diff --git a/MAINTAINERS b/MAINTAINERS index c50c5d235c96..7e31adf97ebb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -203,6 +203,7 @@ F: dlls/jscript/ Joystick input M: Rémi Bernon F: dlls/dinput*/ +F: dlls/gameinput/ F: dlls/joy.cpl/ F: dlls/windows.gaming.input/ F: dlls/winebus.sys/ diff --git a/README.esync b/README.esync new file mode 100644 index 000000000000..6520f2da5640 --- /dev/null +++ b/README.esync @@ -0,0 +1,196 @@ +This is eventfd-based synchronization, or 'esync' for short. Turn it on with +WINEESYNC=1; debug it with +esync. + +== BUGS AND LIMITATIONS == + +Please let me know if you find any bugs. If you can, also attach a log with ++seh,+pid,+esync,+server,+timestamp. + +If you get something like "eventfd: Too many open files" and then things start +crashing, you've probably run out of file descriptors. esync creates one +eventfd descriptor for each synchronization object, and some games may use a +large number of these. Linux by default limits a process to 4096 file +descriptors, which probably was reasonable back in the nineties but isn't +really anymore. (Fortunately Debian and derivatives [Ubuntu, Mint] already +have a reasonable limit.) To raise the limit you'll want to edit +/etc/security/limits.conf and add a line like + +* hard nofile 1048576 + +then restart your session. + +On distributions using systemd, the settings in `/etc/security/limits.conf` +will be overridden by systemd's own settings. If you run `ulimit -Hn` and it +returns a lower number than the one you've previously set, then you can set + +DefaultLimitNOFILE=1024:1048576 + +in both `/etc/systemd/system.conf` and `/etc/systemd/user.conf`. You can then +execute `sudo systemctl daemon-reexec` and restart your session. Check again +with `ulimit -Hn` that the limit is correct. + +Also note that if the wineserver has esync active, all clients also must, and +vice versa. Otherwise things will probably crash quite badly. + +== EXPLANATION == + +The aim is to execute all synchronization operations in "user-space", that is, +without going through wineserver. We do this using Linux's eventfd +facility. The main impetus to using eventfd is so that we can poll multiple +objects at once; in particular we can't do this with futexes, or pthread +semaphores, or the like. The only way I know of to wait on any of multiple +objects is to use select/poll/epoll to wait on multiple fds, and eventfd gives +us those fds in a quite usable way. + +Whenever a semaphore, event, or mutex is created, we have the server, instead +of creating a traditional server-side event/semaphore/mutex, instead create an +'esync' primitive. These live in esync.c and are very slim objects; in fact, +they don't even know what type of primitive they are. The server is involved +at all because we still need a way of creating named objects, passing handles +to another process, etc. + +The server creates an eventfd file descriptor with the requested parameters +and passes it back to ntdll. ntdll creates an object of the appropriate type, +then caches it in a table. This table is copied almost wholesale from the fd +cache code in server.c. + +Specific operations follow quite straightforwardly from eventfd: + +* To release an object, or set an event, we simply write() to it. +* An object is signalled if read() succeeds on it. Notably, we create all + eventfd descriptors with O_NONBLOCK, so that we can atomically check if an + object is signalled and grab it if it is. This also lets us reset events. +* For objects whose state should not be reset upon waiting—e.g. manual-reset + events—we simply check for the POLLIN flag instead of reading. +* Semaphores are handled by the EFD_SEMAPHORE flag. This matches up quite well + (although with some difficulties; see below). +* Mutexes store their owner thread locally. This isn't reliable information if + a different process's thread owns the mutex, but this doesn't matter—a + thread should only care whether it owns the mutex, so it knows whether to + try waiting on it or simply to increase the recursion count. + +The interesting part about esync is that (almost) all waits happen in ntdll, +including those on server-bound objects. The idea here is that on the server +side, for any waitable object, we create an eventfd file descriptor (not an +esync primitive), and then pass it to ntdll if the program tries to wait on +it. These are cached too, so only the first wait will require a round trip to +the server. Then the server signals the file descriptor as appropriate, and +thereby wakes up the client. So far this is implemented for processes, +threads, message queues (difficult; see below), and device managers (necessary +for drivers to work). All of these are necessarily server-bound, so we +wouldn't really gain anything by signalling on the client side instead. Of +course, except possibly for message queues, it's not likely that any program +(cutting-edge D3D game or not) is going to be causing a great wineserver load +by waiting on any of these objects; the motivation was rather to provide a way +to wait on ntdll-bound and server-bound objects at the same time. + +Some cases are still passed to the server, and there's probably no reason not +to keep them that way. Those that I noticed while testing include: async +objects, which are internal to the file APIs and never exposed to userspace, +startup_info objects, which are internal to the loader and signalled when a +process starts, and keyed events, which are exposed through an ntdll API +(although not through kernel32) but can't be mixed with other objects (you +have to use NtWaitForKeyedEvent()). Other cases include: named pipes, debug +events, sockets, and timers. It's unlikely we'll want to optimize debug events +or sockets (or any of the other, rather rare, objects), but it is possible +we'll want to optimize named pipes or timers. + +There were two sort of complications when working out the above. The first one +was events. The trouble is that (1) the server actually creates some events by +itself and (2) the server sometimes manipulates events passed by the +client. Resolving the first case was easy enough, and merely entailed creating +eventfd descriptors for the events the same way as for processes and threads +(note that we don't really lose anything this way; the events include +"LowMemoryCondition" and the event that signals system processes to shut +down). For the second case I basically had to hook the server-side event +functions to redirect to esync versions if the event was actually an esync +primitive. + +The second complication was message queues. The difficulty here is that X11 +signals events by writing into a pipe (at least I think it's a pipe?), and so +as a result wineserver has to poll on that descriptor. In theory we could just +let wineserver do so and then signal us as appropriate, except that wineserver +only polls on the pipe when the thread is waiting for events (otherwise we'd +get e.g. keyboard input while the thread is doing something else, and spin +forever trying to wake up a thread that doesn't care). The obvious solution is +just to poll on that fd ourselves, and that's what I did—it's just that +getting the fd from wineserver was kind of ugly, and the code for waiting was +also kind of ugly basically because we have to wait on both X11's fd and the +"normal" process/thread-style wineserver fd that we use to signal sent +messages. The upshot about the whole thing was that races are basically +impossible, since a thread can only wait on its own queue. + +System APCs already work, since the server will forcibly suspend a thread if +it's not already waiting, and so we just need to check for EINTR from +poll(). User APCs and alertable waits are implemented in a similar style to +message queues (well, sort of): whenever someone executes an alertable wait, +we add an additional eventfd to the list, which the server signals when an APC +arrives. If that eventfd gets signaled, we hand it off to the server to take +care of, and return STATUS_USER_APC. + +Originally I kept the volatile state of semaphores and mutexes inside a +variable local to the handle, with the knowledge that this would break if +someone tried to open the handle elsewhere or duplicate it. It did, and so now +this state is stored inside shared memory. This is of the POSIX variety, is +allocated by the server (but never mapped there) and lives under the path +"/wine-esync". + +There are a couple things that this infrastructure can't handle, although +surprisingly there aren't that many. In particular: +* Implementing wait-all, i.e. WaitForMultipleObjects(..., TRUE, ...), is not + exactly possible the way we'd like it to be possible. In theory that + function should wait until it knows all objects are available, then grab + them all at once atomically. The server (like the kernel) can do this + because the server is single-threaded and can't race with itself. We can't + do this in ntdll, though. The approach I've taken I've laid out in great + detail in the relevant patch, but for a quick summary we poll on each object + until it's signaled (but don't grab it), check them all again, and if + they're all signaled we try to grab them all at once in a tight loop, and if + we fail on any of them we reset the count on whatever we shouldn't have + consumed. Such a blip would necessarily be very quick. +* The whole patchset only works on Linux, where eventfd is available. However, + it should be possible to make it work on a Mac, since eventfd is just a + quicker, easier way to use pipes (i.e. instead of writing 1 to the fd you'd + write 1 byte; instead of reading a 64-bit value from the fd you'd read as + many bytes as you can carry, which is admittedly less than 2**64 but + can probably be something reasonable.) It's also possible, although I + haven't yet looked, to use some different kind of synchronization + primitives, but pipes would be easiest to tack onto this framework. +* PulseEvent() can't work the way it's supposed to work. Fortunately it's rare + and deprecated. It's also explicitly mentioned on MSDN that a thread can + miss the notification for a kernel APC, so in a sense we're not necessarily + doing anything wrong. + +There are some things that are perfectly implementable but that I just haven't +done yet: +* Other synchronizable server primitives. It's unlikely we'll need any of + these, except perhaps named pipes (which would honestly be rather difficult) + and (maybe) timers. +* Access masks. We'd need to store these inside ntdll, and validate them when + someone tries to execute esync operations. + +This patchset was inspired by Daniel Santos' "hybrid synchronization" +patchset. My idea was to create a framework whereby even contended waits could +be executed in userspace, eliminating a lot of the complexity that his +synchronization primitives used. I do however owe some significant gratitude +toward him for setting me on the right path. + +I've tried to maximize code separation, both to make any potential rebases +easier and to ensure that esync is only active when configured. All code in +existing source files is guarded with "if (do_esync())", and generally that +condition is followed by "return esync_version_of_this_method(...);", where +the latter lives in esync.c and is declared in esync.h. I've also tried to +make the patchset very clear and readable—to write it as if I were going to +submit it upstream. (Some intermediate patches do break things, which Wine is +generally against, but I think it's for the better in this case.) I have cut +some corners, though; there is some error checking missing, or implicit +assumptions that the program is behaving correctly. + +I've tried to be careful about races. There are a lot of comments whose +purpose are basically to assure me that races are impossible. In most cases we +don't have to worry about races since all of the low-level synchronization is +done by the kernel. + +Anyway, yeah, this is esync. Use it if you like. + +--Zebediah Figura diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 000000000000..0e3ca52c1787 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e +tools/make_requests +tools/make_specfiles +dlls/winevulkan/make_vulkan -x vk.xml -X video.xml +autoreconf -ifv +rm -rf autom4te.cache + +echo "Now run ./configure" diff --git a/configure b/configure deleted file mode 100755 index fe7464a61d01..000000000000 --- a/configure +++ /dev/null @@ -1,24766 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for Wine 10.0. -# -# Report bugs to . -# -# -# Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, -# Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in #( - e) case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else case e in #( - e) case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ) -then : - -else case e in #( - e) exitcode=1; echo positional parameters were not saved. ;; -esac -fi -test x\$exitcode = x0 || exit 1 -blah=\$(echo \$(echo blah)) -test x\"\$blah\" = xblah || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" - if (eval "$as_required") 2>/dev/null -then : - as_have_required=yes -else case e in #( - e) as_have_required=no ;; -esac -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null -then : - -else case e in #( - e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$as_shell as_have_required=yes - if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null -then : - break 2 -fi -fi - done;; - esac - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in #( - e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi ;; -esac -fi - - - if test "x$CONFIG_SHELL" != x -then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed 'exec'. -printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno -then : - printf "%s\n" "$0: This script requires a shell more modern than all" - printf "%s\n" "$0: the shells that I found on your system." - if test ${ZSH_VERSION+y} ; then - printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" - printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." - else - printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and -$0: wine-devel@winehq.org about your system, including any -$0: error possibly output before this message. Then install -$0: a modern shell, or manually run the script under such a -$0: shell if you do have one." - fi - exit 1 -fi ;; -esac -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in #( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in #( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf "%s\n" "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - t clear - :clear - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -# For backward compatibility with old third-party macros, we provide -# the shell variables $as_echo and $as_echo_n. New code should use -# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. -as_echo='printf %s\n' -as_echo_n='printf %s' - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='Wine' -PACKAGE_TARNAME='wine' -PACKAGE_VERSION='10.0' -PACKAGE_STRING='Wine 10.0' -PACKAGE_BUGREPORT='wine-devel@winehq.org' -PACKAGE_URL='https://www.winehq.org' - -ac_unique_file="server/atom.c" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_STDIO_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_header_c_list= -enable_year2038=yes -ac_subst_vars='LTLIBOBJS -LIBOBJS -TAGSFLAGS -RT_LIBS -WINELOADER_PROGRAMS -DELAYLOADFLAG -MSVCRTFLAGS -NETAPI_LIBS -NETAPI_CFLAGS -PROCSTAT_LIBS -GSSAPI_LIBS -GSSAPI_CFLAGS -KRB5_LIBS -KRB5_CFLAGS -FONTCONFIG_LIBS -FONTCONFIG_CFLAGS -CUPS_LIBS -CUPS_CFLAGS -CAPI20_LIBS -CAPI20_CFLAGS -SDL2_LIBS -SDL2_CFLAGS -UNWIND_LIBS -UNWIND_CFLAGS -UDEV_LIBS -UDEV_CFLAGS -OSS4_LIBS -OSS4_CFLAGS -ALSA_LIBS -GSTREAMER_LIBS -GSTREAMER_CFLAGS -FFMPEG_LIBS -FFMPEG_CFLAGS -PULSE_LIBS -PULSE_CFLAGS -GETTEXTPO_LIBS -FREETYPE_LIBS -FREETYPE_CFLAGS -RESOLV_LIBS -GPHOTO2_PORT_LIBS -GPHOTO2_PORT_CFLAGS -GPHOTO2_LIBS -GPHOTO2_CFLAGS -USB_LIBS -USB_CFLAGS -SANE_LIBS -SANE_CFLAGS -GNUTLS_LIBS -GNUTLS_CFLAGS -DBUS_LIBS -DBUS_CFLAGS -INOTIFY_LIBS -INOTIFY_CFLAGS -PCSCLITE_LIBS -PCAP_LIBS -WAYLAND_EGL_LIBS -WAYLAND_EGL_CFLAGS -EGL_LIBS -EGL_CFLAGS -XKBREGISTRY_LIBS -XKBREGISTRY_CFLAGS -XKBCOMMON_LIBS -XKBCOMMON_CFLAGS -WAYLAND_SCANNER -WAYLAND_CLIENT_LIBS -WAYLAND_CLIENT_CFLAGS -X_LIBS -X_CFLAGS -CPP -XMKMF -PTHREAD_LIBS -ZLIB_PE_LIBS -ZLIB_PE_CFLAGS -XSLT_PE_LIBS -XSLT_PE_CFLAGS -XML2_PE_LIBS -XML2_PE_CFLAGS -VKD3D_PE_LIBS -VKD3D_PE_CFLAGS -TIFF_PE_LIBS -TIFF_PE_CFLAGS -PNG_PE_LIBS -PNG_PE_CFLAGS -MUSL_PE_LIBS -MUSL_PE_CFLAGS -MPG123_PE_LIBS -MPG123_PE_CFLAGS -LDAP_PE_LIBS -LDAP_PE_CFLAGS -LCMS2_PE_LIBS -LCMS2_PE_CFLAGS -JXR_PE_LIBS -JXR_PE_CFLAGS -JPEG_PE_LIBS -JPEG_PE_CFLAGS -GSM_PE_LIBS -GSM_PE_CFLAGS -FLUIDSYNTH_PE_LIBS -FLUIDSYNTH_PE_CFLAGS -FAUDIO_PE_LIBS -FAUDIO_PE_CFLAGS -CAPSTONE_PE_LIBS -CAPSTONE_PE_CFLAGS -MINGW_PKG_CONFIG -PE_ARCHS -WINELOADER_DEPENDS -ac_ct_OBJC -OBJCFLAGS -OBJC -OPENCL_LIBS -COREAUDIO_LIBS -SYSTEMCONFIGURATION_LIBS -SECURITY_LIBS -APPKIT_LIBS -CORESERVICES_LIBS -APPLICATIONSERVICES_LIBS -METAL_LIBS -IOKIT_LIBS -DISKARBITRATION_LIBS -COREFOUNDATION_LIBS -CARBON_LIBS -CONFIGURE_TARGETS -DISABLED_SUBDIRS -SUBDIRS -READELF -OTOOL -LDD -DLLEXT -WINEPRELOADER_LDFLAGS -WINELOADER_LDFLAGS -TOP_INSTALL_DEV -TOP_INSTALL_LIB -UNIXLDFLAGS -UNIXDLLFLAGS -EXTRACFLAGS -LDEXECFLAGS -LDDLLFLAGS -DLLFLAGS -OPENGL_LIBS -I386_LIBS -MSGFMT -ICOTOOL -CONVERT -RSVG -FONTFORGE -PKG_CONFIG -LN_S -STRIP -BISON -FLEX -SED_CMD -RUNTESTFLAGS -toolsdir -x86_64_DISABLED_SUBDIRS -x86_64_DELAYLOADFLAG -x86_64_STRIP -x86_64_TARGET -x86_64_DEBUG -x86_64_LDFLAGS -x86_64_EXTRACFLAGS -x86_64_CFLAGS -x86_64_CC -i386_DISABLED_SUBDIRS -i386_DELAYLOADFLAG -i386_STRIP -i386_TARGET -i386_DEBUG -i386_LDFLAGS -i386_EXTRACFLAGS -i386_CFLAGS -i386_CC -arm64ec_DISABLED_SUBDIRS -arm64ec_DELAYLOADFLAG -arm64ec_STRIP -arm64ec_TARGET -arm64ec_DEBUG -arm64ec_LDFLAGS -arm64ec_EXTRACFLAGS -arm64ec_CFLAGS -arm64ec_CC -arm_DISABLED_SUBDIRS -arm_DELAYLOADFLAG -arm_STRIP -arm_TARGET -arm_DEBUG -arm_LDFLAGS -arm_EXTRACFLAGS -arm_CFLAGS -arm_CC -aarch64_DISABLED_SUBDIRS -aarch64_DELAYLOADFLAG -aarch64_STRIP -aarch64_TARGET -aarch64_DEBUG -aarch64_LDFLAGS -aarch64_EXTRACFLAGS -aarch64_CFLAGS -aarch64_CC -HOST_ARCH -toolsext -TARGETFLAGS -LD -CPPBIN -ac_ct_CXX -CXXFLAGS -CXX -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -SARIF_CONVERTER -srcdir -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -system_dllpath -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -runstatedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -enable_archs -enable_win16 -enable_win64 -enable_tests -enable_build_id -enable_maintainer_mode -enable_sast -enable_silent_rules -enable_werror -with_alsa -with_capi -with_coreaudio -with_cups -with_dbus -with_ffmpeg -with_fontconfig -with_freetype -with_gettext -with_gettextpo -with_gphoto -with_gnutls -with_gssapi -with_gstreamer -with_inotify -with_krb5 -with_mingw -with_netapi -with_opencl -with_opengl -with_osmesa -with_oss -with_pcap -with_pcsclite -with_pthread -with_pulse -with_sane -with_sdl -with_udev -with_unwind -with_usb -with_v4l2 -with_vulkan -with_wayland -with_xcomposite -with_xcursor -with_xfixes -with_xinerama -with_xinput -with_xinput2 -with_xrandr -with_xrender -with_xshape -with_xshm -with_xxf86vm -with_system_dllpath -with_wine_tools -with_wine64 -enable_largefile -with_x -enable_acledit -enable_aclui -enable_activeds_tlb -enable_activeds -enable_actxprxy -enable_adsldp -enable_adsldpc -enable_advapi32 -enable_advpack -enable_amsi -enable_amstream -enable_apisetschema -enable_apphelp -enable_appwiz_cpl -enable_appxdeploymentclient -enable_atl -enable_atl100 -enable_atl110 -enable_atl80 -enable_atl90 -enable_atlthunk -enable_atmlib -enable_authz -enable_avicap32 -enable_avifil32 -enable_avrt -enable_bcp47langs -enable_bcrypt -enable_bcryptprimitives -enable_bluetoothapis -enable_browseui -enable_bthprops_cpl -enable_cabinet -enable_capi2032 -enable_cards -enable_cdosys -enable_cfgmgr32 -enable_clusapi -enable_cng_sys -enable_colorcnv -enable_combase -enable_comcat -enable_comctl32 -enable_comdlg32 -enable_coml2 -enable_compstui -enable_comsvcs -enable_concrt140 -enable_connect -enable_coremessaging -enable_credui -enable_crtdll -enable_crypt32 -enable_cryptdlg -enable_cryptdll -enable_cryptext -enable_cryptnet -enable_cryptowinrt -enable_cryptsp -enable_cryptui -enable_ctapi32 -enable_ctl3d32 -enable_d2d1 -enable_d3d10 -enable_d3d10_1 -enable_d3d10core -enable_d3d11 -enable_d3d12 -enable_d3d12core -enable_d3d8 -enable_d3d8thk -enable_d3d9 -enable_d3dcompiler_33 -enable_d3dcompiler_34 -enable_d3dcompiler_35 -enable_d3dcompiler_36 -enable_d3dcompiler_37 -enable_d3dcompiler_38 -enable_d3dcompiler_39 -enable_d3dcompiler_40 -enable_d3dcompiler_41 -enable_d3dcompiler_42 -enable_d3dcompiler_43 -enable_d3dcompiler_46 -enable_d3dcompiler_47 -enable_d3dim -enable_d3dim700 -enable_d3drm -enable_d3dx10_33 -enable_d3dx10_34 -enable_d3dx10_35 -enable_d3dx10_36 -enable_d3dx10_37 -enable_d3dx10_38 -enable_d3dx10_39 -enable_d3dx10_40 -enable_d3dx10_41 -enable_d3dx10_42 -enable_d3dx10_43 -enable_d3dx11_42 -enable_d3dx11_43 -enable_d3dx9_24 -enable_d3dx9_25 -enable_d3dx9_26 -enable_d3dx9_27 -enable_d3dx9_28 -enable_d3dx9_29 -enable_d3dx9_30 -enable_d3dx9_31 -enable_d3dx9_32 -enable_d3dx9_33 -enable_d3dx9_34 -enable_d3dx9_35 -enable_d3dx9_36 -enable_d3dx9_37 -enable_d3dx9_38 -enable_d3dx9_39 -enable_d3dx9_40 -enable_d3dx9_41 -enable_d3dx9_42 -enable_d3dx9_43 -enable_d3dxof -enable_dataexchange -enable_davclnt -enable_dbgeng -enable_dbghelp -enable_dciman32 -enable_dcomp -enable_ddraw -enable_ddrawex -enable_desk_cpl -enable_devenum -enable_dhcpcsvc -enable_dhcpcsvc6 -enable_dhtmled_ocx -enable_diasymreader -enable_difxapi -enable_dinput -enable_dinput8 -enable_directmanipulation -enable_dispex -enable_dmband -enable_dmcompos -enable_dmime -enable_dmloader -enable_dmscript -enable_dmstyle -enable_dmsynth -enable_dmusic -enable_dmusic32 -enable_dnsapi -enable_dplay -enable_dplayx -enable_dpnaddr -enable_dpnet -enable_dpnhpast -enable_dpnhupnp -enable_dpnlobby -enable_dpvoice -enable_dpwsockx -enable_drmclien -enable_dsdmo -enable_dsound -enable_dsquery -enable_dssenh -enable_dsuiext -enable_dswave -enable_dwmapi -enable_dwrite -enable_dx8vb -enable_dxcore -enable_dxdiagn -enable_dxgi -enable_dxtrans -enable_dxva2 -enable_esent -enable_evr -enable_explorerframe -enable_faultrep -enable_feclient -enable_fltlib -enable_fltmgr_sys -enable_fntcache -enable_fontsub -enable_fusion -enable_fwpuclnt -enable_gameux -enable_gamingtcui -enable_gdi32 -enable_gdiplus -enable_geolocation -enable_glu32 -enable_gphoto2_ds -enable_gpkcsp -enable_graphicscapture -enable_hal -enable_hhctrl_ocx -enable_hid -enable_hidclass_sys -enable_hidparse_sys -enable_hlink -enable_hnetcfg -enable_hrtfapo -enable_http_sys -enable_httpapi -enable_hvsimanagementapi -enable_ia2comproxy -enable_iccvid -enable_icmp -enable_icmui -enable_ieframe -enable_ieproxy -enable_iertutil -enable_imaadp32_acm -enable_imagehlp -enable_imm32 -enable_inetcomm -enable_inetcpl_cpl -enable_inetmib1 -enable_infosoft -enable_initpki -enable_inkobj -enable_inseng -enable_iphlpapi -enable_iprop -enable_ir50_32 -enable_irprops_cpl -enable_itircl -enable_itss -enable_joy_cpl -enable_jscript -enable_jsproxy -enable_kerberos -enable_kernel32 -enable_kernelbase -enable_ksecdd_sys -enable_ksproxy_ax -enable_ksuser -enable_ktmw32 -enable_l3codeca_acm -enable_l3codecx_ax -enable_light_msstyles -enable_loadperf -enable_localspl -enable_localui -enable_lz32 -enable_magnification -enable_mapi32 -enable_mapistub -enable_mciavi32 -enable_mcicda -enable_mciqtz32 -enable_mciseq -enable_mciwave -enable_mf -enable_mf3216 -enable_mfasfsrcsnk -enable_mferror -enable_mfh264enc -enable_mfmediaengine -enable_mfmp4srcsnk -enable_mfplat -enable_mfplay -enable_mfreadwrite -enable_mfsrcsnk -enable_mgmtapi -enable_midimap -enable_mlang -enable_mmcndmgr -enable_mmdevapi -enable_mouhid_sys -enable_mountmgr_sys -enable_mp3dmod -enable_mpr -enable_mprapi -enable_msacm32_drv -enable_msacm32 -enable_msado15 -enable_msadp32_acm -enable_msasn1 -enable_msauddecmft -enable_mscat32 -enable_mscms -enable_mscoree -enable_mscorwks -enable_msctf -enable_msctfmonitor -enable_msctfp -enable_msdaps -enable_msdasql -enable_msdelta -enable_msdmo -enable_msdrm -enable_msftedit -enable_msg711_acm -enable_msgsm32_acm -enable_mshtml_tlb -enable_mshtml -enable_msi -enable_msident -enable_msimg32 -enable_msimsg -enable_msimtf -enable_msisip -enable_msisys_ocx -enable_msls31 -enable_msmpeg2vdec -enable_msnet32 -enable_mspatcha -enable_msports -enable_msrle32 -enable_msscript_ocx -enable_mssign32 -enable_mssip32 -enable_mstask -enable_msttsengine -enable_msv1_0 -enable_msvcirt -enable_msvcm80 -enable_msvcm90 -enable_msvcp100 -enable_msvcp110 -enable_msvcp120 -enable_msvcp120_app -enable_msvcp140 -enable_msvcp140_1 -enable_msvcp140_2 -enable_msvcp140_atomic_wait -enable_msvcp140_codecvt_ids -enable_msvcp60 -enable_msvcp70 -enable_msvcp71 -enable_msvcp80 -enable_msvcp90 -enable_msvcp_win -enable_msvcr100 -enable_msvcr110 -enable_msvcr120 -enable_msvcr120_app -enable_msvcr70 -enable_msvcr71 -enable_msvcr80 -enable_msvcr90 -enable_msvcrt -enable_msvcrt20 -enable_msvcrt40 -enable_msvcrtd -enable_msvfw32 -enable_msvidc32 -enable_msvproc -enable_mswsock -enable_msxml -enable_msxml2 -enable_msxml3 -enable_msxml4 -enable_msxml6 -enable_mtxdm -enable_ncrypt -enable_nddeapi -enable_ndis_sys -enable_netapi32 -enable_netcfgx -enable_netio_sys -enable_netprofm -enable_netutils -enable_newdev -enable_ninput -enable_normaliz -enable_npmshtml -enable_npptools -enable_nsi -enable_nsiproxy_sys -enable_ntdll -enable_ntdsapi -enable_ntoskrnl_exe -enable_ntprint -enable_objsel -enable_odbc32 -enable_odbcbcp -enable_odbccp32 -enable_odbccu32 -enable_ole32 -enable_oleacc -enable_oleaut32 -enable_olecli32 -enable_oledb32 -enable_oledlg -enable_olepro32 -enable_olesvr32 -enable_olethk32 -enable_opcservices -enable_opencl -enable_opengl32 -enable_packager -enable_pdh -enable_photometadatahandler -enable_pidgen -enable_powrprof -enable_printui -enable_prntvpt -enable_profapi -enable_propsys -enable_psapi -enable_pstorec -enable_pwrshplugin -enable_qasf -enable_qcap -enable_qdvd -enable_qedit -enable_qmgr -enable_qmgrprxy -enable_quartz -enable_query -enable_qwave -enable_rasapi32 -enable_rasdlg -enable_regapi -enable_resampledmo -enable_resutils -enable_riched20 -enable_riched32 -enable_rometadata -enable_rpcrt4 -enable_rsabase -enable_rsaenh -enable_rstrtmgr -enable_rtutils -enable_rtworkq -enable_samlib -enable_sane_ds -enable_sapi -enable_sas -enable_scarddlg -enable_scardsvr -enable_sccbase -enable_schannel -enable_schedsvc -enable_scrobj -enable_scrrun -enable_scsiport_sys -enable_sechost -enable_secur32 -enable_security -enable_sensapi -enable_serialui -enable_setupapi -enable_sfc -enable_sfc_os -enable_shcore -enable_shdoclc -enable_shdocvw -enable_shell32 -enable_shfolder -enable_shlwapi -enable_slbcsp -enable_slc -enable_snmpapi -enable_softpub -enable_spoolss -enable_sppc -enable_srclient -enable_srvcli -enable_srvsvc -enable_sspicli -enable_stdole2_tlb -enable_stdole32_tlb -enable_sti -enable_strmdll -enable_svrapi -enable_sxs -enable_t2embed -enable_tapi32 -enable_taskschd -enable_tbs -enable_tdh -enable_tdi_sys -enable_threadpoolwinrt -enable_traffic -enable_twain_32 -enable_twinapi_appcore -enable_tzres -enable_ucrtbase -enable_uianimation -enable_uiautomationcore -enable_uiribbon -enable_unicows -enable_updspapi -enable_url -enable_urlmon -enable_usbd_sys -enable_user32 -enable_userenv -enable_usp10 -enable_utildll -enable_uxtheme -enable_vbscript -enable_vcomp -enable_vcomp100 -enable_vcomp110 -enable_vcomp120 -enable_vcomp140 -enable_vcomp90 -enable_vcruntime140 -enable_vcruntime140_1 -enable_vdmdbg -enable_version -enable_vga -enable_virtdisk -enable_vssapi -enable_vulkan_1 -enable_wbemdisp -enable_wbemprox -enable_wdscore -enable_webservices -enable_websocket -enable_wer -enable_wevtapi -enable_wevtsvc -enable_wiaservc -enable_wimgapi -enable_win32u -enable_windows_applicationmodel -enable_windows_devices_bluetooth -enable_windows_devices_enumeration -enable_windows_devices_usb -enable_windows_gaming_input -enable_windows_gaming_ui_gamebar -enable_windows_globalization -enable_windows_media_devices -enable_windows_media_mediacontrol -enable_windows_media_speech -enable_windows_media -enable_windows_networking_connectivity -enable_windows_networking_hostname -enable_windows_networking -enable_windows_perception_stub -enable_windows_security_authentication_onlineid -enable_windows_security_credentials_ui_userconsentverifier -enable_windows_storage_applicationdata -enable_windows_system_profile_systemmanufacturers -enable_windows_ui -enable_windows_web -enable_windowscodecs -enable_windowscodecsext -enable_winealsa_drv -enable_wineandroid_drv -enable_winebth_sys -enable_winebus_sys -enable_winecoreaudio_drv -enable_winecrt0 -enable_wined3d -enable_winedmo -enable_winegstreamer -enable_winehid_sys -enable_winemac_drv -enable_winemapi -enable_wineoss_drv -enable_wineps_drv -enable_winepulse_drv -enable_wineusb_sys -enable_winevulkan -enable_winewayland_drv -enable_winex11_drv -enable_winexinput_sys -enable_wing32 -enable_winhttp -enable_wininet -enable_winmm -enable_winnls32 -enable_winprint -enable_winscard -enable_winspool_drv -enable_winsta -enable_wintab32 -enable_wintrust -enable_wintypes -enable_winusb -enable_wlanapi -enable_wlanui -enable_wldap32 -enable_wldp -enable_wmadmod -enable_wmasf -enable_wmi -enable_wmilib_sys -enable_wmiutils -enable_wmp -enable_wmphoto -enable_wmvcore -enable_wmvdecod -enable_wnaspi32 -enable_wofutil -enable_wow64 -enable_wow64cpu -enable_wow64win -enable_wpc -enable_wpcap -enable_ws2_32 -enable_wsdapi -enable_wshom_ocx -enable_wsnmp32 -enable_wsock32 -enable_wtsapi32 -enable_wuapi -enable_wuaueng -enable_x3daudio1_0 -enable_x3daudio1_1 -enable_x3daudio1_2 -enable_x3daudio1_3 -enable_x3daudio1_4 -enable_x3daudio1_5 -enable_x3daudio1_6 -enable_x3daudio1_7 -enable_xactengine2_0 -enable_xactengine2_4 -enable_xactengine2_7 -enable_xactengine2_9 -enable_xactengine3_0 -enable_xactengine3_1 -enable_xactengine3_2 -enable_xactengine3_3 -enable_xactengine3_4 -enable_xactengine3_5 -enable_xactengine3_6 -enable_xactengine3_7 -enable_xapofx1_1 -enable_xapofx1_2 -enable_xapofx1_3 -enable_xapofx1_4 -enable_xapofx1_5 -enable_xaudio2_0 -enable_xaudio2_1 -enable_xaudio2_2 -enable_xaudio2_3 -enable_xaudio2_4 -enable_xaudio2_5 -enable_xaudio2_6 -enable_xaudio2_7 -enable_xaudio2_8 -enable_xaudio2_9 -enable_xinput1_1 -enable_xinput1_2 -enable_xinput1_3 -enable_xinput1_4 -enable_xinput9_1_0 -enable_xinputuap -enable_xmllite -enable_xolehlp -enable_xpsprint -enable_xpssvcs -enable_xtajit64 -enable_fonts -enable_include -enable_adsiid -enable_capstone -enable_dmoguids -enable_dxerr8 -enable_dxerr9 -enable_dxguid -enable_faudio -enable_fluidsynth -enable_gsm -enable_jpeg -enable_jxr -enable_lcms2 -enable_ldap -enable_mfuuid -enable_mpg123 -enable_musl -enable_png -enable_strmbase -enable_strmiids -enable_tiff -enable_uuid -enable_vkd3d -enable_wbemuuid -enable_wmcodecdspuuid -enable_xml2 -enable_xslt -enable_zlib -enable_loader -enable_nls -enable_po -enable_arp -enable_aspnet_regiis -enable_attrib -enable_cabarc -enable_cacls -enable_certutil -enable_chcp_com -enable_clock -enable_cmd -enable_conhost -enable_control -enable_cscript -enable_dism -enable_dllhost -enable_dplaysvr -enable_dpnsvr -enable_dpvsetup -enable_dxdiag -enable_eject -enable_expand -enable_explorer -enable_extrac32 -enable_fc -enable_find -enable_findstr -enable_fsutil -enable_hh -enable_hostname -enable_icacls -enable_icinfo -enable_iexplore -enable_ipconfig -enable_klist -enable_lodctr -enable_mofcomp -enable_mshta -enable_msidb -enable_msiexec -enable_msinfo32 -enable_net -enable_netsh -enable_netstat -enable_ngen -enable_notepad -enable_oleview -enable_ping -enable_plugplay -enable_pnputil -enable_powershell -enable_presentationfontcache -enable_progman -enable_reg -enable_regasm -enable_regedit -enable_regini -enable_regsvcs -enable_regsvr32 -enable_robocopy -enable_rpcss -enable_rundll32 -enable_sc -enable_schtasks -enable_sdbinst -enable_secedit -enable_servicemodelreg -enable_services -enable_setx -enable_shutdown -enable_sort -enable_spoolsv -enable_start -enable_subst -enable_svchost -enable_systeminfo -enable_taskkill -enable_tasklist -enable_taskmgr -enable_termsv -enable_uninstaller -enable_unlodctr -enable_view -enable_wevtutil -enable_where -enable_whoami -enable_wineboot -enable_winebrowser -enable_winecfg -enable_wineconsole -enable_winedbg -enable_winedevice -enable_winefile -enable_winemenubuilder -enable_winemine -enable_winemsibuilder -enable_winepath -enable_winetest -enable_winhlp32 -enable_winmgmt -enable_winver -enable_wmic -enable_wmplayer -enable_wordpad -enable_write -enable_wscript -enable_wuauserv -enable_wusa -enable_xcopy -enable_server -enable_tools -enable_sfnt2fon -enable_widl -enable_winebuild -enable_winedump -enable_winegcc -enable_winemaker -enable_wmc -enable_wrc -enable_year2038 -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -CXX -CXXFLAGS -CCC -OBJC -OBJCFLAGS -CAPSTONE_PE_CFLAGS -CAPSTONE_PE_LIBS -FAUDIO_PE_CFLAGS -FAUDIO_PE_LIBS -FLUIDSYNTH_PE_CFLAGS -FLUIDSYNTH_PE_LIBS -GSM_PE_CFLAGS -GSM_PE_LIBS -JPEG_PE_CFLAGS -JPEG_PE_LIBS -JXR_PE_CFLAGS -JXR_PE_LIBS -LCMS2_PE_CFLAGS -LCMS2_PE_LIBS -LDAP_PE_CFLAGS -LDAP_PE_LIBS -MPG123_PE_CFLAGS -MPG123_PE_LIBS -MUSL_PE_CFLAGS -MUSL_PE_LIBS -PNG_PE_CFLAGS -PNG_PE_LIBS -TIFF_PE_CFLAGS -TIFF_PE_LIBS -VKD3D_PE_CFLAGS -VKD3D_PE_LIBS -XML2_PE_CFLAGS -XML2_PE_LIBS -XSLT_PE_CFLAGS -XSLT_PE_LIBS -ZLIB_PE_CFLAGS -ZLIB_PE_LIBS -XMKMF -CPP -WAYLAND_CLIENT_CFLAGS -WAYLAND_CLIENT_LIBS -XKBCOMMON_CFLAGS -XKBCOMMON_LIBS -XKBREGISTRY_CFLAGS -XKBREGISTRY_LIBS -EGL_CFLAGS -EGL_LIBS -WAYLAND_EGL_CFLAGS -WAYLAND_EGL_LIBS -INOTIFY_CFLAGS -INOTIFY_LIBS -DBUS_CFLAGS -DBUS_LIBS -GNUTLS_CFLAGS -GNUTLS_LIBS -SANE_CFLAGS -SANE_LIBS -USB_CFLAGS -USB_LIBS -GPHOTO2_CFLAGS -GPHOTO2_LIBS -GPHOTO2_PORT_CFLAGS -GPHOTO2_PORT_LIBS -FREETYPE_CFLAGS -FREETYPE_LIBS -PULSE_CFLAGS -PULSE_LIBS -FFMPEG_CFLAGS -FFMPEG_LIBS -GSTREAMER_CFLAGS -GSTREAMER_LIBS -UDEV_CFLAGS -UDEV_LIBS -UNWIND_CFLAGS -UNWIND_LIBS -SDL2_CFLAGS -SDL2_LIBS -CAPI20_CFLAGS -CAPI20_LIBS -CUPS_CFLAGS -CUPS_LIBS -FONTCONFIG_CFLAGS -FONTCONFIG_LIBS -KRB5_CFLAGS -KRB5_LIBS -GSSAPI_CFLAGS -GSSAPI_LIBS -NETAPI_CFLAGS -NETAPI_LIBS' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: '$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: '$ac_option' -Try '$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: '$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: '$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -'configure' configures Wine 10.0 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print 'checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for '--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or '..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, 'make install' will install all the files in -'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify -an installation prefix other than '$ac_default_prefix' using '--prefix', -for instance '--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/wine] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -X features: - --x-includes=DIR X include files are in DIR - --x-libraries=DIR X library files are in DIR - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of Wine 10.0:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-archs={i386,x86_64,arm,aarch64} - enable multiple architectures for PE compilation - --disable-win16 do not include Win16 support - --enable-win64 build a Win64 emulator on AMD64 (won't run Win32 - binaries) - --disable-tests do not build the regression tests - --enable-build-id include .buildid section in output objects - --enable-maintainer-mode - enable maintainer-specific build rules - --enable-sast enable static application security testing using - Clang - --enable-silent-rules use silent build rules (override: "make V=1") - --enable-werror treat compilation warnings as errors - --disable-largefile omit support for large files - --disable-year2038 don't support timestamps after 2038 - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --without-alsa do not use the Alsa sound support - --without-capi do not use CAPI (ISDN support) - --without-coreaudio do not use the CoreAudio sound support - --without-cups do not use CUPS - --without-dbus do not use DBus (dynamic device support) - --without-ffmpeg do not use the FFmpeg library - --without-fontconfig do not use fontconfig - --without-freetype do not use the FreeType library - --without-gettext do not use gettext - --with-gettextpo use the GetTextPO library to rebuild po files - --without-gphoto do not use gphoto (Digital Camera support) - --without-gnutls do not use GnuTLS (schannel support) - --without-gssapi do not use GSSAPI (Kerberos SSP support) - --without-gstreamer do not use GStreamer (codecs support) - --without-inotify do not use inotify (filesystem change notifications) - --without-krb5 do not use krb5 (Kerberos) - --without-mingw do not use the MinGW cross-compiler - --without-netapi do not use the Samba NetAPI library - --without-opencl do not use OpenCL - --without-opengl do not use OpenGL - --without-osmesa do not use the OSMesa library - --without-oss do not use the OSS sound support - --without-pcap do not use the Packet Capture library - --without-pcsclite do not use PCSC lite - --without-pthread do not use the pthread library - --without-pulse do not use PulseAudio sound support - --without-sane do not use SANE (scanner support) - --without-sdl do not use SDL - --without-udev do not use udev (plug and play support) - --without-unwind do not use the libunwind library (exception - handling) - --without-usb do not use the libusb library - --without-v4l2 do not use v4l2 (video capture) - --without-vulkan do not use Vulkan - --without-wayland do not build the Wayland driver - --without-xcomposite do not use the Xcomposite extension - --without-xcursor do not use the Xcursor extension - --without-xfixes do not use Xfixes for clipboard change notifications - --without-xinerama do not use Xinerama (legacy multi-monitor support) - --without-xinput do not use the Xinput extension - --without-xinput2 do not use the Xinput 2 extension - --without-xrandr do not use Xrandr (multi-monitor support) - --without-xrender do not use the Xrender extension - --without-xshape do not use the Xshape extension - --without-xshm do not use XShm (shared memory extension) - --without-xxf86vm do not use XFree video mode extension - --with-system-dllpath=PATH - load external PE dependencies from colon-separated - path PATH - --with-wine-tools=DIR use Wine tools from directory DIR - --with-wine64=DIR use the 64-bit Wine in DIR for a Wow64 build - --with-x use the X Window System - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CXX C++ compiler command - CXXFLAGS C++ compiler flags - OBJC Objective C compiler command - OBJCFLAGS Objective C compiler flags - CAPSTONE_PE_CFLAGS - C compiler flags for the PE capstone, overriding the bundled - version - CAPSTONE_PE_LIBS - Linker flags for the PE capstone, overriding the bundled version - FAUDIO_PE_CFLAGS - C compiler flags for the PE faudio, overriding the bundled - version - FAUDIO_PE_LIBS - Linker flags for the PE faudio, overriding the bundled version - FLUIDSYNTH_PE_CFLAGS - C compiler flags for the PE fluidsynth, overriding the bundled - version - FLUIDSYNTH_PE_LIBS - Linker flags for the PE fluidsynth, overriding the bundled - version - GSM_PE_CFLAGS - C compiler flags for the PE gsm, overriding the bundled version - GSM_PE_LIBS Linker flags for the PE gsm, overriding the bundled version - JPEG_PE_CFLAGS - C compiler flags for the PE jpeg, overriding the bundled version - JPEG_PE_LIBS - Linker flags for the PE jpeg, overriding the bundled version - JXR_PE_CFLAGS - C compiler flags for the PE jxr, overriding the bundled version - JXR_PE_LIBS Linker flags for the PE jxr, overriding the bundled version - LCMS2_PE_CFLAGS - C compiler flags for the PE lcms2, overriding the bundled - version - LCMS2_PE_LIBS - Linker flags for the PE lcms2, overriding the bundled version - LDAP_PE_CFLAGS - C compiler flags for the PE ldap, overriding the bundled version - LDAP_PE_LIBS - Linker flags for the PE ldap, overriding the bundled version - MPG123_PE_CFLAGS - C compiler flags for the PE mpg123, overriding the bundled - version - MPG123_PE_LIBS - Linker flags for the PE mpg123, overriding the bundled version - MUSL_PE_CFLAGS - C compiler flags for the PE musl, overriding the bundled version - MUSL_PE_LIBS - Linker flags for the PE musl, overriding the bundled version - PNG_PE_CFLAGS - C compiler flags for the PE png, overriding the bundled version - PNG_PE_LIBS Linker flags for the PE png, overriding the bundled version - TIFF_PE_CFLAGS - C compiler flags for the PE tiff, overriding the bundled version - TIFF_PE_LIBS - Linker flags for the PE tiff, overriding the bundled version - VKD3D_PE_CFLAGS - C compiler flags for the PE vkd3d, overriding the bundled - version - VKD3D_PE_LIBS - Linker flags for the PE vkd3d, overriding the bundled version - XML2_PE_CFLAGS - C compiler flags for the PE xml2, overriding the bundled version - XML2_PE_LIBS - Linker flags for the PE xml2, overriding the bundled version - XSLT_PE_CFLAGS - C compiler flags for the PE xslt, overriding the bundled version - XSLT_PE_LIBS - Linker flags for the PE xslt, overriding the bundled version - ZLIB_PE_CFLAGS - C compiler flags for the PE zlib, overriding the bundled version - ZLIB_PE_LIBS - Linker flags for the PE zlib, overriding the bundled version - XMKMF Path to xmkmf, Makefile generator for X Window System - CPP C preprocessor - WAYLAND_CLIENT_CFLAGS - C compiler flags for wayland-client, overriding pkg-config - WAYLAND_CLIENT_LIBS - Linker flags for wayland-client, overriding pkg-config - XKBCOMMON_CFLAGS - C compiler flags for xkbcommon, overriding pkg-config - XKBCOMMON_LIBS - Linker flags for xkbcommon, overriding pkg-config - XKBREGISTRY_CFLAGS - C compiler flags for xkbregistry, overriding pkg-config - XKBREGISTRY_LIBS - Linker flags for xkbregistry, overriding pkg-config - EGL_CFLAGS C compiler flags for egl, overriding pkg-config - EGL_LIBS Linker flags for egl, overriding pkg-config - WAYLAND_EGL_CFLAGS - C compiler flags for wayland-egl, overriding pkg-config - WAYLAND_EGL_LIBS - Linker flags for wayland-egl, overriding pkg-config - INOTIFY_CFLAGS - C compiler flags for libinotify, overriding pkg-config - INOTIFY_LIBS - Linker flags for libinotify, overriding pkg-config - DBUS_CFLAGS C compiler flags for dbus-1, overriding pkg-config - DBUS_LIBS Linker flags for dbus-1, overriding pkg-config - GNUTLS_CFLAGS - C compiler flags for gnutls, overriding pkg-config - GNUTLS_LIBS Linker flags for gnutls, overriding pkg-config - SANE_CFLAGS C compiler flags for sane-backends, overriding pkg-config - SANE_LIBS Linker flags for sane-backends, overriding pkg-config - USB_CFLAGS C compiler flags for libusb-1.0, overriding pkg-config - USB_LIBS Linker flags for libusb-1.0, overriding pkg-config - GPHOTO2_CFLAGS - C compiler flags for libgphoto2, overriding pkg-config - GPHOTO2_LIBS - Linker flags for libgphoto2, overriding pkg-config - GPHOTO2_PORT_CFLAGS - C compiler flags for libgphoto2_port, overriding pkg-config - GPHOTO2_PORT_LIBS - Linker flags for libgphoto2_port, overriding pkg-config - FREETYPE_CFLAGS - C compiler flags for freetype2, overriding pkg-config - FREETYPE_LIBS - Linker flags for freetype2, overriding pkg-config - PULSE_CFLAGS - C compiler flags for libpulse, overriding pkg-config - PULSE_LIBS Linker flags for libpulse, overriding pkg-config - FFMPEG_CFLAGS - C compiler flags for libavutil libavformat libavcodec, - overriding pkg-config - FFMPEG_LIBS Linker flags for libavutil libavformat libavcodec, overriding - pkg-config - GSTREAMER_CFLAGS - C compiler flags for gstreamer-1.0 gstreamer-video-1.0 - gstreamer-audio-1.0 gstreamer-tag-1.0, overriding pkg-config - GSTREAMER_LIBS - Linker flags for gstreamer-1.0 gstreamer-video-1.0 - gstreamer-audio-1.0 gstreamer-tag-1.0, overriding pkg-config - UDEV_CFLAGS C compiler flags for libudev, overriding pkg-config - UDEV_LIBS Linker flags for libudev, overriding pkg-config - UNWIND_CFLAGS - C compiler flags for libunwind, overriding pkg-config - UNWIND_LIBS Linker flags for libunwind, overriding pkg-config - SDL2_CFLAGS C compiler flags for sdl2, overriding pkg-config - SDL2_LIBS Linker flags for sdl2, overriding pkg-config - CAPI20_CFLAGS - C compiler flags for capi20, overriding pkg-config - CAPI20_LIBS Linker flags for capi20, overriding pkg-config - CUPS_CFLAGS C compiler flags for cups, overriding pkg-config - CUPS_LIBS Linker flags for cups, overriding pkg-config - FONTCONFIG_CFLAGS - C compiler flags for fontconfig, overriding pkg-config - FONTCONFIG_LIBS - Linker flags for fontconfig, overriding pkg-config - KRB5_CFLAGS C compiler flags for krb5, overriding pkg-config - KRB5_LIBS Linker flags for krb5, overriding pkg-config - GSSAPI_CFLAGS - C compiler flags for krb5-gssapi, overriding pkg-config - GSSAPI_LIBS Linker flags for krb5-gssapi, overriding pkg-config - NETAPI_CFLAGS - C compiler flags for netapi, overriding pkg-config - NETAPI_LIBS Linker flags for netapi, overriding pkg-config - -Use these variables to override the choices made by 'configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -Wine home page: . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for configure.gnu first; this name is used for a wrapper for - # Metaconfig's "Configure" on case-insensitive file systems. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -Wine configure 10.0 -generated by GNU Autoconf 2.72 - -Copyright (C) 2023 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -# ac_fn_c_try_compile LINENO -# -------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else case e in #( - e) printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_compile - -# ac_fn_cxx_try_compile LINENO -# ---------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else case e in #( - e) printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_compile - -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - } -then : - ac_retval=0 -else case e in #( - e) printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else case e in #( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - -# ac_fn_objc_try_compile LINENO -# ----------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_objc_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_objc_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else case e in #( - e) printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_objc_try_compile - -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (void); below. */ - -#include -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (void); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main (void) -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$3=yes" -else case e in #( - e) eval "$3=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_func - -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - } -then : - ac_retval=0 -else case e in #( - e) printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 ;; -esac -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - -# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES -# ---------------------------------------------------- -# Tries to find if the field MEMBER exists in type AGGR, after including -# INCLUDES, setting cache variable VAR accordingly. -ac_fn_c_check_member () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 -printf %s "checking for $2.$3... " >&6; } -if eval test \${$4+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main (void) -{ -static $2 ac_aggr; -if (ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$4=yes" -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main (void) -{ -static $2 ac_aggr; -if (sizeof ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$4=yes" -else case e in #( - e) eval "$4=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$4 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_member - -# ac_fn_c_check_type LINENO TYPE VAR INCLUDES -# ------------------------------------------- -# Tests whether TYPE exists after having included INCLUDES, setting cache -# variable VAR accordingly. -ac_fn_c_check_type () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) eval "$3=no" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main (void) -{ -if (sizeof ($2)) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main (void) -{ -if (sizeof (($2))) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in #( - e) eval "$3=yes" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_type -ac_configure_args_raw= -for ac_arg -do - case $ac_arg in - *\'*) - ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append ac_configure_args_raw " '$ac_arg'" -done - -case $ac_configure_args_raw in - *$as_nl*) - ac_safe_unquote= ;; - *) - ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. - ac_unsafe_a="$ac_unsafe_z#~" - ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" - ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; -esac - -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by Wine $as_me 10.0, which was -generated by GNU Autoconf 2.72. Invocation command line was - - $ $0$ac_configure_args_raw - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - printf "%s\n" "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Sanitize IFS. - IFS=" "" $as_nl" - # Save into config.log some information that might help in debugging. - { - echo - - printf "%s\n" "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - printf "%s\n" "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - printf "%s\n" "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - printf "%s\n" "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - printf "%s\n" "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - printf "%s\n" "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - printf "%s\n" "$as_me: caught signal $ac_signal" - printf "%s\n" "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -printf "%s\n" "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -if test -n "$CONFIG_SITE"; then - ac_site_files="$CONFIG_SITE" -elif test "x$prefix" != xNONE; then - ac_site_files="$prefix/share/config.site $prefix/etc/config.site" -else - ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" -fi - -for ac_site_file in $ac_site_files -do - case $ac_site_file in #( - */*) : - ;; #( - *) : - ac_site_file=./$ac_site_file ;; -esac - if test -f "$ac_site_file" && test -r "$ac_site_file"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See 'config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -printf "%s\n" "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -printf "%s\n" "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Test code for whether the C compiler supports C89 (global declarations) -ac_c_conftest_c89_globals=' -/* Does the compiler advertise C89 conformance? - Do not test the value of __STDC__, because some compilers set it to 0 - while being otherwise adequately conformant. */ -#if !defined __STDC__ -# error "Compiler does not advertise C89 conformance" -#endif - -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ -struct buf { int x; }; -struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (char **p, int i) -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* C89 style stringification. */ -#define noexpand_stringify(a) #a -const char *stringified = noexpand_stringify(arbitrary+token=sequence); - -/* C89 style token pasting. Exercises some of the corner cases that - e.g. old MSVC gets wrong, but not very hard. */ -#define noexpand_concat(a,b) a##b -#define expand_concat(a,b) noexpand_concat(a,b) -extern int vA; -extern int vbee; -#define aye A -#define bee B -int *pvA = &expand_concat(v,aye); -int *pvbee = &noexpand_concat(v,bee); - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not \xHH hex character constants. - These do not provoke an error unfortunately, instead are silently treated - as an "x". The following induces an error, until -std is added to get - proper ANSI mode. Curiously \x00 != x always comes out true, for an - array size at least. It is necessary to write \x00 == 0 to get something - that is true only with -std. */ -int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) '\''x'\'' -int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), - int, int);' - -# Test code for whether the C compiler supports C89 (body of main). -ac_c_conftest_c89_main=' -ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); -' - -# Test code for whether the C compiler supports C99 (global declarations) -ac_c_conftest_c99_globals=' -/* Does the compiler advertise C99 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L -# error "Compiler does not advertise C99 conformance" -#endif - -// See if C++-style comments work. - -#include -extern int puts (const char *); -extern int printf (const char *, ...); -extern int dprintf (int, const char *, ...); -extern void *malloc (size_t); -extern void free (void *); - -// Check varargs macros. These examples are taken from C99 6.10.3.5. -// dprintf is used instead of fprintf to avoid needing to declare -// FILE and stderr. -#define debug(...) dprintf (2, __VA_ARGS__) -#define showlist(...) puts (#__VA_ARGS__) -#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) -static void -test_varargs_macros (void) -{ - int x = 1234; - int y = 5678; - debug ("Flag"); - debug ("X = %d\n", x); - showlist (The first, second, and third items.); - report (x>y, "x is %d but y is %d", x, y); -} - -// Check long long types. -#define BIG64 18446744073709551615ull -#define BIG32 4294967295ul -#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) -#if !BIG_OK - #error "your preprocessor is broken" -#endif -#if BIG_OK -#else - #error "your preprocessor is broken" -#endif -static long long int bignum = -9223372036854775807LL; -static unsigned long long int ubignum = BIG64; - -struct incomplete_array -{ - int datasize; - double data[]; -}; - -struct named_init { - int number; - const wchar_t *name; - double average; -}; - -typedef const char *ccp; - -static inline int -test_restrict (ccp restrict text) -{ - // Iterate through items via the restricted pointer. - // Also check for declarations in for loops. - for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) - continue; - return 0; -} - -// Check varargs and va_copy. -static bool -test_varargs (const char *format, ...) -{ - va_list args; - va_start (args, format); - va_list args_copy; - va_copy (args_copy, args); - - const char *str = ""; - int number = 0; - float fnumber = 0; - - while (*format) - { - switch (*format++) - { - case '\''s'\'': // string - str = va_arg (args_copy, const char *); - break; - case '\''d'\'': // int - number = va_arg (args_copy, int); - break; - case '\''f'\'': // float - fnumber = va_arg (args_copy, double); - break; - default: - break; - } - } - va_end (args_copy); - va_end (args); - - return *str && number && fnumber; -} -' - -# Test code for whether the C compiler supports C99 (body of main). -ac_c_conftest_c99_main=' - // Check bool. - _Bool success = false; - success |= (argc != 0); - - // Check restrict. - if (test_restrict ("String literal") == 0) - success = true; - char *restrict newvar = "Another string"; - - // Check varargs. - success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); - test_varargs_macros (); - - // Check flexible array members. - struct incomplete_array *ia = - malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); - ia->datasize = 10; - for (int i = 0; i < ia->datasize; ++i) - ia->data[i] = i * 1.234; - // Work around memory leak warnings. - free (ia); - - // Check named initializers. - struct named_init ni = { - .number = 34, - .name = L"Test wide string", - .average = 543.34343, - }; - - ni.number = 58; - - int dynamic_array[ni.number]; - dynamic_array[0] = argv[0][0]; - dynamic_array[ni.number - 1] = 543; - - // work around unused variable warnings - ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' - || dynamic_array[ni.number - 1] != 543); -' - -# Test code for whether the C compiler supports C11 (global declarations) -ac_c_conftest_c11_globals=' -/* Does the compiler advertise C11 conformance? */ -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L -# error "Compiler does not advertise C11 conformance" -#endif - -// Check _Alignas. -char _Alignas (double) aligned_as_double; -char _Alignas (0) no_special_alignment; -extern char aligned_as_int; -char _Alignas (0) _Alignas (int) aligned_as_int; - -// Check _Alignof. -enum -{ - int_alignment = _Alignof (int), - int_array_alignment = _Alignof (int[100]), - char_alignment = _Alignof (char) -}; -_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); - -// Check _Noreturn. -int _Noreturn does_not_return (void) { for (;;) continue; } - -// Check _Static_assert. -struct test_static_assert -{ - int x; - _Static_assert (sizeof (int) <= sizeof (long int), - "_Static_assert does not work in struct"); - long int y; -}; - -// Check UTF-8 literals. -#define u8 syntax error! -char const utf8_literal[] = u8"happens to be ASCII" "another string"; - -// Check duplicate typedefs. -typedef long *long_ptr; -typedef long int *long_ptr; -typedef long_ptr long_ptr; - -// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. -struct anonymous -{ - union { - struct { int i; int j; }; - struct { int k; long int l; } w; - }; - int m; -} v1; -' - -# Test code for whether the C compiler supports C11 (body of main). -ac_c_conftest_c11_main=' - _Static_assert ((offsetof (struct anonymous, i) - == offsetof (struct anonymous, w.k)), - "Anonymous union alignment botch"); - v1.i = 2; - v1.w.k = 5; - ok |= v1.i != 5; -' - -# Test code for whether the C compiler supports C11 (complete). -ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} -${ac_c_conftest_c11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - ${ac_c_conftest_c11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C99 (complete). -ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (complete). -ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - return ok; -} -" - -# Test code for whether the C++ compiler supports C++98 (global declarations) -ac_cxx_conftest_cxx98_globals=' -// Does the compiler advertise C++98 conformance? -#if !defined __cplusplus || __cplusplus < 199711L -# error "Compiler does not advertise C++98 conformance" -#endif - -// These inclusions are to reject old compilers that -// lack the unsuffixed header files. -#include -#include - -// and are *not* freestanding headers in C++98. -extern void assert (int); -namespace std { - extern int strcmp (const char *, const char *); -} - -// Namespaces, exceptions, and templates were all added after "C++ 2.0". -using std::exception; -using std::strcmp; - -namespace { - -void test_exception_syntax() -{ - try { - throw "test"; - } catch (const char *s) { - // Extra parentheses suppress a warning when building autoconf itself, - // due to lint rules shared with more typical C programs. - assert (!(strcmp) (s, "test")); - } -} - -template struct test_template -{ - T const val; - explicit test_template(T t) : val(t) {} - template T add(U u) { return static_cast(u) + val; } -}; - -} // anonymous namespace -' - -# Test code for whether the C++ compiler supports C++98 (body of main) -ac_cxx_conftest_cxx98_main=' - assert (argc); - assert (! argv[0]); -{ - test_exception_syntax (); - test_template tt (2.0); - assert (tt.add (4) == 6.0); - assert (true && !false); -} -' - -# Test code for whether the C++ compiler supports C++11 (global declarations) -ac_cxx_conftest_cxx11_globals=' -// Does the compiler advertise C++ 2011 conformance? -#if !defined __cplusplus || __cplusplus < 201103L -# error "Compiler does not advertise C++11 conformance" -#endif - -namespace cxx11test -{ - constexpr int get_val() { return 20; } - - struct testinit - { - int i; - double d; - }; - - class delegate - { - public: - delegate(int n) : n(n) {} - delegate(): delegate(2354) {} - - virtual int getval() { return this->n; }; - protected: - int n; - }; - - class overridden : public delegate - { - public: - overridden(int n): delegate(n) {} - virtual int getval() override final { return this->n * 2; } - }; - - class nocopy - { - public: - nocopy(int i): i(i) {} - nocopy() = default; - nocopy(const nocopy&) = delete; - nocopy & operator=(const nocopy&) = delete; - private: - int i; - }; - - // for testing lambda expressions - template Ret eval(Fn f, Ret v) - { - return f(v); - } - - // for testing variadic templates and trailing return types - template auto sum(V first) -> V - { - return first; - } - template auto sum(V first, Args... rest) -> V - { - return first + sum(rest...); - } -} -' - -# Test code for whether the C++ compiler supports C++11 (body of main) -ac_cxx_conftest_cxx11_main=' -{ - // Test auto and decltype - auto a1 = 6538; - auto a2 = 48573953.4; - auto a3 = "String literal"; - - int total = 0; - for (auto i = a3; *i; ++i) { total += *i; } - - decltype(a2) a4 = 34895.034; -} -{ - // Test constexpr - short sa[cxx11test::get_val()] = { 0 }; -} -{ - // Test initializer lists - cxx11test::testinit il = { 4323, 435234.23544 }; -} -{ - // Test range-based for - int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, - 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; - for (auto &x : array) { x += 23; } -} -{ - // Test lambda expressions - using cxx11test::eval; - assert (eval ([](int x) { return x*2; }, 21) == 42); - double d = 2.0; - assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); - assert (d == 5.0); - assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); - assert (d == 5.0); -} -{ - // Test use of variadic templates - using cxx11test::sum; - auto a = sum(1); - auto b = sum(1, 2); - auto c = sum(1.0, 2.0, 3.0); -} -{ - // Test constructor delegation - cxx11test::delegate d1; - cxx11test::delegate d2(); - cxx11test::delegate d3(45); -} -{ - // Test override and final - cxx11test::overridden o1(55464); -} -{ - // Test nullptr - char *c = nullptr; -} -{ - // Test template brackets - test_template<::test_template> v(test_template(12)); -} -{ - // Unicode literals - char const *utf8 = u8"UTF-8 string \u2500"; - char16_t const *utf16 = u"UTF-8 string \u2500"; - char32_t const *utf32 = U"UTF-32 string \u2500"; -} -' - -# Test code for whether the C compiler supports C++11 (complete). -ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} -${ac_cxx_conftest_cxx11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_cxx_conftest_cxx98_main} - ${ac_cxx_conftest_cxx11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C++98 (complete). -ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_cxx_conftest_cxx98_main} - return ok; -} -" - -as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" -as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" -as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" -as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" -as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" -as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" -as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" -as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" -as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" - -# Auxiliary files required by this configure script. -ac_aux_files="config.guess config.sub" - -# Locations in which to look for auxiliary files. -ac_aux_dir_candidates="${srcdir}/tools" - -# Search for a directory containing all of the required auxiliary files, -# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. -# If we don't find one directory that contains all the files we need, -# we report the set of missing files from the *first* directory in -# $ac_aux_dir_candidates and give up. -ac_missing_aux_files="" -ac_first_candidate=: -printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in $ac_aux_dir_candidates -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - - printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 - ac_aux_dir_found=yes - ac_install_sh= - for ac_aux in $ac_aux_files - do - # As a special case, if "install-sh" is required, that requirement - # can be satisfied by any of "install-sh", "install.sh", or "shtool", - # and $ac_install_sh is set appropriately for whichever one is found. - if test x"$ac_aux" = x"install-sh" - then - if test -f "${as_dir}install-sh"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 - ac_install_sh="${as_dir}install-sh -c" - elif test -f "${as_dir}install.sh"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 - ac_install_sh="${as_dir}install.sh -c" - elif test -f "${as_dir}shtool"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 - ac_install_sh="${as_dir}shtool install -c" - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} install-sh" - else - break - fi - fi - else - if test -f "${as_dir}${ac_aux}"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" - else - break - fi - fi - fi - done - if test "$ac_aux_dir_found" = yes; then - ac_aux_dir="$as_dir" - break - fi - ac_first_candidate=false - - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else case e in #( - e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; -esac -fi - - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -if test -f "${ac_aux_dir}config.guess"; then - ac_config_guess="$SHELL ${ac_aux_dir}config.guess" -fi -if test -f "${ac_aux_dir}config.sub"; then - ac_config_sub="$SHELL ${ac_aux_dir}config.sub" -fi -if test -f "$ac_aux_dir/configure"; then - ac_configure="$SHELL ${ac_aux_dir}configure" -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 -printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 -printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 -printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 -printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 -printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 -printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' - and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_config_headers="$ac_config_headers include/config.h" - - - -libwine_version="1.0" - - -# Check whether --enable-archs was given. -if test ${enable_archs+y} -then : - enableval=$enable_archs; -fi - -# Check whether --enable-win16 was given. -if test ${enable_win16+y} -then : - enableval=$enable_win16; -fi - -# Check whether --enable-win64 was given. -if test ${enable_win64+y} -then : - enableval=$enable_win64; -fi - -# Check whether --enable-tests was given. -if test ${enable_tests+y} -then : - enableval=$enable_tests; -fi - -# Check whether --enable-build-id was given. -if test ${enable_build_id+y} -then : - enableval=$enable_build_id; -fi - -# Check whether --enable-maintainer-mode was given. -if test ${enable_maintainer_mode+y} -then : - enableval=$enable_maintainer_mode; -fi - -# Check whether --enable-sast was given. -if test ${enable_sast+y} -then : - enableval=$enable_sast; -fi - -# Check whether --enable-silent-rules was given. -if test ${enable_silent_rules+y} -then : - enableval=$enable_silent_rules; -fi - -# Check whether --enable-werror was given. -if test ${enable_werror+y} -then : - enableval=$enable_werror; -fi - - - -# Check whether --with-alsa was given. -if test ${with_alsa+y} -then : - withval=$with_alsa; -fi - - -# Check whether --with-capi was given. -if test ${with_capi+y} -then : - withval=$with_capi; -fi - - -# Check whether --with-coreaudio was given. -if test ${with_coreaudio+y} -then : - withval=$with_coreaudio; -fi - - -# Check whether --with-cups was given. -if test ${with_cups+y} -then : - withval=$with_cups; -fi - - -# Check whether --with-dbus was given. -if test ${with_dbus+y} -then : - withval=$with_dbus; -fi - - -# Check whether --with-ffmpeg was given. -if test ${with_ffmpeg+y} -then : - withval=$with_ffmpeg; -fi - - -# Check whether --with-fontconfig was given. -if test ${with_fontconfig+y} -then : - withval=$with_fontconfig; -fi - - -# Check whether --with-freetype was given. -if test ${with_freetype+y} -then : - withval=$with_freetype; -fi - - -# Check whether --with-gettext was given. -if test ${with_gettext+y} -then : - withval=$with_gettext; -fi - - -# Check whether --with-gettextpo was given. -if test ${with_gettextpo+y} -then : - withval=$with_gettextpo; if test "x$withval" = "xno"; then ac_cv_header_gettext_po_h=no; fi -fi - - -# Check whether --with-gphoto was given. -if test ${with_gphoto+y} -then : - withval=$with_gphoto; -fi - - -# Check whether --with-gnutls was given. -if test ${with_gnutls+y} -then : - withval=$with_gnutls; -fi - - -# Check whether --with-gssapi was given. -if test ${with_gssapi+y} -then : - withval=$with_gssapi; -fi - - -# Check whether --with-gstreamer was given. -if test ${with_gstreamer+y} -then : - withval=$with_gstreamer; -fi - - -# Check whether --with-inotify was given. -if test ${with_inotify+y} -then : - withval=$with_inotify; -fi - - -# Check whether --with-krb5 was given. -if test ${with_krb5+y} -then : - withval=$with_krb5; -fi - - -# Check whether --with-mingw was given. -if test ${with_mingw+y} -then : - withval=$with_mingw; -fi - - -# Check whether --with-netapi was given. -if test ${with_netapi+y} -then : - withval=$with_netapi; -fi - - -# Check whether --with-opencl was given. -if test ${with_opencl+y} -then : - withval=$with_opencl; if test "x$withval" = "xno"; then ac_cv_header_CL_cl_h=no; ac_cv_header_OpenCL_opencl_h=no; fi -fi - - -# Check whether --with-opengl was given. -if test ${with_opengl+y} -then : - withval=$with_opengl; -fi - - -# Check whether --with-osmesa was given. -if test ${with_osmesa+y} -then : - withval=$with_osmesa; -fi - - -# Check whether --with-oss was given. -if test ${with_oss+y} -then : - withval=$with_oss; -fi - - -# Check whether --with-pcap was given. -if test ${with_pcap+y} -then : - withval=$with_pcap; if test "x$withval" = "xno"; then ac_cv_header_pcap_pcap_h=no; fi -fi - - -# Check whether --with-pcsclite was given. -if test ${with_pcsclite+y} -then : - withval=$with_pcsclite; -fi - - -# Check whether --with-pthread was given. -if test ${with_pthread+y} -then : - withval=$with_pthread; -fi - - -# Check whether --with-pulse was given. -if test ${with_pulse+y} -then : - withval=$with_pulse; -fi - - -# Check whether --with-sane was given. -if test ${with_sane+y} -then : - withval=$with_sane; -fi - - -# Check whether --with-sdl was given. -if test ${with_sdl+y} -then : - withval=$with_sdl; -fi - - -# Check whether --with-udev was given. -if test ${with_udev+y} -then : - withval=$with_udev; -fi - - -# Check whether --with-unwind was given. -if test ${with_unwind+y} -then : - withval=$with_unwind; -fi - - -# Check whether --with-usb was given. -if test ${with_usb+y} -then : - withval=$with_usb; -fi - - -# Check whether --with-v4l2 was given. -if test ${with_v4l2+y} -then : - withval=$with_v4l2; -fi - - -# Check whether --with-vulkan was given. -if test ${with_vulkan+y} -then : - withval=$with_vulkan; -fi - - -# Check whether --with-wayland was given. -if test ${with_wayland+y} -then : - withval=$with_wayland; -fi - - -# Check whether --with-xcomposite was given. -if test ${with_xcomposite+y} -then : - withval=$with_xcomposite; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi -fi - - -# Check whether --with-xcursor was given. -if test ${with_xcursor+y} -then : - withval=$with_xcursor; if test "x$withval" = "xno"; then ac_cv_header_X11_Xcursor_Xcursor_h=no; fi -fi - - -# Check whether --with-xfixes was given. -if test ${with_xfixes+y} -then : - withval=$with_xfixes; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xfixes_h=no; fi -fi - - -# Check whether --with-xinerama was given. -if test ${with_xinerama+y} -then : - withval=$with_xinerama; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xinerama_h=no; fi -fi - - -# Check whether --with-xinput was given. -if test ${with_xinput+y} -then : - withval=$with_xinput; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_XInput_h=no; fi -fi - - -# Check whether --with-xinput2 was given. -if test ${with_xinput2+y} -then : - withval=$with_xinput2; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_XInput2_h=no; fi -fi - - -# Check whether --with-xrandr was given. -if test ${with_xrandr+y} -then : - withval=$with_xrandr; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xrandr_h=no; fi -fi - - -# Check whether --with-xrender was given. -if test ${with_xrender+y} -then : - withval=$with_xrender; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xrender_h=no; fi -fi - - -# Check whether --with-xshape was given. -if test ${with_xshape+y} -then : - withval=$with_xshape; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_shape_h=no; fi -fi - - -# Check whether --with-xshm was given. -if test ${with_xshm+y} -then : - withval=$with_xshm; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_XShm_h=no; fi -fi - - -# Check whether --with-xxf86vm was given. -if test ${with_xxf86vm+y} -then : - withval=$with_xxf86vm; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_xf86vmode_h=no; ac_cv_header_X11_extensions_xf86vmproto_h=no; fi -fi - - - -# Check whether --with-system-dllpath was given. -if test ${with_system_dllpath+y} -then : - withval=$with_system_dllpath; system_dllpath=$withval - -fi - - -# Check whether --with-wine-tools was given. -if test ${with_wine_tools+y} -then : - withval=$with_wine_tools; -fi - - -# Check whether --with-wine64 was given. -if test ${with_wine64+y} -then : - withval=$with_wine64; -fi - - - - - - # Make sure we can run config.sub. -$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -printf %s "checking build system type... " >&6; } -if test ${ac_cv_build+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` -test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 - ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -printf "%s\n" "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -printf %s "checking host system type... " >&6; } -if test ${ac_cv_host+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 -fi - ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -printf "%s\n" "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac - - - - -if test "x$enable_sast" = xyes -then : - CC=${CC:-clang} -with_mingw=${with_mingw:-clang} -for ac_prog in sarif-converter -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_SARIF_CONVERTER+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$SARIF_CONVERTER"; then - ac_cv_prog_SARIF_CONVERTER="$SARIF_CONVERTER" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_SARIF_CONVERTER="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -SARIF_CONVERTER=$ac_cv_prog_SARIF_CONVERTER -if test -n "$SARIF_CONVERTER"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SARIF_CONVERTER" >&5 -printf "%s\n" "$SARIF_CONVERTER" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$SARIF_CONVERTER" && break -done -test -n "$SARIF_CONVERTER" || SARIF_CONVERTER="false" - -fi - - - - - - - - - - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" - fi -fi -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. -set dummy ${ac_tool_prefix}clang; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}clang" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "clang", so it can be a program name with args. -set dummy clang; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="clang" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -fi - - -test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See 'config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion -version; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -printf %s "checking whether the C compiler works... " >&6; } -ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. -# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an '-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else case e in #( - e) ac_file='' ;; -esac -fi -if test -z "$ac_file" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See 'config.log' for more details" "$LINENO" 5; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -printf %s "checking for C compiler default output file name... " >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -printf "%s\n" "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -printf %s "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) -# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will -# work properly (i.e., refer to 'conftest.exe'), while it won't with -# 'rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else case e in #( - e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest conftest$ac_cv_exeext -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -printf "%s\n" "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -FILE *f = fopen ("conftest.out", "w"); - if (!f) - return 1; - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -printf %s "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use '--host'. -See 'config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -printf "%s\n" "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext \ - conftest.o conftest.obj conftest.out -ac_clean_files=$ac_clean_files_save -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -printf %s "checking for suffix of object files... " >&6; } -if test ${ac_cv_objext+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else case e in #( - e) printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -printf "%s\n" "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 -printf %s "checking whether the compiler supports GNU C... " >&6; } -if test ${ac_cv_c_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else case e in #( - e) ac_compiler_gnu=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+y} -ac_save_CFLAGS=$CFLAGS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -printf %s "checking whether $CC accepts -g... " >&6; } -if test ${ac_cv_prog_cc_g+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -else case e in #( - e) CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in #( - e) ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -printf "%s\n" "$ac_cv_prog_cc_g" >&6; } -if test $ac_test_CFLAGS; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -ac_prog_cc_stdc=no -if test x$ac_prog_cc_stdc = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 -printf %s "checking for $CC option to enable C11 features... " >&6; } -if test ${ac_cv_prog_cc_c11+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c11=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c11_program -_ACEOF -for ac_arg in '' -std=gnu11 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c11" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c11" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c11" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 -printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 -printf %s "checking for $CC option to enable C99 features... " >&6; } -if test ${ac_cv_prog_cc_c99+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c99=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c99_program -_ACEOF -for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c99=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c99" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c99" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c99" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 -printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 ;; -esac -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 -printf %s "checking for $CC option to enable C89 features... " >&6; } -if test ${ac_cv_prog_cc_c89+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c89_program -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC ;; -esac -fi - -if test "x$ac_cv_prog_cc_c89" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cc_c89" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" ;; -esac -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 ;; -esac -fi -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - - - - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -z "$CXX"; then - if test -n "$CCC"; then - CXX=$CCC - else - if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CXX+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -printf "%s\n" "$CXX" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CXX+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -printf "%s\n" "$ac_ct_CXX" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$ac_ct_CXX" && break -done - - if test "x$ac_ct_CXX" = x; then - CXX="g++" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CXX=$ac_ct_CXX - fi -fi - - fi -fi -# Provide some information about the compiler. -printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 -printf %s "checking whether the compiler supports GNU C++... " >&6; } -if test ${ac_cv_cxx_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else case e in #( - e) ac_compiler_gnu=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GXX=yes -else - GXX= -fi -ac_test_CXXFLAGS=${CXXFLAGS+y} -ac_save_CXXFLAGS=$CXXFLAGS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 -printf %s "checking whether $CXX accepts -g... " >&6; } -if test ${ac_cv_prog_cxx_g+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_save_cxx_werror_flag=$ac_cxx_werror_flag - ac_cxx_werror_flag=yes - ac_cv_prog_cxx_g=no - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_g=yes -else case e in #( - e) CXXFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - -else case e in #( - e) ac_cxx_werror_flag=$ac_save_cxx_werror_flag - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } -if test $ac_test_CXXFLAGS; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -ac_prog_cxx_stdcxx=no -if test x$ac_prog_cxx_stdcxx = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 -printf %s "checking for $CXX option to enable C++11 features... " >&6; } -if test ${ac_cv_prog_cxx_cxx11+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cxx_cxx11=no -ac_save_CXX=$CXX -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_cxx_conftest_cxx11_program -_ACEOF -for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA -do - CXX="$ac_save_CXX $ac_arg" - if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_cxx11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cxx_cxx11" != "xno" && break -done -rm -f conftest.$ac_ext -CXX=$ac_save_CXX ;; -esac -fi - -if test "x$ac_cv_prog_cxx_cxx11" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cxx_cxx11" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 -printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx11" ;; -esac -fi - ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 - ac_prog_cxx_stdcxx=cxx11 ;; -esac -fi -fi -if test x$ac_prog_cxx_stdcxx = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 -printf %s "checking for $CXX option to enable C++98 features... " >&6; } -if test ${ac_cv_prog_cxx_cxx98+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_cv_prog_cxx_cxx98=no -ac_save_CXX=$CXX -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_cxx_conftest_cxx98_program -_ACEOF -for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA -do - CXX="$ac_save_CXX $ac_arg" - if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_cxx98=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cxx_cxx98" != "xno" && break -done -rm -f conftest.$ac_ext -CXX=$ac_save_CXX ;; -esac -fi - -if test "x$ac_cv_prog_cxx_cxx98" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else case e in #( - e) if test "x$ac_cv_prog_cxx_cxx98" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 -printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx98" ;; -esac -fi - ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 - ac_prog_cxx_stdcxx=cxx98 ;; -esac -fi -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cpp", so it can be a program name with args. -set dummy ${ac_tool_prefix}cpp; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CPPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CPPBIN"; then - ac_cv_prog_CPPBIN="$CPPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CPPBIN="${ac_tool_prefix}cpp" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CPPBIN=$ac_cv_prog_CPPBIN -if test -n "$CPPBIN"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPPBIN" >&5 -printf "%s\n" "$CPPBIN" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CPPBIN"; then - ac_ct_CPPBIN=$CPPBIN - # Extract the first word of "cpp", so it can be a program name with args. -set dummy cpp; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CPPBIN+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_CPPBIN"; then - ac_cv_prog_ac_ct_CPPBIN="$ac_ct_CPPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CPPBIN="cpp" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_CPPBIN=$ac_cv_prog_ac_ct_CPPBIN -if test -n "$ac_ct_CPPBIN"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CPPBIN" >&5 -printf "%s\n" "$ac_ct_CPPBIN" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_CPPBIN" = x; then - CPPBIN="cpp" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CPPBIN=$ac_ct_CPPBIN - fi -else - CPPBIN="$ac_cv_prog_CPPBIN" -fi - - -printf "%s\n" "#define EXEEXT \"$ac_exeext\"" >>confdefs.h - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. -set dummy ${ac_tool_prefix}ld; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_LD+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$LD"; then - ac_cv_prog_LD="$LD" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_LD="${ac_tool_prefix}ld" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -LD=$ac_cv_prog_LD -if test -n "$LD"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 -printf "%s\n" "$LD" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_LD"; then - ac_ct_LD=$LD - # Extract the first word of "ld", so it can be a program name with args. -set dummy ld; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_LD+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_LD"; then - ac_cv_prog_ac_ct_LD="$ac_ct_LD" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_LD="ld" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_LD=$ac_cv_prog_ac_ct_LD -if test -n "$ac_ct_LD"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LD" >&5 -printf "%s\n" "$ac_ct_LD" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_LD" = x; then - LD="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - LD=$ac_ct_LD - fi -else - LD="$ac_cv_prog_LD" -fi - - -case $host in - *-darwin*) - with_fontconfig=${with_fontconfig:-no} - ;; - *-mingw32*|*-cygwin*) - enable_win16=${enable_win16:-no} - with_mingw=${with_mingw:-no} - ;; -esac - - -case $host in - x86_64*|amd64*) - if test "x$enable_win64" != "xyes" -a "$cross_compiling" != "yes" -a x"$enable_archs" = x - then - CC="$CC -m32" - CXX="$CXX -m32" - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC works" >&5 -printf %s "checking whether $CC works... " >&6; } -if test ${wine_cv_cc_m32+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_cc_m32=yes -else case e in #( - e) wine_cv_cc_m32=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_cc_m32" >&5 -printf "%s\n" "$wine_cv_cc_m32" >&6; } - test $wine_cv_cc_m32 != no || as_fn_error $? "Cannot build a 32-bit program, you need to install 32-bit development libraries." "$LINENO" 5 - host_cpu="i386" - notice_platform="32-bit " - TARGETFLAGS="$TARGETFLAGS -m32" - PKG_CONFIG_LIBDIR=${PKG_CONFIG_LIBDIR:-/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib32/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig} - export PKG_CONFIG_LIBDIR - else - CC="$CC -m64" - CXX="$CXX -m64" - host_cpu="x86_64" - notice_platform="64-bit " - TARGETFLAGS="$TARGETFLAGS -m64" - fi - ;; - arm*) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports Thumb-2" >&5 -printf %s "checking whether $CC supports Thumb-2... " >&6; } -if test ${wine_cv_thumb2+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -asm(".syntax unified\n\t.thumb\n\tldm r0,{r0-r8}"); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_thumb2=yes -else case e in #( - e) wine_cv_thumb2=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_thumb2" >&5 -printf "%s\n" "$wine_cv_thumb2" >&6; } - if test x"$wine_cv_thumb2" = xyes - then - CFLAGS="$CFLAGS -mthumb" - else - CFLAGS="$CFLAGS -marm" - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports floating point instructions" >&5 -printf %s "checking whether $CC supports floating point instructions... " >&6; } -if test ${wine_cv_float_abi+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -asm("vmrs r2,fpscr"); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_float_abi=yes -else case e in #( - e) wine_cv_float_abi=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_float_abi" >&5 -printf "%s\n" "$wine_cv_float_abi" >&6; } - test $wine_cv_float_abi != no || as_fn_error $? "The ARM target needs to support floating point instructions." "$LINENO" 5 - ;; -esac - -if test "x$enable_win64" = "xyes" -then - test -z "$with_wine64" || as_fn_error $? "--enable-win64 and --with-wine64 are mutually exclusive. ---enable-win64 should be used in the 64-bit build tree, --with-wine64 in the 32-bit Wow64 build tree." "$LINENO" 5 -fi - -case $build_os in - cygwin*|mingw32*) toolsext=".exe" - ;; - *) toolsext="" - ;; -esac - -HOST_ARCH=unknown -case "$host_cpu" in - aarch64*) HOST_ARCH=aarch64 ;; - arm*) HOST_ARCH=arm ;; - i[3456789]86*) HOST_ARCH=i386 ;; - x86_64) HOST_ARCH=x86_64 ;; -esac - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the directory containing the Wine tools" >&5 -printf %s "checking for the directory containing the Wine tools... " >&6; } -if test ${wine_cv_toolsdir+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) wine_cv_toolsdir="$with_wine_tools" - if test -z "$with_wine_tools"; then - if test "$cross_compiling" = "yes"; then - as_fn_error $? "you must use the --with-wine-tools option when cross-compiling." "$LINENO" 5 - elif test -n "$with_wine64"; then - wine_cv_toolsdir="$with_wine64" - fi - fi ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_toolsdir" >&5 -printf "%s\n" "$wine_cv_toolsdir" >&6; } -if test -z "$wine_cv_toolsdir"; then - wine_makedep=tools/makedep$toolsext -elif test -d "$wine_cv_toolsdir/tools/winebuild"; then - wine_makedep=$wine_cv_toolsdir/tools/makedep$toolsext - enable_tools=${enable_tools:-no} - test -f "$wine_makedep" || as_fn_error $? "the Wine tools have not yet been built in $wine_cv_toolsdir" "$LINENO" 5 -else - as_fn_error $? "could not find Wine tools in $wine_cv_toolsdir" "$LINENO" 5 -fi -toolsdir=$wine_cv_toolsdir - -RUNTESTFLAGS="-q -P wine" - -SED_CMD="LC_ALL=C sed -e 's,@bindir@,\${bindir},g' -e 's,@PACKAGE_STRING@,$PACKAGE_STRING,g' -e 's,@PACKAGE_VERSION@,$PACKAGE_VERSION,g'" - - -if test -n "$host_alias" -a "$host_alias" != "$build_alias" -then - TARGETFLAGS="-b $host_alias $TARGETFLAGS" -fi - -for ac_prog in flex -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_FLEX+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$FLEX"; then - ac_cv_prog_FLEX="$FLEX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_FLEX="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -FLEX=$ac_cv_prog_FLEX -if test -n "$FLEX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FLEX" >&5 -printf "%s\n" "$FLEX" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$FLEX" && break -done -test -n "$FLEX" || FLEX="none" - -if test "$FLEX" = "none" -then - as_fn_error $? "no suitable flex found. Please install the 'flex' package." "$LINENO" 5 -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether flex is recent enough" >&5 -printf %s "checking whether flex is recent enough... " >&6; } -if test ${wine_cv_recent_flex+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat >conftest.l </dev/null 2>&5 - then - wine_cv_recent_flex=yes - else - wine_cv_recent_flex=no - fi ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_recent_flex" >&5 -printf "%s\n" "$wine_cv_recent_flex" >&6; } -test $wine_cv_recent_flex != no || as_fn_error $? "Your flex version is too old. Please install flex version 2.5.33 or newer." "$LINENO" 5 - -for ac_prog in bison -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_BISON+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$BISON"; then - ac_cv_prog_BISON="$BISON" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_BISON="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -BISON=$ac_cv_prog_BISON -if test -n "$BISON"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BISON" >&5 -printf "%s\n" "$BISON" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$BISON" && break -done -test -n "$BISON" || BISON="none" - -if test "$BISON" = "none" -then - as_fn_error $? "no suitable bison found. Please install the 'bison' package." "$LINENO" 5 -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether bison is recent enough" >&5 -printf %s "checking whether bison is recent enough... " >&6; } -if test ${wine_cv_recent_bison+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat >conftest.y </dev/null 2>&5 - then - wine_cv_recent_bison=yes - else - wine_cv_recent_bison=no - fi ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_recent_bison" >&5 -printf "%s\n" "$wine_cv_recent_bison" >&6; } -test $wine_cv_recent_bison != no || as_fn_error $? "Your bison version is too old. Please install bison version 3.0 or newer." "$LINENO" 5 - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf "%s\n" "$STRIP" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf "%s\n" "$ac_ct_STRIP" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP="strip" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -printf %s "checking whether ln -s works... " >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -printf "%s\n" "no, using $LN_S" >&6; } -fi - -if test ${ac_tool_prefix+y} -then : - # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. -set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$PKG_CONFIG"; then - ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -PKG_CONFIG=$ac_cv_prog_PKG_CONFIG -if test -n "$PKG_CONFIG"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -printf "%s\n" "$PKG_CONFIG" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if ${ac_cv_prog_PKG_CONFIG:+false} : -then : - if test "x$cross_compiling" = xyes -then : - -else case e in #( - e) { ac_cv_prog_PKG_CONFIG=; unset ac_cv_prog_PKG_CONFIG;} - # Extract the first word of "pkg-config", so it can be a program name with args. -set dummy pkg-config; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$PKG_CONFIG"; then - ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_PKG_CONFIG="pkg-config" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -PKG_CONFIG=$ac_cv_prog_PKG_CONFIG -if test -n "$PKG_CONFIG"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -printf "%s\n" "$PKG_CONFIG" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - ;; -esac -fi -else case e in #( - e) PKG_CONFIG=$ac_cv_prog_PKG_CONFIG ;; -esac -fi - -if test "x$enable_maintainer_mode" != "xyes" -then - FONTFORGE="" - RSVG="" - CONVERT="" - ICOTOOL="" -else - test "$srcdir" = . || as_fn_error $? "Maintainer mode cannot work out of tree." "$LINENO" 5 - for ac_prog in fontforge -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_FONTFORGE+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$FONTFORGE"; then - ac_cv_prog_FONTFORGE="$FONTFORGE" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_FONTFORGE="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -FONTFORGE=$ac_cv_prog_FONTFORGE -if test -n "$FONTFORGE"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FONTFORGE" >&5 -printf "%s\n" "$FONTFORGE" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$FONTFORGE" && break -done -test -n "$FONTFORGE" || FONTFORGE="false" - - for ac_prog in rsvg-convert rsvg -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_RSVG+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$RSVG"; then - ac_cv_prog_RSVG="$RSVG" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_RSVG="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -RSVG=$ac_cv_prog_RSVG -if test -n "$RSVG"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RSVG" >&5 -printf "%s\n" "$RSVG" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$RSVG" && break -done -test -n "$RSVG" || RSVG="false" - - for ac_prog in convert -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CONVERT+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$CONVERT"; then - ac_cv_prog_CONVERT="$CONVERT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CONVERT="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -CONVERT=$ac_cv_prog_CONVERT -if test -n "$CONVERT"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CONVERT" >&5 -printf "%s\n" "$CONVERT" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$CONVERT" && break -done -test -n "$CONVERT" || CONVERT="false" - - for ac_prog in icotool -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ICOTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ICOTOOL"; then - ac_cv_prog_ICOTOOL="$ICOTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ICOTOOL="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ICOTOOL=$ac_cv_prog_ICOTOOL -if test -n "$ICOTOOL"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ICOTOOL" >&5 -printf "%s\n" "$ICOTOOL" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$ICOTOOL" && break -done -test -n "$ICOTOOL" || ICOTOOL="false" - - test "$FONTFORGE" != "false" || as_fn_error $? "You need fontforge to rebuild fonts in maintainer mode." "$LINENO" 5 - test "$RSVG" != "false" || as_fn_error $? "You need rsvg to rebuild icons in maintainer mode." "$LINENO" 5 - - if test "$CONVERT" = false - then - as_fn_error $? "You need imagemagick to rebuild icons in maintainer mode." "$LINENO" 5 - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for recent enough imagemagick" >&5 -printf %s "checking for recent enough imagemagick... " >&6; } - convert_version=`convert --version | head -n1` - if test "x$convert_version" != "x" - then - convert_version_major=`expr "$convert_version" : '.* \([0-9]*\)\.[0-9]*'` - convert_version_minor=`expr "$convert_version" : '.* [0-9]*\.\([0-9]*\)'` - if test "$convert_version_major" -eq 6 -a "$convert_version_minor" -lt 6 - then - CONVERT=false - fi - fi - if test "$CONVERT" = false - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no ($convert_version_major.$convert_version_minor)" >&5 -printf "%s\n" "no ($convert_version_major.$convert_version_minor)" >&6; } - as_fn_error $? "You need imagemagick version 6.6 or newer to rebuild icons in maintainer mode." "$LINENO" 5 - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($convert_version_major.$convert_version_minor)" >&5 -printf "%s\n" "yes ($convert_version_major.$convert_version_minor)" >&6; } - fi - fi - - if test "$ICOTOOL" = false - then - as_fn_error $? "You need icotool to rebuild icons in maintainer mode." "$LINENO" 5 - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for recent enough icotool" >&5 -printf %s "checking for recent enough icotool... " >&6; } - icotool_version=`icotool --version | head -n1` - if test "x$icotool_version" != "x" - then - icotool_version_major=`expr "$icotool_version" : '.* \([0-9]*\)\.[0-9]*'` - icotool_version_minor=`expr "$icotool_version" : '.* [0-9]*\.\([0-9]*\)'` - if test "$icotool_version_major" -eq 0 -a "$icotool_version_minor" -lt 29 - then - ICOTOOL=false - as_fn_append wine_warnings "|icotool version 0.29.0 or newer is needed to rebuild icons." - fi - fi - if test "$ICOTOOL" = false - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no ($icotool_version_major.$icotool_version_minor)" >&5 -printf "%s\n" "no ($icotool_version_major.$icotool_version_minor)" >&6; } - as_fn_error $? "You need icotool version 0.29.0 or newer to rebuild icons in maintainer mode." "$LINENO" 5 - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($icotool_version_major.$icotool_version_minor)" >&5 -printf "%s\n" "yes ($icotool_version_major.$icotool_version_minor)" >&6; } - fi - fi - - with_gettext=yes - with_gettextpo=yes - - enable_werror=yes -fi - -if test "x$with_gettext" != xno -then - for ac_prog in msgfmt -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_MSGFMT+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$MSGFMT"; then - ac_cv_prog_MSGFMT="$MSGFMT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_MSGFMT="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -MSGFMT=$ac_cv_prog_MSGFMT -if test -n "$MSGFMT"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 -printf "%s\n" "$MSGFMT" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$MSGFMT" && break -done -test -n "$MSGFMT" || MSGFMT="false" - - if test "$MSGFMT" != "false" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether msgfmt supports contexts" >&5 -printf %s "checking whether msgfmt supports contexts... " >&6; } -if test ${wine_cv_msgfmt_contexts+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat >conftest.po <&5 - then - wine_cv_msgfmt_contexts=yes - else - wine_cv_msgfmt_contexts=no - fi ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_msgfmt_contexts" >&5 -printf "%s\n" "$wine_cv_msgfmt_contexts" >&6; } - test $wine_cv_msgfmt_contexts != no || MSGFMT=false - fi -else - MSGFMT=false -fi -if test "$MSGFMT" = false -then : - case "x$with_gettext" in - x) as_fn_append wine_warnings "|gettext tools not found (or too old), translations won't be built." ;; - xno) ;; - *) as_fn_error $? "gettext tools not found (or too old), translations won't be built. -This is an error since --with-gettext was requested." "$LINENO" 5 ;; -esac -enable_po=${enable_po:-no} -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for i386_set_ldt in -li386" >&5 -printf %s "checking for i386_set_ldt in -li386... " >&6; } -if test ${ac_cv_lib_i386_i386_set_ldt+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-li386 $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char i386_set_ldt (void); -int -main (void) -{ -return i386_set_ldt (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_i386_i386_set_ldt=yes -else case e in #( - e) ac_cv_lib_i386_i386_set_ldt=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_i386_i386_set_ldt" >&5 -printf "%s\n" "$ac_cv_lib_i386_i386_set_ldt" >&6; } -if test "x$ac_cv_lib_i386_i386_set_ldt" = xyes -then : - I386_LIBS="-li386" - -fi - - -OPENGL_LIBS="" - - - -# Check whether --enable-largefile was given. -if test ${enable_largefile+y} -then : - enableval=$enable_largefile; -fi -if test "$enable_largefile,$enable_year2038" != no,no -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable large file support" >&5 -printf %s "checking for $CC option to enable large file support... " >&6; } -if test ${ac_cv_sys_largefile_opts+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_save_CC="$CC" - ac_opt_found=no - for ac_opt in "none needed" "-D_FILE_OFFSET_BITS=64" "-D_LARGE_FILES=1" "-n32"; do - if test x"$ac_opt" != x"none needed" -then : - CC="$ac_save_CC $ac_opt" -fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#ifndef FTYPE -# define FTYPE off_t -#endif - /* Check that FTYPE can represent 2**63 - 1 correctly. - We can't simply define LARGE_FTYPE to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_FTYPE (((FTYPE) 1 << 31 << 31) - 1 + ((FTYPE) 1 << 31 << 31)) - int FTYPE_is_large[(LARGE_FTYPE % 2147483629 == 721 - && LARGE_FTYPE % 2147483647 == 1) - ? 1 : -1]; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - if test x"$ac_opt" = x"none needed" -then : - # GNU/Linux s390x and alpha need _FILE_OFFSET_BITS=64 for wide ino_t. - CC="$CC -DFTYPE=ino_t" - if ac_fn_c_try_compile "$LINENO" -then : - -else case e in #( - e) CC="$CC -D_FILE_OFFSET_BITS=64" - if ac_fn_c_try_compile "$LINENO" -then : - ac_opt='-D_FILE_OFFSET_BITS=64' -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam -fi - ac_cv_sys_largefile_opts=$ac_opt - ac_opt_found=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - test $ac_opt_found = no || break - done - CC="$ac_save_CC" - - test $ac_opt_found = yes || ac_cv_sys_largefile_opts="support not detected" ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_opts" >&5 -printf "%s\n" "$ac_cv_sys_largefile_opts" >&6; } - -ac_have_largefile=yes -case $ac_cv_sys_largefile_opts in #( - "none needed") : - ;; #( - "supported through gnulib") : - ;; #( - "support not detected") : - ac_have_largefile=no ;; #( - "-D_FILE_OFFSET_BITS=64") : - -printf "%s\n" "#define _FILE_OFFSET_BITS 64" >>confdefs.h - ;; #( - "-D_LARGE_FILES=1") : - -printf "%s\n" "#define _LARGE_FILES 1" >>confdefs.h - ;; #( - "-n32") : - CC="$CC -n32" ;; #( - *) : - as_fn_error $? "internal error: bad value for \$ac_cv_sys_largefile_opts" "$LINENO" 5 ;; -esac - -if test "$enable_year2038" != no -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option for timestamps after 2038" >&5 -printf %s "checking for $CC option for timestamps after 2038... " >&6; } -if test ${ac_cv_sys_year2038_opts+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_save_CPPFLAGS="$CPPFLAGS" - ac_opt_found=no - for ac_opt in "none needed" "-D_TIME_BITS=64" "-D__MINGW_USE_VC2005_COMPAT" "-U_USE_32_BIT_TIME_T -D__MINGW_USE_VC2005_COMPAT"; do - if test x"$ac_opt" != x"none needed" -then : - CPPFLAGS="$ac_save_CPPFLAGS $ac_opt" -fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - /* Check that time_t can represent 2**32 - 1 correctly. */ - #define LARGE_TIME_T \\ - ((time_t) (((time_t) 1 << 30) - 1 + 3 * ((time_t) 1 << 30))) - int verify_time_t_range[(LARGE_TIME_T / 65537 == 65535 - && LARGE_TIME_T % 65537 == 0) - ? 1 : -1]; - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_sys_year2038_opts="$ac_opt" - ac_opt_found=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - test $ac_opt_found = no || break - done - CPPFLAGS="$ac_save_CPPFLAGS" - test $ac_opt_found = yes || ac_cv_sys_year2038_opts="support not detected" ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_year2038_opts" >&5 -printf "%s\n" "$ac_cv_sys_year2038_opts" >&6; } - -ac_have_year2038=yes -case $ac_cv_sys_year2038_opts in #( - "none needed") : - ;; #( - "support not detected") : - ac_have_year2038=no ;; #( - "-D_TIME_BITS=64") : - -printf "%s\n" "#define _TIME_BITS 64" >>confdefs.h - ;; #( - "-D__MINGW_USE_VC2005_COMPAT") : - -printf "%s\n" "#define __MINGW_USE_VC2005_COMPAT 1" >>confdefs.h - ;; #( - "-U_USE_32_BIT_TIME_T"*) : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "the 'time_t' type is currently forced to be 32-bit. It -will stop working after mid-January 2038. Remove -_USE_32BIT_TIME_T from the compiler flags. -See 'config.log' for more details" "$LINENO" 5; } ;; #( - *) : - as_fn_error $? "internal error: bad value for \$ac_cv_sys_year2038_opts" "$LINENO" 5 ;; -esac - -fi - -fi -if false -then : - if test "$enable_year2038,$ac_have_year2038,$cross_compiling" = yes,no,no -then : - # If we're not cross compiling and 'touch' works with a large - # timestamp, then we can presume the system supports wider time_t - # *somehow* and we just weren't able to detect it. One common - # case that we deliberately *don't* probe for is a system that - # supports both 32- and 64-bit ABIs but only the 64-bit ABI offers - # wide time_t. (It would be inappropriate for us to override an - # intentional use of -m32.) Error out, demanding use of - # --disable-year2038 if this is intentional. - if TZ=UTC0 touch -t 210602070628.15 conftest.time 2>/dev/null -then : - case `TZ=UTC0 LC_ALL=C ls -l conftest.time 2>/dev/null` in #( - *'Feb 7 2106'* | *'Feb 7 17:10'*) : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "this system appears to support timestamps after -mid-January 2038, but no mechanism for enabling wide -'time_t' was detected. Did you mean to build a 64-bit -binary? (E.g., 'CC=\"${CC} -m64\"'.) To proceed with -32-bit time_t, configure with '--disable-year2038'. -See 'config.log' for more details" "$LINENO" 5; } ;; #( - *) : - ;; -esac -fi -fi -fi - -ac_header= ac_cache= -for ac_item in $ac_header_c_list -do - if test $ac_cache; then - ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" - if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then - printf "%s\n" "#define $ac_item 1" >> confdefs.h - fi - ac_header= ac_cache= - elif test $ac_header; then - ac_cache=$ac_item - else - ac_header=$ac_item - fi -done - - - - - - - - -if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes -then : - -printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "CL/cl.h" "ac_cv_header_CL_cl_h" "$ac_includes_default" -if test "x$ac_cv_header_CL_cl_h" = xyes -then : - printf "%s\n" "#define HAVE_CL_CL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "EGL/egl.h" "ac_cv_header_EGL_egl_h" "$ac_includes_default" -if test "x$ac_cv_header_EGL_egl_h" = xyes -then : - printf "%s\n" "#define HAVE_EGL_EGL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "OpenCL/opencl.h" "ac_cv_header_OpenCL_opencl_h" "$ac_includes_default" -if test "x$ac_cv_header_OpenCL_opencl_h" = xyes -then : - printf "%s\n" "#define HAVE_OPENCL_OPENCL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default" -if test "x$ac_cv_header_arpa_inet_h" = xyes -then : - printf "%s\n" "#define HAVE_ARPA_INET_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "arpa/nameser.h" "ac_cv_header_arpa_nameser_h" "$ac_includes_default" -if test "x$ac_cv_header_arpa_nameser_h" = xyes -then : - printf "%s\n" "#define HAVE_ARPA_NAMESER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "asm/termbits.h" "ac_cv_header_asm_termbits_h" "$ac_includes_default" -if test "x$ac_cv_header_asm_termbits_h" = xyes -then : - printf "%s\n" "#define HAVE_ASM_TERMBITS_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "asm/types.h" "ac_cv_header_asm_types_h" "$ac_includes_default" -if test "x$ac_cv_header_asm_types_h" = xyes -then : - printf "%s\n" "#define HAVE_ASM_TYPES_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "asm/user.h" "ac_cv_header_asm_user_h" "$ac_includes_default" -if test "x$ac_cv_header_asm_user_h" = xyes -then : - printf "%s\n" "#define HAVE_ASM_USER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "elf.h" "ac_cv_header_elf_h" "$ac_includes_default" -if test "x$ac_cv_header_elf_h" = xyes -then : - printf "%s\n" "#define HAVE_ELF_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "gettext-po.h" "ac_cv_header_gettext_po_h" "$ac_includes_default" -if test "x$ac_cv_header_gettext_po_h" = xyes -then : - printf "%s\n" "#define HAVE_GETTEXT_PO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "link.h" "ac_cv_header_link_h" "$ac_includes_default" -if test "x$ac_cv_header_link_h" = xyes -then : - printf "%s\n" "#define HAVE_LINK_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/cdrom.h" "ac_cv_header_linux_cdrom_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_cdrom_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_CDROM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/filter.h" "ac_cv_header_linux_filter_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_filter_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_FILTER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/hdreg.h" "ac_cv_header_linux_hdreg_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_hdreg_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_HDREG_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/hidraw.h" "ac_cv_header_linux_hidraw_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_hidraw_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_HIDRAW_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/input.h" "ac_cv_header_linux_input_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_input_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_INPUT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/ioctl.h" "ac_cv_header_linux_ioctl_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_ioctl_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_IOCTL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/major.h" "ac_cv_header_linux_major_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_major_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_MAJOR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/param.h" "ac_cv_header_linux_param_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_param_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_PARAM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/serial.h" "ac_cv_header_linux_serial_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_serial_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_SERIAL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_types_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_TYPES_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/ucdrom.h" "ac_cv_header_linux_ucdrom_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_ucdrom_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_UCDROM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/wireless.h" "ac_cv_header_linux_wireless_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_wireless_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_WIRELESS_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "lwp.h" "ac_cv_header_lwp_h" "$ac_includes_default" -if test "x$ac_cv_header_lwp_h" = xyes -then : - printf "%s\n" "#define HAVE_LWP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "mach-o/loader.h" "ac_cv_header_mach_o_loader_h" "$ac_includes_default" -if test "x$ac_cv_header_mach_o_loader_h" = xyes -then : - printf "%s\n" "#define HAVE_MACH_O_LOADER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "mach/mach.h" "ac_cv_header_mach_mach_h" "$ac_includes_default" -if test "x$ac_cv_header_mach_mach_h" = xyes -then : - printf "%s\n" "#define HAVE_MACH_MACH_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "machine/cpu.h" "ac_cv_header_machine_cpu_h" "$ac_includes_default" -if test "x$ac_cv_header_machine_cpu_h" = xyes -then : - printf "%s\n" "#define HAVE_MACHINE_CPU_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "machine/sysarch.h" "ac_cv_header_machine_sysarch_h" "$ac_includes_default" -if test "x$ac_cv_header_machine_sysarch_h" = xyes -then : - printf "%s\n" "#define HAVE_MACHINE_SYSARCH_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "mntent.h" "ac_cv_header_mntent_h" "$ac_includes_default" -if test "x$ac_cv_header_mntent_h" = xyes -then : - printf "%s\n" "#define HAVE_MNTENT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" -if test "x$ac_cv_header_netdb_h" = xyes -then : - printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$ac_includes_default" -if test "x$ac_cv_header_netinet_in_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/in_systm.h" "ac_cv_header_netinet_in_systm_h" "$ac_includes_default" -if test "x$ac_cv_header_netinet_in_systm_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IN_SYSTM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/tcp.h" "ac_cv_header_netinet_tcp_h" "$ac_includes_default" -if test "x$ac_cv_header_netinet_tcp_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_TCP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/tcp_fsm.h" "ac_cv_header_netinet_tcp_fsm_h" "$ac_includes_default" -if test "x$ac_cv_header_netinet_tcp_fsm_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_TCP_FSM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "pcap/pcap.h" "ac_cv_header_pcap_pcap_h" "$ac_includes_default" -if test "x$ac_cv_header_pcap_pcap_h" = xyes -then : - printf "%s\n" "#define HAVE_PCAP_PCAP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "port.h" "ac_cv_header_port_h" "$ac_includes_default" -if test "x$ac_cv_header_port_h" = xyes -then : - printf "%s\n" "#define HAVE_PORT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "pwd.h" "ac_cv_header_pwd_h" "$ac_includes_default" -if test "x$ac_cv_header_pwd_h" = xyes -then : - printf "%s\n" "#define HAVE_PWD_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sched.h" "ac_cv_header_sched_h" "$ac_includes_default" -if test "x$ac_cv_header_sched_h" = xyes -then : - printf "%s\n" "#define HAVE_SCHED_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "scsi/scsi.h" "ac_cv_header_scsi_scsi_h" "$ac_includes_default" -if test "x$ac_cv_header_scsi_scsi_h" = xyes -then : - printf "%s\n" "#define HAVE_SCSI_SCSI_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "scsi/scsi_ioctl.h" "ac_cv_header_scsi_scsi_ioctl_h" "$ac_includes_default" -if test "x$ac_cv_header_scsi_scsi_ioctl_h" = xyes -then : - printf "%s\n" "#define HAVE_SCSI_SCSI_IOCTL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "scsi/sg.h" "ac_cv_header_scsi_sg_h" "$ac_includes_default" -if test "x$ac_cv_header_scsi_sg_h" = xyes -then : - printf "%s\n" "#define HAVE_SCSI_SG_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/attr.h" "ac_cv_header_sys_attr_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_attr_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_ATTR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/auxv.h" "ac_cv_header_sys_auxv_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_auxv_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_AUXV_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/cdio.h" "ac_cv_header_sys_cdio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_cdio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_CDIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/epoll.h" "ac_cv_header_sys_epoll_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_epoll_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_EPOLL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/event.h" "ac_cv_header_sys_event_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_event_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_EVENT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/extattr.h" "ac_cv_header_sys_extattr_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_extattr_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_EXTATTR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/filio.h" "ac_cv_header_sys_filio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_filio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_FILIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/ipc.h" "ac_cv_header_sys_ipc_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_ipc_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_IPC_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/link.h" "ac_cv_header_sys_link_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_link_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_LINK_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/modem.h" "ac_cv_header_sys_modem_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_modem_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_MODEM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/mtio.h" "ac_cv_header_sys_mtio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mtio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_MTIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_param_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/prctl.h" "ac_cv_header_sys_prctl_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_prctl_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_PRCTL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/ptrace.h" "ac_cv_header_sys_ptrace_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_ptrace_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_PTRACE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/queue.h" "ac_cv_header_sys_queue_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_queue_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_QUEUE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_random_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_RANDOM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_resource_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_RESOURCE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/scsiio.h" "ac_cv_header_sys_scsiio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_scsiio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SCSIIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/shm.h" "ac_cv_header_sys_shm_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_shm_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SHM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/signal.h" "ac_cv_header_sys_signal_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_signal_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SIGNAL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/socketvar.h" "ac_cv_header_sys_socketvar_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_socketvar_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SOCKETVAR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/sockio.h" "ac_cv_header_sys_sockio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sockio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SOCKIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/statvfs.h" "ac_cv_header_sys_statvfs_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_statvfs_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_STATVFS_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/strtio.h" "ac_cv_header_sys_strtio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_strtio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_STRTIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/syscall.h" "ac_cv_header_sys_syscall_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_syscall_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SYSCALL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/sysinfo.h" "ac_cv_header_sys_sysinfo_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysinfo_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SYSINFO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/times.h" "ac_cv_header_sys_times_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_times_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_TIMES_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/uio.h" "ac_cv_header_sys_uio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_uio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_UIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/user.h" "ac_cv_header_sys_user_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_user_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_USER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/utsname.h" "ac_cv_header_sys_utsname_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_utsname_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_UTSNAME_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/vnode.h" "ac_cv_header_sys_vnode_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_vnode_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_VNODE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/xattr.h" "ac_cv_header_sys_xattr_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_xattr_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_XATTR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "syscall.h" "ac_cv_header_syscall_h" "$ac_includes_default" -if test "x$ac_cv_header_syscall_h" = xyes -then : - printf "%s\n" "#define HAVE_SYSCALL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "utime.h" "ac_cv_header_utime_h" "$ac_includes_default" -if test "x$ac_cv_header_utime_h" = xyes -then : - printf "%s\n" "#define HAVE_UTIME_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "valgrind/memcheck.h" "ac_cv_header_valgrind_memcheck_h" "$ac_includes_default" -if test "x$ac_cv_header_valgrind_memcheck_h" = xyes -then : - printf "%s\n" "#define HAVE_VALGRIND_MEMCHECK_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" -if test "x$ac_cv_header_valgrind_valgrind_h" = xyes -then : - printf "%s\n" "#define HAVE_VALGRIND_VALGRIND_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mkdev_h" = xyes -then : - -printf "%s\n" "#define MAJOR_IN_MKDEV 1" >>confdefs.h - -fi - -if test $ac_cv_header_sys_mkdev_h = no; then - ac_fn_c_check_header_compile "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysmacros_h" = xyes -then : - -printf "%s\n" "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h - -fi - -fi - - - -ac_fn_c_check_header_compile "$LINENO" "sys/conf.h" "ac_cv_header_sys_conf_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_conf_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_CONF_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/mount.h" "ac_cv_header_sys_mount_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_mount_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_MOUNT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/statfs.h" "ac_cv_header_sys_statfs_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_statfs_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_STATFS_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/user.h" "ac_cv_header_sys_user_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_user_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_USER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/vfs.h" "ac_cv_header_sys_vfs_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_vfs_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_VFS_H 1" >>confdefs.h - -fi - - -saved_sysctl_h_CFLAGS=$CFLAGS -test "x${GCC}" != xyes || CFLAGS="$CFLAGS -Werror" -ac_fn_c_check_header_compile "$LINENO" "sys/sysctl.h" "ac_cv_header_sys_sysctl_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_sysctl_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SYSCTL_H 1" >>confdefs.h - -fi - -CFLAGS=$saved_sysctl_h_CFLAGS - -ac_fn_c_check_header_compile "$LINENO" "netinet/ip.h" "ac_cv_header_netinet_ip_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_ip_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_net_if_h" = xyes -then : - printf "%s\n" "#define HAVE_NET_IF_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "net/if_arp.h" "ac_cv_header_net_if_arp_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_net_if_arp_h" = xyes -then : - printf "%s\n" "#define HAVE_NET_IF_ARP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "net/if_dl.h" "ac_cv_header_net_if_dl_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_net_if_dl_h" = xyes -then : - printf "%s\n" "#define HAVE_NET_IF_DL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "net/if_types.h" "ac_cv_header_net_if_types_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_net_if_types_h" = xyes -then : - printf "%s\n" "#define HAVE_NET_IF_TYPES_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "net/route.h" "ac_cv_header_net_route_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_net_route_h" = xyes -then : - printf "%s\n" "#define HAVE_NET_ROUTE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/if_ether.h" "ac_cv_header_netinet_if_ether_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_if_ether_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IF_ETHER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/in_pcb.h" "ac_cv_header_netinet_in_pcb_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_in_pcb_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IN_PCB_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/ip_icmp.h" "ac_cv_header_netinet_ip_icmp_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_ip_icmp_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IP_ICMP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/ip_var.h" "ac_cv_header_netinet_ip_var_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_ip_var_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IP_VAR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/udp.h" "ac_cv_header_netinet_udp_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_udp_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_UDP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet6/ip6_var.h" "ac_cv_header_netinet6_ip6_var_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet6_ip6_var_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET6_IP6_VAR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netipx/ipx.h" "ac_cv_header_netipx_ipx_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netipx_ipx_h" = xyes -then : - printf "%s\n" "#define HAVE_NETIPX_IPX_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_sys_un_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_UN_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "netinet/udp_var.h" "ac_cv_header_netinet_udp_var_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif - #ifdef HAVE_NETINET_IP_VAR_H - # include - #endif - #ifdef HAVE_NETINET_IP_ICMP_H - # include - #endif - #ifdef HAVE_NETINET_UDP_H - # include - #endif - #ifdef HAVE_NETINET_TCP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_udp_var_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_UDP_VAR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/icmp_var.h" "ac_cv_header_netinet_icmp_var_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif - #ifdef HAVE_NETINET_IP_VAR_H - # include - #endif - #ifdef HAVE_NETINET_IP_ICMP_H - # include - #endif - #ifdef HAVE_NETINET_UDP_H - # include - #endif - #ifdef HAVE_NETINET_TCP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_icmp_var_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_ICMP_VAR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/icmp6.h" "ac_cv_header_netinet_icmp6_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif - #ifdef HAVE_NETINET_IP_VAR_H - # include - #endif - #ifdef HAVE_NETINET_IP_ICMP_H - # include - #endif - #ifdef HAVE_NETINET_UDP_H - # include - #endif - #ifdef HAVE_NETINET_TCP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_icmp6_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_ICMP6_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/tcp_var.h" "ac_cv_header_netinet_tcp_var_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif - #ifdef HAVE_NETINET_IP_VAR_H - # include - #endif - #ifdef HAVE_NETINET_IP_ICMP_H - # include - #endif - #ifdef HAVE_NETINET_UDP_H - # include - #endif - #ifdef HAVE_NETINET_TCP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_tcp_var_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_TCP_VAR_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "linux/ipx.h" "ac_cv_header_linux_ipx_h" "#include - #include - #ifdef HAVE_ASM_TYPES_H - # include - #endif - #ifdef HAVE_LINUX_TYPES_H - # include - #endif -" -if test "x$ac_cv_header_linux_ipx_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_IPX_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/irda.h" "ac_cv_header_linux_irda_h" "#include - #include - #ifdef HAVE_ASM_TYPES_H - # include - #endif - #ifdef HAVE_LINUX_TYPES_H - # include - #endif -" -if test "x$ac_cv_header_linux_irda_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_IRDA_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/rtnetlink.h" "ac_cv_header_linux_rtnetlink_h" "#include - #include - #ifdef HAVE_ASM_TYPES_H - # include - #endif - #ifdef HAVE_LINUX_TYPES_H - # include - #endif -" -if test "x$ac_cv_header_linux_rtnetlink_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_RTNETLINK_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "#include - #include - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_ARPA_NAMESER_H - # include - #endif -" -if test "x$ac_cv_header_resolv_h" = xyes -then : - printf "%s\n" "#define HAVE_RESOLV_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "#include -" -if test "x$ac_cv_header_ifaddrs_h" = xyes -then : - printf "%s\n" "#define HAVE_IFADDRS_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "sys/ucontext.h" "ac_cv_header_sys_ucontext_h" "#include -" -if test "x$ac_cv_header_sys_ucontext_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_UCONTEXT_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "sys/thr.h" "ac_cv_header_sys_thr_h" "#include -#ifdef HAVE_SYS_UCONTEXT_H -#include -#endif -" -if test "x$ac_cv_header_sys_thr_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_THR_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "pthread_np.h" "ac_cv_header_pthread_np_h" "#include -" -if test "x$ac_cv_header_pthread_np_h" = xyes -then : - printf "%s\n" "#define HAVE_PTHREAD_NP_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "linux/videodev2.h" "ac_cv_header_linux_videodev2_h" "#include -#include -#ifdef HAVE_ASM_TYPES_H -#include -#endif -" -if test "x$ac_cv_header_linux_videodev2_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_VIDEODEV2_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "libprocstat.h" "ac_cv_header_libprocstat_h" "#ifdef HAVE_SYS_PARAM_H -#include -#endif -#include -#ifdef HAVE_SYS_QUEUE_H -#include -#endif -" -if test "x$ac_cv_header_libprocstat_h" = xyes -then : - printf "%s\n" "#define HAVE_LIBPROCSTAT_H 1" >>confdefs.h - -fi - - -if test "x$ac_cv_header_sys_xattr_h" = xyes -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getxattr takes additional arguments" >&5 -printf %s "checking whether getxattr takes additional arguments... " >&6; } -if test ${wine_cv_xattr_extra_args+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -getxattr("", "", "", 0, 0, 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - wine_cv_xattr_extra_args=yes -else case e in #( - e) wine_cv_xattr_extra_args=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_xattr_extra_args" >&5 -printf "%s\n" "$wine_cv_xattr_extra_args" >&6; } - test $wine_cv_xattr_extra_args != yes || -printf "%s\n" "#define XATTR_ADDITIONAL_OPTIONS 1" >>confdefs.h - -fi - - -DLLFLAGS="" - -LDDLLFLAGS="" - -LDEXECFLAGS="" - -EXTRACFLAGS="" - -UNIXDLLFLAGS="-fPIC" - -UNIXLDFLAGS="-shared -Wl,-Bsymbolic -Wl,-soname,\$(UNIXLIB)" - -TOP_INSTALL_LIB="" - -TOP_INSTALL_DEV="" - -WINELOADER_LDFLAGS="" - -WINEPRELOADER_LDFLAGS="" - -DLLEXT=".so" - -LIBEXT="so" -# Extract the first word of "ldd", so it can be a program name with args. -set dummy ldd; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_LDD+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $LDD in - [\\/]* | ?:[\\/]*) - ac_cv_path_LDD="$LDD" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_dummy="/sbin:/usr/sbin:$PATH" -for as_dir in $as_dummy -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_LDD="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_LDD" && ac_cv_path_LDD="true" - ;; -esac ;; -esac -fi -LDD=$ac_cv_path_LDD -if test -n "$LDD"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDD" >&5 -printf "%s\n" "$LDD" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$OTOOL"; then - ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OTOOL=$ac_cv_prog_OTOOL -if test -n "$OTOOL"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 -printf "%s\n" "$OTOOL" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL"; then - ac_ct_OTOOL=$OTOOL - # Extract the first word of "otool", so it can be a program name with args. -set dummy otool; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_OTOOL"; then - ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL="otool" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL -if test -n "$ac_ct_OTOOL"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 -printf "%s\n" "$ac_ct_OTOOL" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_OTOOL" = x; then - OTOOL="otool" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL=$ac_ct_OTOOL - fi -else - OTOOL="$ac_cv_prog_OTOOL" -fi - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}readelf", so it can be a program name with args. -set dummy ${ac_tool_prefix}readelf; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_READELF+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$READELF"; then - ac_cv_prog_READELF="$READELF" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_READELF="${ac_tool_prefix}readelf" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -READELF=$ac_cv_prog_READELF -if test -n "$READELF"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $READELF" >&5 -printf "%s\n" "$READELF" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_READELF"; then - ac_ct_READELF=$READELF - # Extract the first word of "readelf", so it can be a program name with args. -set dummy readelf; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_READELF+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_READELF"; then - ac_cv_prog_ac_ct_READELF="$ac_ct_READELF" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_READELF="readelf" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_READELF=$ac_cv_prog_ac_ct_READELF -if test -n "$ac_ct_READELF"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_READELF" >&5 -printf "%s\n" "$ac_ct_READELF" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_READELF" = x; then - READELF="true" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - READELF=$ac_ct_READELF - fi -else - READELF="$ac_cv_prog_READELF" -fi - -wine_rules="all:" -SUBDIRS="" - -DISABLED_SUBDIRS="" - -CONFIGURE_TARGETS="" - - -wine_fn_config_makefile () -{ - as_fn_append SUBDIRS " \\$as_nl $1" - eval enable=\$$2 - case "$enable" in - no) as_fn_append DISABLED_SUBDIRS " $1" ;; - yes) ;; - *aarch64*|*arm*|*i386*|*x86_64*) - if test -n "$PE_ARCHS" - then - for i in $PE_ARCHS - do - test $(expr ",$enable," : ".*,$i,") -gt 0 || as_fn_append ${i}_DISABLED_SUBDIRS " $1" - done - else - test $(expr ",$enable," : ".*,$HOST_ARCH,") -gt 0 || as_fn_append DISABLED_SUBDIRS " $1" - fi ;; - "") - case "$1, $PE_ARCHS " in - programs/*,*\ arm64ec\ *) as_fn_append arm64ec_DISABLED_SUBDIRS " $1" ;; - esac ;; - esac -} - -wine_fn_config_symlink () -{ - ac_links=$@ - as_fn_append wine_rules " -$ac_links: - @./config.status \$@" - for f in $ac_links; do as_fn_append CONFIGURE_TARGETS " $f"; done -} - -case $host_os in - cygwin*|mingw32*) - LIBEXT="dll" - DLLEXT="" - EXTRACFLAGS="-D__WINE_PE_BUILD" - enable_loader=${enable_loader:-no} - enable_server=${enable_server:-no} - with_x=${with_x:-no} - with_pthread=${with_pthread:-no} - ;; - - darwin*|macosx*) - LIBEXT="dylib" - DLLFLAGS="$DLLFLAGS -fPIC" - LDDLLFLAGS="-fPIC" - enable_winemac_drv=${enable_winemac_drv:-yes} - CARBON_LIBS="-framework Carbon" - - COREFOUNDATION_LIBS="-framework CoreFoundation" - - DISKARBITRATION_LIBS="-framework DiskArbitration -framework CoreFoundation" - - IOKIT_LIBS="-framework IOKit -framework CoreFoundation" - - METAL_LIBS="-framework Metal" - - APPLICATIONSERVICES_LIBS="-framework ApplicationServices" - - CORESERVICES_LIBS="-framework CoreServices" - - APPKIT_LIBS="-framework AppKit" - - SECURITY_LIBS="-framework Security -framework CoreFoundation" - - SYSTEMCONFIGURATION_LIBS="-framework SystemConfiguration" - - - WINELOADER_LDFLAGS="-Wl,-segalign,0x1000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist" - - case $HOST_ARCH in - i386) wine_use_preloader=yes ;; - x86_64) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-no_huge" >&5 -printf %s "checking whether the compiler supports -Wl,-no_huge... " >&6; } -if test ${ac_cv_cflags__Wl__no_huge+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-no_huge" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__no_huge=yes -else case e in #( - e) ac_cv_cflags__Wl__no_huge=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__no_huge" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__no_huge" >&6; } -if test "x$ac_cv_cflags__Wl__no_huge" = xyes -then : - wine_use_preloader=no - WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -Wl,-no_pie,-image_base,0x200000000,-no_huge,-no_fixup_chains,-segalign,0x1000,-segaddr,WINE_RESERVE,0x1000,-segaddr,WINE_TOP_DOWN,0x7ff000000000" -else case e in #( - e) wine_use_preloader=yes ;; -esac -fi - ;; - *) wine_use_preloader=no ;; - esac - - if test "$wine_use_preloader" = "yes" - then - WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -mmacosx-version-min=10.7 -Wl,-no_new_main,-segalign,0x1000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-no_pie" >&5 -printf %s "checking whether the compiler supports -Wl,-no_pie... " >&6; } -if test ${ac_cv_cflags__Wl__no_pie+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-no_pie" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__no_pie=yes -else case e in #( - e) ac_cv_cflags__Wl__no_pie=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__no_pie" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__no_pie" >&6; } -if test "x$ac_cv_cflags__Wl__no_pie" = xyes -then : - WINEPRELOADER_LDFLAGS="-Wl,-no_pie $WINEPRELOADER_LDFLAGS" -fi - case $HOST_ARCH in - i386) - WINEPRELOADER_LDFLAGS="-Wl,-image_base,0x7d400000 $WINEPRELOADER_LDFLAGS" - ;; - x86_64) - WINEPRELOADER_LDFLAGS="-Wl,-image_base,0x200000000,-segalign,0x1000,-segaddr,WINE_RESERVE,0x1000 $WINEPRELOADER_LDFLAGS" - ;; - esac - WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -mmacosx-version-min=10.7" - fi - - if test "x$with_coreaudio" != "xno"; - then - COREAUDIO_LIBS="-framework CoreFoundation -framework CoreAudio -framework AudioUnit -framework AudioToolbox -framework CoreMIDI" - - enable_winecoreaudio_drv=${enable_winecoreaudio_drv:-yes} - fi - if test "$ac_cv_header_OpenCL_opencl_h" = "yes" - then - OPENCL_LIBS="-framework OpenCL" - - ac_cv_lib_OpenCL_clGetPlatformInfo=yes - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether MTLDevice protocol supports registryID property" >&5 -printf %s "checking whether MTLDevice protocol supports registryID property... " >&6; } - ac_ext=m -ac_cpp='$OBJCPP $CPPFLAGS' -ac_compile='$OBJC -c $OBJCFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$OBJC -o conftest$ac_exeext $OBJCFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_objc_compiler_gnu - - ac_ext=m -ac_cpp='$OBJCPP $CPPFLAGS' -ac_compile='$OBJC -c $OBJCFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$OBJC -o conftest$ac_exeext $OBJCFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_objc_compiler_gnu -if test -n "$ac_tool_prefix"; then - for ac_prog in gcc objcc objc cc CC clang - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OBJC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$OBJC"; then - ac_cv_prog_OBJC="$OBJC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OBJC="$ac_tool_prefix$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -OBJC=$ac_cv_prog_OBJC -if test -n "$OBJC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJC" >&5 -printf "%s\n" "$OBJC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$OBJC" && break - done -fi -if test -z "$OBJC"; then - ac_ct_OBJC=$OBJC - for ac_prog in gcc objcc objc cc CC clang -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OBJC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$ac_ct_OBJC"; then - ac_cv_prog_ac_ct_OBJC="$ac_ct_OBJC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OBJC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -ac_ct_OBJC=$ac_cv_prog_ac_ct_OBJC -if test -n "$ac_ct_OBJC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJC" >&5 -printf "%s\n" "$ac_ct_OBJC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$ac_ct_OBJC" && break -done - - if test "x$ac_ct_OBJC" = x; then - OBJC="gcc" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJC=$ac_ct_OBJC - fi -fi - -# Provide some information about the compiler. -printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Objective C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU Objective C" >&5 -printf %s "checking whether the compiler supports GNU Objective C... " >&6; } -if test ${ac_cv_objc_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_objc_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else case e in #( - e) ac_compiler_gnu=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_objc_compiler_gnu=$ac_compiler_gnu - ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objc_compiler_gnu" >&5 -printf "%s\n" "$ac_cv_objc_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_objc_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GOBJC=yes -else - GOBJC= -fi -ac_test_OBJCFLAGS=${OBJCFLAGS+y} -ac_save_OBJCFLAGS=$OBJCFLAGS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $OBJC accepts -g" >&5 -printf %s "checking whether $OBJC accepts -g... " >&6; } -if test ${ac_cv_prog_objc_g+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_save_objc_werror_flag=$ac_objc_werror_flag - ac_objc_werror_flag=yes - ac_cv_prog_objc_g=no - OBJCFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_objc_try_compile "$LINENO" -then : - ac_cv_prog_objc_g=yes -else case e in #( - e) OBJCFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_objc_try_compile "$LINENO" -then : - -else case e in #( - e) ac_objc_werror_flag=$ac_save_objc_werror_flag - OBJCFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_objc_try_compile "$LINENO" -then : - ac_cv_prog_objc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_objc_werror_flag=$ac_save_objc_werror_flag ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_objc_g" >&5 -printf "%s\n" "$ac_cv_prog_objc_g" >&6; } -if test $ac_test_OBJCFLAGS; then - OBJCFLAGS=$ac_save_OBJCFLAGS -elif test $ac_cv_prog_objc_g = yes; then - if test "$GOBJC" = yes; then - OBJCFLAGS="-g -O2" - else - OBJCFLAGS="-g" - fi -else - if test "$GOBJC" = yes; then - OBJCFLAGS="-O2" - else - OBJCFLAGS= - fi -fi -ac_ext=m -ac_cpp='$OBJCPP $CPPFLAGS' -ac_compile='$OBJC -c $OBJCFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$OBJC -o conftest$ac_exeext $OBJCFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_objc_compiler_gnu - - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -id device; device.registryID; - ; - return 0; -} -_ACEOF -if ac_fn_objc_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - -printf "%s\n" "#define HAVE_MTLDEVICE_REGISTRYID 1" >>confdefs.h - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - UNIXLDFLAGS="-dynamiclib -install_name @rpath/\$(UNIXLIB) -Wl,-rpath,@loader_path\/" - WINELOADER_DEPENDS="wine_info.plist" - - ;; - - linux-android*) - -printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h - - DLLFLAGS="$DLLFLAGS -fPIC" - LDDLLFLAGS="-fPIC" - LDEXECFLAGS="-Wl,-pie" - enable_wineandroid_drv=${enable_wineandroid_drv:-yes} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-z,defs" >&5 -printf %s "checking whether the compiler supports -Wl,-z,defs... " >&6; } -if test ${ac_cv_cflags__Wl__z_defs+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-z,defs" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__z_defs=yes -else case e in #( - e) ac_cv_cflags__Wl__z_defs=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__z_defs" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__z_defs" >&6; } -if test "x$ac_cv_cflags__Wl__z_defs" = xyes -then : - UNIXLDFLAGS="$UNIXLDFLAGS -Wl,-z,defs" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fPIC -Wl,--export-dynamic" >&5 -printf %s "checking whether the compiler supports -fPIC -Wl,--export-dynamic... " >&6; } -if test ${ac_cv_cflags__fPIC__Wl___export_dynamic+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fPIC -Wl,--export-dynamic" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fPIC__Wl___export_dynamic=yes -else case e in #( - e) ac_cv_cflags__fPIC__Wl___export_dynamic=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fPIC__Wl___export_dynamic" >&5 -printf "%s\n" "$ac_cv_cflags__fPIC__Wl___export_dynamic" >&6; } -if test "x$ac_cv_cflags__fPIC__Wl___export_dynamic" = xyes -then : - WINELOADER_LDFLAGS="-Wl,--export-dynamic" -fi - WINEPRELOADER_LDFLAGS="-static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7d400000" - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lEGL" >&5 -printf %s "checking for -lEGL... " >&6; } -if test ${ac_cv_lib_soname_EGL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lEGL $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char eglGetProcAddress (void); -int -main (void) -{ -return eglGetProcAddress (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_EGL=`$ac_cv_path_LDD conftest.exe | grep "EGL" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_EGL=`$OTOOL -L conftest$ac_exeext | grep "libEGL\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libEGL\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_EGL=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libEGL\\.$LIBEXT" | sed -e "s/^.*\\[\\(libEGL\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_EGL:+false} : -then : - ac_cv_lib_soname_EGL=`$LDD conftest$ac_exeext | grep "libEGL\\.$LIBEXT" | sed -e "s/^.*\(libEGL\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_EGL= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_EGL:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_EGL" >&5 -printf "%s\n" "$ac_cv_lib_soname_EGL" >&6; } - -printf "%s\n" "#define SONAME_LIBEGL \"$ac_cv_lib_soname_EGL\"" >>confdefs.h - - ;; -esac -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lGLESv2" >&5 -printf %s "checking for -lGLESv2... " >&6; } -if test ${ac_cv_lib_soname_GLESv2+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lGLESv2 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char glFlush (void); -int -main (void) -{ -return glFlush (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_GLESv2=`$ac_cv_path_LDD conftest.exe | grep "GLESv2" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_GLESv2=`$OTOOL -L conftest$ac_exeext | grep "libGLESv2\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libGLESv2\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_GLESv2=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libGLESv2\\.$LIBEXT" | sed -e "s/^.*\\[\\(libGLESv2\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_GLESv2:+false} : -then : - ac_cv_lib_soname_GLESv2=`$LDD conftest$ac_exeext | grep "libGLESv2\\.$LIBEXT" | sed -e "s/^.*\(libGLESv2\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_GLESv2= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_GLESv2:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_GLESv2" >&5 -printf "%s\n" "$ac_cv_lib_soname_GLESv2" >&6; } - -printf "%s\n" "#define SONAME_LIBGLESV2 \"$ac_cv_lib_soname_GLESv2\"" >>confdefs.h - - ;; -esac -fi - - if test "x$exec_prefix" = xNONE - then - case $HOST_ARCH in - i386) exec_prefix='${prefix}/x86' ;; - x86_64) exec_prefix='${prefix}/x86_64' ;; - arm) exec_prefix='${prefix}/armeabi-v7a' ;; - aarch64) exec_prefix='${prefix}/arm64-v8a' ;; - esac - fi - ;; - - *) - -printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h - - if test $HOST_ARCH = i386 - then - DLLFLAGS="$DLLFLAGS -fno-PIC" - LDDLLFLAGS="-fno-PIC" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fno-PIC -Wl,-z,notext" >&5 -printf %s "checking whether the compiler supports -fno-PIC -Wl,-z,notext... " >&6; } -if test ${ac_cv_cflags__fno_PIC__Wl__z_notext+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fno-PIC -Wl,-z,notext" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fno_PIC__Wl__z_notext=yes -else case e in #( - e) ac_cv_cflags__fno_PIC__Wl__z_notext=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_PIC__Wl__z_notext" >&5 -printf "%s\n" "$ac_cv_cflags__fno_PIC__Wl__z_notext" >&6; } -if test "x$ac_cv_cflags__fno_PIC__Wl__z_notext" = xyes -then : - LDDLLFLAGS="$LDDLLFLAGS -Wl,-z,notext" -fi - else - DLLFLAGS="$DLLFLAGS -fPIC" - LDDLLFLAGS="-fPIC" - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -Wl,-z,defs works correctly" >&5 -printf %s "checking whether -Wl,-z,defs works correctly... " >&6; } -if test ${ac_cv_wl_z_defs+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $UNIXDLLFLAGS $UNIXLDFLAGS -Wl,-z,defs" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -extern char **environ; char **envp; void myfunc(void) { envp = environ; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_wl_z_defs=yes -else case e in #( - e) ac_cv_wl_z_defs=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - CFLAGS=$ac_save_CFLAGS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_wl_z_defs" >&5 -printf "%s\n" "$ac_cv_wl_z_defs" >&6; } - test $ac_cv_wl_z_defs != yes || as_fn_append UNIXLDFLAGS " -Wl,-z,defs" - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,--export-dynamic" >&5 -printf %s "checking whether the compiler supports -Wl,--export-dynamic... " >&6; } -if test ${ac_cv_cflags__Wl___export_dynamic+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,--export-dynamic" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl___export_dynamic=yes -else case e in #( - e) ac_cv_cflags__Wl___export_dynamic=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl___export_dynamic" >&5 -printf "%s\n" "$ac_cv_cflags__Wl___export_dynamic" >&6; } -if test "x$ac_cv_cflags__Wl___export_dynamic" = xyes -then : - WINELOADER_LDFLAGS="-Wl,--export-dynamic" -fi - WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs" - - case $host_os in - linux*) - as_fn_append WINELOADER_LDFLAGS " -pie" - case $HOST_ARCH in - i386|arm) - as_fn_append WINEPRELOADER_LDFLAGS " -static -Wl,-Ttext=0x7d400000" ;; - *) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -static-pie" >&5 -printf %s "checking whether the compiler supports -static-pie... " >&6; } -if test ${ac_cv_cflags__static_pie+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -static-pie" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__static_pie=yes -else case e in #( - e) ac_cv_cflags__static_pie=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__static_pie" >&5 -printf "%s\n" "$ac_cv_cflags__static_pie" >&6; } -if test "x$ac_cv_cflags__static_pie" = xyes -then : - as_fn_append WINEPRELOADER_LDFLAGS " -static-pie" -else case e in #( - e) as_fn_append WINEPRELOADER_LDFLAGS " -static -Wl,-Ttext=0x7d7d00000000" ;; -esac -fi - ;; - esac - ;; - *) - case $HOST_ARCH in - i386|arm) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-Ttext-segment=0x60000000" >&5 -printf %s "checking whether the compiler supports -Wl,-Ttext-segment=0x60000000... " >&6; } -if test ${ac_cv_cflags__Wl__Ttext_segment_0x60000000+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-Ttext-segment=0x60000000" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__Ttext_segment_0x60000000=yes -else case e in #( - e) ac_cv_cflags__Wl__Ttext_segment_0x60000000=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__Ttext_segment_0x60000000" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__Ttext_segment_0x60000000" >&6; } -if test "x$ac_cv_cflags__Wl__Ttext_segment_0x60000000" = xyes -then : - as_fn_append WINELOADER_LDFLAGS " -Wl,-Ttext-segment=0x60000000" -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,--section-start,.interp=0x60000400" >&5 -printf %s "checking whether the compiler supports -Wl,--section-start,.interp=0x60000400... " >&6; } -if test ${ac_cv_cflags__Wl___section_start__interp_0x60000400+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,--section-start,.interp=0x60000400" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl___section_start__interp_0x60000400=yes -else case e in #( - e) ac_cv_cflags__Wl___section_start__interp_0x60000400=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl___section_start__interp_0x60000400" >&5 -printf "%s\n" "$ac_cv_cflags__Wl___section_start__interp_0x60000400" >&6; } -if test "x$ac_cv_cflags__Wl___section_start__interp_0x60000400" = xyes -then : - as_fn_append WINELOADER_LDFLAGS " -Wl,--section-start,.interp=0x60000400" -fi ;; -esac -fi - ;; - *) - as_fn_append WINELOADER_LDFLAGS " -pie" - ;; - esac - ;; - esac - ;; -esac - -enable_winecoreaudio_drv=${enable_winecoreaudio_drv:-no} -enable_wineandroid_drv=${enable_wineandroid_drv:-no} -enable_winemac_drv=${enable_winemac_drv:-no} - -PE_ARCHS="" - -cross_archs= -if test ${enable_archs+y} -then : - test "x$with_system_dllpath" = "x" || as_fn_error $? "\"The --with-system-dllpath option is not compatible with --enable-archs\"" "$LINENO" 5 - ac_save_IFS=$IFS - IFS=' ,' - set x $enable_archs - IFS=$ac_save_IFS - shift - for arch - do - case $arch in - i386|x86_64|arm|aarch64|arm64ec) cross_archs="$cross_archs $arch" ;; - *) as_fn_error $? "Unknown cross-compilation architecture '$arch'" "$LINENO" 5 ;; - esac - done -else case e in #( - e) if test "x$with_mingw" != xno - then - test $HOST_ARCH = unknown || cross_archs=$HOST_ARCH - fi ;; -esac -fi - -saved_CC=$CC -saved_CFLAGS=$CFLAGS -saved_CPPFLAGS=$CPPFLAGS -saved_LDFLAGS=$LDFLAGS - -{ extra_arch=; unset extra_arch;} -for arch in $cross_archs -do - case $arch in - arm64ec) test ${extra_arch+y} || extra_arch=x86_64 ;; - x86_64) extra_arch="" ;; - esac -done - -for wine_arch in $cross_archs $extra_arch -do - case "x$with_mingw" in - xclang|x*/clang) eval "${wine_arch}_CC=\$with_mingw" ;; - esac - if eval \${${wine_arch}_CC:+false} : -then : - case $wine_arch in - aarch64) - for ac_prog in aarch64-w64-mingw32-clang aarch64-w64-mingw32-gcc clang -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_aarch64_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$aarch64_CC"; then - ac_cv_prog_aarch64_CC="$aarch64_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_aarch64_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -aarch64_CC=$ac_cv_prog_aarch64_CC -if test -n "$aarch64_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $aarch64_CC" >&5 -printf "%s\n" "$aarch64_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$aarch64_CC" && break -done -test -n "$aarch64_CC" || aarch64_CC="false" - - ;; - arm64ec) - for ac_prog in arm64ec-w64-mingw32-clang arm64ec-w64-mingw32-gcc clang -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_arm64ec_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$arm64ec_CC"; then - ac_cv_prog_arm64ec_CC="$arm64ec_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_arm64ec_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -arm64ec_CC=$ac_cv_prog_arm64ec_CC -if test -n "$arm64ec_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $arm64ec_CC" >&5 -printf "%s\n" "$arm64ec_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$arm64ec_CC" && break -done -test -n "$arm64ec_CC" || arm64ec_CC="false" - - ;; - arm) - for ac_prog in armv7-w64-mingw32-clang armv7-w64-mingw32-gcc clang -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_arm_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$arm_CC"; then - ac_cv_prog_arm_CC="$arm_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_arm_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -arm_CC=$ac_cv_prog_arm_CC -if test -n "$arm_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $arm_CC" >&5 -printf "%s\n" "$arm_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$arm_CC" && break -done -test -n "$arm_CC" || arm_CC="false" - - ;; - i386) - ac_prefix_list="i686-w64-mingw32-gcc i586-w64-mingw32-gcc i486-w64-mingw32-gcc i386-w64-mingw32-gcc i686-w64-mingw32-clang i586-w64-mingw32-clang i486-w64-mingw32-clang i386-w64-mingw32-clang " - for ac_prog in $ac_prefix_list clang -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_i386_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$i386_CC"; then - ac_cv_prog_i386_CC="$i386_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_i386_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -i386_CC=$ac_cv_prog_i386_CC -if test -n "$i386_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $i386_CC" >&5 -printf "%s\n" "$i386_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$i386_CC" && break -done -test -n "$i386_CC" || i386_CC="false" - - ;; - x86_64) - ac_prefix_list="x86_64-w64-mingw32-gcc amd64-w64-mingw32-gcc x86_64-w64-mingw32-clang amd64-w64-mingw32-clang " - for ac_prog in $ac_prefix_list clang -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_x86_64_CC+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$x86_64_CC"; then - ac_cv_prog_x86_64_CC="$x86_64_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_x86_64_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -x86_64_CC=$ac_cv_prog_x86_64_CC -if test -n "$x86_64_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $x86_64_CC" >&5 -printf "%s\n" "$x86_64_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$x86_64_CC" && break -done -test -n "$x86_64_CC" || x86_64_CC="false" - - ;; - esac -fi - - CPPFLAGS="" - if eval test \${${wine_arch}_CFLAGS+y} -then : - -else case e in #( - e) eval "${wine_arch}_CFLAGS=\${CROSSCFLAGS:-\"-g -O2\"}" ;; -esac -fi - if eval test \${${wine_arch}_LDFLAGS+y} -then : - -else case e in #( - e) eval "${wine_arch}_LDFLAGS=\$CROSSLDFLAGS" ;; -esac -fi - eval CC=\$${wine_arch}_CC - eval CFLAGS=\$${wine_arch}_CFLAGS - eval LDFLAGS=\$${wine_arch}_LDFLAGS - eval "${wine_arch}_EXTRACFLAGS=\"-D__WINE_PE_BUILD -Wall\"" - - target="" - set x $CC - shift - while test $# -ge 1 - do - case "$1" in - */*-gcc) target=`expr "$1" : '.*/\(.*\)-gcc'` ;; - */*-clang) target=`expr "$1" : '.*/\(.*\)-clang'` ;; - *-gcc) target=`expr "$1" : '\(.*\)-gcc'` ;; - *-clang) target=`expr "$1" : '\(.*\)-clang'` ;; - esac - shift - done - - llvm_target=$target - target_strip=${target:-llvm}-strip - if test -z "$llvm_target" - then - case $wine_arch in - i386) llvm_target=i686-windows ;; - arm) llvm_target=armv7-windows ;; - *) llvm_target=$wine_arch-windows ;; - esac - fi - llvm_extra_cflags="-target $llvm_target -fuse-ld=lld" - llvm_extra_ldflags="" - llvm_cflags="" - case $llvm_target in - *windows) llvm_cflags="-Wl,-subsystem:console -Wl,-WX" ;; - esac - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_$llvm_extra_cflags $llvm_cflags --no-default-config" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $llvm_extra_cflags $llvm_cflags --no-default-config" >&5 -printf %s "checking whether $CC supports $llvm_extra_cflags $llvm_cflags --no-default-config... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs $llvm_extra_cflags $llvm_cflags --no-default-config" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - llvm_extra_cflags="$llvm_extra_cflags --no-default-config" - llvm_extra_ldflags="--no-default-config" -else case e in #( - e) { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_$llvm_extra_cflags $llvm_cflags" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $llvm_extra_cflags $llvm_cflags" >&5 -printf %s "checking whether $CC supports $llvm_extra_cflags $llvm_cflags... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs $llvm_extra_cflags $llvm_cflags" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - : -else case e in #( - e) llvm_extra_cflags="" ;; -esac -fi } ;; -esac -fi } - if test -n "$llvm_extra_cflags" - then - target=$llvm_target - eval "${wine_arch}_DELAYLOADFLAG=\"-Wl,-delayload,\"" - as_fn_append ${wine_arch}_EXTRACFLAGS " $llvm_extra_cflags" - as_fn_append ${wine_arch}_LDFLAGS " $llvm_extra_ldflags" - CFLAGS="$CFLAGS $llvm_extra_cflags $llvm_cflags" - else - as_wine_cv_crosscc=`printf "%s\n" "wine_cv_${wine_arch}_crosscc" | sed "$as_sed_sh"` - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC works" >&5 -printf %s "checking whether $CC works... " >&6; } -if eval test \${$as_wine_cv_crosscc+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$as_wine_cv_crosscc=yes" -else case e in #( - e) eval "$as_wine_cv_crosscc=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$as_wine_cv_crosscc - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - if eval test \"x\$"$as_wine_cv_crosscc"\" = x"no" -then : - target= -fi - - fi - - if test -z "$target" - then - if test ${enable_archs+y} -then : - as_fn_error $? "$wine_arch PE cross-compiler not found. -This is an error since --enable-archs=$wine_arch was requested." "$LINENO" 5 -fi - continue - fi - - eval "${wine_arch}_TARGET=\$target" - eval "${wine_arch}_STRIP=\$target_strip" - as_wine_cv_crosscc_c99=`printf "%s\n" "ac_cv_${wine_arch}_crosscc_c99" | sed "$as_sed_sh"` - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 -printf %s "checking for $CC option to enable C99 features... " >&6; } - if eval test \${$as_wine_cv_crosscc_c99+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) eval "$as_wine_cv_crosscc_c99=no" - for arg in '' '-std=gnu99' '-D__STDC__' - do - test -z "$arg" || CC="$CC $arg" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c99_program -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$as_wine_cv_crosscc_c99=\$arg" -else case e in #( - e) eval "$as_wine_cv_crosscc_c99=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - eval CC=\$${wine_arch}_CC - if eval test \"x\$"$as_wine_cv_crosscc_c99"\" = x"no" -then : - -else case e in #( - e) break ;; -esac -fi - done ;; -esac -fi - - eval res=\$$as_wine_cv_crosscc_c99 - - case "x$res" in - x) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } ;; - xno) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } - if test ${enable_archs+y} -then : - as_fn_error $? "$wine_arch PE cross-compiler supporting C99 not found. -This is an error since --enable-archs=$wine_arch was requested." "$LINENO" 5 -fi - continue - ;; - x*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $res" >&5 -printf "%s\n" "$res" >&6; } - as_fn_append ${wine_arch}_CC " $res" ;; - esac - - if test "x$wine_arch" = xi386 -then : - -else case e in #( - e) as_wine_cv_seh_support=`printf "%s\n" "ac_cv_${wine_arch}_seh_support" | sed "$as_sed_sh"` - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports SEH directives" >&5 -printf %s "checking whether $CC supports SEH directives... " >&6; } -if eval test \${$as_wine_cv_seh_support+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -asm(".text\nac_test:\t.seh_proc ac_test\n\tnop\n\t.seh_stackalloc 16\n\t.seh_endprologue\n\t.seh_endproc"); -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$as_wine_cv_seh_support=yes" -else case e in #( - e) eval "$as_wine_cv_seh_support=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -eval ac_res=\$$as_wine_cv_seh_support - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval res=\$$as_wine_cv_seh_support - - if test "x$res" = xyes -then : - -else case e in #( - e) if test ${enable_archs+y} -then : - as_fn_error $? "The $wine_arch PE cross-compiler doesn't support SEH directives. -This is an error since --enable-archs=$wine_arch was requested." "$LINENO" 5 -fi - continue ;; -esac -fi ;; -esac -fi - - if test "x$wine_arch" = x$extra_arch -then : - -else case e in #( - e) as_fn_append PE_ARCHS " $wine_arch" ;; -esac -fi - - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-fno-strict-aliasing" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fno-strict-aliasing" >&5 -printf %s "checking whether $CC supports -fno-strict-aliasing... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -fno-strict-aliasing" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -fno-strict-aliasing" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Werror=unknown-warning-option" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking whether $CC supports -Werror=unknown-warning-option... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Werror=unknown-warning-option" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - CFLAGS="$CFLAGS -Werror=unknown-warning-option" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Werror=ignored-optimization-argument" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Werror=ignored-optimization-argument" >&5 -printf %s "checking whether $CC supports -Werror=ignored-optimization-argument... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Werror=ignored-optimization-argument" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - CFLAGS="$CFLAGS -Werror=ignored-optimization-argument" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wdeclaration-after-statement" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wdeclaration-after-statement" >&5 -printf %s "checking whether $CC supports -Wdeclaration-after-statement... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wdeclaration-after-statement" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wdeclaration-after-statement" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wempty-body" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wempty-body" >&5 -printf %s "checking whether $CC supports -Wempty-body... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wempty-body" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wempty-body" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wignored-qualifiers" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wignored-qualifiers" >&5 -printf %s "checking whether $CC supports -Wignored-qualifiers... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wignored-qualifiers" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wignored-qualifiers" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Winit-self" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Winit-self" >&5 -printf %s "checking whether $CC supports -Winit-self... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Winit-self" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Winit-self" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wpacked-not-aligned" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wpacked-not-aligned" >&5 -printf %s "checking whether $CC supports -Wpacked-not-aligned... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wpacked-not-aligned" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wno-packed-not-aligned" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wpragma-pack" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wpragma-pack" >&5 -printf %s "checking whether $CC supports -Wpragma-pack... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wpragma-pack" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wno-pragma-pack" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wmicrosoft-enum-forward-reference" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wmicrosoft-enum-forward-reference" >&5 -printf %s "checking whether $CC supports -Wmicrosoft-enum-forward-reference... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wmicrosoft-enum-forward-reference" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wno-microsoft-enum-forward-reference" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wshift-overflow=2" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wshift-overflow=2" >&5 -printf %s "checking whether $CC supports -Wshift-overflow=2... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wshift-overflow=2" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wshift-overflow=2" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wstrict-prototypes" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wstrict-prototypes" >&5 -printf %s "checking whether $CC supports -Wstrict-prototypes... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wstrict-prototypes" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wstrict-prototypes" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wtype-limits" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wtype-limits" >&5 -printf %s "checking whether $CC supports -Wtype-limits... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wtype-limits" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wtype-limits" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wunused-but-set-parameter" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wunused-but-set-parameter" >&5 -printf %s "checking whether $CC supports -Wunused-but-set-parameter... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wunused-but-set-parameter" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wunused-but-set-parameter" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wvla" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wvla" >&5 -printf %s "checking whether $CC supports -Wvla... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wvla" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wvla" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wwrite-strings" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wwrite-strings" >&5 -printf %s "checking whether $CC supports -Wwrite-strings... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wwrite-strings" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wwrite-strings" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wpointer-arith" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wpointer-arith" >&5 -printf %s "checking whether $CC supports -Wpointer-arith... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wpointer-arith" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wpointer-arith" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wlogical-op" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wlogical-op" >&5 -printf %s "checking whether $CC supports -Wlogical-op... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wlogical-op" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wlogical-op" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wabsolute-value" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wabsolute-value" >&5 -printf %s "checking whether $CC supports -Wabsolute-value... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wabsolute-value" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wabsolute-value" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wenum-enum-conversion" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wenum-enum-conversion" >&5 -printf %s "checking whether $CC supports -Wenum-enum-conversion... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wenum-enum-conversion" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - : -else case e in #( - e) { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wenum-conversion" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wenum-conversion" >&5 -printf %s "checking whether $CC supports -Wenum-conversion... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wenum-conversion" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used0x50 = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wenum-conversion" -fi } ;; -esac -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-ffunction-sections" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -ffunction-sections" >&5 -printf %s "checking whether $CC supports -ffunction-sections... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -ffunction-sections" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -ffunction-sections" -fi } - - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-fms-hotpatch -DMIN_CLANG_VERSION=18" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fms-hotpatch -DMIN_CLANG_VERSION=18" >&5 -printf %s "checking whether $CC supports -fms-hotpatch -DMIN_CLANG_VERSION=18... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -fms-hotpatch -DMIN_CLANG_VERSION=18" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -fms-hotpatch" - as_fn_append ${wine_arch}_LDFLAGS " -fms-hotpatch" -fi } - - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-flarge-source-files -Wmisleading-indentation" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -flarge-source-files -Wmisleading-indentation" >&5 -printf %s "checking whether $CC supports -flarge-source-files -Wmisleading-indentation... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -flarge-source-files -Wmisleading-indentation" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wno-misleading-indentation" -fi } - - case $wine_arch in - i386) { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-fno-omit-frame-pointer" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fno-omit-frame-pointer" >&5 -printf %s "checking whether $CC supports -fno-omit-frame-pointer... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -fno-omit-frame-pointer" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -fno-omit-frame-pointer" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-mpreferred-stack-boundary=2" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -mpreferred-stack-boundary=2" >&5 -printf %s "checking whether $CC supports -mpreferred-stack-boundary=2... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -mpreferred-stack-boundary=2" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -mpreferred-stack-boundary=2" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wl,--disable-stdcall-fixup" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wl,--disable-stdcall-fixup" >&5 -printf %s "checking whether $CC supports -Wl,--disable-stdcall-fixup... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wl,--disable-stdcall-fixup" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_LDFLAGS " -Wl,--disable-stdcall-fixup" -fi } ;; - x86_64) { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wformat-overflow" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wformat-overflow" >&5 -printf %s "checking whether $CC supports -Wformat-overflow... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wformat-overflow" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wformat-overflow" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wnonnull" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wnonnull" >&5 -printf %s "checking whether $CC supports -Wnonnull... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wnonnull" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wnonnull" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-mcx16" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -mcx16" >&5 -printf %s "checking whether $CC supports -mcx16... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -mcx16" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -mcx16" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-mcmodel=small" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -mcmodel=small" >&5 -printf %s "checking whether $CC supports -mcmodel=small... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -mcmodel=small" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -mcmodel=small" -fi } ;; - esac - - wine_crossdebug=$CROSSDEBUG - if test -z "$wine_crossdebug" - then - for ac_flag in $CFLAGS; do - case $ac_flag in - -gdwarf*) wine_crossdebug=dwarf ;; - -gcodeview) wine_crossdebug=pdb ;; - -g) wine_crossdebug=${wine_crossdebug:-dwarf} ;; - esac - done - fi - - ac_debug_format_seen="" - for ac_flag in $CFLAGS; do - case $ac_flag in - -gdwarf*|-gcodeview) ac_debug_format_seen=$ac_flag ;; - esac - done - if test "x$ac_debug_format_seen" = x - then - case $wine_crossdebug in - *dwarf) { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wl,-debug:dwarf" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wl,-debug:dwarf" >&5 -printf %s "checking whether $CC supports -Wl,-debug:dwarf... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wl,-debug:dwarf" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_LDFLAGS " -Wl,-debug:dwarf" - CFLAGS="$CFLAGS -Wl,-debug:dwarf" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-gdwarf-4" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -gdwarf-4" >&5 -printf %s "checking whether $CC supports -gdwarf-4... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -gdwarf-4" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -gdwarf-4" -fi } ;; - pdb) { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-gcodeview" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -gcodeview" >&5 -printf %s "checking whether $CC supports -gcodeview... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -gcodeview" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -gcodeview" -fi } ;; - esac - fi - eval "${wine_arch}_DEBUG=\$wine_crossdebug" - - test "x$enable_werror" != xyes || { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Werror" | sed "$as_sed_sh"` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Werror" >&5 -printf %s "checking whether $CC supports -Werror... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Werror" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -void *__os_arm64x_dispatch_ret = 0; -const unsigned int _load_config_used[0x50] = { sizeof(_load_config_used) }; -#if defined(__clang_major__) && defined(MIN_CLANG_VERSION) && __clang_major__ < MIN_CLANG_VERSION -#error Too old clang version -#endif -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else case e in #( - e) eval "$as_ac_var=no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext ;; -esac -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Werror" -fi } - test "x$enable_build_id" != xyes || as_fn_append ${wine_arch}_LDFLAGS " -Wl,--build-id" - -done - -CC=$saved_CC -CFLAGS=$saved_CFLAGS -CPPFLAGS=$saved_CPPFLAGS -LDFLAGS=$saved_LDFLAGS - -case $HOST_ARCH in - arm|aarch64) - test "x$PE_ARCHS" != x || as_fn_error $? "PE cross-compilation is required for $HOST_ARCH, please install clang/llvm-dlltool/lld, or llvm-mingw." "$LINENO" 5 - DLLEXT="" ;; - *) - if test "x$PE_ARCHS" = "x" -then : - case "x$with_mingw" in - x) as_fn_append wine_notices "|Suitable PE cross-compiler not found, PE files won't be built." ;; - xno) ;; - *) as_fn_error $? "Suitable PE cross-compiler not found, PE files won't be built. -This is an error since --with-mingw was requested." "$LINENO" 5 ;; -esac - -fi ;; -esac - - -if test "x$with_system_dllpath" != "x" -a -n "$PE_ARCHS" -then - if test "x$HOST_ARCH" = xi386 -then : - ac_prefix_list="i686-w64-mingw32-pkg-config i586-w64-mingw32-pkg-config i486-w64-mingw32-pkg-config i386-w64-mingw32-pkg-config " -else case e in #( - e) ac_prefix_list="$host_cpu-w64-mingw32-pkg-config" ;; -esac -fi -for ac_prog in $ac_prefix_list -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_MINGW_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) if test -n "$MINGW_PKG_CONFIG"; then - ac_cv_prog_MINGW_PKG_CONFIG="$MINGW_PKG_CONFIG" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_MINGW_PKG_CONFIG="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi ;; -esac -fi -MINGW_PKG_CONFIG=$ac_cv_prog_MINGW_PKG_CONFIG -if test -n "$MINGW_PKG_CONFIG"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MINGW_PKG_CONFIG" >&5 -printf "%s\n" "$MINGW_PKG_CONFIG" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$MINGW_PKG_CONFIG" && break -done -test -n "$MINGW_PKG_CONFIG" || MINGW_PKG_CONFIG="false" - -if ${FAUDIO_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - FAUDIO_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags FAudio 2>/dev/null` -fi -fi -if ${FAUDIO_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - FAUDIO_PE_LIBS=`$MINGW_PKG_CONFIG --libs FAudio 2>/dev/null` -fi -fi -FAUDIO_PE_LIBS=${FAUDIO_PE_LIBS:-"-lFAudio"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $FAUDIO_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW FAudio.h" >&5 -printf %s "checking for MinGW FAudio.h... " >&6; } -if test ${ac_cv_mingw_header_FAudio_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_FAudio_h=yes -else case e in #( - e) ac_cv_mingw_header_FAudio_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_FAudio_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_FAudio_h" >&6; } -if test "x$ac_cv_mingw_header_FAudio_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for FAudio_CommitOperationSet in MinGW -lFAudio" >&5 -printf %s "checking for FAudio_CommitOperationSet in MinGW -lFAudio... " >&6; } -if test ${ac_cv_mingw_lib_FAudio+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lFAudio $FAUDIO_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char FAudio_CommitOperationSet (void); -int -main (void) -{ -return FAudio_CommitOperationSet (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_FAudio=yes -else case e in #( - e) ac_cv_mingw_lib_FAudio=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_FAudio" >&5 -printf "%s\n" "$ac_cv_mingw_lib_FAudio" >&6; } -if test "x$ac_cv_mingw_lib_FAudio" = xyes -then : - : -else case e in #( - e) FAUDIO_PE_CFLAGS=""; FAUDIO_PE_LIBS="" ;; -esac -fi -else case e in #( - e) FAUDIO_PE_CFLAGS=""; FAUDIO_PE_LIBS="" ;; -esac -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$FAUDIO_PE_LIBS" = "x" - then - as_fn_append wine_notices "|FAudio ${notice_platform}MinGW development files not found (or too old); using bundled version." - fi - - if ${FLUIDSYNTH_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - FLUIDSYNTH_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags fluidsynth 2>/dev/null` -fi -fi -if ${FLUIDSYNTH_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - FLUIDSYNTH_PE_LIBS=`$MINGW_PKG_CONFIG --libs fluidsynth 2>/dev/null` -fi -fi -FLUIDSYNTH_PE_LIBS=${FLUIDSYNTH_PE_LIBS:-"-lfluidsynth"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $FLUIDSYNTH_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW fluidsynth.h" >&5 -printf %s "checking for MinGW fluidsynth.h... " >&6; } -if test ${ac_cv_mingw_header_fluidsynth_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_fluidsynth_h=yes -else case e in #( - e) ac_cv_mingw_header_fluidsynth_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_fluidsynth_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_fluidsynth_h" >&6; } -if test "x$ac_cv_mingw_header_fluidsynth_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for new_fluid_synth in MinGW -lfluidsynth" >&5 -printf %s "checking for new_fluid_synth in MinGW -lfluidsynth... " >&6; } -if test ${ac_cv_mingw_lib_fluidsynth+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lfluidsynth $FLUIDSYNTH_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char new_fluid_synth (void); -int -main (void) -{ -return new_fluid_synth (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_fluidsynth=yes -else case e in #( - e) ac_cv_mingw_lib_fluidsynth=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_fluidsynth" >&5 -printf "%s\n" "$ac_cv_mingw_lib_fluidsynth" >&6; } -if test "x$ac_cv_mingw_lib_fluidsynth" = xyes -then : - : -else case e in #( - e) FLUIDSYNTH_PE_CFLAGS=""; FLUIDSYNTH_PE_LIBS="" ;; -esac -fi -else case e in #( - e) FLUIDSYNTH_PE_CFLAGS=""; FLUIDSYNTH_PE_LIBS="" ;; -esac -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$FLUIDSYNTH_PE_LIBS" = "x" - then - as_fn_append wine_notices "|Fluidsynth ${notice_platform}MinGW development files not found (or too old); using bundled version." - fi - - if ${JPEG_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - JPEG_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libjpeg 2>/dev/null` -fi -fi -if ${JPEG_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - JPEG_PE_LIBS=`$MINGW_PKG_CONFIG --libs libjpeg 2>/dev/null` -fi -fi - -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $JPEG_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW jpeglib.h" >&5 -printf %s "checking for MinGW jpeglib.h... " >&6; } -if test ${ac_cv_mingw_header_jpeglib_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_jpeglib_h=yes -else case e in #( - e) ac_cv_mingw_header_jpeglib_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_jpeglib_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_jpeglib_h" >&6; } -if test "x$ac_cv_mingw_header_jpeglib_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for jpeg_start_decompress in MinGW -ljpeg" >&5 -printf %s "checking for jpeg_start_decompress in MinGW -ljpeg... " >&6; } -if test ${ac_cv_mingw_lib_jpeg+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-ljpeg $JPEG_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char jpeg_start_decompress (void); -int -main (void) -{ -return jpeg_start_decompress (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_jpeg=yes -else case e in #( - e) ac_cv_mingw_lib_jpeg=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_jpeg" >&5 -printf "%s\n" "$ac_cv_mingw_lib_jpeg" >&6; } -if test "x$ac_cv_mingw_lib_jpeg" = xyes -then : - : -else case e in #( - e) JPEG_PE_CFLAGS=""; JPEG_PE_LIBS="" ;; -esac -fi -else case e in #( - e) JPEG_PE_CFLAGS=""; JPEG_PE_LIBS="" ;; -esac -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$JPEG_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libjpeg ${notice_platform}MinGW development files not found; using bundled version." - fi - - if ${LCMS2_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - LCMS2_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags lcms2 2>/dev/null` -fi -fi -if ${LCMS2_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - LCMS2_PE_LIBS=`$MINGW_PKG_CONFIG --libs lcms2 2>/dev/null` -fi -fi -LCMS2_PE_LIBS=${LCMS2_PE_LIBS:-"-llcms2"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $LCMS2_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW lcms2.h" >&5 -printf %s "checking for MinGW lcms2.h... " >&6; } -if test ${ac_cv_mingw_header_lcms2_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_lcms2_h=yes -else case e in #( - e) ac_cv_mingw_header_lcms2_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_lcms2_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_lcms2_h" >&6; } -if test "x$ac_cv_mingw_header_lcms2_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cmsOpenProfileFromFile in MinGW -llcms2" >&5 -printf %s "checking for cmsOpenProfileFromFile in MinGW -llcms2... " >&6; } -if test ${ac_cv_mingw_lib_lcms2+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-llcms2 $LCMS2_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char cmsOpenProfileFromFile (void); -int -main (void) -{ -return cmsOpenProfileFromFile (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_lcms2=yes -else case e in #( - e) ac_cv_mingw_lib_lcms2=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_lcms2" >&5 -printf "%s\n" "$ac_cv_mingw_lib_lcms2" >&6; } -if test "x$ac_cv_mingw_lib_lcms2" = xyes -then : - : -else case e in #( - e) LCMS2_PE_CFLAGS=""; LCMS2_PE_LIBS="" ;; -esac -fi -else case e in #( - e) LCMS2_PE_CFLAGS=""; LCMS2_PE_LIBS="" ;; -esac -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$LCMS2_PE_LIBS" = "x" - then - as_fn_append wine_notices "|liblcms2 ${notice_platform}MinGW development files not found; using bundled version." - fi - - if ${MPG123_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - MPG123_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libmpg123 2>/dev/null` -fi -fi -if ${MPG123_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - MPG123_PE_LIBS=`$MINGW_PKG_CONFIG --libs libmpg123 2>/dev/null` -fi -fi -MPG123_PE_LIBS=${MPG123_PE_LIBS:-"-lmpg123"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $MPG123_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW mpg123.h" >&5 -printf %s "checking for MinGW mpg123.h... " >&6; } -if test ${ac_cv_mingw_header_mpg123_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_mpg123_h=yes -else case e in #( - e) ac_cv_mingw_header_mpg123_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_mpg123_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_mpg123_h" >&6; } -if test "x$ac_cv_mingw_header_mpg123_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mpg123_feed in MinGW -lmpg123" >&5 -printf %s "checking for mpg123_feed in MinGW -lmpg123... " >&6; } -if test ${ac_cv_mingw_lib_mpg123+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lmpg123 $MPG123_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char mpg123_feed (void); -int -main (void) -{ -return mpg123_feed (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_mpg123=yes -else case e in #( - e) ac_cv_mingw_lib_mpg123=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_mpg123" >&5 -printf "%s\n" "$ac_cv_mingw_lib_mpg123" >&6; } -if test "x$ac_cv_mingw_lib_mpg123" = xyes -then : - : -else case e in #( - e) MPG123_PE_CFLAGS=""; MPG123_PE_LIBS="" ;; -esac -fi -else case e in #( - e) MPG123_PE_CFLAGS=""; MPG123_PE_LIBS="" ;; -esac -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$MPG123_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libmpg123 ${notice_platform}MinGW development files not found (or too old); using bundled version." - fi - - if ${PNG_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - PNG_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libpng 2>/dev/null` -fi -fi -if ${PNG_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - PNG_PE_LIBS=`$MINGW_PKG_CONFIG --libs libpng 2>/dev/null` -fi -fi - -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $PNG_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW png.h" >&5 -printf %s "checking for MinGW png.h... " >&6; } -if test ${ac_cv_mingw_header_png_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_png_h=yes -else case e in #( - e) ac_cv_mingw_header_png_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_png_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_png_h" >&6; } -if test "x$ac_cv_mingw_header_png_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for png_create_read_struct in MinGW -lpng" >&5 -printf %s "checking for png_create_read_struct in MinGW -lpng... " >&6; } -if test ${ac_cv_mingw_lib_png+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lpng $PNG_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char png_create_read_struct (void); -int -main (void) -{ -return png_create_read_struct (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_png=yes -else case e in #( - e) ac_cv_mingw_lib_png=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_png" >&5 -printf "%s\n" "$ac_cv_mingw_lib_png" >&6; } -if test "x$ac_cv_mingw_lib_png" = xyes -then : - : -else case e in #( - e) PNG_PE_CFLAGS=""; PNG_PE_LIBS="" ;; -esac -fi -else case e in #( - e) PNG_PE_CFLAGS=""; PNG_PE_LIBS="" ;; -esac -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$PNG_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libpng ${notice_platform}MinGW development files not found; using bundled version." - fi - - if ${TIFF_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - TIFF_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libtiff-4 2>/dev/null` -fi -fi -if ${TIFF_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - TIFF_PE_LIBS=`$MINGW_PKG_CONFIG --libs libtiff-4 2>/dev/null` -fi -fi - -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $TIFF_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW tiffio.h" >&5 -printf %s "checking for MinGW tiffio.h... " >&6; } -if test ${ac_cv_mingw_header_tiffio_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_tiffio_h=yes -else case e in #( - e) ac_cv_mingw_header_tiffio_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_tiffio_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_tiffio_h" >&6; } -if test "x$ac_cv_mingw_header_tiffio_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for TIFFClientOpen in MinGW -ltiff" >&5 -printf %s "checking for TIFFClientOpen in MinGW -ltiff... " >&6; } -if test ${ac_cv_mingw_lib_tiff+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-ltiff $TIFF_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char TIFFClientOpen (void); -int -main (void) -{ -return TIFFClientOpen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_tiff=yes -else case e in #( - e) ac_cv_mingw_lib_tiff=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_tiff" >&5 -printf "%s\n" "$ac_cv_mingw_lib_tiff" >&6; } -if test "x$ac_cv_mingw_lib_tiff" = xyes -then : - : -else case e in #( - e) TIFF_PE_CFLAGS=""; TIFF_PE_LIBS="" ;; -esac -fi -else case e in #( - e) TIFF_PE_CFLAGS=""; TIFF_PE_LIBS="" ;; -esac -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$TIFF_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libtiff ${notice_platform}MinGW development files not found; using bundled version." - fi - - if ${XML2_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - XML2_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libxml-2.0 2>/dev/null` -fi -fi -if ${XML2_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - XML2_PE_LIBS=`$MINGW_PKG_CONFIG --libs libxml-2.0 2>/dev/null` -fi -fi -XML2_PE_LIBS=${XML2_PE_LIBS:-"-lxml2"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $XML2_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW libxml/parser.h" >&5 -printf %s "checking for MinGW libxml/parser.h... " >&6; } -if test ${ac_cv_mingw_header_libxml_parser_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_libxml_parser_h=yes -else case e in #( - e) ac_cv_mingw_header_libxml_parser_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_libxml_parser_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_libxml_parser_h" >&6; } -if test "x$ac_cv_mingw_header_libxml_parser_h" = xyes -then : - -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW libxml/xmlsave.h" >&5 -printf %s "checking for MinGW libxml/xmlsave.h... " >&6; } -if test ${ac_cv_mingw_header_libxml_xmlsave_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_libxml_xmlsave_h=yes -else case e in #( - e) ac_cv_mingw_header_libxml_xmlsave_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_libxml_xmlsave_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_libxml_xmlsave_h" >&6; } -if test "x$ac_cv_mingw_header_libxml_xmlsave_h" = xyes -then : - -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW libxml/SAX2.h" >&5 -printf %s "checking for MinGW libxml/SAX2.h... " >&6; } -if test ${ac_cv_mingw_header_libxml_SAX2_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_libxml_SAX2_h=yes -else case e in #( - e) ac_cv_mingw_header_libxml_SAX2_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_libxml_SAX2_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_libxml_SAX2_h" >&6; } -if test "x$ac_cv_mingw_header_libxml_SAX2_h" = xyes -then : - -fi - if test "$ac_cv_mingw_header_libxml_parser_h" = "yes" -a "$ac_cv_mingw_header_libxml_xmlsave_h" = "yes" -a "$ac_cv_mingw_header_libxml_SAX2_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for xmlFirstElementChild in MinGW -lxml2" >&5 -printf %s "checking for xmlFirstElementChild in MinGW -lxml2... " >&6; } -if test ${ac_cv_mingw_lib_xml2+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lxml2 $XML2_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char xmlFirstElementChild (void); -int -main (void) -{ -return xmlFirstElementChild (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_xml2=yes -else case e in #( - e) ac_cv_mingw_lib_xml2=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_xml2" >&5 -printf "%s\n" "$ac_cv_mingw_lib_xml2" >&6; } -if test "x$ac_cv_mingw_lib_xml2" = xyes -then : - : -else case e in #( - e) XML2_PE_CFLAGS=""; XML2_PE_LIBS="" ;; -esac -fi - else - XML2_PE_CFLAGS="" - XML2_PE_LIBS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$XML2_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libxml2 ${notice_platform}MinGW development files not found (or too old); using bundled version." - fi - - if ${XSLT_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - XSLT_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libxslt 2>/dev/null` -fi -fi -if ${XSLT_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - XSLT_PE_LIBS=`$MINGW_PKG_CONFIG --libs libxslt 2>/dev/null` -fi -fi -XSLT_PE_LIBS=${XSLT_PE_LIBS:-"-lxslt"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $XSLT_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW libxslt/pattern.h" >&5 -printf %s "checking for MinGW libxslt/pattern.h... " >&6; } -if test ${ac_cv_mingw_header_libxslt_pattern_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_libxslt_pattern_h=yes -else case e in #( - e) ac_cv_mingw_header_libxslt_pattern_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_libxslt_pattern_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_libxslt_pattern_h" >&6; } -if test "x$ac_cv_mingw_header_libxslt_pattern_h" = xyes -then : - -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW libxslt/transform.h" >&5 -printf %s "checking for MinGW libxslt/transform.h... " >&6; } -if test ${ac_cv_mingw_header_libxslt_transform_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_libxslt_transform_h=yes -else case e in #( - e) ac_cv_mingw_header_libxslt_transform_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_libxslt_transform_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_libxslt_transform_h" >&6; } -if test "x$ac_cv_mingw_header_libxslt_transform_h" = xyes -then : - -fi - if test "$ac_cv_mingw_header_libxslt_pattern_h" = "yes" -a "$ac_cv_mingw_header_libxslt_transform_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for xsltCompilePattern in MinGW -lxslt" >&5 -printf %s "checking for xsltCompilePattern in MinGW -lxslt... " >&6; } -if test ${ac_cv_mingw_lib_xslt+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lxslt $XSLT_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char xsltCompilePattern (void); -int -main (void) -{ -return xsltCompilePattern (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_xslt=yes -else case e in #( - e) ac_cv_mingw_lib_xslt=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_xslt" >&5 -printf "%s\n" "$ac_cv_mingw_lib_xslt" >&6; } -if test "x$ac_cv_mingw_lib_xslt" = xyes -then : - : -else case e in #( - e) XSLT_PE_CFLAGS=""; XSLT_PE_LIBS="" ;; -esac -fi - else - XSLT_PE_CFLAGS="" - XSLT_PE_LIBS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$XSLT_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libxslt ${notice_platform}MinGW development files not found; using bundled version." - fi - - if ${VKD3D_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - VKD3D_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libvkd3d libvkd3d-shader 2>/dev/null` -fi -fi -if ${VKD3D_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - VKD3D_PE_LIBS=`$MINGW_PKG_CONFIG --libs libvkd3d libvkd3d-shader 2>/dev/null` -fi -fi -VKD3D_PE_LIBS=${VKD3D_PE_LIBS:-"-lvkd3d -lvkd3d-shader"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $VKD3D_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW vkd3d.h" >&5 -printf %s "checking for MinGW vkd3d.h... " >&6; } -if test ${ac_cv_mingw_header_vkd3d_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_vkd3d_h=yes -else case e in #( - e) ac_cv_mingw_header_vkd3d_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_vkd3d_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_vkd3d_h" >&6; } -if test "x$ac_cv_mingw_header_vkd3d_h" = xyes -then : - -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW vkd3d_shader.h" >&5 -printf %s "checking for MinGW vkd3d_shader.h... " >&6; } -if test ${ac_cv_mingw_header_vkd3d_shader_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_vkd3d_shader_h=yes -else case e in #( - e) ac_cv_mingw_header_vkd3d_shader_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_vkd3d_shader_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_vkd3d_shader_h" >&6; } -if test "x$ac_cv_mingw_header_vkd3d_shader_h" = xyes -then : - -fi - if test "$ac_cv_mingw_header_vkd3d_h" = "yes" -a "$ac_cv_mingw_header_vkd3d_shader_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for vkd3d_set_log_callback in MinGW -lvkd3d" >&5 -printf %s "checking for vkd3d_set_log_callback in MinGW -lvkd3d... " >&6; } -if test ${ac_cv_mingw_lib_vkd3d+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lvkd3d $VKD3D_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char vkd3d_set_log_callback (void); -int -main (void) -{ -return vkd3d_set_log_callback (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_vkd3d=yes -else case e in #( - e) ac_cv_mingw_lib_vkd3d=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_vkd3d" >&5 -printf "%s\n" "$ac_cv_mingw_lib_vkd3d" >&6; } -if test "x$ac_cv_mingw_lib_vkd3d" = xyes -then : - : -else case e in #( - e) : ;; -esac -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for vkd3d_shader_build_varying_map in MinGW -lvkd3d-shader" >&5 -printf %s "checking for vkd3d_shader_build_varying_map in MinGW -lvkd3d-shader... " >&6; } -if test ${ac_cv_mingw_lib_vkd3d_shader+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lvkd3d-shader $VKD3D_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char vkd3d_shader_build_varying_map (void); -int -main (void) -{ -return vkd3d_shader_build_varying_map (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_vkd3d_shader=yes -else case e in #( - e) ac_cv_mingw_lib_vkd3d_shader=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_vkd3d_shader" >&5 -printf "%s\n" "$ac_cv_mingw_lib_vkd3d_shader" >&6; } -if test "x$ac_cv_mingw_lib_vkd3d_shader" = xyes -then : - : -else case e in #( - e) : ;; -esac -fi - if test "$ac_cv_mingw_lib_vkd3d" = "no" -o "$ac_cv_mingw_lib_vkd3d_shader" = "no" - then - VKD3D_PE_CFLAGS="" - VKD3D_PE_LIBS="" - fi - else - VKD3D_PE_CFLAGS="" - VKD3D_PE_LIBS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$VKD3D_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libvkd3d ${notice_platform}MinGW development files not found (or too old); using bundled version." - fi - - if ${ZLIB_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - ZLIB_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags zlib 2>/dev/null` -fi -fi -if ${ZLIB_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - ZLIB_PE_LIBS=`$MINGW_PKG_CONFIG --libs zlib 2>/dev/null` -fi -fi -ZLIB_PE_LIBS=${ZLIB_PE_LIBS:-"-lz"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $ZLIB_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW zlib.h" >&5 -printf %s "checking for MinGW zlib.h... " >&6; } -if test ${ac_cv_mingw_header_zlib_h+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_zlib_h=yes -else case e in #( - e) ac_cv_mingw_header_zlib_h=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_zlib_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_zlib_h" >&6; } -if test "x$ac_cv_mingw_header_zlib_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inflate in MinGW -lz" >&5 -printf %s "checking for inflate in MinGW -lz... " >&6; } -if test ${ac_cv_mingw_lib_z+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lz $ZLIB_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char inflate (void); -int -main (void) -{ -return inflate (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_z=yes -else case e in #( - e) ac_cv_mingw_lib_z=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_z" >&5 -printf "%s\n" "$ac_cv_mingw_lib_z" >&6; } -if test "x$ac_cv_mingw_lib_z" = xyes -then : - : -else case e in #( - e) ZLIB_PE_CFLAGS=""; ZLIB_PE_LIBS="" ;; -esac -fi -else case e in #( - e) ZLIB_PE_CFLAGS=""; ZLIB_PE_LIBS="" ;; -esac -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$ZLIB_PE_LIBS" = "x" - then - as_fn_append wine_notices "|zlib ${notice_platform}MinGW development files not found; using bundled version." - fi -fi - -if ${CAPSTONE_PE_LIBS:+false} : -then : - CAPSTONE_PE_LIBS=capstone - if ${CAPSTONE_PE_CFLAGS:+false} : -then : - CAPSTONE_PE_CFLAGS="-I\$(top_srcdir)/libs/capstone/include" -else case e in #( - e) enable_capstone=no ;; -esac -fi -else case e in #( - e) enable_capstone=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: capstone cflags: $CAPSTONE_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: capstone libs: $CAPSTONE_PE_LIBS" >&5 - -if ${FAUDIO_PE_LIBS:+false} : -then : - FAUDIO_PE_LIBS="faudio mfplat mfreadwrite mfuuid propsys" - if ${FAUDIO_PE_CFLAGS:+false} : -then : - FAUDIO_PE_CFLAGS="-I\$(top_srcdir)/libs/faudio/include" -else case e in #( - e) enable_faudio=no ;; -esac -fi -else case e in #( - e) enable_faudio=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: faudio cflags: $FAUDIO_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: faudio libs: $FAUDIO_PE_LIBS" >&5 - -if ${FLUIDSYNTH_PE_LIBS:+false} : -then : - FLUIDSYNTH_PE_LIBS="fluidsynth" - if ${FLUIDSYNTH_PE_CFLAGS:+false} : -then : - FLUIDSYNTH_PE_CFLAGS="-I\$(top_srcdir)/libs/fluidsynth/include" -else case e in #( - e) enable_fluidsynth=no ;; -esac -fi -else case e in #( - e) enable_fluidsynth=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: fluidsynth cflags: $FLUIDSYNTH_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: fluidsynth libs: $FLUIDSYNTH_PE_LIBS" >&5 - -if ${GSM_PE_LIBS:+false} : -then : - GSM_PE_LIBS=gsm - if ${GSM_PE_CFLAGS:+false} : -then : - GSM_PE_CFLAGS="-I\$(top_srcdir)/libs/gsm/inc" -else case e in #( - e) enable_gsm=no ;; -esac -fi -else case e in #( - e) enable_gsm=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gsm cflags: $GSM_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gsm libs: $GSM_PE_LIBS" >&5 - -if ${JPEG_PE_LIBS:+false} : -then : - JPEG_PE_LIBS=jpeg - if ${JPEG_PE_CFLAGS:+false} : -then : - JPEG_PE_CFLAGS="-I\$(top_srcdir)/libs/jpeg" -else case e in #( - e) enable_jpeg=no ;; -esac -fi -else case e in #( - e) enable_jpeg=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: jpeg cflags: $JPEG_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: jpeg libs: $JPEG_PE_LIBS" >&5 - -if ${JXR_PE_LIBS:+false} : -then : - JXR_PE_LIBS=jxr - if ${JXR_PE_CFLAGS:+false} : -then : - JXR_PE_CFLAGS="-I\$(top_srcdir)/libs/jxr/jxrgluelib -I\$(top_srcdir)/libs/jxr/image/sys" -else case e in #( - e) enable_jxr=no ;; -esac -fi -else case e in #( - e) enable_jxr=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: jxr cflags: $JXR_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: jxr libs: $JXR_PE_LIBS" >&5 - -if ${LCMS2_PE_LIBS:+false} : -then : - LCMS2_PE_LIBS=lcms2 - if ${LCMS2_PE_CFLAGS:+false} : -then : - LCMS2_PE_CFLAGS="-I\$(top_srcdir)/libs/lcms2/include" -else case e in #( - e) enable_lcms2=no ;; -esac -fi -else case e in #( - e) enable_lcms2=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: lcms2 cflags: $LCMS2_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: lcms2 libs: $LCMS2_PE_LIBS" >&5 - -if ${LDAP_PE_LIBS:+false} : -then : - LDAP_PE_LIBS=ldap - if ${LDAP_PE_CFLAGS:+false} : -then : - LDAP_PE_CFLAGS="-I\$(top_srcdir)/libs/ldap/include" -else case e in #( - e) enable_ldap=no ;; -esac -fi -else case e in #( - e) enable_ldap=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: ldap cflags: $LDAP_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: ldap libs: $LDAP_PE_LIBS" >&5 - -if ${MPG123_PE_LIBS:+false} : -then : - MPG123_PE_LIBS=mpg123 - if ${MPG123_PE_CFLAGS:+false} : -then : - MPG123_PE_CFLAGS="-I\$(top_srcdir)/libs/mpg123/src/include" -else case e in #( - e) enable_mpg123=no ;; -esac -fi -else case e in #( - e) enable_mpg123=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: mpg123 cflags: $MPG123_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: mpg123 libs: $MPG123_PE_LIBS" >&5 - -if ${MUSL_PE_LIBS:+false} : -then : - MUSL_PE_LIBS=musl - if ${MUSL_PE_CFLAGS:+false} : -then : - MUSL_PE_CFLAGS= -else case e in #( - e) enable_musl=no ;; -esac -fi -else case e in #( - e) enable_musl=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: musl cflags: $MUSL_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: musl libs: $MUSL_PE_LIBS" >&5 - -if ${PNG_PE_LIBS:+false} : -then : - PNG_PE_LIBS="png \$(ZLIB_PE_LIBS)" - if ${PNG_PE_CFLAGS:+false} : -then : - PNG_PE_CFLAGS="-I\$(top_srcdir)/libs/png" -else case e in #( - e) enable_png=no ;; -esac -fi -else case e in #( - e) enable_png=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: png cflags: $PNG_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: png libs: $PNG_PE_LIBS" >&5 - -if ${TIFF_PE_LIBS:+false} : -then : - TIFF_PE_LIBS="tiff \$(ZLIB_PE_LIBS)" - if ${TIFF_PE_CFLAGS:+false} : -then : - TIFF_PE_CFLAGS="-I\$(top_srcdir)/libs/tiff/libtiff" -else case e in #( - e) enable_tiff=no ;; -esac -fi -else case e in #( - e) enable_tiff=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: tiff cflags: $TIFF_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: tiff libs: $TIFF_PE_LIBS" >&5 - -if ${VKD3D_PE_LIBS:+false} : -then : - VKD3D_PE_LIBS=vkd3d - if ${VKD3D_PE_CFLAGS:+false} : -then : - VKD3D_PE_CFLAGS="-I\$(top_srcdir)/libs/vkd3d/include" -else case e in #( - e) enable_vkd3d=no ;; -esac -fi -else case e in #( - e) enable_vkd3d=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: vkd3d cflags: $VKD3D_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: vkd3d libs: $VKD3D_PE_LIBS" >&5 - -if ${XML2_PE_LIBS:+false} : -then : - XML2_PE_LIBS=xml2 - if ${XML2_PE_CFLAGS:+false} : -then : - XML2_PE_CFLAGS="-I\$(top_srcdir)/libs/xml2/include -DLIBXML_STATIC" -else case e in #( - e) enable_xml2=no ;; -esac -fi -else case e in #( - e) enable_xml2=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xml2 cflags: $XML2_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xml2 libs: $XML2_PE_LIBS" >&5 - -if ${XSLT_PE_LIBS:+false} : -then : - XSLT_PE_LIBS=xslt - if ${XSLT_PE_CFLAGS:+false} : -then : - XSLT_PE_CFLAGS="-I\$(top_srcdir)/libs/xslt/libxslt -I\$(top_srcdir)/libs/xslt -DLIBXSLT_STATIC" -else case e in #( - e) enable_xslt=no ;; -esac -fi -else case e in #( - e) enable_xslt=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xslt cflags: $XSLT_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xslt libs: $XSLT_PE_LIBS" >&5 - -if ${ZLIB_PE_LIBS:+false} : -then : - ZLIB_PE_LIBS=z - if ${ZLIB_PE_CFLAGS:+false} : -then : - ZLIB_PE_CFLAGS="-I\$(top_srcdir)/libs/zlib -DFAR= -DZ_SOLO" -else case e in #( - e) enable_zlib=no ;; -esac -fi -else case e in #( - e) enable_zlib=no ;; -esac -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: zlib cflags: $ZLIB_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: zlib libs: $ZLIB_PE_LIBS" >&5 - - - -if test "x$with_pthread" = xno -then : - -else case e in #( - e) ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" -if test "x$ac_cv_func_pthread_create" = xyes -then : - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 -printf %s "checking for pthread_create in -lpthread... " >&6; } -if test ${ac_cv_lib_pthread_pthread_create+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lpthread $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char pthread_create (void); -int -main (void) -{ -return pthread_create (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_pthread_pthread_create=yes -else case e in #( - e) ac_cv_lib_pthread_pthread_create=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 -printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } -if test "x$ac_cv_lib_pthread_pthread_create" = xyes -then : - PTHREAD_LIBS="-lpthread" - -fi - ;; -esac -fi - ;; -esac -fi -if test "x$ac_cv_func_pthread_create" != xyes -a "x$PTHREAD_LIBS" = x -then : - case "x$with_pthread" in - xno) ;; - *) as_fn_error $? "pthread ${notice_platform}development files not found. -Wine cannot support threads without libpthread. -Use the --without-pthread option if you really want this." "$LINENO" 5 ;; -esac - -fi - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -printf %s "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if test ${ac_cv_prog_CPP+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) # Double quotes because $CC needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - -else case e in #( - e) # Broken: fails on valid input. -continue ;; -esac -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - # Broken: success on invalid input. -continue -else case e in #( - e) # Passes both tests. -ac_preproc_ok=: -break ;; -esac -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok -then : - break -fi - - done - ac_cv_prog_CPP=$CPP - ;; -esac -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -printf "%s\n" "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - -else case e in #( - e) # Broken: fails on valid input. -continue ;; -esac -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - # Broken: success on invalid input. -continue -else case e in #( - e) # Passes both tests. -ac_preproc_ok=: -break ;; -esac -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok -then : - -else case e in #( - e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See 'config.log' for more details" "$LINENO" 5; } ;; -esac -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for X" >&5 -printf %s "checking for X... " >&6; } - - -# Check whether --with-x was given. -if test ${with_x+y} -then : - withval=$with_x; -fi - -# $have_x is 'yes', 'no', 'disabled', or empty when we do not yet know. -if test "x$with_x" = xno; then - # The user explicitly disabled X. - have_x=disabled -else - case $x_includes,$x_libraries in #( - *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( - *,NONE | NONE,*) if test ${ac_cv_have_x+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) # One or both of the vars are not set, and there is no cached value. -ac_x_includes=no -ac_x_libraries=no -# Do we need to do anything special at all? -ac_save_LIBS=$LIBS -LIBS="-lX11 $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -XrmInitialize () - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - # We can compile and link X programs with no special options. - ac_x_includes= - ac_x_libraries= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS="$ac_save_LIBS" -# If that didn't work, only try xmkmf and file system searches -# for native compilation. -if test x"$ac_x_includes" = xno && test "$cross_compiling" = no -then : - rm -f -r conftest.dir -if mkdir conftest.dir; then - cd conftest.dir - cat >Imakefile <<'_ACEOF' -incroot: - @echo incroot='${INCROOT}' -usrlibdir: - @echo usrlibdir='${USRLIBDIR}' -libdir: - @echo libdir='${LIBDIR}' -_ACEOF - if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then - # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. - for ac_var in incroot usrlibdir libdir; do - eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" - done - # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. - for ac_extension in a so sl dylib la dll; do - if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && - test -f "$ac_im_libdir/libX11.$ac_extension"; then - ac_im_usrlibdir=$ac_im_libdir; break - fi - done - # Screen out bogus values from the imake configuration. They are - # bogus both because they are the default anyway, and because - # using them would break gcc on systems where it needs fixed includes. - case $ac_im_incroot in - /usr/include) ac_x_includes= ;; - *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; - esac - case $ac_im_usrlibdir in - /usr/lib | /usr/lib64 | /lib | /lib64) ;; - *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; - esac - fi - cd .. - rm -f -r conftest.dir -fi - - # Standard set of common directories for X headers. -# Check X11 before X11Rn because it is often a symlink to the current release. -ac_x_header_dirs=' -/usr/X11/include -/usr/X11R7/include -/usr/X11R6/include -/usr/X11R5/include -/usr/X11R4/include - -/usr/include/X11 -/usr/include/X11R7 -/usr/include/X11R6 -/usr/include/X11R5 -/usr/include/X11R4 - -/usr/local/X11/include -/usr/local/X11R7/include -/usr/local/X11R6/include -/usr/local/X11R5/include -/usr/local/X11R4/include - -/usr/local/include/X11 -/usr/local/include/X11R7 -/usr/local/include/X11R6 -/usr/local/include/X11R5 -/usr/local/include/X11R4 - -/opt/X11/include - -/usr/X386/include -/usr/x386/include -/usr/XFree86/include/X11 - -/usr/include -/usr/local/include -/usr/unsupported/include -/usr/athena/include -/usr/local/x11r5/include -/usr/lpp/Xamples/include - -/usr/openwin/include -/usr/openwin/share/include' - -if test "$ac_x_includes" = no; then - # Guess where to find include files, by looking for Xlib.h. - # First, try using that file with no special directory specified. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - # We can compile using X headers with no special include directory. -ac_x_includes= -else case e in #( - e) for ac_dir in $ac_x_header_dirs; do - if test -r "$ac_dir/X11/Xlib.h"; then - ac_x_includes=$ac_dir - break - fi -done ;; -esac -fi -rm -f conftest.err conftest.i conftest.$ac_ext -fi # $ac_x_includes = no - -if test "$ac_x_libraries" = no; then - # Check for the libraries. - # See if we find them without any special options. - # Don't add to $LIBS permanently. - ac_save_LIBS=$LIBS - LIBS="-lX11 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -XrmInitialize () - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - LIBS=$ac_save_LIBS -# We can link X programs with no special library path. -ac_x_libraries= -else case e in #( - e) LIBS=$ac_save_LIBS -for ac_dir in `printf "%s\n" "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` -do - # Don't even attempt the hair of trying to link an X program! - for ac_extension in a so sl dylib la dll; do - if test -r "$ac_dir/libX11.$ac_extension"; then - ac_x_libraries=$ac_dir - break 2 - fi - done -done ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi # $ac_x_libraries = no - -fi -# Record the results. -case $ac_x_includes,$ac_x_libraries in #( - no,* | *,no | *\'*) : - # Didn't find X, or a directory has "'" in its name. - ac_cv_have_x="have_x=no" ;; #( - *) : - # Record where we found X for the cache. - ac_cv_have_x="have_x=yes\ - ac_x_includes='$ac_x_includes'\ - ac_x_libraries='$ac_x_libraries'" ;; -esac ;; -esac -fi -;; #( - *) have_x=yes;; - esac - eval "$ac_cv_have_x" -fi # $with_x != no - -if test "$have_x" != yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 -printf "%s\n" "$have_x" >&6; } - no_x=yes -else - # If each of the values was on the command line, it overrides each guess. - test "x$x_includes" = xNONE && x_includes=$ac_x_includes - test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries - # Update the cache value to reflect the command line values. - ac_cv_have_x="have_x=yes\ - ac_x_includes='$x_includes'\ - ac_x_libraries='$x_libraries'" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 -printf "%s\n" "libraries $x_libraries, headers $x_includes" >&6; } -fi - -if test "$have_x" = "yes" -then - test -z "$x_includes" || X_CFLAGS="$X_CFLAGS -I$x_includes" - - test -z "$x_libraries" || X_LIBS="$X_LIBS -L$x_libraries" - - - ac_save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $X_CFLAGS" - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lX11" >&5 -printf %s "checking for -lX11... " >&6; } -if test ${ac_cv_lib_soname_X11+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lX11 $X_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XCreateWindow (void); -int -main (void) -{ -return XCreateWindow (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_X11=`$ac_cv_path_LDD conftest.exe | grep "X11" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_X11=`$OTOOL -L conftest$ac_exeext | grep "libX11\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libX11\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_X11=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libX11\\.$LIBEXT" | sed -e "s/^.*\\[\\(libX11\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_X11:+false} : -then : - ac_cv_lib_soname_X11=`$LDD conftest$ac_exeext | grep "libX11\\.$LIBEXT" | sed -e "s/^.*\(libX11\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_X11= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_X11:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_X11" >&5 -printf "%s\n" "$ac_cv_lib_soname_X11" >&6; } - -printf "%s\n" "#define SONAME_LIBX11 \"$ac_cv_lib_soname_X11\"" >>confdefs.h - - ;; -esac -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXext" >&5 -printf %s "checking for -lXext... " >&6; } -if test ${ac_cv_lib_soname_Xext+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lXext $X_LIBS -lX11 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XextCreateExtension (void); -int -main (void) -{ -return XextCreateExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xext=`$ac_cv_path_LDD conftest.exe | grep "Xext" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xext=`$OTOOL -L conftest$ac_exeext | grep "libXext\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXext\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xext=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXext\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXext\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xext:+false} : -then : - ac_cv_lib_soname_Xext=`$LDD conftest$ac_exeext | grep "libXext\\.$LIBEXT" | sed -e "s/^.*\(libXext\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_Xext= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_Xext:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xext" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xext" >&6; } - -printf "%s\n" "#define SONAME_LIBXEXT \"$ac_cv_lib_soname_Xext\"" >>confdefs.h - - X_LIBS="$X_LIBS -lXext" ;; -esac -fi - X_LIBS="$X_LIBS -lX11" - - xlib_includes="#include -#include " - - ac_fn_c_check_header_compile "$LINENO" "X11/extensions/shape.h" "ac_cv_header_X11_extensions_shape_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_extensions_shape_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_SHAPE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/XInput2.h" "ac_cv_header_X11_extensions_XInput2_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_extensions_XInput2_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XINPUT2_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/XShm.h" "ac_cv_header_X11_extensions_XShm_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_extensions_XShm_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XSHM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xfixes.h" "ac_cv_header_X11_extensions_Xfixes_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_extensions_Xfixes_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XFIXES_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xinerama.h" "ac_cv_header_X11_extensions_Xinerama_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_extensions_Xinerama_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XINERAMA_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xrandr.h" "ac_cv_header_X11_extensions_Xrandr_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_extensions_Xrandr_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XRANDR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xrender.h" "ac_cv_header_X11_extensions_Xrender_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_extensions_Xrender_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XRENDER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/xf86vmode.h" "ac_cv_header_X11_extensions_xf86vmode_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_extensions_xf86vmode_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XF86VMODE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/xf86vmproto.h" "ac_cv_header_X11_extensions_xf86vmproto_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_extensions_xf86vmproto_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XF86VMPROTO_H 1" >>confdefs.h - -fi - - - ac_fn_c_check_header_compile "$LINENO" "X11/Xcursor/Xcursor.h" "ac_cv_header_X11_Xcursor_Xcursor_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_Xcursor_Xcursor_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXcursor" >&5 -printf %s "checking for -lXcursor... " >&6; } -if test ${ac_cv_lib_soname_Xcursor+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lXcursor $X_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XcursorImageLoadCursor (void); -int -main (void) -{ -return XcursorImageLoadCursor (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xcursor=`$ac_cv_path_LDD conftest.exe | grep "Xcursor" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xcursor=`$OTOOL -L conftest$ac_exeext | grep "libXcursor\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXcursor\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xcursor=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXcursor\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXcursor\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xcursor:+false} : -then : - ac_cv_lib_soname_Xcursor=`$LDD conftest$ac_exeext | grep "libXcursor\\.$LIBEXT" | sed -e "s/^.*\(libXcursor\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_Xcursor= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_Xcursor:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xcursor" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xcursor" >&6; } - -printf "%s\n" "#define SONAME_LIBXCURSOR \"$ac_cv_lib_soname_Xcursor\"" >>confdefs.h - - ;; -esac -fi -fi - - if test "x$ac_cv_lib_soname_Xcursor" = "x" -then : - case "x$with_xcursor" in - x) as_fn_append wine_notices "|libxcursor ${notice_platform}development files not found, the Xcursor extension won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxcursor ${notice_platform}development files not found, the Xcursor extension won't be supported. -This is an error since --with-xcursor was requested." "$LINENO" 5 ;; -esac - -fi - - ac_fn_c_check_header_compile "$LINENO" "X11/extensions/XInput.h" "ac_cv_header_X11_extensions_XInput_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_extensions_XInput_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXi" >&5 -printf %s "checking for -lXi... " >&6; } -if test ${ac_cv_lib_soname_Xi+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lXi $X_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XOpenDevice (void); -int -main (void) -{ -return XOpenDevice (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xi=`$ac_cv_path_LDD conftest.exe | grep "Xi" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xi=`$OTOOL -L conftest$ac_exeext | grep "libXi\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXi\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xi=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXi\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXi\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xi:+false} : -then : - ac_cv_lib_soname_Xi=`$LDD conftest$ac_exeext | grep "libXi\\.$LIBEXT" | sed -e "s/^.*\(libXi\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_Xi= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_Xi:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xi" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xi" >&6; } - -printf "%s\n" "#define SONAME_LIBXI \"$ac_cv_lib_soname_Xi\"" >>confdefs.h - - ;; -esac -fi -fi - - if test "x$ac_cv_lib_soname_Xi" = "x" -then : - case "x$with_xinput" in - x) as_fn_append wine_notices "|libxi ${notice_platform}development files not found, the Xinput extension won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxi ${notice_platform}development files not found, the Xinput extension won't be supported. -This is an error since --with-xinput was requested." "$LINENO" 5 ;; -esac - -fi - - if test "x$ac_cv_lib_soname_Xi" != x - then - if test "$ac_cv_header_X11_extensions_XInput2_h" != "yes" -then : - case "x$with_xinput2" in - x) as_fn_append wine_notices "|XInput2 headers not found, the XInput 2 extension won't be supported." ;; - xno) ;; - *) as_fn_error $? "XInput2 headers not found, the XInput 2 extension won't be supported. -This is an error since --with-xinput2 was requested." "$LINENO" 5 ;; -esac - -fi - fi - - if test "$ac_cv_header_X11_extensions_XShm_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for XShmQueryExtension in -lXext" >&5 -printf %s "checking for XShmQueryExtension in -lXext... " >&6; } -if test ${ac_cv_lib_Xext_XShmQueryExtension+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lXext $X_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XShmQueryExtension (void); -int -main (void) -{ -return XShmQueryExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_Xext_XShmQueryExtension=yes -else case e in #( - e) ac_cv_lib_Xext_XShmQueryExtension=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xext_XShmQueryExtension" >&5 -printf "%s\n" "$ac_cv_lib_Xext_XShmQueryExtension" >&6; } -if test "x$ac_cv_lib_Xext_XShmQueryExtension" = xyes -then : - -printf "%s\n" "#define HAVE_LIBXXSHM 1" >>confdefs.h - -fi - - fi - if test "$ac_cv_lib_Xext_XShmQueryExtension" != "yes" -then : - case "x$with_xshm" in - x) as_fn_append wine_notices "|XShm ${notice_platform}development files not found, X Shared Memory won't be supported." ;; - xno) ;; - *) as_fn_error $? "XShm ${notice_platform}development files not found, X Shared Memory won't be supported. -This is an error since --with-xshm was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_shape_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for XShapeQueryExtension in -lXext" >&5 -printf %s "checking for XShapeQueryExtension in -lXext... " >&6; } -if test ${ac_cv_lib_Xext_XShapeQueryExtension+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lXext $X_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XShapeQueryExtension (void); -int -main (void) -{ -return XShapeQueryExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_Xext_XShapeQueryExtension=yes -else case e in #( - e) ac_cv_lib_Xext_XShapeQueryExtension=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xext_XShapeQueryExtension" >&5 -printf "%s\n" "$ac_cv_lib_Xext_XShapeQueryExtension" >&6; } -if test "x$ac_cv_lib_Xext_XShapeQueryExtension" = xyes -then : - -printf "%s\n" "#define HAVE_LIBXSHAPE 1" >>confdefs.h - -fi - - fi - if test "$ac_cv_lib_Xext_XShapeQueryExtension" != "yes" -then : - case "x$with_xshape" in - x) as_fn_append wine_notices "|XShape ${notice_platform}development files not found, XShape won't be supported." ;; - xno) ;; - *) as_fn_error $? "XShape ${notice_platform}development files not found, XShape won't be supported. -This is an error since --with-xshape was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_xf86vmode_h" = "yes" -o "$ac_cv_header_X11_extensions_xf86vmproto_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXxf86vm" >&5 -printf %s "checking for -lXxf86vm... " >&6; } -if test ${ac_cv_lib_soname_Xxf86vm+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lXxf86vm $X_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XF86VidModeQueryExtension (void); -int -main (void) -{ -return XF86VidModeQueryExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xxf86vm=`$ac_cv_path_LDD conftest.exe | grep "Xxf86vm" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xxf86vm=`$OTOOL -L conftest$ac_exeext | grep "libXxf86vm\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXxf86vm\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xxf86vm=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXxf86vm\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXxf86vm\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xxf86vm:+false} : -then : - ac_cv_lib_soname_Xxf86vm=`$LDD conftest$ac_exeext | grep "libXxf86vm\\.$LIBEXT" | sed -e "s/^.*\(libXxf86vm\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_Xxf86vm= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_Xxf86vm:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xxf86vm" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xxf86vm" >&6; } - -printf "%s\n" "#define SONAME_LIBXXF86VM \"$ac_cv_lib_soname_Xxf86vm\"" >>confdefs.h - - ;; -esac -fi - fi - if test "x$ac_cv_lib_soname_Xxf86vm" = "x" -then : - case "x$with_xxf86vm" in - x) as_fn_append wine_notices "|libXxf86vm ${notice_platform}development files not found, XFree86 Vidmode won't be supported." ;; - xno) ;; - *) as_fn_error $? "libXxf86vm ${notice_platform}development files not found, XFree86 Vidmode won't be supported. -This is an error since --with-xxf86vm was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_Xrender_h" = "yes" -a "x$ac_cv_lib_soname_X11" != "x" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXrender" >&5 -printf %s "checking for -lXrender... " >&6; } -if test ${ac_cv_lib_soname_Xrender+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lXrender $X_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XRenderQueryExtension (void); -int -main (void) -{ -return XRenderQueryExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xrender=`$ac_cv_path_LDD conftest.exe | grep "Xrender" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xrender=`$OTOOL -L conftest$ac_exeext | grep "libXrender\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXrender\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xrender=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXrender\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXrender\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xrender:+false} : -then : - ac_cv_lib_soname_Xrender=`$LDD conftest$ac_exeext | grep "libXrender\\.$LIBEXT" | sed -e "s/^.*\(libXrender\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_Xrender= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_Xrender:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xrender" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xrender" >&6; } - -printf "%s\n" "#define SONAME_LIBXRENDER \"$ac_cv_lib_soname_Xrender\"" >>confdefs.h - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for XRenderSetPictureTransform in -lXrender" >&5 -printf %s "checking for XRenderSetPictureTransform in -lXrender... " >&6; } -if test ${ac_cv_lib_Xrender_XRenderSetPictureTransform+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lXrender $X_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XRenderSetPictureTransform (void); -int -main (void) -{ -return XRenderSetPictureTransform (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_Xrender_XRenderSetPictureTransform=yes -else case e in #( - e) ac_cv_lib_Xrender_XRenderSetPictureTransform=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xrender_XRenderSetPictureTransform" >&5 -printf "%s\n" "$ac_cv_lib_Xrender_XRenderSetPictureTransform" >&6; } -if test "x$ac_cv_lib_Xrender_XRenderSetPictureTransform" = xyes -then : - -printf "%s\n" "#define HAVE_XRENDERSETPICTURETRANSFORM 1" >>confdefs.h - -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for XRenderCreateLinearGradient in -lXrender" >&5 -printf %s "checking for XRenderCreateLinearGradient in -lXrender... " >&6; } -if test ${ac_cv_lib_Xrender_XRenderCreateLinearGradient+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lXrender $X_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XRenderCreateLinearGradient (void); -int -main (void) -{ -return XRenderCreateLinearGradient (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_Xrender_XRenderCreateLinearGradient=yes -else case e in #( - e) ac_cv_lib_Xrender_XRenderCreateLinearGradient=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xrender_XRenderCreateLinearGradient" >&5 -printf "%s\n" "$ac_cv_lib_Xrender_XRenderCreateLinearGradient" >&6; } -if test "x$ac_cv_lib_Xrender_XRenderCreateLinearGradient" = xyes -then : - -printf "%s\n" "#define HAVE_XRENDERCREATELINEARGRADIENT 1" >>confdefs.h - -fi - ;; -esac -fi - - fi - if test "x$ac_cv_lib_soname_Xrender" = "x" -then : - case "x$with_xrender" in - x) as_fn_append wine_warnings "|libxrender ${notice_platform}development files not found, XRender won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxrender ${notice_platform}development files not found, XRender won't be supported. -This is an error since --with-xrender was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_Xrandr_h" = "yes" -a "x$ac_cv_lib_soname_Xrender" != "x" - then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main (void) -{ -static typeof(XRRSetScreenConfigAndRate) * func; if (func) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXrandr" >&5 -printf %s "checking for -lXrandr... " >&6; } -if test ${ac_cv_lib_soname_Xrandr+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lXrandr $X_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XRRQueryExtension (void); -int -main (void) -{ -return XRRQueryExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xrandr=`$ac_cv_path_LDD conftest.exe | grep "Xrandr" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xrandr=`$OTOOL -L conftest$ac_exeext | grep "libXrandr\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXrandr\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xrandr=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXrandr\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXrandr\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xrandr:+false} : -then : - ac_cv_lib_soname_Xrandr=`$LDD conftest$ac_exeext | grep "libXrandr\\.$LIBEXT" | sed -e "s/^.*\(libXrandr\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_Xrandr= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_Xrandr:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xrandr" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xrandr" >&6; } - -printf "%s\n" "#define SONAME_LIBXRANDR \"$ac_cv_lib_soname_Xrandr\"" >>confdefs.h - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main (void) -{ -static typeof(XRRGetProviderResources) *f; if (f) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -printf "%s\n" "#define HAVE_XRRGETPROVIDERRESOURCES 1" >>confdefs.h - -else case e in #( - e) as_fn_append wine_notices "|libxrandr ${notice_platform}development files too old, XRandR display device handler won't be supported." ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - fi - if test "x$ac_cv_lib_soname_Xrandr" = "x" -then : - case "x$with_xrandr" in - x) as_fn_append wine_notices "|libxrandr ${notice_platform}development files not found, XRandr won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxrandr ${notice_platform}development files not found, XRandr won't be supported. -This is an error since --with-xrandr was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_Xfixes_h" = "yes" - then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main (void) -{ -static typeof(XFixesQueryVersion) * func; if (func) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXfixes" >&5 -printf %s "checking for -lXfixes... " >&6; } -if test ${ac_cv_lib_soname_Xfixes+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lXfixes $X_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XFixesQueryVersion (void); -int -main (void) -{ -return XFixesQueryVersion (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xfixes=`$ac_cv_path_LDD conftest.exe | grep "Xfixes" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xfixes=`$OTOOL -L conftest$ac_exeext | grep "libXfixes\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXfixes\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xfixes=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXfixes\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXfixes\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xfixes:+false} : -then : - ac_cv_lib_soname_Xfixes=`$LDD conftest$ac_exeext | grep "libXfixes\\.$LIBEXT" | sed -e "s/^.*\(libXfixes\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_Xfixes= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_Xfixes:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xfixes" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xfixes" >&6; } - -printf "%s\n" "#define SONAME_LIBXFIXES \"$ac_cv_lib_soname_Xfixes\"" >>confdefs.h - - ;; -esac -fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - fi - if test "x$ac_cv_lib_soname_Xfixes" = "x" -then : - case "x$with_xfixes" in - x) as_fn_append wine_notices "|libxfixes ${notice_platform}development files not found, Xfixes won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxfixes ${notice_platform}development files not found, Xfixes won't be supported. -This is an error since --with-xfixes was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_Xinerama_h" = "yes" - then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main (void) -{ -static typeof(XineramaQueryScreens) * func; if (func) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXinerama" >&5 -printf %s "checking for -lXinerama... " >&6; } -if test ${ac_cv_lib_soname_Xinerama+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lXinerama $X_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XineramaQueryScreens (void); -int -main (void) -{ -return XineramaQueryScreens (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xinerama=`$ac_cv_path_LDD conftest.exe | grep "Xinerama" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xinerama=`$OTOOL -L conftest$ac_exeext | grep "libXinerama\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXinerama\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xinerama=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXinerama\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXinerama\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xinerama:+false} : -then : - ac_cv_lib_soname_Xinerama=`$LDD conftest$ac_exeext | grep "libXinerama\\.$LIBEXT" | sed -e "s/^.*\(libXinerama\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_Xinerama= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_Xinerama:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xinerama" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xinerama" >&6; } - -printf "%s\n" "#define SONAME_LIBXINERAMA \"$ac_cv_lib_soname_Xinerama\"" >>confdefs.h - - ;; -esac -fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - fi - if test "x$ac_cv_lib_soname_Xinerama" = "x" -then : - case "x$with_xinerama" in - x) as_fn_append wine_notices "|libxinerama ${notice_platform}development files not found, multi-monitor setups won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxinerama ${notice_platform}development files not found, multi-monitor setups won't be supported. -This is an error since --with-xinerama was requested." "$LINENO" 5 ;; -esac - -fi - - ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xcomposite.h" "ac_cv_header_X11_extensions_Xcomposite_h" "$xlib_includes -" -if test "x$ac_cv_header_X11_extensions_Xcomposite_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXcomposite" >&5 -printf %s "checking for -lXcomposite... " >&6; } -if test ${ac_cv_lib_soname_Xcomposite+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lXcomposite $X_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char XCompositeRedirectWindow (void); -int -main (void) -{ -return XCompositeRedirectWindow (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xcomposite=`$ac_cv_path_LDD conftest.exe | grep "Xcomposite" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xcomposite=`$OTOOL -L conftest$ac_exeext | grep "libXcomposite\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXcomposite\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xcomposite=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXcomposite\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXcomposite\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xcomposite:+false} : -then : - ac_cv_lib_soname_Xcomposite=`$LDD conftest$ac_exeext | grep "libXcomposite\\.$LIBEXT" | sed -e "s/^.*\(libXcomposite\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_Xcomposite= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_Xcomposite:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xcomposite" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xcomposite" >&6; } - -printf "%s\n" "#define SONAME_LIBXCOMPOSITE \"$ac_cv_lib_soname_Xcomposite\"" >>confdefs.h - - ;; -esac -fi -fi - - if test "x$ac_cv_lib_soname_Xcomposite" = "x" -then : - case "x$with_xcomposite" in - x) as_fn_append wine_notices "|libxcomposite ${notice_platform}development files not found, Xcomposite won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxcomposite ${notice_platform}development files not found, Xcomposite won't be supported. -This is an error since --with-xcomposite was requested." "$LINENO" 5 ;; -esac - -fi - - ac_fn_c_check_member "$LINENO" "XICCallback" "callback" "ac_cv_member_XICCallback_callback" "$xlib_includes -" -if test "x$ac_cv_member_XICCallback_callback" = xyes -then : - -printf "%s\n" "#define HAVE_XICCALLBACK_CALLBACK 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "XEvent" "xcookie" "ac_cv_member_XEvent_xcookie" "$xlib_includes -" -if test "x$ac_cv_member_XEvent_xcookie" = xyes -then : - -printf "%s\n" "#define HAVE_XEVENT_XCOOKIE 1" >>confdefs.h - - -fi - - - - opengl_msg="" - if test "x$with_opengl" != "xno" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lGL" >&5 -printf %s "checking for -lGL... " >&6; } -if test ${ac_cv_lib_soname_GL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lGL $X_LIBS -lm $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char glXCreateContext (void); -int -main (void) -{ -return glXCreateContext (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_GL=`$ac_cv_path_LDD conftest.exe | grep "GL" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_GL=`$OTOOL -L conftest$ac_exeext | grep "libGL\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libGL\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_GL=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libGL\\.$LIBEXT" | sed -e "s/^.*\\[\\(libGL\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_GL:+false} : -then : - ac_cv_lib_soname_GL=`$LDD conftest$ac_exeext | grep "libGL\\.$LIBEXT" | sed -e "s/^.*\(libGL\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_GL= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_GL:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lGL" >&5 -printf %s "checking for -lGL... " >&6; } -if test ${ac_cv_lib_soname_GL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lGL $X_LIBS -lm -dylib_file /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char glXCreateContext (void); -int -main (void) -{ -return glXCreateContext (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_GL=`$ac_cv_path_LDD conftest.exe | grep "GL" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_GL=`$OTOOL -L conftest$ac_exeext | grep "libGL\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libGL\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_GL=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libGL\\.$LIBEXT" | sed -e "s/^.*\\[\\(libGL\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_GL:+false} : -then : - ac_cv_lib_soname_GL=`$LDD conftest$ac_exeext | grep "libGL\\.$LIBEXT" | sed -e "s/^.*\(libGL\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_GL= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_GL:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - if test -f /usr/X11R6/lib/libGL.a - then - opengl_msg="/usr/X11R6/lib/libGL.a is present on your system. -This probably prevents linking to OpenGL. Try deleting the file and restarting configure." - else - opengl_msg="No OpenGL library found on this system." - fi -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_GL" >&5 -printf "%s\n" "$ac_cv_lib_soname_GL" >&6; } - -printf "%s\n" "#define SONAME_LIBGL \"$ac_cv_lib_soname_GL\"" >>confdefs.h - - OPENGL_LIBS="-Xlinker -dylib_file -Xlinker /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib -lGL" ;; -esac -fi -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_GL" >&5 -printf "%s\n" "$ac_cv_lib_soname_GL" >&6; } - -printf "%s\n" "#define SONAME_LIBGL \"$ac_cv_lib_soname_GL\"" >>confdefs.h - - OPENGL_LIBS="-lGL" ;; -esac -fi - if test "x$with_osmesa" != "xno" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lOSMesa" >&5 -printf %s "checking for -lOSMesa... " >&6; } -if test ${ac_cv_lib_soname_OSMesa+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lOSMesa $X_LIBS -lm $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char OSMesaGetProcAddress (void); -int -main (void) -{ -return OSMesaGetProcAddress (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_OSMesa=`$ac_cv_path_LDD conftest.exe | grep "OSMesa" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_OSMesa=`$OTOOL -L conftest$ac_exeext | grep "libOSMesa\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libOSMesa\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_OSMesa=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libOSMesa\\.$LIBEXT" | sed -e "s/^.*\\[\\(libOSMesa\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_OSMesa:+false} : -then : - ac_cv_lib_soname_OSMesa=`$LDD conftest$ac_exeext | grep "libOSMesa\\.$LIBEXT" | sed -e "s/^.*\(libOSMesa\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_OSMesa= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_OSMesa:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_OSMesa" >&5 -printf "%s\n" "$ac_cv_lib_soname_OSMesa" >&6; } - -printf "%s\n" "#define SONAME_LIBOSMESA \"$ac_cv_lib_soname_OSMesa\"" >>confdefs.h - - ;; -esac -fi - if test "x$ac_cv_lib_soname_OSMesa" = "x" -then : - case "x$with_osmesa" in - x) as_fn_append wine_notices "|libOSMesa ${notice_platform}development files not found (or too old), OpenGL rendering in bitmaps won't be supported." ;; - xno) ;; - *) as_fn_error $? "libOSMesa ${notice_platform}development files not found (or too old), OpenGL rendering in bitmaps won't be supported. -This is an error since --with-osmesa was requested." "$LINENO" 5 ;; -esac - -fi - fi - fi - if test -n "$opengl_msg" -then : - case "x$with_opengl" in - x) as_fn_append wine_warnings "|$opengl_msg -OpenGL and Direct3D won't be supported." ;; - xno) ;; - *) as_fn_error $? "$opengl_msg -OpenGL and Direct3D won't be supported. -This is an error since --with-opengl was requested." "$LINENO" 5 ;; -esac - -fi - - CPPFLAGS="$ac_save_CPPFLAGS" -else - X_CFLAGS="" - X_LIBS="" -fi - -if test "x$with_wayland" != "xno" -then - rm -f conftest.err -if ${WAYLAND_CLIENT_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - WAYLAND_CLIENT_CFLAGS=`$PKG_CONFIG --cflags wayland-client 2>conftest.err` -fi -fi - -if ${WAYLAND_CLIENT_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - WAYLAND_CLIENT_LIBS=`$PKG_CONFIG --libs wayland-client 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: wayland-client cflags: $WAYLAND_CLIENT_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: wayland-client libs: $WAYLAND_CLIENT_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: wayland-client errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $WAYLAND_CLIENT_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "wayland-client.h" "ac_cv_header_wayland_client_h" "$ac_includes_default" -if test "x$ac_cv_header_wayland_client_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wl_display_connect in -lwayland-client" >&5 -printf %s "checking for wl_display_connect in -lwayland-client... " >&6; } -if test ${ac_cv_lib_wayland_client_wl_display_connect+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lwayland-client $WAYLAND_CLIENT_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char wl_display_connect (void); -int -main (void) -{ -return wl_display_connect (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_wayland_client_wl_display_connect=yes -else case e in #( - e) ac_cv_lib_wayland_client_wl_display_connect=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wayland_client_wl_display_connect" >&5 -printf "%s\n" "$ac_cv_lib_wayland_client_wl_display_connect" >&6; } -if test "x$ac_cv_lib_wayland_client_wl_display_connect" = xyes -then : - # Extract the first word of "wayland-scanner", so it can be a program name with args. -set dummy wayland-scanner; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_WAYLAND_SCANNER+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) case $WAYLAND_SCANNER in - [\\/]* | ?:[\\/]*) - ac_cv_path_WAYLAND_SCANNER="$WAYLAND_SCANNER" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_WAYLAND_SCANNER="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_WAYLAND_SCANNER" && ac_cv_path_WAYLAND_SCANNER="`test -n "$PKG_CONFIG" && $PKG_CONFIG --variable=wayland_scanner wayland-scanner 2>/dev/null`" - ;; -esac ;; -esac -fi -WAYLAND_SCANNER=$ac_cv_path_WAYLAND_SCANNER -if test -n "$WAYLAND_SCANNER"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WAYLAND_SCANNER" >&5 -printf "%s\n" "$WAYLAND_SCANNER" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -else case e in #( - e) WAYLAND_CLIENT_LIBS="" ;; -esac -fi - -fi - -CPPFLAGS=$ac_save_CPPFLAGS - - rm -f conftest.err -if ${XKBCOMMON_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - XKBCOMMON_CFLAGS=`$PKG_CONFIG --cflags xkbcommon 2>conftest.err` -fi -fi - -if ${XKBCOMMON_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - XKBCOMMON_LIBS=`$PKG_CONFIG --libs xkbcommon 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xkbcommon cflags: $XKBCOMMON_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xkbcommon libs: $XKBCOMMON_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: xkbcommon errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $XKBCOMMON_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "xkbcommon/xkbcommon.h" "ac_cv_header_xkbcommon_xkbcommon_h" "$ac_includes_default" -if test "x$ac_cv_header_xkbcommon_xkbcommon_h" = xyes -then : - printf "%s\n" "#define HAVE_XKBCOMMON_XKBCOMMON_H 1" >>confdefs.h - -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for xkb_context_new in -lxkbcommon" >&5 -printf %s "checking for xkb_context_new in -lxkbcommon... " >&6; } -if test ${ac_cv_lib_xkbcommon_xkb_context_new+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lxkbcommon $XKBCOMMON_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char xkb_context_new (void); -int -main (void) -{ -return xkb_context_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_xkbcommon_xkb_context_new=yes -else case e in #( - e) ac_cv_lib_xkbcommon_xkb_context_new=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xkbcommon_xkb_context_new" >&5 -printf "%s\n" "$ac_cv_lib_xkbcommon_xkb_context_new" >&6; } -if test "x$ac_cv_lib_xkbcommon_xkb_context_new" = xyes -then : - : -else case e in #( - e) XKBCOMMON_LIBS="" ;; -esac -fi - -CPPFLAGS=$ac_save_CPPFLAGS - - rm -f conftest.err -if ${XKBREGISTRY_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - XKBREGISTRY_CFLAGS=`$PKG_CONFIG --cflags xkbregistry 2>conftest.err` -fi -fi - -if ${XKBREGISTRY_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - XKBREGISTRY_LIBS=`$PKG_CONFIG --libs xkbregistry 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xkbregistry cflags: $XKBREGISTRY_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xkbregistry libs: $XKBREGISTRY_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: xkbregistry errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $XKBREGISTRY_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "xkbcommon/xkbregistry.h" "ac_cv_header_xkbcommon_xkbregistry_h" "$ac_includes_default" -if test "x$ac_cv_header_xkbcommon_xkbregistry_h" = xyes -then : - printf "%s\n" "#define HAVE_XKBCOMMON_XKBREGISTRY_H 1" >>confdefs.h - -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rxkb_context_new in -lxkbregistry" >&5 -printf %s "checking for rxkb_context_new in -lxkbregistry... " >&6; } -if test ${ac_cv_lib_xkbregistry_rxkb_context_new+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lxkbregistry $XKBREGISTRY_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char rxkb_context_new (void); -int -main (void) -{ -return rxkb_context_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_xkbregistry_rxkb_context_new=yes -else case e in #( - e) ac_cv_lib_xkbregistry_rxkb_context_new=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xkbregistry_rxkb_context_new" >&5 -printf "%s\n" "$ac_cv_lib_xkbregistry_rxkb_context_new" >&6; } -if test "x$ac_cv_lib_xkbregistry_rxkb_context_new" = xyes -then : - : -else case e in #( - e) XKBREGISTRY_LIBS="" ;; -esac -fi - -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$with_opengl" != "xno" - then - rm -f conftest.err -if ${EGL_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - EGL_CFLAGS=`$PKG_CONFIG --cflags egl 2>conftest.err` -fi -fi - -if ${EGL_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - EGL_LIBS=`$PKG_CONFIG --libs egl 2>/dev/null` -fi -fi - -EGL_LIBS=${EGL_LIBS:-"-lEGL"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: egl cflags: $EGL_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: egl libs: $EGL_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: egl errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $EGL_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "EGL/egl.h" "ac_cv_header_EGL_egl_h" "$ac_includes_default" -if test "x$ac_cv_header_EGL_egl_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lEGL" >&5 -printf %s "checking for -lEGL... " >&6; } -if test ${ac_cv_lib_soname_EGL+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lEGL $EGL_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char eglGetProcAddress (void); -int -main (void) -{ -return eglGetProcAddress (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_EGL=`$ac_cv_path_LDD conftest.exe | grep "EGL" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_EGL=`$OTOOL -L conftest$ac_exeext | grep "libEGL\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libEGL\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_EGL=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libEGL\\.$LIBEXT" | sed -e "s/^.*\\[\\(libEGL\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_EGL:+false} : -then : - ac_cv_lib_soname_EGL=`$LDD conftest$ac_exeext | grep "libEGL\\.$LIBEXT" | sed -e "s/^.*\(libEGL\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_EGL= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_EGL:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_EGL" >&5 -printf "%s\n" "$ac_cv_lib_soname_EGL" >&6; } - -printf "%s\n" "#define SONAME_LIBEGL \"$ac_cv_lib_soname_EGL\"" >>confdefs.h - - ;; -esac -fi -fi - -CPPFLAGS=$ac_save_CPPFLAGS - - rm -f conftest.err -if ${WAYLAND_EGL_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - WAYLAND_EGL_CFLAGS=`$PKG_CONFIG --cflags wayland-egl 2>conftest.err` -fi -fi - -if ${WAYLAND_EGL_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - WAYLAND_EGL_LIBS=`$PKG_CONFIG --libs wayland-egl 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: wayland-egl cflags: $WAYLAND_EGL_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: wayland-egl libs: $WAYLAND_EGL_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: wayland-egl errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $WAYLAND_EGL_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "wayland-egl.h" "ac_cv_header_wayland_egl_h" "$ac_includes_default" -if test "x$ac_cv_header_wayland_egl_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wl_egl_window_create in -lwayland-egl" >&5 -printf %s "checking for wl_egl_window_create in -lwayland-egl... " >&6; } -if test ${ac_cv_lib_wayland_egl_wl_egl_window_create+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lwayland-egl $WAYLAND_EGL_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char wl_egl_window_create (void); -int -main (void) -{ -return wl_egl_window_create (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_wayland_egl_wl_egl_window_create=yes -else case e in #( - e) ac_cv_lib_wayland_egl_wl_egl_window_create=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wayland_egl_wl_egl_window_create" >&5 -printf "%s\n" "$ac_cv_lib_wayland_egl_wl_egl_window_create" >&6; } -if test "x$ac_cv_lib_wayland_egl_wl_egl_window_create" = xyes -then : - -printf "%s\n" "#define HAVE_LIBWAYLAND_EGL 1" >>confdefs.h - -else case e in #( - e) WAYLAND_EGL_LIBS="" ;; -esac -fi - -fi - -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$with_wayland" != "x" - then - if test -z "$ac_cv_lib_soname_EGL" -o "$ac_cv_lib_wayland_egl_wl_egl_window_create" != yes -then : - case "x$with_opengl" in - x) as_fn_append wine_notices "|EGL ${notice_platform}development files not found, the Wayland driver won't support OpenGL" ;; - xno) ;; - *) as_fn_error $? "EGL ${notice_platform}development files not found, the Wayland driver won't support OpenGL -This is an error since --with-opengl was requested." "$LINENO" 5 ;; -esac - -fi - fi - fi -fi -if test -z "$WAYLAND_CLIENT_LIBS" -o -z "$WAYLAND_SCANNER" -o -z "$XKBCOMMON_LIBS" -o -z "$XKBREGISTRY_LIBS" -o "$ac_cv_header_linux_input_h" = "no" -then : - case "x$with_wayland" in - x) as_fn_append wine_notices "|Wayland ${notice_platform}development files not found, the Wayland driver won't be supported." ;; - xno) ;; - *) as_fn_error $? "Wayland ${notice_platform}development files not found, the Wayland driver won't be supported. -This is an error since --with-wayland was requested." "$LINENO" 5 ;; -esac -enable_winewayland_drv=${enable_winewayland_drv:-no} -fi - -if test "$enable_wineandroid_drv$enable_winemac_drv$enable_winewayland_drv" = "nonono" -then - if test "x$X_LIBS" = "x" -then : - case "x$with_x" in - xno) ;; - *) as_fn_error $? "X ${notice_platform}development files not found. Wine will be built -without X support, which probably isn't what you want. You will need -to install ${notice_platform}development packages of Xlib at the very least. -Use the --without-x option if you really want this." "$LINENO" 5 ;; -esac -enable_winex11_drv=${enable_winex11_drv:-no} -fi -else - if test "x$X_LIBS" = "x" -then : - case "x$with_x" in - x) as_fn_append wine_notices "|X ${notice_platform}development files not found, the X11 driver won't be supported." ;; - xno) ;; - *) as_fn_error $? "X ${notice_platform}development files not found, the X11 driver won't be supported. -This is an error since --with-x was requested." "$LINENO" 5 ;; -esac -enable_winex11_drv=${enable_winex11_drv:-no} -fi -fi - -if test "$ac_cv_header_CL_cl_h" = "yes" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clGetPlatformInfo in -lOpenCL" >&5 -printf %s "checking for clGetPlatformInfo in -lOpenCL... " >&6; } -if test ${ac_cv_lib_OpenCL_clGetPlatformInfo+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lOpenCL $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char clGetPlatformInfo (void); -int -main (void) -{ -return clGetPlatformInfo (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_OpenCL_clGetPlatformInfo=yes -else case e in #( - e) ac_cv_lib_OpenCL_clGetPlatformInfo=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_OpenCL_clGetPlatformInfo" >&5 -printf "%s\n" "$ac_cv_lib_OpenCL_clGetPlatformInfo" >&6; } -if test "x$ac_cv_lib_OpenCL_clGetPlatformInfo" = xyes -then : - OPENCL_LIBS="-lOpenCL" - -fi - -fi -if test "x$ac_cv_lib_OpenCL_clGetPlatformInfo" != xyes -then : - case "x$with_opencl" in - x) as_fn_append wine_notices "|OpenCL ${notice_platform}development files not found, OpenCL won't be supported." ;; - xno) ;; - *) as_fn_error $? "OpenCL ${notice_platform}development files not found, OpenCL won't be supported. -This is an error since --with-opencl was requested." "$LINENO" 5 ;; -esac -enable_opencl=${enable_opencl:-no} -fi - -if test "$ac_cv_header_pcap_pcap_h" = "yes" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcap_init in -lpcap" >&5 -printf %s "checking for pcap_init in -lpcap... " >&6; } -if test ${ac_cv_lib_pcap_pcap_init+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lpcap $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char pcap_init (void); -int -main (void) -{ -return pcap_init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_pcap_pcap_init=yes -else case e in #( - e) ac_cv_lib_pcap_pcap_init=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_init" >&5 -printf "%s\n" "$ac_cv_lib_pcap_pcap_init" >&6; } -if test "x$ac_cv_lib_pcap_pcap_init" = xyes -then : - PCAP_LIBS="-lpcap" - -fi - -fi -if test "x$ac_cv_lib_pcap_pcap_init" != xyes -then : - case "x$with_pcap" in - x) as_fn_append wine_notices "|pcap ${notice_platform}development files not found, wpcap won't be supported." ;; - xno) ;; - *) as_fn_error $? "pcap ${notice_platform}development files not found, wpcap won't be supported. -This is an error since --with-pcap was requested." "$LINENO" 5 ;; -esac -enable_wpcap=${enable_wpcap:-no} -fi - -if test "x$with_pcsclite" != "xno" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SCardEstablishContext in -lpcsclite" >&5 -printf %s "checking for SCardEstablishContext in -lpcsclite... " >&6; } -if test ${ac_cv_lib_pcsclite_SCardEstablishContext+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lpcsclite $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char SCardEstablishContext (void); -int -main (void) -{ -return SCardEstablishContext (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_pcsclite_SCardEstablishContext=yes -else case e in #( - e) ac_cv_lib_pcsclite_SCardEstablishContext=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcsclite_SCardEstablishContext" >&5 -printf "%s\n" "$ac_cv_lib_pcsclite_SCardEstablishContext" >&6; } -if test "x$ac_cv_lib_pcsclite_SCardEstablishContext" = xyes -then : - PCSCLITE_LIBS="-lpcsclite" - -else case e in #( - e) case $host_os in - darwin*|macosx*) PCSCLITE_LIBS="-framework PCSC" - ;; - esac ;; -esac -fi - -fi -if test "x$PCSCLITE_LIBS" = x -then : - case "x$with_pcsclite" in - x) as_fn_append wine_notices "|libpcsclite not found, smart cards won't be supported." ;; - xno) ;; - *) as_fn_error $? "libpcsclite not found, smart cards won't be supported. -This is an error since --with-pcsclite was requested." "$LINENO" 5 ;; -esac -enable_winscard=${enable_winscard:-no} -fi - -if test "x$with_inotify" != "xno" -then - rm -f conftest.err -if ${INOTIFY_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - INOTIFY_CFLAGS=`$PKG_CONFIG --cflags libinotify 2>conftest.err` -fi -fi - -if ${INOTIFY_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - INOTIFY_LIBS=`$PKG_CONFIG --libs libinotify 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libinotify cflags: $INOTIFY_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libinotify libs: $INOTIFY_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libinotify errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $INOTIFY_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "sys/inotify.h" "ac_cv_header_sys_inotify_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_inotify_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_INOTIFY_H 1" >>confdefs.h - -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inotify_add_watch in -linotify" >&5 -printf %s "checking for inotify_add_watch in -linotify... " >&6; } -if test ${ac_cv_lib_inotify_inotify_add_watch+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-linotify $INOTIFY_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char inotify_add_watch (void); -int -main (void) -{ -return inotify_add_watch (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_inotify_inotify_add_watch=yes -else case e in #( - e) ac_cv_lib_inotify_inotify_add_watch=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inotify_inotify_add_watch" >&5 -printf "%s\n" "$ac_cv_lib_inotify_inotify_add_watch" >&6; } -if test "x$ac_cv_lib_inotify_inotify_add_watch" = xyes -then : - : -else case e in #( - e) INOTIFY_LIBS="" ;; -esac -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "$ac_cv_header_sys_inotify_h" != "yes" -then : - case "x$with_inotify" in - x) as_fn_append wine_notices "|libinotify ${notice_platform}development files not found (or too old), filesystem change notifications won't be supported." ;; - xno) ;; - *) as_fn_error $? "libinotify ${notice_platform}development files not found (or too old), filesystem change notifications won't be supported. -This is an error since --with-inotify was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_dbus" != "xno" -then - rm -f conftest.err -if ${DBUS_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - DBUS_CFLAGS=`$PKG_CONFIG --cflags dbus-1 2>conftest.err` -fi -fi - -if ${DBUS_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - DBUS_LIBS=`$PKG_CONFIG --libs dbus-1 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: dbus-1 cflags: $DBUS_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: dbus-1 libs: $DBUS_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: dbus-1 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $DBUS_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "dbus/dbus.h" "ac_cv_header_dbus_dbus_h" "$ac_includes_default" -if test "x$ac_cv_header_dbus_dbus_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -ldbus-1" >&5 -printf %s "checking for -ldbus-1... " >&6; } -if test ${ac_cv_lib_soname_dbus_1+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-ldbus-1 $DBUS_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dbus_connection_close (void); -int -main (void) -{ -return dbus_connection_close (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_dbus_1=`$ac_cv_path_LDD conftest.exe | grep "dbus-1" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_dbus_1=`$OTOOL -L conftest$ac_exeext | grep "libdbus-1\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libdbus-1\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_dbus_1=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libdbus-1\\.$LIBEXT" | sed -e "s/^.*\\[\\(libdbus-1\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_dbus_1:+false} : -then : - ac_cv_lib_soname_dbus_1=`$LDD conftest$ac_exeext | grep "libdbus-1\\.$LIBEXT" | sed -e "s/^.*\(libdbus-1\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_dbus_1= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_dbus_1:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - DBUS_CFLAGS="" -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_dbus_1" >&5 -printf "%s\n" "$ac_cv_lib_soname_dbus_1" >&6; } - -printf "%s\n" "#define SONAME_LIBDBUS_1 \"$ac_cv_lib_soname_dbus_1\"" >>confdefs.h - - ;; -esac -fi -else case e in #( - e) DBUS_CFLAGS="" ;; -esac -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -case $host_os in - darwin*|macosx*) ;; - *) if test "x$ac_cv_lib_soname_dbus_1" = "x" -then : - case "x$with_dbus" in - x) as_fn_append wine_notices "|libdbus ${notice_platform}development files not found, no dynamic device support." ;; - xno) ;; - *) as_fn_error $? "libdbus ${notice_platform}development files not found, no dynamic device support. -This is an error since --with-dbus was requested." "$LINENO" 5 ;; -esac - -fi ;; -esac - -if test "x$with_gnutls" != "xno" -then - rm -f conftest.err -if ${GNUTLS_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GNUTLS_CFLAGS=`$PKG_CONFIG --cflags gnutls 2>conftest.err` -fi -fi - -if ${GNUTLS_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GNUTLS_LIBS=`$PKG_CONFIG --libs gnutls 2>/dev/null` -fi -fi - -GNUTLS_LIBS=${GNUTLS_LIBS:-"-lgnutls"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gnutls cflags: $GNUTLS_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gnutls libs: $GNUTLS_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: gnutls errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $GNUTLS_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "gnutls/gnutls.h" "ac_cv_header_gnutls_gnutls_h" "$ac_includes_default" -if test "x$ac_cv_header_gnutls_gnutls_h" = xyes -then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main (void) -{ -static typeof(gnutls_mac_get_key_size) *func; if (func) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lgnutls" >&5 -printf %s "checking for -lgnutls... " >&6; } -if test ${ac_cv_lib_soname_gnutls+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lgnutls $GNUTLS_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char gnutls_global_init (void); -int -main (void) -{ -return gnutls_global_init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_gnutls=`$ac_cv_path_LDD conftest.exe | grep "gnutls" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_gnutls=`$OTOOL -L conftest$ac_exeext | grep "libgnutls\\(-deb0\\)\\{0,1\\}\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libgnutls\\(-deb0\\)\\{0,1\\}\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_gnutls=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libgnutls\\(-deb0\\)\\{0,1\\}\\.$LIBEXT" | sed -e "s/^.*\\[\\(libgnutls\\(-deb0\\)\\{0,1\\}\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_gnutls:+false} : -then : - ac_cv_lib_soname_gnutls=`$LDD conftest$ac_exeext | grep "libgnutls\\(-deb0\\)\\{0,1\\}\\.$LIBEXT" | sed -e "s/^.*\(libgnutls\\(-deb0\\)\\{0,1\\}\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_gnutls= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_gnutls:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - GNUTLS_CFLAGS="" -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_gnutls" >&5 -printf "%s\n" "$ac_cv_lib_soname_gnutls" >&6; } - -printf "%s\n" "#define SONAME_LIBGNUTLS \"$ac_cv_lib_soname_gnutls\"" >>confdefs.h - - ;; -esac -fi - ac_wine_check_funcs_save_LIBS="$LIBS" -LIBS="$LIBS $GNUTLS_LIBS" - - for ac_func in gnutls_cipher_init -do : - ac_fn_c_check_func "$LINENO" "gnutls_cipher_init" "ac_cv_func_gnutls_cipher_init" -if test "x$ac_cv_func_gnutls_cipher_init" = xyes -then : - printf "%s\n" "#define HAVE_GNUTLS_CIPHER_INIT 1" >>confdefs.h - -else case e in #( - e) as_fn_append wine_notices "|libgnutls ${notice_platform}development files too old, bcrypt encryption won't be supported." ;; -esac -fi - -done -LIBS="$ac_wine_check_funcs_save_LIBS" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -else case e in #( - e) GNUTLS_CFLAGS="" ;; -esac -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_gnutls" = "x" -then : - case "x$with_gnutls" in - x) as_fn_append wine_warnings "|libgnutls ${notice_platform}development files not found, no schannel support." ;; - xno) ;; - *) as_fn_error $? "libgnutls ${notice_platform}development files not found, no schannel support. -This is an error since --with-gnutls was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_sane" != "xno" -then - rm -f conftest.err -if ${SANE_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - SANE_CFLAGS=`$PKG_CONFIG --cflags sane-backends 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || SANE_CFLAGS=${SANE_CFLAGS:-`${SANE_CONFIG:-sane-config} --cflags 2>/dev/null`} -if ${SANE_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - SANE_LIBS=`$PKG_CONFIG --libs sane-backends 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || SANE_LIBS=${SANE_LIBS:-`${SANE_CONFIG:-sane-config} --ldflags 2>/dev/null`} - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: sane-backends cflags: $SANE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: sane-backends libs: $SANE_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: sane-backends errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $SANE_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "sane/sane.h" "ac_cv_header_sane_sane_h" "$ac_includes_default" -if test "x$ac_cv_header_sane_sane_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sane_init in -lsane" >&5 -printf %s "checking for sane_init in -lsane... " >&6; } -if test ${ac_cv_lib_sane_sane_init+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lsane $SANE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char sane_init (void); -int -main (void) -{ -return sane_init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_sane_sane_init=yes -else case e in #( - e) ac_cv_lib_sane_sane_init=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sane_sane_init" >&5 -printf "%s\n" "$ac_cv_lib_sane_sane_init" >&6; } -if test "x$ac_cv_lib_sane_sane_init" = xyes -then : - : -fi - -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "$ac_cv_lib_sane_sane_init" != "yes" -then : - case "x$with_sane" in - x) as_fn_append wine_notices "|libsane ${notice_platform}development files not found, scanners won't be supported." ;; - xno) ;; - *) as_fn_error $? "libsane ${notice_platform}development files not found, scanners won't be supported. -This is an error since --with-sane was requested." "$LINENO" 5 ;; -esac -enable_sane_ds=${enable_sane_ds:-no} -fi - -if test "x$with_usb" != "xno" -then - rm -f conftest.err -if ${USB_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - USB_CFLAGS=`$PKG_CONFIG --cflags libusb-1.0 2>conftest.err` -fi -fi - -if ${USB_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - USB_LIBS=`$PKG_CONFIG --libs libusb-1.0 2>/dev/null` -fi -fi - -USB_LIBS=${USB_LIBS:-"-lusb-1.0"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libusb-1.0 cflags: $USB_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libusb-1.0 libs: $USB_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libusb-1.0 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $USB_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "libusb.h" "ac_cv_header_libusb_h" "$ac_includes_default" -if test "x$ac_cv_header_libusb_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libusb_interrupt_event_handler in -lusb-1.0" >&5 -printf %s "checking for libusb_interrupt_event_handler in -lusb-1.0... " >&6; } -if test ${ac_cv_lib_usb_1_0_libusb_interrupt_event_handler+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lusb-1.0 $USB_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char libusb_interrupt_event_handler (void); -int -main (void) -{ -return libusb_interrupt_event_handler (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_usb_1_0_libusb_interrupt_event_handler=yes -else case e in #( - e) ac_cv_lib_usb_1_0_libusb_interrupt_event_handler=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" >&5 -printf "%s\n" "$ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" >&6; } -if test "x$ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" = xyes -then : - : -else case e in #( - e) USB_LIBS="" ;; -esac -fi - -else case e in #( - e) USB_LIBS="" ;; -esac -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "$ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" != "yes" -then : - case "x$with_usb" in - x) as_fn_append wine_notices "|libusb-1.0 ${notice_platform}development files not found (or too old), USB devices won't be supported." ;; - xno) ;; - *) as_fn_error $? "libusb-1.0 ${notice_platform}development files not found (or too old), USB devices won't be supported. -This is an error since --with-usb was requested." "$LINENO" 5 ;; -esac -enable_wineusb_sys=${enable_wineusb_sys:-no} -fi - -if test "x$with_v4l2" != "xno" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lv4l2" >&5 -printf %s "checking for -lv4l2... " >&6; } -if test ${ac_cv_lib_soname_v4l2+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lv4l2 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char v4l2_open (void); -int -main (void) -{ -return v4l2_open (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_v4l2=`$ac_cv_path_LDD conftest.exe | grep "v4l2" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_v4l2=`$OTOOL -L conftest$ac_exeext | grep "libv4l2\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libv4l2\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_v4l2=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libv4l2\\.$LIBEXT" | sed -e "s/^.*\\[\\(libv4l2\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_v4l2:+false} : -then : - ac_cv_lib_soname_v4l2=`$LDD conftest$ac_exeext | grep "libv4l2\\.$LIBEXT" | sed -e "s/^.*\(libv4l2\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_v4l2= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_v4l2:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_v4l2" >&5 -printf "%s\n" "$ac_cv_lib_soname_v4l2" >&6; } - -printf "%s\n" "#define SONAME_LIBV4L2 \"$ac_cv_lib_soname_v4l2\"" >>confdefs.h - - ;; -esac -fi -fi -if test "x$ac_cv_lib_soname_v4l2" = "x" -then : - case "x$with_v4l2" in - x) as_fn_append wine_notices "|libv4l2 ${notice_platform}development files not found." ;; - xno) ;; - *) as_fn_error $? "libv4l2 ${notice_platform}development files not found. -This is an error since --with-v4l2 was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_gphoto" != "xno" -then - rm -f conftest.err -if ${GPHOTO2_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GPHOTO2_CFLAGS=`$PKG_CONFIG --cflags libgphoto2 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || GPHOTO2_CFLAGS=${GPHOTO2_CFLAGS:-`${GPHOTO2_CONFIG:-gphoto2-config} --cflags 2>/dev/null`} -if ${GPHOTO2_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GPHOTO2_LIBS=`$PKG_CONFIG --libs libgphoto2 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || GPHOTO2_LIBS=${GPHOTO2_LIBS:-`${GPHOTO2_CONFIG:-gphoto2-config} --libs 2>/dev/null`} -GPHOTO2_LIBS=${GPHOTO2_LIBS:-"-lgphoto2"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libgphoto2 cflags: $GPHOTO2_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libgphoto2 libs: $GPHOTO2_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libgphoto2 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $GPHOTO2_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "gphoto2-camera.h" "ac_cv_header_gphoto2_camera_h" "$ac_includes_default" -if test "x$ac_cv_header_gphoto2_camera_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gp_camera_new in -lgphoto2" >&5 -printf %s "checking for gp_camera_new in -lgphoto2... " >&6; } -if test ${ac_cv_lib_gphoto2_gp_camera_new+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lgphoto2 $GPHOTO2_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char gp_camera_new (void); -int -main (void) -{ -return gp_camera_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_gphoto2_gp_camera_new=yes -else case e in #( - e) ac_cv_lib_gphoto2_gp_camera_new=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gphoto2_gp_camera_new" >&5 -printf "%s\n" "$ac_cv_lib_gphoto2_gp_camera_new" >&6; } -if test "x$ac_cv_lib_gphoto2_gp_camera_new" = xyes -then : - : -fi - -fi - -CPPFLAGS=$ac_save_CPPFLAGS - - rm -f conftest.err -if ${GPHOTO2_PORT_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GPHOTO2_PORT_CFLAGS=`$PKG_CONFIG --cflags libgphoto2_port 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || GPHOTO2_PORT_CFLAGS=${GPHOTO2_PORT_CFLAGS:-`${GPHOTO2_PORT_CONFIG:-gphoto2-port-config} --cflags 2>/dev/null`} -if ${GPHOTO2_PORT_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GPHOTO2_PORT_LIBS=`$PKG_CONFIG --libs libgphoto2_port 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || GPHOTO2_PORT_LIBS=${GPHOTO2_PORT_LIBS:-`${GPHOTO2_PORT_CONFIG:-gphoto2-port-config} --libs 2>/dev/null`} -GPHOTO2_PORT_LIBS=${GPHOTO2_PORT_LIBS:-"-lgphoto2_port"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libgphoto2_port cflags: $GPHOTO2_PORT_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libgphoto2_port libs: $GPHOTO2_PORT_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libgphoto2_port errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $GPHOTO2_PORT_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "gphoto2-port.h" "ac_cv_header_gphoto2_port_h" "$ac_includes_default" -if test "x$ac_cv_header_gphoto2_port_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gp_port_info_list_new in -lgphoto2_port" >&5 -printf %s "checking for gp_port_info_list_new in -lgphoto2_port... " >&6; } -if test ${ac_cv_lib_gphoto2_port_gp_port_info_list_new+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lgphoto2_port $GPHOTO2_PORT_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char gp_port_info_list_new (void); -int -main (void) -{ -return gp_port_info_list_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_gphoto2_port_gp_port_info_list_new=yes -else case e in #( - e) ac_cv_lib_gphoto2_port_gp_port_info_list_new=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gphoto2_port_gp_port_info_list_new" >&5 -printf "%s\n" "$ac_cv_lib_gphoto2_port_gp_port_info_list_new" >&6; } -if test "x$ac_cv_lib_gphoto2_port_gp_port_info_list_new" = xyes -then : - -printf "%s\n" "#define HAVE_GPHOTO2_PORT 1" >>confdefs.h - -else case e in #( - e) GPHOTO2_PORT_LIBS=""; GPHOTO2_PORT_CFLAGS="" ;; -esac -fi - -else case e in #( - e) GPHOTO2_PORT_LIBS=""; GPHOTO2_PORT_CFLAGS="" ;; -esac -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "$ac_cv_lib_gphoto2_gp_camera_new" != "yes" -then : - case "x$with_gphoto" in - x) as_fn_append wine_notices "|libgphoto2 ${notice_platform}development files not found, digital cameras won't be supported." ;; - xno) ;; - *) as_fn_error $? "libgphoto2 ${notice_platform}development files not found, digital cameras won't be supported. -This is an error since --with-gphoto was requested." "$LINENO" 5 ;; -esac -enable_gphoto2_ds=${enable_gphoto2_ds:-no} -fi -if test "$ac_cv_lib_gphoto2_port_gp_port_info_list_new" != "yes" -then : - case "x$with_gphoto" in - x) as_fn_append wine_notices "|libgphoto2_port ${notice_platform}development files not found, digital cameras won't be auto-detected." ;; - xno) ;; - *) as_fn_error $? "libgphoto2_port ${notice_platform}development files not found, digital cameras won't be auto-detected. -This is an error since --with-gphoto was requested." "$LINENO" 5 ;; -esac - -fi - - -if test "$ac_cv_header_resolv_h" = "yes" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for resolver library" >&5 -printf %s "checking for resolver library... " >&6; } -if test ${ac_cv_have_resolv+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_save_LIBS="$LIBS" - for lib in '' -lresolv - do - LIBS="$lib $ac_save_LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef HAVE_NETINET_IN_H -#include -#endif -#include -int -main (void) -{ -if (!(_res.options & RES_INIT)) res_init(); res_query("foo",ns_c_in,0,0,0); ns_initparse(0,0,0) - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_have_resolv=${lib:-"none required"} -else case e in #( - e) ac_cv_have_resolv="not found" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - test "x$ac_cv_have_resolv" = "xnot found" || break - done - LIBS="$ac_save_LIBS" ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_resolv" >&5 -printf "%s\n" "$ac_cv_have_resolv" >&6; } - - case "$ac_cv_have_resolv" in - "not found") ;; - "none required") - -printf "%s\n" "#define HAVE_RESOLV 1" >>confdefs.h - ;; - *) - printf "%s\n" "#define HAVE_RESOLV 1" >>confdefs.h - - RESOLV_LIBS=$ac_cv_have_resolv - ;; - esac - - if test "x$ac_cv_have_resolv" != "xnot found" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for res_getservers" >&5 -printf %s "checking for res_getservers... " >&6; } -if test ${ac_cv_have_res_getservers+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_save_LIBS="$LIBS" - LIBS="$RESOLV_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -res_getservers(NULL, NULL, 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_have_res_getservers=yes -else case e in #( - e) ac_cv_have_res_getservers=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$ac_save_LIBS" ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_res_getservers" >&5 -printf "%s\n" "$ac_cv_have_res_getservers" >&6; } - if test "$ac_cv_have_res_getservers" = "yes" - then - -printf "%s\n" "#define HAVE_RES_GETSERVERS 1" >>confdefs.h - - fi - fi -fi - -if test "x$with_freetype" != "xno" -then - rm -f conftest.err -if ${FREETYPE_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - FREETYPE_CFLAGS=`$PKG_CONFIG --cflags freetype2 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || FREETYPE_CFLAGS=${FREETYPE_CFLAGS:-`(${FREETYPE_CONFIG:-freetype-config} --cflags || ${FREETYPE2_CONFIG:-freetype2-config} --cflags) 2>/dev/null`} -if ${FREETYPE_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - FREETYPE_LIBS=`$PKG_CONFIG --libs freetype2 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || FREETYPE_LIBS=${FREETYPE_LIBS:-`(${FREETYPE_CONFIG:-freetype-config} --libs || ${FREETYPE2_CONFIG:-freetype2-config} --libs) 2>/dev/null`} -FREETYPE_LIBS=${FREETYPE_LIBS:-"-lfreetype"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: freetype2 cflags: $FREETYPE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: freetype2 libs: $FREETYPE_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: freetype2 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $FREETYPE_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "ft2build.h" "ac_cv_header_ft2build_h" "$ac_includes_default" -if test "x$ac_cv_header_ft2build_h" = xyes -then : - printf "%s\n" "#define HAVE_FT2BUILD_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_ft2build_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lfreetype" >&5 -printf %s "checking for -lfreetype... " >&6; } -if test ${ac_cv_lib_soname_freetype+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lfreetype $FREETYPE_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char FT_Init_FreeType (void); -int -main (void) -{ -return FT_Init_FreeType (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_freetype=`$ac_cv_path_LDD conftest.exe | grep "freetype" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_freetype=`$OTOOL -L conftest$ac_exeext | grep "libfreetype\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libfreetype\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_freetype=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libfreetype\\.$LIBEXT" | sed -e "s/^.*\\[\\(libfreetype\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_freetype:+false} : -then : - ac_cv_lib_soname_freetype=`$LDD conftest$ac_exeext | grep "libfreetype\\.$LIBEXT" | sed -e "s/^.*\(libfreetype\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_freetype= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_freetype:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - FREETYPE_LIBS="" -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_freetype" >&5 -printf "%s\n" "$ac_cv_lib_soname_freetype" >&6; } - -printf "%s\n" "#define SONAME_LIBFREETYPE \"$ac_cv_lib_soname_freetype\"" >>confdefs.h - - -printf "%s\n" "#define HAVE_FREETYPE 1" >>confdefs.h - - ac_fn_c_check_type "$LINENO" "FT_TrueTypeEngineType" "ac_cv_type_FT_TrueTypeEngineType" "#include -#include FT_MODULE_H -" -if test "x$ac_cv_type_FT_TrueTypeEngineType" = xyes -then : - -printf "%s\n" "#define HAVE_FT_TRUETYPEENGINETYPE 1" >>confdefs.h - - -fi - ;; -esac -fi - else - FREETYPE_CFLAGS="" - FREETYPE_LIBS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_freetype" = x -then : - case "x$with_freetype" in - xno) ;; - *) as_fn_error $? "FreeType ${notice_platform}development files not found. Fonts will not be built. -Use the --without-freetype option if you really want this." "$LINENO" 5 ;; -esac -enable_fonts=${enable_fonts:-no} -fi - -ac_wine_check_funcs_save_LIBS="$LIBS" -LIBS="$LIBS $PTHREAD_LIBS" -ac_fn_c_check_func "$LINENO" "pthread_getthreadid_np" "ac_cv_func_pthread_getthreadid_np" -if test "x$ac_cv_func_pthread_getthreadid_np" = xyes -then : - printf "%s\n" "#define HAVE_PTHREAD_GETTHREADID_NP 1" >>confdefs.h - -fi - -LIBS="$ac_wine_check_funcs_save_LIBS" - -if test "x$enable_tools" != xno -a "x$with_gettextpo" = xyes -then - if test "$ac_cv_header_gettext_po_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for po_message_msgctxt in -lgettextpo" >&5 -printf %s "checking for po_message_msgctxt in -lgettextpo... " >&6; } -if test ${ac_cv_lib_gettextpo_po_message_msgctxt+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lgettextpo $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char po_message_msgctxt (void); -int -main (void) -{ -return po_message_msgctxt (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_gettextpo_po_message_msgctxt=yes -else case e in #( - e) ac_cv_lib_gettextpo_po_message_msgctxt=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gettextpo_po_message_msgctxt" >&5 -printf "%s\n" "$ac_cv_lib_gettextpo_po_message_msgctxt" >&6; } -if test "x$ac_cv_lib_gettextpo_po_message_msgctxt" = xyes -then : - -printf "%s\n" "#define HAVE_LIBGETTEXTPO 1" >>confdefs.h - - GETTEXTPO_LIBS="-lgettextpo" - -fi - - fi - if test "x$GETTEXTPO_LIBS" = "x" -then : - case "x$with_gettextpo" in - x) as_fn_append wine_notices "|GetText ${notice_platform}development files not found (or too old), po files can't be rebuilt." ;; - xno) ;; - *) as_fn_error $? "GetText ${notice_platform}development files not found (or too old), po files can't be rebuilt. -This is an error since --with-gettextpo was requested." "$LINENO" 5 ;; -esac - -fi - if test "$srcdir" != . -then : - case "x$with_gettextpo" in - x) as_fn_append wine_notices "|Rebuilding po files is not supported for out of tree builds." ;; - xno) ;; - *) as_fn_error $? "Rebuilding po files is not supported for out of tree builds. -This is an error since --with-gettextpo was requested." "$LINENO" 5 ;; -esac - -fi -fi - -if test "x$with_pulse" != "xno"; -then - rm -f conftest.err -if ${PULSE_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - PULSE_CFLAGS=`$PKG_CONFIG --cflags libpulse 2>conftest.err` -fi -fi - -if ${PULSE_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - PULSE_LIBS=`$PKG_CONFIG --libs libpulse 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libpulse cflags: $PULSE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libpulse libs: $PULSE_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libpulse errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $PULSE_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "pulse/pulseaudio.h" "ac_cv_header_pulse_pulseaudio_h" "$ac_includes_default" -if test "x$ac_cv_header_pulse_pulseaudio_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pa_stream_is_corked in -lpulse" >&5 -printf %s "checking for pa_stream_is_corked in -lpulse... " >&6; } -if test ${ac_cv_lib_pulse_pa_stream_is_corked+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lpulse $PULSE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char pa_stream_is_corked (void); -int -main (void) -{ -return pa_stream_is_corked (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_pulse_pa_stream_is_corked=yes -else case e in #( - e) ac_cv_lib_pulse_pa_stream_is_corked=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pulse_pa_stream_is_corked" >&5 -printf "%s\n" "$ac_cv_lib_pulse_pa_stream_is_corked" >&6; } -if test "x$ac_cv_lib_pulse_pa_stream_is_corked" = xyes -then : - : -else case e in #( - e) PULSE_LIBS="" ;; -esac -fi - -else case e in #( - e) PULSE_LIBS="" ;; -esac -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test -z "$PULSE_LIBS" -then : - case "x$with_pulse" in - x) as_fn_append wine_notices "|libpulse ${notice_platform}development files not found or too old, Pulse won't be supported." ;; - xno) ;; - *) as_fn_error $? "libpulse ${notice_platform}development files not found or too old, Pulse won't be supported. -This is an error since --with-pulse was requested." "$LINENO" 5 ;; -esac -enable_winepulse_drv=${enable_winepulse_drv:-no} -fi - -if test "x$with_ffmpeg" != "xno"; -then - rm -f conftest.err -if ${FFMPEG_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - FFMPEG_CFLAGS=`$PKG_CONFIG --cflags libavutil libavformat libavcodec 2>conftest.err` -fi -fi - -if ${FFMPEG_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - FFMPEG_LIBS=`$PKG_CONFIG --libs libavutil libavformat libavcodec 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libavutil libavformat libavcodec cflags: $FFMPEG_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libavutil libavformat libavcodec libs: $FFMPEG_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libavutil libavformat libavcodec errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $FFMPEG_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "libavutil/avutil.h" "ac_cv_header_libavutil_avutil_h" "$ac_includes_default" -if test "x$ac_cv_header_libavutil_avutil_h" = xyes -then : - printf "%s\n" "#define HAVE_LIBAVUTIL_AVUTIL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "libavformat/avformat.h" "ac_cv_header_libavformat_avformat_h" "$ac_includes_default" -if test "x$ac_cv_header_libavformat_avformat_h" = xyes -then : - printf "%s\n" "#define HAVE_LIBAVFORMAT_AVFORMAT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "libavcodec/avcodec.h" "ac_cv_header_libavcodec_avcodec_h" "$ac_includes_default" -if test "x$ac_cv_header_libavcodec_avcodec_h" = xyes -then : - printf "%s\n" "#define HAVE_LIBAVCODEC_AVCODEC_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "libavcodec/bsf.h" "ac_cv_header_libavcodec_bsf_h" "$ac_includes_default" -if test "x$ac_cv_header_libavcodec_bsf_h" = xyes -then : - printf "%s\n" "#define HAVE_LIBAVCODEC_BSF_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_libavutil_avutil_h" = "yes" -a "$ac_cv_header_libavformat_avformat_h" = "yes" -a "$ac_cv_header_libavcodec_avcodec_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for av_log_set_callback in -lavutil" >&5 -printf %s "checking for av_log_set_callback in -lavutil... " >&6; } -if test ${ac_cv_lib_avutil_av_log_set_callback+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lavutil $FFMPEG_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char av_log_set_callback (void); -int -main (void) -{ -return av_log_set_callback (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_avutil_av_log_set_callback=yes -else case e in #( - e) ac_cv_lib_avutil_av_log_set_callback=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_avutil_av_log_set_callback" >&5 -printf "%s\n" "$ac_cv_lib_avutil_av_log_set_callback" >&6; } -if test "x$ac_cv_lib_avutil_av_log_set_callback" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for av_find_input_format in -lavformat" >&5 -printf %s "checking for av_find_input_format in -lavformat... " >&6; } -if test ${ac_cv_lib_avformat_av_find_input_format+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lavformat $FFMPEG_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char av_find_input_format (void); -int -main (void) -{ -return av_find_input_format (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_avformat_av_find_input_format=yes -else case e in #( - e) ac_cv_lib_avformat_av_find_input_format=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_avformat_av_find_input_format" >&5 -printf "%s\n" "$ac_cv_lib_avformat_av_find_input_format" >&6; } -if test "x$ac_cv_lib_avformat_av_find_input_format" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for avcodec_get_name in -lavcodec" >&5 -printf %s "checking for avcodec_get_name in -lavcodec... " >&6; } -if test ${ac_cv_lib_avcodec_avcodec_get_name+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lavcodec $FFMPEG_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char avcodec_get_name (void); -int -main (void) -{ -return avcodec_get_name (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_avcodec_avcodec_get_name=yes -else case e in #( - e) ac_cv_lib_avcodec_avcodec_get_name=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_avcodec_avcodec_get_name" >&5 -printf "%s\n" "$ac_cv_lib_avcodec_avcodec_get_name" >&6; } -if test "x$ac_cv_lib_avcodec_avcodec_get_name" = xyes -then : - -printf "%s\n" "#define HAVE_FFMPEG 1" >>confdefs.h - -else case e in #( - e) FFMPEG_LIBS="" ;; -esac -fi - -else case e in #( - e) FFMPEG_LIBS="" ;; -esac -fi - -else case e in #( - e) FFMPEG_LIBS="" ;; -esac -fi - - else - FFMPEG_LIBS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$FFMPEG_LIBS" = x -then : - case "x$with_ffmpeg" in - x) as_fn_append wine_notices "|FFmpeg ${notice_platform}development files not found." ;; - xno) ;; - *) as_fn_error $? "FFmpeg ${notice_platform}development files not found. -This is an error since --with-ffmpeg was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_gstreamer" != "xno" -then - rm -f conftest.err -if ${GSTREAMER_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GSTREAMER_CFLAGS=`$PKG_CONFIG --cflags gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 gstreamer-tag-1.0 2>conftest.err` -fi -fi - -if ${GSTREAMER_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GSTREAMER_LIBS=`$PKG_CONFIG --libs gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 gstreamer-tag-1.0 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 gstreamer-tag-1.0 cflags: $GSTREAMER_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 gstreamer-tag-1.0 libs: $GSTREAMER_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 gstreamer-tag-1.0 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $GSTREAMER_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "gst/gst.h" "ac_cv_header_gst_gst_h" "$ac_includes_default" -if test "x$ac_cv_header_gst_gst_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether gint64 defined by gst/gst.h is indeed 64-bit" >&5 -printf %s "checking whether gint64 defined by gst/gst.h is indeed 64-bit... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -static int a[sizeof(gint64) > 4 ? 1 : -1]; if (a[0]) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gst_pad_new in -lgstreamer-1.0" >&5 -printf %s "checking for gst_pad_new in -lgstreamer-1.0... " >&6; } -if test ${ac_cv_lib_gstreamer_1_0_gst_pad_new+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lgstreamer-1.0 $GSTREAMER_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char gst_pad_new (void); -int -main (void) -{ -return gst_pad_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_gstreamer_1_0_gst_pad_new=yes -else case e in #( - e) ac_cv_lib_gstreamer_1_0_gst_pad_new=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gstreamer_1_0_gst_pad_new" >&5 -printf "%s\n" "$ac_cv_lib_gstreamer_1_0_gst_pad_new" >&6; } -if test "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" = xyes -then : - : -fi - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - ac_glib2_broken=yes - enable_winegstreamer=${enable_winegstreamer:-no} - as_fn_append wine_notices "|glib-2.0 pkgconfig configuration is for the wrong architecture, winegstreamer won't be built." ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_glib2_broken" != xyes -a "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" != xyes -then : - case "x$with_gstreamer" in - x) as_fn_append wine_notices "|gstreamer-1.0 base plugins ${notice_platform}development files not found, GStreamer won't be supported." ;; - xno) ;; - *) as_fn_error $? "gstreamer-1.0 base plugins ${notice_platform}development files not found, GStreamer won't be supported. -This is an error since --with-gstreamer was requested." "$LINENO" 5 ;; -esac -enable_winegstreamer=${enable_winegstreamer:-no} -fi - -ALSA_LIBS="" - -if test "x$with_alsa" != "xno" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_hw_params_get_access_mask in -lasound" >&5 -printf %s "checking for snd_pcm_hw_params_get_access_mask in -lasound... " >&6; } -if test ${ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lasound $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char snd_pcm_hw_params_get_access_mask (void); -int -main (void) -{ -return snd_pcm_hw_params_get_access_mask (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask=yes -else case e in #( - e) ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask" >&5 -printf "%s\n" "$ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask" >&6; } -if test "x$ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask" = xyes -then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -snd_pcm_hw_params_get_access_mask(NULL, NULL) - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ALSA_LIBS="-lasound" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -test -n "$ALSA_LIBS" || enable_winealsa_drv=${enable_winealsa_drv:-no} - -if test "x$with_oss" != xno -then - ac_save_CPPFLAGS="$CPPFLAGS" - if test -f /etc/oss.conf - then - . /etc/oss.conf - fi - ac_oss_incl="-I${OSSLIBDIR:-/usr/lib/oss}/include" - CPPFLAGS="$CPPFLAGS $ac_oss_incl" - ac_fn_c_check_header_compile "$LINENO" "sys/soundcard.h" "ac_cv_header_sys_soundcard_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_soundcard_h" = xyes -then : - ac_fn_c_check_member "$LINENO" "oss_sysinfo" "numaudioengines" "ac_cv_member_oss_sysinfo_numaudioengines" "#include -" -if test "x$ac_cv_member_oss_sysinfo_numaudioengines" = xyes -then : - -printf "%s\n" "#define HAVE_OSS_SYSINFO_NUMAUDIOENGINES 1" >>confdefs.h - -OSS4_CFLAGS="$ac_oss_incl" - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _oss_ioctl in -lossaudio" >&5 -printf %s "checking for _oss_ioctl in -lossaudio... " >&6; } -if test ${ac_cv_lib_ossaudio__oss_ioctl+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lossaudio $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char _oss_ioctl (void); -int -main (void) -{ -return _oss_ioctl (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_ossaudio__oss_ioctl=yes -else case e in #( - e) ac_cv_lib_ossaudio__oss_ioctl=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ossaudio__oss_ioctl" >&5 -printf "%s\n" "$ac_cv_lib_ossaudio__oss_ioctl" >&6; } -if test "x$ac_cv_lib_ossaudio__oss_ioctl" = xyes -then : - OSS4_LIBS="-lossaudio" - -fi - -fi - -fi - - CPPFLAGS="$ac_save_CPPFLAGS" -fi -if test "x$ac_cv_member_oss_sysinfo_numaudioengines" != xyes -then : - case "x$with_oss" in - x) as_fn_append wine_notices "|OSS sound system found but too old (OSSv4 needed), OSS won't be supported." ;; - xno) ;; - *) as_fn_error $? "OSS sound system found but too old (OSSv4 needed), OSS won't be supported. -This is an error since --with-oss was requested." "$LINENO" 5 ;; -esac -enable_wineoss_drv=${enable_wineoss_drv:-no} -fi - -if test "x$with_udev" != "xno" -then - rm -f conftest.err -if ${UDEV_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - UDEV_CFLAGS=`$PKG_CONFIG --cflags libudev 2>conftest.err` -fi -fi - -if ${UDEV_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - UDEV_LIBS=`$PKG_CONFIG --libs libudev 2>/dev/null` -fi -fi - -UDEV_LIBS=${UDEV_LIBS:-"-ludev"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libudev cflags: $UDEV_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libudev libs: $UDEV_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libudev errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $UDEV_CFLAGS" - for ac_header in libudev.h -do : - ac_fn_c_check_header_compile "$LINENO" "libudev.h" "ac_cv_header_libudev_h" "$ac_includes_default" -if test "x$ac_cv_header_libudev_h" = xyes -then : - printf "%s\n" "#define HAVE_LIBUDEV_H 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for udev_new in -ludev" >&5 -printf %s "checking for udev_new in -ludev... " >&6; } -if test ${ac_cv_lib_udev_udev_new+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-ludev $UDEV_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char udev_new (void); -int -main (void) -{ -return udev_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_udev_udev_new=yes -else case e in #( - e) ac_cv_lib_udev_udev_new=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_udev_udev_new" >&5 -printf "%s\n" "$ac_cv_lib_udev_udev_new" >&6; } -if test "x$ac_cv_lib_udev_udev_new" = xyes -then : - -printf "%s\n" "#define HAVE_UDEV 1" >>confdefs.h - -else case e in #( - e) UDEV_LIBS="" ;; -esac -fi - -else case e in #( - e) UDEV_LIBS="" ;; -esac -fi - -done -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$UDEV_LIBS" = "x" -then : - case "x$with_udev" in - x) as_fn_append wine_notices "|libudev ${notice_platform}development files not found, plug and play won't be supported." ;; - xno) ;; - *) as_fn_error $? "libudev ${notice_platform}development files not found, plug and play won't be supported. -This is an error since --with-udev was requested." "$LINENO" 5 ;; -esac - -fi - -if test $HOST_ARCH = x86_64 -then - if test "x$with_unwind" != xno - then - rm -f conftest.err -if ${UNWIND_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - UNWIND_CFLAGS=`$PKG_CONFIG --cflags libunwind 2>conftest.err` -fi -fi - -if ${UNWIND_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - UNWIND_LIBS=`$PKG_CONFIG --libs libunwind 2>/dev/null` -fi -fi - -UNWIND_LIBS=${UNWIND_LIBS:-"-lunwind"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libunwind cflags: $UNWIND_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libunwind libs: $UNWIND_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libunwind errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $UNWIND_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for unw_step" >&5 -printf %s "checking for unw_step... " >&6; } -if test ${wine_cv_have_unw_step+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#define UNW_LOCAL_ONLY -#include -int -main (void) -{ -unw_cursor_t cursor; unw_step( &cursor ); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_have_unw_step="yes" -else case e in #( - e) wine_cv_have_unw_step="no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_have_unw_step" >&5 -printf "%s\n" "$wine_cv_have_unw_step" >&6; } - if test "$wine_cv_have_unw_step" = no -a -n "$UNWIND_LIBS" - then - save_libs=$LIBS - UNWIND_LIBS="-static-libgcc $UNWIND_LIBS" - LIBS="$UNWIND_LIBS $LIBS" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for unw_step in libunwind" >&5 -printf %s "checking for unw_step in libunwind... " >&6; } -if test ${wine_cv_have_libunwind_unw_step+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#define UNW_LOCAL_ONLY -#include -int -main (void) -{ -unw_cursor_t cursor; unw_step( &cursor ); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_have_libunwind_unw_step="yes" -else case e in #( - e) wine_cv_have_libunwind_unw_step="no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_have_libunwind_unw_step" >&5 -printf "%s\n" "$wine_cv_have_libunwind_unw_step" >&6; } - LIBS=$save_libs - fi - test "$wine_cv_have_libunwind_unw_step" = yes || UNWIND_LIBS="" - if test "x$wine_cv_have_unw_step$wine_cv_have_libunwind_unw_step" != xnono - then - -printf "%s\n" "#define HAVE_LIBUNWIND 1" >>confdefs.h - - fi -CPPFLAGS=$ac_save_CPPFLAGS - - fi - case $host in - *-darwin*) - if test "x$wine_cv_have_unw_step$wine_cv_have_libunwind_unw_step" = xnono -then : - case "x$with_unwind" in - x) as_fn_append wine_notices "|libunwind ${notice_platform}development files not found, stack unwinding won't work." ;; - xno) ;; - *) as_fn_error $? "libunwind ${notice_platform}development files not found, stack unwinding won't work. -This is an error since --with-unwind was requested." "$LINENO" 5 ;; -esac - -fi ;; - esac -fi - -if test "x$with_sdl" != "xno" -then - rm -f conftest.err -if ${SDL2_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - SDL2_CFLAGS=`$PKG_CONFIG --cflags sdl2 2>conftest.err` -fi -fi - -if ${SDL2_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - SDL2_LIBS=`$PKG_CONFIG --libs sdl2 2>/dev/null` -fi -fi - -SDL2_LIBS=${SDL2_LIBS:-"-lSDL2"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: sdl2 cflags: $SDL2_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: sdl2 libs: $SDL2_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: sdl2 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $SDL2_CFLAGS" - for ac_header in SDL.h -do : - ac_fn_c_check_header_compile "$LINENO" "SDL.h" "ac_cv_header_SDL_h" "$ac_includes_default" -if test "x$ac_cv_header_SDL_h" = xyes -then : - printf "%s\n" "#define HAVE_SDL_H 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lSDL2" >&5 -printf %s "checking for -lSDL2... " >&6; } -if test ${ac_cv_lib_soname_SDL2+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lSDL2 $SDL2_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char SDL_Init (void); -int -main (void) -{ -return SDL_Init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_SDL2=`$ac_cv_path_LDD conftest.exe | grep "SDL2" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_SDL2=`$OTOOL -L conftest$ac_exeext | grep "libSDL2-2.0*\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libSDL2-2.0*\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_SDL2=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libSDL2-2.0*\\.$LIBEXT" | sed -e "s/^.*\\[\\(libSDL2-2.0*\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_SDL2:+false} : -then : - ac_cv_lib_soname_SDL2=`$LDD conftest$ac_exeext | grep "libSDL2-2.0*\\.$LIBEXT" | sed -e "s/^.*\(libSDL2-2.0*\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_SDL2= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_SDL2:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_SDL2" >&5 -printf "%s\n" "$ac_cv_lib_soname_SDL2" >&6; } - -printf "%s\n" "#define SONAME_LIBSDL2 \"$ac_cv_lib_soname_SDL2\"" >>confdefs.h - - ;; -esac -fi -fi - -done -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_SDL2" = "x" -then : - case "x$with_sdl" in - x) as_fn_append wine_notices "|libSDL2 ${notice_platform}development files not found, SDL2 won't be supported." ;; - xno) ;; - *) as_fn_error $? "libSDL2 ${notice_platform}development files not found, SDL2 won't be supported. -This is an error since --with-sdl was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_capi" != "xno" -then - rm -f conftest.err -if ${CAPI20_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - CAPI20_CFLAGS=`$PKG_CONFIG --cflags capi20 2>conftest.err` -fi -fi - -if ${CAPI20_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - CAPI20_LIBS=`$PKG_CONFIG --libs capi20 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: capi20 cflags: $CAPI20_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: capi20 libs: $CAPI20_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: capi20 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $CAPI20_CFLAGS" - ac_fn_c_check_header_compile "$LINENO" "capi20.h" "ac_cv_header_capi20_h" "#define __user -" -if test "x$ac_cv_header_capi20_h" = xyes -then : - printf "%s\n" "#define HAVE_CAPI20_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/capi.h" "ac_cv_header_linux_capi_h" "#define __user -" -if test "x$ac_cv_header_linux_capi_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_CAPI_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_capi20_h" = "yes" -a "$ac_cv_header_linux_capi_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for capi20_register in -lcapi20" >&5 -printf %s "checking for capi20_register in -lcapi20... " >&6; } -if test ${ac_cv_lib_capi20_capi20_register+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lcapi20 $CAPI20_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char capi20_register (void); -int -main (void) -{ -return capi20_register (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_capi20_capi20_register=yes -else case e in #( - e) ac_cv_lib_capi20_capi20_register=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_capi20_capi20_register" >&5 -printf "%s\n" "$ac_cv_lib_capi20_capi20_register" >&6; } -if test "x$ac_cv_lib_capi20_capi20_register" = xyes -then : - : -else case e in #( - e) CAPI20_LIBS="" ;; -esac -fi - - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_capi20_capi20_register" != xyes -then : - case "x$with_capi" in - x) as_fn_append wine_notices "|libcapi20 ${notice_platform}development files not found, ISDN won't be supported." ;; - xno) ;; - *) as_fn_error $? "libcapi20 ${notice_platform}development files not found, ISDN won't be supported. -This is an error since --with-capi was requested." "$LINENO" 5 ;; -esac -enable_capi2032=${enable_capi2032:-no} -fi - -if test "x$with_cups" != "xno" -then - rm -f conftest.err -if ${CUPS_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - CUPS_CFLAGS=`$PKG_CONFIG --cflags cups 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || CUPS_CFLAGS=${CUPS_CFLAGS:-`${CUPS_CONFIG:-cups-config} --cflags 2>/dev/null`} -if ${CUPS_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - CUPS_LIBS=`$PKG_CONFIG --libs cups 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || CUPS_LIBS=${CUPS_LIBS:-`${CUPS_CONFIG:-cups-config} --libs 2>/dev/null`} -CUPS_LIBS=${CUPS_LIBS:-"-lcups"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: cups cflags: $CUPS_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: cups libs: $CUPS_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: cups errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $CUPS_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "cups/cups.h" "ac_cv_header_cups_cups_h" "$ac_includes_default" -if test "x$ac_cv_header_cups_cups_h" = xyes -then : - printf "%s\n" "#define HAVE_CUPS_CUPS_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "cups/ppd.h" "ac_cv_header_cups_ppd_h" "$ac_includes_default" -if test "x$ac_cv_header_cups_ppd_h" = xyes -then : - printf "%s\n" "#define HAVE_CUPS_PPD_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_cups_cups_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lcups" >&5 -printf %s "checking for -lcups... " >&6; } -if test ${ac_cv_lib_soname_cups+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lcups $CUPS_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char cupsGetDefault (void); -int -main (void) -{ -return cupsGetDefault (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_cups=`$ac_cv_path_LDD conftest.exe | grep "cups" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_cups=`$OTOOL -L conftest$ac_exeext | grep "libcups\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libcups\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_cups=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libcups\\.$LIBEXT" | sed -e "s/^.*\\[\\(libcups\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_cups:+false} : -then : - ac_cv_lib_soname_cups=`$LDD conftest$ac_exeext | grep "libcups\\.$LIBEXT" | sed -e "s/^.*\(libcups\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_cups= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_cups:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - CUPS_LIBS="" -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_cups" >&5 -printf "%s\n" "$ac_cv_lib_soname_cups" >&6; } - -printf "%s\n" "#define SONAME_LIBCUPS \"$ac_cv_lib_soname_cups\"" >>confdefs.h - - ;; -esac -fi - else - CUPS_CFLAGS="" - CUPS_LIBS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_cups" = "x" -then : - case "x$with_cups" in - x) as_fn_append wine_notices "|libcups ${notice_platform}development files not found, CUPS won't be supported." ;; - xno) ;; - *) as_fn_error $? "libcups ${notice_platform}development files not found, CUPS won't be supported. -This is an error since --with-cups was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_fontconfig" != "xno" -then - rm -f conftest.err -if ${FONTCONFIG_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - FONTCONFIG_CFLAGS=`$PKG_CONFIG --cflags fontconfig 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || FONTCONFIG_CFLAGS=${FONTCONFIG_CFLAGS:-$X_CFLAGS} -if ${FONTCONFIG_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - FONTCONFIG_LIBS=`$PKG_CONFIG --libs fontconfig 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || FONTCONFIG_LIBS=${FONTCONFIG_LIBS:-$X_LIBS} - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: fontconfig cflags: $FONTCONFIG_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: fontconfig libs: $FONTCONFIG_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: fontconfig errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $FONTCONFIG_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "fontconfig/fontconfig.h" "ac_cv_header_fontconfig_fontconfig_h" "$ac_includes_default" -if test "x$ac_cv_header_fontconfig_fontconfig_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lfontconfig" >&5 -printf %s "checking for -lfontconfig... " >&6; } -if test ${ac_cv_lib_soname_fontconfig+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lfontconfig $FONTCONFIG_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char FcInit (void); -int -main (void) -{ -return FcInit (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_fontconfig=`$ac_cv_path_LDD conftest.exe | grep "fontconfig" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_fontconfig=`$OTOOL -L conftest$ac_exeext | grep "libfontconfig\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libfontconfig\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_fontconfig=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libfontconfig\\.$LIBEXT" | sed -e "s/^.*\\[\\(libfontconfig\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_fontconfig:+false} : -then : - ac_cv_lib_soname_fontconfig=`$LDD conftest$ac_exeext | grep "libfontconfig\\.$LIBEXT" | sed -e "s/^.*\(libfontconfig\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_fontconfig= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_fontconfig:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - FONTCONFIG_CFLAGS="" -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_fontconfig" >&5 -printf "%s\n" "$ac_cv_lib_soname_fontconfig" >&6; } - -printf "%s\n" "#define SONAME_LIBFONTCONFIG \"$ac_cv_lib_soname_fontconfig\"" >>confdefs.h - - ;; -esac -fi -else case e in #( - e) FONTCONFIG_CFLAGS="" ;; -esac -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_fontconfig" = "x" -then : - case "x$with_fontconfig" in - x) as_fn_append wine_notices "|fontconfig ${notice_platform}development files not found, fontconfig won't be supported." ;; - xno) ;; - *) as_fn_error $? "fontconfig ${notice_platform}development files not found, fontconfig won't be supported. -This is an error since --with-fontconfig was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_krb5" != "xno" -then - rm -f conftest.err -if ${KRB5_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - KRB5_CFLAGS=`$PKG_CONFIG --cflags krb5 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || KRB5_CFLAGS=${KRB5_CFLAGS:-`${KRB5_CONFIG:-krb5-config} --cflags 2>/dev/null`} -if ${KRB5_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - KRB5_LIBS=`$PKG_CONFIG --libs krb5 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || KRB5_LIBS=${KRB5_LIBS:-`${KRB5_CONFIG:-krb5-config} --libs 2>/dev/null`} - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: krb5 cflags: $KRB5_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: krb5 libs: $KRB5_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: krb5 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $KRB5_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "krb5/krb5.h" "ac_cv_header_krb5_krb5_h" "$ac_includes_default" -if test "x$ac_cv_header_krb5_krb5_h" = xyes -then : - printf "%s\n" "#define HAVE_KRB5_KRB5_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_krb5_krb5_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lkrb5" >&5 -printf %s "checking for -lkrb5... " >&6; } -if test ${ac_cv_lib_soname_krb5+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lkrb5 $KRB5_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char krb5_is_config_principal (void); -int -main (void) -{ -return krb5_is_config_principal (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_krb5=`$ac_cv_path_LDD conftest.exe | grep "krb5" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_krb5=`$OTOOL -L conftest$ac_exeext | grep "libkrb5\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libkrb5\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_krb5=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libkrb5\\.$LIBEXT" | sed -e "s/^.*\\[\\(libkrb5\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_krb5:+false} : -then : - ac_cv_lib_soname_krb5=`$LDD conftest$ac_exeext | grep "libkrb5\\.$LIBEXT" | sed -e "s/^.*\(libkrb5\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_krb5= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_krb5:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - KRB5_CFLAGS="" -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_krb5" >&5 -printf "%s\n" "$ac_cv_lib_soname_krb5" >&6; } - -printf "%s\n" "#define SONAME_LIBKRB5 \"$ac_cv_lib_soname_krb5\"" >>confdefs.h - - ;; -esac -fi - else - KRB5_CFLAGS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_krb5" = "x" -then : - case "x$with_krb5" in - x) as_fn_append wine_notices "|libkrb5 ${notice_platform}development files not found (or too old), Kerberos won't be supported." ;; - xno) ;; - *) as_fn_error $? "libkrb5 ${notice_platform}development files not found (or too old), Kerberos won't be supported. -This is an error since --with-krb5 was requested." "$LINENO" 5 ;; -esac - -fi -test "x$ac_cv_lib_soname_krb5" != "x" || with_gssapi=${with_gssapi:-no} - -if test "x$with_gssapi" != "xno" -then - rm -f conftest.err -if ${GSSAPI_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GSSAPI_CFLAGS=`$PKG_CONFIG --cflags krb5-gssapi 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || GSSAPI_CFLAGS=${GSSAPI_CFLAGS:-`${KRB5_CONFIG:-krb5-config} --cflags gssapi 2>/dev/null`} -if ${GSSAPI_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GSSAPI_LIBS=`$PKG_CONFIG --libs krb5-gssapi 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || GSSAPI_LIBS=${GSSAPI_LIBS:-`${KRB5_CONFIG:-krb5-config} --libs gssapi 2>/dev/null`} - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: krb5-gssapi cflags: $GSSAPI_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: krb5-gssapi libs: $GSSAPI_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: krb5-gssapi errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $GSSAPI_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "gssapi/gssapi.h" "ac_cv_header_gssapi_gssapi_h" "$ac_includes_default" -if test "x$ac_cv_header_gssapi_gssapi_h" = xyes -then : - printf "%s\n" "#define HAVE_GSSAPI_GSSAPI_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "gssapi/gssapi_ext.h" "ac_cv_header_gssapi_gssapi_ext_h" "$ac_includes_default" -if test "x$ac_cv_header_gssapi_gssapi_ext_h" = xyes -then : - printf "%s\n" "#define HAVE_GSSAPI_GSSAPI_EXT_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_gssapi_gssapi_h" = "yes" -a "$ac_cv_header_gssapi_gssapi_ext_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lgssapi_krb5" >&5 -printf %s "checking for -lgssapi_krb5... " >&6; } -if test ${ac_cv_lib_soname_gssapi_krb5+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lgssapi_krb5 $GSSAPI_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char gss_init_sec_context (void); -int -main (void) -{ -return gss_init_sec_context (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_gssapi_krb5=`$ac_cv_path_LDD conftest.exe | grep "gssapi_krb5" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_gssapi_krb5=`$OTOOL -L conftest$ac_exeext | grep "libgssapi_krb5\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libgssapi_krb5\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_gssapi_krb5=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libgssapi_krb5\\.$LIBEXT" | sed -e "s/^.*\\[\\(libgssapi_krb5\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_gssapi_krb5:+false} : -then : - ac_cv_lib_soname_gssapi_krb5=`$LDD conftest$ac_exeext | grep "libgssapi_krb5\\.$LIBEXT" | sed -e "s/^.*\(libgssapi_krb5\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_gssapi_krb5= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_gssapi_krb5:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - GSSAPI_CFLAGS="" -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_gssapi_krb5" >&5 -printf "%s\n" "$ac_cv_lib_soname_gssapi_krb5" >&6; } - -printf "%s\n" "#define SONAME_LIBGSSAPI_KRB5 \"$ac_cv_lib_soname_gssapi_krb5\"" >>confdefs.h - - ;; -esac -fi - else - GSSAPI_CFLAGS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_gssapi_krb5" = "x" -then : - case "x$with_gssapi" in - x) as_fn_append wine_notices "|libgssapi_krb5 ${notice_platform}development files not found (or too old), no Kerberos SSP support." ;; - xno) ;; - *) as_fn_error $? "libgssapi_krb5 ${notice_platform}development files not found (or too old), no Kerberos SSP support. -This is an error since --with-gssapi was requested." "$LINENO" 5 ;; -esac - -fi - -if test "$ac_cv_header_libprocstat_h" = "yes" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for procstat_open_sysctl in -lprocstat" >&5 -printf %s "checking for procstat_open_sysctl in -lprocstat... " >&6; } -if test ${ac_cv_lib_procstat_procstat_open_sysctl+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lprocstat $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char procstat_open_sysctl (void); -int -main (void) -{ -return procstat_open_sysctl (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_procstat_procstat_open_sysctl=yes -else case e in #( - e) ac_cv_lib_procstat_procstat_open_sysctl=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_procstat_procstat_open_sysctl" >&5 -printf "%s\n" "$ac_cv_lib_procstat_procstat_open_sysctl" >&6; } -if test "x$ac_cv_lib_procstat_procstat_open_sysctl" = xyes -then : - -printf "%s\n" "#define HAVE_LIBPROCSTAT 1" >>confdefs.h - - PROCSTAT_LIBS="-lprocstat" - -fi - -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lodbc" >&5 -printf %s "checking for -lodbc... " >&6; } -if test ${ac_cv_lib_soname_odbc+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lodbc $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char SQLConnect (void); -int -main (void) -{ -return SQLConnect (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_odbc=`$ac_cv_path_LDD conftest.exe | grep "odbc" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_odbc=`$OTOOL -L conftest$ac_exeext | grep "libodbc\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libodbc\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_odbc=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libodbc\\.$LIBEXT" | sed -e "s/^.*\\[\\(libodbc\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_odbc:+false} : -then : - ac_cv_lib_soname_odbc=`$LDD conftest$ac_exeext | grep "libodbc\\.$LIBEXT" | sed -e "s/^.*\(libodbc\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_odbc= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_odbc:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - printf "%s\n" "#define SONAME_LIBODBC \"libodbc.$LIBEXT\"" >>confdefs.h - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_odbc" >&5 -printf "%s\n" "$ac_cv_lib_soname_odbc" >&6; } - -printf "%s\n" "#define SONAME_LIBODBC \"$ac_cv_lib_soname_odbc\"" >>confdefs.h - - ;; -esac -fi - -if test "x$with_netapi" != "xno" -then - rm -f conftest.err -if ${NETAPI_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - NETAPI_CFLAGS=`$PKG_CONFIG --cflags netapi 2>conftest.err` -fi -fi - -if ${NETAPI_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - NETAPI_LIBS=`$PKG_CONFIG --libs netapi 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: netapi cflags: $NETAPI_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: netapi libs: $NETAPI_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: netapi errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $NETAPI_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lnetapi" >&5 -printf %s "checking for -lnetapi... " >&6; } -if test ${ac_cv_lib_soname_netapi+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lnetapi $NETAPI_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char libnetapi_init (void); -int -main (void) -{ -return libnetapi_init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_netapi=`$ac_cv_path_LDD conftest.exe | grep "netapi" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_netapi=`$OTOOL -L conftest$ac_exeext | grep "libnetapi\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libnetapi\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_netapi=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libnetapi\\.$LIBEXT" | sed -e "s/^.*\\[\\(libnetapi\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_netapi:+false} : -then : - ac_cv_lib_soname_netapi=`$LDD conftest$ac_exeext | grep "libnetapi\\.$LIBEXT" | sed -e "s/^.*\(libnetapi\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_netapi= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_netapi:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - printf "%s\n" "#define SONAME_LIBNETAPI \"libnetapi.$LIBEXT\"" >>confdefs.h - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_netapi" >&5 -printf "%s\n" "$ac_cv_lib_soname_netapi" >&6; } - -printf "%s\n" "#define SONAME_LIBNETAPI \"$ac_cv_lib_soname_netapi\"" >>confdefs.h - - ;; -esac -fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_netapi" = "x" -then : - case "x$with_netapi" in - x) as_fn_append wine_notices "|libnetapi not found, Samba NetAPI won't be supported." ;; - xno) ;; - *) as_fn_error $? "libnetapi not found, Samba NetAPI won't be supported. -This is an error since --with-netapi was requested." "$LINENO" 5 ;; -esac -enable_netapi=${enable_netapi:-no} -fi - - -if test "x$enable_winealsa_drv$enable_winecoreaudio_drv$enable_winepulse_drv$enable_wineoss_drv$enable_wineandroid_drv" = xnonononono -a \ - "x$with_alsa$with_coreaudio$with_oss$with_pulse" != xnononono -then - as_fn_append wine_warnings "|No sound system was found. Windows applications will be silent." -fi - -if test "x$with_vulkan" != "xno" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lvulkan" >&5 -printf %s "checking for -lvulkan... " >&6; } -if test ${ac_cv_lib_soname_vulkan+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lvulkan $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char vkGetInstanceProcAddr (void); -int -main (void) -{ -return vkGetInstanceProcAddr (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_vulkan=`$ac_cv_path_LDD conftest.exe | grep "vulkan" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_vulkan=`$OTOOL -L conftest$ac_exeext | grep "libvulkan\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libvulkan\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_vulkan=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libvulkan\\.$LIBEXT" | sed -e "s/^.*\\[\\(libvulkan\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_vulkan:+false} : -then : - ac_cv_lib_soname_vulkan=`$LDD conftest$ac_exeext | grep "libvulkan\\.$LIBEXT" | sed -e "s/^.*\(libvulkan\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_vulkan= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_vulkan:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_vulkan" >&5 -printf "%s\n" "$ac_cv_lib_soname_vulkan" >&6; } - -printf "%s\n" "#define SONAME_LIBVULKAN \"$ac_cv_lib_soname_vulkan\"" >>confdefs.h - - ;; -esac -fi - if test "x$ac_cv_lib_soname_vulkan" = "x" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lMoltenVK" >&5 -printf %s "checking for -lMoltenVK... " >&6; } -if test ${ac_cv_lib_soname_MoltenVK+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_soname_save_LIBS=$LIBS -LIBS="-lMoltenVK $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char vkGetInstanceProcAddr (void); -int -main (void) -{ -return vkGetInstanceProcAddr (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_MoltenVK=`$ac_cv_path_LDD conftest.exe | grep "MoltenVK" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_MoltenVK=`$OTOOL -L conftest$ac_exeext | grep "libMoltenVK\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libMoltenVK\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_MoltenVK=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libMoltenVK\\.$LIBEXT" | sed -e "s/^.*\\[\\(libMoltenVK\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_MoltenVK:+false} : -then : - ac_cv_lib_soname_MoltenVK=`$LDD conftest$ac_exeext | grep "libMoltenVK\\.$LIBEXT" | sed -e "s/^.*\(libMoltenVK\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else case e in #( - e) ac_cv_lib_soname_MoltenVK= ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS ;; -esac -fi -if ${ac_cv_lib_soname_MoltenVK:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_MoltenVK" >&5 -printf "%s\n" "$ac_cv_lib_soname_MoltenVK" >&6; } - -printf "%s\n" "#define SONAME_LIBMOLTENVK \"$ac_cv_lib_soname_MoltenVK\"" >>confdefs.h - - printf "%s\n" "#define SONAME_LIBVULKAN \"$ac_cv_lib_soname_MoltenVK\"" >>confdefs.h - ;; -esac -fi - fi -fi -if test "x$ac_cv_lib_soname_vulkan" = "x" -a "x$ac_cv_lib_soname_MoltenVK" = "x" -then : - case "x$with_vulkan" in - x) as_fn_append wine_notices "|libvulkan and libMoltenVK ${notice_platform}development files not found, Vulkan won't be supported." ;; - xno) ;; - *) as_fn_error $? "libvulkan and libMoltenVK ${notice_platform}development files not found, Vulkan won't be supported. -This is an error since --with-vulkan was requested." "$LINENO" 5 ;; -esac - -fi - - -if test "x${GCC}" = "xyes" -then - EXTRACFLAGS="$EXTRACFLAGS -Wall -pipe" - - saved_CFLAGS=$CFLAGS - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Werror=unknown-warning-option" >&5 -printf %s "checking whether the compiler supports -Werror=unknown-warning-option... " >&6; } -if test ${ac_cv_cflags__Werror_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Werror=unknown-warning-option" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Werror_unknown_warning_option=yes -else case e in #( - e) ac_cv_cflags__Werror_unknown_warning_option=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Werror_unknown_warning_option" >&5 -printf "%s\n" "$ac_cv_cflags__Werror_unknown_warning_option" >&6; } -if test "x$ac_cv_cflags__Werror_unknown_warning_option" = xyes -then : - CFLAGS="$CFLAGS -Werror=unknown-warning-option" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Werror=unused-command-line-argument" >&5 -printf %s "checking whether the compiler supports -Werror=unused-command-line-argument... " >&6; } -if test ${ac_cv_cflags__Werror_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Werror=unused-command-line-argument" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Werror_unused_command_line_argument=yes -else case e in #( - e) ac_cv_cflags__Werror_unused_command_line_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Werror_unused_command_line_argument" >&5 -printf "%s\n" "$ac_cv_cflags__Werror_unused_command_line_argument" >&6; } -if test "x$ac_cv_cflags__Werror_unused_command_line_argument" = xyes -then : - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Werror=ignored-optimization-argument" >&5 -printf %s "checking whether the compiler supports -Werror=ignored-optimization-argument... " >&6; } -if test ${ac_cv_cflags__Werror_ignored_optimization_argument+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Werror=ignored-optimization-argument" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Werror_ignored_optimization_argument=yes -else case e in #( - e) ac_cv_cflags__Werror_ignored_optimization_argument=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Werror_ignored_optimization_argument" >&5 -printf "%s\n" "$ac_cv_cflags__Werror_ignored_optimization_argument" >&6; } -if test "x$ac_cv_cflags__Werror_ignored_optimization_argument" = xyes -then : - CFLAGS="$CFLAGS -Werror=ignored-optimization-argument" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fcf-protection=none" >&5 -printf %s "checking whether the compiler supports -fcf-protection=none... " >&6; } -if test ${ac_cv_cflags__fcf_protection_none+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fcf-protection=none" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fcf_protection_none=yes -else case e in #( - e) ac_cv_cflags__fcf_protection_none=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fcf_protection_none" >&5 -printf "%s\n" "$ac_cv_cflags__fcf_protection_none" >&6; } -if test "x$ac_cv_cflags__fcf_protection_none" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -fcf-protection=none" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fvisibility=hidden" >&5 -printf %s "checking whether the compiler supports -fvisibility=hidden... " >&6; } -if test ${ac_cv_cflags__fvisibility_hidden+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fvisibility=hidden" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fvisibility_hidden=yes -else case e in #( - e) ac_cv_cflags__fvisibility_hidden=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fvisibility_hidden" >&5 -printf "%s\n" "$ac_cv_cflags__fvisibility_hidden" >&6; } -if test "x$ac_cv_cflags__fvisibility_hidden" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -fvisibility=hidden" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fno-stack-protector" >&5 -printf %s "checking whether the compiler supports -fno-stack-protector... " >&6; } -if test ${ac_cv_cflags__fno_stack_protector+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fno-stack-protector" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fno_stack_protector=yes -else case e in #( - e) ac_cv_cflags__fno_stack_protector=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_stack_protector" >&5 -printf "%s\n" "$ac_cv_cflags__fno_stack_protector" >&6; } -if test "x$ac_cv_cflags__fno_stack_protector" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -fno-stack-protector" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fno-strict-aliasing" >&5 -printf %s "checking whether the compiler supports -fno-strict-aliasing... " >&6; } -if test ${ac_cv_cflags__fno_strict_aliasing+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fno-strict-aliasing" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fno_strict_aliasing=yes -else case e in #( - e) ac_cv_cflags__fno_strict_aliasing=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_strict_aliasing" >&5 -printf "%s\n" "$ac_cv_cflags__fno_strict_aliasing" >&6; } -if test "x$ac_cv_cflags__fno_strict_aliasing" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -fno-strict-aliasing" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wdeclaration-after-statement" >&5 -printf %s "checking whether the compiler supports -Wdeclaration-after-statement... " >&6; } -if test ${ac_cv_cflags__Wdeclaration_after_statement+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wdeclaration-after-statement" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wdeclaration_after_statement=yes -else case e in #( - e) ac_cv_cflags__Wdeclaration_after_statement=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wdeclaration_after_statement" >&5 -printf "%s\n" "$ac_cv_cflags__Wdeclaration_after_statement" >&6; } -if test "x$ac_cv_cflags__Wdeclaration_after_statement" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wdeclaration-after-statement" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wempty-body" >&5 -printf %s "checking whether the compiler supports -Wempty-body... " >&6; } -if test ${ac_cv_cflags__Wempty_body+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wempty-body" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wempty_body=yes -else case e in #( - e) ac_cv_cflags__Wempty_body=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wempty_body" >&5 -printf "%s\n" "$ac_cv_cflags__Wempty_body" >&6; } -if test "x$ac_cv_cflags__Wempty_body" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wempty-body" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wignored-qualifiers" >&5 -printf %s "checking whether the compiler supports -Wignored-qualifiers... " >&6; } -if test ${ac_cv_cflags__Wignored_qualifiers+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wignored-qualifiers" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wignored_qualifiers=yes -else case e in #( - e) ac_cv_cflags__Wignored_qualifiers=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wignored_qualifiers" >&5 -printf "%s\n" "$ac_cv_cflags__Wignored_qualifiers" >&6; } -if test "x$ac_cv_cflags__Wignored_qualifiers" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wignored-qualifiers" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Winit-self" >&5 -printf %s "checking whether the compiler supports -Winit-self... " >&6; } -if test ${ac_cv_cflags__Winit_self+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Winit-self" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Winit_self=yes -else case e in #( - e) ac_cv_cflags__Winit_self=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Winit_self" >&5 -printf "%s\n" "$ac_cv_cflags__Winit_self" >&6; } -if test "x$ac_cv_cflags__Winit_self" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Winit-self" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wlogical-op" >&5 -printf %s "checking whether the compiler supports -Wlogical-op... " >&6; } -if test ${ac_cv_cflags__Wlogical_op+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wlogical-op" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wlogical_op=yes -else case e in #( - e) ac_cv_cflags__Wlogical_op=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wlogical_op" >&5 -printf "%s\n" "$ac_cv_cflags__Wlogical_op" >&6; } -if test "x$ac_cv_cflags__Wlogical_op" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wlogical-op" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wpacked-not-aligned" >&5 -printf %s "checking whether the compiler supports -Wpacked-not-aligned... " >&6; } -if test ${ac_cv_cflags__Wpacked_not_aligned+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wpacked-not-aligned" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wpacked_not_aligned=yes -else case e in #( - e) ac_cv_cflags__Wpacked_not_aligned=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wpacked_not_aligned" >&5 -printf "%s\n" "$ac_cv_cflags__Wpacked_not_aligned" >&6; } -if test "x$ac_cv_cflags__Wpacked_not_aligned" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wno-packed-not-aligned" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wpointer-arith" >&5 -printf %s "checking whether the compiler supports -Wpointer-arith... " >&6; } -if test ${ac_cv_cflags__Wpointer_arith+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wpointer-arith" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wpointer_arith=yes -else case e in #( - e) ac_cv_cflags__Wpointer_arith=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wpointer_arith" >&5 -printf "%s\n" "$ac_cv_cflags__Wpointer_arith" >&6; } -if test "x$ac_cv_cflags__Wpointer_arith" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wpointer-arith" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wpragma-pack" >&5 -printf %s "checking whether the compiler supports -Wpragma-pack... " >&6; } -if test ${ac_cv_cflags__Wpragma_pack+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wpragma-pack" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wpragma_pack=yes -else case e in #( - e) ac_cv_cflags__Wpragma_pack=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wpragma_pack" >&5 -printf "%s\n" "$ac_cv_cflags__Wpragma_pack" >&6; } -if test "x$ac_cv_cflags__Wpragma_pack" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wno-pragma-pack" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wshift-overflow=2" >&5 -printf %s "checking whether the compiler supports -Wshift-overflow=2... " >&6; } -if test ${ac_cv_cflags__Wshift_overflow_2+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wshift-overflow=2" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wshift_overflow_2=yes -else case e in #( - e) ac_cv_cflags__Wshift_overflow_2=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wshift_overflow_2" >&5 -printf "%s\n" "$ac_cv_cflags__Wshift_overflow_2" >&6; } -if test "x$ac_cv_cflags__Wshift_overflow_2" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wshift-overflow=2" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wstrict-prototypes" >&5 -printf %s "checking whether the compiler supports -Wstrict-prototypes... " >&6; } -if test ${ac_cv_cflags__Wstrict_prototypes+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wstrict-prototypes" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wstrict_prototypes=yes -else case e in #( - e) ac_cv_cflags__Wstrict_prototypes=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wstrict_prototypes" >&5 -printf "%s\n" "$ac_cv_cflags__Wstrict_prototypes" >&6; } -if test "x$ac_cv_cflags__Wstrict_prototypes" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wstrict-prototypes" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wtype-limits" >&5 -printf %s "checking whether the compiler supports -Wtype-limits... " >&6; } -if test ${ac_cv_cflags__Wtype_limits+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wtype-limits" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wtype_limits=yes -else case e in #( - e) ac_cv_cflags__Wtype_limits=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wtype_limits" >&5 -printf "%s\n" "$ac_cv_cflags__Wtype_limits" >&6; } -if test "x$ac_cv_cflags__Wtype_limits" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wtype-limits" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wunused-but-set-parameter" >&5 -printf %s "checking whether the compiler supports -Wunused-but-set-parameter... " >&6; } -if test ${ac_cv_cflags__Wunused_but_set_parameter+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wunused-but-set-parameter" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wunused_but_set_parameter=yes -else case e in #( - e) ac_cv_cflags__Wunused_but_set_parameter=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wunused_but_set_parameter" >&5 -printf "%s\n" "$ac_cv_cflags__Wunused_but_set_parameter" >&6; } -if test "x$ac_cv_cflags__Wunused_but_set_parameter" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wunused-but-set-parameter" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wvla" >&5 -printf %s "checking whether the compiler supports -Wvla... " >&6; } -if test ${ac_cv_cflags__Wvla+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wvla" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wvla=yes -else case e in #( - e) ac_cv_cflags__Wvla=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wvla" >&5 -printf "%s\n" "$ac_cv_cflags__Wvla" >&6; } -if test "x$ac_cv_cflags__Wvla" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wvla" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wwrite-strings" >&5 -printf %s "checking whether the compiler supports -Wwrite-strings... " >&6; } -if test ${ac_cv_cflags__Wwrite_strings+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wwrite-strings" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wwrite_strings=yes -else case e in #( - e) ac_cv_cflags__Wwrite_strings=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wwrite_strings" >&5 -printf "%s\n" "$ac_cv_cflags__Wwrite_strings" >&6; } -if test "x$ac_cv_cflags__Wwrite_strings" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wwrite-strings" -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -flarge-source-files -Wmisleading-indentation" >&5 -printf %s "checking whether the compiler supports -flarge-source-files -Wmisleading-indentation... " >&6; } -if test ${ac_cv_cflags__flarge_source_files__Wmisleading_indentation+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -flarge-source-files -Wmisleading-indentation" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__flarge_source_files__Wmisleading_indentation=yes -else case e in #( - e) ac_cv_cflags__flarge_source_files__Wmisleading_indentation=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__flarge_source_files__Wmisleading_indentation" >&5 -printf "%s\n" "$ac_cv_cflags__flarge_source_files__Wmisleading_indentation" >&6; } -if test "x$ac_cv_cflags__flarge_source_files__Wmisleading_indentation" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wno-misleading-indentation" -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for flags needed for 64-bit compare-and-swap support" >&5 -printf %s "checking for flags needed for 64-bit compare-and-swap support... " >&6; } -if test ${wine_cv_64bit_compare_swap+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 -#error no -#endif -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - wine_cv_64bit_compare_swap="none needed" -else case e in #( - e) case $HOST_ARCH in - i386) wine_cv_64bit_compare_swap="-march=i586" ;; - arm) wine_cv_64bit_compare_swap="-march=armv7-a" ;; - *) wine_cv_64bit_compare_swap="unknown" ;; - esac - if test "x$wine_cv_64bit_compare_swap" != xunknown - then - CFLAGS="$CFLAGS $wine_cv_64bit_compare_swap" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 -#error no -#endif -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else case e in #( - e) wine_cv_64bit_compare_swap="unknown" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$saved_CFLAGS - fi ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_64bit_compare_swap" >&5 -printf "%s\n" "$wine_cv_64bit_compare_swap" >&6; } - case "$wine_cv_64bit_compare_swap" in - unknown) as_fn_error $? "gcc doesn't support 64-bit compare-and-swap on this platform" "$LINENO" 5 ;; - "none needed") ;; - *) EXTRACFLAGS="$EXTRACFLAGS $wine_cv_64bit_compare_swap" ;; - esac - - ac_debug_format_seen="" - for ac_flag in $CFLAGS; do - case $ac_flag in - -gdwarf*) ac_debug_format_seen=yes ;; - -g) ac_debug_format_seen=${ac_debug_format_seen:-default} ;; - esac - done - if test "x$ac_debug_format_seen" = xdefault - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -gdwarf-4" >&5 -printf %s "checking whether the compiler supports -gdwarf-4... " >&6; } -if test ${ac_cv_cflags__gdwarf_4+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -gdwarf-4" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__gdwarf_4=yes -else case e in #( - e) ac_cv_cflags__gdwarf_4=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__gdwarf_4" >&5 -printf "%s\n" "$ac_cv_cflags__gdwarf_4" >&6; } -if test "x$ac_cv_cflags__gdwarf_4" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -gdwarf-4" -fi - fi - - MSVCRTFLAGS="" - - case $host_os in - mingw32*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-delayload,autoconftest.dll" >&5 -printf %s "checking whether the compiler supports -Wl,-delayload,autoconftest.dll... " >&6; } -if test ${ac_cv_cflags__Wl__delayload_autoconftest_dll+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-delayload,autoconftest.dll" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__delayload_autoconftest_dll=yes -else case e in #( - e) ac_cv_cflags__Wl__delayload_autoconftest_dll=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__delayload_autoconftest_dll" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__delayload_autoconftest_dll" >&6; } -if test "x$ac_cv_cflags__Wl__delayload_autoconftest_dll" = xyes -then : - DELAYLOADFLAG="-Wl,-delayload," - -fi ;; - *) MSVCRTFLAGS="-D_WIN32" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fno-builtin" >&5 -printf %s "checking whether the compiler supports -fno-builtin... " >&6; } -if test ${ac_cv_cflags__fno_builtin+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fno-builtin" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fno_builtin=yes -else case e in #( - e) ac_cv_cflags__fno_builtin=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_builtin" >&5 -printf "%s\n" "$ac_cv_cflags__fno_builtin" >&6; } -if test "x$ac_cv_cflags__fno_builtin" = xyes -then : - MSVCRTFLAGS="$MSVCRTFLAGS -fno-builtin" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fshort-wchar" >&5 -printf %s "checking whether the compiler supports -fshort-wchar... " >&6; } -if test ${ac_cv_cflags__fshort_wchar+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fshort-wchar" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fshort_wchar=yes -else case e in #( - e) ac_cv_cflags__fshort_wchar=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fshort_wchar" >&5 -printf "%s\n" "$ac_cv_cflags__fshort_wchar" >&6; } -if test "x$ac_cv_cflags__fshort_wchar" = xyes -then : - MSVCRTFLAGS="$MSVCRTFLAGS -fshort-wchar" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wno-format" >&5 -printf %s "checking whether the compiler supports -Wno-format... " >&6; } -if test ${ac_cv_cflags__Wno_format+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wno-format" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wno_format=yes -else case e in #( - e) ac_cv_cflags__Wno_format=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wno_format" >&5 -printf "%s\n" "$ac_cv_cflags__Wno_format" >&6; } -if test "x$ac_cv_cflags__Wno_format" = xyes -then : - MSVCRTFLAGS="$MSVCRTFLAGS -Wno-format" -fi ;; - esac - - case $HOST_ARCH in - i386) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fno-omit-frame-pointer" >&5 -printf %s "checking whether the compiler supports -fno-omit-frame-pointer... " >&6; } -if test ${ac_cv_cflags__fno_omit_frame_pointer+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fno-omit-frame-pointer" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fno_omit_frame_pointer=yes -else case e in #( - e) ac_cv_cflags__fno_omit_frame_pointer=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_omit_frame_pointer" >&5 -printf "%s\n" "$ac_cv_cflags__fno_omit_frame_pointer" >&6; } -if test "x$ac_cv_cflags__fno_omit_frame_pointer" = xyes -then : - MSVCRTFLAGS="$MSVCRTFLAGS -fno-omit-frame-pointer" -fi ;; - x86_64) - case $host_os in - cygwin*|mingw32*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wno-format" >&5 -printf %s "checking whether the compiler supports -Wno-format... " >&6; } -if test ${ac_cv_cflags__Wno_format+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wno-format" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wno_format=yes -else case e in #( - e) ac_cv_cflags__Wno_format=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wno_format" >&5 -printf "%s\n" "$ac_cv_cflags__Wno_format" >&6; } -if test "x$ac_cv_cflags__Wno_format" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wno-format" -fi ;; - *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working -mabi=ms" >&5 -printf %s "checking for working -mabi=ms... " >&6; } -if test ${ac_cv_mabi_ms+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) CFLAGS="$CFLAGS -mabi=ms" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int a(int b, ...) { __builtin_ms_va_list list; __builtin_ms_va_start(list,b); } -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mabi_ms=yes -else case e in #( - e) ac_cv_mabi_ms=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$saved_CFLAGS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mabi_ms" >&5 -printf "%s\n" "$ac_cv_mabi_ms" >&6; } - if test "x$ac_cv_mabi_ms" = xyes -then : - MSVCRTFLAGS="$MSVCRTFLAGS -mabi=ms" -else case e in #( - e) test -n "$PE_ARCHS" || as_fn_error $? "The compiler doesn't support -mabi=ms. Use gcc instead of clang, or install mingw-w64." "$LINENO" 5 - DLLEXT="" ;; -esac -fi ;; - esac ;; - arm) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wincompatible-function-pointer-types" >&5 -printf %s "checking whether the compiler supports -Wincompatible-function-pointer-types... " >&6; } -if test ${ac_cv_cflags__Wincompatible_function_pointer_types+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wincompatible-function-pointer-types" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wincompatible_function_pointer_types=yes -else case e in #( - e) ac_cv_cflags__Wincompatible_function_pointer_types=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wincompatible_function_pointer_types" >&5 -printf "%s\n" "$ac_cv_cflags__Wincompatible_function_pointer_types" >&6; } -if test "x$ac_cv_cflags__Wincompatible_function_pointer_types" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wno-error=incompatible-function-pointer-types" -fi ;; - esac - - CFLAGS=$saved_CFLAGS - - if test "x$enable_werror" = "xyes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Werror" >&5 -printf %s "checking whether the compiler supports -Werror... " >&6; } -if test ${ac_cv_cflags__Werror+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Werror" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Werror=yes -else case e in #( - e) ac_cv_cflags__Werror=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Werror" >&5 -printf "%s\n" "$ac_cv_cflags__Werror" >&6; } -if test "x$ac_cv_cflags__Werror" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Werror" -fi - fi - - if test "x$enable_build_id" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,--build-id" >&5 -printf %s "checking whether the compiler supports -Wl,--build-id... " >&6; } -if test ${ac_cv_cflags__Wl___build_id+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,--build-id" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl___build_id=yes -else case e in #( - e) ac_cv_cflags__Wl___build_id=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl___build_id" >&5 -printf "%s\n" "$ac_cv_cflags__Wl___build_id" >&6; } -if test "x$ac_cv_cflags__Wl___build_id" = xyes -then : - LDFLAGS="$LDFLAGS -Wl,--build-id" -fi -fi -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the need to disable Fortify" >&5 -printf %s "checking for the need to disable Fortify... " >&6; } -if test ${ac_cv_c_fortify_enabled+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -#if (defined(__USE_FORTIFY_LEVEL) && __USE_FORTIFY_LEVEL > 0) || (defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0) -#error Fortify enabled -#endif - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_fortify_enabled=no -else case e in #( - e) ac_cv_c_fortify_enabled=yes ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_fortify_enabled" >&5 -printf "%s\n" "$ac_cv_c_fortify_enabled" >&6; } -if test "$ac_cv_c_fortify_enabled" = yes -then - CFLAGS="$CFLAGS -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0" -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether CFI directives are supported in assembly code" >&5 -printf %s "checking whether CFI directives are supported in assembly code... " >&6; } -if test ${ac_cv_c_cfi_support+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -asm(".text\nac_test:\t.cfi_startproc\n\t.long 0\n\t.cfi_endproc"); -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_cfi_support="yes" -else case e in #( - e) ac_cv_c_cfi_support="no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_cfi_support" >&5 -printf "%s\n" "$ac_cv_c_cfi_support" >&6; } -if test "$ac_cv_c_cfi_support" = "yes" -then - DLLFLAGS="$DLLFLAGS -fasynchronous-unwind-tables" - LDDLLFLAGS="$LDDLLFLAGS -fasynchronous-unwind-tables" - UNIXDLLFLAGS="$UNIXDLLFLAGS -fasynchronous-unwind-tables" -elif test $HOST_ARCH = x86_64 -then - as_fn_append wine_warnings "|building 64-bit Wine without support for CFI directives; exception handling will not work properly." -fi - - -case "$HOST_ARCH,$PE_ARCHS" in - x86_64,*i386*) wine_binary="wine" ;; - x86_64,*) wine_binary="wine64" ;; - *) wine_binary="wine" ;; -esac -WINELOADER_PROGRAMS="$wine_binary" - - -case $host_os in - linux*) - if test $HOST_ARCH != unknown - then - wine_use_preloader=yes - fi - ;; -esac - -if test "$wine_use_preloader" = "yes" -then - test "$wine_binary" = wine || as_fn_append CONFIGURE_TARGETS " loader/wine-preloader" - WINELOADER_PROGRAMS="$WINELOADER_PROGRAMS $wine_binary-preloader" - -printf "%s\n" "#define HAVE_WINE_PRELOADER 1" >>confdefs.h - -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 -printf %s "checking for library containing dlopen... " >&6; } -if test ${ac_cv_search_dlopen+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (void); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -for ac_lib in '' dl -do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO" -then : - ac_cv_search_dlopen=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext - if test ${ac_cv_search_dlopen+y} -then : - break -fi -done -if test ${ac_cv_search_dlopen+y} -then : - -else case e in #( - e) ac_cv_search_dlopen=no ;; -esac -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 -printf "%s\n" "$ac_cv_search_dlopen" >&6; } -ac_res=$ac_cv_search_dlopen -if test "$ac_res" != no -then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - -ac_save_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS $BUILTINFLAG" -ac_fn_c_check_func "$LINENO" "dladdr1" "ac_cv_func_dladdr1" -if test "x$ac_cv_func_dladdr1" = xyes -then : - printf "%s\n" "#define HAVE_DLADDR1 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "dlinfo" "ac_cv_func_dlinfo" -if test "x$ac_cv_func_dlinfo" = xyes -then : - printf "%s\n" "#define HAVE_DLINFO 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "epoll_create" "ac_cv_func_epoll_create" -if test "x$ac_cv_func_epoll_create" = xyes -then : - printf "%s\n" "#define HAVE_EPOLL_CREATE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "fstatfs" "ac_cv_func_fstatfs" -if test "x$ac_cv_func_fstatfs" = xyes -then : - printf "%s\n" "#define HAVE_FSTATFS 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "futimens" "ac_cv_func_futimens" -if test "x$ac_cv_func_futimens" = xyes -then : - printf "%s\n" "#define HAVE_FUTIMENS 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "futimes" "ac_cv_func_futimes" -if test "x$ac_cv_func_futimes" = xyes -then : - printf "%s\n" "#define HAVE_FUTIMES 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "futimesat" "ac_cv_func_futimesat" -if test "x$ac_cv_func_futimesat" = xyes -then : - printf "%s\n" "#define HAVE_FUTIMESAT 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo" -if test "x$ac_cv_func_getaddrinfo" = xyes -then : - printf "%s\n" "#define HAVE_GETADDRINFO 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "getattrlist" "ac_cv_func_getattrlist" -if test "x$ac_cv_func_getattrlist" = xyes -then : - printf "%s\n" "#define HAVE_GETATTRLIST 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "getauxval" "ac_cv_func_getauxval" -if test "x$ac_cv_func_getauxval" = xyes -then : - printf "%s\n" "#define HAVE_GETAUXVAL 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "getifaddrs" "ac_cv_func_getifaddrs" -if test "x$ac_cv_func_getifaddrs" = xyes -then : - printf "%s\n" "#define HAVE_GETIFADDRS 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "getrandom" "ac_cv_func_getrandom" -if test "x$ac_cv_func_getrandom" = xyes -then : - printf "%s\n" "#define HAVE_GETRANDOM 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "kqueue" "ac_cv_func_kqueue" -if test "x$ac_cv_func_kqueue" = xyes -then : - printf "%s\n" "#define HAVE_KQUEUE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" -if test "x$ac_cv_func_pipe2" = xyes -then : - printf "%s\n" "#define HAVE_PIPE2 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "port_create" "ac_cv_func_port_create" -if test "x$ac_cv_func_port_create" = xyes -then : - printf "%s\n" "#define HAVE_PORT_CREATE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "posix_fadvise" "ac_cv_func_posix_fadvise" -if test "x$ac_cv_func_posix_fadvise" = xyes -then : - printf "%s\n" "#define HAVE_POSIX_FADVISE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "posix_fallocate" "ac_cv_func_posix_fallocate" -if test "x$ac_cv_func_posix_fallocate" = xyes -then : - printf "%s\n" "#define HAVE_POSIX_FALLOCATE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "prctl" "ac_cv_func_prctl" -if test "x$ac_cv_func_prctl" = xyes -then : - printf "%s\n" "#define HAVE_PRCTL 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "sched_getcpu" "ac_cv_func_sched_getcpu" -if test "x$ac_cv_func_sched_getcpu" = xyes -then : - printf "%s\n" "#define HAVE_SCHED_GETCPU 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "sched_yield" "ac_cv_func_sched_yield" -if test "x$ac_cv_func_sched_yield" = xyes -then : - printf "%s\n" "#define HAVE_SCHED_YIELD 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "setproctitle" "ac_cv_func_setproctitle" -if test "x$ac_cv_func_setproctitle" = xyes -then : - printf "%s\n" "#define HAVE_SETPROCTITLE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "setprogname" "ac_cv_func_setprogname" -if test "x$ac_cv_func_setprogname" = xyes -then : - printf "%s\n" "#define HAVE_SETPROGNAME 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "sigprocmask" "ac_cv_func_sigprocmask" -if test "x$ac_cv_func_sigprocmask" = xyes -then : - printf "%s\n" "#define HAVE_SIGPROCMASK 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "sysinfo" "ac_cv_func_sysinfo" -if test "x$ac_cv_func_sysinfo" = xyes -then : - printf "%s\n" "#define HAVE_SYSINFO 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "tcdrain" "ac_cv_func_tcdrain" -if test "x$ac_cv_func_tcdrain" = xyes -then : - printf "%s\n" "#define HAVE_TCDRAIN 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "thr_kill2" "ac_cv_func_thr_kill2" -if test "x$ac_cv_func_thr_kill2" = xyes -then : - printf "%s\n" "#define HAVE_THR_KILL2 1" >>confdefs.h - -fi - -CFLAGS="$ac_save_CFLAGS" - -ac_save_LIBS=$LIBS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 -printf %s "checking for library containing clock_gettime... " >&6; } -if test ${ac_cv_search_clock_gettime+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char clock_gettime (void); -int -main (void) -{ -return clock_gettime (); - ; - return 0; -} -_ACEOF -for ac_lib in '' rt -do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO" -then : - ac_cv_search_clock_gettime=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext - if test ${ac_cv_search_clock_gettime+y} -then : - break -fi -done -if test ${ac_cv_search_clock_gettime+y} -then : - -else case e in #( - e) ac_cv_search_clock_gettime=no ;; -esac -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 -printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } -ac_res=$ac_cv_search_clock_gettime -if test "$ac_res" != no -then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h - - test "$ac_res" = "none required" || RT_LIBS="$ac_res" - -fi - -LIBS=$ac_save_LIBS - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sched_setaffinity" >&5 -printf %s "checking for sched_setaffinity... " >&6; } -if test ${wine_cv_have_sched_setaffinity+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -sched_setaffinity(0, 0, 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_have_sched_setaffinity=yes -else case e in #( - e) wine_cv_have_sched_setaffinity=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_have_sched_setaffinity" >&5 -printf "%s\n" "$wine_cv_have_sched_setaffinity" >&6; } -if test "$wine_cv_have_sched_setaffinity" = "yes" -then - -printf "%s\n" "#define HAVE_SCHED_SETAFFINITY 1" >>confdefs.h - -fi - - -ac_fn_c_check_type "$LINENO" "request_sense" "ac_cv_type_request_sense" "#include -" -if test "x$ac_cv_type_request_sense" = xyes -then : - -printf "%s\n" "#define HAVE_REQUEST_SENSE 1" >>confdefs.h - - -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we can use re-entrant gethostbyname_r Linux style" >&5 -printf %s "checking whether we can use re-entrant gethostbyname_r Linux style... " >&6; } -if test ${wine_cv_linux_gethostbyname_r_6+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ - - char *name=0; - struct hostent he; - struct hostent *result; - char *buf=0; - int bufsize=0; - int errnr; - char *addr=0; - int addrlen=0; - int addrtype=0; - gethostbyname_r(name,&he,buf,bufsize,&result,&errnr); - gethostbyaddr_r(addr, addrlen, addrtype,&he,buf,bufsize,&result,&errnr); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_linux_gethostbyname_r_6=yes -else case e in #( - e) wine_cv_linux_gethostbyname_r_6=no - ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_linux_gethostbyname_r_6" >&5 -printf "%s\n" "$wine_cv_linux_gethostbyname_r_6" >&6; } - if test "$wine_cv_linux_gethostbyname_r_6" = "yes" - then - -printf "%s\n" "#define HAVE_LINUX_GETHOSTBYNAME_R_6 1" >>confdefs.h - - fi - -ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_len" "ac_cv_member_struct_sockaddr_un_sun_len" "#include -#include -#ifdef HAVE_SYS_UN_H -# include -#endif -" -if test "x$ac_cv_member_struct_sockaddr_un_sun_len" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "scsireq_t" "cmd" "ac_cv_member_scsireq_t_cmd" "#include -#ifdef HAVE_SCSI_SG_H -#include -#endif -" -if test "x$ac_cv_member_scsireq_t_cmd" = xyes -then : - -printf "%s\n" "#define HAVE_SCSIREQ_T_CMD 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "sg_io_hdr_t" "interface_id" "ac_cv_member_sg_io_hdr_t_interface_id" "#include -#ifdef HAVE_SCSI_SG_H -#include -#endif -" -if test "x$ac_cv_member_sg_io_hdr_t_interface_id" = xyes -then : - -printf "%s\n" "#define HAVE_SG_IO_HDR_T_INTERFACE_ID 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "siginfo_t" "si_fd" "ac_cv_member_siginfo_t_si_fd" "#include -" -if test "x$ac_cv_member_siginfo_t_si_fd" = xyes -then : - -printf "%s\n" "#define HAVE_SIGINFO_T_SI_FD 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct mtget" "mt_blksiz" "ac_cv_member_struct_mtget_mt_blksiz" "#include -#ifdef HAVE_SYS_MTIO_H -#include -#endif -" -if test "x$ac_cv_member_struct_mtget_mt_blksiz" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_MTGET_MT_BLKSIZ 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct mtget" "mt_gstat" "ac_cv_member_struct_mtget_mt_gstat" "#include -#ifdef HAVE_SYS_MTIO_H -#include -#endif -" -if test "x$ac_cv_member_struct_mtget_mt_gstat" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_MTGET_MT_GSTAT 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct mtget" "mt_blkno" "ac_cv_member_struct_mtget_mt_blkno" "#include -#ifdef HAVE_SYS_MTIO_H -#include -#endif -" -if test "x$ac_cv_member_struct_mtget_mt_blkno" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_MTGET_MT_BLKNO 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim" "ac_cv_member_struct_stat_st_mtim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_mtim" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIM 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimespec" "ac_cv_member_struct_stat_st_mtimespec" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_mtimespec" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIMESPEC 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_ctim" "ac_cv_member_struct_stat_st_ctim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_ctim" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_CTIM 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_ctimespec" "ac_cv_member_struct_stat_st_ctimespec" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_ctimespec" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_CTIMESPEC 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_atim" "ac_cv_member_struct_stat_st_atim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_atim" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_ATIM 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_atimespec" "ac_cv_member_struct_stat_st_atimespec" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_atimespec" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_ATIMESPEC 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtime" "ac_cv_member_struct_stat_st_birthtime" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtime" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtim" "ac_cv_member_struct_stat_st_birthtim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtim" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BIRTHTIM 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtimespec" "ac_cv_member_struct_stat_st_birthtimespec" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtimespec" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "__st_birthtime" "ac_cv_member_struct_stat___st_birthtime" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat___st_birthtime" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT___ST_BIRTHTIME 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "__st_birthtim" "ac_cv_member_struct_stat___st_birthtim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat___st_birthtim" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT___ST_BIRTHTIM 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct sockaddr_in6" "sin6_scope_id" "ac_cv_member_struct_sockaddr_in6_sin6_scope_id" "#include -#ifdef HAVE_NETINET_IN_H -#include -#endif -" -if test "x$ac_cv_member_struct_sockaddr_in6_sin6_scope_id" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct __res_state" "_u._ext.nscount6" "ac_cv_member_struct___res_state__u__ext_nscount6" "#ifdef HAVE_RESOLV_H -#include -#endif -" -if test "x$ac_cv_member_struct___res_state__u__ext_nscount6" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct in6_pktinfo" "ipi6_addr" "ac_cv_member_struct_in6_pktinfo_ipi6_addr" "#ifdef HAVE_NETINET_IN_H -#include -#endif -" -if test "x$ac_cv_member_struct_in6_pktinfo_ipi6_addr" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_IN6_PKTINFO_IPI6_ADDR 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct ipstat" "ips_total" "ac_cv_member_struct_ipstat_ips_total" "#include -#ifdef HAVE_SYS_SOCKETVAR_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_ipstat_ips_total" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_IPSTAT_IPS_TOTAL 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct ip_stats" "ips_total" "ac_cv_member_struct_ip_stats_ips_total" "#ifdef HAVE_NETINET_IP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_ip_stats_ips_total" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_IP_STATS_IPS_TOTAL 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct ip6stat" "ip6s_total" "ac_cv_member_struct_ip6stat_ip6s_total" "#include -#ifdef HAVE_SYS_SOCKETVAR_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET6_IP6_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_ip6stat_ip6s_total" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_IP6STAT_IP6S_TOTAL 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct icmpstat" "icps_error" "ac_cv_member_struct_icmpstat_icps_error" "#include -#ifdef HAVE_SYS_SOCKETVAR_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IP_H -#include -#endif -#ifdef HAVE_NETINET_IP_ICMP_H -#include -#endif -#ifdef HAVE_NETINET_ICMP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_icmpstat_icps_error" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_ICMPSTAT_ICPS_ERROR 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct icmp6stat" "icp6s_error" "ac_cv_member_struct_icmp6stat_icp6s_error" "#include -#ifdef HAVE_SYS_SOCKETVAR_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_ICMP6_H -#include -#endif -" -if test "x$ac_cv_member_struct_icmp6stat_icp6s_error" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_ICMP6STAT_ICP6S_ERROR 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct tcpstat" "tcps_connattempt" "ac_cv_member_struct_tcpstat_tcps_connattempt" "#include -#ifdef HAVE_SYS_SOCKETVAR_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#ifdef HAVE_NETINET_TCP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_tcpstat_tcps_connattempt" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct tcp_stats" "tcps_connattempt" "ac_cv_member_struct_tcp_stats_tcps_connattempt" "#ifdef HAVE_NETINET_TCP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_tcp_stats_tcps_connattempt" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct udpstat" "udps_ipackets" "ac_cv_member_struct_udpstat_udps_ipackets" "#include -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IP_VAR_H -#include -#endif -#ifdef HAVE_NETINET_UDP_H -#include -#endif -#ifdef HAVE_NETINET_UDP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_udpstat_udps_ipackets" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_UDPSTAT_UDPS_IPACKETS 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_hwaddr" "ac_cv_member_struct_ifreq_ifr_hwaddr" "#include -#ifdef HAVE_NET_IF_H -# include -#endif -" -if test "x$ac_cv_member_struct_ifreq_ifr_hwaddr" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_IFREQ_IFR_HWADDR 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct sysinfo" "totalram" "ac_cv_member_struct_sysinfo_totalram" "#ifdef HAVE_SYS_SYSINFO_H -# include -#endif -" -if test "x$ac_cv_member_struct_sysinfo_totalram" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_SYSINFO_TOTALRAM 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct sysinfo" "mem_unit" "ac_cv_member_struct_sysinfo_mem_unit" "#ifdef HAVE_SYS_SYSINFO_H -# include -#endif -" -if test "x$ac_cv_member_struct_sysinfo_mem_unit" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_SYSINFO_MEM_UNIT 1" >>confdefs.h - - -fi - - -LIBS="$ac_save_LIBS" - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __builtin_popcount" >&5 -printf %s "checking for __builtin_popcount... " >&6; } -if test ${ac_cv_have___builtin_popcount+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -return __builtin_popcount(1) - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_have___builtin_popcount="yes" -else case e in #( - e) ac_cv_have___builtin_popcount="no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have___builtin_popcount" >&5 -printf "%s\n" "$ac_cv_have___builtin_popcount" >&6; } -if test "$ac_cv_have___builtin_popcount" = "yes" -then - -printf "%s\n" "#define HAVE___BUILTIN_POPCOUNT 1" >>confdefs.h - -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __clear_cache" >&5 -printf %s "checking for __clear_cache... " >&6; } -if test ${ac_cv_have___clear_cache+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -__clear_cache((void*)0, (void*)0); return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_have___clear_cache="yes" -else case e in #( - e) ac_cv_have___clear_cache="no" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have___clear_cache" >&5 -printf "%s\n" "$ac_cv_have___clear_cache" >&6; } -if test "$ac_cv_have___clear_cache" = "yes" -then - -printf "%s\n" "#define HAVE___CLEAR_CACHE 1" >>confdefs.h - -fi - - -case $host_cpu in - *i[3456789]86*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __i386__" >&5 -printf %s "checking whether we need to define __i386__... " >&6; } -if test ${ac_cv_cpp_def___i386__+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __i386__ -#error no -#endif -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_cpp_def___i386__=yes -else case e in #( - e) ac_cv_cpp_def___i386__=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___i386__" >&5 -printf "%s\n" "$ac_cv_cpp_def___i386__" >&6; } -if test "x$ac_cv_cpp_def___i386__" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -D__i386__" -fi ;; - *x86_64*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __x86_64__" >&5 -printf %s "checking whether we need to define __x86_64__... " >&6; } -if test ${ac_cv_cpp_def___x86_64__+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __x86_64__ -#error no -#endif -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_cpp_def___x86_64__=yes -else case e in #( - e) ac_cv_cpp_def___x86_64__=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___x86_64__" >&5 -printf "%s\n" "$ac_cv_cpp_def___x86_64__" >&6; } -if test "x$ac_cv_cpp_def___x86_64__" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -D__x86_64__" -fi ;; - *powerpc64*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __powerpc64__" >&5 -printf %s "checking whether we need to define __powerpc64__... " >&6; } -if test ${ac_cv_cpp_def___powerpc64__+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __powerpc64__ -#error no -#endif -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_cpp_def___powerpc64__=yes -else case e in #( - e) ac_cv_cpp_def___powerpc64__=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___powerpc64__" >&5 -printf "%s\n" "$ac_cv_cpp_def___powerpc64__" >&6; } -if test "x$ac_cv_cpp_def___powerpc64__" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -D__powerpc64__" -fi ;; - *aarch64*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __aarch64__" >&5 -printf %s "checking whether we need to define __aarch64__... " >&6; } -if test ${ac_cv_cpp_def___aarch64__+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __aarch64__ -#error no -#endif -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_cpp_def___aarch64__=yes -else case e in #( - e) ac_cv_cpp_def___aarch64__=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___aarch64__" >&5 -printf "%s\n" "$ac_cv_cpp_def___aarch64__" >&6; } -if test "x$ac_cv_cpp_def___aarch64__" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -D__aarch64__" -fi ;; - *arm*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __arm__" >&5 -printf %s "checking whether we need to define __arm__... " >&6; } -if test ${ac_cv_cpp_def___arm__+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __arm__ -#error no -#endif -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_cpp_def___arm__=yes -else case e in #( - e) ac_cv_cpp_def___arm__=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___arm__" >&5 -printf "%s\n" "$ac_cv_cpp_def___arm__" >&6; } -if test "x$ac_cv_cpp_def___arm__" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -D__arm__" -fi ;; -esac - - -enable_win16=${enable_win16:-i386} -enable_vcruntime140_1=${enable_vcruntime140_1:-x86_64,arm64ec} - -if test -n "$PE_ARCHS" -then - enable_wow64=${enable_wow64:-aarch64,x86_64} - enable_wow64win=${enable_wow64win:-aarch64,x86_64} - enable_wow64cpu=${enable_wow64cpu:-x86_64} - enable_xtajit64=${enable_xtajit64:-arm64ec} -else - enable_wow64=${enable_wow64:-no} - enable_wow64win=${enable_wow64win:-no} - enable_wow64cpu=${enable_wow64cpu:-no} - enable_xtajit64=${enable_xtajit64:-no} -fi - -enable_cmd=${enable_cmd:-yes} -enable_dllhost=${enable_dllhost:-yes} -enable_dpnsvr=${enable_dpnsvr:-i386,x86_64,arm64ec} -enable_dxdiag=${enable_dxdiag:-yes} -enable_msiexec=${enable_msiexec:-yes} -enable_netsh=${enable_netsh:-yes} -enable_regsvr32=${enable_regsvr32:-yes} -enable_rundll32=${enable_rundll32:-yes} - -enable_winetest=${enable_winetest:-$enable_tests} - - - - - -ac_config_commands="$ac_config_commands include/stamp-h" - -printf %s "creating Makefile rules..." >&6 - -makedep_flags=" -C" -test "x$enable_silent_rules" = xyes && makedep_flags="$makedep_flags -S" - -wine_srcdir= -test "$srcdir" = . || wine_srcdir="$srcdir/" - -ac_config_links="$ac_config_links wine:tools/winewrapper" -wine_fn_config_symlink wine -if test "$wine_binary" = wine64 -o -n "$with_wine64"; then -ac_config_links="$ac_config_links wine64:tools/winewrapper" -wine_fn_config_symlink wine64 -fi - -wine_fn_config_makefile dlls/acledit enable_acledit -wine_fn_config_makefile dlls/aclui enable_aclui -wine_fn_config_makefile dlls/activeds.tlb enable_activeds_tlb -wine_fn_config_makefile dlls/activeds enable_activeds -wine_fn_config_makefile dlls/activeds/tests enable_tests -wine_fn_config_makefile dlls/actxprxy enable_actxprxy -wine_fn_config_makefile dlls/adsldp enable_adsldp -wine_fn_config_makefile dlls/adsldp/tests enable_tests -wine_fn_config_makefile dlls/adsldpc enable_adsldpc -wine_fn_config_makefile dlls/advapi32 enable_advapi32 -wine_fn_config_makefile dlls/advapi32/tests enable_tests -wine_fn_config_makefile dlls/advpack enable_advpack -wine_fn_config_makefile dlls/advpack/tests enable_tests -wine_fn_config_makefile dlls/amsi enable_amsi -wine_fn_config_makefile dlls/amstream enable_amstream -wine_fn_config_makefile dlls/amstream/tests enable_tests -wine_fn_config_makefile dlls/apisetschema enable_apisetschema -wine_fn_config_makefile dlls/apphelp enable_apphelp -wine_fn_config_makefile dlls/apphelp/tests enable_tests -wine_fn_config_makefile dlls/appwiz.cpl enable_appwiz_cpl -wine_fn_config_makefile dlls/appxdeploymentclient enable_appxdeploymentclient -wine_fn_config_makefile dlls/atl enable_atl -wine_fn_config_makefile dlls/atl/tests enable_tests -wine_fn_config_makefile dlls/atl100 enable_atl100 -wine_fn_config_makefile dlls/atl100/tests enable_tests -wine_fn_config_makefile dlls/atl110 enable_atl110 -wine_fn_config_makefile dlls/atl110/tests enable_tests -wine_fn_config_makefile dlls/atl80 enable_atl80 -wine_fn_config_makefile dlls/atl80/tests enable_tests -wine_fn_config_makefile dlls/atl90 enable_atl90 -wine_fn_config_makefile dlls/atlthunk enable_atlthunk -wine_fn_config_makefile dlls/atlthunk/tests enable_tests -wine_fn_config_makefile dlls/atmlib enable_atmlib -wine_fn_config_makefile dlls/authz enable_authz -wine_fn_config_makefile dlls/avicap32 enable_avicap32 -wine_fn_config_makefile dlls/avifil32 enable_avifil32 -wine_fn_config_makefile dlls/avifil32/tests enable_tests -wine_fn_config_makefile dlls/avifile.dll16 enable_win16 -wine_fn_config_makefile dlls/avrt enable_avrt -wine_fn_config_makefile dlls/bcp47langs enable_bcp47langs -wine_fn_config_makefile dlls/bcrypt enable_bcrypt -wine_fn_config_makefile dlls/bcrypt/tests enable_tests -wine_fn_config_makefile dlls/bcryptprimitives enable_bcryptprimitives -wine_fn_config_makefile dlls/bluetoothapis enable_bluetoothapis -wine_fn_config_makefile dlls/bluetoothapis/tests enable_tests -wine_fn_config_makefile dlls/browseui enable_browseui -wine_fn_config_makefile dlls/browseui/tests enable_tests -wine_fn_config_makefile dlls/bthprops.cpl enable_bthprops_cpl -wine_fn_config_makefile dlls/cabinet enable_cabinet -wine_fn_config_makefile dlls/cabinet/tests enable_tests -wine_fn_config_makefile dlls/capi2032 enable_capi2032 -wine_fn_config_makefile dlls/cards enable_cards -wine_fn_config_makefile dlls/cdosys enable_cdosys -wine_fn_config_makefile dlls/cfgmgr32 enable_cfgmgr32 -wine_fn_config_makefile dlls/cfgmgr32/tests enable_tests -wine_fn_config_makefile dlls/clusapi enable_clusapi -wine_fn_config_makefile dlls/cng.sys enable_cng_sys -wine_fn_config_makefile dlls/colorcnv enable_colorcnv -wine_fn_config_makefile dlls/combase enable_combase -wine_fn_config_makefile dlls/combase/tests enable_tests -wine_fn_config_makefile dlls/comcat enable_comcat -wine_fn_config_makefile dlls/comcat/tests enable_tests -wine_fn_config_makefile dlls/comctl32 enable_comctl32 -wine_fn_config_makefile dlls/comctl32/tests enable_tests -wine_fn_config_makefile dlls/comdlg32 enable_comdlg32 -wine_fn_config_makefile dlls/comdlg32/tests enable_tests -wine_fn_config_makefile dlls/coml2 enable_coml2 -wine_fn_config_makefile dlls/comm.drv16 enable_win16 -wine_fn_config_makefile dlls/commdlg.dll16 enable_win16 -wine_fn_config_makefile dlls/compobj.dll16 enable_win16 -wine_fn_config_makefile dlls/compstui enable_compstui -wine_fn_config_makefile dlls/compstui/tests enable_tests -wine_fn_config_makefile dlls/comsvcs enable_comsvcs -wine_fn_config_makefile dlls/comsvcs/tests enable_tests -wine_fn_config_makefile dlls/concrt140 enable_concrt140 -wine_fn_config_makefile dlls/concrt140/tests enable_tests -wine_fn_config_makefile dlls/connect enable_connect -wine_fn_config_makefile dlls/coremessaging enable_coremessaging -wine_fn_config_makefile dlls/credui enable_credui -wine_fn_config_makefile dlls/credui/tests enable_tests -wine_fn_config_makefile dlls/crtdll enable_crtdll -wine_fn_config_makefile dlls/crypt32 enable_crypt32 -wine_fn_config_makefile dlls/crypt32/tests enable_tests -wine_fn_config_makefile dlls/cryptdlg enable_cryptdlg -wine_fn_config_makefile dlls/cryptdll enable_cryptdll -wine_fn_config_makefile dlls/cryptext enable_cryptext -wine_fn_config_makefile dlls/cryptnet enable_cryptnet -wine_fn_config_makefile dlls/cryptnet/tests enable_tests -wine_fn_config_makefile dlls/cryptowinrt enable_cryptowinrt -wine_fn_config_makefile dlls/cryptowinrt/tests enable_tests -wine_fn_config_makefile dlls/cryptsp enable_cryptsp -wine_fn_config_makefile dlls/cryptui enable_cryptui -wine_fn_config_makefile dlls/cryptui/tests enable_tests -wine_fn_config_makefile dlls/ctapi32 enable_ctapi32 -wine_fn_config_makefile dlls/ctl3d.dll16 enable_win16 -wine_fn_config_makefile dlls/ctl3d32 enable_ctl3d32 -wine_fn_config_makefile dlls/ctl3dv2.dll16 enable_win16 -wine_fn_config_makefile dlls/d2d1 enable_d2d1 -wine_fn_config_makefile dlls/d2d1/tests enable_tests -wine_fn_config_makefile dlls/d3d10 enable_d3d10 -wine_fn_config_makefile dlls/d3d10/tests enable_tests -wine_fn_config_makefile dlls/d3d10_1 enable_d3d10_1 -wine_fn_config_makefile dlls/d3d10_1/tests enable_tests -wine_fn_config_makefile dlls/d3d10core enable_d3d10core -wine_fn_config_makefile dlls/d3d10core/tests enable_tests -wine_fn_config_makefile dlls/d3d11 enable_d3d11 -wine_fn_config_makefile dlls/d3d11/tests enable_tests -wine_fn_config_makefile dlls/d3d12 enable_d3d12 -wine_fn_config_makefile dlls/d3d12/tests enable_tests -wine_fn_config_makefile dlls/d3d12core enable_d3d12core -wine_fn_config_makefile dlls/d3d8 enable_d3d8 -wine_fn_config_makefile dlls/d3d8/tests enable_tests -wine_fn_config_makefile dlls/d3d8thk enable_d3d8thk -wine_fn_config_makefile dlls/d3d9 enable_d3d9 -wine_fn_config_makefile dlls/d3d9/tests enable_tests -wine_fn_config_makefile dlls/d3dcompiler_33 enable_d3dcompiler_33 -wine_fn_config_makefile dlls/d3dcompiler_34 enable_d3dcompiler_34 -wine_fn_config_makefile dlls/d3dcompiler_35 enable_d3dcompiler_35 -wine_fn_config_makefile dlls/d3dcompiler_36 enable_d3dcompiler_36 -wine_fn_config_makefile dlls/d3dcompiler_37 enable_d3dcompiler_37 -wine_fn_config_makefile dlls/d3dcompiler_38 enable_d3dcompiler_38 -wine_fn_config_makefile dlls/d3dcompiler_39 enable_d3dcompiler_39 -wine_fn_config_makefile dlls/d3dcompiler_40 enable_d3dcompiler_40 -wine_fn_config_makefile dlls/d3dcompiler_41 enable_d3dcompiler_41 -wine_fn_config_makefile dlls/d3dcompiler_42 enable_d3dcompiler_42 -wine_fn_config_makefile dlls/d3dcompiler_43 enable_d3dcompiler_43 -wine_fn_config_makefile dlls/d3dcompiler_43/tests enable_tests -wine_fn_config_makefile dlls/d3dcompiler_46 enable_d3dcompiler_46 -wine_fn_config_makefile dlls/d3dcompiler_46/tests enable_tests -wine_fn_config_makefile dlls/d3dcompiler_47 enable_d3dcompiler_47 -wine_fn_config_makefile dlls/d3dcompiler_47/tests enable_tests -wine_fn_config_makefile dlls/d3dim enable_d3dim -wine_fn_config_makefile dlls/d3dim700 enable_d3dim700 -wine_fn_config_makefile dlls/d3drm enable_d3drm -wine_fn_config_makefile dlls/d3drm/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_33 enable_d3dx10_33 -wine_fn_config_makefile dlls/d3dx10_34 enable_d3dx10_34 -wine_fn_config_makefile dlls/d3dx10_34/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_35 enable_d3dx10_35 -wine_fn_config_makefile dlls/d3dx10_35/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_36 enable_d3dx10_36 -wine_fn_config_makefile dlls/d3dx10_36/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_37 enable_d3dx10_37 -wine_fn_config_makefile dlls/d3dx10_37/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_38 enable_d3dx10_38 -wine_fn_config_makefile dlls/d3dx10_38/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_39 enable_d3dx10_39 -wine_fn_config_makefile dlls/d3dx10_39/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_40 enable_d3dx10_40 -wine_fn_config_makefile dlls/d3dx10_40/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_41 enable_d3dx10_41 -wine_fn_config_makefile dlls/d3dx10_41/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_42 enable_d3dx10_42 -wine_fn_config_makefile dlls/d3dx10_42/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_43 enable_d3dx10_43 -wine_fn_config_makefile dlls/d3dx10_43/tests enable_tests -wine_fn_config_makefile dlls/d3dx11_42 enable_d3dx11_42 -wine_fn_config_makefile dlls/d3dx11_42/tests enable_tests -wine_fn_config_makefile dlls/d3dx11_43 enable_d3dx11_43 -wine_fn_config_makefile dlls/d3dx11_43/tests enable_tests -wine_fn_config_makefile dlls/d3dx9_24 enable_d3dx9_24 -wine_fn_config_makefile dlls/d3dx9_25 enable_d3dx9_25 -wine_fn_config_makefile dlls/d3dx9_26 enable_d3dx9_26 -wine_fn_config_makefile dlls/d3dx9_27 enable_d3dx9_27 -wine_fn_config_makefile dlls/d3dx9_28 enable_d3dx9_28 -wine_fn_config_makefile dlls/d3dx9_29 enable_d3dx9_29 -wine_fn_config_makefile dlls/d3dx9_30 enable_d3dx9_30 -wine_fn_config_makefile dlls/d3dx9_31 enable_d3dx9_31 -wine_fn_config_makefile dlls/d3dx9_32 enable_d3dx9_32 -wine_fn_config_makefile dlls/d3dx9_33 enable_d3dx9_33 -wine_fn_config_makefile dlls/d3dx9_34 enable_d3dx9_34 -wine_fn_config_makefile dlls/d3dx9_35 enable_d3dx9_35 -wine_fn_config_makefile dlls/d3dx9_36 enable_d3dx9_36 -wine_fn_config_makefile dlls/d3dx9_36/tests enable_tests -wine_fn_config_makefile dlls/d3dx9_37 enable_d3dx9_37 -wine_fn_config_makefile dlls/d3dx9_38 enable_d3dx9_38 -wine_fn_config_makefile dlls/d3dx9_39 enable_d3dx9_39 -wine_fn_config_makefile dlls/d3dx9_40 enable_d3dx9_40 -wine_fn_config_makefile dlls/d3dx9_41 enable_d3dx9_41 -wine_fn_config_makefile dlls/d3dx9_42 enable_d3dx9_42 -wine_fn_config_makefile dlls/d3dx9_43 enable_d3dx9_43 -wine_fn_config_makefile dlls/d3dx9_43/tests enable_tests -wine_fn_config_makefile dlls/d3dxof enable_d3dxof -wine_fn_config_makefile dlls/d3dxof/tests enable_tests -wine_fn_config_makefile dlls/dataexchange enable_dataexchange -wine_fn_config_makefile dlls/dataexchange/tests enable_tests -wine_fn_config_makefile dlls/davclnt enable_davclnt -wine_fn_config_makefile dlls/dbgeng enable_dbgeng -wine_fn_config_makefile dlls/dbgeng/tests enable_tests -wine_fn_config_makefile dlls/dbghelp enable_dbghelp -wine_fn_config_makefile dlls/dbghelp/tests enable_tests -wine_fn_config_makefile dlls/dciman32 enable_dciman32 -wine_fn_config_makefile dlls/dcomp enable_dcomp -wine_fn_config_makefile dlls/ddeml.dll16 enable_win16 -wine_fn_config_makefile dlls/ddraw enable_ddraw -wine_fn_config_makefile dlls/ddraw/tests enable_tests -wine_fn_config_makefile dlls/ddrawex enable_ddrawex -wine_fn_config_makefile dlls/ddrawex/tests enable_tests -wine_fn_config_makefile dlls/desk.cpl enable_desk_cpl -wine_fn_config_makefile dlls/devenum enable_devenum -wine_fn_config_makefile dlls/devenum/tests enable_tests -wine_fn_config_makefile dlls/dhcpcsvc enable_dhcpcsvc -wine_fn_config_makefile dlls/dhcpcsvc/tests enable_tests -wine_fn_config_makefile dlls/dhcpcsvc6 enable_dhcpcsvc6 -wine_fn_config_makefile dlls/dhtmled.ocx enable_dhtmled_ocx -wine_fn_config_makefile dlls/diasymreader enable_diasymreader -wine_fn_config_makefile dlls/difxapi enable_difxapi -wine_fn_config_makefile dlls/dinput enable_dinput -wine_fn_config_makefile dlls/dinput/tests enable_tests -wine_fn_config_makefile dlls/dinput8 enable_dinput8 -wine_fn_config_makefile dlls/directmanipulation enable_directmanipulation -wine_fn_config_makefile dlls/directmanipulation/tests enable_tests -wine_fn_config_makefile dlls/dispdib.dll16 enable_win16 -wine_fn_config_makefile dlls/dispex enable_dispex -wine_fn_config_makefile dlls/dispex/tests enable_tests -wine_fn_config_makefile dlls/display.drv16 enable_win16 -wine_fn_config_makefile dlls/dmband enable_dmband -wine_fn_config_makefile dlls/dmband/tests enable_tests -wine_fn_config_makefile dlls/dmcompos enable_dmcompos -wine_fn_config_makefile dlls/dmcompos/tests enable_tests -wine_fn_config_makefile dlls/dmime enable_dmime -wine_fn_config_makefile dlls/dmime/tests enable_tests -wine_fn_config_makefile dlls/dmloader enable_dmloader -wine_fn_config_makefile dlls/dmloader/tests enable_tests -wine_fn_config_makefile dlls/dmscript enable_dmscript -wine_fn_config_makefile dlls/dmscript/tests enable_tests -wine_fn_config_makefile dlls/dmstyle enable_dmstyle -wine_fn_config_makefile dlls/dmstyle/tests enable_tests -wine_fn_config_makefile dlls/dmsynth enable_dmsynth -wine_fn_config_makefile dlls/dmsynth/tests enable_tests -wine_fn_config_makefile dlls/dmusic enable_dmusic -wine_fn_config_makefile dlls/dmusic/tests enable_tests -wine_fn_config_makefile dlls/dmusic32 enable_dmusic32 -wine_fn_config_makefile dlls/dnsapi enable_dnsapi -wine_fn_config_makefile dlls/dnsapi/tests enable_tests -wine_fn_config_makefile dlls/dplay enable_dplay -wine_fn_config_makefile dlls/dplayx enable_dplayx -wine_fn_config_makefile dlls/dplayx/tests enable_tests -wine_fn_config_makefile dlls/dpnaddr enable_dpnaddr -wine_fn_config_makefile dlls/dpnet enable_dpnet -wine_fn_config_makefile dlls/dpnet/tests enable_tests -wine_fn_config_makefile dlls/dpnhpast enable_dpnhpast -wine_fn_config_makefile dlls/dpnhupnp enable_dpnhupnp -wine_fn_config_makefile dlls/dpnlobby enable_dpnlobby -wine_fn_config_makefile dlls/dpvoice enable_dpvoice -wine_fn_config_makefile dlls/dpvoice/tests enable_tests -wine_fn_config_makefile dlls/dpwsockx enable_dpwsockx -wine_fn_config_makefile dlls/drmclien enable_drmclien -wine_fn_config_makefile dlls/dsdmo enable_dsdmo -wine_fn_config_makefile dlls/dsdmo/tests enable_tests -wine_fn_config_makefile dlls/dsound enable_dsound -wine_fn_config_makefile dlls/dsound/tests enable_tests -wine_fn_config_makefile dlls/dsquery enable_dsquery -wine_fn_config_makefile dlls/dssenh enable_dssenh -wine_fn_config_makefile dlls/dssenh/tests enable_tests -wine_fn_config_makefile dlls/dsuiext enable_dsuiext -wine_fn_config_makefile dlls/dswave enable_dswave -wine_fn_config_makefile dlls/dswave/tests enable_tests -wine_fn_config_makefile dlls/dwmapi enable_dwmapi -wine_fn_config_makefile dlls/dwmapi/tests enable_tests -wine_fn_config_makefile dlls/dwrite enable_dwrite -wine_fn_config_makefile dlls/dwrite/tests enable_tests -wine_fn_config_makefile dlls/dx8vb enable_dx8vb -wine_fn_config_makefile dlls/dxcore enable_dxcore -wine_fn_config_makefile dlls/dxdiagn enable_dxdiagn -wine_fn_config_makefile dlls/dxdiagn/tests enable_tests -wine_fn_config_makefile dlls/dxgi enable_dxgi -wine_fn_config_makefile dlls/dxgi/tests enable_tests -wine_fn_config_makefile dlls/dxtrans enable_dxtrans -wine_fn_config_makefile dlls/dxva2 enable_dxva2 -wine_fn_config_makefile dlls/dxva2/tests enable_tests -wine_fn_config_makefile dlls/esent enable_esent -wine_fn_config_makefile dlls/evr enable_evr -wine_fn_config_makefile dlls/evr/tests enable_tests -wine_fn_config_makefile dlls/explorerframe enable_explorerframe -wine_fn_config_makefile dlls/explorerframe/tests enable_tests -wine_fn_config_makefile dlls/faultrep enable_faultrep -wine_fn_config_makefile dlls/faultrep/tests enable_tests -wine_fn_config_makefile dlls/feclient enable_feclient -wine_fn_config_makefile dlls/fltlib enable_fltlib -wine_fn_config_makefile dlls/fltmgr.sys enable_fltmgr_sys -wine_fn_config_makefile dlls/fntcache enable_fntcache -wine_fn_config_makefile dlls/fontsub enable_fontsub -wine_fn_config_makefile dlls/fusion enable_fusion -wine_fn_config_makefile dlls/fusion/tests enable_tests -wine_fn_config_makefile dlls/fwpuclnt enable_fwpuclnt -wine_fn_config_makefile dlls/gameux enable_gameux -wine_fn_config_makefile dlls/gameux/tests enable_tests -wine_fn_config_makefile dlls/gamingtcui enable_gamingtcui -wine_fn_config_makefile dlls/gdi.exe16 enable_win16 -wine_fn_config_makefile dlls/gdi32 enable_gdi32 -wine_fn_config_makefile dlls/gdi32/tests enable_tests -wine_fn_config_makefile dlls/gdiplus enable_gdiplus -wine_fn_config_makefile dlls/gdiplus/tests enable_tests -wine_fn_config_makefile dlls/geolocation enable_geolocation -wine_fn_config_makefile dlls/geolocation/tests enable_tests -wine_fn_config_makefile dlls/glu32 enable_glu32 -wine_fn_config_makefile dlls/glu32/tests enable_tests -wine_fn_config_makefile dlls/gphoto2.ds enable_gphoto2_ds -wine_fn_config_makefile dlls/gpkcsp enable_gpkcsp -wine_fn_config_makefile dlls/graphicscapture enable_graphicscapture -wine_fn_config_makefile dlls/graphicscapture/tests enable_tests -wine_fn_config_makefile dlls/hal enable_hal -wine_fn_config_makefile dlls/hhctrl.ocx enable_hhctrl_ocx -wine_fn_config_makefile dlls/hid enable_hid -wine_fn_config_makefile dlls/hid/tests enable_tests -wine_fn_config_makefile dlls/hidclass.sys enable_hidclass_sys -wine_fn_config_makefile dlls/hidparse.sys enable_hidparse_sys -wine_fn_config_makefile dlls/hlink enable_hlink -wine_fn_config_makefile dlls/hlink/tests enable_tests -wine_fn_config_makefile dlls/hnetcfg enable_hnetcfg -wine_fn_config_makefile dlls/hnetcfg/tests enable_tests -wine_fn_config_makefile dlls/hrtfapo enable_hrtfapo -wine_fn_config_makefile dlls/http.sys enable_http_sys -wine_fn_config_makefile dlls/httpapi enable_httpapi -wine_fn_config_makefile dlls/httpapi/tests enable_tests -wine_fn_config_makefile dlls/hvsimanagementapi enable_hvsimanagementapi -wine_fn_config_makefile dlls/hvsimanagementapi/tests enable_tests -wine_fn_config_makefile dlls/ia2comproxy enable_ia2comproxy -wine_fn_config_makefile dlls/iccvid enable_iccvid -wine_fn_config_makefile dlls/icmp enable_icmp -wine_fn_config_makefile dlls/icmui enable_icmui -wine_fn_config_makefile dlls/icmui/tests enable_tests -wine_fn_config_makefile dlls/ieframe enable_ieframe -wine_fn_config_makefile dlls/ieframe/tests enable_tests -wine_fn_config_makefile dlls/ieproxy enable_ieproxy -wine_fn_config_makefile dlls/iertutil enable_iertutil -wine_fn_config_makefile dlls/iertutil/tests enable_tests -wine_fn_config_makefile dlls/ifsmgr.vxd enable_win16 -wine_fn_config_makefile dlls/imaadp32.acm enable_imaadp32_acm -wine_fn_config_makefile dlls/imagehlp enable_imagehlp -wine_fn_config_makefile dlls/imagehlp/tests enable_tests -wine_fn_config_makefile dlls/imm.dll16 enable_win16 -wine_fn_config_makefile dlls/imm32 enable_imm32 -wine_fn_config_makefile dlls/imm32/tests enable_tests -wine_fn_config_makefile dlls/inetcomm enable_inetcomm -wine_fn_config_makefile dlls/inetcomm/tests enable_tests -wine_fn_config_makefile dlls/inetcpl.cpl enable_inetcpl_cpl -wine_fn_config_makefile dlls/inetmib1 enable_inetmib1 -wine_fn_config_makefile dlls/inetmib1/tests enable_tests -wine_fn_config_makefile dlls/infosoft enable_infosoft -wine_fn_config_makefile dlls/infosoft/tests enable_tests -wine_fn_config_makefile dlls/initpki enable_initpki -wine_fn_config_makefile dlls/inkobj enable_inkobj -wine_fn_config_makefile dlls/inseng enable_inseng -wine_fn_config_makefile dlls/iphlpapi enable_iphlpapi -wine_fn_config_makefile dlls/iphlpapi/tests enable_tests -wine_fn_config_makefile dlls/iprop enable_iprop -wine_fn_config_makefile dlls/ir50_32 enable_ir50_32 -wine_fn_config_makefile dlls/irprops.cpl enable_irprops_cpl -wine_fn_config_makefile dlls/itircl enable_itircl -wine_fn_config_makefile dlls/itss enable_itss -wine_fn_config_makefile dlls/itss/tests enable_tests -wine_fn_config_makefile dlls/joy.cpl enable_joy_cpl -wine_fn_config_makefile dlls/jscript enable_jscript -wine_fn_config_makefile dlls/jscript/tests enable_tests -wine_fn_config_makefile dlls/jsproxy enable_jsproxy -wine_fn_config_makefile dlls/jsproxy/tests enable_tests -wine_fn_config_makefile dlls/kerberos enable_kerberos -wine_fn_config_makefile dlls/kernel32 enable_kernel32 -wine_fn_config_makefile dlls/kernel32/tests enable_tests -wine_fn_config_makefile dlls/kernelbase enable_kernelbase -wine_fn_config_makefile dlls/kernelbase/tests enable_tests -wine_fn_config_makefile dlls/keyboard.drv16 enable_win16 -wine_fn_config_makefile dlls/krnl386.exe16 enable_win16 -wine_fn_config_makefile dlls/ksecdd.sys enable_ksecdd_sys -wine_fn_config_makefile dlls/ksproxy.ax enable_ksproxy_ax -wine_fn_config_makefile dlls/ksuser enable_ksuser -wine_fn_config_makefile dlls/ktmw32 enable_ktmw32 -wine_fn_config_makefile dlls/l3codeca.acm enable_l3codeca_acm -wine_fn_config_makefile dlls/l3codecx.ax enable_l3codecx_ax -wine_fn_config_makefile dlls/light.msstyles enable_light_msstyles -wine_fn_config_makefile dlls/loadperf enable_loadperf -wine_fn_config_makefile dlls/localspl enable_localspl -wine_fn_config_makefile dlls/localspl/tests enable_tests -wine_fn_config_makefile dlls/localui enable_localui -wine_fn_config_makefile dlls/localui/tests enable_tests -wine_fn_config_makefile dlls/lz32 enable_lz32 -wine_fn_config_makefile dlls/lz32/tests enable_tests -wine_fn_config_makefile dlls/lzexpand.dll16 enable_win16 -wine_fn_config_makefile dlls/magnification enable_magnification -wine_fn_config_makefile dlls/mapi32 enable_mapi32 -wine_fn_config_makefile dlls/mapi32/tests enable_tests -wine_fn_config_makefile dlls/mapistub enable_mapistub -wine_fn_config_makefile dlls/mciavi32 enable_mciavi32 -wine_fn_config_makefile dlls/mcicda enable_mcicda -wine_fn_config_makefile dlls/mciqtz32 enable_mciqtz32 -wine_fn_config_makefile dlls/mciseq enable_mciseq -wine_fn_config_makefile dlls/mciwave enable_mciwave -wine_fn_config_makefile dlls/mf enable_mf -wine_fn_config_makefile dlls/mf/tests enable_tests -wine_fn_config_makefile dlls/mf3216 enable_mf3216 -wine_fn_config_makefile dlls/mfasfsrcsnk enable_mfasfsrcsnk -wine_fn_config_makefile dlls/mferror enable_mferror -wine_fn_config_makefile dlls/mfh264enc enable_mfh264enc -wine_fn_config_makefile dlls/mfmediaengine enable_mfmediaengine -wine_fn_config_makefile dlls/mfmediaengine/tests enable_tests -wine_fn_config_makefile dlls/mfmp4srcsnk enable_mfmp4srcsnk -wine_fn_config_makefile dlls/mfplat enable_mfplat -wine_fn_config_makefile dlls/mfplat/tests enable_tests -wine_fn_config_makefile dlls/mfplay enable_mfplay -wine_fn_config_makefile dlls/mfplay/tests enable_tests -wine_fn_config_makefile dlls/mfreadwrite enable_mfreadwrite -wine_fn_config_makefile dlls/mfreadwrite/tests enable_tests -wine_fn_config_makefile dlls/mfsrcsnk enable_mfsrcsnk -wine_fn_config_makefile dlls/mfsrcsnk/tests enable_tests -wine_fn_config_makefile dlls/mgmtapi enable_mgmtapi -wine_fn_config_makefile dlls/midimap enable_midimap -wine_fn_config_makefile dlls/mlang enable_mlang -wine_fn_config_makefile dlls/mlang/tests enable_tests -wine_fn_config_makefile dlls/mmcndmgr enable_mmcndmgr -wine_fn_config_makefile dlls/mmcndmgr/tests enable_tests -wine_fn_config_makefile dlls/mmdevapi enable_mmdevapi -wine_fn_config_makefile dlls/mmdevapi/tests enable_tests -wine_fn_config_makefile dlls/mmdevldr.vxd enable_win16 -wine_fn_config_makefile dlls/mmsystem.dll16 enable_win16 -wine_fn_config_makefile dlls/monodebg.vxd enable_win16 -wine_fn_config_makefile dlls/mouhid.sys enable_mouhid_sys -wine_fn_config_makefile dlls/mountmgr.sys enable_mountmgr_sys -wine_fn_config_makefile dlls/mouse.drv16 enable_win16 -wine_fn_config_makefile dlls/mp3dmod enable_mp3dmod -wine_fn_config_makefile dlls/mp3dmod/tests enable_tests -wine_fn_config_makefile dlls/mpr enable_mpr -wine_fn_config_makefile dlls/mpr/tests enable_tests -wine_fn_config_makefile dlls/mprapi enable_mprapi -wine_fn_config_makefile dlls/msacm.dll16 enable_win16 -wine_fn_config_makefile dlls/msacm32.drv enable_msacm32_drv -wine_fn_config_makefile dlls/msacm32 enable_msacm32 -wine_fn_config_makefile dlls/msacm32/tests enable_tests -wine_fn_config_makefile dlls/msado15 enable_msado15 -wine_fn_config_makefile dlls/msado15/tests enable_tests -wine_fn_config_makefile dlls/msadp32.acm enable_msadp32_acm -wine_fn_config_makefile dlls/msasn1 enable_msasn1 -wine_fn_config_makefile dlls/msasn1/tests enable_tests -wine_fn_config_makefile dlls/msauddecmft enable_msauddecmft -wine_fn_config_makefile dlls/mscat32 enable_mscat32 -wine_fn_config_makefile dlls/mscms enable_mscms -wine_fn_config_makefile dlls/mscms/tests enable_tests -wine_fn_config_makefile dlls/mscoree enable_mscoree -wine_fn_config_makefile dlls/mscoree/tests enable_tests -wine_fn_config_makefile dlls/mscorwks enable_mscorwks -wine_fn_config_makefile dlls/msctf enable_msctf -wine_fn_config_makefile dlls/msctf/tests enable_tests -wine_fn_config_makefile dlls/msctfmonitor enable_msctfmonitor -wine_fn_config_makefile dlls/msctfp enable_msctfp -wine_fn_config_makefile dlls/msdaps enable_msdaps -wine_fn_config_makefile dlls/msdasql enable_msdasql -wine_fn_config_makefile dlls/msdasql/tests enable_tests -wine_fn_config_makefile dlls/msdelta enable_msdelta -wine_fn_config_makefile dlls/msdmo enable_msdmo -wine_fn_config_makefile dlls/msdmo/tests enable_tests -wine_fn_config_makefile dlls/msdrm enable_msdrm -wine_fn_config_makefile dlls/msftedit enable_msftedit -wine_fn_config_makefile dlls/msftedit/tests enable_tests -wine_fn_config_makefile dlls/msg711.acm enable_msg711_acm -wine_fn_config_makefile dlls/msgsm32.acm enable_msgsm32_acm -wine_fn_config_makefile dlls/mshtml.tlb enable_mshtml_tlb -wine_fn_config_makefile dlls/mshtml enable_mshtml -wine_fn_config_makefile dlls/mshtml/tests enable_tests -wine_fn_config_makefile dlls/msi enable_msi -wine_fn_config_makefile dlls/msi/tests enable_tests -wine_fn_config_makefile dlls/msident enable_msident -wine_fn_config_makefile dlls/msimg32 enable_msimg32 -wine_fn_config_makefile dlls/msimsg enable_msimsg -wine_fn_config_makefile dlls/msimtf enable_msimtf -wine_fn_config_makefile dlls/msisip enable_msisip -wine_fn_config_makefile dlls/msisys.ocx enable_msisys_ocx -wine_fn_config_makefile dlls/msls31 enable_msls31 -wine_fn_config_makefile dlls/msmpeg2vdec enable_msmpeg2vdec -wine_fn_config_makefile dlls/msnet32 enable_msnet32 -wine_fn_config_makefile dlls/mspatcha enable_mspatcha -wine_fn_config_makefile dlls/mspatcha/tests enable_tests -wine_fn_config_makefile dlls/msports enable_msports -wine_fn_config_makefile dlls/msrle32 enable_msrle32 -wine_fn_config_makefile dlls/msrle32/tests enable_tests -wine_fn_config_makefile dlls/msscript.ocx enable_msscript_ocx -wine_fn_config_makefile dlls/msscript.ocx/tests enable_tests -wine_fn_config_makefile dlls/mssign32 enable_mssign32 -wine_fn_config_makefile dlls/mssip32 enable_mssip32 -wine_fn_config_makefile dlls/mstask enable_mstask -wine_fn_config_makefile dlls/mstask/tests enable_tests -wine_fn_config_makefile dlls/msttsengine enable_msttsengine -wine_fn_config_makefile dlls/msv1_0 enable_msv1_0 -wine_fn_config_makefile dlls/msvcirt enable_msvcirt -wine_fn_config_makefile dlls/msvcirt/tests enable_tests -wine_fn_config_makefile dlls/msvcm80 enable_msvcm80 -wine_fn_config_makefile dlls/msvcm90 enable_msvcm90 -wine_fn_config_makefile dlls/msvcp100 enable_msvcp100 -wine_fn_config_makefile dlls/msvcp100/tests enable_tests -wine_fn_config_makefile dlls/msvcp110 enable_msvcp110 -wine_fn_config_makefile dlls/msvcp110/tests enable_tests -wine_fn_config_makefile dlls/msvcp120 enable_msvcp120 -wine_fn_config_makefile dlls/msvcp120/tests enable_tests -wine_fn_config_makefile dlls/msvcp120_app enable_msvcp120_app -wine_fn_config_makefile dlls/msvcp140 enable_msvcp140 -wine_fn_config_makefile dlls/msvcp140/tests enable_tests -wine_fn_config_makefile dlls/msvcp140_1 enable_msvcp140_1 -wine_fn_config_makefile dlls/msvcp140_1/tests enable_tests -wine_fn_config_makefile dlls/msvcp140_2 enable_msvcp140_2 -wine_fn_config_makefile dlls/msvcp140_2/tests enable_tests -wine_fn_config_makefile dlls/msvcp140_atomic_wait enable_msvcp140_atomic_wait -wine_fn_config_makefile dlls/msvcp140_atomic_wait/tests enable_tests -wine_fn_config_makefile dlls/msvcp140_codecvt_ids enable_msvcp140_codecvt_ids -wine_fn_config_makefile dlls/msvcp60 enable_msvcp60 -wine_fn_config_makefile dlls/msvcp60/tests enable_tests -wine_fn_config_makefile dlls/msvcp70 enable_msvcp70 -wine_fn_config_makefile dlls/msvcp71 enable_msvcp71 -wine_fn_config_makefile dlls/msvcp80 enable_msvcp80 -wine_fn_config_makefile dlls/msvcp90 enable_msvcp90 -wine_fn_config_makefile dlls/msvcp90/tests enable_tests -wine_fn_config_makefile dlls/msvcp_win enable_msvcp_win -wine_fn_config_makefile dlls/msvcr100 enable_msvcr100 -wine_fn_config_makefile dlls/msvcr100/tests enable_tests -wine_fn_config_makefile dlls/msvcr110 enable_msvcr110 -wine_fn_config_makefile dlls/msvcr110/tests enable_tests -wine_fn_config_makefile dlls/msvcr120 enable_msvcr120 -wine_fn_config_makefile dlls/msvcr120/tests enable_tests -wine_fn_config_makefile dlls/msvcr120_app enable_msvcr120_app -wine_fn_config_makefile dlls/msvcr70 enable_msvcr70 -wine_fn_config_makefile dlls/msvcr70/tests enable_tests -wine_fn_config_makefile dlls/msvcr71 enable_msvcr71 -wine_fn_config_makefile dlls/msvcr71/tests enable_tests -wine_fn_config_makefile dlls/msvcr80 enable_msvcr80 -wine_fn_config_makefile dlls/msvcr80/tests enable_tests -wine_fn_config_makefile dlls/msvcr90 enable_msvcr90 -wine_fn_config_makefile dlls/msvcr90/tests enable_tests -wine_fn_config_makefile dlls/msvcrt enable_msvcrt -wine_fn_config_makefile dlls/msvcrt/tests enable_tests -wine_fn_config_makefile dlls/msvcrt20 enable_msvcrt20 -wine_fn_config_makefile dlls/msvcrt40 enable_msvcrt40 -wine_fn_config_makefile dlls/msvcrtd enable_msvcrtd -wine_fn_config_makefile dlls/msvcrtd/tests enable_tests -wine_fn_config_makefile dlls/msvfw32 enable_msvfw32 -wine_fn_config_makefile dlls/msvfw32/tests enable_tests -wine_fn_config_makefile dlls/msvidc32 enable_msvidc32 -wine_fn_config_makefile dlls/msvideo.dll16 enable_win16 -wine_fn_config_makefile dlls/msvproc enable_msvproc -wine_fn_config_makefile dlls/mswsock enable_mswsock -wine_fn_config_makefile dlls/msxml enable_msxml -wine_fn_config_makefile dlls/msxml2 enable_msxml2 -wine_fn_config_makefile dlls/msxml3 enable_msxml3 -wine_fn_config_makefile dlls/msxml3/tests enable_tests -wine_fn_config_makefile dlls/msxml4 enable_msxml4 -wine_fn_config_makefile dlls/msxml4/tests enable_tests -wine_fn_config_makefile dlls/msxml6 enable_msxml6 -wine_fn_config_makefile dlls/msxml6/tests enable_tests -wine_fn_config_makefile dlls/mtxdm enable_mtxdm -wine_fn_config_makefile dlls/ncrypt enable_ncrypt -wine_fn_config_makefile dlls/ncrypt/tests enable_tests -wine_fn_config_makefile dlls/nddeapi enable_nddeapi -wine_fn_config_makefile dlls/ndis.sys enable_ndis_sys -wine_fn_config_makefile dlls/ndis.sys/tests enable_tests -wine_fn_config_makefile dlls/netapi32 enable_netapi32 -wine_fn_config_makefile dlls/netapi32/tests enable_tests -wine_fn_config_makefile dlls/netcfgx enable_netcfgx -wine_fn_config_makefile dlls/netcfgx/tests enable_tests -wine_fn_config_makefile dlls/netio.sys enable_netio_sys -wine_fn_config_makefile dlls/netprofm enable_netprofm -wine_fn_config_makefile dlls/netprofm/tests enable_tests -wine_fn_config_makefile dlls/netutils enable_netutils -wine_fn_config_makefile dlls/newdev enable_newdev -wine_fn_config_makefile dlls/ninput enable_ninput -wine_fn_config_makefile dlls/ninput/tests enable_tests -wine_fn_config_makefile dlls/normaliz enable_normaliz -wine_fn_config_makefile dlls/npmshtml enable_npmshtml -wine_fn_config_makefile dlls/npptools enable_npptools -wine_fn_config_makefile dlls/nsi enable_nsi -wine_fn_config_makefile dlls/nsi/tests enable_tests -wine_fn_config_makefile dlls/nsiproxy.sys enable_nsiproxy_sys -wine_fn_config_makefile dlls/ntdll enable_ntdll -wine_fn_config_makefile dlls/ntdll/tests enable_tests -wine_fn_config_makefile dlls/ntdsapi enable_ntdsapi -wine_fn_config_makefile dlls/ntdsapi/tests enable_tests -wine_fn_config_makefile dlls/ntoskrnl.exe enable_ntoskrnl_exe -wine_fn_config_makefile dlls/ntoskrnl.exe/tests enable_tests -wine_fn_config_makefile dlls/ntprint enable_ntprint -wine_fn_config_makefile dlls/ntprint/tests enable_tests -wine_fn_config_makefile dlls/objsel enable_objsel -wine_fn_config_makefile dlls/odbc32 enable_odbc32 -wine_fn_config_makefile dlls/odbc32/tests enable_tests -wine_fn_config_makefile dlls/odbcbcp enable_odbcbcp -wine_fn_config_makefile dlls/odbccp32 enable_odbccp32 -wine_fn_config_makefile dlls/odbccp32/tests enable_tests -wine_fn_config_makefile dlls/odbccu32 enable_odbccu32 -wine_fn_config_makefile dlls/ole2.dll16 enable_win16 -wine_fn_config_makefile dlls/ole2conv.dll16 enable_win16 -wine_fn_config_makefile dlls/ole2disp.dll16 enable_win16 -wine_fn_config_makefile dlls/ole2nls.dll16 enable_win16 -wine_fn_config_makefile dlls/ole2prox.dll16 enable_win16 -wine_fn_config_makefile dlls/ole2thk.dll16 enable_win16 -wine_fn_config_makefile dlls/ole32 enable_ole32 -wine_fn_config_makefile dlls/ole32/tests enable_tests -wine_fn_config_makefile dlls/oleacc enable_oleacc -wine_fn_config_makefile dlls/oleacc/tests enable_tests -wine_fn_config_makefile dlls/oleaut32 enable_oleaut32 -wine_fn_config_makefile dlls/oleaut32/tests enable_tests -wine_fn_config_makefile dlls/olecli.dll16 enable_win16 -wine_fn_config_makefile dlls/olecli32 enable_olecli32 -wine_fn_config_makefile dlls/oledb32 enable_oledb32 -wine_fn_config_makefile dlls/oledb32/tests enable_tests -wine_fn_config_makefile dlls/oledlg enable_oledlg -wine_fn_config_makefile dlls/oledlg/tests enable_tests -wine_fn_config_makefile dlls/olepro32 enable_olepro32 -wine_fn_config_makefile dlls/olesvr.dll16 enable_win16 -wine_fn_config_makefile dlls/olesvr32 enable_olesvr32 -wine_fn_config_makefile dlls/olethk32 enable_olethk32 -wine_fn_config_makefile dlls/opcservices enable_opcservices -wine_fn_config_makefile dlls/opcservices/tests enable_tests -wine_fn_config_makefile dlls/opencl enable_opencl -wine_fn_config_makefile dlls/opengl32 enable_opengl32 -wine_fn_config_makefile dlls/opengl32/tests enable_tests -wine_fn_config_makefile dlls/packager enable_packager -wine_fn_config_makefile dlls/packager/tests enable_tests -wine_fn_config_makefile dlls/pdh enable_pdh -wine_fn_config_makefile dlls/pdh/tests enable_tests -wine_fn_config_makefile dlls/photometadatahandler enable_photometadatahandler -wine_fn_config_makefile dlls/pidgen enable_pidgen -wine_fn_config_makefile dlls/powrprof enable_powrprof -wine_fn_config_makefile dlls/printui enable_printui -wine_fn_config_makefile dlls/prntvpt enable_prntvpt -wine_fn_config_makefile dlls/prntvpt/tests enable_tests -wine_fn_config_makefile dlls/profapi enable_profapi -wine_fn_config_makefile dlls/propsys enable_propsys -wine_fn_config_makefile dlls/propsys/tests enable_tests -wine_fn_config_makefile dlls/psapi enable_psapi -wine_fn_config_makefile dlls/psapi/tests enable_tests -wine_fn_config_makefile dlls/pstorec enable_pstorec -wine_fn_config_makefile dlls/pstorec/tests enable_tests -wine_fn_config_makefile dlls/pwrshplugin enable_pwrshplugin -wine_fn_config_makefile dlls/qasf enable_qasf -wine_fn_config_makefile dlls/qasf/tests enable_tests -wine_fn_config_makefile dlls/qcap enable_qcap -wine_fn_config_makefile dlls/qcap/tests enable_tests -wine_fn_config_makefile dlls/qdvd enable_qdvd -wine_fn_config_makefile dlls/qdvd/tests enable_tests -wine_fn_config_makefile dlls/qedit enable_qedit -wine_fn_config_makefile dlls/qedit/tests enable_tests -wine_fn_config_makefile dlls/qmgr enable_qmgr -wine_fn_config_makefile dlls/qmgr/tests enable_tests -wine_fn_config_makefile dlls/qmgrprxy enable_qmgrprxy -wine_fn_config_makefile dlls/quartz enable_quartz -wine_fn_config_makefile dlls/quartz/tests enable_tests -wine_fn_config_makefile dlls/query enable_query -wine_fn_config_makefile dlls/qwave enable_qwave -wine_fn_config_makefile dlls/qwave/tests enable_tests -wine_fn_config_makefile dlls/rasapi16.dll16 enable_win16 -wine_fn_config_makefile dlls/rasapi32 enable_rasapi32 -wine_fn_config_makefile dlls/rasapi32/tests enable_tests -wine_fn_config_makefile dlls/rasdlg enable_rasdlg -wine_fn_config_makefile dlls/regapi enable_regapi -wine_fn_config_makefile dlls/resampledmo enable_resampledmo -wine_fn_config_makefile dlls/resutils enable_resutils -wine_fn_config_makefile dlls/riched20 enable_riched20 -wine_fn_config_makefile dlls/riched20/tests enable_tests -wine_fn_config_makefile dlls/riched32 enable_riched32 -wine_fn_config_makefile dlls/riched32/tests enable_tests -wine_fn_config_makefile dlls/rometadata enable_rometadata -wine_fn_config_makefile dlls/rometadata/tests enable_tests -wine_fn_config_makefile dlls/rpcrt4 enable_rpcrt4 -wine_fn_config_makefile dlls/rpcrt4/tests enable_tests -wine_fn_config_makefile dlls/rsabase enable_rsabase -wine_fn_config_makefile dlls/rsaenh enable_rsaenh -wine_fn_config_makefile dlls/rsaenh/tests enable_tests -wine_fn_config_makefile dlls/rstrtmgr enable_rstrtmgr -wine_fn_config_makefile dlls/rtutils enable_rtutils -wine_fn_config_makefile dlls/rtworkq enable_rtworkq -wine_fn_config_makefile dlls/rtworkq/tests enable_tests -wine_fn_config_makefile dlls/samlib enable_samlib -wine_fn_config_makefile dlls/sane.ds enable_sane_ds -wine_fn_config_makefile dlls/sapi enable_sapi -wine_fn_config_makefile dlls/sapi/tests enable_tests -wine_fn_config_makefile dlls/sas enable_sas -wine_fn_config_makefile dlls/scarddlg enable_scarddlg -wine_fn_config_makefile dlls/scardsvr enable_scardsvr -wine_fn_config_makefile dlls/sccbase enable_sccbase -wine_fn_config_makefile dlls/schannel enable_schannel -wine_fn_config_makefile dlls/schannel/tests enable_tests -wine_fn_config_makefile dlls/schedsvc enable_schedsvc -wine_fn_config_makefile dlls/schedsvc/tests enable_tests -wine_fn_config_makefile dlls/scrobj enable_scrobj -wine_fn_config_makefile dlls/scrobj/tests enable_tests -wine_fn_config_makefile dlls/scrrun enable_scrrun -wine_fn_config_makefile dlls/scrrun/tests enable_tests -wine_fn_config_makefile dlls/scsiport.sys enable_scsiport_sys -wine_fn_config_makefile dlls/sechost enable_sechost -wine_fn_config_makefile dlls/secur32 enable_secur32 -wine_fn_config_makefile dlls/secur32/tests enable_tests -wine_fn_config_makefile dlls/security enable_security -wine_fn_config_makefile dlls/sensapi enable_sensapi -wine_fn_config_makefile dlls/serialui enable_serialui -wine_fn_config_makefile dlls/serialui/tests enable_tests -wine_fn_config_makefile dlls/setupapi enable_setupapi -wine_fn_config_makefile dlls/setupapi/tests enable_tests -wine_fn_config_makefile dlls/setupx.dll16 enable_win16 -wine_fn_config_makefile dlls/sfc enable_sfc -wine_fn_config_makefile dlls/sfc_os enable_sfc_os -wine_fn_config_makefile dlls/shcore enable_shcore -wine_fn_config_makefile dlls/shcore/tests enable_tests -wine_fn_config_makefile dlls/shdoclc enable_shdoclc -wine_fn_config_makefile dlls/shdocvw enable_shdocvw -wine_fn_config_makefile dlls/shdocvw/tests enable_tests -wine_fn_config_makefile dlls/shell.dll16 enable_win16 -wine_fn_config_makefile dlls/shell32 enable_shell32 -wine_fn_config_makefile dlls/shell32/tests enable_tests -wine_fn_config_makefile dlls/shfolder enable_shfolder -wine_fn_config_makefile dlls/shlwapi enable_shlwapi -wine_fn_config_makefile dlls/shlwapi/tests enable_tests -wine_fn_config_makefile dlls/slbcsp enable_slbcsp -wine_fn_config_makefile dlls/slc enable_slc -wine_fn_config_makefile dlls/slc/tests enable_tests -wine_fn_config_makefile dlls/snmpapi enable_snmpapi -wine_fn_config_makefile dlls/snmpapi/tests enable_tests -wine_fn_config_makefile dlls/softpub enable_softpub -wine_fn_config_makefile dlls/sound.drv16 enable_win16 -wine_fn_config_makefile dlls/spoolss enable_spoolss -wine_fn_config_makefile dlls/spoolss/tests enable_tests -wine_fn_config_makefile dlls/sppc enable_sppc -wine_fn_config_makefile dlls/srclient enable_srclient -wine_fn_config_makefile dlls/srvcli enable_srvcli -wine_fn_config_makefile dlls/srvsvc enable_srvsvc -wine_fn_config_makefile dlls/sspicli enable_sspicli -wine_fn_config_makefile dlls/stdole2.tlb enable_stdole2_tlb -wine_fn_config_makefile dlls/stdole32.tlb enable_stdole32_tlb -wine_fn_config_makefile dlls/sti enable_sti -wine_fn_config_makefile dlls/sti/tests enable_tests -wine_fn_config_makefile dlls/storage.dll16 enable_win16 -wine_fn_config_makefile dlls/stress.dll16 enable_win16 -wine_fn_config_makefile dlls/strmdll enable_strmdll -wine_fn_config_makefile dlls/svrapi enable_svrapi -wine_fn_config_makefile dlls/sxs enable_sxs -wine_fn_config_makefile dlls/sxs/tests enable_tests -wine_fn_config_makefile dlls/system.drv16 enable_win16 -wine_fn_config_makefile dlls/t2embed enable_t2embed -wine_fn_config_makefile dlls/t2embed/tests enable_tests -wine_fn_config_makefile dlls/tapi32 enable_tapi32 -wine_fn_config_makefile dlls/tapi32/tests enable_tests -wine_fn_config_makefile dlls/taskschd enable_taskschd -wine_fn_config_makefile dlls/taskschd/tests enable_tests -wine_fn_config_makefile dlls/tbs enable_tbs -wine_fn_config_makefile dlls/tdh enable_tdh -wine_fn_config_makefile dlls/tdi.sys enable_tdi_sys -wine_fn_config_makefile dlls/threadpoolwinrt enable_threadpoolwinrt -wine_fn_config_makefile dlls/threadpoolwinrt/tests enable_tests -wine_fn_config_makefile dlls/toolhelp.dll16 enable_win16 -wine_fn_config_makefile dlls/traffic enable_traffic -wine_fn_config_makefile dlls/twain.dll16 enable_win16 -wine_fn_config_makefile dlls/twain_32 enable_twain_32 -wine_fn_config_makefile dlls/twain_32/tests enable_tests -wine_fn_config_makefile dlls/twinapi.appcore enable_twinapi_appcore -wine_fn_config_makefile dlls/twinapi.appcore/tests enable_tests -wine_fn_config_makefile dlls/typelib.dll16 enable_win16 -wine_fn_config_makefile dlls/tzres enable_tzres -wine_fn_config_makefile dlls/ucrtbase enable_ucrtbase -wine_fn_config_makefile dlls/ucrtbase/tests enable_tests -wine_fn_config_makefile dlls/uianimation enable_uianimation -wine_fn_config_makefile dlls/uianimation/tests enable_tests -wine_fn_config_makefile dlls/uiautomationcore enable_uiautomationcore -wine_fn_config_makefile dlls/uiautomationcore/tests enable_tests -wine_fn_config_makefile dlls/uiribbon enable_uiribbon -wine_fn_config_makefile dlls/unicows enable_unicows -wine_fn_config_makefile dlls/updspapi enable_updspapi -wine_fn_config_makefile dlls/url enable_url -wine_fn_config_makefile dlls/urlmon enable_urlmon -wine_fn_config_makefile dlls/urlmon/tests enable_tests -wine_fn_config_makefile dlls/usbd.sys enable_usbd_sys -wine_fn_config_makefile dlls/user.exe16 enable_win16 -wine_fn_config_makefile dlls/user32 enable_user32 -wine_fn_config_makefile dlls/user32/tests enable_tests -wine_fn_config_makefile dlls/userenv enable_userenv -wine_fn_config_makefile dlls/userenv/tests enable_tests -wine_fn_config_makefile dlls/usp10 enable_usp10 -wine_fn_config_makefile dlls/usp10/tests enable_tests -wine_fn_config_makefile dlls/utildll enable_utildll -wine_fn_config_makefile dlls/uxtheme enable_uxtheme -wine_fn_config_makefile dlls/uxtheme/tests enable_tests -wine_fn_config_makefile dlls/vbscript enable_vbscript -wine_fn_config_makefile dlls/vbscript/tests enable_tests -wine_fn_config_makefile dlls/vcomp enable_vcomp -wine_fn_config_makefile dlls/vcomp/tests enable_tests -wine_fn_config_makefile dlls/vcomp100 enable_vcomp100 -wine_fn_config_makefile dlls/vcomp110 enable_vcomp110 -wine_fn_config_makefile dlls/vcomp110/tests enable_tests -wine_fn_config_makefile dlls/vcomp120 enable_vcomp120 -wine_fn_config_makefile dlls/vcomp140 enable_vcomp140 -wine_fn_config_makefile dlls/vcomp90 enable_vcomp90 -wine_fn_config_makefile dlls/vcruntime140 enable_vcruntime140 -wine_fn_config_makefile dlls/vcruntime140_1 enable_vcruntime140_1 -wine_fn_config_makefile dlls/vdhcp.vxd enable_win16 -wine_fn_config_makefile dlls/vdmdbg enable_vdmdbg -wine_fn_config_makefile dlls/ver.dll16 enable_win16 -wine_fn_config_makefile dlls/version enable_version -wine_fn_config_makefile dlls/version/tests enable_tests -wine_fn_config_makefile dlls/vga enable_vga -wine_fn_config_makefile dlls/virtdisk enable_virtdisk -wine_fn_config_makefile dlls/virtdisk/tests enable_tests -wine_fn_config_makefile dlls/vmm.vxd enable_win16 -wine_fn_config_makefile dlls/vnbt.vxd enable_win16 -wine_fn_config_makefile dlls/vnetbios.vxd enable_win16 -wine_fn_config_makefile dlls/vssapi enable_vssapi -wine_fn_config_makefile dlls/vtdapi.vxd enable_win16 -wine_fn_config_makefile dlls/vulkan-1 enable_vulkan_1 -wine_fn_config_makefile dlls/vulkan-1/tests enable_tests -wine_fn_config_makefile dlls/vwin32.vxd enable_win16 -wine_fn_config_makefile dlls/w32skrnl enable_win16 -wine_fn_config_makefile dlls/w32sys.dll16 enable_win16 -wine_fn_config_makefile dlls/wbemdisp enable_wbemdisp -wine_fn_config_makefile dlls/wbemdisp/tests enable_tests -wine_fn_config_makefile dlls/wbemprox enable_wbemprox -wine_fn_config_makefile dlls/wbemprox/tests enable_tests -wine_fn_config_makefile dlls/wdscore enable_wdscore -wine_fn_config_makefile dlls/webservices enable_webservices -wine_fn_config_makefile dlls/webservices/tests enable_tests -wine_fn_config_makefile dlls/websocket enable_websocket -wine_fn_config_makefile dlls/wer enable_wer -wine_fn_config_makefile dlls/wer/tests enable_tests -wine_fn_config_makefile dlls/wevtapi enable_wevtapi -wine_fn_config_makefile dlls/wevtapi/tests enable_tests -wine_fn_config_makefile dlls/wevtsvc enable_wevtsvc -wine_fn_config_makefile dlls/wiaservc enable_wiaservc -wine_fn_config_makefile dlls/wiaservc/tests enable_tests -wine_fn_config_makefile dlls/wimgapi enable_wimgapi -wine_fn_config_makefile dlls/win32s16.dll16 enable_win16 -wine_fn_config_makefile dlls/win32u enable_win32u -wine_fn_config_makefile dlls/win32u/tests enable_tests -wine_fn_config_makefile dlls/win87em.dll16 enable_win16 -wine_fn_config_makefile dlls/winaspi.dll16 enable_win16 -wine_fn_config_makefile dlls/windebug.dll16 enable_win16 -wine_fn_config_makefile dlls/windows.applicationmodel enable_windows_applicationmodel -wine_fn_config_makefile dlls/windows.applicationmodel/tests enable_tests -wine_fn_config_makefile dlls/windows.devices.bluetooth enable_windows_devices_bluetooth -wine_fn_config_makefile dlls/windows.devices.bluetooth/tests enable_tests -wine_fn_config_makefile dlls/windows.devices.enumeration enable_windows_devices_enumeration -wine_fn_config_makefile dlls/windows.devices.enumeration/tests enable_tests -wine_fn_config_makefile dlls/windows.devices.usb enable_windows_devices_usb -wine_fn_config_makefile dlls/windows.devices.usb/tests enable_tests -wine_fn_config_makefile dlls/windows.gaming.input enable_windows_gaming_input -wine_fn_config_makefile dlls/windows.gaming.input/tests enable_tests -wine_fn_config_makefile dlls/windows.gaming.ui.gamebar enable_windows_gaming_ui_gamebar -wine_fn_config_makefile dlls/windows.gaming.ui.gamebar/tests enable_tests -wine_fn_config_makefile dlls/windows.globalization enable_windows_globalization -wine_fn_config_makefile dlls/windows.globalization/tests enable_tests -wine_fn_config_makefile dlls/windows.media.devices enable_windows_media_devices -wine_fn_config_makefile dlls/windows.media.devices/tests enable_tests -wine_fn_config_makefile dlls/windows.media.mediacontrol enable_windows_media_mediacontrol -wine_fn_config_makefile dlls/windows.media.mediacontrol/tests enable_tests -wine_fn_config_makefile dlls/windows.media.speech enable_windows_media_speech -wine_fn_config_makefile dlls/windows.media.speech/tests enable_tests -wine_fn_config_makefile dlls/windows.media enable_windows_media -wine_fn_config_makefile dlls/windows.media/tests enable_tests -wine_fn_config_makefile dlls/windows.networking.connectivity enable_windows_networking_connectivity -wine_fn_config_makefile dlls/windows.networking.connectivity/tests enable_tests -wine_fn_config_makefile dlls/windows.networking.hostname enable_windows_networking_hostname -wine_fn_config_makefile dlls/windows.networking.hostname/tests enable_tests -wine_fn_config_makefile dlls/windows.networking enable_windows_networking -wine_fn_config_makefile dlls/windows.perception.stub enable_windows_perception_stub -wine_fn_config_makefile dlls/windows.perception.stub/tests enable_tests -wine_fn_config_makefile dlls/windows.security.authentication.onlineid enable_windows_security_authentication_onlineid -wine_fn_config_makefile dlls/windows.security.authentication.onlineid/tests enable_tests -wine_fn_config_makefile dlls/windows.security.credentials.ui.userconsentverifier enable_windows_security_credentials_ui_userconsentverifier -wine_fn_config_makefile dlls/windows.security.credentials.ui.userconsentverifier/tests enable_tests -wine_fn_config_makefile dlls/windows.storage.applicationdata enable_windows_storage_applicationdata -wine_fn_config_makefile dlls/windows.storage.applicationdata/tests enable_tests -wine_fn_config_makefile dlls/windows.system.profile.systemmanufacturers enable_windows_system_profile_systemmanufacturers -wine_fn_config_makefile dlls/windows.system.profile.systemmanufacturers/tests enable_tests -wine_fn_config_makefile dlls/windows.ui enable_windows_ui -wine_fn_config_makefile dlls/windows.ui/tests enable_tests -wine_fn_config_makefile dlls/windows.web enable_windows_web -wine_fn_config_makefile dlls/windows.web/tests enable_tests -wine_fn_config_makefile dlls/windowscodecs enable_windowscodecs -wine_fn_config_makefile dlls/windowscodecs/tests enable_tests -wine_fn_config_makefile dlls/windowscodecsext enable_windowscodecsext -wine_fn_config_makefile dlls/windowscodecsext/tests enable_tests -wine_fn_config_makefile dlls/winealsa.drv enable_winealsa_drv -wine_fn_config_makefile dlls/wineandroid.drv enable_wineandroid_drv -wine_fn_config_makefile dlls/winebth.sys enable_winebth_sys -wine_fn_config_makefile dlls/winebus.sys enable_winebus_sys -wine_fn_config_makefile dlls/winecoreaudio.drv enable_winecoreaudio_drv -wine_fn_config_makefile dlls/winecrt0 enable_winecrt0 -wine_fn_config_makefile dlls/wined3d enable_wined3d -wine_fn_config_makefile dlls/winedmo enable_winedmo -wine_fn_config_makefile dlls/winegstreamer enable_winegstreamer -wine_fn_config_makefile dlls/winehid.sys enable_winehid_sys -wine_fn_config_makefile dlls/winemac.drv enable_winemac_drv -wine_fn_config_makefile dlls/winemapi enable_winemapi -wine_fn_config_makefile dlls/wineoss.drv enable_wineoss_drv -wine_fn_config_makefile dlls/wineps.drv enable_wineps_drv -wine_fn_config_makefile dlls/wineps16.drv16 enable_win16 -wine_fn_config_makefile dlls/winepulse.drv enable_winepulse_drv -wine_fn_config_makefile dlls/wineusb.sys enable_wineusb_sys -wine_fn_config_makefile dlls/winevulkan enable_winevulkan -wine_fn_config_makefile dlls/winewayland.drv enable_winewayland_drv -wine_fn_config_makefile dlls/winex11.drv enable_winex11_drv -wine_fn_config_makefile dlls/winexinput.sys enable_winexinput_sys -wine_fn_config_makefile dlls/wing.dll16 enable_win16 -wine_fn_config_makefile dlls/wing32 enable_wing32 -wine_fn_config_makefile dlls/wing32/tests enable_tests -wine_fn_config_makefile dlls/winhttp enable_winhttp -wine_fn_config_makefile dlls/winhttp/tests enable_tests -wine_fn_config_makefile dlls/wininet enable_wininet -wine_fn_config_makefile dlls/wininet/tests enable_tests -wine_fn_config_makefile dlls/winmm enable_winmm -wine_fn_config_makefile dlls/winmm/tests enable_tests -wine_fn_config_makefile dlls/winnls.dll16 enable_win16 -wine_fn_config_makefile dlls/winnls32 enable_winnls32 -wine_fn_config_makefile dlls/winprint enable_winprint -wine_fn_config_makefile dlls/winscard enable_winscard -wine_fn_config_makefile dlls/winscard/tests enable_tests -wine_fn_config_makefile dlls/winsock.dll16 enable_win16 -wine_fn_config_makefile dlls/winspool.drv enable_winspool_drv -wine_fn_config_makefile dlls/winspool.drv/tests enable_tests -wine_fn_config_makefile dlls/winsta enable_winsta -wine_fn_config_makefile dlls/wintab.dll16 enable_win16 -wine_fn_config_makefile dlls/wintab32 enable_wintab32 -wine_fn_config_makefile dlls/wintab32/tests enable_tests -wine_fn_config_makefile dlls/wintrust enable_wintrust -wine_fn_config_makefile dlls/wintrust/tests enable_tests -wine_fn_config_makefile dlls/wintypes enable_wintypes -wine_fn_config_makefile dlls/wintypes/tests enable_tests -wine_fn_config_makefile dlls/winusb enable_winusb -wine_fn_config_makefile dlls/wlanapi enable_wlanapi -wine_fn_config_makefile dlls/wlanapi/tests enable_tests -wine_fn_config_makefile dlls/wlanui enable_wlanui -wine_fn_config_makefile dlls/wldap32 enable_wldap32 -wine_fn_config_makefile dlls/wldap32/tests enable_tests -wine_fn_config_makefile dlls/wldp enable_wldp -wine_fn_config_makefile dlls/wldp/tests enable_tests -wine_fn_config_makefile dlls/wmadmod enable_wmadmod -wine_fn_config_makefile dlls/wmasf enable_wmasf -wine_fn_config_makefile dlls/wmi enable_wmi -wine_fn_config_makefile dlls/wmilib.sys enable_wmilib_sys -wine_fn_config_makefile dlls/wmiutils enable_wmiutils -wine_fn_config_makefile dlls/wmiutils/tests enable_tests -wine_fn_config_makefile dlls/wmp enable_wmp -wine_fn_config_makefile dlls/wmp/tests enable_tests -wine_fn_config_makefile dlls/wmphoto enable_wmphoto -wine_fn_config_makefile dlls/wmvcore enable_wmvcore -wine_fn_config_makefile dlls/wmvcore/tests enable_tests -wine_fn_config_makefile dlls/wmvdecod enable_wmvdecod -wine_fn_config_makefile dlls/wnaspi32 enable_wnaspi32 -wine_fn_config_makefile dlls/wofutil enable_wofutil -wine_fn_config_makefile dlls/wow32 enable_win16 -wine_fn_config_makefile dlls/wow64 enable_wow64 -wine_fn_config_makefile dlls/wow64cpu enable_wow64cpu -wine_fn_config_makefile dlls/wow64win enable_wow64win -wine_fn_config_makefile dlls/wpc enable_wpc -wine_fn_config_makefile dlls/wpc/tests enable_tests -wine_fn_config_makefile dlls/wpcap enable_wpcap -wine_fn_config_makefile dlls/wpcap/tests enable_tests -wine_fn_config_makefile dlls/ws2_32 enable_ws2_32 -wine_fn_config_makefile dlls/ws2_32/tests enable_tests -wine_fn_config_makefile dlls/wsdapi enable_wsdapi -wine_fn_config_makefile dlls/wsdapi/tests enable_tests -wine_fn_config_makefile dlls/wshom.ocx enable_wshom_ocx -wine_fn_config_makefile dlls/wshom.ocx/tests enable_tests -wine_fn_config_makefile dlls/wsnmp32 enable_wsnmp32 -wine_fn_config_makefile dlls/wsnmp32/tests enable_tests -wine_fn_config_makefile dlls/wsock32 enable_wsock32 -wine_fn_config_makefile dlls/wtsapi32 enable_wtsapi32 -wine_fn_config_makefile dlls/wtsapi32/tests enable_tests -wine_fn_config_makefile dlls/wuapi enable_wuapi -wine_fn_config_makefile dlls/wuaueng enable_wuaueng -wine_fn_config_makefile dlls/x3daudio1_0 enable_x3daudio1_0 -wine_fn_config_makefile dlls/x3daudio1_1 enable_x3daudio1_1 -wine_fn_config_makefile dlls/x3daudio1_2 enable_x3daudio1_2 -wine_fn_config_makefile dlls/x3daudio1_3 enable_x3daudio1_3 -wine_fn_config_makefile dlls/x3daudio1_4 enable_x3daudio1_4 -wine_fn_config_makefile dlls/x3daudio1_5 enable_x3daudio1_5 -wine_fn_config_makefile dlls/x3daudio1_6 enable_x3daudio1_6 -wine_fn_config_makefile dlls/x3daudio1_7 enable_x3daudio1_7 -wine_fn_config_makefile dlls/xactengine2_0 enable_xactengine2_0 -wine_fn_config_makefile dlls/xactengine2_4 enable_xactengine2_4 -wine_fn_config_makefile dlls/xactengine2_7 enable_xactengine2_7 -wine_fn_config_makefile dlls/xactengine2_9 enable_xactengine2_9 -wine_fn_config_makefile dlls/xactengine3_0 enable_xactengine3_0 -wine_fn_config_makefile dlls/xactengine3_1 enable_xactengine3_1 -wine_fn_config_makefile dlls/xactengine3_2 enable_xactengine3_2 -wine_fn_config_makefile dlls/xactengine3_3 enable_xactengine3_3 -wine_fn_config_makefile dlls/xactengine3_4 enable_xactengine3_4 -wine_fn_config_makefile dlls/xactengine3_5 enable_xactengine3_5 -wine_fn_config_makefile dlls/xactengine3_6 enable_xactengine3_6 -wine_fn_config_makefile dlls/xactengine3_7 enable_xactengine3_7 -wine_fn_config_makefile dlls/xactengine3_7/tests enable_tests -wine_fn_config_makefile dlls/xapofx1_1 enable_xapofx1_1 -wine_fn_config_makefile dlls/xapofx1_2 enable_xapofx1_2 -wine_fn_config_makefile dlls/xapofx1_3 enable_xapofx1_3 -wine_fn_config_makefile dlls/xapofx1_4 enable_xapofx1_4 -wine_fn_config_makefile dlls/xapofx1_5 enable_xapofx1_5 -wine_fn_config_makefile dlls/xaudio2_0 enable_xaudio2_0 -wine_fn_config_makefile dlls/xaudio2_1 enable_xaudio2_1 -wine_fn_config_makefile dlls/xaudio2_2 enable_xaudio2_2 -wine_fn_config_makefile dlls/xaudio2_3 enable_xaudio2_3 -wine_fn_config_makefile dlls/xaudio2_4 enable_xaudio2_4 -wine_fn_config_makefile dlls/xaudio2_5 enable_xaudio2_5 -wine_fn_config_makefile dlls/xaudio2_6 enable_xaudio2_6 -wine_fn_config_makefile dlls/xaudio2_7 enable_xaudio2_7 -wine_fn_config_makefile dlls/xaudio2_7/tests enable_tests -wine_fn_config_makefile dlls/xaudio2_8 enable_xaudio2_8 -wine_fn_config_makefile dlls/xaudio2_8/tests enable_tests -wine_fn_config_makefile dlls/xaudio2_9 enable_xaudio2_9 -wine_fn_config_makefile dlls/xinput1_1 enable_xinput1_1 -wine_fn_config_makefile dlls/xinput1_2 enable_xinput1_2 -wine_fn_config_makefile dlls/xinput1_3 enable_xinput1_3 -wine_fn_config_makefile dlls/xinput1_3/tests enable_tests -wine_fn_config_makefile dlls/xinput1_4 enable_xinput1_4 -wine_fn_config_makefile dlls/xinput9_1_0 enable_xinput9_1_0 -wine_fn_config_makefile dlls/xinputuap enable_xinputuap -wine_fn_config_makefile dlls/xmllite enable_xmllite -wine_fn_config_makefile dlls/xmllite/tests enable_tests -wine_fn_config_makefile dlls/xolehlp enable_xolehlp -wine_fn_config_makefile dlls/xpsprint enable_xpsprint -wine_fn_config_makefile dlls/xpssvcs enable_xpssvcs -wine_fn_config_makefile dlls/xtajit64 enable_xtajit64 -wine_fn_config_makefile fonts enable_fonts -wine_fn_config_makefile include enable_include -wine_fn_config_makefile libs/adsiid enable_adsiid -wine_fn_config_makefile libs/capstone enable_capstone -wine_fn_config_makefile libs/dmoguids enable_dmoguids -wine_fn_config_makefile libs/dxerr8 enable_dxerr8 -wine_fn_config_makefile libs/dxerr9 enable_dxerr9 -wine_fn_config_makefile libs/dxguid enable_dxguid -wine_fn_config_makefile libs/faudio enable_faudio -wine_fn_config_makefile libs/fluidsynth enable_fluidsynth -wine_fn_config_makefile libs/gsm enable_gsm -wine_fn_config_makefile libs/jpeg enable_jpeg -wine_fn_config_makefile libs/jxr enable_jxr -wine_fn_config_makefile libs/lcms2 enable_lcms2 -wine_fn_config_makefile libs/ldap enable_ldap -wine_fn_config_makefile libs/mfuuid enable_mfuuid -wine_fn_config_makefile libs/mpg123 enable_mpg123 -wine_fn_config_makefile libs/musl enable_musl -wine_fn_config_makefile libs/png enable_png -wine_fn_config_makefile libs/strmbase enable_strmbase -wine_fn_config_makefile libs/strmiids enable_strmiids -wine_fn_config_makefile libs/tiff enable_tiff -wine_fn_config_makefile libs/uuid enable_uuid -wine_fn_config_makefile libs/vkd3d enable_vkd3d -wine_fn_config_makefile libs/wbemuuid enable_wbemuuid -wine_fn_config_makefile libs/wmcodecdspuuid enable_wmcodecdspuuid -wine_fn_config_makefile libs/xml2 enable_xml2 -wine_fn_config_makefile libs/xslt enable_xslt -wine_fn_config_makefile libs/zlib enable_zlib -wine_fn_config_makefile loader enable_loader -wine_fn_config_makefile nls enable_nls -wine_fn_config_makefile po enable_po -wine_fn_config_makefile programs/arp enable_arp -wine_fn_config_makefile programs/aspnet_regiis enable_aspnet_regiis -wine_fn_config_makefile programs/attrib enable_attrib -wine_fn_config_makefile programs/cabarc enable_cabarc -wine_fn_config_makefile programs/cacls enable_cacls -wine_fn_config_makefile programs/certutil enable_certutil -wine_fn_config_makefile programs/chcp.com enable_chcp_com -wine_fn_config_makefile programs/clock enable_clock -wine_fn_config_makefile programs/cmd enable_cmd -wine_fn_config_makefile programs/cmd/tests enable_tests -wine_fn_config_makefile programs/conhost enable_conhost -wine_fn_config_makefile programs/conhost/tests enable_tests -wine_fn_config_makefile programs/control enable_control -wine_fn_config_makefile programs/cscript enable_cscript -wine_fn_config_makefile programs/dism enable_dism -wine_fn_config_makefile programs/dllhost enable_dllhost -wine_fn_config_makefile programs/dplaysvr enable_dplaysvr -wine_fn_config_makefile programs/dpnsvr enable_dpnsvr -wine_fn_config_makefile programs/dpvsetup enable_dpvsetup -wine_fn_config_makefile programs/dxdiag enable_dxdiag -wine_fn_config_makefile programs/eject enable_eject -wine_fn_config_makefile programs/expand enable_expand -wine_fn_config_makefile programs/explorer enable_explorer -wine_fn_config_makefile programs/explorer/tests enable_tests -wine_fn_config_makefile programs/extrac32 enable_extrac32 -wine_fn_config_makefile programs/fc enable_fc -wine_fn_config_makefile programs/fc/tests enable_tests -wine_fn_config_makefile programs/find enable_find -wine_fn_config_makefile programs/find/tests enable_tests -wine_fn_config_makefile programs/findstr enable_findstr -wine_fn_config_makefile programs/findstr/tests enable_tests -wine_fn_config_makefile programs/fsutil enable_fsutil -wine_fn_config_makefile programs/fsutil/tests enable_tests -wine_fn_config_makefile programs/hh enable_hh -wine_fn_config_makefile programs/hostname enable_hostname -wine_fn_config_makefile programs/icacls enable_icacls -wine_fn_config_makefile programs/icinfo enable_icinfo -wine_fn_config_makefile programs/iexplore enable_iexplore -wine_fn_config_makefile programs/ipconfig enable_ipconfig -wine_fn_config_makefile programs/klist enable_klist -wine_fn_config_makefile programs/lodctr enable_lodctr -wine_fn_config_makefile programs/mofcomp enable_mofcomp -wine_fn_config_makefile programs/mshta enable_mshta -wine_fn_config_makefile programs/msidb enable_msidb -wine_fn_config_makefile programs/msiexec enable_msiexec -wine_fn_config_makefile programs/msinfo32 enable_msinfo32 -wine_fn_config_makefile programs/net enable_net -wine_fn_config_makefile programs/net/tests enable_tests -wine_fn_config_makefile programs/netsh enable_netsh -wine_fn_config_makefile programs/netstat enable_netstat -wine_fn_config_makefile programs/ngen enable_ngen -wine_fn_config_makefile programs/notepad enable_notepad -wine_fn_config_makefile programs/oleview enable_oleview -wine_fn_config_makefile programs/ping enable_ping -wine_fn_config_makefile programs/plugplay enable_plugplay -wine_fn_config_makefile programs/pnputil enable_pnputil -wine_fn_config_makefile programs/powershell enable_powershell -wine_fn_config_makefile programs/presentationfontcache enable_presentationfontcache -wine_fn_config_makefile programs/progman enable_progman -wine_fn_config_makefile programs/reg enable_reg -wine_fn_config_makefile programs/reg/tests enable_tests -wine_fn_config_makefile programs/regasm enable_regasm -wine_fn_config_makefile programs/regedit enable_regedit -wine_fn_config_makefile programs/regedit/tests enable_tests -wine_fn_config_makefile programs/regini enable_regini -wine_fn_config_makefile programs/regsvcs enable_regsvcs -wine_fn_config_makefile programs/regsvr32 enable_regsvr32 -wine_fn_config_makefile programs/robocopy enable_robocopy -wine_fn_config_makefile programs/rpcss enable_rpcss -wine_fn_config_makefile programs/rundll.exe16 enable_win16 -wine_fn_config_makefile programs/rundll32 enable_rundll32 -wine_fn_config_makefile programs/sc enable_sc -wine_fn_config_makefile programs/sc/tests enable_tests -wine_fn_config_makefile programs/schtasks enable_schtasks -wine_fn_config_makefile programs/schtasks/tests enable_tests -wine_fn_config_makefile programs/sdbinst enable_sdbinst -wine_fn_config_makefile programs/secedit enable_secedit -wine_fn_config_makefile programs/servicemodelreg enable_servicemodelreg -wine_fn_config_makefile programs/services enable_services -wine_fn_config_makefile programs/services/tests enable_tests -wine_fn_config_makefile programs/setx enable_setx -wine_fn_config_makefile programs/shutdown enable_shutdown -wine_fn_config_makefile programs/sort enable_sort -wine_fn_config_makefile programs/spoolsv enable_spoolsv -wine_fn_config_makefile programs/start enable_start -wine_fn_config_makefile programs/subst enable_subst -wine_fn_config_makefile programs/svchost enable_svchost -wine_fn_config_makefile programs/systeminfo enable_systeminfo -wine_fn_config_makefile programs/taskkill enable_taskkill -wine_fn_config_makefile programs/tasklist enable_tasklist -wine_fn_config_makefile programs/tasklist/tests enable_tests -wine_fn_config_makefile programs/taskmgr enable_taskmgr -wine_fn_config_makefile programs/termsv enable_termsv -wine_fn_config_makefile programs/uninstaller enable_uninstaller -wine_fn_config_makefile programs/unlodctr enable_unlodctr -wine_fn_config_makefile programs/view enable_view -wine_fn_config_makefile programs/wevtutil enable_wevtutil -wine_fn_config_makefile programs/where enable_where -wine_fn_config_makefile programs/whoami enable_whoami -wine_fn_config_makefile programs/wineboot enable_wineboot -wine_fn_config_makefile programs/winebrowser enable_winebrowser -wine_fn_config_makefile programs/winecfg enable_winecfg -wine_fn_config_makefile programs/wineconsole enable_wineconsole -wine_fn_config_makefile programs/winedbg enable_winedbg -wine_fn_config_makefile programs/winedevice enable_winedevice -wine_fn_config_makefile programs/winefile enable_winefile -wine_fn_config_makefile programs/winemenubuilder enable_winemenubuilder -wine_fn_config_makefile programs/winemine enable_winemine -wine_fn_config_makefile programs/winemsibuilder enable_winemsibuilder -wine_fn_config_makefile programs/winepath enable_winepath -wine_fn_config_makefile programs/winetest enable_winetest -wine_fn_config_makefile programs/winevdm enable_win16 -wine_fn_config_makefile programs/winhelp.exe16 enable_win16 -wine_fn_config_makefile programs/winhlp32 enable_winhlp32 -wine_fn_config_makefile programs/winmgmt enable_winmgmt -wine_fn_config_makefile programs/winoldap.mod16 enable_win16 -wine_fn_config_makefile programs/winver enable_winver -wine_fn_config_makefile programs/wmic enable_wmic -wine_fn_config_makefile programs/wmplayer enable_wmplayer -wine_fn_config_makefile programs/wordpad enable_wordpad -wine_fn_config_makefile programs/write enable_write -wine_fn_config_makefile programs/wscript enable_wscript -wine_fn_config_makefile programs/wscript/tests enable_tests -wine_fn_config_makefile programs/wuauserv enable_wuauserv -wine_fn_config_makefile programs/wusa enable_wusa -wine_fn_config_makefile programs/xcopy enable_xcopy -wine_fn_config_makefile programs/xcopy/tests enable_tests -wine_fn_config_makefile server enable_server -test "x$enable_tools" = xno || wine_fn_config_makefile tools enable_tools -test "x$enable_tools" = xno || wine_fn_config_makefile tools/sfnt2fon enable_sfnt2fon -test "x$enable_tools" = xno || wine_fn_config_makefile tools/widl enable_widl -test "x$enable_tools" = xno || wine_fn_config_makefile tools/winebuild enable_winebuild -test "x$enable_tools" = xno || wine_fn_config_makefile tools/winedump enable_winedump -test "x$enable_tools" = xno || wine_fn_config_makefile tools/winegcc enable_winegcc -test "x$enable_tools" = xno || wine_fn_config_makefile tools/winemaker enable_winemaker -test "x$enable_tools" = xno || wine_fn_config_makefile tools/wmc enable_wmc -test "x$enable_tools" = xno || wine_fn_config_makefile tools/wrc enable_wrc - - -as_fn_append CONFIGURE_TARGETS " TAGS" -as_fn_append CONFIGURE_TARGETS " tags" -as_fn_append CONFIGURE_TARGETS " autom4te.cache" -as_fn_append CONFIGURE_TARGETS " compile_commands.json" -as_fn_append CONFIGURE_TARGETS " config.log" -as_fn_append CONFIGURE_TARGETS " config.status" -as_fn_append CONFIGURE_TARGETS " include/config.h" -as_fn_append CONFIGURE_TARGETS " include/stamp-h" -test "$wine_binary" = wine || as_fn_append CONFIGURE_TARGETS " loader/wine" - -if test "x$enable_tools" != xno -then - ac_config_commands="$ac_config_commands tools/makedep" - -fi - -ac_config_commands="$ac_config_commands Makefile" - - - -SHELL=/bin/sh - - - -as_fn_append wine_rules " -all: wine - @echo \"Wine build complete.\" -Makefile: config.status - @./config.status Makefile -config.status: ${wine_srcdir}configure - @./config.status --recheck -include/config.h: include/stamp-h -include/stamp-h: ${wine_srcdir}include/config.h.in config.status - @./config.status include/config.h include/stamp-h" - -if test "x$enable_maintainer_mode" = xyes -then - as_fn_append wine_rules " -configure: configure.ac aclocal.m4 - autoconf --warnings=all -include/config.h.in: include/stamp-h.in -include/stamp-h.in: configure.ac aclocal.m4 - autoheader --warnings=all - @echo timestamp > \$@" -fi - - -if test -n "$with_wine64" -then - case "$with_wine64" in - /*) reldir="" ;; - *) reldir="../" ;; - esac - rm -f fonts server 2>/dev/null - as_fn_append wine_rules " -all: loader/wine64 loader/wine64-preloader $with_wine64/loader/wine $with_wine64/loader/wine-preloader -loader/wine64 loader/wine64-preloader: - rm -f \$@ && \$(LN_S) $reldir$with_wine64/\$@ \$@ -$with_wine64/loader/wine: - rm -f \$@ && \$(LN_S) $ac_pwd/loader/wine \$@ -$with_wine64/loader/wine-preloader: - rm -f \$@ && \$(LN_S) $ac_pwd/loader/wine-preloader \$@ -clean:: - rm -f loader/wine64 loader/wine64-preloader $with_wine64/loader/wine $with_wine64/loader/wine-preloader" -else - TOP_INSTALL_DEV="$TOP_INSTALL_DEV include" - TOP_INSTALL_LIB="$TOP_INSTALL_LIB \ -fonts \ -loader/wine.inf \ -nls \ -programs/msidb/msidb \ -programs/msiexec/msiexec \ -programs/notepad/notepad \ -programs/regedit/regedit \ -programs/regsvr32/regsvr32 \ -programs/wineboot/wineboot \ -programs/winecfg/winecfg \ -programs/wineconsole/wineconsole \ -programs/winedbg/winedbg \ -programs/winefile/winefile \ -programs/winemine/winemine \ -programs/winepath/winepath \ -server/wineserver" - - case $host_os in - cygwin*|mingw32*|darwin*|macosx*|linux-android*) ;; - *) TOP_INSTALL_LIB="$TOP_INSTALL_LIB loader/wine.desktop" ;; - esac -fi - - -as_fn_append wine_rules " -distclean:: clean - rm -rf autom4te.cache -maintainer-clean:: - rm -f configure include/config.h.in" - - -as_fn_append wine_rules " -dlls/ntdll/unix/version.c: dummy - @version=\`(GIT_DIR=${wine_srcdir}.git git describe HEAD 2>/dev/null || echo \"wine-\$(PACKAGE_VERSION)\") | sed -n -e '\$\$s/\(.*\)/const char wine_build[] = \"\\1\";/p'\` && (echo \$\$version | cmp -s - \$@) || echo \$\$version >\$@ || (rm -f \$@ && exit 1) -programs/winetest/build.rc: dummy - @build=\"STRINGTABLE { 1 \\\"\`GIT_DIR=${wine_srcdir}.git git rev-parse HEAD 2>/dev/null\`\\\" }\" && (echo \$\$build | cmp -s - \$@) || echo \$\$build >\$@ || (rm -f \$@ && exit 1) -programs/winetest/build.nfo: - @-\$(CC) -v 2>\$@ -dlls/wineandroid.drv/wine-debug.apk: dlls/wineandroid.drv/build.gradle ${wine_srcdir}dlls/wineandroid.drv/AndroidManifest.xml ${wine_srcdir}dlls/wineandroid.drv/WineActivity.java ${wine_srcdir}dlls/wineandroid.drv/wine.svg - cd dlls/wineandroid.drv && gradle -q -Psrcdir=$srcdir assembleDebug - mv dlls/wineandroid.drv/build/outputs/apk/wine-debug.apk \$@" - - -TAGSFLAGS="--langmap='c:+.idl.l.rh,make:(Make*.in)'" - -as_fn_append wine_rules " -TAGS etags: - rm -f TAGS - (test -d .git && git ls-files || find -L $srcdir -name '*.[ch]' -print) | xargs etags -a \$(TAGSFLAGS) -tags ctags: - rm -f tags - (test -d .git && git ls-files || find -L $srcdir -name '*.[ch]' -print) | xargs ctags -a \$(TAGSFLAGS) -dummy: -.PHONY: dummy" - -printf "%s\n" " done" >&6 -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# 'ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* 'ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # 'set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # 'set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -printf "%s\n" "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - -# Check whether --enable-year2038 was given. -if test ${enable_year2038+y} -then : - enableval=$enable_year2038; -fi - - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else case e in #( - e) case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as 'sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf "%s\n" "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else case e in #( - e) as_fn_append () - { - eval $1=\$$1\$2 - } ;; -esac -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else case e in #( - e) as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } ;; -esac -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -# For backward compatibility with old third-party macros, we provide -# the shell variables $as_echo and $as_echo_n. New code should use -# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. -as_echo='printf %s\n' -as_echo_n='printf %s' - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. - # In both cases, we have to default to 'cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" -as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated - -# Sed expression to map a string onto a valid variable name. -as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" -as_tr_sh="eval sed '$as_sed_sh'" # deprecated - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by Wine $as_me 10.0, which was -generated by GNU Autoconf 2.72. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_headers="$ac_config_headers" -config_links="$ac_config_links" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -'$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration headers: -$config_headers - -Configuration links: -$config_links - -Configuration commands: -$config_commands - -Report bugs to . -Wine home page: ." - -_ACEOF -ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` -ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config='$ac_cs_config_escaped' -ac_cs_version="\\ -Wine config.status 10.0 -configured by $0, generated by GNU Autoconf 2.72, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2023 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - printf "%s\n" "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - printf "%s\n" "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: '$1' -Try '$0 --help' for more information.";; - --help | --hel | -h ) - printf "%s\n" "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: '$1' -Try '$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - printf "%s\n" "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -wine_fn_output_makedep () -{ - as_dir=tools; as_fn_mkdir_p - $CC -c -I${wine_srcdir}tools -Iinclude -I${wine_srcdir}include -D__WINESRC__ -DWINE_UNIX_LIB $EXTRACFLAGS $CPPFLAGS $CFLAGS -o tools/makedep.o ${wine_srcdir}tools/makedep.c - $CC -o tools/makedep$ac_exeext tools/makedep.o $LDFLAGS -} -wine_fn_output_makefile () -{ - cat <<\_WINE_EOF >\$tmp/makefile && mv -f \$tmp/makefile \$1 && "$wine_makedep"$makedep_flags && return -# This Makefile understands the following targets: -# -# all (default): build wine -# clean: remove all intermediate files -# distclean: also remove all files created by configure -# test: run tests -# testclean: clean test results to force running all tests again -# install-lib: install libraries needed to run applications -# install-dev: install development environment -# install: install everything -# uninstall: uninstall everything -# ctags: create a tags file for vim and others. -# etags: create a TAGS file for Emacs. - -SHELL = $SHELL -PATH_SEPARATOR = $PATH_SEPARATOR -PACKAGE_NAME = $PACKAGE_NAME -PACKAGE_TARNAME = $PACKAGE_TARNAME -PACKAGE_VERSION = $PACKAGE_VERSION -PACKAGE_STRING = $PACKAGE_STRING -PACKAGE_BUGREPORT = $PACKAGE_BUGREPORT -PACKAGE_URL = $PACKAGE_URL -exec_prefix = $exec_prefix -prefix = $prefix -program_transform_name = $program_transform_name -bindir = $bindir -sbindir = $sbindir -libexecdir = $libexecdir -datarootdir = $datarootdir -datadir = $datadir -sysconfdir = $sysconfdir -sharedstatedir = $sharedstatedir -localstatedir = $localstatedir -runstatedir = $runstatedir -includedir = $includedir -oldincludedir = $oldincludedir -docdir = $docdir -infodir = $infodir -htmldir = $htmldir -dvidir = $dvidir -pdfdir = $pdfdir -psdir = $psdir -libdir = $libdir -localedir = $localedir -mandir = $mandir -DEFS = $DEFS -ECHO_C = $ECHO_C -ECHO_N = $ECHO_N -ECHO_T = $ECHO_T -LIBS = $LIBS -build_alias = $build_alias -host_alias = $host_alias -target_alias = $target_alias -system_dllpath = $system_dllpath -build = $build -build_cpu = $build_cpu -build_vendor = $build_vendor -build_os = $build_os -host = $host -host_cpu = $host_cpu -host_vendor = $host_vendor -host_os = $host_os -srcdir = $srcdir -SARIF_CONVERTER = $SARIF_CONVERTER -CC = $CC -CFLAGS = $CFLAGS -LDFLAGS = $LDFLAGS -CPPFLAGS = $CPPFLAGS -ac_ct_CC = $ac_ct_CC -EXEEXT = $EXEEXT -OBJEXT = $OBJEXT -CXX = $CXX -CXXFLAGS = $CXXFLAGS -ac_ct_CXX = $ac_ct_CXX -CPPBIN = $CPPBIN -LD = $LD -TARGETFLAGS = $TARGETFLAGS -toolsext = $toolsext -HOST_ARCH = $HOST_ARCH -aarch64_CC = $aarch64_CC -aarch64_CFLAGS = $aarch64_CFLAGS -aarch64_EXTRACFLAGS = $aarch64_EXTRACFLAGS -aarch64_LDFLAGS = $aarch64_LDFLAGS -aarch64_DEBUG = $aarch64_DEBUG -aarch64_TARGET = $aarch64_TARGET -aarch64_STRIP = $aarch64_STRIP -aarch64_DELAYLOADFLAG = $aarch64_DELAYLOADFLAG -aarch64_DISABLED_SUBDIRS = $aarch64_DISABLED_SUBDIRS -arm_CC = $arm_CC -arm_CFLAGS = $arm_CFLAGS -arm_EXTRACFLAGS = $arm_EXTRACFLAGS -arm_LDFLAGS = $arm_LDFLAGS -arm_DEBUG = $arm_DEBUG -arm_TARGET = $arm_TARGET -arm_STRIP = $arm_STRIP -arm_DELAYLOADFLAG = $arm_DELAYLOADFLAG -arm_DISABLED_SUBDIRS = $arm_DISABLED_SUBDIRS -arm64ec_CC = $arm64ec_CC -arm64ec_CFLAGS = $arm64ec_CFLAGS -arm64ec_EXTRACFLAGS = $arm64ec_EXTRACFLAGS -arm64ec_LDFLAGS = $arm64ec_LDFLAGS -arm64ec_DEBUG = $arm64ec_DEBUG -arm64ec_TARGET = $arm64ec_TARGET -arm64ec_STRIP = $arm64ec_STRIP -arm64ec_DELAYLOADFLAG = $arm64ec_DELAYLOADFLAG -arm64ec_DISABLED_SUBDIRS = $arm64ec_DISABLED_SUBDIRS -i386_CC = $i386_CC -i386_CFLAGS = $i386_CFLAGS -i386_EXTRACFLAGS = $i386_EXTRACFLAGS -i386_LDFLAGS = $i386_LDFLAGS -i386_DEBUG = $i386_DEBUG -i386_TARGET = $i386_TARGET -i386_STRIP = $i386_STRIP -i386_DELAYLOADFLAG = $i386_DELAYLOADFLAG -i386_DISABLED_SUBDIRS = $i386_DISABLED_SUBDIRS -x86_64_CC = $x86_64_CC -x86_64_CFLAGS = $x86_64_CFLAGS -x86_64_EXTRACFLAGS = $x86_64_EXTRACFLAGS -x86_64_LDFLAGS = $x86_64_LDFLAGS -x86_64_DEBUG = $x86_64_DEBUG -x86_64_TARGET = $x86_64_TARGET -x86_64_STRIP = $x86_64_STRIP -x86_64_DELAYLOADFLAG = $x86_64_DELAYLOADFLAG -x86_64_DISABLED_SUBDIRS = $x86_64_DISABLED_SUBDIRS -toolsdir = $toolsdir -RUNTESTFLAGS = $RUNTESTFLAGS -SED_CMD = $SED_CMD -FLEX = $FLEX -BISON = $BISON -STRIP = $STRIP -LN_S = $LN_S -PKG_CONFIG = $PKG_CONFIG -FONTFORGE = $FONTFORGE -RSVG = $RSVG -CONVERT = $CONVERT -ICOTOOL = $ICOTOOL -MSGFMT = $MSGFMT -I386_LIBS = $I386_LIBS -OPENGL_LIBS = $OPENGL_LIBS -DLLFLAGS = $DLLFLAGS -LDDLLFLAGS = $LDDLLFLAGS -LDEXECFLAGS = $LDEXECFLAGS -EXTRACFLAGS = $EXTRACFLAGS -UNIXDLLFLAGS = $UNIXDLLFLAGS -UNIXLDFLAGS = $UNIXLDFLAGS -TOP_INSTALL_LIB = $TOP_INSTALL_LIB -TOP_INSTALL_DEV = $TOP_INSTALL_DEV -WINELOADER_LDFLAGS = $WINELOADER_LDFLAGS -WINEPRELOADER_LDFLAGS = $WINEPRELOADER_LDFLAGS -DLLEXT = $DLLEXT -LDD = $LDD -OTOOL = $OTOOL -READELF = $READELF -SUBDIRS = $SUBDIRS -DISABLED_SUBDIRS = $DISABLED_SUBDIRS -CONFIGURE_TARGETS = $CONFIGURE_TARGETS -CARBON_LIBS = $CARBON_LIBS -COREFOUNDATION_LIBS = $COREFOUNDATION_LIBS -DISKARBITRATION_LIBS = $DISKARBITRATION_LIBS -IOKIT_LIBS = $IOKIT_LIBS -METAL_LIBS = $METAL_LIBS -APPLICATIONSERVICES_LIBS = $APPLICATIONSERVICES_LIBS -CORESERVICES_LIBS = $CORESERVICES_LIBS -APPKIT_LIBS = $APPKIT_LIBS -SECURITY_LIBS = $SECURITY_LIBS -SYSTEMCONFIGURATION_LIBS = $SYSTEMCONFIGURATION_LIBS -COREAUDIO_LIBS = $COREAUDIO_LIBS -OPENCL_LIBS = $OPENCL_LIBS -OBJC = $OBJC -OBJCFLAGS = $OBJCFLAGS -ac_ct_OBJC = $ac_ct_OBJC -WINELOADER_DEPENDS = $WINELOADER_DEPENDS -PE_ARCHS = $PE_ARCHS -MINGW_PKG_CONFIG = $MINGW_PKG_CONFIG -CAPSTONE_PE_CFLAGS = $CAPSTONE_PE_CFLAGS -CAPSTONE_PE_LIBS = $CAPSTONE_PE_LIBS -FAUDIO_PE_CFLAGS = $FAUDIO_PE_CFLAGS -FAUDIO_PE_LIBS = $FAUDIO_PE_LIBS -FLUIDSYNTH_PE_CFLAGS = $FLUIDSYNTH_PE_CFLAGS -FLUIDSYNTH_PE_LIBS = $FLUIDSYNTH_PE_LIBS -GSM_PE_CFLAGS = $GSM_PE_CFLAGS -GSM_PE_LIBS = $GSM_PE_LIBS -JPEG_PE_CFLAGS = $JPEG_PE_CFLAGS -JPEG_PE_LIBS = $JPEG_PE_LIBS -JXR_PE_CFLAGS = $JXR_PE_CFLAGS -JXR_PE_LIBS = $JXR_PE_LIBS -LCMS2_PE_CFLAGS = $LCMS2_PE_CFLAGS -LCMS2_PE_LIBS = $LCMS2_PE_LIBS -LDAP_PE_CFLAGS = $LDAP_PE_CFLAGS -LDAP_PE_LIBS = $LDAP_PE_LIBS -MPG123_PE_CFLAGS = $MPG123_PE_CFLAGS -MPG123_PE_LIBS = $MPG123_PE_LIBS -MUSL_PE_CFLAGS = $MUSL_PE_CFLAGS -MUSL_PE_LIBS = $MUSL_PE_LIBS -PNG_PE_CFLAGS = $PNG_PE_CFLAGS -PNG_PE_LIBS = $PNG_PE_LIBS -TIFF_PE_CFLAGS = $TIFF_PE_CFLAGS -TIFF_PE_LIBS = $TIFF_PE_LIBS -VKD3D_PE_CFLAGS = $VKD3D_PE_CFLAGS -VKD3D_PE_LIBS = $VKD3D_PE_LIBS -XML2_PE_CFLAGS = $XML2_PE_CFLAGS -XML2_PE_LIBS = $XML2_PE_LIBS -XSLT_PE_CFLAGS = $XSLT_PE_CFLAGS -XSLT_PE_LIBS = $XSLT_PE_LIBS -ZLIB_PE_CFLAGS = $ZLIB_PE_CFLAGS -ZLIB_PE_LIBS = $ZLIB_PE_LIBS -PTHREAD_LIBS = $PTHREAD_LIBS -XMKMF = $XMKMF -CPP = $CPP -X_CFLAGS = $X_CFLAGS -X_LIBS = $X_LIBS -WAYLAND_CLIENT_CFLAGS = $WAYLAND_CLIENT_CFLAGS -WAYLAND_CLIENT_LIBS = $WAYLAND_CLIENT_LIBS -WAYLAND_SCANNER = $WAYLAND_SCANNER -XKBCOMMON_CFLAGS = $XKBCOMMON_CFLAGS -XKBCOMMON_LIBS = $XKBCOMMON_LIBS -XKBREGISTRY_CFLAGS = $XKBREGISTRY_CFLAGS -XKBREGISTRY_LIBS = $XKBREGISTRY_LIBS -EGL_CFLAGS = $EGL_CFLAGS -EGL_LIBS = $EGL_LIBS -WAYLAND_EGL_CFLAGS = $WAYLAND_EGL_CFLAGS -WAYLAND_EGL_LIBS = $WAYLAND_EGL_LIBS -PCAP_LIBS = $PCAP_LIBS -PCSCLITE_LIBS = $PCSCLITE_LIBS -INOTIFY_CFLAGS = $INOTIFY_CFLAGS -INOTIFY_LIBS = $INOTIFY_LIBS -DBUS_CFLAGS = $DBUS_CFLAGS -DBUS_LIBS = $DBUS_LIBS -GNUTLS_CFLAGS = $GNUTLS_CFLAGS -GNUTLS_LIBS = $GNUTLS_LIBS -SANE_CFLAGS = $SANE_CFLAGS -SANE_LIBS = $SANE_LIBS -USB_CFLAGS = $USB_CFLAGS -USB_LIBS = $USB_LIBS -GPHOTO2_CFLAGS = $GPHOTO2_CFLAGS -GPHOTO2_LIBS = $GPHOTO2_LIBS -GPHOTO2_PORT_CFLAGS = $GPHOTO2_PORT_CFLAGS -GPHOTO2_PORT_LIBS = $GPHOTO2_PORT_LIBS -RESOLV_LIBS = $RESOLV_LIBS -FREETYPE_CFLAGS = $FREETYPE_CFLAGS -FREETYPE_LIBS = $FREETYPE_LIBS -GETTEXTPO_LIBS = $GETTEXTPO_LIBS -PULSE_CFLAGS = $PULSE_CFLAGS -PULSE_LIBS = $PULSE_LIBS -FFMPEG_CFLAGS = $FFMPEG_CFLAGS -FFMPEG_LIBS = $FFMPEG_LIBS -GSTREAMER_CFLAGS = $GSTREAMER_CFLAGS -GSTREAMER_LIBS = $GSTREAMER_LIBS -ALSA_LIBS = $ALSA_LIBS -OSS4_CFLAGS = $OSS4_CFLAGS -OSS4_LIBS = $OSS4_LIBS -UDEV_CFLAGS = $UDEV_CFLAGS -UDEV_LIBS = $UDEV_LIBS -UNWIND_CFLAGS = $UNWIND_CFLAGS -UNWIND_LIBS = $UNWIND_LIBS -SDL2_CFLAGS = $SDL2_CFLAGS -SDL2_LIBS = $SDL2_LIBS -CAPI20_CFLAGS = $CAPI20_CFLAGS -CAPI20_LIBS = $CAPI20_LIBS -CUPS_CFLAGS = $CUPS_CFLAGS -CUPS_LIBS = $CUPS_LIBS -FONTCONFIG_CFLAGS = $FONTCONFIG_CFLAGS -FONTCONFIG_LIBS = $FONTCONFIG_LIBS -KRB5_CFLAGS = $KRB5_CFLAGS -KRB5_LIBS = $KRB5_LIBS -GSSAPI_CFLAGS = $GSSAPI_CFLAGS -GSSAPI_LIBS = $GSSAPI_LIBS -PROCSTAT_LIBS = $PROCSTAT_LIBS -NETAPI_CFLAGS = $NETAPI_CFLAGS -NETAPI_LIBS = $NETAPI_LIBS -MSVCRTFLAGS = $MSVCRTFLAGS -DELAYLOADFLAG = $DELAYLOADFLAG -WINELOADER_PROGRAMS = $WINELOADER_PROGRAMS -RT_LIBS = $RT_LIBS -TAGSFLAGS = $TAGSFLAGS -LIBOBJS = $LIBOBJS -LTLIBOBJS = $LTLIBOBJS -$SET_MAKE -$wine_rules -_WINE_EOF - as_fn_error $? "could not create Makefile" "$LINENO" 5 -} - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "include/config.h") CONFIG_HEADERS="$CONFIG_HEADERS include/config.h" ;; - "include/stamp-h") CONFIG_COMMANDS="$CONFIG_COMMANDS include/stamp-h" ;; - "wine") CONFIG_LINKS="$CONFIG_LINKS wine:tools/winewrapper" ;; - "wine64") CONFIG_LINKS="$CONFIG_LINKS wine64:tools/winewrapper" ;; - "tools/makedep") CONFIG_COMMANDS="$CONFIG_COMMANDS tools/makedep" ;; - "Makefile") CONFIG_COMMANDS="$CONFIG_COMMANDS Makefile" ;; - - *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers - test ${CONFIG_LINKS+y} || CONFIG_LINKS=$config_links - test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to '$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with './config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script 'defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >$CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - # Preserve the white space surrounding the "#". - print prefix "define", macro P[macro] D[macro] - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :H $CONFIG_HEADERS :L $CONFIG_LINKS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain ':'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is 'configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -printf "%s\n" "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`printf "%s\n" "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - printf "%s\n" "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - printf "%s\n" "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi - ;; - :L) - # - # CONFIG_LINK - # - - if test "$ac_source" = "$ac_file" && test "$srcdir" = '.'; then - : - else - # Prefer the file from the source tree if names are identical. - if test "$ac_source" = "$ac_file" || test ! -r "$ac_source"; then - ac_source=$srcdir/$ac_source - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: linking $ac_source to $ac_file" >&5 -printf "%s\n" "$as_me: linking $ac_source to $ac_file" >&6;} - - if test ! -r "$ac_source"; then - as_fn_error $? "$ac_source: file not found" "$LINENO" 5 - fi - rm -f "$ac_file" - - # Try a relative symlink, then a hard link, then a copy. - case $ac_source in - [\\/$]* | ?:[\\/]* ) ac_rel_source=$ac_source ;; - *) ac_rel_source=$ac_top_build_prefix$ac_source ;; - esac - ln -s "$ac_rel_source" "$ac_file" 2>/dev/null || - ln "$ac_source" "$ac_file" 2>/dev/null || - cp -p "$ac_source" "$ac_file" || - as_fn_error $? "cannot link or copy $ac_source to $ac_file" "$LINENO" 5 - fi - ;; - :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -printf "%s\n" "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "include/stamp-h":C) echo timestamp > include/stamp-h ;; - "tools/makedep":C) wine_fn_output_makedep || as_fn_exit $? ;; - "Makefile":C) wine_fn_output_makefile Makefile ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - - -if test "$no_create" = "yes" -then - exit 0 -fi - -ac_save_IFS="$IFS" -if test "x$wine_notices" != x; then - echo >&6 - IFS="|" - for msg in $wine_notices; do - IFS="$ac_save_IFS" - if ${msg:+false} : -then : - -else case e in #( - e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $msg" >&5 -printf "%s\n" "$as_me: $msg" >&6;} ;; -esac -fi - done -fi -IFS="|" -for msg in $wine_warnings; do - IFS="$ac_save_IFS" - if ${msg:+false} : -then : - -else case e in #( - e) echo >&2 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $msg" >&5 -printf "%s\n" "$as_me: WARNING: $msg" >&2;} ;; -esac -fi -done -IFS="$ac_save_IFS" - -printf "%s\n" " -$as_me: Finished. Do '${MAKE-make}' to compile Wine. -" >&6 - - diff --git a/configure.ac b/configure.ac index b999e3506e0e..5fbc2890d73a 100644 --- a/configure.ac +++ b/configure.ac @@ -33,6 +33,7 @@ AC_ARG_WITH(dbus, AS_HELP_STRING([--without-dbus],[do not use DBus (dynamic AC_ARG_WITH(ffmpeg, AS_HELP_STRING([--without-ffmpeg],[do not use the FFmpeg library])) AC_ARG_WITH(fontconfig,AS_HELP_STRING([--without-fontconfig],[do not use fontconfig])) AC_ARG_WITH(freetype, AS_HELP_STRING([--without-freetype],[do not use the FreeType library])) +AC_ARG_WITH(gcrypt, AS_HELP_STRING([--without-gcrypt],[do not use libgcrypt])) AC_ARG_WITH(gettext, AS_HELP_STRING([--without-gettext],[do not use gettext])) AC_ARG_WITH(gettextpo, AS_HELP_STRING([--with-gettextpo],[use the GetTextPO library to rebuild po files]), [if test "x$withval" = "xno"; then ac_cv_header_gettext_po_h=no; fi]) @@ -52,6 +53,7 @@ AC_ARG_WITH(oss, AS_HELP_STRING([--without-oss],[do not use the OSS sound AC_ARG_WITH(pcap, AS_HELP_STRING([--without-pcap],[do not use the Packet Capture library]), [if test "x$withval" = "xno"; then ac_cv_header_pcap_pcap_h=no; fi]) AC_ARG_WITH(pcsclite, AS_HELP_STRING([--without-pcsclite],[do not use PCSC lite])) +AC_ARG_WITH(piper, AS_HELP_STRING([--without-piper],[do not use the Piper TTS library])) AC_ARG_WITH(pthread, AS_HELP_STRING([--without-pthread],[do not use the pthread library])) AC_ARG_WITH(pulse, AS_HELP_STRING([--without-pulse],[do not use PulseAudio sound support])) AC_ARG_WITH(sane, AS_HELP_STRING([--without-sane],[do not use SANE (scanner support)])) @@ -60,6 +62,7 @@ AC_ARG_WITH(udev, AS_HELP_STRING([--without-udev],[do not use udev (plug an AC_ARG_WITH(unwind, AS_HELP_STRING([--without-unwind],[do not use the libunwind library (exception handling)])) AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use the libusb library])) AC_ARG_WITH(v4l2, AS_HELP_STRING([--without-v4l2],[do not use v4l2 (video capture)])) +AC_ARG_WITH(vosk, AS_HELP_STRING([--without-vosk],[do not use Vosk])) AC_ARG_WITH(vulkan, AS_HELP_STRING([--without-vulkan],[do not use Vulkan])) AC_ARG_WITH(wayland, AS_HELP_STRING([--without-wayland],[do not build the Wayland driver])) AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]), @@ -175,7 +178,7 @@ case "$host_cpu" in x86_64) HOST_ARCH=x86_64 ;; esac m4_set_add_all([_AC_SUBST_VARS],[HOST_ARCH]m4_foreach([cpu],[aarch64,arm,arm64ec,i386,x86_64], - [m4_foreach([var],[CC,CFLAGS,EXTRACFLAGS,LDFLAGS,DEBUG,TARGET,STRIP,DELAYLOADFLAG,DISABLED_SUBDIRS],[,cpu[_]var])])) + [m4_foreach([var],[CC,CFLAGS,EXTRACFLAGS,CXXFLAGS,LDFLAGS,DEBUG,TARGET,STRIP,DELAYLOADFLAG,DISABLED_SUBDIRS],[,cpu[_]var])])) AC_CACHE_CHECK([for the directory containing the Wine tools], wine_cv_toolsdir, [wine_cv_toolsdir="$with_wine_tools" @@ -370,6 +373,7 @@ AC_CHECK_HEADERS(\ OpenCL/opencl.h \ arpa/inet.h \ arpa/nameser.h \ + asm/hwcap.h \ asm/termbits.h \ asm/types.h \ asm/user.h \ @@ -378,12 +382,14 @@ AC_CHECK_HEADERS(\ link.h \ linux/cdrom.h \ linux/filter.h \ + linux/futex.h \ linux/hdreg.h \ linux/hidraw.h \ linux/input.h \ linux/ioctl.h \ linux/major.h \ linux/param.h \ + linux/seccomp.h \ linux/serial.h \ linux/types.h \ linux/ucdrom.h \ @@ -411,6 +417,7 @@ AC_CHECK_HEADERS(\ sys/cdio.h \ sys/epoll.h \ sys/event.h \ + sys/eventfd.h \ sys/extattr.h \ sys/filio.h \ sys/ipc.h \ @@ -441,7 +448,8 @@ AC_CHECK_HEADERS(\ syscall.h \ utime.h \ valgrind/memcheck.h \ - valgrind/valgrind.h + valgrind/valgrind.h \ + vosk_api.h ) AC_HEADER_MAJOR() @@ -1177,6 +1185,7 @@ WINE_EXTLIB_FLAGS(MPG123, mpg123, mpg123, "-I\$(top_srcdir)/libs/mpg123/src/incl WINE_EXTLIB_FLAGS(MUSL, musl, musl) WINE_EXTLIB_FLAGS(PNG, png, "png \$(ZLIB_PE_LIBS)", "-I\$(top_srcdir)/libs/png") WINE_EXTLIB_FLAGS(TIFF, tiff, "tiff \$(ZLIB_PE_LIBS)", "-I\$(top_srcdir)/libs/tiff/libtiff") +WINE_EXTLIB_FLAGS(TOMCRYPT, tomcrypt, tomcrypt, "-I\$(top_srcdir)/libs/tomcrypt/src/headers -DLTC_NO_PROTOTYPES -DLTC_SOURCE") WINE_EXTLIB_FLAGS(VKD3D, vkd3d, vkd3d, "-I\$(top_srcdir)/libs/vkd3d/include") WINE_EXTLIB_FLAGS(XML2, xml2, xml2, "-I\$(top_srcdir)/libs/xml2/include -DLIBXML_STATIC") WINE_EXTLIB_FLAGS(XSLT, xslt, xslt, "-I\$(top_srcdir)/libs/xslt/libxslt -I\$(top_srcdir)/libs/xslt -DLIBXSLT_STATIC") @@ -1210,6 +1219,7 @@ then dnl *** All of the following tests require X11/Xlib.h AC_CHECK_HEADERS([X11/extensions/shape.h \ + X11/extensions/XInput.h \ X11/extensions/XInput2.h \ X11/extensions/XShm.h \ X11/extensions/Xfixes.h \ @@ -1410,15 +1420,6 @@ else [enable_winex11_drv]) fi -dnl **** Check for OpenCL **** -if test "$ac_cv_header_CL_cl_h" = "yes" -then - AC_CHECK_LIB(OpenCL,clGetPlatformInfo,[AC_SUBST(OPENCL_LIBS,["-lOpenCL"])]) -fi -WINE_NOTICE_WITH(opencl,[test "x$ac_cv_lib_OpenCL_clGetPlatformInfo" != xyes], - [OpenCL ${notice_platform}development files not found, OpenCL won't be supported.], - [enable_opencl]) - dnl **** Check for libpcap **** if test "$ac_cv_header_pcap_pcap_h" = "yes" then @@ -1479,6 +1480,23 @@ fi WINE_WARNING_WITH(gnutls,[test "x$ac_cv_lib_soname_gnutls" = "x"], [libgnutls ${notice_platform}development files not found, no schannel support.]) +dnl **** Check for libdrm **** +WINE_PACKAGE_FLAGS(DRM,[libdrm],,,, + [AC_CHECK_HEADERS([xf86drm.h], + [WINE_CHECK_SONAME(drm,drmOpen,,,[$DRM_LIBS])])]) + +WINE_PACKAGE_FLAGS(DRMAMDGPU,[libdrm_amdgpu],,,, + [AC_CHECK_HEADERS([amdgpu_drm.h], + [WINE_CHECK_SONAME(drm_amdgpu,amdgpu_query_info,,,[$DRMAMDGPU_LIBS])])]) + +dnl **** Check for libgmp **** +if test "x$with_gnutls" != "xno" +then + WINE_PACKAGE_FLAGS(GMP,[gmp],[-lgmp],,, + [AC_CHECK_HEADERS([gmp.h], + [WINE_CHECK_SONAME(gmp,__gmpz_init,,[GMP_CFLAGS=""],[$GMP_LIBS],[[libgmp-*]])])]) +fi + dnl **** Check for SANE **** if test "x$with_sane" != "xno" then @@ -1654,7 +1672,7 @@ WINE_NOTICE_WITH(ffmpeg,[test "x$FFMPEG_LIBS" = x], dnl **** Check for gstreamer **** if test "x$with_gstreamer" != "xno" then - WINE_PACKAGE_FLAGS(GSTREAMER,[gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 gstreamer-tag-1.0],,,, + WINE_PACKAGE_FLAGS(GSTREAMER,[gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 gstreamer-tag-1.0 gstreamer-gl-1.0],,,, [AC_CHECK_HEADER([gst/gst.h], [AC_MSG_CHECKING([whether gint64 defined by gst/gst.h is indeed 64-bit]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], @@ -1871,6 +1889,14 @@ then WINE_WARNING([No sound system was found. Windows applications will be silent.]) fi +dnl **** Check for Vosk **** +if test x$with_vosk != xno +then + WINE_CHECK_SONAME(vosk,vosk_recognizer_new) +fi +WINE_NOTICE_WITH(vosk,[test x$ac_cv_lib_soname_vosk = x], + [libvosk ${notice_platform}development files not found, speech recognition won't be supported.]) + dnl *** Check for Vulkan *** if test "x$with_vulkan" != "xno" then @@ -1883,6 +1909,31 @@ fi WINE_NOTICE_WITH(vulkan,[test "x$ac_cv_lib_soname_vulkan" = "x" -a "x$ac_cv_lib_soname_MoltenVK" = "x"], [libvulkan and libMoltenVK ${notice_platform}development files not found, Vulkan won't be supported.]) +dnl **** Check for gcrypt **** +if test "x$with_gcrypt" != "xno" +then + WINE_PACKAGE_FLAGS(GCRYPT,[libgcrypt],,,, + [AC_CHECK_HEADERS([gcrypt.h]) + if test "$ac_cv_header_gcrypt_h" = "yes" + then + WINE_CHECK_SONAME(gcrypt,gcry_sexp_build,,,[$GCRYPT_LIBS]) + fi]) +fi +WINE_NOTICE_WITH(gcrypt,[test "x$ac_cv_lib_soname_gcrypt" = "x"], + [libgcrypt ${notice_platform}development files not found, GCRYPT won't be supported.]) + +dnl **** Check for libpiper **** +if test "x$with_piper" != "xno" +then + WINE_PACKAGE_FLAGS(PIPER,[piper],[-lpiper],,, + [AC_CHECK_HEADER(piper/piper_c.h, + [AC_CHECK_LIB(piper,piperInitialize,[:],[PIPER_LIBS=""],[$PIPER_LIBS])], + [PIPER_LIBS=""])]) +fi +WINE_NOTICE_WITH(piper,[test "$ac_cv_lib_piper_piperInitialize" != "yes"], + [libpiper ${notice_platform}development files not found, protontts won't be supported.], + [enable_protontts]) + dnl **** Check for gcc specific options **** if test "x${GCC}" = "xyes" @@ -2079,6 +2130,7 @@ AC_CHECK_FUNCS(\ port_create \ posix_fadvise \ posix_fallocate \ + ppoll \ prctl \ sched_getcpu \ sched_yield \ @@ -2098,6 +2150,12 @@ AC_SEARCH_LIBS(clock_gettime, rt, test "$ac_res" = "none required" || AC_SUBST(RT_LIBS,"$ac_res")]) LIBS=$ac_save_LIBS +ac_save_LIBS=$LIBS +AC_SEARCH_LIBS(shm_open, rt, + [AC_DEFINE(HAVE_SHM_OPEN, 1, [Define to 1 if you have the `shm_open' function.]) + test "$ac_res" = "none required" || AC_SUBST(RT_LIBS,"$ac_res")]) +LIBS=$ac_save_LIBS + AC_CACHE_CHECK([for sched_setaffinity],wine_cv_have_sched_setaffinity, AC_LINK_IFELSE([AC_LANG_PROGRAM( [[#include ]], [[sched_setaffinity(0, 0, 0);]])],[wine_cv_have_sched_setaffinity=yes],[wine_cv_have_sched_setaffinity=no])) @@ -2338,7 +2396,7 @@ esac dnl *** Check for modules to disable by default enable_win16=${enable_win16:-i386} -enable_vcruntime140_1=${enable_vcruntime140_1:-x86_64,arm64ec} +enable_vcruntime140_1=${enable_vcruntime140_1:-x86_64,arm64ec,aarch64} if test -n "$PE_ARCHS" then @@ -2356,7 +2414,7 @@ fi dnl Explicitly enable some programs for arm64ec enable_cmd=${enable_cmd:-yes} enable_dllhost=${enable_dllhost:-yes} -enable_dpnsvr=${enable_dpnsvr:-i386,x86_64,arm64ec} +enable_dpnsvr=${enable_dpnsvr:-i386,x86_64,arm64ec,aarch64} enable_dxdiag=${enable_dxdiag:-yes} enable_msiexec=${enable_msiexec:-yes} enable_netsh=${enable_netsh:-yes} @@ -2398,6 +2456,8 @@ WINE_CONFIG_MAKEFILE(dlls/advapi32/tests) WINE_CONFIG_MAKEFILE(dlls/advpack) WINE_CONFIG_MAKEFILE(dlls/advpack/tests) WINE_CONFIG_MAKEFILE(dlls/amsi) +WINE_CONFIG_MAKEFILE(dlls/amd_ags_x64) +WINE_CONFIG_MAKEFILE(dlls/amdxc64) WINE_CONFIG_MAKEFILE(dlls/amstream) WINE_CONFIG_MAKEFILE(dlls/amstream/tests) WINE_CONFIG_MAKEFILE(dlls/apisetschema) @@ -2405,6 +2465,7 @@ WINE_CONFIG_MAKEFILE(dlls/apphelp) WINE_CONFIG_MAKEFILE(dlls/apphelp/tests) WINE_CONFIG_MAKEFILE(dlls/appwiz.cpl) WINE_CONFIG_MAKEFILE(dlls/appxdeploymentclient) +WINE_CONFIG_MAKEFILE(dlls/atiadlxx) WINE_CONFIG_MAKEFILE(dlls/atl) WINE_CONFIG_MAKEFILE(dlls/atl/tests) WINE_CONFIG_MAKEFILE(dlls/atl100) @@ -2417,6 +2478,7 @@ WINE_CONFIG_MAKEFILE(dlls/atl90) WINE_CONFIG_MAKEFILE(dlls/atlthunk) WINE_CONFIG_MAKEFILE(dlls/atlthunk/tests) WINE_CONFIG_MAKEFILE(dlls/atmlib) +WINE_CONFIG_MAKEFILE(dlls/audioses) WINE_CONFIG_MAKEFILE(dlls/authz) WINE_CONFIG_MAKEFILE(dlls/avicap32) WINE_CONFIG_MAKEFILE(dlls/avifil32) @@ -2670,6 +2732,7 @@ WINE_CONFIG_MAKEFILE(dlls/fontsub) WINE_CONFIG_MAKEFILE(dlls/fusion) WINE_CONFIG_MAKEFILE(dlls/fusion/tests) WINE_CONFIG_MAKEFILE(dlls/fwpuclnt) +WINE_CONFIG_MAKEFILE(dlls/gameinput) WINE_CONFIG_MAKEFILE(dlls/gameux) WINE_CONFIG_MAKEFILE(dlls/gameux/tests) WINE_CONFIG_MAKEFILE(dlls/gamingtcui) @@ -2707,6 +2770,7 @@ WINE_CONFIG_MAKEFILE(dlls/iccvid) WINE_CONFIG_MAKEFILE(dlls/icmp) WINE_CONFIG_MAKEFILE(dlls/icmui) WINE_CONFIG_MAKEFILE(dlls/icmui/tests) +WINE_CONFIG_MAKEFILE(dlls/icu) WINE_CONFIG_MAKEFILE(dlls/ieframe) WINE_CONFIG_MAKEFILE(dlls/ieframe/tests) WINE_CONFIG_MAKEFILE(dlls/ieproxy) @@ -2732,7 +2796,6 @@ WINE_CONFIG_MAKEFILE(dlls/inseng) WINE_CONFIG_MAKEFILE(dlls/iphlpapi) WINE_CONFIG_MAKEFILE(dlls/iphlpapi/tests) WINE_CONFIG_MAKEFILE(dlls/iprop) -WINE_CONFIG_MAKEFILE(dlls/ir50_32) WINE_CONFIG_MAKEFILE(dlls/irprops.cpl) WINE_CONFIG_MAKEFILE(dlls/itircl) WINE_CONFIG_MAKEFILE(dlls/itss) @@ -2920,6 +2983,7 @@ WINE_CONFIG_MAKEFILE(dlls/msvfw32) WINE_CONFIG_MAKEFILE(dlls/msvfw32/tests) WINE_CONFIG_MAKEFILE(dlls/msvidc32) WINE_CONFIG_MAKEFILE(dlls/msvideo.dll16,enable_win16) +WINE_CONFIG_MAKEFILE(dlls/msvdsp) WINE_CONFIG_MAKEFILE(dlls/msvproc) WINE_CONFIG_MAKEFILE(dlls/mswsock) WINE_CONFIG_MAKEFILE(dlls/msxml) @@ -2961,6 +3025,7 @@ WINE_CONFIG_MAKEFILE(dlls/ntoskrnl.exe) WINE_CONFIG_MAKEFILE(dlls/ntoskrnl.exe/tests) WINE_CONFIG_MAKEFILE(dlls/ntprint) WINE_CONFIG_MAKEFILE(dlls/ntprint/tests) +WINE_CONFIG_MAKEFILE(dlls/nvcuda) WINE_CONFIG_MAKEFILE(dlls/objsel) WINE_CONFIG_MAKEFILE(dlls/odbc32) WINE_CONFIG_MAKEFILE(dlls/odbc32/tests) @@ -3008,6 +3073,7 @@ WINE_CONFIG_MAKEFILE(dlls/prntvpt/tests) WINE_CONFIG_MAKEFILE(dlls/profapi) WINE_CONFIG_MAKEFILE(dlls/propsys) WINE_CONFIG_MAKEFILE(dlls/propsys/tests) +WINE_CONFIG_MAKEFILE(dlls/protontts) WINE_CONFIG_MAKEFILE(dlls/psapi) WINE_CONFIG_MAKEFILE(dlls/psapi/tests) WINE_CONFIG_MAKEFILE(dlls/pstorec) @@ -3080,6 +3146,7 @@ WINE_CONFIG_MAKEFILE(dlls/setupapi/tests) WINE_CONFIG_MAKEFILE(dlls/setupx.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/sfc) WINE_CONFIG_MAKEFILE(dlls/sfc_os) +WINE_CONFIG_MAKEFILE(dlls/sharedgpures.sys) WINE_CONFIG_MAKEFILE(dlls/shcore) WINE_CONFIG_MAKEFILE(dlls/shcore/tests) WINE_CONFIG_MAKEFILE(dlls/shdoclc) @@ -3124,6 +3191,7 @@ WINE_CONFIG_MAKEFILE(dlls/taskschd) WINE_CONFIG_MAKEFILE(dlls/taskschd/tests) WINE_CONFIG_MAKEFILE(dlls/tbs) WINE_CONFIG_MAKEFILE(dlls/tdh) +WINE_CONFIG_MAKEFILE(dlls/tdh/tests) WINE_CONFIG_MAKEFILE(dlls/tdi.sys) WINE_CONFIG_MAKEFILE(dlls/threadpoolwinrt) WINE_CONFIG_MAKEFILE(dlls/threadpoolwinrt/tests) @@ -3161,6 +3229,8 @@ WINE_CONFIG_MAKEFILE(dlls/uxtheme) WINE_CONFIG_MAKEFILE(dlls/uxtheme/tests) WINE_CONFIG_MAKEFILE(dlls/vbscript) WINE_CONFIG_MAKEFILE(dlls/vbscript/tests) +WINE_CONFIG_MAKEFILE(dlls/vccorlib140) +WINE_CONFIG_MAKEFILE(dlls/vccorlib140/tests) WINE_CONFIG_MAKEFILE(dlls/vcomp) WINE_CONFIG_MAKEFILE(dlls/vcomp/tests) WINE_CONFIG_MAKEFILE(dlls/vcomp100) @@ -3177,6 +3247,7 @@ WINE_CONFIG_MAKEFILE(dlls/ver.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/version) WINE_CONFIG_MAKEFILE(dlls/version/tests) WINE_CONFIG_MAKEFILE(dlls/vga) +WINE_CONFIG_MAKEFILE(dlls/vidreszr) WINE_CONFIG_MAKEFILE(dlls/virtdisk) WINE_CONFIG_MAKEFILE(dlls/virtdisk/tests) WINE_CONFIG_MAKEFILE(dlls/vmm.vxd,enable_win16) @@ -3246,6 +3317,8 @@ WINE_CONFIG_MAKEFILE(dlls/windows.security.credentials.ui.userconsentverifier) WINE_CONFIG_MAKEFILE(dlls/windows.security.credentials.ui.userconsentverifier/tests) WINE_CONFIG_MAKEFILE(dlls/windows.storage.applicationdata) WINE_CONFIG_MAKEFILE(dlls/windows.storage.applicationdata/tests) +WINE_CONFIG_MAKEFILE(dlls/windows.storage) +WINE_CONFIG_MAKEFILE(dlls/windows.storage/tests) WINE_CONFIG_MAKEFILE(dlls/windows.system.profile.systemmanufacturers) WINE_CONFIG_MAKEFILE(dlls/windows.system.profile.systemmanufacturers/tests) WINE_CONFIG_MAKEFILE(dlls/windows.ui) @@ -3418,6 +3491,7 @@ WINE_CONFIG_MAKEFILE(libs/png) WINE_CONFIG_MAKEFILE(libs/strmbase) WINE_CONFIG_MAKEFILE(libs/strmiids) WINE_CONFIG_MAKEFILE(libs/tiff) +WINE_CONFIG_MAKEFILE(libs/tomcrypt) WINE_CONFIG_MAKEFILE(libs/uuid) WINE_CONFIG_MAKEFILE(libs/vkd3d) WINE_CONFIG_MAKEFILE(libs/wbemuuid) @@ -3431,6 +3505,7 @@ WINE_CONFIG_MAKEFILE(po) WINE_CONFIG_MAKEFILE(programs/arp) WINE_CONFIG_MAKEFILE(programs/aspnet_regiis) WINE_CONFIG_MAKEFILE(programs/attrib) +WINE_CONFIG_MAKEFILE(programs/belauncher) WINE_CONFIG_MAKEFILE(programs/cabarc) WINE_CONFIG_MAKEFILE(programs/cacls) WINE_CONFIG_MAKEFILE(programs/certutil) @@ -3445,6 +3520,7 @@ WINE_CONFIG_MAKEFILE(programs/cscript) WINE_CONFIG_MAKEFILE(programs/dism) WINE_CONFIG_MAKEFILE(programs/dllhost) WINE_CONFIG_MAKEFILE(programs/dplaysvr) +WINE_CONFIG_MAKEFILE(programs/dotnetfx35) WINE_CONFIG_MAKEFILE(programs/dpnsvr) WINE_CONFIG_MAKEFILE(programs/dpvsetup) WINE_CONFIG_MAKEFILE(programs/dxdiag) @@ -3461,6 +3537,7 @@ WINE_CONFIG_MAKEFILE(programs/findstr) WINE_CONFIG_MAKEFILE(programs/findstr/tests) WINE_CONFIG_MAKEFILE(programs/fsutil) WINE_CONFIG_MAKEFILE(programs/fsutil/tests) +WINE_CONFIG_MAKEFILE(programs/getminidump) WINE_CONFIG_MAKEFILE(programs/hh) WINE_CONFIG_MAKEFILE(programs/hostname) WINE_CONFIG_MAKEFILE(programs/icacls) @@ -3516,6 +3593,7 @@ WINE_CONFIG_MAKEFILE(programs/start) WINE_CONFIG_MAKEFILE(programs/subst) WINE_CONFIG_MAKEFILE(programs/svchost) WINE_CONFIG_MAKEFILE(programs/systeminfo) +WINE_CONFIG_MAKEFILE(programs/tabtip) WINE_CONFIG_MAKEFILE(programs/taskkill) WINE_CONFIG_MAKEFILE(programs/tasklist) WINE_CONFIG_MAKEFILE(programs/tasklist/tests) diff --git a/dlls/actxprxy/Makefile.in b/dlls/actxprxy/Makefile.in index 0397f7c3a935..36aa17b61ef5 100644 --- a/dlls/actxprxy/Makefile.in +++ b/dlls/actxprxy/Makefile.in @@ -8,6 +8,7 @@ SOURCES = \ actxprxy_hlink.idl \ actxprxy_htiface.idl \ actxprxy_htiframe.idl \ + actxprxy_mshtml.idl \ actxprxy_objsafe.idl \ actxprxy_ocmm.idl \ actxprxy_servprov.idl \ diff --git a/dlls/actxprxy/actxprxy_mshtml.idl b/dlls/actxprxy/actxprxy_mshtml.idl new file mode 100644 index 000000000000..6f4a7ca9fd08 --- /dev/null +++ b/dlls/actxprxy/actxprxy_mshtml.idl @@ -0,0 +1,35 @@ +/* + * Copyright 2009 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* just a wrapper for mshtmhst.idl */ + +#pragma makedep proxy +#pragma makedep register + +#define NO_MSHTML_IMPORT + +#include "mshtml.idl" +#include "mshtmhst.idl" +#include "shdeprecated.idl" +#include "docobjectservice.idl" + +[ + threading(both), + uuid(b8da6310-e19b-11d0-933c-00a0c90dcaa9) /* IActiveScriptStats */ +] +coclass PSFactoryBuffer { interface IFactoryBuffer; } diff --git a/dlls/advapi32/Makefile.in b/dlls/advapi32/Makefile.in index 1b6cce08e674..98694c814c58 100644 --- a/dlls/advapi32/Makefile.in +++ b/dlls/advapi32/Makefile.in @@ -1,8 +1,8 @@ EXTRADEFS = -D_ADVAPI32_ MODULE = advapi32.dll IMPORTLIB = advapi32 -IMPORTS = kernelbase sechost msvcrt -DELAYIMPORTS = rpcrt4 user32 +IMPORTS = kernelbase sechost msvcrt rpcrt4 +DELAYIMPORTS = user32 SOURCES = \ advapi.c \ diff --git a/dlls/advapi32/advapi.c b/dlls/advapi32/advapi.c index 2284e92b2638..127cec572522 100644 --- a/dlls/advapi32/advapi.c +++ b/dlls/advapi32/advapi.c @@ -44,14 +44,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(advapi); */ BOOL WINAPI GetUserNameA( LPSTR name, LPDWORD size ) { - DWORD len = GetEnvironmentVariableA( "WINEUSERNAME", name, *size ); - BOOL ret; - - if (!len) return FALSE; - if ((ret = (len < *size))) len++; - else SetLastError( ERROR_INSUFFICIENT_BUFFER ); - *size = len; - return ret; + static const char steamuserA[] = {'s','t','e','a','m','u','s','e','r',0}; + if(*size < ARRAY_SIZE(steamuserA)){ + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + *size = ARRAY_SIZE(steamuserA); + return FALSE; + } + memcpy(name, steamuserA, sizeof(steamuserA)); + *size = ARRAY_SIZE(steamuserA); + return TRUE; } /****************************************************************************** @@ -59,14 +60,15 @@ BOOL WINAPI GetUserNameA( LPSTR name, LPDWORD size ) */ BOOL WINAPI GetUserNameW( LPWSTR name, LPDWORD size ) { - DWORD len = GetEnvironmentVariableW( L"WINEUSERNAME", name, *size ); - BOOL ret; - - if (!len) return FALSE; - if ((ret = (len < *size))) len++; - else SetLastError( ERROR_INSUFFICIENT_BUFFER ); - *size = len; - return ret; + static const WCHAR steamuserW[] = {'s','t','e','a','m','u','s','e','r',0}; + if(*size < ARRAY_SIZE(steamuserW)){ + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + *size = ARRAY_SIZE(steamuserW); + return FALSE; + } + memcpy(name, steamuserW, sizeof(steamuserW)); + *size = ARRAY_SIZE(steamuserW); + return TRUE; } /****************************************************************************** diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec index dde83cc70450..809a9e7b5816 100644 --- a/dlls/advapi32/advapi32.spec +++ b/dlls/advapi32/advapi32.spec @@ -280,7 +280,7 @@ @ stdcall -import EnumServicesStatusExW(long long long long ptr long ptr ptr ptr wstr) @ stdcall EnumServicesStatusW (long long long ptr long ptr ptr ptr) @ stdcall EnumerateTraceGuids(ptr long ptr) -# @ stub EnumerateTraceGuidsEx +@ stdcall EnumerateTraceGuidsEx(long ptr long ptr long ptr) @ stdcall -import EqualDomainSid(ptr ptr ptr) @ stdcall -import EqualPrefixSid(ptr ptr) @ stdcall -import EqualSid(ptr ptr) @@ -295,7 +295,7 @@ @ stdcall EventUnregister(int64) ntdll.EtwEventUnregister @ stdcall EventWrite(int64 ptr long ptr) ntdll.EtwEventWrite # @ stub EventWriteEndScenario -# @ stub EventWriteEx +@ stdcall EventWriteEx(int64 ptr int64 long ptr ptr long ptr) ntdll.EtwEventWriteEx # @ stub EventWriteStartScenario @ stdcall EventWriteString(int64 long int64 ptr) ntdll.EtwEventWriteString @ stdcall EventWriteTransfer(int64 ptr ptr ptr long ptr) ntdll.EtwEventWriteTransfer diff --git a/dlls/advapi32/crypt.c b/dlls/advapi32/crypt.c index 0c94999660a2..d996bc545d15 100644 --- a/dlls/advapi32/crypt.c +++ b/dlls/advapi32/crypt.c @@ -645,9 +645,19 @@ BOOL WINAPI CryptReleaseContext (HCRYPTPROV hProv, DWORD dwFlags) if (InterlockedDecrement(&pProv->refcount) == 0) { + static unsigned int once; + char sgi[64]; + ret = pProv->pFuncs->pCPReleaseContext(pProv->hPrivate, dwFlags); pProv->dwMagic = 0; - FreeLibrary(pProv->hModule); + if(GetEnvironmentVariableA("SteamGameId", sgi, sizeof(sgi)) && !strcmp(sgi, "1252330")) + { + if (!once++) FIXME("HACK: not freeing provider library.\n"); + } + else + { + FreeLibrary(pProv->hModule); + } #if 0 CRYPT_Free(pProv->pVTable->pContextInfo); #endif diff --git a/dlls/advapi32/eventlog.c b/dlls/advapi32/eventlog.c index 58db53f5536a..46300bd9e6ca 100644 --- a/dlls/advapi32/eventlog.c +++ b/dlls/advapi32/eventlog.c @@ -727,3 +727,15 @@ ULONG WINAPI EnumerateTraceGuids(PTRACE_GUID_PROPERTIES *propertiesarray, FIXME("%p %ld %p: stub\n", propertiesarray, arraycount, guidcount); return ERROR_INVALID_PARAMETER; } + +/****************************************************************************** + * EnumerateTraceGuidsEx [ADVAPI32.@] + */ +ULONG WINAPI EnumerateTraceGuidsEx(TRACE_QUERY_INFO_CLASS class, void *in, ULONG in_size, void *out, ULONG out_size, + ULONG *ret_len) +{ + FIXME("%d %p %ld %p %ld %p: stub\n", class, in, in_size, out, out_size, ret_len); + + *ret_len = 0; + return ERROR_INVALID_PARAMETER; +} diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c index 97304d641098..fed8ef5179f6 100644 --- a/dlls/advapi32/security.c +++ b/dlls/advapi32/security.c @@ -244,12 +244,42 @@ BOOL ADVAPI_IsLocalComputer(LPCWSTR ServerName) return Result; } +static BOOL WINAPI init_computer_sid( INIT_ONCE *init_once, void *parameter, void **context ) +{ + DWORD *sub_authority = parameter; + unsigned int i, count; + DWORD len, index; + BOOL found = FALSE; + DWORD values[3]; + char buffer[64]; + LSTATUS status; + + len = ARRAY_SIZE(buffer); + index = 0; + while (!(status = RegEnumKeyExA( HKEY_USERS, index, buffer, &len, NULL, NULL, NULL, NULL ))) + { + count = sscanf(buffer, "S-1-5-21-%lu-%lu-%lu", &values[0], &values[1], &values[2]); + if (count == 3) + { + if (found) + ERR( "Multiple users are not supported.\n" ); + for (i = 0; i < 3; ++i) + sub_authority[i] = values[i]; + found = TRUE; + } + ++index; + len = ARRAY_SIZE(buffer); + } + return found; +} + /************************************************************ * ADVAPI_GetComputerSid */ BOOL ADVAPI_GetComputerSid(PSID sid) { - static const struct /* same fields as struct SID */ + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + static struct /* same fields as struct SID */ { BYTE Revision; BYTE SubAuthorityCount; @@ -258,6 +288,9 @@ BOOL ADVAPI_GetComputerSid(PSID sid) } computer_sid = { SID_REVISION, 4, { SECURITY_NT_AUTHORITY }, { SECURITY_NT_NON_UNIQUE, 0, 0, 0 } }; + if (!InitOnceExecuteOnce( &init_once, init_computer_sid, computer_sid.SubAuthority + 1, NULL )) + ERR( "Could not initialize computer sid.\n" ); + memcpy( sid, &computer_sid, sizeof(computer_sid) ); return TRUE; } @@ -3110,7 +3143,7 @@ DWORD WINAPI TreeSetNamedSecurityInfoW(WCHAR *name, SE_OBJECT_TYPE type, SECURIT FIXME("(%s, %d, %lu, %p, %p, %p, %p, %lu, %p, %d, %p) stub\n", debugstr_w(name), type, info, owner, group, dacl, sacl, action, progress, pis, args); - return ERROR_CALL_NOT_IMPLEMENTED; + return ERROR_SUCCESS; } /****************************************************************************** diff --git a/dlls/advapi32/tests/crypt.c b/dlls/advapi32/tests/crypt.c index 64067bea8ee0..b8e4453d3820 100644 --- a/dlls/advapi32/tests/crypt.c +++ b/dlls/advapi32/tests/crypt.c @@ -478,6 +478,44 @@ static void test_incorrect_api_usage(void) ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError()); } +static void test_garbage_data(void) +{ + struct KeyBlob + { + BLOBHEADER header; + DWORD key_size; + BYTE key_data[2048]; + } key_blob; + + BOOL result; + HCRYPTPROV hProv; + HCRYPTKEY hkey = 0; + + /* When verifying logins in "Marvel Heroes", the application passes garbage data + * in a reserved field that should always be 0 (according to documentation). + * + * This doesn't lead to any error on Windows. + */ + + result = CryptAcquireContextA(&hProv, 0, 0, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); + ok (result, "%08lx\n", GetLastError()); + + key_blob.header.bType = PLAINTEXTKEYBLOB; + key_blob.header.bVersion = CUR_BLOB_VERSION; + key_blob.header.reserved = 29806; /* Not allowed, but accepted? */ + key_blob.header.aiKeyAlg = CALG_AES_128; + key_blob.key_size = 16; + + result = CryptImportKey(hProv, (BYTE *)&key_blob, sizeof(BLOBHEADER) + sizeof(DWORD) + key_blob.key_size, 0, 0, &hkey); + ok(result, "CryptImportKey failed: %08lx\n", GetLastError()); + + CryptDestroyKey(hkey); + + result = CryptReleaseContext(hProv, 0); + ok(result, "got %lu\n", GetLastError()); + +} + static const BYTE privKey[] = { 0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x79, 0x10, 0x1c, 0xd0, 0x6b, 0x10, @@ -1293,6 +1331,7 @@ START_TEST(crypt) test_CryptReleaseContext(); test_acquire_context(); test_incorrect_api_usage(); + test_garbage_data(); test_verify_sig(); test_machine_guid(); test_container_sd(); diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c index cc9c0bff2c67..119e287c5db8 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -3378,6 +3378,78 @@ static void test_redirection(void) RegDeleteKeyA( key32, "" ); RegCloseKey( key32 ); + + /* HKCU\\Software is shared. */ + err = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Wow6432Node\\tmp", 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &key, NULL ); + ok( !err, "got %#lx.\n", err ); + RegDeleteKeyA( key, "" ); + RegCloseKey( key ); + + err = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\TestKey", 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &root64, NULL ); + ok( !err, "got %#lx.\n", err ); + err = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\Wow6432Node\\TestKey", 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &root32 ); + ok ( err == ERROR_FILE_NOT_FOUND, "got %#lx.\n", err ); + + err = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Wow6432Node\\TestKey", 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &root32, NULL ); + ok( !err, "got %#lx.\n", err ); + + dw = 1; + err = RegSetKeyValueA( root64, NULL, "val", REG_DWORD, &dw, sizeof(dw) ); + ok( !err, "got %#lx.\n", err ); + + dw = 2; + err = RegSetKeyValueA( root32, NULL, "val", REG_DWORD, &dw, sizeof(dw) ); + ok( !err, "got %#lx.\n", err ); + + err = RegCreateKeyExA( root64, "subkey", 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &key64, NULL ); + ok( !err, "got %#lx.\n", err ); + dw = 1; + err = RegSetKeyValueA( key64, NULL, "val", REG_DWORD, &dw, sizeof(dw) ); + ok( !err, "got %#lx.\n", err ); + + err = RegCreateKeyExA( root32, "subkey", 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &key32, NULL ); + ok( !err, "got %#lx.\n", err ); + dw = 2; + err = RegSetKeyValueA( key32, NULL, "val", REG_DWORD, &dw, sizeof(dw) ); + ok( !err, "got %#lx.\n", err ); + + err = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\TestKey", 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &key ); + ok( !err, "got %#lx.\n", err ); + len = sizeof(dw); + err = RegQueryValueExA( key, "val", NULL, NULL, (BYTE *)&dw, &len ); + ok( !err, "got %#lx.\n", err ); + ok( dw == 1, "got %lu.\n", dw ); + RegCloseKey( key ); + err = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\TestKey", 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, &key ); + ok( !err, "got %#lx.\n", err ); + len = sizeof(dw); + err = RegQueryValueExA( key, "val", NULL, NULL, (BYTE *)&dw, &len ); + ok( !err, "got %#lx.\n", err ); + ok( dw == 1, "got %lu.\n", dw ); + RegCloseKey( key ); + err = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\TestKey\\subkey", 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &key ); + ok( !err, "got %#lx.\n", err ); + len = sizeof(dw); + err = RegQueryValueExA( key, "val", NULL, NULL, (BYTE *)&dw, &len ); + ok( !err, "got %#lx.\n", err ); + ok( dw == 1, "got %lu.\n", dw ); + RegCloseKey( key ); + err = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\TestKey\\subkey", 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, &key ); + ok( !err, "got %#lx.\n", err ); + len = sizeof(dw); + err = RegQueryValueExA( key, "val", NULL, NULL, (BYTE *)&dw, &len ); + ok( !err, "got %#lx.\n", err ); + ok( dw == 1, "got %lu.\n", dw ); + RegCloseKey( key ); + + RegDeleteKeyA( key64, "" ); + RegCloseKey( key64 ); + RegDeleteKeyA( key32, "" ); + RegCloseKey( key32 ); + RegDeleteKeyA( root32, "" ); + RegCloseKey( root32 ); + RegDeleteKeyA( root64, "" ); + RegCloseKey( root64 ); } static void test_classesroot(void) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index e215ab9e5f21..a87fe5528e67 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -728,6 +728,9 @@ static void test_lookupPrivilegeValue(void) } } +static TOKEN_OWNER *get_alloc_token_owner( HANDLE token ); +static TOKEN_PRIMARY_GROUP *get_alloc_token_primary_group( HANDLE token ); + static void test_FileSecurity(void) { char wintmpdir [MAX_PATH]; @@ -742,6 +745,16 @@ static void test_FileSecurity(void) const SECURITY_INFORMATION request = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION; + TOKEN_OWNER *owner; + PSID owner_sid; + BOOL defaulted, present; + TOKEN_PRIMARY_GROUP *group; + SECURITY_ATTRIBUTES sa; + PACL dacl; + ACL_SIZE_INFORMATION acl_size; + ACCESS_ALLOWED_ACE *ace; + static SID owner_rights_sid = { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_OWNER_RIGHTS_RID } }; + const WCHAR sd_onwer_rights_str[] = L"D:(A;;FA;;;S-1-3-4)"; if (!GetTempPathA (sizeof (wintmpdir), wintmpdir)) { win_skip ("GetTempPathA failed\n"); @@ -837,6 +850,58 @@ static void test_FileSecurity(void) ok (GetLastError() == ERROR_FILE_NOT_FOUND, "last error ERROR_FILE_NOT_FOUND expected, got %ld\n", GetLastError()); + sa.nLength = sizeof(sa); + sa.bInheritHandle = FALSE; + rc = ConvertStringSecurityDescriptorToSecurityDescriptorW(sd_onwer_rights_str, SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL); + ok(rc, "got error %lu.\n", GetLastError()); + + DeleteFileA(file); + fh = CreateFileA(file, GENERIC_READ, 0, &sa, CREATE_ALWAYS, 0, NULL); + ok (fh != INVALID_HANDLE_VALUE, "error %lu\n", GetLastError()); + LocalFree(sa.lpSecurityDescriptor); + + rc = GetFileSecurityA (file, OWNER_SECURITY_INFORMATION, NULL, 0, &retSize); + ok (!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %ld, error %lu.\n", rc, GetLastError()); + sd = HeapAlloc (GetProcessHeap (), 0, sdSize); + rc = GetFileSecurityA (file, OWNER_SECURITY_INFORMATION, sd, retSize, &retSize); + ok(rc, "got error %lu.\n", GetLastError()); + rc = GetSecurityDescriptorOwner(sd, &owner_sid, &defaulted); + ok(rc, "got error %lu.\n", GetLastError()); + ok(!defaulted, "got %d.\n", defaulted); + owner = get_alloc_token_owner(GetCurrentProcessToken()); + todo_wine ok(EqualSid(owner_sid, owner->Owner), "Owner SIDs are not equal %s != %s\n", debugstr_sid(owner_sid), debugstr_sid(owner->Owner)); + HeapFree (GetProcessHeap (), 0, owner); + HeapFree (GetProcessHeap (), 0, sd); + + group = get_alloc_token_primary_group(GetCurrentProcessToken()); + test_group_equal(fh, group->PrimaryGroup, __LINE__); + HeapFree (GetProcessHeap (), 0, group); + + CloseHandle(fh); + + fh = CreateFileA(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + ok (fh != INVALID_HANDLE_VALUE, "error %lu\n", GetLastError()); + if (fh != INVALID_HANDLE_VALUE) + { + rc = GetFileSecurityA (file, DACL_SECURITY_INFORMATION, NULL, 0, &retSize); + ok (!rc && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %ld, error %lu.\n", rc, GetLastError()); + sd = HeapAlloc (GetProcessHeap (), 0, sdSize); + rc = GetFileSecurityA (file, DACL_SECURITY_INFORMATION, sd, retSize, &retSize); + ok(rc, "got error %lu.\n", GetLastError()); + rc = GetSecurityDescriptorDacl(sd, &present, &dacl, &defaulted); + ok(rc, "got error %lu.\n", GetLastError()); + ok(present, "got %d.\n", present); + ok(!defaulted, "got %d.\n", defaulted); + rc = GetAclInformation(dacl, &acl_size, sizeof(acl_size), AclSizeInformation); + ok(rc, "got error %lu.\n", GetLastError()); + ok(acl_size.AceCount == 1, "got %lu.\n", acl_size.AceCount); + rc = GetAce(dacl, 0, (VOID **)&ace); + ok(rc, "got error %lu.\n", GetLastError()); + ok(EqualSid(&ace->SidStart, &owner_rights_sid), "Owner SIDs are not equal %s != %s\n", debugstr_sid(&ace->SidStart), debugstr_sid(&owner_rights_sid)); + CloseHandle(fh); + HeapFree (GetProcessHeap (), 0, sd); + } + cleanup: /* Remove temporary file and directory */ DeleteFileA(file); @@ -3612,7 +3677,7 @@ static void test_CreateDirectoryA(void) } ok(!error, "GetNamedSecurityInfo failed with error %ld\n", error); test_inherited_dacl(pDacl, admin_sid, user_sid, OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE, - 0x1f01ff, FALSE, TRUE, FALSE, __LINE__); + 0x1f01ff, FALSE, FALSE, FALSE, __LINE__); LocalFree(pSD); /* Test inheritance of ACLs in CreateFile without security descriptor */ @@ -3658,7 +3723,6 @@ static void test_CreateDirectoryA(void) ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %ld\n", error); bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); ok(bret, "GetAclInformation failed\n"); - todo_wine ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", acl_size.AceCount); LocalFree(pSD); @@ -3668,15 +3732,11 @@ static void test_CreateDirectoryA(void) (PSID *)&owner, NULL, &pDacl, NULL, &pSD); todo_wine ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %ld\n", error); - if (error == ERROR_SUCCESS) - { - bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); - ok(bret, "GetAclInformation failed\n"); - todo_wine - ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", - acl_size.AceCount); - LocalFree(pSD); - } + bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); + ok(bret, "GetAclInformation failed\n"); + ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", + acl_size.AceCount); + LocalFree(pSD); CloseHandle(hTemp); /* Test inheritance of ACLs in NtCreateFile without security descriptor */ @@ -3746,16 +3806,154 @@ static void test_CreateDirectoryA(void) OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, (PSID *)&owner, NULL, &pDacl, NULL, &pSD); todo_wine + ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", + acl_size.AceCount); + LocalFree(pSD); + CloseHandle(hTemp); + + /* Test inheritance of ACLs in CreateDirectory without security descriptor */ + strcpy(tmpfile, tmpdir); + lstrcatA(tmpfile, "/tmpdir"); + bret = CreateDirectoryA(tmpfile, NULL); + ok(bret == TRUE, "CreateDirectoryA failed with error %lu\n", GetLastError()); + + error = GetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "Failed to get permissions on file\n"); + test_inherited_dacl(pDacl, admin_sid, user_sid, + OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERITED_ACE, + 0x1f01ff, TRUE, TRUE, TRUE, __LINE__); + LocalFree(pSD); + bret = RemoveDirectoryA(tmpfile); + ok(bret == TRUE, "RemoveDirectoryA failed with error %lu\n", GetLastError()); + + /* Test inheritance of ACLs in CreateDirectory with security descriptor */ + pSD = &sd; + InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION); + pDacl = HeapAlloc(GetProcessHeap(), 0, sizeof(ACL)); + bret = InitializeAcl(pDacl, sizeof(ACL), ACL_REVISION); + ok(bret, "Failed to initialize ACL\n"); + bret = SetSecurityDescriptorDacl(pSD, TRUE, pDacl, FALSE); + ok(bret, "Failed to add ACL to security desciptor\n"); + + strcpy(tmpfile, tmpdir); + lstrcatA(tmpfile, "/tmpdir1"); + + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = TRUE; + bret = CreateDirectoryA(tmpfile, &sa); + ok(bret == TRUE, "CreateDirectoryA failed with error %lu\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, pDacl); + + error = GetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %lu\n", error); + bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); + ok(bret, "GetAclInformation failed\n"); + ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%lu != 0).\n", + acl_size.AceCount); + LocalFree(pSD); + + SetLastError(0xdeadbeef); + bret = RemoveDirectoryA(tmpfile); + error = GetLastError(); + ok(bret == FALSE, "RemoveDirectoryA unexpected succeeded\n"); + ok(error == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %lu\n", error); + + pSD = &sd; + InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION); + pDacl = HeapAlloc(GetProcessHeap(), 0, 100); + bret = InitializeAcl(pDacl, 100, ACL_REVISION); + ok(bret, "Failed to initialize ACL.\n"); + bret = AddAccessAllowedAceEx(pDacl, ACL_REVISION, 0, GENERIC_ALL, user_sid); + ok(bret, "Failed to add Current User to ACL.\n"); + bret = SetSecurityDescriptorDacl(pSD, TRUE, pDacl, FALSE); + ok(bret, "Failed to add ACL to security desciptor.\n"); + error = SetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, + NULL, pDacl, NULL); + ok(error == ERROR_SUCCESS, "SetNamedSecurityInfoA failed with error %lu\n", error); + HeapFree(GetProcessHeap(), 0, pDacl); + + bret = RemoveDirectoryA(tmpfile); + ok(bret == TRUE, "RemoveDirectoryA failed with error %lu\n", GetLastError()); + + /* Test inheritance of ACLs in NtCreateFile(..., FILE_DIRECTORY_FILE, ...) without security descriptor */ + strcpy(tmpfile, tmpdir); + lstrcatA(tmpfile, "/tmpdir"); + get_nt_pathW(tmpfile, &tmpfileW); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &tmpfileW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + status = NtCreateFile(&hTemp, GENERIC_READ | DELETE, &attr, &io, NULL, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, FILE_CREATE, FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE, NULL, 0); + ok(!status, "NtCreateFile failed with %08lx\n", status); + RtlFreeUnicodeString(&tmpfileW); + + error = GetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "Failed to get permissions on file\n"); + test_inherited_dacl(pDacl, admin_sid, user_sid, + OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERITED_ACE, + 0x1f01ff, TRUE, TRUE, TRUE, __LINE__); + LocalFree(pSD); + CloseHandle(hTemp); + + /* Test inheritance of ACLs in NtCreateFile(..., FILE_DIRECTORY_FILE, ...) with security descriptor */ + pSD = &sd; + InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION); + pDacl = HeapAlloc(GetProcessHeap(), 0, sizeof(ACL)); + bret = InitializeAcl(pDacl, sizeof(ACL), ACL_REVISION); + ok(bret, "Failed to initialize ACL\n"); + bret = SetSecurityDescriptorDacl(pSD, TRUE, pDacl, FALSE); + ok(bret, "Failed to add ACL to security desciptor\n"); + + strcpy(tmpfile, tmpdir); + lstrcatA(tmpfile, "/tmpdir2"); + get_nt_pathW(tmpfile, &tmpfileW); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &tmpfileW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = pSD; + attr.SecurityQualityOfService = NULL; + + status = NtCreateFile(&hTemp, GENERIC_READ | DELETE, &attr, &io, NULL, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, FILE_CREATE, FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE, NULL, 0); + ok(!status, "NtCreateFile failed with %08lx\n", status); + RtlFreeUnicodeString(&tmpfileW); + HeapFree(GetProcessHeap(), 0, pDacl); + + error = GetSecurityInfo(hTemp, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %ld\n", error); - if (error == ERROR_SUCCESS) - { - bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); - ok(bret, "GetAclInformation failed\n"); - todo_wine - ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", - acl_size.AceCount); - LocalFree(pSD); - } + bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); + ok(bret, "GetAclInformation failed\n"); + todo_wine + ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", + acl_size.AceCount); + LocalFree(pSD); + + error = GetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %ld\n", error); + bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); + ok(bret, "GetAclInformation failed\n"); + todo_wine + ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", + acl_size.AceCount); + LocalFree(pSD); CloseHandle(hTemp); done: @@ -3916,21 +4114,20 @@ static void test_GetNamedSecurityInfoA(void) bret = GetAce(pDacl, 0, (VOID **)&ace); ok(bret, "Failed to get Current User ACE.\n"); bret = EqualSid(&ace->SidStart, user_sid); - todo_wine ok(bret, "Current User ACE (%s) != Current User SID (%s).\n", - debugstr_sid(&ace->SidStart), debugstr_sid(user_sid)); + ok(bret, "Current User ACE (%s) != Current User SID (%s).\n", + debugstr_sid(&ace->SidStart), debugstr_sid(user_sid)); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); - ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%lx != 0x1f01ff)\n", - ace->Mask); + ok(ace->Mask == 0x1f01ff, + "Current User ACE has unexpected mask (0x%lx != 0x1f01ff)\n", ace->Mask); } if (acl_size.AceCount > 1) { bret = GetAce(pDacl, 1, (VOID **)&ace); ok(bret, "Failed to get Administators Group ACE.\n"); bret = EqualSid(&ace->SidStart, admin_sid); - todo_wine ok(bret || broken(!bret) /* win2k */, - "Administators Group ACE (%s) != Administators Group SID (%s).\n", - debugstr_sid(&ace->SidStart), debugstr_sid(admin_sid)); + ok(bret || broken(!bret) /* win2k */, "Administators Group ACE (%s) != Administators Group SID (%s).\n", + debugstr_sid(&ace->SidStart), debugstr_sid(admin_sid)); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); ok(ace->Mask == 0x1f01ff || broken(ace->Mask == GENERIC_ALL) /* win2k */, @@ -3957,8 +4154,8 @@ static void test_GetNamedSecurityInfoA(void) { bret = GetAce(pDacl, 0, (VOID **)&ace); ok(bret, "Failed to get ACE.\n"); - todo_wine ok(((ACE_HEADER *)ace)->AceFlags & INHERITED_ACE, - "ACE has unexpected flags: 0x%x\n", ((ACE_HEADER *)ace)->AceFlags); + ok(((ACE_HEADER *)ace)->AceFlags & INHERITED_ACE, + "ACE has unexpected flags: 0x%x\n", ((ACE_HEADER *)ace)->AceFlags); } LocalFree(pSD); @@ -4753,23 +4950,22 @@ static void test_GetSecurityInfo(void) bret = GetAce(pDacl, 0, (VOID **)&ace); ok(bret, "Failed to get Current User ACE.\n"); bret = EqualSid(&ace->SidStart, user_sid); - todo_wine ok(bret, "Current User ACE (%s) != Current User SID (%s).\n", - debugstr_sid(&ace->SidStart), debugstr_sid(user_sid)); + ok(bret, "Current User ACE (%s) != Current User SID (%s).\n", debugstr_sid(&ace->SidStart), debugstr_sid(user_sid)); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%lx != 0x1f01ff)\n", - ace->Mask); + ace->Mask); } if (acl_size.AceCount > 1) { bret = GetAce(pDacl, 1, (VOID **)&ace); ok(bret, "Failed to get Administators Group ACE.\n"); bret = EqualSid(&ace->SidStart, admin_sid); - todo_wine ok(bret, "Administators Group ACE (%s) != Administators Group SID (%s).\n", debugstr_sid(&ace->SidStart), debugstr_sid(admin_sid)); + ok(bret, "Administators Group ACE (%s) != Administators Group SID (%s).\n", debugstr_sid(&ace->SidStart), debugstr_sid(admin_sid)); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); - ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%lx != 0x1f01ff)\n", - ace->Mask); + ok(ace->Mask == 0x1f01ff, + "Administators Group ACE has unexpected mask (0x%lx != 0x1f01ff)\n", ace->Mask); } LocalFree(pSD); CloseHandle(obj); diff --git a/dlls/amd_ags_x64/Makefile.in b/dlls/amd_ags_x64/Makefile.in new file mode 100644 index 000000000000..034413158025 --- /dev/null +++ b/dlls/amd_ags_x64/Makefile.in @@ -0,0 +1,14 @@ +EXTRADEFS = -DWINE_NO_LONG_TYPES +MODULE = amd_ags_x64.dll +UNIXLIB = amd_ags_x64.so +UNIX_CFLAGS = $(DRM_CFLAGS) +UNIX_LIBS = $(DRM_LIBS) $(DRMAMDGPU_LIBS) +IMPORTS = version vulkan-1 user32 +IMPORTLIB = amd_ags_x64 + +EXTRADLLFLAGS = -mno-cygwin + +SOURCES = \ + amd_ags_x64_main.c \ + unixlib.c \ + dxvk_interfaces.idl diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h new file mode 100644 index 000000000000..2b9674362224 --- /dev/null +++ b/dlls/amd_ags_x64/amd_ags.h @@ -0,0 +1,2069 @@ +// +// Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +/// \file +/// \mainpage +/// AGS Library Overview +/// -------------------- +/// This document provides an overview of the AGS (AMD GPU Services) library. The AGS library provides software developers with the ability to query +/// AMD GPU software and hardware state information that is not normally available through standard operating systems or graphic APIs. +/// +/// The latest version of the API is publicly hosted here: https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/. +/// It is also worth checking http://gpuopen.com/gaming-product/amd-gpu-services-ags-library/ for any updates and articles on AGS. +/// \internal +/// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/ +/// \endinternal +/// +/// --------------------------------------- +/// What's new in AGS 6.0 since version 5.4.2 +/// --------------------------------------- +/// AGS 6.0 includes the following updates: +/// * DX12 ray tracing hit token for RDNA2 hardware. +/// * Shader intrinsic that exposes ReadLaneAt in DX12. +/// * Shader intrinsics that expose explicit float conversions in DX12. +/// * Refactored and revised API to minimize user error. +/// * Added agsGetVersionNumber. +/// * Detection for external GPUs. +/// * Detection of RDNA2 architecture. +/// * Grouped the more established intrinsics together into per year support. +/// * Function pointer typedefs for the API +/// +/// --------------------------------------- +/// What's new in AGS 5.4.2 since version 5.4.1 +/// --------------------------------------- +/// AGS 5.4.2 includes the following updates: +/// * sharedMemoryInBytes has been reinstated. +/// * Clock speed returned for APUs. +/// +/// --------------------------------------- +/// What's new in AGS 5.4.1 since version 5.4.0 +/// --------------------------------------- +/// AGS 5.4.1 includes the following updates: +/// * AsicFamily_Count to help with code maintenance. +/// * Visual Studio 2019 support. +/// * x86 support +/// * BaseInstance and BaseVertex intrinsics along with corresponding caps bits. +/// * GetWaveSize intrinsic along with corresponding caps bits. +/// +/// --------------------------------------- +/// What's new in AGS 5.4 since version 5.3 +/// --------------------------------------- +/// AGS 5.4 includes the following updates: +/// * A more detailed description of the GPU architecture, now including RDNA GPUs. +/// * Radeon 7 core and memory speeds returned. +/// * Draw index and Atomic U64 intrinsics for both DX11 and DX12. +/// +/// --------------------------------------- +/// What's new in AGS 5.3 since version 5.2 +/// --------------------------------------- +/// AGS 5.3 includes the following updates: +/// * DX11 deferred context support for Multi Draw Indirect and UAV Overlap extensions. +/// * A Radeon Software Version helper to determine whether the installed driver meets your game's minimum driver version requirements. +/// * Freesync HDR Gamma 2.2 mode which uses a 1010102 swapchain and can be considered as an alternative to using the 64 bit swapchain required for Freesync HDR scRGB. +/// +/// What's new in AGS 5.2.1 since version 5.2.0 +/// --------------------------------------- +/// * Fix for crash when using Eyefinity +/// * Fix for DX12 app registration in the UWP version +/// +/// +/// What's new in AGS 5.2.0 since version 5.1 +/// --------------------------------------- +/// AGS 5.2 includes the following updates: +/// * DX12 app registration API +/// * DX11 breadcrumb marker API for tracking down GPU hangs:\ref agsDriverExtensionsDX11_WriteBreadcrumb +/// * DX12 extensions now require the creation of the device via \ref agsDriverExtensionsDX12_CreateDevice +/// * agsGetCrossfireGPUCount has been removed in favor of retrieving the value from \ref agsDriverExtensionsDX11_CreateDevice +/// * API change that fixes a reference leak in \ref agsDriverExtensionsDX11_DestroyDevice +/// +/// What's new in AGS 5.1.1 since version 5.0.6 +/// --------------------------------------- +/// AGS 5.1.1 includes the following updates: +/// * An API change for DX11 extensions +/// - It is now mandatory to call agsDriverExtensionsDX11_CreateDevice() when creating a device if the user wants to access any DX11 AMD extensions. +/// - The corresponding agsDriverExtensionsDX11_DestroyDevice() call must be called to release the device and free up the internal resources allocated by the create call. +/// * App registration extension for DX11. +/// * Freesync 2 HDR support. +/// * Wave reduce and wave scan shader extensions. +/// * AMD user markers for DX12. +/// * Eyefinity bug fixes. +/// * MultiDrawIndexedInstancedIndirectCountIndirect parameter bug fix. +/// * Static lib versions of the binary. +/// * VS2017 support for the samples. +/// +/// What's new in AGS 5.x since version 4.x +/// --------------------------------------- +/// Version 5.x is a major overhaul of the library designed to provide a much clearer view of the GPUs in the system and the displays attached to them. +/// It also exposes the ability to query each display for HDR capabilities and put those HDR capable displays into various HDR modes. +/// Some functions such as agsGetGPUMemorySize and agsGetEyefinityConfigInfo have been removed in favor of including this information in the device & display enumeration. +/// Features include: +/// * Full GPU enumeration with adapter string, device id, revision id and vendor id. +/// * Per GPU display enumeration including information on display name, resolution and HDR capabilities. +/// * Optional user supplied memory allocator. +/// * Function to set displays into HDR mode. +/// * A Microsoft WACK compliant version of the library. +/// * DirectX11 shader compiler controls. +/// * DirectX11 multiview extension enabling MultiView and MultiRes rendering. +/// * DirectX11 Crossfire API now supports using the API without needing a driver profile. Can also specify the transfer engine. +/// +/// Using the AGS library +/// --------------------- +/// It is recommended to take a look at the source code for the samples that come with the AGS SDK: +/// * AGSSample +/// * CrossfireSample +/// * EyefinitySample +/// The AGSSample application is the simplest of the three examples and demonstrates the code required to initialize AGS and use it to query the GPU and Eyefinity state. +/// The CrossfireSample application demonstrates the use of the new API to transfer resources on GPUs in Crossfire mode. Lastly, the EyefinitySample application provides a more +/// extensive example of Eyefinity setup than the basic example provided in AGSSample. +/// There are other samples on Github that demonstrate the DirectX shader extensions, such as the Barycentrics11 and Barycentrics12 samples. +/// +/// To add AGS support to an existing project, follow these steps: +/// * Link your project against the correct import library. Choose from either the 32 bit or 64 bit version. +/// * Copy the AGS dll into the same directory as your game executable. +/// * Include the amd_ags.h header file from your source code. +/// * Include the AGS hlsl files if you are using the shader intrinsics. +/// * Declare a pointer to an AGSContext and make this available for all subsequent calls to AGS. +/// * On game initialization, call \ref agsInitialize passing in the address of the context. On success, this function will return a valid context pointer. +/// +/// Don't forget to cleanup AGS by calling \ref agsDeInitialize when the app exits, after the device has been destroyed. + +#ifndef AMD_AGS_H +#define AMD_AGS_H + +#define AMD_AGS_VERSION_MAJOR 6 ///< AGS major version +#define AMD_AGS_VERSION_MINOR 0 ///< AGS minor version +#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version + +#ifdef __cplusplus +extern "C" { +#endif + +/// \defgroup Defines AGS defines +/// @{ +#define AMD_AGS_API WINAPI + +#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams and the Radeon Software Version +#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version +/// @} + +// Forward declaration of D3D and DXGI types +struct IDXGIAdapter; +struct IDXGISwapChain; +struct DXGI_SWAP_CHAIN_DESC; +enum D3D_DRIVER_TYPE; +enum D3D_FEATURE_LEVEL; + enum D3D_PRIMITIVE_TOPOLOGY; + +// Forward declaration of D3D11 types +struct ID3D11Device; +struct ID3D11DeviceContext; +struct ID3D11Resource; +struct ID3D11Buffer; +struct ID3D11Texture1D; +struct ID3D11Texture2D; +struct ID3D11Texture3D; +struct D3D11_BUFFER_DESC; +struct D3D11_TEXTURE1D_DESC; +struct D3D11_TEXTURE2D_DESC; +struct D3D11_TEXTURE3D_DESC; +struct D3D11_SUBRESOURCE_DATA; + +// Forward declaration of D3D12 types +struct ID3D12Device; +struct ID3D12GraphicsCommandList; + +/// \defgroup enums General enumerations +/// @{ + +/// The return codes +typedef enum AGSReturnCode +{ + AGS_SUCCESS, ///< Successful function call + AGS_FAILURE, ///< Failed to complete call for some unspecified reason + AGS_INVALID_ARGS, ///< Invalid arguments into the function + AGS_OUT_OF_MEMORY, ///< Out of memory when allocating space internally + AGS_MISSING_D3D_DLL, ///< Returned when a D3D dll fails to load + AGS_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver + // AGS_NO_AMD_DRIVER_INSTALLED ADDED IN 5.4.1 + AGS_NO_AMD_DRIVER_INSTALLED, ///< Returned if the AMD GPU driver does not appear to be installed + AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension + AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library) + AGS_DX_FAILURE, ///< Failure from DirectX runtime + AGS_D3DDEVICE_NOT_CREATED, ///< Failure due to not creating the D3D device successfully via AGS. +} AGSReturnCode; + +/// The DirectX11 extension support bits +typedef enum AGSDriverExtensionDX11 +{ + AGS_DX11_EXTENSION_QUADLIST = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_SCREENRECTLIST = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_UAV_OVERLAP = 1 << 2, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_DEPTH_BOUNDS_TEST = 1 << 3, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_MULTIDRAWINDIRECT = 1 << 4, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_MULTIDRAWINDIRECT_COUNTINDIRECT = 1 << 5, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_CROSSFIRE_API = 1 << 6, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 7, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_READLANE = 1 << 8, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_LANEID = 1 << 9, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_SWIZZLE = 1 << 10, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_BALLOT = 1 << 11, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_MBCOUNT = 1 << 12, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_MED3 = 1 << 13, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 14, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 15, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX11_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 16, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS = 1 << 17, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, ///< Supported in Radeon Software Version 16.12.1 onwards. + AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX11_EXTENSION_BREADCRUMB_MARKERS = 1 << 20, ///< Supported in Radeon Software Version 17.11.1 onwards. + AGS_DX11_EXTENSION_MDI_DEFERRED_CONTEXTS = 1 << 21, ///< Supported in Radeon Software Version 18.8.1 onwards. + AGS_DX11_EXTENSION_UAV_OVERLAP_DEFERRED_CONTEXTS = 1 << 22, ///< Supported in Radeon Software Version 18.8.1 onwards. + AGS_DX11_EXTENSION_DEPTH_BOUNDS_DEFERRED_CONTEXTS = 1 << 23, ///< Supported in Radeon Software Version 18.8.1 onwards. + AGS_DX11_EXTENSION_INTRINSIC_DRAW_INDEX = 1 << 24, ///< Supported in Radeon Software Version 19.12.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 25, ///< Supported in Radeon Software Version 19.12.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_GET_WAVE_SIZE = 1 << 26, ///< Supported in Radeon Software Version 20.2.1 onwards. + AGS_DX11_EXTENSION_INTRINSIC_BASE_VERTEX = 1 << 27, ///< Supported in Radeon Software Version 20.2.1 onwards. + AGS_DX11_EXTENSION_INTRINSIC_BASE_INSTANCE = 1 << 28 ///< Supported in Radeon Software Version 20.2.1 onwards. +} AGSDriverExtensionDX11; + +/// The DirectX12 extension support bits +typedef enum AGSDriverExtensionDX12 +{ + AGS_DX12_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_READLANE = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_LANEID = 1 << 2, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_SWIZZLE = 1 << 3, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_BALLOT = 1 << 4, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_MBCOUNT = 1 << 5, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_MED3 = 1 << 6, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 7, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 8, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX12_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 9, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX12_EXTENSION_USER_MARKERS = 1 << 10, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX12_EXTENSION_APP_REGISTRATION = 1 << 11, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX12_EXTENSION_INTRINSIC_UAV_BIND_SLOT = 1 << 12, ///< Supported in Radeon Software Version 19.5.1 onwards. + AGS_DX12_EXTENSION_INTRINSIC_DRAW_INDEX = 1 << 13, ///< Supported in Radeon Software Version 19.12.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 14, ///< Supported in Radeon Software Version 19.12.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_BASE_VERTEX = 1 << 15, ///< Supported in Radeon Software Version 20.2.1 onwards. + AGS_DX12_EXTENSION_INTRINSIC_BASE_INSTANCE = 1 << 16, ///< Supported in Radeon Software Version 20.2.1 onwards. + AGS_DX12_EXTENSION_INTRINSIC_GET_WAVE_SIZE = 1 << 17 ///< Supported in Radeon Software Version 20.5.1 onwards. +} AGSDriverExtensionDX12; + +/// The space id for DirectX12 intrinsic support +const unsigned int AGS_DX12_SHADER_INTRINSICS_SPACE_ID = 0x7FFF0ADE; // 2147420894 + +/// The display flags describing various properties of the display. +typedef enum AGSDisplayFlags +{ + AGS_DISPLAYFLAG_PRIMARY_DISPLAY = 1 << 0, ///< Whether this display is marked as the primary display. Not set on the WACK version. + AGS_DISPLAYFLAG_HDR10 = 1 << 1, ///< HDR10 is supported on this display + AGS_DISPLAYFLAG_DOLBYVISION = 1 << 2, ///< Dolby Vision is supported on this display + AGS_DISPLAYFLAG_FREESYNC = 1 << 3, ///< Freesync is supported on this display + AGS_DISPLAYFLAG_FREESYNC_HDR = 1 << 4, ///< Freesync HDR is supported on this display + AGS_DISPLAYFLAG_EYEFINITY_IN_GROUP = 1 << 5, ///< The display is part of the Eyefinity group + AGS_DISPLAYFLAG_EYEFINITY_PREFERRED_DISPLAY = 1 << 6, ///< The display is the preferred display in the Eyefinity group for displaying the UI + AGS_DISPLAYFLAG_EYEFINITY_IN_PORTRAIT_MODE = 1 << 7, ///< The display is in the Eyefinity group but in portrait mode +} AGSDisplayFlags; + +/// The display settings flags. +typedef enum AGSDisplaySettingsFlags +{ + AGS_DISPLAYSETTINGSFLAG_DISABLE_LOCAL_DIMMING = 1 << 0, ///< Disables local dimming if possible +} AGSDisplaySettingsFlags; + +/// @} + +typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInitialize + +/// The rectangle struct used by AGS. +typedef struct AGSRect +{ + int offsetX; ///< Offset on X axis + int offsetY; ///< Offset on Y axis + int width; ///< Width of rectangle + int height; ///< Height of rectangle +} AGSRect; + +typedef struct AGSEyefinityInfo +{ + int iSLSActive; // Indicates if Eyefinity is active for the operating system display + // index passed into atiEyefinityGetConfigInfo(). 1 if enabled and 0 if disabled. + + int iSLSGridWidth; // Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + // For example, a 3 display wide by 2 high Eyefinity setup will return 3 for this entry. + int iSLSGridHeight; // Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + // For example, a 3 display wide by 2 high Eyefinity setup will return 2 for this entry. + + int iSLSWidth; // Contains width in pixels of the multi-monitor Single Large Surface. The value returned is + // a function of the width of the SLS grid, of the horizontal resolution of each display, and + // of whether or not bezel compensation is enabled. + int iSLSHeight; // Contains height in pixels of the multi-monitor Single Large Surface. The value returned is + // a function of the height of the SLS grid, of the vertical resolution of each display, and + // of whether or not bezel compensation is enabled. + + int iBezelCompensatedDisplay; // Indicates if bezel compensation is used for the current SLS display area. + // 1 if enabled, and 0 if disabled. +} AGSEyefinityInfo; + +/// The display info struct used to describe a display enumerated by AGS +typedef struct AGSDisplayInfo_403 +{ + int iGridXCoord; // Contains horizontal SLS grid coordinate of the display. The value is zero based with + // increasing values from left to right of the overall SLS grid. For example, the left-most + // display of a 3x2 Eyefinity setup will have the value 0, and the right-most will have + // the value 2. + int iGridYCoord; // Contains vertical SLS grid coordinate of the display. The value is zero based with + // increasing values from top to bottom of the overall SLS grid. For example, the top + // display of a 3x2 Eyefinity setup will have the value 0, and the bottom will have the + // value 1. + + AGSRect displayRect; // Contains the base offset and dimensions in pixels of the SLS rendering + // area associated with this display. If bezel compensation is enabled, this + // area will be larger than what the display can natively present to account + // for bezel area. If bezel compensation is disabled, this area will be equal + // to what the display can support natively. + + AGSRect displayRectVisible; // Contains the base offset and dimensions in pixels of the SLS rendering area + // associated with this display that is visible to the end user. If bezel + // compensation is enabled, this area will be equal to what the display can + // natively, but smaller that the area described in the displayRect entry. If + // bezel compensation is disabled, this area will be equal to what the display + // can support natively and equal to the area described in the displayRect entry. + // Developers wishing to place UI, HUD, or other game assets on a given display + // so that it is visible and accessible to end users need to locate them inside + // of the region defined by this rect. + + int iPreferredDisplay; // Indicates whether or not this display is the preferred one for rendering of + // game HUD and UI elements. Only one display out of the whole SLS grid will have + // this be true if it is the preferred display and 0 otherwise. Developers wishing + // to place specific UI, HUD, or other game assets on a given display so that it + // is visible and accessible to end users need to locate them inside of the region + // defined by this rect. +} AGSDisplayInfo_403; + +typedef struct AGSDisplayInfo_511 +{ + char name[ 256 ]; ///< The name of the display + char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName + + unsigned int displayFlags; ///< Bitfield of \ref AGSDisplayFlags + + int maxResolutionX; ///< The maximum supported resolution of the unrotated display + int maxResolutionY; ///< The maximum supported resolution of the unrotated display + float maxRefreshRate; ///< The maximum supported refresh rate of the display + + AGSRect currentResolution; ///< The current resolution and position in the desktop, ignoring Eyefinity bezel compensation + AGSRect visibleResolution; ///< The visible resolution and position. When Eyefinity bezel compensation is enabled this will + ///< be the sub region in the Eyefinity single large surface (SLS) + float currentRefreshRate; ///< The current refresh rate + + int eyefinityGridCoordX; ///< The X coordinate in the Eyefinity grid. -1 if not in an Eyefinity group + int eyefinityGridCoordY; ///< The Y coordinate in the Eyefinity grid. -1 if not in an Eyefinity group + + double chromaticityRedX; ///< Red display primary X coord + double chromaticityRedY; ///< Red display primary Y coord + + double chromaticityGreenX; ///< Green display primary X coord + double chromaticityGreenY; ///< Green display primary Y coord + + double chromaticityBlueX; ///< Blue display primary X coord + double chromaticityBlueY; ///< Blue display primary Y coord + + double chromaticityWhitePointX; ///< White point X coord + double chromaticityWhitePointY; ///< White point Y coord + + double screenDiffuseReflectance; ///< Percentage expressed between 0 - 1 + double screenSpecularReflectance; ///< Percentage expressed between 0 - 1 + + double minLuminance; ///< The minimum luminance of the display in nits + double maxLuminance; ///< The maximum luminance of the display in nits + double avgLuminance; ///< The average luminance of the display in nits + + int logicalDisplayIndex; ///< The internally used index of this display + int adlAdapterIndex; ///< The internally used ADL adapter index +} AGSDisplayInfo_511; + +/// The display info struct used to describe a display enumerated by AGS +typedef struct AGSDisplayInfo_600 +{ + char name[ 256 ]; ///< The name of the display + char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName + + unsigned int isPrimaryDisplay : 1; ///< Whether this display is marked as the primary display + unsigned int HDR10 : 1; ///< HDR10 is supported on this display + unsigned int dolbyVision : 1; ///< Dolby Vision is supported on this display + unsigned int freesync : 1; ///< Freesync is supported on this display + unsigned int freesyncHDR : 1; ///< Freesync HDR is supported on this display + unsigned int eyefinityInGroup : 1; ///< The display is part of the Eyefinity group + unsigned int eyefinityPreferredDisplay : 1; ///< The display is the preferred display in the Eyefinity group for displaying the UI + unsigned int eyefinityInPortraitMode : 1; ///< The display is in the Eyefinity group but in portrait mode + unsigned int reservedPadding : 24; ///< Reserved for future use + + int maxResolutionX; ///< The maximum supported resolution of the unrotated display + int maxResolutionY; ///< The maximum supported resolution of the unrotated display + float maxRefreshRate; ///< The maximum supported refresh rate of the display + + AGSRect currentResolution; ///< The current resolution and position in the desktop, ignoring Eyefinity bezel compensation + AGSRect visibleResolution; ///< The visible resolution and position. When Eyefinity bezel compensation is enabled this will + ///< be the sub region in the Eyefinity single large surface (SLS) + float currentRefreshRate; ///< The current refresh rate + + int eyefinityGridCoordX; ///< The X coordinate in the Eyefinity grid. -1 if not in an Eyefinity group + int eyefinityGridCoordY; ///< The Y coordinate in the Eyefinity grid. -1 if not in an Eyefinity group + + double chromaticityRedX; ///< Red display primary X coord + double chromaticityRedY; ///< Red display primary Y coord + + double chromaticityGreenX; ///< Green display primary X coord + double chromaticityGreenY; ///< Green display primary Y coord + + double chromaticityBlueX; ///< Blue display primary X coord + double chromaticityBlueY; ///< Blue display primary Y coord + + double chromaticityWhitePointX; ///< White point X coord + double chromaticityWhitePointY; ///< White point Y coord + + double screenDiffuseReflectance; ///< Percentage expressed between 0 - 1 + double screenSpecularReflectance; ///< Percentage expressed between 0 - 1 + + double minLuminance; ///< The minimum luminance of the display in nits + double maxLuminance; ///< The maximum luminance of the display in nits + double avgLuminance; ///< The average luminance of the display in nits + + int logicalDisplayIndex; ///< The internally used index of this display + int adlAdapterIndex; ///< The internally used ADL adapter index + int reserved; ///< reserved field +} AGSDisplayInfo_600; + +/// The architecture version +typedef enum ArchitectureVersion +{ + ArchitectureVersion_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId + ArchitectureVersion_PreGCN, ///< AMD architecture, pre-GCN + ArchitectureVersion_GCN ///< AMD GCN architecture +} ArchitectureVersion; + +/// The ASIC family +typedef enum AsicFamily +{ + AsicFamily_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId + AsicFamily_PreGCN, ///< Pre GCN architecture. + AsicFamily_GCN1, ///< AMD GCN 1 architecture: Oland, Cape Verde, Pitcairn & Tahiti. + AsicFamily_GCN2, ///< AMD GCN 2 architecture: Hawaii & Bonaire. This also includes APUs Kaveri and Carrizo. + AsicFamily_GCN3, ///< AMD GCN 3 architecture: Tonga & Fiji. + AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris. + AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU). + AsicFamily_RDNA, ///< AMD RDNA architecture + AsicFamily_RDNA2, ///< AMD RDNA2 architecture + AsicFamily_RDNA3, ///< AMD RDNA3 architecture + AsicFamily_RDNA4, ///< AMD RDNA4 architecture + + AsicFamily_Count ///< Number of enumerated ASIC families +} AsicFamily; + +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo_511 +{ + ArchitectureVersion architectureVersion; ///< Set to Unknown if not AMD hardware + const char* adapterString; ///< The adapter name string + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of GCN compute units. Zero if not GCN + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + float teraFlops; ///< Teraflops of GPU. Zero if not GCN. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. + long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters +} AGSDeviceInfo_511; + +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo_520 +{ + const char* adapterString; ///< The adapter name string + ArchitectureVersion architectureVersion; ///< Set to Unknown if not AMD hardware + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of compute units. Zero if not GCN onwards + int numROPs; ///< Number of ROPs + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + int memoryBandwidth; ///< Memory bandwidth in MB/s + float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. + long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters +} AGSDeviceInfo_520; + +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo_540 +{ + const char* adapterString; ///< The adapter name string + AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware + int isAPU; ///< Whether or not this is an APU + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of compute units. + int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. + + int numROPs; ///< Number of ROPs + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + int memoryBandwidth; ///< Memory bandwidth in MB/s + float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. + unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. + unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs + ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters +} AGSDeviceInfo_540; + +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo_541 +{ + const char* adapterString; ///< The adapter name string + AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware + int isAPU; ///< Whether or not this is an APU + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of compute units. + int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. + + int numROPs; ///< Number of ROPs + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + int memoryBandwidth; ///< Memory bandwidth in MB/s + float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. + long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters +} AGSDeviceInfo_541; + +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo_542 +{ + const char* adapterString; ///< The adapter name string + AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware + int isAPU; ///< Whether or not this is an APU + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of compute units. + int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. + + int numROPs; ///< Number of ROPs + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + int memoryBandwidth; ///< Memory bandwidth in MB/s + float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. + unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. + unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs + ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters +} AGSDeviceInfo_542; + +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo_600 +{ + const char* adapterString; ///< The adapter name string + AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware + unsigned int isAPU : 1; ///< Whether this device is an APU + unsigned int isPrimaryDevice : 1; ///< Whether this device is marked as the primary device + unsigned int isExternal :1; ///< Whether this device is a detachable, external device + unsigned int reservedPadding : 29; ///< Reserved for future use + + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of compute units + int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. + + int numROPs; ///< Number of ROPs + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + int memoryBandwidth; ///< Memory bandwidth in MB/s + float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. + unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs + ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo_600* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters + int reserved; ///< reserved field +} AGSDeviceInfo_600; + +struct AGSDeviceInfo; + +/// \defgroup general General API functions +/// API for initialization, cleanup, HDR display modes and Crossfire GPU count +/// @{ + +typedef void* (__stdcall *AGS_ALLOC_CALLBACK_511)( int allocationSize ); ///< AGS user defined allocation prototype +typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( size_t allocationSize ); ///< AGS user defined allocation prototype +typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype + +/// The different modes to control Crossfire behavior. +typedef enum AGSCrossfireMode +{ + AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering. If this mode is specified, do NOT use the agsDriverExtensionsDX11_Create*() APIs to create resources + AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile + AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering +} AGSCrossfireMode; + +/// The configuration options that can be passed in to \ref agsInititalize +struct AGSConfiguration_403 +{ + AGSCrossfireMode crossfireMode; // Desired Crossfire mode. See AGSCrossfireMode for more details +}; + +typedef struct AGSConfiguration_511 +{ + AGS_ALLOC_CALLBACK_511 allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used + AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used +} AGSConfiguration_511; + +typedef struct AGSConfiguration_520 +{ + AGS_ALLOC_CALLBACK allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used + AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used +} AGSConfiguration_520; + +typedef union AGSConfiguration +{ + AGSConfiguration_511 agsConfiguration511; + AGSConfiguration_520 agsConfiguration520; +} AGSConfiguration; + +struct AGSGPUInfo_311 +{ + ArchitectureVersion version; // Set to Unknown if not AMD hardware + const char* adapterString; // The adapter name string. NULL if not AMD hardware + int deviceId; // The device id + int revisionId; // The revision id + + const char* driverVersion; // The driver package version + + int iNumCUs; // Number of GCN compute units. Zero if not GCN + int iCoreClock; // core clock speed at 100% power in MHz + int iMemoryClock; // memory clock speed at 100% power in MHz + float fTFlops; // Teraflops of GPU. Zero if not GCN. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD +}; + +struct AGSGPUInfo_320 +{ + int agsVersionMajor; // Major field of Major.Minor.Patch AGS version number + int agsVersionMinor; // Minor field of Major.Minor.Patch AGS version number + int agsVersionPatch; // Patch field of Major.Minor.Patch AGS version number + + ArchitectureVersion architectureVersion; // Set to Unknown if not AMD hardware + const char* adapterString; // The adapter name string. NULL if not AMD hardware + int deviceId; // The device id + int revisionId; // The revision id + + const char* driverVersion; // The driver package version + + int iNumCUs; // Number of GCN compute units. Zero if not GCN + int iCoreClock; // core clock speed at 100% power in MHz + int iMemoryClock; // memory clock speed at 100% power in MHz + float fTFlops; // Teraflops of GPU. Zero if not GCN. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD +}; + +/// The top level GPU information returned from \ref agsInitialize +struct AGSGPUInfo_403 +{ + int agsVersionMajor; // Major field of Major.Minor.Patch AGS version number + int agsVersionMinor; // Minor field of Major.Minor.Patch AGS version number + int agsVersionPatch; // Patch field of Major.Minor.Patch AGS version number + + ArchitectureVersion architectureVersion; // Set to Unknown if not AMD hardware + const char* adapterString; // The adapter name string. NULL if not AMD hardware + int deviceId; // The device id + int revisionId; // The revision id + + const char* driverVersion; // The driver package version + const char* radeonSoftwareVersion; // The Radeon Software Version + + int iNumCUs; // Number of GCN compute units. Zero if not GCN + int iCoreClock; // core clock speed at 100% power in MHz + int iMemoryClock; // memory clock speed at 100% power in MHz + float fTFlops; // Teraflops of GPU. Zero if not GCN. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD +}; + +typedef struct AGSGPUInfo_511 +{ + int agsVersionMajor; ///< Major field of Major.Minor.Patch AGS version number + int agsVersionMinor; ///< Minor field of Major.Minor.Patch AGS version number + int agsVersionPatch; ///< Patch field of Major.Minor.Patch AGS version number + int isWACKCompliant; ///< 1 if WACK compliant. + + const char* driverVersion; ///< The AMD driver package version + const char* radeonSoftwareVersion; ///< The Radeon Software Version + + int numDevices; ///< Number of GPUs in the system + struct AGSDeviceInfo* devices; ///< List of GPUs in the system +} AGSGPUInfo_511; + +/// The top level GPU information returned from \ref agsInit +typedef struct AGSGPUInfo_600 +{ + const char* driverVersion; ///< The AMD driver package version + const char* radeonSoftwareVersion; ///< The Radeon Software Version + + int numDevices; ///< Number of GPUs in the system + struct AGSDeviceInfo* devices; ///< List of GPUs in the system +} AGSGPUInfo_600; + +/// The display mode +typedef enum AGSDisplaySettings_Mode_506 +{ + Mode_506_SDR, ///< SDR mode + Mode_506_scRGB, ///< scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. Uses REC709 primaries. + Mode_506_PQ, ///< PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. Uses BT2020 primaries. + Mode_506_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain +} AGSDisplaySettings_Mode_506; + +typedef enum AGSDisplaySettings_Mode_600 +{ + Mode_600_SDR, ///< SDR mode + Mode_600_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. + Mode_600_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. + Mode_600_FreesyncHDR_scRGB, ///< Freesync HDR scRGB, requiring an FP16 swapchain. A value of 1.0 == 80 nits. + Mode_600_FreesyncHDR_Gamma22, ///< Freesync HDR Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. + Mode_600_DolbyVision, ///< Dolby Vision, requiring an 8888 UNORM swapchain + + Mode_600_Count ///< Number of enumerated display modes +} AGSDisplaySettings_Mode_600; + +/// The struct to specify the display settings to the driver. +typedef struct AGSDisplaySettings_506 +{ + AGSDisplaySettings_Mode_506 mode; ///< The display mode to set the display into + + double chromaticityRedX; ///< Red display primary X coord + double chromaticityRedY; ///< Red display primary Y coord + + double chromaticityGreenX; ///< Green display primary X coord + double chromaticityGreenY; ///< Green display primary Y coord + + double chromaticityBlueX; ///< Blue display primary X coord + double chromaticityBlueY; ///< Blue display primary Y coord + + double chromaticityWhitePointX; ///< White point X coord + double chromaticityWhitePointY; ///< White point Y coord + + double minLuminance; ///< The minimum scene luminance in nits + double maxLuminance; ///< The maximum scene luminance in nits + + double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) + double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) +} AGSDisplaySettings_506; + +/// The struct to specify the display settings to the driver. +typedef struct AGSDisplaySettings_511 +{ + AGSDisplaySettings_Mode_600 mode; ///< The display mode to set the display into + + double chromaticityRedX; ///< Red display primary X coord + double chromaticityRedY; ///< Red display primary Y coord + + double chromaticityGreenX; ///< Green display primary X coord + double chromaticityGreenY; ///< Green display primary Y coord + + double chromaticityBlueX; ///< Blue display primary X coord + double chromaticityBlueY; ///< Blue display primary Y coord + + double chromaticityWhitePointX; ///< White point X coord + double chromaticityWhitePointY; ///< White point Y coord + + double minLuminance; ///< The minimum scene luminance in nits + double maxLuminance; ///< The maximum scene luminance in nits + + double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) + double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) + + // ADDED IN 5.2.0 + int flags; ///< Bitfield of ::AGSDisplaySettingsFlags +} AGSDisplaySettings_511; + +/// The struct to specify the display settings to the driver. +typedef struct AGSDisplaySettings_600 +{ + AGSDisplaySettings_Mode_600 mode; ///< The display mode to set the display into + + double chromaticityRedX; ///< Red display primary X coord + double chromaticityRedY; ///< Red display primary Y coord + + double chromaticityGreenX; ///< Green display primary X coord + double chromaticityGreenY; ///< Green display primary Y coord + + double chromaticityBlueX; ///< Blue display primary X coord + double chromaticityBlueY; ///< Blue display primary Y coord + + double chromaticityWhitePointX; ///< White point X coord + double chromaticityWhitePointY; ///< White point Y coord + + double minLuminance; ///< The minimum scene luminance in nits + double maxLuminance; ///< The maximum scene luminance in nits + + double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) + double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) + + unsigned int disableLocalDimming : 1; ///< Disables local dimming if possible + unsigned int reservedPadding : 31; ///< Reserved +} AGSDisplaySettings_600; + +typedef union AGSDisplaySettings +{ + AGSDisplaySettings_506 agsDisplaySettings506; + AGSDisplaySettings_511 agsDisplaySettings511; + AGSDisplaySettings_600 agsDisplaySettings600; +} AGSDisplaySettings; + +/// The result returned from \ref agsCheckDriverVersion +typedef enum AGSDriverVersionResult +{ + AGS_SOFTWAREVERSIONCHECK_OK, ///< The reported Radeon Software Version is newer or the same as the required version + AGS_SOFTWAREVERSIONCHECK_OLDER, ///< The reported Radeon Software Version is older than the required version + AGS_SOFTWAREVERSIONCHECK_UNDEFINED ///< The check could not determine as result. This could be because it is a private or custom driver or just invalid arguments. +} AGSDriverVersionResult; + +/// +/// Helper function to check the installed software version against the required software version. +/// +/// \param [in] radeonSoftwareVersionReported The Radeon Software Version returned from \ref AGSGPUInfo::radeonSoftwareVersion. +/// \param [in] radeonSoftwareVersionRequired The Radeon Software Version to check against. This is specificed using \ref AGS_MAKE_VERSION. +/// \return The result of the check. +/// +AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoftwareVersionReported, unsigned int radeonSoftwareVersionRequired ); + +/// +/// Function to return the AGS version number. +/// +/// \return The version number made using AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ). +/// +AMD_AGS_API int agsGetVersionNumber( void ); + +/// +/// Function used to initialize the AGS library. +/// Must be called prior to any of the subsequent AGS API calls. +/// Must be called prior to ID3D11Device or ID3D12Device creation. +/// \note The caller of this function should handle the possibility of the call failing in the cases below. One option is to do a vendor id check and only call \ref agsInit if there is an AMD GPU present. +/// \note This function will fail with \ref AGS_NO_AMD_DRIVER_INSTALLED if there is no AMD driver found on the system. +/// \note This function will fail with \ref AGS_LEGACY_DRIVER in Catalyst versions before 12.20. +/// \note It is good practice to check the AGS version returned from AGSGPUInfo against the version defined in the header in case a mismatch between the dll and header has occurred. +/// +/// \param [in, out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls. +/// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration. +/// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system. +/// +AMD_AGS_API AGSReturnCode agsInit( AGSContext** context, const AGSConfiguration* config, AGSGPUInfo_511* gpuInfo ); + +/// +/// Function used to initialize the AGS library. +/// agsVersion must be specified as AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ) or the call will return \ref AGS_INVALID_ARGS. +/// Must be called prior to any of the subsequent AGS API calls. +/// Must be called prior to ID3D11Device or ID3D12Device creation. +/// \note The caller of this function should handle the possibility of the call failing in the cases below. One option is to do a vendor id check and only call \ref agsInitialize if there is an AMD GPU present. +/// \note This function will fail with \ref AGS_NO_AMD_DRIVER_INSTALLED if there is no AMD driver found on the system. +/// \note This function will fail with \ref AGS_LEGACY_DRIVER in Catalyst versions before 12.20. +/// +/// \param [in] agsVersion The API version specified using the \ref AGS_MAKE_VERSION macro. If this does not match the version in the binary this initialization call will fail. +/// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration. +/// \param [out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls. +/// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system. +/// +AMD_AGS_API AGSReturnCode agsInitialize( int agsVersion, const AGSConfiguration* config, AGSContext** context, AGSGPUInfo_600* gpuInfo ); + +/// +/// Function used to clean up the AGS library. +/// +/// \param [in] context Pointer to a context. This function will deallocate the context from the heap. +/// +AMD_AGS_API AGSReturnCode agsDeInit( AGSContext* context ); + +/// +/// Function used to clean up the AGS library. +/// +/// \param [in] context Pointer to a context. This function will deallocate the context from the heap. +/// +AMD_AGS_API AGSReturnCode agsDeInitialize( AGSContext* context ); + +AMD_AGS_API AGSReturnCode agsGetGPUInfo( AGSContext* context, AGSGPUInfo_600 *gpu_info ); + +/// +/// Function used to query the number of GPUs used for Crossfire acceleration. +/// This may be different from the total number of GPUs present in the system. +/// +/// \param [in] context Pointer to a context. +/// \param [out] numGPUs Number of GPUs used for Crossfire acceleration +/// +/// REMOVED IN 5.2.0 +AMD_AGS_API AGSReturnCode agsGetCrossfireGPUCount( AGSContext* context, int* numGPUs ); + +/// +/// Function used to set a specific display into HDR mode +/// \note Setting all of the values apart from color space and transfer function to zero will cause the display to use defaults. +/// \note Call this function after each mode change (switch to fullscreen, any change in swapchain etc). +/// \note HDR10 PQ mode requires a 1010102 swapchain. +/// \note HDR10 scRGB mode requires an FP16 swapchain. +/// \note Freesync HDR scRGB mode requires an FP16 swapchain. +/// \note Freesync HDR Gamma 2.2 mode requires a 1010102 swapchain. +/// \note Dolby Vision requires a 8888 UNORM swapchain. +/// +/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize +/// \param [in] deviceIndex The index of the device listed in \ref AGSGPUInfo::devices. +/// \param [in] displayIndex The index of the display listed in \ref AGSDeviceInfo::displays. +/// \param [in] settings Pointer to the display settings to use. +/// +AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceIndex, int displayIndex, const AGSDisplaySettings* settings ); + +/// @} + +/// \defgroup dx12 DirectX12 Extensions +/// DirectX12 driver extensions +/// @{ + +/// \defgroup dx12init Device and device object creation and cleanup +/// It is now mandatory to call \ref agsDriverExtensionsDX12_CreateDevice when creating a device if the user wants to access any future DX12 AMD extensions. +/// The corresponding \ref agsDriverExtensionsDX12_DestroyDevice call must be called to release the device and free up the internal resources allocated by the create call. +/// @{ + +/// The struct to specify the DX12 device creation parameters +typedef struct AGSDX12DeviceCreationParams +{ + IDXGIAdapter* pAdapter; ///< Pointer to the adapter to use when creating the device. This may be null. + IID iid; ///< The interface ID for the type of device to be created. + D3D_FEATURE_LEVEL FeatureLevel; ///< The minimum feature level to create the device with. +} AGSDX12DeviceCreationParams; + +/// The struct to specify DX12 additional device creation parameters +typedef struct AGSDX12ExtensionParams +{ + const WCHAR* pAppName; ///< Application name + const WCHAR* pEngineName; ///< Engine name + unsigned int appVersion; ///< Application version + unsigned int engineVersion; ///< Engine version + // ADDED IN 5.4.0 + unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. Refer to the \ref agsDriverExtensionsDX12_CreateDevice documentation for more details. +} AGSDX12ExtensionParams; + +/// The struct to hold all the returned parameters from the device creation call +typedef struct AGSDX12ReturnedParams +{ + ID3D12Device* pDevice; ///< The newly created device + /* + This was changed to a struct in 6.0.0+ but it's still the size of an unsigned int. + Ignoring this change for now. + + typedef struct ExtensionsSupported /// Extensions for DX12 + { + unsigned int intrinsics16 : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. ReadFirstLane, ReadLane, LaneID, Swizzle, Ballot, MBCount, Med3, Barycentrics + unsigned int intrinsics17 : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. WaveReduce, WaveScan + unsigned int userMarkers : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. + unsigned int appRegistration : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. + unsigned int UAVBindSlot : 1; ///< Supported in Radeon Software Version 19.5.1 onwards. + unsigned int intrinsics19 : 1; ///< Supported in Radeon Software Version 19.12.2 onwards. DrawIndex, AtomicU64 + unsigned int baseVertex : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. + unsigned int baseInstance : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. + unsigned int getWaveSize : 1; ///< Supported in Radeon Software Version 20.5.1 onwards. + unsigned int floatConversion : 1; ///< Supported in Radeon Software Version 20.5.1 onwards. + unsigned int readLaneAt : 1; ///< Supported in Radeon Software Version 20.11.2 onwards. + unsigned int rayHitToken : 1; ///< Supported in Radeon Software Version 20.11.2 onwards. + unsigned int shaderClock : 1; ///< Supported in Radeon Software Version 23.1.1 onwards. + unsigned int padding : 19; ///< Reserved + } ExtensionsSupported; + ExtensionsSupported extensionsSupported; ///< List of supported extensions + */ + + unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX12_CreateDevice will fill in to indicate which extensions are supported. See \ref AGSDriverExtensionDX12 +} AGSDX12ReturnedParams; + + +// Description +// Function used to query the number of GPUs in the system. +// This number may be different from agsGetCrossfireGPUCount as it reports +// all devices installed in the system, and not only those configured for +// Crossfire. +// +// Input params +// context - Pointer to a context. +// +// Output params +// numGPUs - Number of GPUs in the system. +// +AMD_AGS_API AGSReturnCode agsGetTotalGPUCount( AGSContext* context, int* numGPUs ); + +// Description +// Function used to query the memory size of a GPU. The number of GPUs should +// be obtained using agsGetTotalGPUCount +// +// Input params +// context - Pointer to a context. +// gpuIndex - The GPU index to query +// +// Output params +// sizeInBytes - Memory size on the device in bytes +// +AMD_AGS_API AGSReturnCode agsGetGPUMemorySize( AGSContext* context, int gpuIndex, long long* sizeInBytes ); + +// Description +// Function used to query Eyefinity configuration state information relevant to ISVs. State info returned +// includes: whether Eyefinity is enabled or not, SLS grid configuration, SLS dimensions, whether bezel +// compensation is enabled or not, SLS grid coordinate for each display, total rendering area for each +// display, visible rendering area for each display, and a preferred display flag. +// +// This function needs to be called twice. Firstly to null into eyefinityInfo and displaysInfo. This will +// return the number of AGSDisplayInfo objects to allocate. +// Second call requires valid pointers to eyefinityInfo and the newly allocated displaysInfo array. It is the +// responsibility of the caller to free this memory. +// +// +// Input params +// context - Pointer to a context. +// displayIndex - Operating system specific display index identifier. The value used should be the +// index of the display used for rendering operations. On Windows operating systems, +// the value can be queried using the EnumDisplayDevices() API. +// +// Output params +// eyefinityInfo - This is a pointer to an AGSEyefinityInfo structure that contains system Eyefinity +// configuration information. +// numDisplaysInfo - Pointer to the number of AGSDisplayInfo structures stored in the returned +// displaysInfo array. The value returned is equal to the number of displays +// used for the Eyefinity setup. +// displaysInfo - Pointer to an array of AGSDisplayInfo structures that contains per display +// Eyefinity configuration information. +// +AMD_AGS_API AGSReturnCode agsGetEyefinityConfigInfo( AGSContext *context, int displayIndex, AGSEyefinityInfo *eyefinityInfo, int *numDisplaysInfo, AGSDisplayInfo_403 *displaysInfo ); + +/// +/// Function used to create a D3D12 device with additional AMD-specific initialization parameters. +/// +/// When using the HLSL shader extensions please note: +/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION (/Od) option, otherwise it will not work. +/// * The shader compiler needs D3DCOMPILE_ENABLE_STRICTNESS (/Ges) enabled. +/// * The intrinsic instructions require a 5.1 shader model. +/// * The Root Signature will need to reserve an extra UAV resource slot. This is not a real resource that requires allocating, it is just used to encode the intrinsic instructions. +/// +/// The easiest way to set up the reserved UAV slot is to specify it at u0. The register space id will automatically be assumed to be \ref AGS_DX12_SHADER_INTRINSICS_SPACE_ID. +/// The HLSL expects this as default and the set up code would look similar to this: +/// \code{.cpp} +/// CD3DX12_DESCRIPTOR_RANGE range[]; +/// ... +/// range[ 0 ].Init( D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, AGS_DX12_SHADER_INTRINSICS_SPACE_ID ); // u0 at driver-reserved space id +/// \endcode +/// +/// Newer drivers also support a user-specified slot in which case the register space id is assumed to be 0. It is important that the \ref AGSDX12ReturnedParams::ExtensionsSupported::UAVBindSlot bit is set. +/// to ensure the driver can support this. If not, then u0 and \ref AGS_DX12_SHADER_INTRINSICS_SPACE_ID must be used. +/// If the driver does support this feature and a non zero slot is required, then the HLSL must also define AMD_EXT_SHADER_INTRINSIC_UAV_OVERRIDE as the matching slot value. +/// +/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize +/// \param [in] creationParams Pointer to the struct to specify the existing DX12 device creation parameters. +/// \param [in] extensionParams Optional pointer to the struct to specify DX12 additional device creation parameters. +/// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_CreateDevice( AGSContext* context, const AGSDX12DeviceCreationParams* creationParams, const AGSDX12ExtensionParams* extensionParams, AGSDX12ReturnedParams* returnedParams ); + +/// +/// Function to destroy the D3D12 device. +/// This call will also cleanup any AMD-specific driver extensions for D3D12. +/// +/// \param [in] context Pointer to a context. +/// \param [in] device Pointer to the D3D12 device. +/// \param [out] deviceReferences Optional pointer to an unsigned int that will be set to the value returned from device->Release(). +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DestroyDevice( AGSContext* context, ID3D12Device* device, unsigned int* deviceReferences ); + +/// +/// Function used to initialize the AMD-specific driver extensions for D3D12. +/// Extensions require support in the driver, therefore it is important to check the extensionsSupported bitfield. +/// +/// When using the HLSL shader extensions please note: +/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION option, otherwise it will not work. +/// * The intrinsic instructions require a 5.1 shader model. +/// * The Root Signature will need to use an extra resource and sampler. These are not real resources/samplers, they are just used to encode the intrinsic instruction. +/// +/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize +/// \param [in] device The D3D12 device. +/// \param [out] extensionsSupported Pointer to a bit mask that this function will fill in to indicate which extensions are supported. See ::AGSDriverExtensionDX12 +/// +/// REMOVED IN 5.2.0 +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_Init( AGSContext* context, ID3D12Device* device, unsigned int* extensionsSupported ); + +/// +/// Function used to cleanup any AMD-specific driver extensions for D3D12 +/// +/// \param [in] context Pointer to a context. +/// +/// REMOVED IN 5.2.0 +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DeInit( AGSContext* context ); + +/// @} + +/// \defgroup dx12usermarkers User Markers +/// @{ + +/// +/// Function used to push an AMD user marker onto the command list. +/// This is only has an effect if \ref AGSDX12ReturnedParams::ExtensionsSupported::userMarkers is present. +/// Supported in Radeon Software Version 17.9.1 onwards. +/// +/// \param [in] context Pointer to a context. +/// \param [in] commandList Pointer to the command list. +/// \param [in] data The marker string. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_PushMarker( AGSContext* context, ID3D12GraphicsCommandList* commandList, const char* data ); + +/// +/// Function used to pop an AMD user marker on the command list. +/// Supported in Radeon Software Version 17.9.1 onwards. +/// +/// \param [in] context Pointer to a context. +/// \param [in] commandList Pointer to the command list. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_PopMarker( AGSContext* context, ID3D12GraphicsCommandList* commandList ); + +/// +/// Function used to insert an single event AMD user marker onto the command list. +/// Supported in Radeon Software Version 17.9.1 onwards. +/// +/// \param [in] context Pointer to a context. +/// \param [in] commandList Pointer to the command list. +/// \param [in] data The marker string. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_SetMarker( AGSContext* context, ID3D12GraphicsCommandList* commandList, const char* data ); + +/// @} + +/// @} + +/// \defgroup dx11 DirectX11 Extensions +/// DirectX11 driver extensions +/// @{ + +/// \defgroup dx11init Device creation and cleanup +/// It is now mandatory to call \ref agsDriverExtensionsDX11_CreateDevice when creating a device if the user wants to access any DX11 AMD extensions. +/// The corresponding \ref agsDriverExtensionsDX11_DestroyDevice call must be called to release the device and free up the internal resources allocated by the create call. +/// @{ + +/// The struct to specify the existing DX11 device creation parameters +typedef struct AGSDX11DeviceCreationParams +{ + IDXGIAdapter* pAdapter; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + D3D_DRIVER_TYPE DriverType; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + HMODULE Software; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + UINT Flags; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + const D3D_FEATURE_LEVEL* pFeatureLevels; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + UINT FeatureLevels; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + UINT SDKVersion; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc; ///< Optional swapchain description. Specify this to invoke D3D11CreateDeviceAndSwapChain instead of D3D11CreateDevice. This must be null on the WACK compliant version +} AGSDX11DeviceCreationParams; + +/// The struct to specify DX11 additional device creation parameters +typedef struct AGSDX11ExtensionParams_511 +{ + unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. This must match the slot defined in the HLSL, i.e. #define AmdDxExtShaderIntrinsicsUAVSlot. + /// The default slot is 7, but the caller is free to use an alternative slot. + const WCHAR* pAppName; ///< Application name + UINT appVersion; ///< Application version + const WCHAR* pEngineName; ///< Engine name + UINT engineVersion; ///< Engine version +} AGSDX11ExtensionParams_511; + +typedef struct AGSDX11ExtensionParams_520 +{ + const WCHAR* pAppName; ///< Application name + const WCHAR* pEngineName; ///< Engine name + unsigned int appVersion; ///< Application version + unsigned int engineVersion; ///< Engine version + unsigned int numBreadcrumbMarkers; ///< The number of breadcrumb markers to allocate. Each marker is a uint64 (ie 8 bytes). If 0, the system is disabled. + unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. This must match the slot defined in the HLSL, i.e. "#define AmdDxExtShaderIntrinsicsUAVSlot". + /// The default slot is 7, but the caller is free to use an alternative slot. + /// If 0 is specified, then the default of 7 will be used. + AGSCrossfireMode crossfireMode; ///< Desired Crossfire mode +} AGSDX11ExtensionParams_520; + +typedef union AGSDX11ExtensionParams +{ + AGSDX11ExtensionParams_511 agsDX11ExtensionParams511; + AGSDX11ExtensionParams_520 agsDX11ExtensionParams520; +} AGSDX11ExtensionParams; + +/// The struct to hold all the returned parameters from the device creation call +typedef struct AGSDX11ReturnedParams_511 +{ + ID3D11Device* pDevice; ///< The newly created device + D3D_FEATURE_LEVEL FeatureLevel; ///< The feature level supported by the newly created device + ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context + IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. This is not supported on the WACK compliant version + unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX11_CreateDevice will fill in to indicate which extensions are supported. See AGSDriverExtensionDX11 +} AGSDX11ReturnedParams_511; + +typedef struct AGSDX11ReturnedParams_520 +{ + ID3D11Device* pDevice; ///< The newly created device + ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context + IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. This is not supported on the WACK compliant version + D3D_FEATURE_LEVEL FeatureLevel; ///< The feature level supported by the newly created device + unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX11_CreateDevice will fill in to indicate which extensions are supported. See \ref AGSDriverExtensionDX11 + unsigned int crossfireGPUCount; ///< The number of GPUs that are active for this app + void* breadcrumbBuffer; ///< The CPU buffer returned if the initialization of the breadcrumb was successful. +} AGSDX11ReturnedParams_520; + +typedef struct AGSDX11ExtensionsSupported_600 /// Extensions for DX11 +{ + unsigned int quadList : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int screenRectList : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int uavOverlap : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int depthBoundsTest : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int multiDrawIndirect : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int multiDrawIndirectCountIndirect : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int crossfireAPI : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int createShaderControls : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int intrinsics16 : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. ReadFirstLane, ReadLane, LaneID, Swizzle, Ballot, MBCount, Med3, Barycentrics + unsigned int multiView : 1; ///< Supported in Radeon Software Version 16.12.1 onwards. + unsigned int intrinsics17 : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. WaveReduce, WaveScan + unsigned int appRegistration : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. + unsigned int breadcrumbMarkers : 1; ///< Supported in Radeon Software Version 17.11.1 onwards. + unsigned int MDIDeferredContexts : 1; ///< Supported in Radeon Software Version 18.8.1 onwards. + unsigned int UAVOverlapDeferredContexts : 1; ///< Supported in Radeon Software Version 18.8.1 onwards. + unsigned int depthBoundsDeferredContexts : 1; ///< Supported in Radeon Software Version 18.8.1 onwards. + unsigned int intrinsics19 : 1; ///< Supported in Radeon Software Version 19.12.2 onwards. DrawIndex, AtomicU64 + unsigned int getWaveSize : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. + unsigned int baseVertex : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. + unsigned int baseInstance : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. + unsigned int padding : 12; ///< Reserved +} AGSDX11ExtensionsSupported_600; + +typedef struct AGSDX11ReturnedParams_600 +{ + ID3D11Device* pDevice; ///< The newly created device + ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context + IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. + D3D_FEATURE_LEVEL featureLevel; ///< The feature level supported by the newly created device + AGSDX11ExtensionsSupported_600 extensionsSupported; ///< List of supported extensions + unsigned int crossfireGPUCount; ///< The number of GPUs that are active for this app + void* breadcrumbBuffer; ///< The CPU buffer returned if the initialization of the breadcrumb was successful +} AGSDX11ReturnedParams_600; + +typedef union AGSDX11ReturnedParams +{ + AGSDX11ReturnedParams_511 agsDX11ReturnedParams511; + AGSDX11ReturnedParams_520 agsDX11ReturnedParams520; + AGSDX11ReturnedParams_600 agsDX11ReturnedParams600; +} AGSDX11ReturnedParams; + +/// +/// Function used to create a D3D11 device with additional AMD-specific initialization parameters. +/// +/// When using the HLSL shader extensions please note: +/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION (/Od) option, otherwise it will not work. +/// * The shader compiler needs D3DCOMPILE_ENABLE_STRICTNESS (/Ges) enabled. +/// +/// \param [in] context Pointer to a context. This is generated by \ref agsInititalize +/// \param [in] creationParams Pointer to the struct to specify the existing DX11 device creation parameters. +/// \param [in] extensionParams Optional pointer to the struct to specify DX11 additional device creation parameters. +/// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateDevice( AGSContext* context, const AGSDX11DeviceCreationParams* creationParams, const AGSDX11ExtensionParams* extensionParams, AGSDX11ReturnedParams* returnedParams ); + +/// +/// Function to destroy the D3D11 device and its immediate context. +/// This call will also cleanup any AMD-specific driver extensions for D3D11. +/// +/// \param [in] context Pointer to a context. +/// \param [in] device Pointer to the D3D11 device. +/// \param [out] deviceReferences Optional pointer to an unsigned int that will be set to the value returned from device->Release(). +/// \param [in] immediateContext Pointer to the D3D11 immediate device context. +/// \param [out] immediateContextReferences Optional pointer to an unsigned int that will be set to the value returned from immediateContext->Release(). +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice_520( AGSContext* context, ID3D11Device* device, unsigned int* deviceReferences, ID3D11DeviceContext* immediateContext, unsigned int* immediateContextReferences ); + + +/// +/// Function to destroy the D3D11 device. +/// This call will also cleanup any AMD-specific driver extensions for D3D11. +/// +/// \param [in] context Pointer to a context. +/// \param [in] device Pointer to the D3D11 device. +/// \param [out] references Optional pointer to an unsigned int that will be set to the value returned from device->Release(). +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice_511( AGSContext* context, ID3D11Device* device, unsigned int* references ); + +/// @} + + +/// \defgroup dx11appreg App Registration +/// @{ +/// This extension allows an apllication to voluntarily register itself with the driver, providing a more robust app detection solution and avoid the issue of the driver +/// relying on exe names to match the app to a driver profile. +/// This feature is supported in Radeon Software Version 17.9.2 onwards. +/// Rules: +/// * AppName or EngineName must be set, but both are not required. Engine profiles will be used only if app specific profiles do not exist. +/// * In an engine, the EngineName should be set, so a default profile can be built. If an app modifies the engine, the AppName should be set, to allow a profile for the specific app. +/// * Version number is not mandatory, but heavily suggested. The use of which can prevent the use of profiles for incompatible versions (for instance engine versions that introduce or change features), and can help prevent older profiles from being used (and introducing new bugs) before the profile is tested with new app builds. +/// * If Version numbers are used and a new version is introduced, a new profile will not be enabled until an AMD engineer has been able to update a previous profile, or make a new one. +/// +/// The cases for profile selection are as follows: +/// +/// |Case|Profile Applied| +/// |----|---------------| +/// | App or Engine Version has profile | The profile is used. | +/// | App or Engine Version num < profile version num | The closest profile > the version number is used. | +/// | App or Engine Version num > profile version num | No profile selected/The previous method is used. | +/// | App and Engine Version have profile | The App's profile is used. | +/// | App and Engine Version num < profile version | The closest App profile > the version number is used. | +/// | App and Engine Version, no App profile found | The Engine profile will be used. | +/// | App/Engine name but no Version, has profile | The latest profile is used. | +/// | No name or version, or no profile | The previous app detection method is used. | +/// +/// As shown above, if an App name is given, and a profile is found for that app, that will be prioritized. The Engine name and profile will be used only if no app name is given, or no viable profile is found for the app name. +/// In the case that App nor Engine have a profile, the previous app detection methods will be used. If given a version number that is larger than any profile version number, no profile will be selected. +/// This is specifically to prevent cases where an update to an engine or app will cause catastrophic breaks in the profile, allowing an engineer to test the profile before clearing it for public use with the new engine/app update. +/// +/// @} + +/// \defgroup breadcrumbs Breadcrumb API +/// API for writing top-of-pipe and bottom-of-pipe markers to help track down GPU hangs. +/// +/// The API is available if the \ref AGSDX11ReturnedParams::ExtensionsSupported::breadcrumbMarkers is present. +/// +/// To use the API, a non zero value needs to be specificed in \ref AGSDX11ExtensionParams::numBreadcrumbMarkers. This enables the API (if available) and allocates a system memory buffer +/// which is returned to the user in \ref AGSDX11ReturnedParams::breadcrumbBuffer. +/// +/// The user can now write markers before and after draw calls using \ref agsDriverExtensionsDX11_WriteBreadcrumb. +/// +/// \section background Background +/// +/// A top-of-pipe (TOP) command is scheduled for execution as soon as the command processor (CP) reaches the command. +/// A bottom-of-pipe (BOP) command is scheduled for execution once the previous rendering commands (draw and dispatch) finish execution. +/// TOP and BOP commands do not block CP. i.e. the CP schedules the command for execution then proceeds to the next command without waiting. +/// To effectively use TOP and BOP commands, it is important to understand how they interact with rendering commands: +/// +/// When the CP encounters a rendering command it queues it for execution and moves to the next command. The queued rendering commands are issued in order. +/// There can be multiple rendering commands running in parallel. When a rendering command is issued we say it is at the top of the pipe. When a rendering command +/// finishes execution we say it has reached the bottom of the pipe. +/// +/// A BOP command remains in a waiting queue and is executed once prior rendering commands finish. The queue of BOP commands is limited to 64 entries in GCN generation 1, 2, 3, 4 and 5. +/// If the 64 limit is reached the CP will stop queueing BOP commands and also rendering commands. Developers should limit the number of BOP commands that write markers to avoid contention. +/// In general, developers should limit both TOP and BOP commands to avoid stalling the CP. +/// +/// \subsection eg1 Example 1: +/// +/// \code{.cpp} +/// // Start of a command buffer +/// WriteMarker(TopOfPipe, 1) +/// WriteMarker(BottomOfPipe, 2) +/// WriteMarker(BottomOfPipe, 3) +/// DrawX +/// WriteMarker(BottomOfPipe, 4) +/// WriteMarker(BottomOfPipe, 5) +/// WriteMarker(TopOfPipe, 6) +/// // End of command buffer +/// \endcode +/// +/// In the above example, the CP writes markers 1, 2 and 3 without waiting: +/// Marker 1 is TOP so it's independent from other commands +/// There's no wait for marker 2 and 3 because there are no draws preceding the BOP commands +/// Marker 4 is only written once DrawX finishes execution +/// Marker 5 doesn't wait for additional draws so it is written right after marker 4 +/// Marker 6 can be written as soon as the CP reaches the command. For instance, it is very possible that CP writes marker 6 while DrawX +/// is running and therefore marker 6 gets written before markers 4 and 5 +/// +/// \subsection eg2 Example 2: +/// +/// \code{.cpp} +/// WriteMarker(TopOfPipe, 1) +/// DrawX +/// WriteMarker(BottomOfPipe, 2) +/// WriteMarker(TopOfPipe, 3) +/// DrawY +/// WriteMarker(BottomOfPipe, 4) +/// \endcode +/// +/// In this example marker 1 is written before the start of DrawX +/// Marker 2 is written once DrawX finishes execution +/// Similarly marker 3 is written before the start of DrawY +/// Marker 4 is written once DrawY finishes execution +/// In case of a GPU hang, if markers 1 and 3 are written but markers 2 and 4 are missing we can conclude that: +/// The CP has reached both DrawX and DrawY commands since marker 1 and 3 are present +/// The fact that marker 2 and 4 are missing means that either DrawX is hanging while DrawY is at the top of the pipe or both DrawX and DrawY +/// started and both are simultaneously hanging +/// +/// \subsection eg3 Example 3: +/// +/// \code{.cpp} +/// // Start of a command buffer +/// WriteMarker(BottomOfPipe, 1) +/// DrawX +/// WriteMarker(BottomOfPipe, 2) +/// DrawY +/// WriteMarker(BottomOfPipe, 3) +/// DrawZ +/// WriteMarker(BottomOfPipe, 4) +/// // End of command buffer +/// \endcode +/// +/// In this example marker 1 is written before the start of DrawX +/// Marker 2 is written once DrawX finishes +/// Marker 3 is written once DrawY finishes +/// Marker 4 is written once DrawZ finishes +/// If the GPU hangs and only marker 1 is written we can conclude that the hang is happening in either DrawX, DrawY or DrawZ +/// If the GPU hangs and only marker 1 and 2 are written we can conclude that the hang is happening in DrawY or DrawZ +/// If the GPU hangs and only marker 4 is missing we can conclude that the hang is happening in DrawZ +/// +/// \subsection eg4 Example 4: +/// +/// \code{.cpp} +/// Start of a command buffer +/// WriteMarker(TopOfPipe, 1) +/// DrawX +/// WriteMarker(TopOfPipe, 2) +/// DrawY +/// WriteMarker(TopOfPipe, 3) +/// DrawZ +/// // End of command buffer +/// \endcode +/// +/// In this example, in case the GPU hangs and only marker 1 is written we can conclude that the hang is happening in DrawX +/// In case the GPU hangs and only marker 1 and 2 are written we can conclude that the hang is happening in DrawX or DrawY +/// In case the GPU hangs and all 3 markers are written we can conclude that the hang is happening in any of DrawX, DrawY or DrawZ +/// +/// \subsection eg5 Example 5: +/// +/// \code{.cpp} +/// DrawX +/// WriteMarker(TopOfPipe, 1) +/// WriteMarker(BottomOfPipe, 2) +/// DrawY +/// WriteMarker(TopOfPipe, 3) +/// WriteMarker(BottomOfPipe, 4) +/// \endcode +/// +/// Marker 1 is written right after DrawX is queued for execution. +/// Marker 2 is only written once DrawX finishes execution. +/// Marker 3 is written right after DrawY is queued for execution. +/// Marker 4 is only written once DrawY finishes execution +/// If marker 1 is written we would know that the CP has reached the command DrawX (DrawX at the top of the pipe). +/// If marker 2 is written we can say that DrawX has finished execution (DrawX at the bottom of the pipe). +/// In case the GPU hangs and only marker 1 and 3 are written we can conclude that the hang is happening in DrawX or DrawY +/// In case the GPU hangs and only marker 1 is written we can conclude that the hang is happening in DrawX +/// In case the GPU hangs and only marker 4 is missing we can conclude that the hang is happening in DrawY +/// +/// \section data Retrieving GPU Data +/// +/// In the event of a GPU hang, the user can inspect the system memory buffer to determine which draw has caused the hang. +/// For example: +/// \code{.cpp} +/// // Force the work to be flushed to prevent CPU ahead of GPU +/// g_pImmediateContext->Flush(); +/// +/// // Present the information rendered to the back buffer to the front buffer (the screen) +/// HRESULT hr = g_pSwapChain->Present( 0, 0 ); +/// +/// // Read the marker data buffer once detect device lost +/// if ( hr != S_OK ) +/// { +/// for (UINT i = 0; i < g_NumMarkerWritten; i++) +/// { +/// UINT64* pTempData; +/// pTempData = static_cast(pMarkerBuffer); +/// +/// // Write the marker data to file +/// ofs << i << "\r\n"; +/// ofs << std::hex << *(pTempData + i * 2) << "\r\n"; +/// ofs << std::hex << *(pTempData + (i * 2 + 1)) << "\r\n"; +/// +/// WCHAR s1[256]; +/// setlocale(LC_NUMERIC, "en_US.iso88591"); +/// +/// // Output the marker data to console +/// swprintf(s1, 256, L" The Draw count is %d; The Top maker is % 016llX and the Bottom marker is % 016llX \r\n", i, *(pTempData + i * 2), *(pTempData + (i * 2 + 1))); +/// +/// OutputDebugStringW(s1); +/// } +/// } +/// \endcode +/// +/// The console output would resemble something like: +/// \code{.cpp} +/// D3D11: Removing Device. +/// D3D11 ERROR: ID3D11Device::RemoveDevice: Device removal has been triggered for the following reason (DXGI_ERROR_DEVICE_HUNG: The Device took an unreasonable amount of time to execute its commands, or the hardware crashed/hung. As a result, the TDR (Timeout Detection and Recovery) mechanism has been triggered. The current Device Context was executing commands when the hang occurred. The application may want to respawn and fallback to less aggressive use of the display hardware). [ EXECUTION ERROR #378: DEVICE_REMOVAL_PROCESS_AT_FAULT] +/// The Draw count is 0; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF +/// The Draw count is 1; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF +/// The Draw count is 2; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF +/// The Draw count is 3; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF +/// The Draw count is 4; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF +/// The Draw count is 5; The Top maker is CDCDCDCDCDCDCDCD and the Bottom marker is CDCDCDCDCDCDCDCD +/// The Draw count is 6; The Top maker is CDCDCDCDCDCDCDCD and the Bottom marker is CDCDCDCDCDCDCDCD +/// The Draw count is 7; The Top maker is CDCDCDCDCDCDCDCD and the Bottom marker is CDCDCDCDCDCDCDCD +/// \endcode +/// +/// @{ + +/// The breadcrumb marker struct used by \ref agsDriverExtensionsDX11_WriteBreadcrumb +typedef struct AGSBreadcrumbMarker +{ + unsigned long long markerData; ///< The user data to write. + enum + { + TopOfPipe = 0, ///< Top-of-pipe marker + BottomOfPipe = 1 ///< Bottom-of-pipe marker + } type; ///< Whether this marker is top or bottom of pipe. + unsigned int index; ///< The index of the marker. This should be less than the value specified in \ref AGSDX11ExtensionParams::numBreadcrumbMarkers +} AGSBreadcrumbMarker; + +/// +/// Function to write a breadcrumb marker. +/// +/// This method inserts a write marker operation in the GPU command stream. In the case where the GPU is hanging the write +/// command will never be reached and the marker will never get written to memory. +/// +/// In order to use this function, \ref AGSDX11ExtensionParams::numBreadcrumbMarkers must be set to a non zero value. +/// +/// \param [in] context Pointer to a context. +/// \param [in] marker Pointer to a marker. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_WriteBreadcrumb( AGSContext* context, const AGSBreadcrumbMarker* marker ); + +/// @} + +/// \defgroup dx11Topology Extended Topology +/// API for primitive topologies +/// @{ + +/// Additional topologies supported via extensions +typedef enum AGSPrimitiveTopologyDX11 +{ + AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, ///< Quad list + AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 ///< Screen rect list +} AGSPrimitiveTopologyDX11; + +/// +/// Function used to set the primitive topology. If you are using any of the extended topology types, then this function should +/// be called to set ALL topology types. +/// +/// The Quad List extension is a convenient way to submit quads without using an index buffer. Note that this still submits two triangles at the driver level. +/// In order to use this function, AGS must already be initialized and agsDriverExtensionsDX11_Init must have been called successfully. +/// +/// The Screen Rect extension, which is only available on GCN hardware, allows the user to pass in three of the four corners of a rectangle. +/// The hardware then uses the bounding box of the vertices to rasterize the rectangle primitive (i.e. as a rectangle rather than two triangles). +/// \note Note that this will not return valid interpolated values, only valid SV_Position values. +/// \note If either the Quad List or Screen Rect extension are used, then agsDriverExtensionsDX11_IASetPrimitiveTopology should be called in place of the native DirectX11 equivalent all the time. +/// +/// \param [in] context Pointer to a context. +/// \param [in] topology The topology to set on the D3D11 device. This can be either an AGS-defined topology such as AGS_PRIMITIVE_TOPOLOGY_QUADLIST +/// or a standard D3D-defined topology such as D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP. +/// NB. the AGS-defined types will require casting to a D3D_PRIMITIVE_TOPOLOGY type. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_IASetPrimitiveTopology( AGSContext* context, enum D3D_PRIMITIVE_TOPOLOGY topology ); + +/// @} + +/// \defgroup dx11UAVOverlap UAV Overlap +/// API for enabling overlapping UAV writes +/// @{ + +/// +/// Function used indicate to the driver that it doesn't need to sync the UAVs bound for the subsequent set of back-to-back dispatches. +/// When calling back-to-back draw calls or dispatch calls that write to the same UAV, the AMD DX11 driver will automatically insert a barrier to ensure there are no write after write (WAW) hazards. +/// If the app can guarantee there is no overlap between the writes between these calls, then this extension will remove those barriers allowing the work to run in parallel on the GPU. +/// +/// Usage would be as follows: +/// \code{.cpp} +/// m_device->Dispatch( ... ); // First call that writes to the UAV +/// +/// // Disable automatic WAW syncs +/// agsDriverExtensionsDX11_BeginUAVOverlap( m_agsContext ); +/// +/// // Submit other dispatches that write to the same UAV concurrently +/// m_device->Dispatch( ... ); +/// m_device->Dispatch( ... ); +/// m_device->Dispatch( ... ); +/// +/// // Reenable automatic WAW syncs +/// agsDriverExtensionsDX11_EndUAVOverlap( m_agsContext ); +/// \endcode +/// +/// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. +/// with the AGS_DX11_EXTENSION_DEFERRED_CONTEXTS bit. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_BeginUAVOverlap_520( AGSContext* context ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_BeginUAVOverlap( AGSContext* context, ID3D11DeviceContext* dxContext ); + +/// +/// Function used indicate to the driver it can no longer overlap the batch of back-to-back dispatches that has been submitted. +/// +/// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. +/// with the AGS_DX11_EXTENSION_DEFERRED_CONTEXTS bit. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap_520( AGSContext* context ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap( AGSContext* context, ID3D11DeviceContext* dxContext ); + +/// @} + +/// \defgroup dx11DepthBoundsTest Depth Bounds Test +/// API for enabling depth bounds testing +/// @{ + +/// +/// Function used to set the depth bounds test extension +/// +/// \param [in] context Pointer to a context +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. +/// \param [in] enabled Whether to enable or disable the depth bounds testing. If disabled, the next two args are ignored. +/// \param [in] minDepth The near depth range to clip against. +/// \param [in] maxDepth The far depth range to clip against. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* context, bool enabled, float minDepth, float maxDepth ); + +/* Since 5.3.0 */ +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds_530( AGSContext* context, ID3D11DeviceContext* dxContext, bool enabled, float minDepth, float maxDepth ); + +/// @} + +/// \defgroup mdi Multi Draw Indirect (MDI) +/// API for dispatching multiple instanced draw commands. +/// The multi draw indirect extensions allow multiple sets of DrawInstancedIndirect to be submitted in one API call. +/// The draw calls are issued on the GPU's command processor (CP), potentially saving the significant CPU overheads incurred by submitting the equivalent draw calls on the CPU. +/// +/// The extension allows the following code: +/// \code{.cpp} +/// // Submit n batches of DrawIndirect calls +/// for ( int i = 0; i < n; i++ ) +/// deviceContext->DrawIndexedInstancedIndirect( buffer, i * sizeof( cmd ) ); +/// \endcode +/// To be replaced by the following call: +/// \code{.cpp} +/// // Submit all n batches in one call +/// agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( m_agsContext, deviceContext, n, buffer, 0, sizeof( cmd ) ); +/// \endcode +/// +/// The buffer used for the indirect args must be of the following formats: +/// \code{.cpp} +/// // Buffer layout for agsDriverExtensions_MultiDrawInstancedIndirect +/// struct DrawInstancedIndirectArgs +/// { +/// UINT VertexCountPerInstance; +/// UINT InstanceCount; +/// UINT StartVertexLocation; +/// UINT StartInstanceLocation; +/// }; +/// +/// // Buffer layout for agsDriverExtensions_MultiDrawIndexedInstancedIndirect +/// struct DrawIndexedInstancedIndirectArgs +/// { +/// UINT IndexCountPerInstance; +/// UINT InstanceCount; +/// UINT StartIndexLocation; +/// UINT BaseVertexLocation; +/// UINT StartInstanceLocation; +/// }; +/// \endcode +/// +/// Example usage can be seen in AMD's GeometryFX (https://github.com/GPUOpen-Effects/GeometryFX). In particular, in this file: https://github.com/GPUOpen-Effects/GeometryFX/blob/master/amd_geometryfx/src/AMD_GeometryFX_Filtering.cpp +/// +/// @{ + +/// +/// Function used to submit a batch of draws via MultiDrawIndirect +/// +/// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. +/// \param [in] drawCount The number of draws. +/// \param [in] pBufferForArgs The args buffer. +/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. +/// \param [in] byteStrideForArgs The per element stride of the args buffer. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirect_520( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); + +/// +/// Function used to submit a batch of draws via MultiDrawIndirect +/// +/// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. +/// \param [in] drawCount The number of draws. +/// \param [in] pBufferForArgs The args buffer. +/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. +/// \param [in] byteStrideForArgs The per element stride of the args buffer. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect_520( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); + +/// +/// Function used to submit a batch of draws via MultiDrawIndirect +/// +/// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. +/// \param [in] pBufferForDrawCount The draw count buffer. +/// \param [in] alignedByteOffsetForDrawCount The offset into the draw count buffer. +/// \param [in] pBufferForArgs The args buffer. +/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. +/// \param [in] byteStrideForArgs The per element stride of the args buffer. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect_520( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); + +/// +/// Function used to submit a batch of draws via MultiDrawIndirect +/// +/// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. +/// \param [in] pBufferForDrawCount The draw count buffer. +/// \param [in] alignedByteOffsetForDrawCount The offset into the draw count buffer. +/// \param [in] pBufferForArgs The args buffer. +/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. +/// \param [in] byteStrideForArgs The per element stride of the args buffer. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect_520( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); + +/// @} + +/// \defgroup shadercompiler Shader Compiler Controls +/// API for controlling DirectX11 shader compilation. +/// Check support for this feature using the AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS bit. +/// Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. +/// @{ + +/// +/// This method can be used to limit the maximum number of threads the driver uses for asynchronous shader compilation. +/// Setting it to 0 will disable asynchronous compilation completely and force the shaders to be compiled "inline" on the threads that call Create*Shader. +/// +/// This method can only be called before any shaders are created and being compiled by the driver. +/// If this method is called after shaders have been created the function will return AGS_FAILURE. +/// This function only sets an upper limit.The driver may create fewer threads than allowed by this function. +/// +/// \param [in] context Pointer to a context. +/// \param [in] numberOfThreads The maximum number of threads to use. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount( AGSContext* context, unsigned int numberOfThreads ); + +/// +/// This method can be used to determine the total number of asynchronous shader compile jobs that are either +/// queued for waiting for compilation or being compiled by the driver’'s asynchronous compilation threads. +/// This method can be called at any during the lifetime of the driver. +/// +/// \param [in] context Pointer to a context. +/// \param [out] numberOfJobs Pointer to the number of jobs in flight currently. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NumPendingAsyncCompileJobs( AGSContext* context, unsigned int* numberOfJobs ); + +/// +/// This method can be used to enable or disable the disk based shader cache. +/// Enabling/disabling the disk cache is not supported if is it disabled explicitly via Radeon Settings or by an app profile. +/// Calling this method under these conditions will result in AGS_FAILURE being returned. +/// It is recommended that this method be called before any shaders are created by the application and being compiled by the driver. +/// Doing so at any other time may result in the cache being left in an inconsistent state. +/// +/// \param [in] context Pointer to a context. +/// \param [in] enable Whether to enable the disk cache. 0 to disable, 1 to enable. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDiskShaderCacheEnabled( AGSContext* context, int enable ); + +/// @} + +/// \defgroup multiview Multiview +/// API for multiview broadcasting. +/// Check support for this feature using the AGS_DX11_EXTENSION_MULTIVIEW bit. +/// Supported in Radeon Software Version 16.12.1 (driver version 16.50.2001) onwards. +/// @{ + +/// +/// Function to control draw calls replication to multiple viewports and RT slices. +/// Setting any mask to 0 disables draw replication. +/// +/// \param [in] context Pointer to a context. +/// \param [in] vpMask Viewport control bit mask. +/// \param [in] rtSliceMask RT slice control bit mask. +/// \param [in] vpMaskPerRtSliceEnabled If 0, 16 lower bits of vpMask apply to all RT slices; if 1 each 16 bits of 64-bit mask apply to corresponding 4 RT slices. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetViewBroadcastMasks( AGSContext* context, unsigned long long vpMask, unsigned long long rtSliceMask, int vpMaskPerRtSliceEnabled ); + +/// +/// Function returns max number of supported clip rectangles. +/// +/// \param [in] context Pointer to a context. +/// \param [out] maxRectCount Returned max number of clip rectangles. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_GetMaxClipRects( AGSContext* context, unsigned int* maxRectCount ); + +/// The inclusion mode for the rect +typedef enum AGSClipRect_Mode +{ + ClipRectIncluded = 0, ///< Include the rect + ClipRectExcluded = 1 ///< Exclude the rect +} AGSClipRect_Mode; + +/// The clip rectangle struct used by \ref agsDriverExtensionsDX11_SetClipRects +typedef struct AGSClipRect +{ + AGSClipRect_Mode mode; ///< Include/exclude rect region + AGSRect rect; ///< The rect to include/exclude +} AGSClipRect; + + + +/// +/// Function sets clip rectangles. +/// +/// \param [in] context Pointer to a context. +/// \param [in] clipRectCount Number of specified clip rectangles. Use 0 to disable clip rectangles. +/// \param [in] clipRects Array of clip rectangles. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetClipRects( AGSContext* context, unsigned int clipRectCount, const AGSClipRect* clipRects ); + +/// @} + +/// \defgroup cfxapi Explicit Crossfire API +/// API for explicit control over Crossfire +/// @{ + +/// The Crossfire API transfer types +typedef enum AGSAfrTransferType +{ + AGS_AFR_TRANSFER_DEFAULT = 0, ///< Default Crossfire driver resource tracking + AGS_AFR_TRANSFER_DISABLE = 1, ///< Turn off driver resource tracking + AGS_AFR_TRANSFER_1STEP_P2P = 2, ///< App controlled GPU to next GPU transfer + AGS_AFR_TRANSFER_2STEP_NO_BROADCAST = 3, ///< App controlled GPU to next GPU transfer using intermediate system memory + AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST = 4, ///< App controlled GPU to all render GPUs transfer using intermediate system memory +} AGSAfrTransferType; + +/// The Crossfire API transfer engines +typedef enum AGSAfrTransferEngine +{ + AGS_AFR_TRANSFERENGINE_DEFAULT = 0, ///< Use default engine for Crossfire API transfers + AGS_AFR_TRANSFERENGINE_3D_ENGINE = 1, ///< Use 3D engine for Crossfire API transfers + AGS_AFR_TRANSFERENGINE_COPY_ENGINE = 2, ///< Use Copy engine for Crossfire API transfers +} AGSAfrTransferEngine; + +/// +/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. +/// +/// \param [in] context Pointer to a context. +/// \param [in] desc Pointer to the D3D11 resource description. +/// \param [in] initialData Optional pointer to the initializing data for the resource. +/// \param [out] buffer Returned pointer to the resource. +/// \param [in] transferType The transfer behavior. +/// \param [in] transferEngine The transfer engine to use. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateBuffer( AGSContext* context, const D3D11_BUFFER_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Buffer** buffer, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); + +/// +/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. +/// +/// \param [in] context Pointer to a context. +/// \param [in] desc Pointer to the D3D11 resource description. +/// \param [in] initialData Optional pointer to the initializing data for the resource. +/// \param [out] texture1D Returned pointer to the resource. +/// \param [in] transferType The transfer behavior. +/// \param [in] transferEngine The transfer engine to use. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateTexture1D( AGSContext* context, const D3D11_TEXTURE1D_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Texture1D** texture1D, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); + +/// +/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. +/// +/// \param [in] context Pointer to a context. +/// \param [in] desc Pointer to the D3D11 resource description. +/// \param [in] initialData Optional pointer to the initializing data for the resource. +/// \param [out] texture2D Returned pointer to the resource. +/// \param [in] transferType The transfer behavior. +/// \param [in] transferEngine The transfer engine to use. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateTexture2D( AGSContext* context, const D3D11_TEXTURE2D_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Texture2D** texture2D, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); + +/// +/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. +/// +/// \param [in] context Pointer to a context. +/// \param [in] desc Pointer to the D3D11 resource description. +/// \param [in] initialData Optional pointer to the initializing data for the resource. +/// \param [out] texture3D Returned pointer to the resource. +/// \param [in] transferType The transfer behavior. +/// \param [in] transferEngine The transfer engine to use. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateTexture3D( AGSContext* context, const D3D11_TEXTURE3D_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Texture3D** texture3D, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); + +/// +/// Function to notify the driver that we have finished writing to the resource this frame. +/// This will initiate a transfer for AGS_AFR_TRANSFER_1STEP_P2P, +/// AGS_AFR_TRANSFER_2STEP_NO_BROADCAST, and AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST. +/// +/// \param [in] context Pointer to a context. +/// \param [in] resource Pointer to the resource. +/// \param [in] transferRegions An array of transfer regions (can be null to specify the whole area). +/// \param [in] subresourceArray An array of subresource indices (can be null to specify all subresources). +/// \param [in] numSubresources The number of subresources in subresourceArray OR number of transferRegions. Use 0 to specify ALL subresources and one transferRegion (which may be null if specifying the whole area). +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceEndWrites( AGSContext* context, ID3D11Resource* resource, const D3D11_RECT* transferRegions, const unsigned int* subresourceArray, unsigned int numSubresources ); + +/// +/// This will notify the driver that the app will begin read/write access to the resource. +/// +/// \param [in] context Pointer to a context. +/// \param [in] resource Pointer to the resource. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceBeginAllAccess( AGSContext* context, ID3D11Resource* resource ); + +/// +/// This is used for AGS_AFR_TRANSFER_1STEP_P2P to notify when it is safe to initiate a transfer. +/// This call in frame N-(NumGpus-1) allows a 1 step P2P in frame N to start. +/// This should be called after agsDriverExtensionsDX11_NotifyResourceEndWrites. +/// +/// \param [in] context Pointer to a context. +/// \param [in] resource Pointer to the resource. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceEndAllAccess( AGSContext* context, ID3D11Resource* resource ); + +/// @} + +/// @} + +/// \defgroup typedefs Function pointer typedefs +/// List of function pointer typedefs for the API +/// @{ + +typedef AMD_AGS_API AGSDriverVersionResult (*AGS_CHECKDRIVERVERSION)( const char*, unsigned int ); ///< \ref agsCheckDriverVersion +typedef AMD_AGS_API int (*AGS_GETVERSIONNUMBER)( void ); ///< \ref agsGetVersionNumber +typedef AMD_AGS_API AGSReturnCode (*AGS_INITIALIZE)( int, const AGSConfiguration*, AGSContext**, AGSGPUInfo_600* ); ///< \ref agsInitialize +typedef AMD_AGS_API AGSReturnCode (*AGS_DEINITIALIZE)( AGSContext* ); ///< \ref agsDeInitialize +typedef AMD_AGS_API AGSReturnCode (*AGS_SETDISPLAYMODE)( AGSContext*, int, int, const AGSDisplaySettings* ); ///< \ref agsSetDisplayMode +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_CREATEDEVICE)( AGSContext*, const AGSDX12DeviceCreationParams*, const AGSDX12ExtensionParams*, AGSDX12ReturnedParams* ); ///< \ref agsDriverExtensionsDX12_CreateDevice +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_DESTROYDEVICE)( AGSContext*, ID3D12Device*, unsigned int* ); ///< \ref agsDriverExtensionsDX12_DestroyDevice +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_PUSHMARKER)( AGSContext*, ID3D12GraphicsCommandList*, const char* ); ///< \ref agsDriverExtensionsDX12_PushMarker +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_POPMARKER)( AGSContext*, ID3D12GraphicsCommandList* ); ///< \ref agsDriverExtensionsDX12_PopMarker +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_SETMARKER)( AGSContext*, ID3D12GraphicsCommandList*, const char* ); ///< \ref agsDriverExtensionsDX12_SetMarker +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATEDEVICE)( AGSContext*, const AGSDX11DeviceCreationParams*, const AGSDX11ExtensionParams*, AGSDX11ReturnedParams* ); ///< \ref agsDriverExtensionsDX11_CreateDevice +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_DESTROYDEVICE)( AGSContext*, ID3D11Device*, unsigned int*, ID3D11DeviceContext*, unsigned int* ); ///< \ref agsDriverExtensionsDX11_DestroyDevice +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_WRITEBREADCRUMB)( AGSContext*, const AGSBreadcrumbMarker* ); ///< \ref agsDriverExtensionsDX11_WriteBreadcrumb +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_IASETPRIMITIVETOPOLOGY)( AGSContext*, enum D3D_PRIMITIVE_TOPOLOGY ); ///< \ref agsDriverExtensionsDX11_IASetPrimitiveTopology +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_BEGINUAVOVERLAP)( AGSContext*, ID3D11DeviceContext* ); ///< \ref agsDriverExtensionsDX11_BeginUAVOverlap +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_ENDUAVOVERLAP)( AGSContext*, ID3D11DeviceContext* ); ///< \ref agsDriverExtensionsDX11_EndUAVOverlap +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETDEPTHBOUNDS)( AGSContext*, ID3D11DeviceContext*, bool, float, float ); ///< \ref agsDriverExtensionsDX11_SetDepthBounds +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINSTANCEDINDIRECT)( AGSContext*, ID3D11DeviceContext*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawInstancedIndirect +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINDEXEDINSTANCEDINDIRECT)( AGSContext*, ID3D11DeviceContext*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINSTANCEDINDIRECTCOUNTINDIRECT)( AGSContext*, ID3D11DeviceContext*, ID3D11Buffer*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINDEXEDINSTANCEDINDIRECTCOUNTINDIRECT)( AGSContext*, ID3D11DeviceContext*, ID3D11Buffer*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETMAXASYNCCOMPILETHREADCOUNT)( AGSContext*, unsigned int ); ///< \ref agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NUMPENDINGASYNCOMPILEJOBS)( AGSContext*, unsigned int* ); ///< \ref agsDriverExtensionsDX11_NumPendingAsyncCompileJobs +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETDISKSHADERCACHEENABLED)( AGSContext*, int ); ///< \ref agsDriverExtensionsDX11_SetDiskShaderCacheEnabled +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETVIEWBROADCASTMASKS)( AGSContext*, unsigned long long, unsigned long long, int ); ///< \ref agsDriverExtensionsDX11_SetViewBroadcastMasks +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_GETMAXCLIPRECTS)( AGSContext*, unsigned int* ); ///< \ref agsDriverExtensionsDX11_GetMaxClipRects +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETCLIPRECTS)( AGSContext*, unsigned int, const AGSClipRect* ); ///< \ref agsDriverExtensionsDX11_SetClipRects +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATEBUFFER)( AGSContext*, const D3D11_BUFFER_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Buffer**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateBuffer +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATETEXTURE1D)( AGSContext*, const D3D11_TEXTURE1D_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Texture1D**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateTexture1D +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATETEXTURE2D)( AGSContext*, const D3D11_TEXTURE2D_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Texture2D**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateTexture2D +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATETEXTURE3D)( AGSContext*, const D3D11_TEXTURE3D_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Texture3D**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateTexture3D +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NOTIFYRESOURCEENDWRITES)( AGSContext*, ID3D11Resource*, const D3D11_RECT*, const unsigned int*, unsigned int ); ///< \ref agsDriverExtensionsDX11_NotifyResourceEndWrites +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NOTIFYRESOURCEBEGINALLACCESS)( AGSContext*, ID3D11Resource* ); ///< \ref agsDriverExtensionsDX11_NotifyResourceBeginAllAccess +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NOTIFYRESOURCEENDALLACCESS)( AGSContext*, ID3D11Resource* ); ///< \ref agsDriverExtensionsDX11_NotifyResourceEndAllAccess +/// @} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AMD_AGS_H diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec new file mode 100644 index 000000000000..32b47f2f5537 --- /dev/null +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -0,0 +1,66 @@ +@ stdcall agsDeInit(ptr) +@ stdcall agsDeInitialize(ptr) +@ stdcall agsCheckDriverVersion(ptr long) +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensions_BeginUAVOverlap() DX11_BeginUAVOverlap_impl +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensionsDX11_BeginUAVOverlap() DX11_BeginUAVOverlap_impl +@ stub agsDriverExtensions_IASetPrimitiveTopology +@ stub agsDriverExtensionsDX11_CreateBuffer +@ stub agsDriverExtensions_CreateBuffer +@ stdcall agsDriverExtensionsDX11_CreateDevice(ptr ptr ptr ptr) +@ stub agsDriverExtensionsDX11_CreateFromDevice +@ stub agsDriverExtensionsDX11_CreateTexture1D +@ stub agsDriverExtensionsDX11_CreateTexture2D +@ stub agsDriverExtensionsDX11_CreateTexture3D +@ stub agsDriverExtensions_CreateTexture1D +@ stub agsDriverExtensions_CreateTexture2D +@ stub agsDriverExtensions_CreateTexture3D +@ stdcall agsDriverExtensions_DeInit(ptr) +@ stdcall agsDriverExtensionsDX11_DeInit(ptr) +@ stub agsDriverExtensionsDX11_Destroy +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensionsDX11_DestroyDevice() +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensions_EndUAVOverlap() DX11_EndUAVOverlap_impl +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensionsDX11_EndUAVOverlap() DX11_EndUAVOverlap_impl +@ stub agsDriverExtensionsDX11_GetMaxClipRects +@ stub agsDriverExtensionsDX11_IASetPrimitiveTopology +@ stdcall agsDriverExtensions_Init(ptr ptr ptr) +@ stdcall agsDriverExtensionsDX11_Init(ptr ptr long ptr) +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensions_MultiDrawIndexedInstancedIndirect() DX11_MultiDrawIndexedInstancedIndirect_impl +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect() DX11_MultiDrawIndexedInstancedIndirect_impl +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect() DX11_MultiDrawIndexedInstancedIndirectCountIndirect_impl +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensions_MultiDrawInstancedIndirect() DX11_MultiDrawInstancedIndirect_impl +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensionsDX11_MultiDrawInstancedIndirect() DX11_MultiDrawInstancedIndirect_impl +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect() DX11_MultiDrawInstancedIndirectCountIndirect_impl +@ stub agsDriverExtensionsDX11_NotifyResourceBeginAllAccess +@ stub agsDriverExtensionsDX11_NotifyResourceEndAllAccess +@ stub agsDriverExtensionsDX11_NotifyResourceEndWrites +@ stub agsDriverExtensions_NotifyResourceBeginAllAccess +@ stub agsDriverExtensions_NotifyResourceEndAllAccess +@ stub agsDriverExtensions_NotifyResourceEndWrites +@ stub agsDriverExtensionsDX11_NumPendingAsyncCompileJobs +@ stub agsDriverExtensionsDX11_SetClipRects +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensions_SetDepthBounds() DX11_SetDepthBounds_impl +@ stdcall -norelay -arch=x86_64,arm64ec agsDriverExtensionsDX11_SetDepthBounds() DX11_SetDepthBounds_impl +@ stdcall agsDriverExtensionsDX11_SetDiskShaderCacheEnabled(ptr long) +@ stdcall agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount(ptr long) +@ stub agsDriverExtensionsDX11_SetViewBroadcastMasks +@ stub agsDriverExtensionsDX11_WriteBreadcrumb +@ stdcall agsDriverExtensionsDX12_CreateDevice(ptr ptr ptr ptr) +@ stub agsDriverExtensionsDX12_CreateFromDevice +@ stdcall agsDriverExtensionsDX12_DeInit(ptr) +@ stub agsDriverExtensionsDX12_Destroy +@ stdcall agsDriverExtensionsDX12_DestroyDevice(ptr ptr ptr) +@ stdcall agsDriverExtensionsDX12_Init(ptr ptr ptr) +@ stdcall agsDriverExtensionsDX12_PopMarker(ptr ptr) +@ stdcall agsDriverExtensionsDX12_PushMarker(ptr ptr ptr) +@ stdcall agsDriverExtensionsDX12_SetMarker(ptr ptr ptr) +@ stdcall agsGetCrossfireGPUCount(ptr ptr) +@ stdcall agsGetDriverVersionInfo(ptr ptr) +@ stdcall agsGetVersionNumber() +@ stdcall agsInit(ptr ptr ptr) +@ stdcall agsInitialize(long ptr ptr ptr) +@ stdcall agsSetDisplayMode(ptr long long ptr) +@ stdcall agsGetTotalGPUCount(ptr ptr) +@ stdcall agsGetGPUMemorySize(ptr long ptr) +@ stdcall agsGetEyefinityConfigInfo(ptr long ptr ptr ptr) +@ stdcall agsDriverExtensions_SetCrossfireMode(ptr long) +@ stdcall agsGetGPUInfo(ptr ptr) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c new file mode 100644 index 000000000000..3ba410cb9333 --- /dev/null +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -0,0 +1,2006 @@ +#if 0 +#pragma makedep arm64ec_x64 +#endif + +#include +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "wine/debug.h" +#include "wine/heap.h" + +#include "wine/vulkan.h" +#include "wine/asm.h" + +#define COBJMACROS +#include "initguid.h" +#include "d3d11.h" +#include "d3d12.h" + +#include "dxgi1_6.h" + +#include "dxvk_interfaces.h" + +#include "amd_ags.h" + +#include "unixlib.h" + +WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); + +#define AMD_AGS_CALL(func, args) WINE_UNIX_CALL( unix_ ## func, args ) + +static INIT_ONCE unix_init_once = INIT_ONCE_STATIC_INIT; +static BOOL unix_lib_initialized; + +static BOOL WINAPI init_unix_lib_once( INIT_ONCE *once, void *param, void **context ) +{ + unix_lib_initialized = !__wine_init_unix_call() && !AMD_AGS_CALL( init, NULL ); + return TRUE; +} + +static BOOL init_unix_lib(void) +{ + InitOnceExecuteOnce( &unix_init_once, init_unix_lib_once, NULL, NULL ); + return unix_lib_initialized; +} + +static const char driver_version[] = "99.19.02-230831a-396538C-AMD-Software-Adrenalin-Edition"; +static const char radeon_version[] = "99.10.2"; + +enum amd_ags_version +{ + AMD_AGS_VERSION_4_0_3, + AMD_AGS_VERSION_5_0_5, + AMD_AGS_VERSION_5_1_1, + AMD_AGS_VERSION_5_2_0, + AMD_AGS_VERSION_5_3_0, + AMD_AGS_VERSION_5_4_0, + AMD_AGS_VERSION_5_4_1, + AMD_AGS_VERSION_5_4_2, + AMD_AGS_VERSION_6_0_0, + AMD_AGS_VERSION_6_1_0, + AMD_AGS_VERSION_6_3_0, + + AMD_AGS_VERSION_COUNT +}; + +static const struct +{ + unsigned int ags_min_public_version; + unsigned int ags_max_public_version; + unsigned int device_size; + unsigned int dx11_returned_params_size; + int max_asicFamily; +} +amd_ags_info[AMD_AGS_VERSION_COUNT] = +{ + {AGS_MAKE_VERSION(3, 0, 0), AGS_MAKE_VERSION(4, 0, 3), sizeof(AGSDeviceInfo_511), sizeof(AGSDX11ReturnedParams_511), 0}, + {AGS_MAKE_VERSION(5, 0, 0), AGS_MAKE_VERSION(5, 0, 6), sizeof(AGSDeviceInfo_511), sizeof(AGSDX11ReturnedParams_511), 0}, + {AGS_MAKE_VERSION(5, 1, 1), AGS_MAKE_VERSION(5, 1, 1), sizeof(AGSDeviceInfo_511), sizeof(AGSDX11ReturnedParams_511), 0}, + {AGS_MAKE_VERSION(5, 2, 0), AGS_MAKE_VERSION(5, 2, 1), sizeof(AGSDeviceInfo_520), sizeof(AGSDX11ReturnedParams_520), 0}, + {AGS_MAKE_VERSION(5, 3, 0), AGS_MAKE_VERSION(5, 3, 0), sizeof(AGSDeviceInfo_520), sizeof(AGSDX11ReturnedParams_520), 0}, + {AGS_MAKE_VERSION(5, 4, 0), AGS_MAKE_VERSION(5, 4, 0), sizeof(AGSDeviceInfo_540), sizeof(AGSDX11ReturnedParams_520), AsicFamily_RDNA}, + {AGS_MAKE_VERSION(5, 4, 1), AGS_MAKE_VERSION(5, 4, 1), sizeof(AGSDeviceInfo_541), sizeof(AGSDX11ReturnedParams_520), AsicFamily_RDNA}, + {AGS_MAKE_VERSION(5, 4, 2), AGS_MAKE_VERSION(5, 4, 2), sizeof(AGSDeviceInfo_542), sizeof(AGSDX11ReturnedParams_520), AsicFamily_RDNA}, + {AGS_MAKE_VERSION(6, 0, 0), AGS_MAKE_VERSION(6, 0, 1), sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600), AsicFamily_RDNA2}, + {AGS_MAKE_VERSION(6, 1, 0), AGS_MAKE_VERSION(6, 2, 0), sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600), AsicFamily_RDNA3}, + {AGS_MAKE_VERSION(6, 3, 0), AGS_MAKE_VERSION(6, 3, 0), sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600), AsicFamily_RDNA4}, +}; + +#define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_511, name), \ + offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ + offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), \ + offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} +#define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_511, name), \ + offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ + offsetof(AGSDeviceInfo_520, name), -1, \ + -1, -1, -1, -1, -1}} +#define DEF_FIELD_520_UP(name) {DEVICE_FIELD_##name, {-1, -1, -1, offsetof(AGSDeviceInfo_520, name), \ + offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), \ + offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} +#define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, -1, -1, \ + -1, offsetof(AGSDeviceInfo_540, name), \ + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), \ + offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} +#define DEF_FIELD_540_600(name) {DEVICE_FIELD_##name, {-1, -1, -1, -1, \ + -1, offsetof(AGSDeviceInfo_540, name), \ + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), \ + -1, -1, -1}} +#define DEF_FIELD_600_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_511, name), \ + offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ + offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), \ + -1, -1, -1}} + +#define DEVICE_FIELD_adapterString 0 +#define DEVICE_FIELD_architectureVersion 1 +#define DEVICE_FIELD_asicFamily 2 +#define DEVICE_FIELD_vendorId 3 +#define DEVICE_FIELD_deviceId 4 +#define DEVICE_FIELD_isPrimaryDevice 5 +#define DEVICE_FIELD_localMemoryInBytes 6 +#define DEVICE_FIELD_numDisplays 7 +#define DEVICE_FIELD_displays 8 +#define DEVICE_FIELD_isAPU 9 + +#define DEVICE_FIELD_numCUs 10 +#define DEVICE_FIELD_coreClock 11 +#define DEVICE_FIELD_memoryClock 12 +#define DEVICE_FIELD_teraFlops 13 +#define DEVICE_FIELD_numWGPs 14 +#define DEVICE_FIELD_numROPs 15 +#define DEVICE_FIELD_memoryBandwidth 16 + +static const struct +{ + unsigned int field_index; + int offset[AMD_AGS_VERSION_COUNT]; +} +device_struct_fields[] = +{ + DEF_FIELD(adapterString), + DEF_FIELD_520_BELOW(architectureVersion), + DEF_FIELD_540_UP(asicFamily), + DEF_FIELD(vendorId), + DEF_FIELD(deviceId), + DEF_FIELD_600_BELOW(isPrimaryDevice), + DEF_FIELD(localMemoryInBytes), + DEF_FIELD(numDisplays), + DEF_FIELD(displays), + DEF_FIELD_540_600(isAPU), + DEF_FIELD(numCUs), + DEF_FIELD(coreClock), + DEF_FIELD(memoryClock), + DEF_FIELD(teraFlops), + DEF_FIELD_540_UP(numWGPs), + DEF_FIELD_520_UP(numROPs), + DEF_FIELD_520_UP(memoryBandwidth), +}; + +#undef DEF_FIELD + +#define GET_DEVICE_FIELD_ADDR(device, name, type, version) \ + (device_struct_fields[DEVICE_FIELD_##name].offset[version] == -1 ? NULL \ + : (type *)((BYTE *)device + device_struct_fields[DEVICE_FIELD_##name].offset[version])) + +#define SET_DEVICE_FIELD(device, name, type, version, value) { \ + type *addr; \ + if ((addr = GET_DEVICE_FIELD_ADDR(device, name, type, version))) \ + *addr = value; \ + } + +struct AGSContext +{ + enum amd_ags_version version; + unsigned int device_count; + struct AGSDeviceInfo *devices; + VkPhysicalDeviceProperties *properties; + VkPhysicalDeviceMemoryProperties *memory_properties; + ID3D11DeviceContext *d3d11_context; + AGSDX11ExtensionsSupported_600 extensions; + unsigned int public_version; +}; + +static HMODULE hd3d11, hd3d12; +static typeof(D3D12CreateDevice) *pD3D12CreateDevice; +static typeof(D3D11CreateDevice) *pD3D11CreateDevice; +static typeof(D3D11CreateDeviceAndSwapChain) *pD3D11CreateDeviceAndSwapChain; + +#define AGS_VER_MAJOR(ver) ((ver) >> 22) +#define AGS_VER_MINOR(ver) (((ver) >> 12) & ((1 << 10) - 1)) +#define AGS_VER_PATCH(ver) ((ver) & ((1 << 12) - 1)) + +static const char *debugstr_agsversion(unsigned int ags_version) +{ + return wine_dbg_sprintf("%d.%d.%d", AGS_VER_MAJOR(ags_version), AGS_VER_MINOR(ags_version), AGS_VER_PATCH(ags_version)); +} + +static BOOL load_d3d12_functions(void) +{ + if (hd3d12) + return TRUE; + + if (!(hd3d12 = LoadLibraryA("d3d12.dll"))) + return FALSE; + + pD3D12CreateDevice = (void *)GetProcAddress(hd3d12, "D3D12CreateDevice"); + return TRUE; +} + +static BOOL load_d3d11_functions(void) +{ + if (hd3d11) + return TRUE; + + if (!(hd3d11 = LoadLibraryA("d3d11.dll"))) + return FALSE; + + pD3D11CreateDevice = (void *)GetProcAddress(hd3d11, "D3D11CreateDevice"); + pD3D11CreateDeviceAndSwapChain = (void *)GetProcAddress(hd3d11, "D3D11CreateDeviceAndSwapChain"); + return TRUE; +} + +static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, + VkPhysicalDeviceProperties **out, VkPhysicalDeviceMemoryProperties **out_memory) +{ + VkPhysicalDeviceProperties *properties = NULL; + VkPhysicalDeviceMemoryProperties *memory_properties = NULL; + VkPhysicalDevice *vk_physical_devices = NULL; + VkInstance vk_instance = VK_NULL_HANDLE; + VkInstanceCreateInfo create_info; + AGSReturnCode ret = AGS_SUCCESS; + uint32_t count, i; + VkResult vr; + + *out = NULL; + *out_count = 0; + + memset(&create_info, 0, sizeof(create_info)); + create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + if ((vr = vkCreateInstance(&create_info, NULL, &vk_instance) < 0)) + { + WARN("Failed to create Vulkan instance, vr %d.\n", vr); + goto done; + } + + if ((vr = vkEnumeratePhysicalDevices(vk_instance, &count, NULL)) < 0) + { + WARN("Failed to enumerate devices, vr %d.\n", vr); + goto done; + } + + if (!(vk_physical_devices = heap_calloc(count, sizeof(*vk_physical_devices)))) + { + WARN("Failed to allocate memory.\n"); + ret = AGS_OUT_OF_MEMORY; + goto done; + } + + if ((vr = vkEnumeratePhysicalDevices(vk_instance, &count, vk_physical_devices)) < 0) + { + WARN("Failed to enumerate devices, vr %d.\n", vr); + goto done; + } + + if (!(properties = heap_calloc(count, sizeof(*properties)))) + { + WARN("Failed to allocate memory.\n"); + ret = AGS_OUT_OF_MEMORY; + goto done; + } + + if (!(memory_properties = heap_calloc(count, sizeof(*memory_properties)))) + { + WARN("Failed to allocate memory.\n"); + heap_free(properties); + ret = AGS_OUT_OF_MEMORY; + goto done; + } + + for (i = 0; i < count; ++i) + { + vkGetPhysicalDeviceProperties(vk_physical_devices[i], &properties[i]); + if (properties[i].deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU + && properties[i].deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + { + TRACE("Skipping device type %d.\n", properties[i].deviceType); + --i; + --count; + continue; + } + vkGetPhysicalDeviceMemoryProperties(vk_physical_devices[i], &memory_properties[i]); + } + + *out_count = count; + *out = properties; + *out_memory = memory_properties; + +done: + heap_free(vk_physical_devices); + if (vk_instance) + vkDestroyInstance(vk_instance, NULL); + return ret; +} + +static enum amd_ags_version get_version_number(int ags_version) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(amd_ags_info); i++) + if (ags_version >= amd_ags_info[i].ags_min_public_version && ags_version <= amd_ags_info[i].ags_max_public_version) + { + TRACE("Found AGS v%s (internal %d).\n", debugstr_agsversion(ags_version), i); + return i; + } + ERR("Unknown ags_version %s, using 5.4.1.\n", debugstr_agsversion(ags_version)); + return AMD_AGS_VERSION_5_4_1; +} + +static BOOL get_ags_version_from_resource(const WCHAR *filename, enum amd_ags_version *ret, int *public_version) +{ + DWORD infosize; + void *infobuf; + void *val; + UINT vallen; + VS_FIXEDFILEINFO *info; + UINT16 major, minor, patch; + + infosize = GetFileVersionInfoSizeW(filename, NULL); + if (!infosize) + { + ERR("File version info not found, err %u.\n", GetLastError()); + return FALSE; + } + + if (!(infobuf = heap_alloc(infosize))) + { + ERR("Failed to allocate memory.\n"); + return FALSE; + } + + if (!GetFileVersionInfoW(filename, 0, infosize, infobuf)) + { + ERR("GetFileVersionInfoW failed, err %u.\n", GetLastError()); + heap_free(infobuf); + return FALSE; + } + + if (!VerQueryValueW(infobuf, L"\\", &val, &vallen) || (vallen != sizeof(VS_FIXEDFILEINFO))) + { + ERR("Version value not found, err %u.\n", GetLastError()); + heap_free(infobuf); + return FALSE; + } + + info = val; + major = info->dwFileVersionMS >> 16; + minor = info->dwFileVersionMS; + patch = info->dwFileVersionLS >> 16; + *public_version = AGS_MAKE_VERSION(major, minor, patch); + TRACE("Found amd_ags_x64.dll v%d.%d.%d\n", major, minor, patch); + *ret = get_version_number(*public_version); + heap_free(infobuf); + return TRUE; +} + +static enum amd_ags_version guess_version_from_exports(HMODULE hnative, int *ags_version) +{ + /* Known DLL versions without version info: + * - An update to AGS 5.4.1 included an amd_ags_x64.dll with no file version info; + * - CoD: Modern Warfare Remastered (2017) ships dll without version info which is version 5.0.1 + * (not tagged in AGSSDK history), compatible with 5.0.5. + */ + if (GetProcAddress(hnative, "agsGetDriverVersionInfo")) + { + /* agsGetDriverVersionInfo existed somewhere before 3.1.1, there is no SDK history in github before 3.1.1. */ + TRACE("agsGetDriverVersionInfo found.\n"); + *ags_version = AGS_MAKE_VERSION(3, 0, 0); + return AMD_AGS_VERSION_4_0_3; + } + + if (GetProcAddress(hnative, "agsDriverExtensions_SetCrossfireMode")) + { + /* agsDriverExtensions_SetCrossfireMode was deprecated in 3.2.0 */ + TRACE("agsDriverExtensions_SetCrossfireMode found.\n"); + *ags_version = AGS_MAKE_VERSION(3, 1, 1); + return AMD_AGS_VERSION_4_0_3; + } + if (GetProcAddress(hnative, "agsDriverExtensions_Init")) + { + /* agsGetEyefinityConfigInfo was deprecated in 4.0.0 */ + TRACE("agsDriverExtensions_Init found.\n"); + *ags_version = AGS_MAKE_VERSION(3, 2, 2); + return AMD_AGS_VERSION_4_0_3; + } + if (GetProcAddress(hnative, "agsGetEyefinityConfigInfo")) + { + /* agsGetEyefinityConfigInfo was deprecated in 5.0.0 */ + TRACE("agsGetEyefinityConfigInfo found.\n"); + return AMD_AGS_VERSION_4_0_3; + } + if (GetProcAddress(hnative, "agsDriverExtensionsDX11_Init")) + { + /* agsDriverExtensionsDX11_Init was deprecated in 5.3.0 */ + TRACE("agsDriverExtensionsDX11_Init found.\n"); + return AMD_AGS_VERSION_5_0_5; + } + TRACE("Returning 5.4.1.\n"); + return AMD_AGS_VERSION_5_4_1; +} + +static enum amd_ags_version determine_ags_version(int *ags_version) +{ + /* AMD AGS is not binary compatible between versions (even minor versions), and the game + * does not request a specific version when calling agsInit(). + * Checking the version of amd_ags_x64.dll shipped with the game is the only way to + * determine what version the game was built against. + */ + enum amd_ags_version ret = AMD_AGS_VERSION_5_4_1; + WCHAR dllname[MAX_PATH], temp_path[MAX_PATH], temp_name[MAX_PATH]; + int (WINAPI *pagsGetVersionNumber)(void); + HMODULE hnative = NULL; + DWORD size; + + TRACE("*ags_version %#x.\n", *ags_version); + + if (*ags_version) + return get_version_number(*ags_version); + + *temp_name = 0; + if (!(size = GetModuleFileNameW(GetModuleHandleW(L"amd_ags_x64.dll"), dllname, ARRAY_SIZE(dllname))) + || size == ARRAY_SIZE(dllname)) + { + ERR("GetModuleFileNameW failed.\n"); + goto done; + } + if (!GetTempPathW(MAX_PATH, temp_path) || !GetTempFileNameW(temp_path, L"tmp", 0, temp_name)) + { + ERR("Failed getting temp file name.\n"); + goto done; + } + if (!CopyFileW(dllname, temp_name, FALSE)) + { + ERR("Failed to copy file.\n"); + goto done; + } + + if (get_ags_version_from_resource(temp_name, &ret, ags_version)) + goto done; + + if (!(hnative = LoadLibraryW(temp_name))) + { + ERR("LoadLibraryW failed for %s.\n", debugstr_w(temp_name)); + goto done; + } + + if ((pagsGetVersionNumber = (void *)GetProcAddress(hnative, "agsGetVersionNumber"))) + { + *ags_version = pagsGetVersionNumber(); + ret = get_version_number(*ags_version); + TRACE("Got version %s (%d) from agsGetVersionNumber.\n", debugstr_agsversion(*ags_version), ret); + goto done; + } + + ret = guess_version_from_exports(hnative, ags_version); + +done: + if (!*ags_version) + *ags_version = amd_ags_info[ret].ags_max_public_version; + + if (hnative) + FreeLibrary(hnative); + + if (*temp_name) + DeleteFileW(temp_name); + + TRACE("Using AGS v%s (internal %d) interface\n", debugstr_agsversion(*ags_version), ret); + return ret; +} + +struct monitor_enum_context_600 +{ + const char *adapter_name; + AGSDisplayInfo_600 **ret_displays; + int *ret_display_count; + IDXGIFactory1 *dxgi_factory; +}; + +static void create_dxgi_factory(HMODULE *hdxgi, IDXGIFactory1 **factory) +{ + typeof(CreateDXGIFactory1) *pCreateDXGIFactory1; + + *factory = NULL; + + if (!(*hdxgi = LoadLibraryW(L"dxgi.dll"))) + { + ERR("Could not load dxgi.dll.\n"); + return; + } + + if (!(pCreateDXGIFactory1 = (void *)GetProcAddress(*hdxgi, "CreateDXGIFactory1"))) + { + ERR("Could not find CreateDXGIFactory1.\n"); + return; + } + + if (FAILED(pCreateDXGIFactory1(&IID_IDXGIFactory1, (void**)factory))) + return; +} + +static void release_dxgi_factory(HMODULE hdxgi, IDXGIFactory1 *factory) +{ + if (factory) + IDXGIFactory1_Release(factory); + if (hdxgi) + FreeLibrary(hdxgi); +} + +static void fill_chroma_info(AGSDisplayInfo_600 *info, struct monitor_enum_context_600 *c, HMONITOR monitor) +{ + DXGI_OUTPUT_DESC1 output_desc; + IDXGIAdapter1 *adapter; + IDXGIOutput6 *output6; + IDXGIOutput *output; + BOOL found = FALSE; + unsigned int i, j; + HRESULT hr; + + i = 0; + while (!found && (SUCCEEDED(IDXGIFactory1_EnumAdapters1(c->dxgi_factory, i++, &adapter)))) + { + j = 0; + while (SUCCEEDED(IDXGIAdapter1_EnumOutputs(adapter, j++, &output))) + { + hr = IDXGIOutput_QueryInterface(output, &IID_IDXGIOutput6, (void**)&output6); + IDXGIOutput_Release(output); + if (FAILED(hr)) + { + WARN("Failed to query IDXGIOutput6.\n"); + continue; + } + hr = IDXGIOutput6_GetDesc1(output6, &output_desc); + IDXGIOutput6_Release(output6); + + if (FAILED(hr) || output_desc.Monitor != monitor) + continue; + found = TRUE; + + TRACE("output_desc.ColorSpace %#x.\n", output_desc.ColorSpace); + if (output_desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) + { + TRACE("Reporting monitor %s as HDR10 supported.\n", debugstr_a(info->displayDeviceName)); + info->HDR10 = 1; + } + + info->chromaticityRedX = output_desc.RedPrimary[0]; + info->chromaticityRedY = output_desc.RedPrimary[1]; + info->chromaticityGreenX = output_desc.GreenPrimary[0]; + info->chromaticityGreenY = output_desc.GreenPrimary[1]; + info->chromaticityBlueX = output_desc.BluePrimary[0]; + info->chromaticityBlueY = output_desc.BluePrimary[1]; + info->chromaticityWhitePointX = output_desc.WhitePoint[0]; + info->chromaticityWhitePointY = output_desc.WhitePoint[1]; + + TRACE("chromacity: (%.6lf, %.6lf) (%.6lf, %.6lf) (%.6lf, %.6lf).\n", info->chromaticityRedX, + info->chromaticityRedY, info->chromaticityGreenX, info->chromaticityGreenY, info->chromaticityBlueX, + info->chromaticityBlueY); + + info->screenDiffuseReflectance = 0; + info->screenSpecularReflectance = 0; + + info->minLuminance = output_desc.MinLuminance; + info->maxLuminance = output_desc.MaxLuminance; + info->avgLuminance = output_desc.MaxFullFrameLuminance; + } + IDXGIAdapter1_Release(adapter); + } + + if (!found) + WARN("dxgi output not found.\n"); +} + +static BOOL WINAPI monitor_enum_proc_600(HMONITOR hmonitor, HDC hdc, RECT *rect, LPARAM context) +{ + struct monitor_enum_context_600 *c = (struct monitor_enum_context_600 *)context; + MONITORINFOEXA monitor_info; + AGSDisplayInfo_600 *new_alloc; + DISPLAY_DEVICEA device; + AGSDisplayInfo_600 *info; + unsigned int i, mode; + DEVMODEA dev_mode; + + + monitor_info.cbSize = sizeof(monitor_info); + GetMonitorInfoA(hmonitor, (MONITORINFO *)&monitor_info); + TRACE("monitor_info.szDevice %s.\n", debugstr_a(monitor_info.szDevice)); + + device.cb = sizeof(device); + i = 0; + while (EnumDisplayDevicesA(NULL, i, &device, 0)) + { + TRACE("device.DeviceName %s, device.DeviceString %s.\n", debugstr_a(device.DeviceName), debugstr_a(device.DeviceString)); + ++i; + if (strcmp(device.DeviceString, c->adapter_name) || strcmp(device.DeviceName, monitor_info.szDevice)) + continue; + + if (*c->ret_display_count) + { + if (!(new_alloc = heap_realloc(*c->ret_displays, sizeof(*new_alloc) * (*c->ret_display_count + 1)))) + { + ERR("No memory."); + return FALSE; + } + *c->ret_displays = new_alloc; + } + else if (!(*c->ret_displays = heap_alloc(sizeof(**c->ret_displays)))) + { + ERR("No memory."); + return FALSE; + } + info = &(*c->ret_displays)[*c->ret_display_count]; + memset(info, 0, sizeof(*info)); + strcpy(info->displayDeviceName, device.DeviceName); + if (EnumDisplayDevicesA(info->displayDeviceName, 0, &device, 0)) + { + strcpy(info->name, device.DeviceString); + } + else + { + ERR("Could not get monitor name for device %s.\n", debugstr_a(info->displayDeviceName)); + strcpy(info->name, "Unknown"); + } + if (monitor_info.dwFlags & MONITORINFOF_PRIMARY) + info->isPrimaryDisplay = 1; + + mode = 0; + memset(&dev_mode, 0, sizeof(dev_mode)); + dev_mode.dmSize = sizeof(dev_mode); + while (EnumDisplaySettingsExA(monitor_info.szDevice, mode, &dev_mode, EDS_RAWMODE)) + { + ++mode; + if (dev_mode.dmPelsWidth > info->maxResolutionX) + info->maxResolutionX = dev_mode.dmPelsWidth; + if (dev_mode.dmPelsHeight > info->maxResolutionY) + info->maxResolutionY = dev_mode.dmPelsHeight; + if (dev_mode.dmDisplayFrequency > info->maxRefreshRate) + info->maxRefreshRate = dev_mode.dmDisplayFrequency; + memset(&dev_mode, 0, sizeof(dev_mode)); + dev_mode.dmSize = sizeof(dev_mode); + } + + info->eyefinityGridCoordX = -1; + info->eyefinityGridCoordY = -1; + + info->currentResolution.offsetX = monitor_info.rcMonitor.left; + info->currentResolution.offsetY = monitor_info.rcMonitor.top; + info->currentResolution.width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left; + info->currentResolution.height = monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top; + info->visibleResolution = info->currentResolution; + + memset(&dev_mode, 0, sizeof(dev_mode)); + dev_mode.dmSize = sizeof(dev_mode); + + if (EnumDisplaySettingsExA(monitor_info.szDevice, ENUM_CURRENT_SETTINGS, &dev_mode, EDS_RAWMODE)) + info->currentRefreshRate = dev_mode.dmDisplayFrequency; + else + ERR("Could not get current display settings.\n"); + + fill_chroma_info(info, c, hmonitor); + + ++*c->ret_display_count; + + TRACE("Added display %s for %s.\n", debugstr_a(monitor_info.szDevice), debugstr_a(c->adapter_name)); + } + + return TRUE; +} + +static void init_device_displays_600(const char *adapter_name, AGSDisplayInfo_600 **ret_displays, int *ret_display_count) +{ + struct monitor_enum_context_600 context; + HMODULE hdxgi; + + TRACE("adapter_name %s.\n", debugstr_a(adapter_name)); + + context.adapter_name = adapter_name; + context.ret_displays = ret_displays; + context.ret_display_count = ret_display_count; + create_dxgi_factory(&hdxgi, &context.dxgi_factory); + + EnumDisplayMonitors(NULL, NULL, monitor_enum_proc_600, (LPARAM)&context); + release_dxgi_factory(hdxgi, context.dxgi_factory); +} + +static void init_device_displays_511(const char *adapter_name, AGSDisplayInfo_511 **ret_displays, int *ret_display_count) +{ + AGSDisplayInfo_600 *displays = NULL; + int display_count = 0; + int i; + *ret_displays = NULL; + *ret_display_count = 0; + + init_device_displays_600(adapter_name, &displays, &display_count); + + if ((*ret_displays = heap_alloc(sizeof(**ret_displays) * display_count))) + { + for (i = 0; i < display_count; i++) + { + memcpy(&(*ret_displays)[i], &displays[i], sizeof(AGSDisplayInfo_511)); + } + *ret_display_count = display_count; + } + + heap_free(displays); +} + +static int hide_apu(void) +{ + static int cached = -1; + + if (cached == -1) + { + const char *s; + + cached = ((s = getenv("WINE_HIDE_APU"))) && *s != '0'; + if (cached) + FIXME("hack: hiding APU.\n"); + } + return cached; +} + +static AGSReturnCode init_ags_context(AGSContext *context, int ags_version) +{ + AGSReturnCode ret; + unsigned int i, j; + BYTE *device; + + memset(context, 0, sizeof(*context)); + + context->version = determine_ags_version(&ags_version); + context->public_version = ags_version; + + ret = vk_get_physical_device_properties(&context->device_count, &context->properties, &context->memory_properties); + if (ret != AGS_SUCCESS || !context->device_count) + return ret; + + assert(context->version < AMD_AGS_VERSION_COUNT); + + if (!(context->devices = heap_calloc(context->device_count, amd_ags_info[context->version].device_size))) + { + WARN("Failed to allocate memory.\n"); + heap_free(context->properties); + heap_free(context->memory_properties); + return AGS_OUT_OF_MEMORY; + } + + device = (BYTE *)context->devices; + for (i = 0; i < context->device_count; ++i) + { + const VkPhysicalDeviceProperties *vk_properties = &context->properties[i]; + const VkPhysicalDeviceMemoryProperties *vk_memory_properties = &context->memory_properties[i]; + struct AGSDeviceInfo_600 *device_600 = (struct AGSDeviceInfo_600 *)device; + VkDeviceSize local_memory_size = 0; + + for (j = 0; j < vk_memory_properties->memoryHeapCount; j++) + { + if (vk_memory_properties->memoryHeaps[j].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) + { + local_memory_size = vk_memory_properties->memoryHeaps[j].size; + break; + } + } + + TRACE("device %s, type %d, %04x:%04x, reporting local memory size 0x%s bytes\n", + debugstr_a(vk_properties->deviceName), vk_properties->deviceType, + vk_properties->vendorID, vk_properties->deviceID, wine_dbgstr_longlong(local_memory_size)); + + SET_DEVICE_FIELD(device, adapterString, const char *, context->version, vk_properties->deviceName); + SET_DEVICE_FIELD(device, vendorId, int, context->version, vk_properties->vendorID); + SET_DEVICE_FIELD(device, deviceId, int, context->version, vk_properties->deviceID); + if (vk_properties->vendorID == 0x1002) + { + struct get_device_info_params params = + { + .device_id = vk_properties->deviceID, + }; + + SET_DEVICE_FIELD(device, architectureVersion, ArchitectureVersion, context->version, ArchitectureVersion_GCN); + if (init_unix_lib() && !AMD_AGS_CALL(get_device_info, ¶ms)) + { + SET_DEVICE_FIELD(device, asicFamily, AsicFamily, context->version, + min(params.asic_family, amd_ags_info[context->version].max_asicFamily)); + SET_DEVICE_FIELD(device, numCUs, int, context->version, params.num_cu); + SET_DEVICE_FIELD(device, numWGPs, int, context->version, params.num_wgp); + SET_DEVICE_FIELD(device, numROPs, int, context->version, params.num_rops); + SET_DEVICE_FIELD(device, coreClock, int, context->version, params.core_clock); + SET_DEVICE_FIELD(device, memoryClock, int, context->version, params.memory_clock); + SET_DEVICE_FIELD(device, memoryBandwidth, int, context->version, params.memory_bandwidth); + SET_DEVICE_FIELD(device, teraFlops, float, context->version, params.teraflops); + } + else + { + SET_DEVICE_FIELD(device, asicFamily, AsicFamily, context->version, AsicFamily_GCN4); + } + if (vk_properties->deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU && !hide_apu()) + { + if (context->version >= AMD_AGS_VERSION_6_0_0) + device_600->isAPU = 1; + else + SET_DEVICE_FIELD(device, isAPU, int, context->version, 1); + } + } + SET_DEVICE_FIELD(device, localMemoryInBytes, ULONG64, context->version, local_memory_size); + if (!i) + { + if (context->version >= AMD_AGS_VERSION_6_0_0) + { + // This is a bitfield now... Nice... + device_600->isPrimaryDevice = 1; + } + else + { + SET_DEVICE_FIELD(device, isPrimaryDevice, int, context->version, 1); + } + } + + if (context->version >= AMD_AGS_VERSION_6_0_0) + { + init_device_displays_600(vk_properties->deviceName, + GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo_600 *, context->version), + GET_DEVICE_FIELD_ADDR(device, numDisplays, int, context->version)); + } + else + { + init_device_displays_511(vk_properties->deviceName, + GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo_511 *, context->version), + GET_DEVICE_FIELD_ADDR(device, numDisplays, int, context->version)); + } + + device += amd_ags_info[context->version].device_size; + } + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *config, AGSGPUInfo_511 *gpu_info) +{ + struct AGSContext *object; + AGSReturnCode ret; + + TRACE("context %p, config %p, gpu_info %p.\n", context, config, gpu_info); + + if (!context) + return AGS_INVALID_ARGS; + + if (config) + FIXME("Ignoring config %p.\n", config); + + if (!(object = heap_alloc(sizeof(*object)))) + return AGS_OUT_OF_MEMORY; + + if ((ret = init_ags_context(object, 0)) != AGS_SUCCESS) + { + heap_free(object); + return ret; + } + + if (object->public_version <= AGS_MAKE_VERSION(3, 0, 0)) + { + WARN("Detected pre-historic AGS version.\n"); + goto done; + } + else if (object->public_version <= AGS_MAKE_VERSION(3, 1, 1)) + { + /* Unfortunately it doesn't look sanely possible to distinguish 3.1.1 and 3.1.0 versions, while in + * 3.1.0 radeonSoftwareVersion was present, removed in 3.1.1 and brought back in 3.2.2. */ + struct AGSDeviceInfo_511 *devices = (struct AGSDeviceInfo_511 *)object->devices, *device; + /* config parameter was added in 3.2.0, so gpu_info is actually the second parameter. */ + struct AGSGPUInfo_311 *info = (struct AGSGPUInfo_311 *)config; + unsigned int i; + + if (!info) + goto done; + + TRACE("filling AGSGPUInfo_311.\n"); + if (!object->device_count) + { + ERR("No devices.\n"); + agsDeInit(object); + return AGS_FAILURE; + } + + for (i = 0; i < object->device_count; ++i) + if (devices[i].isPrimaryDevice) + break; + if (i == object->device_count) + { + WARN("No primary device, using first.\n"); + i = 0; + } + device = &devices[i]; + memset(info, 0, sizeof(*info)); + info->adapterString = device->adapterString; + info->deviceId = device->deviceId; + info->revisionId = device->revisionId; + info->driverVersion = driver_version; + info->iNumCUs = device->numCUs; + info->iCoreClock = device->coreClock; + info->iMemoryClock = device->memoryClock; + info->fTFlops = device->teraFlops; + } + else if (object->public_version <= AGS_MAKE_VERSION(3, 2, 2)) + { + /* Unfortunately it doesn't look sanely possible to distinguish 3.2.2 and 3.2.0 versions, while in + * 3.2.2 radeonSoftwareVersion was added in the middle of the structure. So fill the shorter one + * to avoid out of bound write. */ + struct AGSDeviceInfo_511 *devices = (struct AGSDeviceInfo_511 *)object->devices, *device; + struct AGSGPUInfo_320 *info = (struct AGSGPUInfo_320 *)gpu_info; + unsigned int i; + + if (!gpu_info) + goto done; + + TRACE("filling AGSGPUInfo_320.\n"); + if (!object->device_count) + { + ERR("No devices.\n"); + agsDeInit(object); + return AGS_FAILURE; + } + + for (i = 0; i < object->device_count; ++i) + if (devices[i].isPrimaryDevice) + break; + if (i == object->device_count) + { + WARN("No primary device, using first.\n"); + i = 0; + } + device = &devices[i]; + memset(info, 0, sizeof(*info)); + info->agsVersionMajor = AGS_VER_MAJOR(object->public_version); + info->agsVersionMinor = AGS_VER_MINOR(object->public_version); + info->agsVersionPatch = AGS_VER_PATCH(object->public_version); + info->architectureVersion = device->architectureVersion; + info->adapterString = device->adapterString; + info->deviceId = device->deviceId; + info->revisionId = device->revisionId; + info->driverVersion = driver_version; + info->iNumCUs = device->numCUs; + info->iCoreClock = device->coreClock; + info->iMemoryClock = device->memoryClock; + info->fTFlops = device->teraFlops; + } + else if (object->version <= AMD_AGS_VERSION_4_0_3) + { + struct AGSDeviceInfo_511 *devices = (struct AGSDeviceInfo_511 *)object->devices, *device; + struct AGSGPUInfo_403 *info = (struct AGSGPUInfo_403 *)gpu_info; + unsigned int i; + + if (!gpu_info) + goto done; + + if (!object->device_count) + { + ERR("No devices.\n"); + agsDeInit(object); + return AGS_FAILURE; + } + + for (i = 0; i < object->device_count; ++i) + if (devices[i].isPrimaryDevice) + break; + if (i == object->device_count) + { + WARN("No primary device, using first.\n"); + i = 0; + } + device = &devices[i]; + memset(info, 0, sizeof(*info)); + info->agsVersionMajor = AGS_VER_MAJOR(object->public_version); + info->agsVersionMinor = AGS_VER_MINOR(object->public_version); + info->agsVersionPatch = AGS_VER_PATCH(object->public_version); + info->architectureVersion = device->architectureVersion; + info->adapterString = device->adapterString; + info->deviceId = device->deviceId; + info->revisionId = device->revisionId; + info->driverVersion = driver_version; + info->radeonSoftwareVersion = radeon_version; + info->iNumCUs = device->numCUs; + info->iCoreClock = device->coreClock; + info->iMemoryClock = device->memoryClock; + info->fTFlops = device->teraFlops; + } + else + { + if (!gpu_info) + goto done; + + memset(gpu_info, 0, sizeof(*gpu_info)); + gpu_info->agsVersionMajor = AGS_VER_MAJOR(object->public_version); + gpu_info->agsVersionMinor = AGS_VER_MINOR(object->public_version); + gpu_info->agsVersionPatch = AGS_VER_PATCH(object->public_version); + gpu_info->driverVersion = driver_version; + gpu_info->radeonSoftwareVersion = radeon_version; + gpu_info->numDevices = object->device_count; + gpu_info->devices = object->devices; + } + +done: + TRACE("Created context %p.\n", object); + + *context = object; + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsInitialize(int ags_version, const AGSConfiguration *config, AGSContext **context, AGSGPUInfo_600 *gpu_info) +{ + struct AGSContext *object; + AGSReturnCode ret; + + TRACE("ags_verison %d, context %p, config %p, gpu_info %p.\n", ags_version, context, config, gpu_info); + + if (!context) + return AGS_INVALID_ARGS; + + if (config) + FIXME("Ignoring config %p.\n", config); + + if (!(object = heap_alloc(sizeof(*object)))) + return AGS_OUT_OF_MEMORY; + + if ((ret = init_ags_context(object, ags_version)) != AGS_SUCCESS) + { + heap_free(object); + return ret; + } + + if (gpu_info) + { + memset(gpu_info, 0, sizeof(*gpu_info)); + gpu_info->driverVersion = driver_version; + gpu_info->radeonSoftwareVersion = radeon_version; + gpu_info->numDevices = object->device_count; + gpu_info->devices = object->devices; + } + + TRACE("Created context %p.\n", object); + + *context = object; + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsGetGPUInfo(AGSContext* context, AGSGPUInfo_600 *gpu_info) +{ + TRACE("context %p, gpu_info %p.\n", context, gpu_info); + + if (!context || !gpu_info) + return AGS_INVALID_ARGS; + + memset(gpu_info, 0, sizeof(*gpu_info)); + gpu_info->driverVersion = driver_version; + gpu_info->radeonSoftwareVersion = radeon_version; + gpu_info->numDevices = context->device_count; + gpu_info->devices = context->devices; + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDeInit(AGSContext *context) +{ + return agsDeInitialize(context); +} + +AGSReturnCode WINAPI agsDeInitialize(AGSContext *context) +{ + unsigned int i; + BYTE *device; + + TRACE("context %p.\n", context); + + if (!context) + return AGS_SUCCESS; + + if (context->d3d11_context) + { + ID3D11DeviceContext_Release(context->d3d11_context); + context->d3d11_context = NULL; + } + heap_free(context->memory_properties); + heap_free(context->properties); + device = (BYTE *)context->devices; + for (i = 0; i < context->device_count; ++i) + { + heap_free(*GET_DEVICE_FIELD_ADDR(device, displays, void *, context->version)); + device += amd_ags_info[context->version].device_size; + } + heap_free(context->devices); + heap_free(context); + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsGetTotalGPUCount(AGSContext *context, int *numGPUs) +{ + TRACE("context %p, numGPUs %p.\n", context, numGPUs); + + *numGPUs = context->device_count; + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsGetGPUMemorySize( AGSContext *context, int gpuIndex, long long *sizeInBytes ) +{ + struct AGSDeviceInfo_511 *device = &((struct AGSDeviceInfo_511 *)context->devices)[gpuIndex]; + + TRACE("context %p, gpuIndex %d, sizeInBytes %p.\n", context, gpuIndex, sizeInBytes); + + if ((unsigned)gpuIndex >= context->device_count) + return AGS_INVALID_ARGS; + + *sizeInBytes = device->localMemoryInBytes; + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsGetEyefinityConfigInfo( AGSContext *context, int displayIndex, AGSEyefinityInfo *eyefinityInfo, + int *numDisplaysInfo, AGSDisplayInfo_403 *displaysInfo ) +{ + struct AGSDeviceInfo_511 *devices; + unsigned int i; + + TRACE("context %p, displayIndex %d, eyefinityInfo %p, numDisplaysInfo %p, displaysInfo %p\n", + context, displayIndex, eyefinityInfo, numDisplaysInfo, displaysInfo); + + devices = (struct AGSDeviceInfo_511 *)context->devices; + *numDisplaysInfo = 0; + for (i = 0; i < context->device_count; ++i) + *numDisplaysInfo += devices[i].numDisplays; + + if (!eyefinityInfo || !displaysInfo) + return AGS_SUCCESS; + + /* displaysInfo is not filled in on Windows if Eyefinity is not enabled. */ + memset(eyefinityInfo, 0, sizeof(*eyefinityInfo)); + memset(displaysInfo, 0, *numDisplaysInfo * sizeof(*displaysInfo)); + + return AGS_SUCCESS; +} + +static DXGI_COLOR_SPACE_TYPE convert_ags_colorspace_506(AGSDisplaySettings_Mode_506 mode) +{ + switch (mode) + { + default: + ERR("Unknown color space in AGS: %d.\n", mode); + /* fallthrough */ + case Mode_506_SDR: + TRACE("Setting Mode_506_SDR.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + case Mode_506_PQ: + TRACE("Setting Mode_506_PQ.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + case Mode_506_scRGB: + TRACE("Setting Mode_506_scRGB.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; + } +} + +static DXGI_COLOR_SPACE_TYPE convert_ags_colorspace_600(AGSDisplaySettings_Mode_600 mode) +{ + switch (mode) + { + default: + ERR("Unknown color space in AGS: %d\n", mode); + /* fallthrough */ + case Mode_600_SDR: + TRACE("Setting Mode_600_SDR.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + case Mode_600_HDR10_PQ: + TRACE("Setting Mode_600_HDR10_PQ.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + case Mode_600_HDR10_scRGB: + TRACE("Setting Mode_600_HDR10_scRGB.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; + } +} + +static DXGI_HDR_METADATA_HDR10 convert_ags_metadata(const AGSDisplaySettings_600 *settings) +{ + DXGI_HDR_METADATA_HDR10 metadata; + metadata.RedPrimary[0] = settings->chromaticityRedX * 50000; + metadata.RedPrimary[1] = settings->chromaticityRedY * 50000; + metadata.GreenPrimary[0] = settings->chromaticityGreenX * 50000; + metadata.GreenPrimary[1] = settings->chromaticityGreenY * 50000; + metadata.BluePrimary[0] = settings->chromaticityBlueX * 50000; + metadata.BluePrimary[1] = settings->chromaticityBlueY * 50000; + metadata.WhitePoint[0] = settings->chromaticityWhitePointX * 50000; + metadata.WhitePoint[1] = settings->chromaticityWhitePointY * 50000; + metadata.MaxMasteringLuminance = settings->maxLuminance; + metadata.MinMasteringLuminance = settings->minLuminance / 0.0001f; + metadata.MaxContentLightLevel = settings->maxContentLightLevel; + metadata.MaxFrameAverageLightLevel = settings->maxFrameAverageLightLevel; + return metadata; +} + +AGSReturnCode WINAPI agsSetDisplayMode(AGSContext *context, int device_index, int display_index, const AGSDisplaySettings *settings) +{ + const AGSDisplaySettings_506 *settings506 = &settings->agsDisplaySettings506; + const AGSDisplaySettings_600 *settings600 = &settings->agsDisplaySettings600; + IDXGIVkInteropFactory1 *dxgi_interop = NULL; + DXGI_COLOR_SPACE_TYPE colorspace; + DXGI_HDR_METADATA_HDR10 metadata; + AGSReturnCode ret = AGS_SUCCESS; + IDXGIFactory1 *dxgi_factory; + HMODULE hdxgi; + + TRACE("context %p device_index %d display_index %d settings %p\n", context, device_index, + display_index, settings); + + if (!context) + return AGS_INVALID_ARGS; + + create_dxgi_factory(&hdxgi, &dxgi_factory); + if (!dxgi_factory) + goto done; + + if (FAILED(IDXGIFactory1_QueryInterface(dxgi_factory, &IID_IDXGIVkInteropFactory1, (void**)&dxgi_interop))) + { + WARN("Failed to get IDXGIVkInteropFactory1.\n"); + goto done; + } + + colorspace = context->version < AMD_AGS_VERSION_5_1_1 + ? convert_ags_colorspace_506(settings506->mode) + : convert_ags_colorspace_600(settings600->mode); + /* Settings 506, 511 and 600 are identical aside from enum order + use + * of bitfield flags we do not use. */ + metadata = convert_ags_metadata(settings600); + + TRACE("chromacity: (%.6lf, %.6lf) (%.6lf, %.6lf) (%.6lf, %.6lf).\n", settings600->chromaticityRedX, + settings600->chromaticityRedY, settings600->chromaticityGreenX, settings600->chromaticityGreenY, + settings600->chromaticityBlueX, settings600->chromaticityBlueY); + + if (FAILED(IDXGIVkInteropFactory1_SetGlobalHDRState(dxgi_interop, colorspace, &metadata))) + ret = AGS_DX_FAILURE; + +done: + if (dxgi_interop) + IDXGIVkInteropFactory1_Release(dxgi_interop); + release_dxgi_factory(hdxgi, dxgi_factory); + return ret; +} + +AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count) +{ + TRACE("context %p gpu_count %p stub!\n", context, gpu_count); + + if (!context || !gpu_count) + return AGS_INVALID_ARGS; + + *gpu_count = 1; + return AGS_SUCCESS; +} + +struct AGSDriverVersionInfo +{ + char strDriverVersion[256]; + char strCatalystVersion[256]; + char strCatalystWebLink[256]; +}; + +AGSReturnCode WINAPI agsGetDriverVersionInfo(AGSContext *context, struct AGSDriverVersionInfo *ver) +{ + TRACE("context %p, ver %p.\n", context, ver); + + if (!context || !ver) + return AGS_INVALID_ARGS; + + strcpy(ver->strDriverVersion, driver_version); + *ver->strCatalystVersion = 0; + *ver->strCatalystWebLink = 0; + return AGS_SUCCESS; +} + +static void get_dx11_extensions_supported(ID3D11Device *device, AGSDX11ExtensionsSupported_600 *extensions) +{ + ID3D11VkExtDevice *ext_device; + + if (FAILED(ID3D11Device_QueryInterface(device, &IID_ID3D11VkExtDevice, (void **)&ext_device))) + { + TRACE("No ID3D11VkExtDevice.\n"); + return; + } + + extensions->depthBoundsTest = !!ID3D11VkExtDevice_GetExtensionSupport(ext_device, D3D11_VK_EXT_DEPTH_BOUNDS); + extensions->uavOverlap = !!ID3D11VkExtDevice_GetExtensionSupport(ext_device, D3D11_VK_EXT_BARRIER_CONTROL); + extensions->multiDrawIndirect = !!ID3D11VkExtDevice_GetExtensionSupport(ext_device, D3D11_VK_EXT_MULTI_DRAW_INDIRECT); + extensions->multiDrawIndirectCountIndirect = !!ID3D11VkExtDevice_GetExtensionSupport(ext_device, D3D11_VK_EXT_MULTI_DRAW_INDIRECT_COUNT); + extensions->UAVOverlapDeferredContexts = extensions->uavOverlap; + + ID3D11VkExtDevice_Release(ext_device); + + TRACE("extensions %#x.\n", *(unsigned int *)extensions); +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_CreateDevice( AGSContext* context, + const AGSDX11DeviceCreationParams* creation_params, const AGSDX11ExtensionParams* extension_params, + AGSDX11ReturnedParams* returned_params ) +{ + ID3D11DeviceContext *device_context; + IDXGISwapChain *swapchain = NULL; + D3D_FEATURE_LEVEL feature_level; + ID3D11Device *device; + HRESULT hr; + + TRACE("feature levels %u, pSwapChainDesc %p, app %s, engine %s %#x %#x.\n", creation_params->FeatureLevels, + creation_params->pSwapChainDesc, + debugstr_w(extension_params->agsDX11ExtensionParams511.pAppName), + debugstr_w(extension_params->agsDX11ExtensionParams511.pEngineName), + extension_params->agsDX11ExtensionParams511.appVersion, + extension_params->agsDX11ExtensionParams511.engineVersion); + + if (!load_d3d11_functions()) + { + ERR("Could not load d3d11.dll.\n"); + return AGS_MISSING_D3D_DLL; + } + memset( returned_params, 0, amd_ags_info[context->version].dx11_returned_params_size ); + if (creation_params->pSwapChainDesc) + { + hr = pD3D11CreateDeviceAndSwapChain(creation_params->pAdapter, creation_params->DriverType, + creation_params->Software, creation_params->Flags, creation_params->pFeatureLevels, + creation_params->FeatureLevels, creation_params->SDKVersion, creation_params->pSwapChainDesc, + &swapchain, &device, &feature_level, &device_context); + } + else + { + hr = pD3D11CreateDevice(creation_params->pAdapter, creation_params->DriverType, + creation_params->Software, creation_params->Flags, creation_params->pFeatureLevels, + creation_params->FeatureLevels, creation_params->SDKVersion, + &device, &feature_level, &device_context); + } + if (FAILED(hr)) + { + ERR("Device creation failed, hr %#x.\n", hr); + return AGS_DX_FAILURE; + } + + get_dx11_extensions_supported(device, &context->extensions); + + if (context->version < AMD_AGS_VERSION_5_2_0) + { + AGSDX11ReturnedParams_511 *r = &returned_params->agsDX11ReturnedParams511; + r->pDevice = device; + r->pImmediateContext = device_context; + r->pSwapChain = swapchain; + r->FeatureLevel = feature_level; + r->extensionsSupported = *(unsigned int *)&context->extensions; + } + else if (context->version < AMD_AGS_VERSION_6_0_0) + { + AGSDX11ReturnedParams_520 *r = &returned_params->agsDX11ReturnedParams520; + r->pDevice = device; + r->pImmediateContext = device_context; + r->pSwapChain = swapchain; + r->FeatureLevel = feature_level; + r->extensionsSupported = *(unsigned int *)&context->extensions; + } + else + { + AGSDX11ReturnedParams_600 *r = &returned_params->agsDX11ReturnedParams600; + r->pDevice = device; + r->pImmediateContext = device_context; + r->pSwapChain = swapchain; + r->featureLevel = feature_level; + r->extensionsSupported = context->extensions; + } + + if (context->version < AMD_AGS_VERSION_5_3_0) + { + /* Later versions pass context to functions explicitly, no need to keep it. */ + if (context->d3d11_context) + ID3D11DeviceContext_Release(context->d3d11_context); + ID3D11DeviceContext_AddRef(device_context); + context->d3d11_context = device_context; + } + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX12_CreateDevice(AGSContext *context, + const AGSDX12DeviceCreationParams *creation_params, const AGSDX12ExtensionParams *extension_params, + AGSDX12ReturnedParams *returned_params) +{ + HRESULT hr; + + TRACE("feature level %#x, app %s, engine %s %#x %#x.\n", creation_params->FeatureLevel, debugstr_w(extension_params->pAppName), + debugstr_w(extension_params->pEngineName), extension_params->appVersion, extension_params->engineVersion); + + if (!load_d3d12_functions()) + { + ERR("Could not load d3d12.dll.\n"); + return AGS_MISSING_D3D_DLL; + } + + memset(returned_params, 0, sizeof(*returned_params)); + if (FAILED(hr = pD3D12CreateDevice((IUnknown *)creation_params->pAdapter, creation_params->FeatureLevel, + &creation_params->iid, (void **)&returned_params->pDevice))) + { + ERR("D3D12CreateDevice failed, hr %#x.\n", hr); + return AGS_DX_FAILURE; + } + + TRACE("Created d3d12 device %p.\n", returned_params->pDevice); + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX12_DestroyDevice(AGSContext* context, ID3D12Device* device, unsigned int* device_refs) +{ + ULONG ref_count; + + if (!device) + return AGS_SUCCESS; + + ref_count = ID3D12Device_Release(device); + if (device_refs) + *device_refs = (unsigned int)ref_count; + + return AGS_SUCCESS; +} + +AGSDriverVersionResult WINAPI agsCheckDriverVersion(const char* version_reported, unsigned int version_required) +{ + WARN("version_reported %s, version_required %d semi-stub.\n", debugstr_a(version_reported), version_required); + + return AGS_SOFTWAREVERSIONCHECK_OK; +} + +int WINAPI agsGetVersionNumber(void) +{ + int public_version = 0; + enum amd_ags_version version = determine_ags_version(&public_version); + + TRACE("version %s (internal %d).\n", debugstr_agsversion(public_version), version); + + return public_version; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_Init( AGSContext *context, ID3D11Device *device, unsigned int uavSlot, unsigned int *extensionsSupported ) +{ + FIXME("context %p, device %p, uavSlot %u, extensionsSupported %p stub.\n", context, device, uavSlot, extensionsSupported); + + if (!context) + { + ERR("NULL context.\n"); + return AGS_INVALID_ARGS; + } + + *extensionsSupported = 0; + if (device) + { + if (context->version < AMD_AGS_VERSION_5_3_0) + { + /* Later versions pass context to functions explicitly, no need to keep it. */ + if (context->d3d11_context) + { + ID3D11DeviceContext_Release(context->d3d11_context); + context->d3d11_context = NULL; + } + ID3D11Device_GetImmediateContext(device, &context->d3d11_context); + } + get_dx11_extensions_supported(device, &context->extensions); + if (context->public_version <= AGS_MAKE_VERSION(3, 0, 0)) + *extensionsSupported = context->extensions.quadList | (context->extensions.uavOverlap << 1) + | (context->extensions.depthBoundsTest << 2) | (context->extensions.multiDrawIndirect << 3); + else + *extensionsSupported = *(unsigned int *)&context->extensions; + TRACE("-> %#x.\n", *extensionsSupported); + } + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensions_Init( AGSContext* context, ID3D11Device* device, unsigned int* extensionsSupported ) +{ + TRACE("context %p, device %p, extensionsSupported %p.\n", context, device, extensionsSupported); + + return agsDriverExtensionsDX11_Init(context, device, ~0u, extensionsSupported); +} + +AGSReturnCode WINAPI agsDriverExtensions_SetCrossfireMode(AGSContext *context, AGSCrossfireMode mode) +{ + FIXME("context %p, mode %d stub.\n", context, mode); + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_DeInit( AGSContext* context ) +{ + TRACE("context %p.\n", context); + + if (context->d3d11_context) + { + ID3D11DeviceContext_Release(context->d3d11_context); + context->d3d11_context = NULL; + } + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensions_DeInit(AGSContext *context) +{ + return agsDriverExtensionsDX11_DeInit(context); +} + +AGSReturnCode WINAPI agsDriverExtensionsDX12_Init( AGSContext* context, ID3D12Device* device, unsigned int* extensionsSupported ) +{ + FIXME("context %p, device %p, extensionsSupported %p stub.\n", context, device, extensionsSupported); + + *extensionsSupported = 0; + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX12_DeInit( AGSContext* context ) +{ + TRACE("context %p.\n", context); + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX12_SetMarker( AGSContext *context, ID3D12GraphicsCommandList *command_list, const char *data) +{ + WARN("context %p, command_list %p, data %p stub.\n", context, command_list, data); + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX12_PushMarker( AGSContext *context, ID3D12GraphicsCommandList *command_list, const char* data) +{ + WARN("context %p, command_list %p, data %p stub.\n", context, command_list, data); + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX12_PopMarker(AGSContext *context, ID3D12GraphicsCommandList *command_list) +{ + WARN("context %p, command_list %p stub.\n", context, command_list); + + return AGS_SUCCESS; +} + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) +{ + TRACE("%p, %u, %p.\n", instance, reason, reserved); + + switch (reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(instance); + break; + } + + return TRUE; +} + +#ifdef __x86_64__ + +static AGSReturnCode set_depth_bounds(AGSContext* context, ID3D11DeviceContext *dx_context, bool enabled, + float min_depth, float max_depth) +{ + ID3D11VkExtContext *ext_context; + + if (!context->extensions.depthBoundsTest) + return AGS_EXTENSION_NOT_SUPPORTED; + + if (FAILED(ID3D11DeviceContext_QueryInterface(dx_context, &IID_ID3D11VkExtContext, (void **)&ext_context))) + { + TRACE("No ID3D11VkExtContext.\n"); + return AGS_EXTENSION_NOT_SUPPORTED; + } + ID3D11VkExtContext_SetDepthBoundsTest(ext_context, enabled, min_depth, max_depth); + ID3D11VkExtContext_Release(ext_context); + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_SetDepthBounds(AGSContext* context, bool enabled, + float min_depth, float max_depth ) +{ + TRACE("context %p, enabled %d, min_depth %f, max_depth %f.\n", context, enabled, min_depth, max_depth); + + if (!context || !context->d3d11_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + return set_depth_bounds(context, context->d3d11_context, enabled, min_depth, max_depth); +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_SetDepthBounds_530(AGSContext* context, + ID3D11DeviceContext* dx_context, bool enabled, float min_depth, float max_depth ) +{ + TRACE("context %p, dx_context %p, enabled %d, min_depth %f, max_depth %f.\n", context, dx_context, enabled, + min_depth, max_depth); + + if (!context || !dx_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + return set_depth_bounds(context, dx_context, enabled, min_depth, max_depth); +} + +C_ASSERT(AMD_AGS_VERSION_5_3_0 == 4); +__ASM_GLOBAL_FUNC( DX11_SetDepthBounds_impl, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $4,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds_530") ) + +static AGSReturnCode update_uav_overlap(AGSContext* context, ID3D11DeviceContext *dx_context, BOOL set) +{ + ID3D11VkExtContext *ext_context; + + if (!context->extensions.uavOverlap) + return AGS_EXTENSION_NOT_SUPPORTED; + + if (FAILED(ID3D11DeviceContext_QueryInterface(dx_context, &IID_ID3D11VkExtContext, (void **)&ext_context))) + { + TRACE("No ID3D11VkExtContext.\n"); + return AGS_EXTENSION_NOT_SUPPORTED; + } + + ID3D11VkExtContext_SetBarrierControl(ext_context, set ? D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE : 0); + ID3D11VkExtContext_Release(ext_context); + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_BeginUAVOverlap_520(AGSContext *context) +{ + TRACE("context %p.\n", context); + + if (!context || !context->d3d11_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + return update_uav_overlap(context, context->d3d11_context, TRUE); +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_BeginUAVOverlap(AGSContext *context, ID3D11DeviceContext *dx_context) +{ + TRACE("context %p, dx_context %p.\n", context, dx_context); + + if (!context || !dx_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + return update_uav_overlap(context, dx_context, TRUE); +} + +C_ASSERT(AMD_AGS_VERSION_5_3_0 == 4); +__ASM_GLOBAL_FUNC( DX11_BeginUAVOverlap_impl, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $4,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_BeginUAVOverlap_520") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_BeginUAVOverlap") ) + +AGSReturnCode WINAPI agsDriverExtensionsDX11_EndUAVOverlap_520(AGSContext *context) +{ + TRACE("context %p.\n", context); + + if (!context || !context->d3d11_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + return update_uav_overlap(context, context->d3d11_context, FALSE); +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_EndUAVOverlap(AGSContext *context, ID3D11DeviceContext *dx_context) +{ + TRACE("context %p, dx_context %p.\n", context, dx_context); + + if (!context || !dx_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + return update_uav_overlap(context, dx_context, FALSE); +} + +C_ASSERT(AMD_AGS_VERSION_5_3_0 == 4); +__ASM_GLOBAL_FUNC( DX11_EndUAVOverlap_impl, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $4,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_EndUAVOverlap_520") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_EndUAVOverlap") ) + +AGSReturnCode WINAPI agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect(AGSContext *context, ID3D11DeviceContext *dx_context, + unsigned int draw_count, ID3D11Buffer *buffer_for_args, unsigned int aligned_byte_offset_for_args, + unsigned int byte_stride_for_args) +{ + ID3D11VkExtContext *ext_context; + + TRACE("context %p, dx_context %p, draw_count %u, buffer_for_args %p, aligned_byte_offset_for_args %u, byte_stride_for_args %u.\n", + context, dx_context, draw_count, buffer_for_args, aligned_byte_offset_for_args, byte_stride_for_args); + + if (!context || !dx_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + if (!context->extensions.multiDrawIndirect) + return AGS_EXTENSION_NOT_SUPPORTED; + + if (FAILED(ID3D11DeviceContext_QueryInterface(dx_context, &IID_ID3D11VkExtContext, (void **)&ext_context))) + { + TRACE("No ID3D11VkExtContext.\n"); + return AGS_EXTENSION_NOT_SUPPORTED; + } + + ID3D11VkExtContext_MultiDrawIndexedIndirect(ext_context, draw_count, buffer_for_args, aligned_byte_offset_for_args, + byte_stride_for_args); + ID3D11VkExtContext_Release(ext_context); + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect_520(AGSContext *context, + unsigned int draw_count, ID3D11Buffer *buffer_for_args, unsigned int aligned_byte_offset_for_args, + unsigned int byte_stride_for_args) +{ + if (!context || !context->d3d11_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + return agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect(context, context->d3d11_context, draw_count, + buffer_for_args, aligned_byte_offset_for_args, byte_stride_for_args); +} + +C_ASSERT(AMD_AGS_VERSION_5_3_0 == 4); +__ASM_GLOBAL_FUNC( DX11_MultiDrawIndexedInstancedIndirect_impl, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $4,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect_520") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect") ) + + +AGSReturnCode WINAPI agsDriverExtensionsDX11_MultiDrawInstancedIndirect(AGSContext *context, ID3D11DeviceContext *dx_context, + unsigned int draw_count, ID3D11Buffer *buffer_for_args, unsigned int aligned_byte_offset_for_args, + unsigned int byte_stride_for_args) +{ + ID3D11VkExtContext *ext_context; + + TRACE("context %p, dx_context %p, draw_count %u, buffer_for_args %p, aligned_byte_offset_for_args %u, byte_stride_for_args %u.\n", + context, dx_context, draw_count, buffer_for_args, aligned_byte_offset_for_args, byte_stride_for_args); + + if (!context || !dx_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + if (!context->extensions.multiDrawIndirect) + return AGS_EXTENSION_NOT_SUPPORTED; + + if (FAILED(ID3D11DeviceContext_QueryInterface(dx_context, &IID_ID3D11VkExtContext, (void **)&ext_context))) + { + TRACE("No ID3D11VkExtContext.\n"); + return AGS_EXTENSION_NOT_SUPPORTED; + } + + ID3D11VkExtContext_MultiDrawIndirect(ext_context, draw_count, buffer_for_args, aligned_byte_offset_for_args, + byte_stride_for_args); + ID3D11VkExtContext_Release(ext_context); + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_MultiDrawInstancedIndirect_520( AGSContext* context, unsigned int draw_count, + ID3D11Buffer *buffer_for_args, unsigned int aligned_byte_offset_for_args, unsigned int byte_stride_for_args) +{ + if (!context || !context->d3d11_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + return agsDriverExtensionsDX11_MultiDrawInstancedIndirect(context, context->d3d11_context, draw_count, + buffer_for_args, aligned_byte_offset_for_args, byte_stride_for_args); +} + +C_ASSERT(AMD_AGS_VERSION_5_3_0 == 4); +__ASM_GLOBAL_FUNC( DX11_MultiDrawInstancedIndirect_impl, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $4,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_MultiDrawInstancedIndirect_520") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_MultiDrawInstancedIndirect") ) + +static unsigned int get_max_draw_count(ID3D11Buffer *args, unsigned int offset, unsigned int stride, unsigned int size) +{ + D3D11_BUFFER_DESC desc; + unsigned int count; + + ID3D11Buffer_GetDesc(args, &desc); + if (offset >= desc.ByteWidth) + { + WARN("offset %u, buffer size %u.\n", offset, desc.ByteWidth); + return 0; + } + count = (desc.ByteWidth - offset) / stride; + if (desc.ByteWidth - offset - count * stride >= size) + ++count; + if (!count) + WARN("zero count, buffer size %u, offset %u, stride %u, size %u.\n", desc.ByteWidth, offset, stride, size); + return count; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect(AGSContext *context, ID3D11DeviceContext *dx_context, + ID3D11Buffer *buffer_for_draw_count, unsigned int aligned_byte_offset_for_draw_count, ID3D11Buffer *buffer_for_args, + unsigned int aligned_byte_offset_for_args, unsigned int byte_stride_for_args) +{ + ID3D11VkExtContext *ext_context; + unsigned int max_draw_count; + + TRACE("context %p, dx_context %p, count buffer %p, offset %u, args buffer %p, offset %u, stride %u.\n", + context, dx_context, buffer_for_draw_count, aligned_byte_offset_for_draw_count, buffer_for_args, + aligned_byte_offset_for_args, byte_stride_for_args); + + if (!context || !dx_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + if (!context->extensions.multiDrawIndirectCountIndirect) + return AGS_EXTENSION_NOT_SUPPORTED; + + if (FAILED(ID3D11DeviceContext_QueryInterface(dx_context, &IID_ID3D11VkExtContext, (void **)&ext_context))) + { + TRACE("No ID3D11VkExtContext.\n"); + return AGS_EXTENSION_NOT_SUPPORTED; + } + + max_draw_count = get_max_draw_count(buffer_for_args, aligned_byte_offset_for_args, byte_stride_for_args, sizeof(D3D11_DRAW_INDEXED_INSTANCED_INDIRECT_ARGS)); + ID3D11VkExtContext_MultiDrawIndexedIndirectCount(ext_context, max_draw_count, buffer_for_draw_count, aligned_byte_offset_for_draw_count, + buffer_for_args, aligned_byte_offset_for_args, byte_stride_for_args); + ID3D11VkExtContext_Release(ext_context); + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect_520(AGSContext *context, + ID3D11Buffer *buffer_for_draw_count, unsigned int aligned_byte_offset_for_draw_count, ID3D11Buffer *buffer_for_args, + unsigned int aligned_byte_offset_for_args, unsigned int byte_stride_for_args) +{ + if (!context || !context->d3d11_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + return agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect(context, context->d3d11_context, + buffer_for_draw_count, aligned_byte_offset_for_draw_count, + buffer_for_args, aligned_byte_offset_for_args, byte_stride_for_args); +} + +C_ASSERT(AMD_AGS_VERSION_5_3_0 == 4); +__ASM_GLOBAL_FUNC( DX11_MultiDrawIndexedInstancedIndirectCountIndirect_impl, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $4,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect_520") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect") ) + + +AGSReturnCode WINAPI agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect(AGSContext *context, ID3D11DeviceContext *dx_context, + ID3D11Buffer *buffer_for_draw_count, unsigned int aligned_byte_offset_for_draw_count, ID3D11Buffer *buffer_for_args, + unsigned int aligned_byte_offset_for_args, unsigned int byte_stride_for_args) +{ + ID3D11VkExtContext *ext_context; + unsigned int max_draw_count; + + TRACE("context %p, dx_context %p, count buffer %p, offset %u, args buffer %p, offset %u, stride %u.\n", + context, dx_context, buffer_for_draw_count, aligned_byte_offset_for_draw_count, buffer_for_args, + aligned_byte_offset_for_args, byte_stride_for_args); + + if (!context || !dx_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + if (!context->extensions.multiDrawIndirectCountIndirect) + return AGS_EXTENSION_NOT_SUPPORTED; + + if (FAILED(ID3D11DeviceContext_QueryInterface(dx_context, &IID_ID3D11VkExtContext, (void **)&ext_context))) + { + TRACE("No ID3D11VkExtContext.\n"); + return AGS_EXTENSION_NOT_SUPPORTED; + } + + max_draw_count = get_max_draw_count(buffer_for_args, aligned_byte_offset_for_args, byte_stride_for_args, sizeof(D3D11_DRAW_INSTANCED_INDIRECT_ARGS)); + ID3D11VkExtContext_MultiDrawIndirectCount(ext_context, max_draw_count, buffer_for_draw_count, aligned_byte_offset_for_draw_count, + buffer_for_args, aligned_byte_offset_for_args, byte_stride_for_args); + ID3D11VkExtContext_Release(ext_context); + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect_520(AGSContext *context, + ID3D11Buffer *buffer_for_draw_count, unsigned int aligned_byte_offset_for_draw_count, ID3D11Buffer *buffer_for_args, + unsigned int aligned_byte_offset_for_args, unsigned int byte_stride_for_args) +{ + if (!context || !context->d3d11_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + return agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect(context, context->d3d11_context, + buffer_for_draw_count, aligned_byte_offset_for_draw_count, + buffer_for_args, aligned_byte_offset_for_args, byte_stride_for_args); +} + +C_ASSERT(AMD_AGS_VERSION_5_3_0 == 4); +__ASM_GLOBAL_FUNC( DX11_MultiDrawInstancedIndirectCountIndirect_impl, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $4,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect_520") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect") ) + +AGSReturnCode WINAPI agsDriverExtensionsDX11_DestroyDevice_520(AGSContext *context, ID3D11Device* device, + unsigned int *device_ref, ID3D11DeviceContext *device_context, + unsigned int *context_ref) +{ + ULONG ref; + + TRACE("context %p, device %p, device_ref %p, device_context %p, context_ref %p.\n", + context, device, device_ref, device_context, context_ref); + + if (!device) + return AGS_SUCCESS; + + if (context->d3d11_context) + { + ID3D11DeviceContext_Release(context->d3d11_context); + context->d3d11_context = NULL; + } + + ref = ID3D11Device_Release(device); + if (device_ref) + *device_ref = ref; + + if (!device_context) + return AGS_SUCCESS; + + ref = ID3D11DeviceContext_Release(device_context); + if (context_ref) + *context_ref = ref; + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_DestroyDevice_511(AGSContext *context, ID3D11Device *device, + unsigned int *references ) +{ + TRACE("context %p, device %p, references %p.\n", context, device, references); + + return agsDriverExtensionsDX11_DestroyDevice_520(context, device, references, NULL, NULL); +} + +C_ASSERT(AMD_AGS_VERSION_5_2_0 == 3); +__ASM_GLOBAL_FUNC( agsDriverExtensionsDX11_DestroyDevice, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $3,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_DestroyDevice_511") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_DestroyDevice_520") ) +#endif + +AGSReturnCode WINAPI agsDriverExtensionsDX11_SetDiskShaderCacheEnabled(AGSContext *context, int enable) +{ + FIXME("context %p, enable %d stub.\n", context, enable); + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount(AGSContext *context, unsigned int thread_count) +{ + FIXME("context %p, thread_count %u.\n", context, thread_count); + return AGS_SUCCESS; +} diff --git a/dlls/amd_ags_x64/dxvk_interfaces.idl b/dlls/amd_ags_x64/dxvk_interfaces.idl new file mode 100644 index 000000000000..110cdb948964 --- /dev/null +++ b/dlls/amd_ags_x64/dxvk_interfaces.idl @@ -0,0 +1,151 @@ +/* + * Copyright 2023 Paul Gofman for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +import "d3d11.idl"; +import "dxgi1_6.idl"; + +typedef struct VkInstance_T *VkInstance; +typedef void (__stdcall *PFN_vkVoidFunction)(void); +typedef PFN_vkVoidFunction (__stdcall *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); + +typedef enum D3D11_VK_EXTENSION +{ + D3D11_VK_EXT_MULTI_DRAW_INDIRECT, + D3D11_VK_EXT_MULTI_DRAW_INDIRECT_COUNT, + D3D11_VK_EXT_DEPTH_BOUNDS, + D3D11_VK_EXT_BARRIER_CONTROL, + D3D11_VK_NVX_BINARY_IMPORT, + D3D11_VK_NVX_IMAGE_VIEW_HANDLE, +} D3D11_VK_EXTENSION; + +typedef enum D3D11_VK_BARRIER_CONTROL +{ + D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE = 0x1, + D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV = 0x2, +} D3D11_VK_BARRIER_CONTROL; + +[ + object, + uuid(bb8a4fb9-3935-4762-b44b-35189a26414a), + local, + pointer_default(unique) +] +interface ID3D11VkExtShader : IUnknown +{ + HRESULT GetSpirvCode([in, out] SIZE_T *code_size, [out] void *code); +} + +[ + object, + uuid(8a6e3c42-f74c-45b7-8265-a231b677ca17), + local, + pointer_default(unique) +] +interface ID3D11VkExtDevice : IUnknown +{ + BOOL GetExtensionSupport([in] D3D11_VK_EXTENSION extension); +} + +[ + object, + uuid(cfcf64ef-9586-46d0-bca4-97cf2ca61b06), + local, + pointer_default(unique) +] +interface ID3D11VkExtDevice1 : ID3D11VkExtDevice +{ + BOOL GetResourceHandleGPUVirtualAddressAndSizeNVX([in] void *object, [out] UINT64 *gpu_va_start, + [out] UINT64 *gpu_va_size); + BOOL CreateUnorderedAccessViewAndGetDriverHandleNVX([in] ID3D11Resource *resource, + [in] const D3D11_UNORDERED_ACCESS_VIEW_DESC *desc, [out] ID3D11UnorderedAccessView **uav, + UINT32 *driver_handle); + BOOL CreateShaderResourceViewAndGetDriverHandleNVX([in] ID3D11Resource *resource, + [in] const D3D11_SHADER_RESOURCE_VIEW_DESC* desc, [out] ID3D11ShaderResourceView **srv, + UINT32 *dirver_handle); + BOOL CreateSamplerStateAndGetDriverHandleNVX([in] const D3D11_SAMPLER_DESC *sample_desc, + [out] ID3D11SamplerState **sample_state, UINT32 *driver_handle); + BOOL CreateCubinComputeShaderWithNameNVX([in] const void *cubin, [in] UINT32 size, [in] UINT32 block_x, + [in] UINT32 block_y, [in] UINT32 block_z, [in] const char *shader_name, [out] IUnknown **shader); + BOOL GetCudaTextureObjectNVX([in] UINT32 srv_driver_hadnle, [in] UINT32 sample_driver_handle, + [out] UINT32 *cuda_texture_handle); +} + +[ + object, + uuid(fd0bca13-5cb6-4c3a-987e-4750de2ca791), + local, + pointer_default(unique) +] +interface ID3D11VkExtContext : IUnknown +{ + void MultiDrawIndirect([in] UINT draw_count, [in] ID3D11Buffer *buffer_for_args, [in] UINT byte_offset_for_args, + [in] UINT byte_stride_for_args); + void MultiDrawIndexedIndirect([in] UINT draw_count, [in] ID3D11Buffer *buffer_for_args, + [in] UINT byte_offset_for_args, [in] UINT byte_stride_for_args); + void MultiDrawIndirectCount([in] UINT max_draw_count, [in] ID3D11Buffer *buffer_for_count, + [in] UINT byte_offset_for_count, [in] ID3D11Buffer *buffer_for_args, + [in] UINT byte_offset_for_args, [in] UINT byte_stride_for_args); + void MultiDrawIndexedIndirectCount([in] UINT max_draw_count, [in] ID3D11Buffer *buffer_for_count, + [in] UINT byte_offset_for_count, [in] ID3D11Buffer *buffer_for_args, + [in] UINT byte_offset_for_args, [in] UINT byte_stride_for_args); + void SetDepthBoundsTest([in] BOOL enable, [in] FLOAT min_depth_bounds, [in] FLOAT max_depth_bounds); + void SetBarrierControl([in] UINT control_flags); +} + +[ + object, + uuid(874b09b2-ae0b-41d8-8476-5f3b7a0e879d), + local, + pointer_default(unique) +] +interface ID3D11VkExtContext1 : ID3D11VkExtContext +{ + BOOL LaunchCubinShaderNVX([in] IUnknown *shader,[in] UINT32 grid_x, [in] UINT32 grid_y, [in] UINT32 grid_z, + [in] const void *params, [in] UINT32 param_size, [in] void * const *read_resources, + [in] UINT32 read_resource_count, [in] void* const *write_resources, [in] UINT32 write_resources_count); +} + +[ + object, + uuid(4c5e1b0d-b0c8-4131-bfd8-9b2476f7f408), + local, + pointer_default(unique) +] +interface IDXGIVkInteropFactory : IUnknown +{ + void GetVulkanInstance( + [out] VkInstance *pInstance, + [out] PFN_vkGetInstanceProcAddr *ppfnVkGetInstanceProcAddr); +} + +[ + object, + uuid(2a289dbd-2d0a-4a51-89f7-f2adce465cd6), + local, + pointer_default(unique) +] +interface IDXGIVkInteropFactory1 : IDXGIVkInteropFactory +{ + HRESULT GetGlobalHDRState( + [out] DXGI_COLOR_SPACE_TYPE *pOutColorSpace, + [out] DXGI_HDR_METADATA_HDR10 *ppOutMetadata) = 0; + + HRESULT SetGlobalHDRState( + [in] DXGI_COLOR_SPACE_TYPE ColorSpace, + [in] const DXGI_HDR_METADATA_HDR10 *pMetadata) = 0; +} diff --git a/dlls/amd_ags_x64/unixlib.c b/dlls/amd_ags_x64/unixlib.c new file mode 100644 index 000000000000..d34a162b55cb --- /dev/null +++ b/dlls/amd_ags_x64/unixlib.c @@ -0,0 +1,283 @@ +/* + * Unix library for amd_ags_x64 functions + * + * Copyright 2023 Paul Gofman for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" + +#include "wine/debug.h" + +#include "unixlib.h" + +WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); + +#define MAX_DEVICE_COUNT 64 + +static unsigned int device_count; +static struct drm_amdgpu_info_device *amd_info; + +static NTSTATUS init( void *args ) +{ + drmDevicePtr devices[MAX_DEVICE_COUNT]; + amdgpu_device_handle h; + uint32_t major, minor; + int i, count, fd, ret; + + device_count = 0; + + if ((count = drmGetDevices(devices, MAX_DEVICE_COUNT)) <= 0) + { + ERR("drmGetDevices failed, err %d.\n", count); + return STATUS_UNSUCCESSFUL; + } + TRACE("Got %d devices.\n", count); + for (i = 0; i < count; ++i) + { + if (!devices[i] || !devices[i]->nodes[DRM_NODE_RENDER]) + { + TRACE("No render node, skipping.\n"); + continue; + } + if ((fd = open(devices[i]->nodes[DRM_NODE_RENDER], O_RDONLY | O_CLOEXEC)) < 0) + { + ERR("Failed to open device %s, errno %d.\n", devices[i]->nodes[DRM_NODE_RENDER], errno); + continue; + } + if ((ret = amdgpu_device_initialize(fd, &major, &minor, &h))) + { + WARN("Failed to initialize amdgpu device bustype %d, %04x:%04x, err %d.\n", devices[i]->bustype, + devices[i]->deviceinfo.pci->vendor_id, devices[i]->deviceinfo.pci->device_id, ret); + close(fd); + continue; + } + amd_info = realloc(amd_info, (device_count + 1) * sizeof(*amd_info)); + /* amdgpu_query_info() doesn't fail on short buffer (filling in the available buffer size). So older or + * newer DRM version should be fine but zero init the structure to avoid random values. */ + memset(&amd_info[device_count], 0, sizeof(*amd_info)); + if (!(ret = amdgpu_query_info(h, AMDGPU_INFO_DEV_INFO, sizeof(*amd_info), &amd_info[device_count]))) + { + TRACE("Got amdgpu info for device id %04x, family %#x, external_rev %#x, chip_rev %#x.\n", + amd_info[device_count].device_id, amd_info[device_count].family, amd_info[device_count].external_rev, + amd_info[device_count].chip_rev); + ++device_count; + } + else + { + ERR("amdgpu_query_info failed, ret %d.\n", ret); + } + amdgpu_device_deinitialize(h); + close(fd); + } + drmFreeDevices(devices, count); + return STATUS_SUCCESS; +} + +#ifndef AMDGPU_VRAM_TYPE_DDR5 +# define AMDGPU_VRAM_TYPE_DDR5 10 +#endif +#ifndef AMDGPU_VRAM_TYPE_LPDDR4 +# define AMDGPU_VRAM_TYPE_LPDDR4 11 +#endif +#ifndef AMDGPU_VRAM_TYPE_LPDDR5 +# define AMDGPU_VRAM_TYPE_LPDDR5 12 +#endif + +/* From Mesa source. */ +static uint32_t memory_ops_per_clock(uint32_t vram_type) +{ + /* Based on MemoryOpsPerClockTable from PAL. */ + switch (vram_type) { + case AMDGPU_VRAM_TYPE_GDDR1: + case AMDGPU_VRAM_TYPE_GDDR3: /* last in low-end Evergreen */ + case AMDGPU_VRAM_TYPE_GDDR4: /* last in R7xx, not used much */ + case AMDGPU_VRAM_TYPE_UNKNOWN: + default: + return 0; + case AMDGPU_VRAM_TYPE_DDR2: + case AMDGPU_VRAM_TYPE_DDR3: + case AMDGPU_VRAM_TYPE_DDR4: + case AMDGPU_VRAM_TYPE_LPDDR4: + case AMDGPU_VRAM_TYPE_HBM: /* same for HBM2 and HBM3 */ + return 2; + case AMDGPU_VRAM_TYPE_DDR5: + case AMDGPU_VRAM_TYPE_LPDDR5: + case AMDGPU_VRAM_TYPE_GDDR5: /* last in Polaris and low-end Navi14 */ + return 4; + case AMDGPU_VRAM_TYPE_GDDR6: + return 16; + } +} + +typedef enum AsicFamily +{ + AsicFamily_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId + AsicFamily_PreGCN, ///< Pre GCN architecture. + AsicFamily_GCN1, ///< AMD GCN 1 architecture: Oland, Cape Verde, Pitcairn & Tahiti. + AsicFamily_GCN2, ///< AMD GCN 2 architecture: Hawaii & Bonaire. This also includes APUs Kaveri and Carrizo. + AsicFamily_GCN3, ///< AMD GCN 3 architecture: Tonga & Fiji. + AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris. + AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU). + AsicFamily_RDNA, ///< AMD RDNA architecture + AsicFamily_RDNA2, ///< AMD RDNA2 architecture + AsicFamily_RDNA3, ///< AMD RDNA3 architecture + AsicFamily_RDNA4, +} AsicFamily; + +/* Constants from Mesa source. */ +#define FAMILY_UNKNOWN 0x00 +#define FAMILY_TN 0x69 /* # 105 / Trinity APUs */ +#define FAMILY_SI 0x6E /* # 110 / Southern Islands: Tahiti, Pitcairn, CapeVerde, Oland, Hainan */ +#define FAMILY_CI 0x78 /* # 120 / Sea Islands: Bonaire, Hawaii */ +#define FAMILY_KV 0x7D /* # 125 / Kaveri APUs: Spectre, Spooky, Kalindi, Godavari */ +#define FAMILY_VI 0x82 /* # 130 / Volcanic Islands: Iceland, Tonga, Fiji */ +#define FAMILY_POLARIS 0x82 /* # 130 / Polaris: 10, 11, 12 */ +#define FAMILY_CZ 0x87 /* # 135 / Carrizo APUs: Carrizo, Stoney */ +#define FAMILY_AI 0x8D /* # 141 / Vega: 10, 20 */ +#define FAMILY_RV 0x8E /* # 142 / Raven */ +#define FAMILY_NV 0x8F /* # 143 / Navi: 10 */ +#define FAMILY_VGH 0x90 /* # 144 / Van Gogh */ +#define FAMILY_NV3 0x91 /* # 145 / Navi: 3x */ +#define FAMILY_RMB 0x92 /* # 146 / Rembrandt */ +#define FAMILY_RPL 0x95 /* # 149 / Raphael */ +#define FAMILY_GFX1103 0x94 +#define FAMILY_GFX1150 0x96 +#define FAMILY_MDN 0x97 /* # 151 / Mendocino */ +#define FAMILY_GFX12 0x98 + +#define ROUND_DIV(value, div) (((value) + (div) / 2) / (div)) + +static void fill_device_info(struct drm_amdgpu_info_device *info, struct get_device_info_params *out) +{ + uint32_t erev = info->external_rev; + uint64_t max_engine_clock_khz, max_memory_clock_khz; + + out->asic_family = AsicFamily_Unknown; + switch (info->family) + { + case FAMILY_AI: + case FAMILY_RV: + out->asic_family = AsicFamily_Vega; + break; + + /* Treat pre-Polaris cards as Polaris. */ + case FAMILY_CZ: + case FAMILY_SI: + case FAMILY_CI: + case FAMILY_KV: + case FAMILY_POLARIS: + out->asic_family = AsicFamily_GCN4; + break; + + case FAMILY_NV: + if (erev >= 0x01 && erev < 0x28) + out->asic_family = AsicFamily_RDNA; + else if (erev >= 0x28 && erev < 0x50) + out->asic_family = AsicFamily_RDNA2; + break; + + case FAMILY_RMB: + case FAMILY_RPL: + case FAMILY_MDN: + case FAMILY_VGH: + out->asic_family = AsicFamily_RDNA2; + break; + + case FAMILY_NV3: + case FAMILY_GFX1103: + case FAMILY_GFX1150: + out->asic_family = AsicFamily_RDNA3; + break; + + case FAMILY_GFX12: + out->asic_family = AsicFamily_RDNA4; + break; + } + TRACE("family %u, erev %#x -> asicFamily %d.\n", info->family, erev, out->asic_family); + if (out->asic_family == AsicFamily_Unknown && info->family != FAMILY_UNKNOWN) + { + if (info->family > FAMILY_GFX1150) + out->asic_family = AsicFamily_RDNA3; + else + out->asic_family = AsicFamily_GCN4; + + FIXME("Unrecognized family %u, erev %#x -> defaulting to %d.\n", info->family, erev, + out->asic_family); + } + + out->num_cu = info->cu_active_number; + out->num_wgp = out->asic_family >= AsicFamily_RDNA ? out->num_cu / 2 : 0; + out->num_rops = info->num_rb_pipes * 4; + TRACE("num_cu %d, num_wgp %d, num_rops %d.\n", out->num_cu, out->num_wgp, out->num_rops); + /* These numbers are zero on Vangogh, workaround that (similar to how it is currently done + * in Mesa src/amd/common/ac_rgp.c. */ + if (!(max_engine_clock_khz = info->max_engine_clock)) + max_engine_clock_khz = 1300000; + if (!(max_memory_clock_khz = info->max_memory_clock)) + max_memory_clock_khz = 687000; + out->core_clock = ROUND_DIV(max_engine_clock_khz, 1000); + out->memory_clock = ROUND_DIV(max_memory_clock_khz, 1000); + out->memory_bandwidth = ROUND_DIV(max_memory_clock_khz * memory_ops_per_clock(info->vram_type) + * info->vram_bit_width / 8, 1000); + TRACE("core_clock %uMHz, memory_clock %uMHz, memory_bandwidth %u.\n", + out->core_clock, out->memory_clock, out->memory_bandwidth); + out->teraflops = 1e-9f * max_engine_clock_khz * info->cu_active_number * 64 * 2; + TRACE("teraflops %.2f.\n", out->teraflops); +} + +static NTSTATUS get_device_info( void *args ) +{ + struct get_device_info_params *params = args; + unsigned int i; + + for (i = 0; i < device_count; ++i) + { + if (amd_info[i].device_id != params->device_id) + continue; + TRACE("device %04x found.\n", params->device_id); + fill_device_info(&amd_info[i], params); + return STATUS_SUCCESS; + } + TRACE("Device %04x not found.\n", params->device_id); + return STATUS_NOT_FOUND; +} + +const unixlib_entry_t __wine_unix_call_funcs[] = +{ + init, + get_device_info, +}; diff --git a/dlls/amd_ags_x64/unixlib.h b/dlls/amd_ags_x64/unixlib.h new file mode 100644 index 000000000000..72422e1535ca --- /dev/null +++ b/dlls/amd_ags_x64/unixlib.h @@ -0,0 +1,42 @@ +/* + * Unix library interface + * + * Copyright 2023 Paul Gofman for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "wine/unixlib.h" + +enum amd_ags_funcs +{ + unix_init, + unix_get_device_info, +}; + +struct get_device_info_params +{ + uint32_t device_id; + uint32_t _pad; + /* Output parameters. */ + uint32_t asic_family; + uint32_t num_cu; + uint32_t num_wgp; + uint32_t num_rops; + uint32_t core_clock; + uint32_t memory_clock; + uint32_t memory_bandwidth; + float teraflops; +}; diff --git a/dlls/amdxc64/Makefile.in b/dlls/amdxc64/Makefile.in new file mode 100644 index 000000000000..a27f1da40ff6 --- /dev/null +++ b/dlls/amdxc64/Makefile.in @@ -0,0 +1,9 @@ +MODULE = amdxc64.dll +IMPORTS = version vulkan-1 user32 gdi32 +IMPORTLIB = amdxc64 + +EXTRADLLFLAGS = -mno-cygwin + +SOURCES = \ + main.c \ + amdxc_interfaces.idl \ diff --git a/dlls/amdxc64/amdxc64.spec b/dlls/amdxc64/amdxc64.spec new file mode 100644 index 000000000000..5c6ecb267df3 --- /dev/null +++ b/dlls/amdxc64/amdxc64.spec @@ -0,0 +1,5 @@ +@ cdecl AmdExtD3DCreateInterface(ptr ptr ptr) +@ stdcall AmdGetDxcModuleHandle() +@ stub GetSettingsBlobsAll +@ stub OpenAdapter12 +@ stub OpenShimInterface diff --git a/dlls/amdxc64/amdxc_interfaces.idl b/dlls/amdxc64/amdxc_interfaces.idl new file mode 100644 index 000000000000..0c88ec175409 --- /dev/null +++ b/dlls/amdxc64/amdxc_interfaces.idl @@ -0,0 +1,63 @@ +/* + * Copyright 2025 Etaash Mathamsetty + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#pragma makedep register + +import "wtypes.idl"; +import "unknwn.idl"; + +[ + object, + uuid(b58d6601-7401-4234-8180-6febfc0e484c), + local +] +interface IAmdExtFfxApi : IUnknown +{ + HRESULT UpdateFfxApiProvider([in, out] void* pData, [in] unsigned int dataSizeInBytes); +} + +[ + object, + uuid(44085fbe-e839-40c5-bf38-0ebc5ab4d0a6), + local +] +interface IAmdExtAntiLagApi : IUnknown +{ + HRESULT UpdateAntiLagState([in, out] void* pData); +} + +[ + object, + uuid(014937ec-9288-446f-a9ac-d75a8e3a984f), + local +] +interface IAmdExtStub1 : IUnknown +{ + HRESULT QueryInterface2([in, out] void* unk, [in] REFIID iid, [in, out] void** out); +} + +[ + object, + uuid(ba019d53-ccab-4cbd-b56a-7230ed4330ad), + local +] +interface IAmdExtStub2 : IUnknown +{ + void stub(); + void stub2([in] unsigned int unk); + void stub3(); +} diff --git a/dlls/amdxc64/main.c b/dlls/amdxc64/main.c new file mode 100644 index 000000000000..b4eb97f34a99 --- /dev/null +++ b/dlls/amdxc64/main.c @@ -0,0 +1,253 @@ +/* + * amdxc implementation + * + * Copyright 2023 Etaash Mathamsetty + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "ntstatus.h" +#include "winerror.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "wine/debug.h" +#include "wine/heap.h" + +#define COBJMACROS +#include "initguid.h" +#include "d3d12.h" + +#include "amdxc_interfaces.h" + +WINE_DEFAULT_DEBUG_CHANNEL(amdxc); + +struct AMDFSR4FFX +{ + IAmdExtFfxApi IAmdExtFfxApi_iface; + LONG ref; +}; + +static struct AMDFSR4FFX* impl_from_IAmdExtFfxApi(IAmdExtFfxApi* iface) +{ + return CONTAINING_RECORD(iface, struct AMDFSR4FFX, IAmdExtFfxApi_iface); +} + +ULONG STDMETHODCALLTYPE AMDFSR4FFX_AddRef(IAmdExtFfxApi *iface) +{ + struct AMDFSR4FFX* data = impl_from_IAmdExtFfxApi(iface); + return InterlockedIncrement(&data->ref); +} + +ULONG STDMETHODCALLTYPE AMDFSR4FFX_Release(IAmdExtFfxApi *iface) +{ + struct AMDFSR4FFX* data = impl_from_IAmdExtFfxApi(iface); + ULONG ret = InterlockedDecrement(&data->ref); + if (!ret) free(data); + return ret; +} + +HRESULT STDMETHODCALLTYPE AMDFSR4FFX_QueryInterface(IAmdExtFfxApi *iface, REFIID iid, void **obj) +{ + FIXME("%p %s %p", iface, debugstr_guid(iid), obj); + + return E_NOINTERFACE; +} + +typedef HRESULT (__stdcall *updateffxapi_pfn)(void*, unsigned int); + +HRESULT STDMETHODCALLTYPE AMDFSR4FFX_UpdateFfxApiProvider(IAmdExtFfxApi *iface, void* data, unsigned int size) +{ + static int once; + const char *env; + updateffxapi_pfn pfn; + HMODULE amdffx; + + TRACE("%p %p %u\n", iface, data, size); + + env = getenv("FSR4_UPGRADE"); + + if (env && !strcmp(env, "1")) + { + amdffx = LoadLibraryA("amdxcffx64"); + if (!amdffx) + { + ERR("Failed to load FSR4 dll (amdxcffx)!\n"); + return E_NOINTERFACE; + } + + pfn = (updateffxapi_pfn)GetProcAddress(amdffx, "UpdateFfxApiProvider"); + + if (pfn) + { + if (!once++) WARN("Replaced FSR3 with FSR4!\n"); + return pfn(data, size); + } + } + + return E_NOINTERFACE; +} + +static const struct IAmdExtFfxApiVtbl AMDFSR4FFX_vtable = { + AMDFSR4FFX_QueryInterface, + AMDFSR4FFX_AddRef, + AMDFSR4FFX_Release, + AMDFSR4FFX_UpdateFfxApiProvider +}; + +struct AMDExtStub2 +{ + IAmdExtStub2 IAmdExtStub2_iface; + LONG ref; +}; + +struct AMDExtStub2* impl_from_IAMDExtStub2(IAmdExtStub2 *iface) +{ + return CONTAINING_RECORD(iface, struct AMDExtStub2, IAmdExtStub2_iface); +} + +ULONG STDMETHODCALLTYPE AMDExtStub2_AddRef(IAmdExtStub2 *iface) +{ + struct AMDExtStub2 *this = impl_from_IAMDExtStub2(iface); + return InterlockedIncrement(&this->ref); +} + +ULONG STDMETHODCALLTYPE AMDExtStub2_Release(IAmdExtStub2 *iface) +{ + struct AMDExtStub2 *this = impl_from_IAMDExtStub2(iface); + ULONG ret = InterlockedDecrement(&this->ref); + if (!ret) free(this); + return ret; +} + +HRESULT STDMETHODCALLTYPE AMDExtStub2_QueryInterface(IAmdExtStub2 *iface, REFIID iid, void **out) +{ + FIXME("%p %s %p stub!\n", iface, debugstr_guid(iid), out); + return E_NOINTERFACE; +} + +void STDMETHODCALLTYPE AMDExtStub2_stub1(IAmdExtStub2 *iface) +{ + FIXME("%p stub!\n", iface); +} + +void STDMETHODCALLTYPE AMDExtStub2_stub2(IAmdExtStub2 *iface, unsigned int unk) +{ + FIXME("%p %u stub!\n", iface, unk); +} + +void STDMETHODCALLTYPE AMDExtStub2_stub3(IAmdExtStub2 *iface) +{ + FIXME("%p stub!\n", iface); +} + +const static struct IAmdExtStub2Vtbl AMDSTUB2_vtable = { + AMDExtStub2_QueryInterface, + AMDExtStub2_AddRef, + AMDExtStub2_Release, + AMDExtStub2_stub1, + AMDExtStub2_stub2, + AMDExtStub2_stub3 +}; + +struct AMDExtStub1 +{ + IAmdExtStub1 IAmdExtStub1_iface; + LONG ref; +}; + +struct AMDExtStub1* impl_from_IAMDExtStub1(IAmdExtStub1 *iface) +{ + return CONTAINING_RECORD(iface, struct AMDExtStub1, IAmdExtStub1_iface); +} + +ULONG STDMETHODCALLTYPE AMDExtStub1_AddRef(IAmdExtStub1 *iface) +{ + struct AMDExtStub1 *this = impl_from_IAMDExtStub1(iface); + return InterlockedIncrement(&this->ref); +} + +ULONG STDMETHODCALLTYPE AMDExtStub1_Release(IAmdExtStub1 *iface) +{ + struct AMDExtStub1 *this = impl_from_IAMDExtStub1(iface); + ULONG ret = InterlockedDecrement(&this->ref); + if (!ret) free(this); + return ret; +} + +HRESULT STDMETHODCALLTYPE AmdExtStub1_QueryInterface2(IAmdExtStub1 *iface, void* unk, REFIID iid, void **out) +{ + TRACE("%p %p %s %p\n", iface, unk, debugstr_guid(iid), out); + + if(IsEqualGUID(iid, &IID_IAmdExtStub2)) + { + struct AMDExtStub2 *this = calloc(1, sizeof(struct AMDExtStub2)); + + this->IAmdExtStub2_iface.lpVtbl = &AMDSTUB2_vtable; + this->ref = 1; + *out = &this->IAmdExtStub2_iface; + return S_OK; + } else { + FIXME("unknown guid %s\n", debugstr_guid(iid)); + } + + return E_NOINTERFACE; +} + +HRESULT STDMETHODCALLTYPE AmdExtStub1_QueryInterface(IAmdExtStub1 *iface, REFIID iid, void **out) +{ + return AmdExtStub1_QueryInterface2(iface, NULL, iid, out); +} + +static const struct IAmdExtStub1Vtbl AMDSTUB1_vtable = { + AmdExtStub1_QueryInterface, + AMDExtStub1_AddRef, + AMDExtStub1_Release, + AmdExtStub1_QueryInterface2 +}; + +HRESULT CDECL AmdExtD3DCreateInterface(IUnknown *outer, REFIID iid, void **obj) +{ + TRACE("outer %p, iid %s, obj %p\n", outer, debugstr_guid(iid), obj); + + if (IsEqualGUID(iid, &IID_IAmdExtFfxApi)) + { + struct AMDFSR4FFX* ffx = calloc(1, sizeof(struct AMDFSR4FFX)); + ffx->IAmdExtFfxApi_iface.lpVtbl = &AMDFSR4FFX_vtable; + ffx->ref = 1; + *obj = &ffx->IAmdExtFfxApi_iface; + return S_OK; + } else if (IsEqualGUID(iid, &IID_IAmdExtAntiLagApi)) { + return ID3D12Device_QueryInterface((ID3D12Device *)outer, &IID_IAmdExtAntiLagApi, obj); + } else if(IsEqualGUID(iid, &IID_IAmdExtStub1)) { + struct AMDExtStub1 *this = calloc(1, sizeof(struct AMDExtStub1)); + this->IAmdExtStub1_iface.lpVtbl = &AMDSTUB1_vtable; + this->ref = 1; + *obj = &this->IAmdExtStub1_iface; + return S_OK; + } else { + FIXME("unknown guid: %s\n", debugstr_guid(iid)); + } + + return E_NOINTERFACE; +} + +HMODULE WINAPI AmdGetDxcModuleHandle(void) +{ + return GetModuleHandleA(NULL); +} diff --git a/dlls/apisetschema/apisetschema.spec b/dlls/apisetschema/apisetschema.spec index c46918b6fa83..1f40225a9f1e 100644 --- a/dlls/apisetschema/apisetschema.spec +++ b/dlls/apisetschema/apisetschema.spec @@ -1,5 +1,6 @@ apiset api-ms-win-appmodel-runtime-internal-l1-1-1 = kernelbase.dll apiset api-ms-win-appmodel-runtime-l1-1-2 = kernelbase.dll +apiset api-ms-win-audiocore-spatial-config-l1-1-0 = windows.media.devices.dll apiset api-ms-win-base-bootconfig-l1-1-0 = advapi32.dll apiset api-ms-win-base-util-l1-1-0 = advapi32.dll apiset api-ms-win-core-apiquery-l1-1-0 = ntdll.dll @@ -8,6 +9,9 @@ apiset api-ms-win-core-appcompat-l1-1-1 = kernelbase.dll apiset api-ms-win-core-appinit-l1-1-0 = kernel32.dll apiset api-ms-win-core-atoms-l1-1-0 = kernel32.dll apiset api-ms-win-core-backgroundtask-l1-1-0 = kernelbase.dll +apiset api-ms-win-core-biplmapi-l1-1-5 = twinapi.appcore.dll +apiset api-ms-win-core-biplmapi-l1-2-0 = twinapi.appcore.dll +apiset api-ms-win-core-biptcltapi-l1-1-7 = twinapi.appcore.dll apiset api-ms-win-core-calendar-l1-1-0 = kernel32.dll apiset api-ms-win-core-com-l1-1-1 = combase.dll apiset api-ms-win-core-com-l2-1-1 = coml2.dll @@ -16,6 +20,7 @@ apiset api-ms-win-core-com-private-l1-1-0 = combase.dll apiset api-ms-win-core-com-private-l1-2-0 = combase.dll apiset api-ms-win-core-com-private-l1-3-0 = combase.dll apiset api-ms-win-core-comm-l1-1-0 = kernelbase.dll +apiset api-ms-win-core-commandlinetoargv-l1-1-0 = kernelbase.dll apiset api-ms-win-core-console-ansi-l2-1-0 = kernel32.dll apiset api-ms-win-core-console-internal-l1-1-0 = kernelbase.dll apiset api-ms-win-core-console-l1-1-0 = kernelbase.dll @@ -36,6 +41,7 @@ apiset api-ms-win-core-fibers-l1-1-1 = kernelbase.dll apiset api-ms-win-core-fibers-l2-1-1 = kernelbase.dll apiset api-ms-win-core-file-ansi-l1-1-0 = kernel32.dll apiset api-ms-win-core-file-ansi-l2-1-0 = kernel32.dll +apiset api-ms-win-core-file-fromapp-l1-1-0 = kernelbase.dll apiset api-ms-win-core-file-l1-1-0 = kernelbase.dll apiset api-ms-win-core-file-l1-2-2 = kernelbase.dll apiset api-ms-win-core-file-l2-1-2 = kernelbase.dll @@ -101,8 +107,14 @@ apiset api-ms-win-core-psapi-ansi-l1-1-0 = kernelbase.dll apiset api-ms-win-core-psapi-l1-1-0 = kernelbase.dll apiset api-ms-win-core-psapi-obsolete-l1-1-0 = kernelbase.dll apiset api-ms-win-core-psapiansi-l1-1-0 = kernelbase.dll +apiset api-ms-win-core-psm-app-l1-1-0 = twinapi.appcore.dll apiset api-ms-win-core-psm-appnotify-l1-1-0 = twinapi.appcore.dll apiset api-ms-win-core-psm-key-l1-1-1 = kernelbase.dll +apiset api-ms-win-core-psm-plm-l1-1-3 = twinapi.appcore.dll +apiset api-ms-win-core-psm-plm-l1-2-0 = twinapi.appcore.dll +apiset api-ms-win-core-psm-plm-l1-3-0 = twinapi.appcore.dll +apiset api-ms-win-core-psm-rtimer-l1-1-1 = twinapi.appcore.dll +apiset api-ms-win-core-psm-tc-l1-1-1 = twinapi.appcore.dll apiset api-ms-win-core-quirks-l1-1-0 = kernelbase.dll apiset api-ms-win-core-realtime-l1-1-0 = kernelbase.dll apiset api-ms-win-core-registry-l1-1-0 = kernelbase.dll @@ -209,6 +221,7 @@ apiset api-ms-win-gaming-deviceinformation-l1-1-0 = kernelbase.dll apiset api-ms-win-gaming-tcui-l1-1-0 = gamingtcui.dll apiset api-ms-win-gdi-dpiinfo-l1-1-0 = gdi32.dll apiset api-ms-win-http-time-l1-1-0 = kernelbase.dll +apiset api-ms-win-input-ie-interactioncontext-l1-1-0 = apiset api-ms-win-legacy-shlwapi-l1-1-0 = kernelbase.dll apiset api-ms-win-mm-joystick-l1-1-0 = winmm.dll apiset api-ms-win-mm-mci-l1-1-0 = winmm.dll @@ -233,6 +246,8 @@ apiset api-ms-win-power-base-l1-1-0 = powrprof.dll apiset api-ms-win-power-limitsmanagement-l1-1-0 = powrprof.dll apiset api-ms-win-power-setting-l1-1-0 = powrprof.dll apiset api-ms-win-ro-typeresolution-l1-1-1 = wintypes.dll +apiset api-ms-win-rtcore-minuser-private-l1-1-1 = +apiset api-ms-win-rtcore-navigation-l1-1-0 = apiset api-ms-win-rtcore-ntuser-clipboard-l1-1-0 = user32.dll apiset api-ms-win-rtcore-ntuser-draw-l1-1-0 = user32.dll apiset api-ms-win-rtcore-ntuser-powermanagement-l1-1-0 = user32.dll @@ -244,6 +259,7 @@ apiset api-ms-win-rtcore-ntuser-winevent-l1-1-0 = user32.dll apiset api-ms-win-rtcore-ntuser-wmpointer-l1-1-0 = user32.dll apiset api-ms-win-rtcore-ntuser-wmpointer-l1-2-0 = user32.dll apiset api-ms-win-rtcore-ole32-clipboard-l1-1-0 = ole32.dll +apiset api-ms-win-rtcore-session-l1-1-0 = apiset api-ms-win-security-accesshlpr-l1-1-0 = sechost.dll apiset api-ms-win-security-activedirectoryclient-l1-1-0 = ntdsapi.dll apiset api-ms-win-security-appcontainer-l1-1-0 = kernelbase.dll @@ -296,14 +312,35 @@ apiset api-ms-win-shcore-sysinfo-l1-1-0 = shcore.dll apiset api-ms-win-shcore-taskpool-l1-1-0 = shcore.dll apiset api-ms-win-shcore-thread-l1-1-0 = shcore.dll apiset api-ms-win-shcore-unicodeansi-l1-1-0 = shcore.dll +apiset api-ms-win-shell-associations-l1-1-3 = windows.storage.dll +apiset api-ms-win-shell-changenotify-l1-1-1 = windows.storage.dll +apiset api-ms-win-shell-dataobject-l1-1-1 = windows.storage.dll +apiset api-ms-win-shell-namespace-l1-1-1 = windows.storage.dll apiset api-ms-win-shell-shdirectory-l1-1-0 = shcore.dll +apiset api-ms-win-shell-shell32legacy-shdirectory-l1-1-0 = apiset api-ms-win-shell-shellcom-l1-1-0 = shell32.dll -apiset api-ms-win-shell-shellfolders-l1-1-0 = shell32.dll +apiset api-ms-win-shell-shellfolders-l1-1-0 = windows.storage.dll apiset api-ms-win-shlwapi-ie-l1-1-0 = shlwapi.dll apiset api-ms-win-shlwapi-winrt-storage-l1-1-1 = shlwapi.dll apiset api-ms-win-stateseparation-helpers-l1-1-0 = kernelbase.dll +apiset api-ms-win-storage-exports-external-l1-1-2 = windows.storage.dll +apiset api-ms-win-storage-exports-internal-l1-1-0 = windows.storage.dll +apiset ext-ms-mf-pal-l2-1-1 = +apiset ext-ms-onecore-appchromeapi-l1-1-0 = +apiset ext-ms-onecore-appdefaults-l1-1-0 = windows.storage.dll +apiset ext-ms-onecore-appmodel-deployment-internal-l1-1-0 = appxdeploymentclient.dll +apiset ext-ms-onecore-appmodel-emclient-l1-1-0 = +apiset ext-ms-onecore-appmodel-emsvcs-l1-1-0 = +apiset ext-ms-onecore-appmodel-pacmanclient-l1-1-0 = +apiset ext-ms-onecore-comp-dwmmonitor-l1-1-0 = apiset ext-ms-onecore-dcomp-l1-1-0 = dcomp.dll +apiset ext-ms-onecore-defaultdiscovery-l1-1-0 = +apiset ext-ms-onecore-hcap-svf-l1-1-0 = apiset ext-ms-onecore-hlink-l1-1-0 = hlink.dll +apiset ext-ms-onecore-mpc-input-l1-1-0 = +apiset ext-ms-onecore-orientation-l1-1-0 = +apiset ext-ms-onecore-shellchromeapi-l1-1-2 = +apiset ext-ms-onecore-shellremindersapi-l1-1-0 = apiset ext-ms-onecore-shlwapi-l1-1-0 = shlwapi.dll apiset ext-ms-win-adsi-activeds-l1-1-0 = activeds.dll apiset ext-ms-win-advapi32-auth-l1-1-0 = advapi32.dll @@ -317,11 +354,23 @@ apiset ext-ms-win-advapi32-lsa-l1-1-0 = advapi32.dll apiset ext-ms-win-advapi32-msi-l1-1-0 = advapi32.dll apiset ext-ms-win-advapi32-npusername-l1-1-0 = advapi32.dll apiset ext-ms-win-advapi32-ntmarta-l1-1-0 = advapi32.dll +apiset ext-ms-win-advapi32-psm-app-l1-1-0 = twinapi.appcore.dll apiset ext-ms-win-advapi32-registry-l1-1-0 = advapi32.dll apiset ext-ms-win-advapi32-safer-l1-1-0 = advapi32.dll apiset ext-ms-win-advapi32-shutdown-l1-1-0 = advapi32.dll apiset ext-ms-win-appcompat-apphelp-l1-1-2 = apphelp.dll +apiset ext-ms-win-appmodel-appcontainerpath-l1-1-0 = +apiset ext-ms-win-appmodel-datasharingservice-extensions-l1-1-0 = +apiset ext-ms-win-appmodel-deployment-l1-1-1 = +apiset ext-ms-win-appmodel-deploymentvolumes-l1-1-1 = apiset ext-ms-win-appmodel-opc-l1-1-0 = opcservices.dll +apiset ext-ms-win-appmodel-shellexecute-l1-1-0 = windows.storage.dll +apiset ext-ms-win-appmodel-usercontext-l1-1-0 = +apiset ext-ms-win-appmodel-viewscalefactor-l1-1-0 = +apiset ext-ms-win-audio-spatial-systemsound-l1-1-0 = +apiset ext-ms-win-audiocore-pal-l1-2-0 = +apiset ext-ms-win-audiocore-policymanager-l1-1-1 = +apiset ext-ms-win-audiocore-spatial-l1-1-0 = apiset ext-ms-win-authz-claimpolicies-l1-1-0 = authz.dll apiset ext-ms-win-authz-context-l1-1-0 = authz.dll apiset ext-ms-win-base-psapi-l1-1-0 = psapi.dll @@ -329,16 +378,38 @@ apiset ext-ms-win-base-rstrtmgr-l1-1-0 = rstrtmgr.dll apiset ext-ms-win-bluetooth-apis-internal-l1-1-0 = bluetoothapis.dll apiset ext-ms-win-bluetooth-apis-l1-1-0 = bluetoothapis.dll apiset ext-ms-win-bluetooth-apis-private-l1-1-0 = bluetoothapis.dll +apiset ext-ms-win-casting-device-l1-1-0 = +apiset ext-ms-win-ci-xbox-l1-1-0 = +apiset ext-ms-win-cloudap-tbal-l1-1-0 = +apiset ext-ms-win-clouddomainjoin-usermanagement-l1-1-0 = apiset ext-ms-win-cluster-clusapi-l1-1-5 = clusapi.dll apiset ext-ms-win-cluster-resutils-l1-1-3 = resutils.dll +apiset ext-ms-win-cng-rng-l1-1-1 = bcryptprimitives.dll +apiset ext-ms-win-com-apartmentrestriction-l1-1-0 = +apiset ext-ms-win-com-coml2-l1-1-1 = coml2.dll apiset ext-ms-win-com-ole32-l1-1-3 = ole32.dll apiset ext-ms-win-com-ole32-l1-2-0 = ole32.dll apiset ext-ms-win-com-ole32-l1-3-0 = ole32.dll apiset ext-ms-win-com-ole32-l1-4-0 = ole32.dll apiset ext-ms-win-com-sta-l1-1-0 = ole32.dll +apiset ext-ms-win-com-suspendresiliency-l1-1-0 = +apiset ext-ms-win-composition-holographic-l1-1-0 = apiset ext-ms-win-compositor-hosting-l1-1-0 = user32.dll +apiset ext-ms-win-containers-policymanagercli-l1-1-1 = +apiset ext-ms-win-core-app-package-registration-l1-1-1 = +apiset ext-ms-win-core-app-package-volume-l1-1-0 = +apiset ext-ms-win-core-container-init-l1-1-0 = +apiset ext-ms-win-core-dhcp6client-l1-1-0 = apiset ext-ms-win-core-iuri-l1-1-0 = urlmon.dll +apiset ext-ms-win-core-licensemanager-l1-1-2 = apiset ext-ms-win-core-marshal-l2-1-0 = ole32.dll +apiset ext-ms-win-core-psm-extendedresourcemode-l1-1-0 = +apiset ext-ms-win-core-stateseparationext-l1-1-0 = +apiset ext-ms-win-core-winrt-remote-l1-1-0 = +apiset ext-ms-win-core-winsrv-min-l1-1-0 = +apiset ext-ms-win-core-xbrm-l1-1-1 = +apiset ext-ms-win-coreui-l1-1-0 = +apiset ext-ms-win-crypto-xbox-l1-1-0 = apiset ext-ms-win-drvinst-desktop-l1-1-0 = newdev.dll apiset ext-ms-win-dwmapi-ext-l1-1-0 = dwmapi.dll apiset ext-ms-win-dwmapidxgi-ext-l1-1-1 = dwmapi.dll @@ -352,14 +423,20 @@ apiset ext-ms-win-dxcore-l1-1-0 = dxcore.dll apiset ext-ms-win-eventing-pdh-l1-1-2 = pdh.dll apiset ext-ms-win-eventing-tdh-ext-l1-1-0 = tdh.dll apiset ext-ms-win-eventing-tdh-priv-l1-1-0 = tdh.dll +apiset ext-ms-win-feclient-encryptedfile-l1-1-3 = feclient.dll +apiset ext-ms-win-fs-vssapi-l1-1-0 = vssapi.dll +apiset ext-ms-win-gaming-devicefamily-l1-1-0 = apiset ext-ms-win-gaming-xinput-l1-1-0 = xinputuap.dll apiset ext-ms-win-gdi-clipping-l1-1-0 = gdi32.dll apiset ext-ms-win-gdi-dc-create-l1-1-1 = gdi32.dll apiset ext-ms-win-gdi-dc-l1-2-0 = gdi32.dll apiset ext-ms-win-gdi-devcaps-l1-1-0 = gdi32.dll apiset ext-ms-win-gdi-draw-l1-1-1 = gdi32.dll +apiset ext-ms-win-gdi-edgegdi-l1-1-0 = apiset ext-ms-win-gdi-font-l1-1-1 = gdi32.dll apiset ext-ms-win-gdi-gdiplus-l1-1-0 = gdiplus.dll +apiset ext-ms-win-gdi-internal-desktop-l1-1-4 = gdi32.dll +apiset ext-ms-win-gdi-internal-uap-init-l1-1-0 = gdi32.dll apiset ext-ms-win-gdi-metafile-l1-1-2 = gdi32.dll apiset ext-ms-win-gdi-path-l1-1-0 = gdi32.dll apiset ext-ms-win-gdi-print-l1-1-0 = gdi32.dll @@ -367,6 +444,18 @@ apiset ext-ms-win-gdi-private-l1-1-0 = gdi32.dll apiset ext-ms-win-gdi-render-l1-1-0 = gdi32.dll apiset ext-ms-win-gdi-rgn-l1-1-0 = gdi32.dll apiset ext-ms-win-gdi-wcs-l1-1-0 = gdi32.dll +apiset ext-ms-win-hcihealth-utils-l1-1-0 = +apiset ext-ms-win-hyperv-compute-l1-1-1 = +apiset ext-ms-win-hyperv-compute-l1-2-4 = +apiset ext-ms-win-hyperv-computenetwork-l1-1-1 = +apiset ext-ms-win-hyperv-computestorage-l1-1-1 = +apiset ext-ms-win-hyperv-devicevirtualization-l1-1-1 = +apiset ext-ms-win-hyperv-devicevirtualization-l1-2-2 = +apiset ext-ms-win-hyperv-hgs-l1-1-0 = +apiset ext-ms-win-hyperv-hvemulation-l1-1-0 = +apiset ext-ms-win-hyperv-hvplatform-l1-1-5 = +apiset ext-ms-win-ie-textinput-l1-1-0 = +apiset ext-ms-win-imm-l1-1-2 = imm32.dll apiset ext-ms-win-kernel32-appcompat-l1-1-0 = kernel32.dll apiset ext-ms-win-kernel32-datetime-l1-1-0 = kernel32.dll apiset ext-ms-win-kernel32-elevation-l1-1-0 = kernel32.dll @@ -383,18 +472,34 @@ apiset ext-ms-win-kernel32-transacted-l1-1-0 = kernel32.dll apiset ext-ms-win-kernel32-updateresource-l1-1-0 = kernel32.dll apiset ext-ms-win-kernel32-windowserrorreporting-l1-1-1 = kernel32.dll apiset ext-ms-win-kernelbase-processthread-l1-1-0 = kernel32.dll +apiset ext-ms-win-kernelbase-processthread-l1-2-0 = kernel32.dll +apiset ext-ms-win-kioskmode-config-l1-1-0 = apiset ext-ms-win-mapi-mapi32-l1-1-0 = mapistub.dll apiset ext-ms-win-media-avi-l1-1-0 = avifil32.dll +apiset ext-ms-win-media-codecpack-mounting-l1-1-0 = +apiset ext-ms-win-mf-devicespecific-l1-1-0 = +apiset ext-ms-win-mf-vfw-l1-1-0 = +apiset ext-ms-win-mininput-extensions-l1-1-0 = apiset ext-ms-win-mm-msacm-l1-1-0 = msacm32.dll apiset ext-ms-win-mm-pehelper-l1-1-0 = mf.dll apiset ext-ms-win-mm-wmvcore-l1-1-0 = wmvcore.dll +apiset ext-ms-win-msa-device-l1-1-0 = apiset ext-ms-win-msi-misc-l1-1-0 = msi.dll apiset ext-ms-win-msimg-draw-l1-1-0 = msimg32.dll +apiset ext-ms-win-net-vpn-l1-1-0 = +apiset ext-ms-win-networking-iphlpsvc-l1-1-0 = +apiset ext-ms-win-networking-mpssvc-l1-1-0 = +apiset ext-ms-win-networking-ncsiuserprobe-l1-1-0 = +apiset ext-ms-win-networking-teredo-l1-1-0 = windows.networking.connectivity.dll apiset ext-ms-win-networking-wlanapi-l1-1-0 = wlanapi.dll +apiset ext-ms-win-networking-wlanstorage-l1-1-0 = +apiset ext-ms-win-networking-xblconnectivity-l1-1-0 = +apiset ext-ms-win-newdev-config-l1-1-2 = newdev.dll apiset ext-ms-win-ntdsapi-activedirectoryclient-l1-1-1 = ntdsapi.dll apiset ext-ms-win-ntuser-caret-l1-1-0 = user32.dll apiset ext-ms-win-ntuser-chartranslation-l1-1-0 = user32.dll apiset ext-ms-win-ntuser-dc-access-ext-l1-1-0 = user32.dll +apiset ext-ms-win-ntuser-dde-l1-1-0 = user32.dll apiset ext-ms-win-ntuser-dialogbox-l1-1-0 = user32.dll apiset ext-ms-win-ntuser-draw-l1-1-0 = user32.dll apiset ext-ms-win-ntuser-gui-l1-1-0 = user32.dll @@ -442,29 +547,49 @@ apiset ext-ms-win-ole32-bindctx-l1-1-0 = ole32.dll apiset ext-ms-win-ole32-ie-ext-l1-1-0 = ole32.dll apiset ext-ms-win-ole32-oleautomation-l1-1-0 = ole32.dll apiset ext-ms-win-oleacc-l1-1-0 = oleacc.dll +apiset ext-ms-win-onecore-shutdown-l1-1-0 = twinapi.appcore.dll +apiset ext-ms-win-oobe-query-l1-1-0 = +apiset ext-ms-win-perception-device-l1-1-1 = apiset ext-ms-win-printer-prntvpt-l1-1-2 = prntvpt.dll apiset ext-ms-win-printer-winspool-core-l1-1-0 = winspool.drv apiset ext-ms-win-printer-winspool-l1-1-4 = winspool.drv apiset ext-ms-win-printer-winspool-l1-2-0 = winspool.drv apiset ext-ms-win-profile-extender-l1-1-0 = userenv.dll +apiset ext-ms-win-profile-load-l1-1-0 = apiset ext-ms-win-ras-rasapi32-l1-1-0 = rasapi32.dll apiset ext-ms-win-ras-rasdlg-l1-1-0 = rasdlg.dll apiset ext-ms-win-ras-tapi32-l1-1-1 = tapi32.dll +apiset ext-ms-win-remotewipe-platform-l1-1-0 = apiset ext-ms-win-ro-typeresolution-l1-1-1 = wintypes.dll +apiset ext-ms-win-rometadata-dispenser-l1-1-0 = rometadata.dll apiset ext-ms-win-rtcore-gdi-devcaps-l1-1-0 = gdi32.dll apiset ext-ms-win-rtcore-gdi-object-l1-1-0 = gdi32.dll apiset ext-ms-win-rtcore-gdi-rgn-l1-1-0 = gdi32.dll +apiset ext-ms-win-rtcore-minuser-display-l1-1-0 = +apiset ext-ms-win-rtcore-minuser-host-l1-1-0 = +apiset ext-ms-win-rtcore-minuser-input-l1-1-4 = +apiset ext-ms-win-rtcore-minuser-internal-l1-1-0 = +apiset ext-ms-win-rtcore-minuser-private-ext-l1-1-3 = apiset ext-ms-win-rtcore-ntuser-cursor-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-dc-access-l1-1-0 = user32.dll +apiset ext-ms-win-rtcore-ntuser-dialogbox-l1-1-0 = apiset ext-ms-win-rtcore-ntuser-dpi-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-dpi-l1-2-0 = user32.dll +apiset ext-ms-win-rtcore-ntuser-draw-l1-1-0 = +apiset ext-ms-win-rtcore-ntuser-gui-l1-1-1 = apiset ext-ms-win-rtcore-ntuser-iam-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-inputintercept-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-integration-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-keyboard-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-message-ansi-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-message-l1-1-0 = user32.dll +apiset ext-ms-win-rtcore-ntuser-mininit-l1-1-0 = +apiset ext-ms-win-rtcore-ntuser-misc-l1-1-0 = +apiset ext-ms-win-rtcore-ntuser-mouse-l1-1-0 = +apiset ext-ms-win-rtcore-ntuser-powermanagement-l1-1-0 = +apiset ext-ms-win-rtcore-ntuser-private-l1-1-1 = apiset ext-ms-win-rtcore-ntuser-rawinput-l1-1-0 = user32.dll +apiset ext-ms-win-rtcore-ntuser-rawinput-l1-2-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-synch-ext-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-syscolors-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-sysparams-l1-1-0 = user32.dll @@ -473,26 +598,37 @@ apiset ext-ms-win-rtcore-ntuser-window-ansi-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-window-ext-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-window-l1-1-0 = user32.dll apiset ext-ms-win-rtcore-ntuser-winevent-ext-l1-1-0 = user32.dll +apiset ext-ms-win-rtcore-ntuser-winstamin-l1-1-0 = apiset ext-ms-win-rtcore-ntuser-wmpointer-l1-1-0 = user32.dll +apiset ext-ms-win-rtcore-ntuser-wmpointermin-l1-1-0 = apiset ext-ms-win-rtcore-ole32-dragdrop-l1-1-0 = ole32.dll apiset ext-ms-win-rtcore-ole32-misc-l1-1-0 = ole32.dll +apiset ext-ms-win-rtcore-webview-l1-1-0 = apiset ext-ms-win-secur32-translatename-l1-1-0 = secur32.dll +apiset ext-ms-win-security-chambers-l1-1-1 = apiset ext-ms-win-security-credui-l1-1-0 = credui.dll +apiset ext-ms-win-security-crosscontainerauthhelper-l1-1-0 = apiset ext-ms-win-security-cryptui-l1-1-0 = cryptui.dll +apiset ext-ms-win-security-developerunlock-l1-1-0 = +apiset ext-ms-win-security-deviceid-l1-1-0 = apiset ext-ms-win-security-kerberos-l1-1-0 = kerberos.dll apiset ext-ms-win-security-slc-l1-1-0 = slc.dll +apiset ext-ms-win-security-winscard-l1-1-1 = winscard.dll apiset ext-ms-win-session-usertoken-l1-1-0 = wtsapi32.dll +apiset ext-ms-win-session-winlogon-notify-l1-1-0 = apiset ext-ms-win-session-winsta-l1-1-4 = winsta.dll apiset ext-ms-win-session-wtsapi32-l1-1-0 = wtsapi32.dll apiset ext-ms-win-setupapi-classinstallers-l1-1-2 = setupapi.dll apiset ext-ms-win-setupapi-inf-l1-1-1 = setupapi.dll apiset ext-ms-win-setupapi-logging-l1-1-0 = setupapi.dll apiset ext-ms-win-shell-aclui-l1-1-0 = aclui.dll +apiset ext-ms-win-shell-browsersettingsync-l1-1-0 = apiset ext-ms-win-shell-comctl32-da-l1-1-0 = comctl32.dll apiset ext-ms-win-shell-comctl32-init-l1-1-0 = comctl32.dll apiset ext-ms-win-shell-comctl32-l1-1-0 = comctl32.dll apiset ext-ms-win-shell-comctl32-window-l1-1-0 = comctl32.dll apiset ext-ms-win-shell-comdlg32-l1-1-0 = comdlg32.dll +apiset ext-ms-win-shell-directory-l1-1-0 = windows.storage.dll apiset ext-ms-win-shell-exports-internal-l1-1-0 = shell32.dll apiset ext-ms-win-shell-propsys-l1-1-1 = propsys.dll apiset ext-ms-win-shell-shdocvw-l1-1-0 = shdocvw.dll @@ -502,10 +638,35 @@ apiset ext-ms-win-shell-shell32-l1-4-0 = shell32.dll apiset ext-ms-win-shell-shell32-l1-5-0 = shell32.dll apiset ext-ms-win-shell-shlwapi-l1-1-1 = shlwapi.dll apiset ext-ms-win-shell-shlwapi-l1-2-0 = shlwapi.dll +apiset ext-ms-win-shell32-shellcom-l1-1-0 = windows.storage.dll +apiset ext-ms-win-shell32-shellfolders-l1-1-1 = windows.storage.dll +apiset ext-ms-win-shell32-shellfolders-l1-2-1 = windows.storage.dll +apiset ext-ms-win-storage-iscsidsc-l1-1-0 = apiset ext-ms-win-sxs-oleautomation-l1-1-0 = sxs.dll +apiset ext-ms-win-sysmain-sfltapi-l1-1-0 = +apiset ext-ms-win-system-metrics-override-l1-1-1 = +apiset ext-ms-win-test-sys1-l1-1-0 = +apiset ext-ms-win-test-sys2-l1-1-0 = apiset ext-ms-win-tsf-msctf-l1-1-4 = msctf.dll +apiset ext-ms-win-ui-viewmanagement-l1-1-0 = apiset ext-ms-win-uiacore-l1-1-3 = uiautomationcore.dll apiset ext-ms-win-usp10-l1-1-0 = gdi32.dll apiset ext-ms-win-uxtheme-themes-l1-1-0 = uxtheme.dll +apiset ext-ms-win-wer-reporting-l1-1-3 = wer.dll +apiset ext-ms-win-wer-wct-l1-1-0 = wer.dll +apiset ext-ms-win-wer-xbox-l1-1-4 = apiset ext-ms-win-wevtapi-eventlog-l1-1-3 = wevtapi.dll +apiset ext-ms-win-windowing-external-l1-1-0 = windows.ui.dll +apiset ext-ms-win-windowing-internal-l1-1-0 = +apiset ext-ms-win-winlogon-mincreds-l1-1-0 = +apiset ext-ms-win-winrt-storage-l1-1-0 = windows.storage.dll +apiset ext-ms-win-winrt-storage-l1-2-3 = windows.storage.dll apiset ext-ms-win-wlan-scard-l1-1-0 = winscard.dll +apiset ext-ms-win-wpn-phoneext-l1-1-0 = +apiset ext-ms-win-wrp-sfc-l1-1-0 = sfc.dll +apiset ext-ms-win-xaml-pal-l1-1-0 = +apiset ext-ms-win-xaudio-platform-l1-1-0 = +apiset ext-ms-win-xblauth-console-l1-1-0 = +apiset ext-ms-win-xboxlive-xboxnetapisvc-l1-1-0 = +apiset ext-ms-win32-subsystem-query-l1-1-0 = +apiset ext-ms-windowscore-deviceinfo-l1-1-0 = diff --git a/dlls/appwiz.cpl/addons.c b/dlls/appwiz.cpl/addons.c index 7b2c43472ff1..720429bcf993 100644 --- a/dlls/appwiz.cpl/addons.c +++ b/dlls/appwiz.cpl/addons.c @@ -48,7 +48,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl); #ifdef __i386__ #define GECKO_ARCH "x86" #define GECKO_SHA "26cecc47706b091908f7f814bddb074c61beb8063318e9efc5a7f789857793d6" -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__aarch64__) #define GECKO_ARCH "x86_64" #define GECKO_SHA "e590b7d988a32d6aa4cf1d8aa3aa3d33766fdd4cf4c89c2dcc2095ecb28d066f" #else @@ -56,10 +56,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl); #define GECKO_SHA "???" #endif -#define MONO_VERSION "9.4.0" -#if defined(__i386__) || defined(__x86_64__) +#define MONO_VERSION "10.4.1" +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) #define MONO_ARCH "x86" -#define MONO_SHA "cf6173ae94b79e9de13d9a74cdb2560a886fc3d271f9489acb1cfdbd961cacb2" +#define MONO_SHA "071f4b2887e1c97a11d791ff3d65be9429eed6dec4c2708888bfd546ba358e23" #else #define MONO_ARCH "" #define MONO_SHA "???" diff --git a/dlls/atiadlxx/Makefile.in b/dlls/atiadlxx/Makefile.in new file mode 100644 index 000000000000..85cda94c29d9 --- /dev/null +++ b/dlls/atiadlxx/Makefile.in @@ -0,0 +1,8 @@ +EXTRADEFS = -DWINE_NO_LONG_TYPES +MODULE = atiadlxx.dll +IMPORTS = user32 dxgi cfgmgr32 + +EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native + +SOURCES = \ + atiadlxx_main.c diff --git a/dlls/atiadlxx/atiadlxx.spec b/dlls/atiadlxx/atiadlxx.spec new file mode 100644 index 000000000000..532473b0d5a7 --- /dev/null +++ b/dlls/atiadlxx/atiadlxx.spec @@ -0,0 +1,1138 @@ +@ stub ADL2_ADC_CurrentProfileFromDrv_Get +@ stub ADL2_ADC_Display_AdapterDeviceProfileEx_Get +@ stub ADL2_ADC_DrvDataToProfile_Copy +@ stub ADL2_ADC_FindClosestMode_Get +@ stub ADL2_ADC_IsDevModeEqual_Get +@ stub ADL2_ADC_Profile_Apply +@ stub ADL2_APO_AudioDelayAdjustmentInfo_Get +@ stub ADL2_APO_AudioDelay_Restore +@ stub ADL2_APO_AudioDelay_Set +@ stub ADL2_AdapterLimitation_Caps +@ stub ADL2_AdapterX2_Caps +@ stub ADL2_Adapter_AMDAndNonAMDDIsplayClone_Get +@ cdecl ADL2_Adapter_ASICFamilyType_Get(ptr long ptr ptr) +@ stub ADL2_Adapter_ASICInfo_Get +@ stub ADL2_Adapter_Accessibility_Get +@ stub ADL2_Adapter_AceDefaults_Restore +@ cdecl ADL2_Adapter_Active_Get(ptr long ptr) +@ stub ADL2_Adapter_Active_Set +@ stub ADL2_Adapter_Active_SetPrefer +@ cdecl ADL2_Adapter_AdapterInfoX2_Get(ptr ptr) +@ stub ADL2_Adapter_AdapterInfoX3_Get +@ stub ADL2_Adapter_AdapterInfoX4_Get +@ stub ADL2_Adapter_AdapterInfo_Get +@ stub ADL2_Adapter_AdapterList_Disable +@ stub ADL2_Adapter_AdapterLocationPath_Get +@ stub ADL2_Adapter_Aspects_Get +@ stub ADL2_Adapter_AudioChannelSplitConfiguration_Get +@ stub ADL2_Adapter_AudioChannelSplit_Disable +@ stub ADL2_Adapter_AudioChannelSplit_Enable +@ stub ADL2_Adapter_BigSw_Info_Get +@ stub ADL2_Adapter_BlackAndWhiteLevelSupport_Get +@ stub ADL2_Adapter_BlackAndWhiteLevel_Get +@ stub ADL2_Adapter_BlackAndWhiteLevel_Set +@ stub ADL2_Adapter_BoardLayout_Get +@ stub ADL2_Adapter_Caps +@ stub ADL2_Adapter_ChipSetInfo_Get +@ stub ADL2_Adapter_CloneTypes_Get +@ stub ADL2_Adapter_ConfigMemory_Cap +@ stub ADL2_Adapter_ConfigMemory_Get +@ stub ADL2_Adapter_ConfigureState_Get +@ stub ADL2_Adapter_ConnectionData_Get +@ stub ADL2_Adapter_ConnectionData_Remove +@ stub ADL2_Adapter_ConnectionData_Set +@ stub ADL2_Adapter_ConnectionState_Get +@ stub ADL2_Adapter_CrossDisplayPlatformInfo_Get +@ stub ADL2_Adapter_CrossGPUClone_Disable +@ stub ADL2_Adapter_CrossdisplayAdapterRole_Caps +@ stub ADL2_Adapter_CrossdisplayInfoX2_Set +@ stub ADL2_Adapter_CrossdisplayInfo_Get +@ stub ADL2_Adapter_CrossdisplayInfo_Set +@ stub ADL2_Adapter_CrossfireX2_Get +@ cdecl ADL2_Adapter_Crossfire_Caps(ptr long ptr ptr ptr) +@ stub ADL2_Adapter_Crossfire_Get +@ stub ADL2_Adapter_Crossfire_Set +@ stub ADL2_Adapter_DefaultAudioChannelTable_Load +@ stub ADL2_Adapter_Desktop_Caps +@ stub ADL2_Adapter_Desktop_SupportedSLSGridTypes_Get +@ stub ADL2_Adapter_DeviceID_Get +@ stub ADL2_Adapter_DisplayAudioEndpoint_Enable +@ stub ADL2_Adapter_DisplayAudioEndpoint_Mute +@ stub ADL2_Adapter_DisplayAudioInfo_Get +@ stub ADL2_Adapter_DisplayGTCCaps_Get +@ stub ADL2_Adapter_Display_Caps +@ stub ADL2_Adapter_DriverSettings_Get +@ stub ADL2_Adapter_DriverSettings_Set +@ stub ADL2_Adapter_ECC_ErrorInjection_Set +@ stub ADL2_Adapter_ECC_ErrorRecords_Get +@ stub ADL2_Adapter_EDC_ErrorInjection_Set +@ stub ADL2_Adapter_EDC_ErrorRecords_Get +@ stub ADL2_Adapter_EDIDManagement_Caps +@ stub ADL2_Adapter_EmulationMode_Set +@ stub ADL2_Adapter_ExtInfo_Get +@ stub ADL2_Adapter_Feature_Caps +@ stub ADL2_Adapter_FrameMetrics_Caps +@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Disable +@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Enable +@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Get +@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Start +@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Stop +@ stub ADL2_Adapter_FrameMetrics_Get +@ stub ADL2_Adapter_FrameMetrics_Start +@ stub ADL2_Adapter_FrameMetrics_Stop +@ stub ADL2_Adapter_Gamma_Get +@ stub ADL2_Adapter_Gamma_Set +@ cdecl ADL2_Adapter_Graphic_Core_Info_Get(ptr long ptr) +@ stub ADL2_Adapter_HBC_Caps +@ stub ADL2_Adapter_HBM_ECC_UC_Check +@ stub ADL2_Adapter_Headless_Get +@ stub ADL2_Adapter_ID_Get +@ stub ADL2_Adapter_IsGamingDriver_Info_Get +@ stub ADL2_Adapter_LocalDisplayConfig_Get +@ stub ADL2_Adapter_LocalDisplayConfig_Set +@ stub ADL2_Adapter_LocalDisplayState_Get +@ stub ADL2_Adapter_MVPU_Set +@ stub ADL2_Adapter_MaxCursorSize_Get +@ stub ADL2_Adapter_MemoryInfo2_Get +@ cdecl ADL2_Adapter_MemoryInfo_Get(ptr long ptr) +@ stub ADL2_Adapter_MirabilisSupport_Get +@ stub ADL2_Adapter_ModeSwitch +@ stub ADL2_Adapter_ModeTimingOverride_Caps +@ stub ADL2_Adapter_Modes_ReEnumerate +@ stub ADL2_Adapter_NumberOfActivatableSources_Get +@ cdecl ADL2_Adapter_NumberOfAdapters_Get(ptr ptr) +@ cdecl ADL2_Adapter_ObservedClockInfo_Get(ptr long ptr ptr) +@ stub ADL2_Adapter_PMLog_Start +@ stub ADL2_Adapter_PMLog_Stop +@ stub ADL2_Adapter_PMLog_Support_Get +@ stub ADL2_Adapter_PreFlipPostProcessing_Disable +@ stub ADL2_Adapter_PreFlipPostProcessing_Enable +@ stub ADL2_Adapter_PreFlipPostProcessing_Get_Status +@ stub ADL2_Adapter_PreFlipPostProcessing_Select_LUT_Algorithm +@ stub ADL2_Adapter_PreFlipPostProcessing_Select_LUT_Buffer +@ stub ADL2_Adapter_PreFlipPostProcessing_Unselect_LUT_Buffer +@ stub ADL2_Adapter_Primary_Get +@ stub ADL2_Adapter_Primary_Set +@ stub ADL2_Adapter_RAS_ErrorInjection_Set +@ stub ADL2_Adapter_RegValueInt_Get +@ stub ADL2_Adapter_RegValueInt_Set +@ stub ADL2_Adapter_RegValueString_Get +@ stub ADL2_Adapter_RegValueString_Set +@ stub ADL2_Adapter_SWInfo_Get +@ stub ADL2_Adapter_Speed_Caps +@ stub ADL2_Adapter_Speed_Get +@ stub ADL2_Adapter_Speed_Set +@ stub ADL2_Adapter_SupportedConnections_Get +@ stub ADL2_Adapter_TRNG_Get +@ stub ADL2_Adapter_Tear_Free_Cap +@ stub ADL2_Adapter_VRAMUsage_Get +@ stub ADL2_Adapter_VariBrightEnable_Set +@ stub ADL2_Adapter_VariBrightLevel_Get +@ stub ADL2_Adapter_VariBrightLevel_Set +@ stub ADL2_Adapter_VariBright_Caps +@ stub ADL2_Adapter_VerndorID_Int_get +@ stub ADL2_Adapter_VideoBiosInfo_Get +@ stub ADL2_Adapter_VideoTheaterModeInfo_Get +@ stub ADL2_Adapter_VideoTheaterModeInfo_Set +@ stub ADL2_Adapter_XConnectSupport_Get +@ stub ADL2_ApplicationProfilesX2_AppInterceptionList_Set +@ stub ADL2_ApplicationProfilesX2_AppStartStopInfo_Get +@ stub ADL2_ApplicationProfiles_AppInterceptionList_Set +@ stub ADL2_ApplicationProfiles_AppInterception_Set +@ stub ADL2_ApplicationProfiles_AppStartStopInfo_Get +@ stub ADL2_ApplicationProfiles_AppStartStop_Resume +@ stub ADL2_ApplicationProfiles_Applications_Get +@ stub ADL2_ApplicationProfiles_ConvertToCompact +@ stub ADL2_ApplicationProfiles_DriverAreaPrivacy_Get +@ stub ADL2_ApplicationProfiles_GetCustomization +@ stub ADL2_ApplicationProfiles_HitListsX2_Get +@ stub ADL2_ApplicationProfiles_HitListsX3_Get +@ stub ADL2_ApplicationProfiles_HitLists_Get +@ stub ADL2_ApplicationProfiles_ProfileApplicationX2_Assign +@ stub ADL2_ApplicationProfiles_ProfileApplication_Assign +@ stub ADL2_ApplicationProfiles_ProfileOfAnApplicationX2_Search +@ stub ADL2_ApplicationProfiles_ProfileOfAnApplication_InMemorySearch +@ stub ADL2_ApplicationProfiles_ProfileOfAnApplication_Search +@ stub ADL2_ApplicationProfiles_Profile_Create +@ stub ADL2_ApplicationProfiles_Profile_Exist +@ stub ADL2_ApplicationProfiles_Profile_Remove +@ stub ADL2_ApplicationProfiles_PropertyType_Get +@ stub ADL2_ApplicationProfiles_Release_Get +@ stub ADL2_ApplicationProfiles_RemoveApplication +@ stub ADL2_ApplicationProfiles_StatusInfo_Get +@ stub ADL2_ApplicationProfiles_System_Reload +@ stub ADL2_ApplicationProfiles_User_Load +@ stub ADL2_ApplicationProfiles_User_Unload +@ stub ADL2_Audio_CurrentSampleRate_Get +@ stub ADL2_AutoTuningResult_Get +@ stub ADL2_BOOST_Settings_Get +@ stub ADL2_BOOST_Settings_Set +@ stub ADL2_Blockchain_BlockchainMode_Caps +@ stub ADL2_Blockchain_BlockchainMode_Get +@ stub ADL2_Blockchain_BlockchainMode_Set +@ stub ADL2_Blockchain_Hashrate_Set +@ stub ADL2_CDS_UnsafeMode_Set +@ stub ADL2_CHILL_SettingsX2_Get +@ stub ADL2_CHILL_SettingsX2_Set +@ stub ADL2_CV_DongleSettings_Get +@ stub ADL2_CV_DongleSettings_Reset +@ stub ADL2_CV_DongleSettings_Set +@ stub ADL2_Chill_Caps_Get +@ stub ADL2_Chill_Settings_Get +@ stub ADL2_Chill_Settings_Notify +@ stub ADL2_Chill_Settings_Set +@ stub ADL2_CustomFan_Caps +@ stub ADL2_CustomFan_Get +@ stub ADL2_CustomFan_Set +@ stub ADL2_DELAG_Settings_Get +@ stub ADL2_DELAG_Settings_Set +@ stub ADL2_DFP_AllowOnlyCETimings_Get +@ stub ADL2_DFP_AllowOnlyCETimings_Set +@ stub ADL2_DFP_BaseAudioSupport_Get +@ stub ADL2_DFP_GPUScalingEnable_Get +@ stub ADL2_DFP_GPUScalingEnable_Set +@ stub ADL2_DFP_HDMISupport_Get +@ stub ADL2_DFP_MVPUAnalogSupport_Get +@ stub ADL2_DFP_PixelFormat_Caps +@ stub ADL2_DFP_PixelFormat_Get +@ stub ADL2_DFP_PixelFormat_Set +@ stub ADL2_DVRSupport_Get +@ stub ADL2_Desktop_DOPP_Enable +@ stub ADL2_Desktop_DOPP_EnableX2 +@ stub ADL2_Desktop_Detach +@ stub ADL2_Desktop_Device_Create +@ stub ADL2_Desktop_Device_Destroy +@ stub ADL2_Desktop_ExclusiveModeX2_Get +@ stub ADL2_Desktop_HardwareCursor_SetBitmap +@ stub ADL2_Desktop_HardwareCursor_SetPosition +@ stub ADL2_Desktop_HardwareCursor_Toggle +@ stub ADL2_Desktop_PFPAComplete_Set +@ stub ADL2_Desktop_PFPAState_Get +@ stub ADL2_Desktop_PrimaryInfo_Get +@ stub ADL2_Desktop_TextureState_Get +@ stub ADL2_Desktop_Texture_Enable +@ stub ADL2_Device_PMLog_Device_Create +@ stub ADL2_Device_PMLog_Device_Destroy +@ stub ADL2_DisplayScaling_Set +@ stub ADL2_Display_AdapterID_Get +@ stub ADL2_Display_AdjustCaps_Get +@ stub ADL2_Display_AdjustmentCoherent_Get +@ stub ADL2_Display_AdjustmentCoherent_Set +@ stub ADL2_Display_AudioMappingInfo_Get +@ stub ADL2_Display_AvivoColor_Get +@ stub ADL2_Display_AvivoCurrentColor_Set +@ stub ADL2_Display_AvivoDefaultColor_Set +@ stub ADL2_Display_BackLight_Get +@ stub ADL2_Display_BackLight_Set +@ stub ADL2_Display_BezelOffsetSteppingSize_Get +@ stub ADL2_Display_BezelOffset_Set +@ stub ADL2_Display_BezelSupported_Validate +@ stub ADL2_Display_Capabilities_Get +@ stub ADL2_Display_ColorCaps_Get +@ stub ADL2_Display_ColorDepth_Get +@ stub ADL2_Display_ColorDepth_Set +@ stub ADL2_Display_ColorTemperatureSourceDefault_Get +@ stub ADL2_Display_ColorTemperatureSource_Get +@ stub ADL2_Display_ColorTemperatureSource_Set +@ stub ADL2_Display_Color_Get +@ stub ADL2_Display_Color_Set +@ stub ADL2_Display_ConnectedDisplays_Get +@ stub ADL2_Display_ContainerID_Get +@ stub ADL2_Display_ControllerOverlayAdjustmentCaps_Get +@ stub ADL2_Display_ControllerOverlayAdjustmentData_Get +@ stub ADL2_Display_ControllerOverlayAdjustmentData_Set +@ stub ADL2_Display_CustomizedModeListNum_Get +@ stub ADL2_Display_CustomizedModeList_Get +@ stub ADL2_Display_CustomizedMode_Add +@ stub ADL2_Display_CustomizedMode_Delete +@ stub ADL2_Display_CustomizedMode_Validate +@ stub ADL2_Display_DCE_Get +@ stub ADL2_Display_DCE_Set +@ stub ADL2_Display_DDCBlockAccess_Get +@ cdecl ADL2_Display_DDCInfo2_Get(ptr long long ptr) +@ stub ADL2_Display_DDCInfo_Get +@ stub ADL2_Display_Deflicker_Get +@ stub ADL2_Display_Deflicker_Set +@ stub ADL2_Display_DeviceConfig_Get +@ stub ADL2_Display_DisplayContent_Cap +@ stub ADL2_Display_DisplayContent_Get +@ stub ADL2_Display_DisplayContent_Set +@ cdecl ADL2_Display_DisplayInfo_Get(ptr long ptr ptr long) +@ stub ADL2_Display_DisplayMapConfigX2_Set +@ cdecl ADL2_Display_DisplayMapConfig_Get(ptr long ptr ptr ptr ptr long) +@ stub ADL2_Display_DisplayMapConfig_PossibleAddAndRemove +@ stub ADL2_Display_DisplayMapConfig_Set +@ stub ADL2_Display_DisplayMapConfig_Validate +@ stub ADL2_Display_DitherState_Get +@ stub ADL2_Display_DitherState_Set +@ stub ADL2_Display_Downscaling_Caps +@ stub ADL2_Display_DpMstAuxMsg_Get +@ stub ADL2_Display_DpMstInfo_Get +@ stub ADL2_Display_DummyVirtual_Destroy +@ stub ADL2_Display_DummyVirtual_Get +@ stub ADL2_Display_EdidData_Get +@ stub ADL2_Display_EdidData_Set +@ stub ADL2_Display_EnumDisplays_Get +@ stub ADL2_Display_FilterSVideo_Get +@ stub ADL2_Display_FilterSVideo_Set +@ stub ADL2_Display_ForcibleDisplay_Get +@ stub ADL2_Display_ForcibleDisplay_Set +@ stub ADL2_Display_FormatsOverride_Get +@ stub ADL2_Display_FormatsOverride_Set +@ stub ADL2_Display_FreeSyncState_Get +@ stub ADL2_Display_FreeSyncState_Set +@ stub ADL2_Display_FreeSync_Cap +@ stub ADL2_Display_GamutMapping_Get +@ stub ADL2_Display_GamutMapping_Reset +@ stub ADL2_Display_GamutMapping_Set +@ stub ADL2_Display_Gamut_Caps +@ stub ADL2_Display_Gamut_Get +@ stub ADL2_Display_Gamut_Set +@ stub ADL2_Display_HDCP_Get +@ stub ADL2_Display_HDCP_Set +@ stub ADL2_Display_HDRState_Get +@ stub ADL2_Display_HDRState_Set +@ stub ADL2_Display_ImageExpansion_Get +@ stub ADL2_Display_ImageExpansion_Set +@ stub ADL2_Display_InfoPacket_Get +@ stub ADL2_Display_InfoPacket_Set +@ stub ADL2_Display_IsVirtual_Get +@ stub ADL2_Display_LCDRefreshRateCapability_Get +@ stub ADL2_Display_LCDRefreshRateOptions_Get +@ stub ADL2_Display_LCDRefreshRateOptions_Set +@ stub ADL2_Display_LCDRefreshRate_Get +@ stub ADL2_Display_LCDRefreshRate_Set +@ stub ADL2_Display_Limits_Get +@ stub ADL2_Display_MVPUCaps_Get +@ stub ADL2_Display_MVPUStatus_Get +@ stub ADL2_Display_ModeTimingOverrideInfo_Get +@ stub ADL2_Display_ModeTimingOverrideListX2_Get +@ stub ADL2_Display_ModeTimingOverrideListX3_Get +@ stub ADL2_Display_ModeTimingOverrideList_Get +@ stub ADL2_Display_ModeTimingOverrideX2_Get +@ stub ADL2_Display_ModeTimingOverrideX2_Set +@ stub ADL2_Display_ModeTimingOverrideX3_Get +@ stub ADL2_Display_ModeTimingOverride_Delete +@ stub ADL2_Display_ModeTimingOverride_Get +@ stub ADL2_Display_ModeTimingOverride_Set +@ stub ADL2_Display_Modes_Get +@ stub ADL2_Display_Modes_Set +@ stub ADL2_Display_Modes_X2_Get +@ stub ADL2_Display_MonitorPowerState_Set +@ stub ADL2_Display_NativeAUXChannel_Access +@ stub ADL2_Display_NeedWorkaroundFor5Clone_Get +@ stub ADL2_Display_NumberOfDisplays_Get +@ stub ADL2_Display_ODClockConfig_Set +@ stub ADL2_Display_ODClockInfo_Get +@ stub ADL2_Display_Overlap_NotifyAdjustment +@ stub ADL2_Display_Overlap_Set +@ stub ADL2_Display_Overscan_Get +@ stub ADL2_Display_Overscan_Set +@ stub ADL2_Display_PixelFormatDefault_Get +@ stub ADL2_Display_PixelFormat_Get +@ stub ADL2_Display_PixelFormat_Set +@ stub ADL2_Display_Position_Get +@ stub ADL2_Display_Position_Set +@ stub ADL2_Display_PossibleMapping_Get +@ stub ADL2_Display_PossibleMode_Get +@ stub ADL2_Display_PowerXpressActiveGPU_Get +@ stub ADL2_Display_PowerXpressActiveGPU_Set +@ stub ADL2_Display_PowerXpressActvieGPUR2_Get +@ stub ADL2_Display_PowerXpressVersion_Get +@ stub ADL2_Display_PowerXpress_AutoSwitchConfig_Get +@ stub ADL2_Display_PowerXpress_AutoSwitchConfig_Set +@ stub ADL2_Display_PreferredMode_Get +@ stub ADL2_Display_PreservedAspectRatio_Get +@ stub ADL2_Display_PreservedAspectRatio_Set +@ stub ADL2_Display_Property_Get +@ stub ADL2_Display_Property_Set +@ stub ADL2_Display_RcDisplayAdjustment +@ stub ADL2_Display_ReGammaCoefficients_Get +@ stub ADL2_Display_ReGammaCoefficients_Set +@ stub ADL2_Display_ReducedBlanking_Get +@ stub ADL2_Display_ReducedBlanking_Set +@ stub ADL2_Display_RegammaR1_Get +@ stub ADL2_Display_RegammaR1_Set +@ stub ADL2_Display_Regamma_Get +@ stub ADL2_Display_Regamma_Set +@ stub ADL2_Display_SLSBuilder_CommonMode_Get +@ stub ADL2_Display_SLSBuilder_Create +@ stub ADL2_Display_SLSBuilder_DisplaysCanBeNextCandidateInSLS_Get +@ stub ADL2_Display_SLSBuilder_DisplaysCanBeNextCandidateToEnabled_Get +@ stub ADL2_Display_SLSBuilder_Get +@ stub ADL2_Display_SLSBuilder_IsActive_Notify +@ stub ADL2_Display_SLSBuilder_MaxSLSLayoutSize_Get +@ stub ADL2_Display_SLSBuilder_TimeOut_Get +@ stub ADL2_Display_SLSBuilder_Update +@ stub ADL2_Display_SLSGrid_Caps +@ stub ADL2_Display_SLSMapConfigX2_Delete +@ stub ADL2_Display_SLSMapConfigX2_Get +@ stub ADL2_Display_SLSMapConfig_Create +@ stub ADL2_Display_SLSMapConfig_Delete +@ stub ADL2_Display_SLSMapConfig_Get +@ stub ADL2_Display_SLSMapConfig_ImageCropType_Set +@ stub ADL2_Display_SLSMapConfig_Rearrange +@ stub ADL2_Display_SLSMapConfig_SetState +@ stub ADL2_Display_SLSMapConfig_SupportedImageCropType_Get +@ stub ADL2_Display_SLSMapConfig_Valid +@ stub ADL2_Display_SLSMapIndexList_Get +@ stub ADL2_Display_SLSMapIndex_Get +@ stub ADL2_Display_SLSMiddleMode_Get +@ stub ADL2_Display_SLSMiddleMode_Set +@ stub ADL2_Display_SLSRecords_Get +@ stub ADL2_Display_Sharpness_Caps +@ stub ADL2_Display_Sharpness_Get +@ stub ADL2_Display_Sharpness_Info_Get +@ stub ADL2_Display_Sharpness_Set +@ stub ADL2_Display_Size_Get +@ stub ADL2_Display_Size_Set +@ stub ADL2_Display_SourceContentAttribute_Get +@ stub ADL2_Display_SourceContentAttribute_Set +@ stub ADL2_Display_SplitDisplay_Caps +@ stub ADL2_Display_SplitDisplay_Get +@ stub ADL2_Display_SplitDisplay_RestoreDesktopConfiguration +@ stub ADL2_Display_SplitDisplay_Set +@ stub ADL2_Display_SupportedColorDepth_Get +@ stub ADL2_Display_SupportedPixelFormat_Get +@ stub ADL2_Display_SwitchingCapability_Get +@ stub ADL2_Display_TVCaps_Get +@ stub ADL2_Display_TargetTimingX2_Get +@ stub ADL2_Display_TargetTiming_Get +@ stub ADL2_Display_UnderScan_Auto_Get +@ stub ADL2_Display_UnderScan_Auto_Set +@ stub ADL2_Display_UnderscanState_Get +@ stub ADL2_Display_UnderscanState_Set +@ stub ADL2_Display_UnderscanSupport_Get +@ stub ADL2_Display_Underscan_Get +@ stub ADL2_Display_Underscan_Set +@ stub ADL2_Display_Vector_Get +@ stub ADL2_Display_ViewPort_Cap +@ stub ADL2_Display_ViewPort_Get +@ stub ADL2_Display_ViewPort_Set +@ stub ADL2_Display_VirtualType_Get +@ stub ADL2_Display_WriteAndReadI2C +@ stub ADL2_Display_WriteAndReadI2CLargePayload +@ stub ADL2_Display_WriteAndReadI2CRev_Get +@ stub ADL2_ElmCompatibilityMode_Caps +@ stub ADL2_ElmCompatibilityMode_Status_Get +@ stub ADL2_ElmCompatibilityMode_Status_Set +@ stub ADL2_ExclusiveModeGet +@ stub ADL2_FPS_Caps +@ stub ADL2_FPS_Settings_Get +@ stub ADL2_FPS_Settings_Reset +@ stub ADL2_FPS_Settings_Set +@ stub ADL2_Feature_Settings_Get +@ stub ADL2_Feature_Settings_Set +@ stub ADL2_Flush_Driver_Data +@ stub ADL2_GPUVMPageSize_Info_Get +@ stub ADL2_GPUVMPageSize_Info_Set +@ stub ADL2_GPUVerInfo_Get +@ stub ADL2_GcnAsicInfo_Get +@ stub ADL2_Graphics_IsDetachableGraphicsPlatform_Get +@ stub ADL2_Graphics_IsGfx9AndAbove +@ stub ADL2_Graphics_MantleVersion_Get +@ cdecl ADL2_Graphics_Platform_Get(ptr ptr) +@ cdecl ADL2_Graphics_VersionsX2_Get(ptr ptr) +@ stub ADL2_Graphics_Versions_Get +@ stub ADL2_Graphics_VulkanVersion_Get +@ stub ADL2_HybridGraphicsGPU_Set +@ stub ADL2_MGPUSLS_Status_Set +@ stub ADL2_MMD_FeatureList_Get +@ stub ADL2_MMD_FeatureValuesX2_Get +@ stub ADL2_MMD_FeatureValuesX2_Set +@ stub ADL2_MMD_FeatureValues_Get +@ stub ADL2_MMD_FeatureValues_Set +@ stub ADL2_MMD_FeaturesX2_Caps +@ stub ADL2_MMD_Features_Caps +@ stub ADL2_MMD_VideoAdjustInfo_Get +@ stub ADL2_MMD_VideoAdjustInfo_Set +@ stub ADL2_MMD_VideoColor_Caps +@ stub ADL2_MMD_VideoColor_Get +@ stub ADL2_MMD_VideoColor_Set +@ stub ADL2_MMD_Video_Caps +@ stub ADL2_Main_ControlX2_Create +@ cdecl ADL2_Main_Control_Create(ptr long ptr) +@ cdecl ADL2_Main_Control_Destroy(ptr) +@ stub ADL2_Main_Control_GetProcAddress +@ stub ADL2_Main_Control_IsFunctionValid +@ stub ADL2_Main_Control_Refresh +@ stub ADL2_Main_LogDebug_Set +@ stub ADL2_Main_LogError_Set +@ stub ADL2_New_QueryPMLogData_Get +@ stub ADL2_Overdrive5_CurrentActivity_Get +@ stub ADL2_Overdrive5_FanSpeedInfo_Get +@ stub ADL2_Overdrive5_FanSpeedToDefault_Set +@ stub ADL2_Overdrive5_FanSpeed_Get +@ stub ADL2_Overdrive5_FanSpeed_Set +@ stub ADL2_Overdrive5_ODParameters_Get +@ stub ADL2_Overdrive5_ODPerformanceLevels_Get +@ stub ADL2_Overdrive5_ODPerformanceLevels_Set +@ stub ADL2_Overdrive5_PowerControlAbsValue_Caps +@ stub ADL2_Overdrive5_PowerControlAbsValue_Get +@ stub ADL2_Overdrive5_PowerControlAbsValue_Set +@ stub ADL2_Overdrive5_PowerControlInfo_Get +@ stub ADL2_Overdrive5_PowerControl_Caps +@ stub ADL2_Overdrive5_PowerControl_Get +@ stub ADL2_Overdrive5_PowerControl_Set +@ stub ADL2_Overdrive5_Temperature_Get +@ stub ADL2_Overdrive5_ThermalDevices_Enum +@ stub ADL2_Overdrive6_AdvancedFan_Caps +@ stub ADL2_Overdrive6_CapabilitiesEx_Get +@ stub ADL2_Overdrive6_Capabilities_Get +@ stub ADL2_Overdrive6_ControlI2C +@ stub ADL2_Overdrive6_CurrentPower_Get +@ stub ADL2_Overdrive6_CurrentStatus_Get +@ stub ADL2_Overdrive6_FanPWMLimitData_Get +@ stub ADL2_Overdrive6_FanPWMLimitData_Set +@ stub ADL2_Overdrive6_FanPWMLimitRangeInfo_Get +@ stub ADL2_Overdrive6_FanSpeed_Get +@ stub ADL2_Overdrive6_FanSpeed_Reset +@ stub ADL2_Overdrive6_FanSpeed_Set +@ stub ADL2_Overdrive6_FuzzyController_Caps +@ stub ADL2_Overdrive6_MaxClockAdjust_Get +@ stub ADL2_Overdrive6_PowerControlInfo_Get +@ stub ADL2_Overdrive6_PowerControlInfo_Get_X2 +@ stub ADL2_Overdrive6_PowerControl_Caps +@ stub ADL2_Overdrive6_PowerControl_Get +@ stub ADL2_Overdrive6_PowerControl_Set +@ stub ADL2_Overdrive6_StateEx_Get +@ stub ADL2_Overdrive6_StateEx_Set +@ stub ADL2_Overdrive6_StateInfo_Get +@ stub ADL2_Overdrive6_State_Reset +@ stub ADL2_Overdrive6_State_Set +@ stub ADL2_Overdrive6_TargetTemperatureData_Get +@ stub ADL2_Overdrive6_TargetTemperatureData_Set +@ stub ADL2_Overdrive6_TargetTemperatureRangeInfo_Get +@ stub ADL2_Overdrive6_TemperatureEx_Get +@ stub ADL2_Overdrive6_Temperature_Get +@ stub ADL2_Overdrive6_ThermalController_Caps +@ stub ADL2_Overdrive6_ThermalLimitUnlock_Get +@ stub ADL2_Overdrive6_ThermalLimitUnlock_Set +@ stub ADL2_Overdrive6_VoltageControlInfo_Get +@ stub ADL2_Overdrive6_VoltageControl_Get +@ stub ADL2_Overdrive6_VoltageControl_Set +@ stub ADL2_Overdrive8_Current_SettingX2_Get +@ stub ADL2_Overdrive8_Current_SettingX3_Get +@ stub ADL2_Overdrive8_Current_Setting_Get +@ stub ADL2_Overdrive8_Init_SettingX2_Get +@ stub ADL2_Overdrive8_Init_Setting_Get +@ stub ADL2_Overdrive8_PMLogSenorRange_Caps +@ stub ADL2_Overdrive8_PMLogSenorType_Support_Get +@ stub ADL2_Overdrive8_PMLog_ShareMemory_Read +@ stub ADL2_Overdrive8_PMLog_ShareMemory_Start +@ stub ADL2_Overdrive8_PMLog_ShareMemory_Stop +@ stub ADL2_Overdrive8_PMLog_ShareMemory_Support +@ stub ADL2_Overdrive8_Setting_Set +@ stub ADL2_OverdriveN_AutoWattman_Caps +@ stub ADL2_OverdriveN_AutoWattman_Get +@ stub ADL2_OverdriveN_AutoWattman_Set +@ stub ADL2_OverdriveN_CapabilitiesX2_Get +@ stub ADL2_OverdriveN_Capabilities_Get +@ stub ADL2_OverdriveN_CountOfEvents_Get +@ stub ADL2_OverdriveN_FanControl_Get +@ stub ADL2_OverdriveN_FanControl_Set +@ stub ADL2_OverdriveN_MemoryClocksX2_Get +@ stub ADL2_OverdriveN_MemoryClocksX2_Set +@ stub ADL2_OverdriveN_MemoryClocks_Get +@ stub ADL2_OverdriveN_MemoryClocks_Set +@ stub ADL2_OverdriveN_MemoryTimingLevel_Get +@ stub ADL2_OverdriveN_MemoryTimingLevel_Set +@ stub ADL2_OverdriveN_PerformanceStatus_Get +@ stub ADL2_OverdriveN_PowerLimit_Get +@ stub ADL2_OverdriveN_PowerLimit_Set +@ stub ADL2_OverdriveN_SCLKAutoOverClock_Get +@ stub ADL2_OverdriveN_SCLKAutoOverClock_Set +@ stub ADL2_OverdriveN_SettingsExt_Get +@ stub ADL2_OverdriveN_SettingsExt_Set +@ stub ADL2_OverdriveN_SystemClocksX2_Get +@ stub ADL2_OverdriveN_SystemClocksX2_Set +@ stub ADL2_OverdriveN_SystemClocks_Get +@ stub ADL2_OverdriveN_SystemClocks_Set +@ stub ADL2_OverdriveN_Temperature_Get +@ stub ADL2_OverdriveN_Test_Set +@ stub ADL2_OverdriveN_ThrottleNotification_Get +@ stub ADL2_OverdriveN_ZeroRPMFan_Get +@ stub ADL2_OverdriveN_ZeroRPMFan_Set +@ stub ADL2_Overdrive_Caps +@ stub ADL2_PPLogSettings_Get +@ stub ADL2_PPLogSettings_Set +@ stub ADL2_PPW_Caps +@ stub ADL2_PPW_Status_Get +@ stub ADL2_PPW_Status_Set +@ stub ADL2_PageMigration_Settings_Get +@ stub ADL2_PageMigration_Settings_Set +@ stub ADL2_PerGPU_GDEvent_Register +@ stub ADL2_PerGPU_GDEvent_UnRegister +@ stub ADL2_PerfTuning_Status_Get +@ stub ADL2_PerfTuning_Status_Set +@ stub ADL2_PerformanceTuning_Caps +@ stub ADL2_PowerStates_Get +@ stub ADL2_PowerXpress_AncillaryDevices_Get +@ stub ADL2_PowerXpress_Config_Caps +@ stub ADL2_PowerXpress_Configuration_Get +@ stub ADL2_PowerXpress_ExtendedBatteryMode_Caps +@ stub ADL2_PowerXpress_ExtendedBatteryMode_Get +@ stub ADL2_PowerXpress_ExtendedBatteryMode_Set +@ stub ADL2_PowerXpress_LongIdleDetect_Get +@ stub ADL2_PowerXpress_LongIdleDetect_Set +@ stub ADL2_PowerXpress_PowerControlMode_Get +@ stub ADL2_PowerXpress_PowerControlMode_Set +@ stub ADL2_PowerXpress_Scheme_Get +@ stub ADL2_PowerXpress_Scheme_Set +@ stub ADL2_RIS_Settings_Get +@ stub ADL2_RIS_Settings_Set +@ stub ADL2_RegisterEvent +@ stub ADL2_RegisterEventX2 +@ stub ADL2_Remap +@ stub ADL2_RemoteDisplay_Destroy +@ stub ADL2_RemoteDisplay_Display_Acquire +@ stub ADL2_RemoteDisplay_Display_Release +@ stub ADL2_RemoteDisplay_Display_Release_All +@ stub ADL2_RemoteDisplay_Hdcp20_Create +@ stub ADL2_RemoteDisplay_Hdcp20_Destroy +@ stub ADL2_RemoteDisplay_Hdcp20_Notify +@ stub ADL2_RemoteDisplay_Hdcp20_Process +@ stub ADL2_RemoteDisplay_IEPort_Set +@ stub ADL2_RemoteDisplay_Initialize +@ stub ADL2_RemoteDisplay_Nofitiation_Register +@ stub ADL2_RemoteDisplay_Notification_UnRegister +@ stub ADL2_RemoteDisplay_Support_Caps +@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_InUse_Get +@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_Info_Get +@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_RadioState_Get +@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Change +@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Get +@ stub ADL2_RemoteDisplay_WFDDeviceInfo_Get +@ stub ADL2_RemoteDisplay_WFDDeviceName_Change +@ stub ADL2_RemoteDisplay_WFDDevice_StatusInfo_Get +@ stub ADL2_RemoteDisplay_WFDDiscover_Start +@ stub ADL2_RemoteDisplay_WFDDiscover_Stop +@ stub ADL2_RemoteDisplay_WFDLink_Connect +@ stub ADL2_RemoteDisplay_WFDLink_Creation_Accept +@ stub ADL2_RemoteDisplay_WFDLink_Disconnect +@ stub ADL2_RemoteDisplay_WFDLink_WPS_Process +@ stub ADL2_RemoteDisplay_WFDWDSPSettings_Set +@ stub ADL2_RemoteDisplay_WirelessDisplayEnableDisable_Commit +@ stub ADL2_RemotePlay_ControlFlags_Set +@ stub ADL2_ScreenPoint_AudioMappingInfo_Get +@ stub ADL2_Send +@ stub ADL2_SendX2 +@ stub ADL2_Stereo3D_2DPackedFormat_Set +@ stub ADL2_Stereo3D_3DCursorOffset_Get +@ stub ADL2_Stereo3D_3DCursorOffset_Set +@ stub ADL2_Stereo3D_CurrentFormat_Get +@ stub ADL2_Stereo3D_Info_Get +@ stub ADL2_Stereo3D_Modes_Get +@ stub ADL2_SwitchableGraphics_Applications_Get +@ stub ADL2_TV_Standard_Get +@ stub ADL2_TV_Standard_Set +@ stub ADL2_TurboSyncSupport_Get +@ stub ADL2_UnRegisterEvent +@ stub ADL2_UnRegisterEventX2 +@ stub ADL2_User_Settings_Notify +@ stub ADL2_WS_Overdrive_Caps +@ stub ADL2_Win_IsHybridAI +@ stub ADL2_Workstation_8BitGrayscale_Get +@ stub ADL2_Workstation_8BitGrayscale_Set +@ stub ADL2_Workstation_AdapterNumOfGLSyncConnectors_Get +@ stub ADL2_Workstation_Caps +@ stub ADL2_Workstation_DeepBitDepthX2_Get +@ stub ADL2_Workstation_DeepBitDepthX2_Set +@ stub ADL2_Workstation_DeepBitDepth_Get +@ stub ADL2_Workstation_DeepBitDepth_Set +@ stub ADL2_Workstation_DisplayGLSyncMode_Get +@ stub ADL2_Workstation_DisplayGLSyncMode_Set +@ stub ADL2_Workstation_DisplayGenlockCapable_Get +@ stub ADL2_Workstation_ECCData_Get +@ stub ADL2_Workstation_ECCX2_Get +@ stub ADL2_Workstation_ECC_Caps +@ stub ADL2_Workstation_ECC_Get +@ stub ADL2_Workstation_ECC_Set +@ stub ADL2_Workstation_GLSyncCounters_Get +@ stub ADL2_Workstation_GLSyncGenlockConfiguration_Get +@ stub ADL2_Workstation_GLSyncGenlockConfiguration_Set +@ stub ADL2_Workstation_GLSyncModuleDetect_Get +@ stub ADL2_Workstation_GLSyncModuleInfo_Get +@ stub ADL2_Workstation_GLSyncPortState_Get +@ stub ADL2_Workstation_GLSyncPortState_Set +@ stub ADL2_Workstation_GLSyncSupportedTopology_Get +@ stub ADL2_Workstation_GlobalEDIDPersistence_Get +@ stub ADL2_Workstation_GlobalEDIDPersistence_Set +@ stub ADL2_Workstation_LoadBalancing_Caps +@ stub ADL2_Workstation_LoadBalancing_Get +@ stub ADL2_Workstation_LoadBalancing_Set +@ stub ADL2_Workstation_RAS_ErrorCounts_Get +@ stub ADL2_Workstation_RAS_ErrorCounts_Reset +@ stub ADL2_Workstation_SDISegmentList_Get +@ stub ADL2_Workstation_SDI_Caps +@ stub ADL2_Workstation_SDI_Get +@ stub ADL2_Workstation_SDI_Set +@ stub ADL2_Workstation_Stereo_Get +@ stub ADL2_Workstation_Stereo_Set +@ stub ADL2_Workstation_UnsupportedDisplayModes_Enable +@ stub ADL_ADC_CurrentProfileFromDrv_Get +@ stub ADL_ADC_Display_AdapterDeviceProfileEx_Get +@ stub ADL_ADC_DrvDataToProfile_Copy +@ stub ADL_ADC_FindClosestMode_Get +@ stub ADL_ADC_IsDevModeEqual_Get +@ stub ADL_ADC_Profile_Apply +@ stub ADL_APO_AudioDelayAdjustmentInfo_Get +@ stub ADL_APO_AudioDelay_Restore +@ stub ADL_APO_AudioDelay_Set +@ stub ADL_AdapterLimitation_Caps +@ stub ADL_AdapterX2_Caps +@ cdecl ADL_Adapter_ASICFamilyType_Get(long ptr ptr) +@ stub ADL_Adapter_ASICInfo_Get +@ stub ADL_Adapter_Accessibility_Get +@ stub ADL_Adapter_Active_Get +@ stub ADL_Adapter_Active_Set +@ stub ADL_Adapter_Active_SetPrefer +@ stub ADL_Adapter_AdapterInfoX2_Get +@ cdecl ADL_Adapter_AdapterInfo_Get(ptr long) +@ stub ADL_Adapter_AdapterList_Disable +@ stub ADL_Adapter_Aspects_Get +@ stub ADL_Adapter_AudioChannelSplitConfiguration_Get +@ stub ADL_Adapter_AudioChannelSplit_Disable +@ stub ADL_Adapter_AudioChannelSplit_Enable +@ stub ADL_Adapter_BigSw_Info_Get +@ stub ADL_Adapter_BlackAndWhiteLevelSupport_Get +@ stub ADL_Adapter_BlackAndWhiteLevel_Get +@ stub ADL_Adapter_BlackAndWhiteLevel_Set +@ stub ADL_Adapter_BoardLayout_Get +@ stub ADL_Adapter_Caps +@ stub ADL_Adapter_ChipSetInfo_Get +@ stub ADL_Adapter_ConfigMemory_Cap +@ stub ADL_Adapter_ConfigMemory_Get +@ stub ADL_Adapter_ConfigureState_Get +@ stub ADL_Adapter_ConnectionData_Get +@ stub ADL_Adapter_ConnectionData_Remove +@ stub ADL_Adapter_ConnectionData_Set +@ stub ADL_Adapter_ConnectionState_Get +@ stub ADL_Adapter_CrossDisplayPlatformInfo_Get +@ stub ADL_Adapter_CrossdisplayAdapterRole_Caps +@ stub ADL_Adapter_CrossdisplayInfoX2_Set +@ stub ADL_Adapter_CrossdisplayInfo_Get +@ stub ADL_Adapter_CrossdisplayInfo_Set +@ stub ADL_Adapter_CrossfireX2_Get +@ cdecl ADL_Adapter_Crossfire_Caps(long ptr ptr ptr) +@ cdecl ADL_Adapter_Crossfire_Get(long ptr ptr) +@ stub ADL_Adapter_Crossfire_Set +@ stub ADL_Adapter_DefaultAudioChannelTable_Load +@ stub ADL_Adapter_DisplayAudioEndpoint_Enable +@ stub ADL_Adapter_DisplayAudioEndpoint_Mute +@ stub ADL_Adapter_DisplayAudioInfo_Get +@ stub ADL_Adapter_DisplayGTCCaps_Get +@ stub ADL_Adapter_Display_Caps +@ stub ADL_Adapter_DriverSettings_Get +@ stub ADL_Adapter_DriverSettings_Set +@ stub ADL_Adapter_EDIDManagement_Caps +@ stub ADL_Adapter_EmulationMode_Set +@ stub ADL_Adapter_ExtInfo_Get +@ stub ADL_Adapter_Gamma_Get +@ stub ADL_Adapter_Gamma_Set +@ stub ADL_Adapter_ID_Get +@ stub ADL_Adapter_LocalDisplayConfig_Get +@ stub ADL_Adapter_LocalDisplayConfig_Set +@ stub ADL_Adapter_LocalDisplayState_Get +@ stub ADL_Adapter_MaxCursorSize_Get +@ stub ADL_Adapter_MemoryInfo2_Get +@ cdecl ADL_Adapter_MemoryInfo_Get(long ptr) +@ stub ADL_Adapter_MirabilisSupport_Get +@ stub ADL_Adapter_ModeSwitch +@ stub ADL_Adapter_ModeTimingOverride_Caps +@ stub ADL_Adapter_Modes_ReEnumerate +@ stub ADL_Adapter_NumberOfActivatableSources_Get +@ cdecl ADL_Adapter_NumberOfAdapters_Get(ptr) +@ cdecl ADL_Adapter_ObservedClockInfo_Get(long ptr ptr) +@ stub ADL_Adapter_ObservedGameClockInfo_Get +@ stub ADL_Adapter_Primary_Get +@ stub ADL_Adapter_Primary_Set +@ stub ADL_Adapter_RegValueInt_Get +@ stub ADL_Adapter_RegValueInt_Set +@ stub ADL_Adapter_RegValueString_Get +@ stub ADL_Adapter_RegValueString_Set +@ stub ADL_Adapter_SWInfo_Get +@ stub ADL_Adapter_Speed_Caps +@ stub ADL_Adapter_Speed_Get +@ stub ADL_Adapter_Speed_Set +@ stub ADL_Adapter_SupportedConnections_Get +@ stub ADL_Adapter_Tear_Free_Cap +@ stub ADL_Adapter_VariBrightEnable_Set +@ stub ADL_Adapter_VariBrightLevel_Get +@ stub ADL_Adapter_VariBrightLevel_Set +@ stub ADL_Adapter_VariBright_Caps +@ stub ADL_Adapter_VideoBiosInfo_Get +@ stub ADL_Adapter_VideoTheaterModeInfo_Get +@ stub ADL_Adapter_VideoTheaterModeInfo_Set +@ stub ADL_ApplicationProfiles_Applications_Get +@ stub ADL_ApplicationProfiles_ConvertToCompact +@ stub ADL_ApplicationProfiles_DriverAreaPrivacy_Get +@ stub ADL_ApplicationProfiles_GetCustomization +@ stub ADL_ApplicationProfiles_HitListsX2_Get +@ stub ADL_ApplicationProfiles_HitLists_Get +@ stub ADL_ApplicationProfiles_ProfileApplicationX2_Assign +@ stub ADL_ApplicationProfiles_ProfileApplication_Assign +@ stub ADL_ApplicationProfiles_ProfileOfAnApplicationX2_Search +@ stub ADL_ApplicationProfiles_ProfileOfAnApplication_InMemorySearch +@ stub ADL_ApplicationProfiles_ProfileOfAnApplication_Search +@ stub ADL_ApplicationProfiles_Profile_Create +@ stub ADL_ApplicationProfiles_Profile_Exist +@ stub ADL_ApplicationProfiles_Profile_Remove +@ stub ADL_ApplicationProfiles_PropertyType_Get +@ stub ADL_ApplicationProfiles_Release_Get +@ stub ADL_ApplicationProfiles_RemoveApplication +@ stub ADL_ApplicationProfiles_StatusInfo_Get +@ stub ADL_ApplicationProfiles_System_Reload +@ stub ADL_ApplicationProfiles_User_Load +@ stub ADL_ApplicationProfiles_User_Unload +@ stub ADL_Audio_CurrentSampleRate_Get +@ stub ADL_CDS_UnsafeMode_Set +@ stub ADL_CV_DongleSettings_Get +@ stub ADL_CV_DongleSettings_Reset +@ stub ADL_CV_DongleSettings_Set +@ stub ADL_DFP_AllowOnlyCETimings_Get +@ stub ADL_DFP_AllowOnlyCETimings_Set +@ stub ADL_DFP_BaseAudioSupport_Get +@ stub ADL_DFP_GPUScalingEnable_Get +@ stub ADL_DFP_GPUScalingEnable_Set +@ stub ADL_DFP_HDMISupport_Get +@ stub ADL_DFP_MVPUAnalogSupport_Get +@ stub ADL_DFP_PixelFormat_Caps +@ stub ADL_DFP_PixelFormat_Get +@ stub ADL_DFP_PixelFormat_Set +@ stub ADL_DisplayScaling_Set +@ stub ADL_Display_AdapterID_Get +@ stub ADL_Display_AdjustCaps_Get +@ stub ADL_Display_AdjustmentCoherent_Get +@ stub ADL_Display_AdjustmentCoherent_Set +@ stub ADL_Display_AudioMappingInfo_Get +@ stub ADL_Display_AvivoColor_Get +@ stub ADL_Display_AvivoCurrentColor_Set +@ stub ADL_Display_AvivoDefaultColor_Set +@ stub ADL_Display_BackLight_Get +@ stub ADL_Display_BackLight_Set +@ stub ADL_Display_BezelOffsetSteppingSize_Get +@ stub ADL_Display_BezelOffset_Set +@ stub ADL_Display_BezelSupported_Validate +@ stub ADL_Display_Capabilities_Get +@ stub ADL_Display_ColorCaps_Get +@ stub ADL_Display_ColorDepth_Get +@ stub ADL_Display_ColorDepth_Set +@ stub ADL_Display_ColorTemperatureSource_Get +@ stub ADL_Display_ColorTemperatureSource_Set +@ stub ADL_Display_Color_Get +@ stub ADL_Display_Color_Set +@ stub ADL_Display_ConnectedDisplays_Get +@ stub ADL_Display_ContainerID_Get +@ stub ADL_Display_ControllerOverlayAdjustmentCaps_Get +@ stub ADL_Display_ControllerOverlayAdjustmentData_Get +@ stub ADL_Display_ControllerOverlayAdjustmentData_Set +@ stub ADL_Display_CurrentPixelClock_Get +@ stub ADL_Display_CustomizedModeListNum_Get +@ stub ADL_Display_CustomizedModeList_Get +@ stub ADL_Display_CustomizedMode_Add +@ stub ADL_Display_CustomizedMode_Delete +@ stub ADL_Display_CustomizedMode_Validate +@ stub ADL_Display_DCE_Get +@ stub ADL_Display_DCE_Set +@ stub ADL_Display_DDCBlockAccess_Get +@ stub ADL_Display_DDCInfo2_Get +@ stub ADL_Display_DDCInfo_Get +@ stub ADL_Display_Deflicker_Get +@ stub ADL_Display_Deflicker_Set +@ stub ADL_Display_DeviceConfig_Get +@ stub ADL_Display_DisplayContent_Cap +@ stub ADL_Display_DisplayContent_Get +@ stub ADL_Display_DisplayContent_Set +@ cdecl ADL_Display_DisplayInfo_Get(long long ptr long) +@ cdecl ADL_Display_DisplayMapConfig_Get(long ptr ptr ptr ptr long) +@ stub ADL_Display_DisplayMapConfig_PossibleAddAndRemove +@ stub ADL_Display_DisplayMapConfig_Set +@ stub ADL_Display_DisplayMapConfig_Validate +@ stub ADL_Display_DitherState_Get +@ stub ADL_Display_DitherState_Set +@ stub ADL_Display_Downscaling_Caps +@ stub ADL_Display_DpMstInfo_Get +@ stub ADL_Display_EdidData_Get +@ stub ADL_Display_EdidData_Set +@ stub ADL_Display_EnumDisplays_Get +@ stub ADL_Display_FilterSVideo_Get +@ stub ADL_Display_FilterSVideo_Set +@ stub ADL_Display_ForcibleDisplay_Get +@ stub ADL_Display_ForcibleDisplay_Set +@ stub ADL_Display_FormatsOverride_Get +@ stub ADL_Display_FormatsOverride_Set +@ stub ADL_Display_FreeSyncState_Get +@ stub ADL_Display_FreeSyncState_Set +@ stub ADL_Display_FreeSync_Cap +@ stub ADL_Display_GamutMapping_Get +@ stub ADL_Display_GamutMapping_Reset +@ stub ADL_Display_GamutMapping_Set +@ stub ADL_Display_Gamut_Caps +@ stub ADL_Display_Gamut_Get +@ stub ADL_Display_Gamut_Set +@ stub ADL_Display_ImageExpansion_Get +@ stub ADL_Display_ImageExpansion_Set +@ stub ADL_Display_InfoPacket_Get +@ stub ADL_Display_InfoPacket_Set +@ stub ADL_Display_LCDRefreshRateCapability_Get +@ stub ADL_Display_LCDRefreshRateOptions_Get +@ stub ADL_Display_LCDRefreshRateOptions_Set +@ stub ADL_Display_LCDRefreshRate_Get +@ stub ADL_Display_LCDRefreshRate_Set +@ stub ADL_Display_Limits_Get +@ stub ADL_Display_MVPUCaps_Get +@ stub ADL_Display_MVPUStatus_Get +@ stub ADL_Display_ModeTimingOverrideInfo_Get +@ stub ADL_Display_ModeTimingOverrideListX2_Get +@ stub ADL_Display_ModeTimingOverrideList_Get +@ stub ADL_Display_ModeTimingOverrideX2_Get +@ stub ADL_Display_ModeTimingOverride_Delete +@ stub ADL_Display_ModeTimingOverride_Get +@ stub ADL_Display_ModeTimingOverride_Set +@ stub ADL_Display_Modes_Get +@ stub ADL_Display_Modes_Set +@ stub ADL_Display_MonitorPowerState_Set +@ stub ADL_Display_NativeAUXChannel_Access +@ stub ADL_Display_NeedWorkaroundFor5Clone_Get +@ stub ADL_Display_NumberOfDisplays_Get +@ stub ADL_Display_ODClockConfig_Set +@ stub ADL_Display_ODClockInfo_Get +@ stub ADL_Display_Overlap_Set +@ stub ADL_Display_Overscan_Get +@ stub ADL_Display_Overscan_Set +@ stub ADL_Display_PixelClockAllowableRange_Set +@ stub ADL_Display_PixelClockCaps_Get +@ stub ADL_Display_PixelFormat_Get +@ stub ADL_Display_PixelFormat_Set +@ stub ADL_Display_Position_Get +@ stub ADL_Display_Position_Set +@ stub ADL_Display_PossibleMapping_Get +@ stub ADL_Display_PossibleMode_Get +@ stub ADL_Display_PowerXpressActiveGPU_Get +@ stub ADL_Display_PowerXpressActiveGPU_Set +@ stub ADL_Display_PowerXpressActvieGPUR2_Get +@ stub ADL_Display_PowerXpressVersion_Get +@ stub ADL_Display_PowerXpress_AutoSwitchConfig_Get +@ stub ADL_Display_PowerXpress_AutoSwitchConfig_Set +@ stub ADL_Display_PreservedAspectRatio_Get +@ stub ADL_Display_PreservedAspectRatio_Set +@ stub ADL_Display_Property_Get +@ stub ADL_Display_Property_Set +@ stub ADL_Display_RcDisplayAdjustment +@ stub ADL_Display_ReGammaCoefficients_Get +@ stub ADL_Display_ReGammaCoefficients_Set +@ stub ADL_Display_ReducedBlanking_Get +@ stub ADL_Display_ReducedBlanking_Set +@ stub ADL_Display_RegammaR1_Get +@ stub ADL_Display_RegammaR1_Set +@ stub ADL_Display_Regamma_Get +@ stub ADL_Display_Regamma_Set +@ stub ADL_Display_SLSGrid_Caps +@ stub ADL_Display_SLSMapConfigX2_Get +@ stub ADL_Display_SLSMapConfig_Create +@ stub ADL_Display_SLSMapConfig_Delete +@ stub ADL_Display_SLSMapConfig_Get +@ stub ADL_Display_SLSMapConfig_Rearrange +@ stub ADL_Display_SLSMapConfig_SetState +@ stub ADL_Display_SLSMapIndexList_Get +@ stub ADL_Display_SLSMapIndex_Get +@ stub ADL_Display_SLSMiddleMode_Get +@ stub ADL_Display_SLSMiddleMode_Set +@ stub ADL_Display_SLSRecords_Get +@ stub ADL_Display_Sharpness_Caps +@ stub ADL_Display_Sharpness_Get +@ stub ADL_Display_Sharpness_Info_Get +@ stub ADL_Display_Sharpness_Set +@ stub ADL_Display_Size_Get +@ stub ADL_Display_Size_Set +@ stub ADL_Display_SourceContentAttribute_Get +@ stub ADL_Display_SourceContentAttribute_Set +@ stub ADL_Display_SplitDisplay_Caps +@ stub ADL_Display_SplitDisplay_Get +@ stub ADL_Display_SplitDisplay_RestoreDesktopConfiguration +@ stub ADL_Display_SplitDisplay_Set +@ stub ADL_Display_SupportedColorDepth_Get +@ stub ADL_Display_SupportedPixelFormat_Get +@ stub ADL_Display_SwitchingCapability_Get +@ stub ADL_Display_TVCaps_Get +@ stub ADL_Display_TargetTiming_Get +@ stub ADL_Display_UnderScan_Auto_Get +@ stub ADL_Display_UnderScan_Auto_Set +@ stub ADL_Display_Underscan_Get +@ stub ADL_Display_Underscan_Set +@ stub ADL_Display_Vector_Get +@ stub ADL_Display_ViewPort_Cap +@ stub ADL_Display_ViewPort_Get +@ stub ADL_Display_ViewPort_Set +@ stub ADL_Display_WriteAndReadI2C +@ stub ADL_Display_WriteAndReadI2CLargePayload +@ stub ADL_Display_WriteAndReadI2CRev_Get +@ stub ADL_Flush_Driver_Data +@ cdecl ADL_Graphics_Platform_Get(ptr) +@ cdecl ADL_Graphics_Versions_Get(ptr) +@ stub ADL_MMD_FeatureList_Get +@ stub ADL_MMD_FeatureValuesX2_Get +@ stub ADL_MMD_FeatureValuesX2_Set +@ stub ADL_MMD_FeatureValues_Get +@ stub ADL_MMD_FeatureValues_Set +@ stub ADL_MMD_FeaturesX2_Caps +@ stub ADL_MMD_Features_Caps +@ stub ADL_MMD_VideoAdjustInfo_Get +@ stub ADL_MMD_VideoAdjustInfo_Set +@ stub ADL_MMD_VideoColor_Caps +@ stub ADL_MMD_VideoColor_Get +@ stub ADL_MMD_VideoColor_Set +@ stub ADL_MMD_Video_Caps +@ stub ADL_Main_ControlX2_Create +@ cdecl ADL_Main_Control_Create(ptr long) +@ cdecl ADL_Main_Control_Destroy() +@ stub ADL_Main_Control_GetProcAddress +@ stub ADL_Main_Control_IsFunctionValid +@ stub ADL_Main_Control_Refresh +@ stub ADL_Main_LogDebug_Set +@ stub ADL_Main_LogError_Set +@ stub ADL_Overdrive5_CurrentActivity_Get +@ stub ADL_Overdrive5_FanSpeedInfo_Get +@ stub ADL_Overdrive5_FanSpeedToDefault_Set +@ stub ADL_Overdrive5_FanSpeed_Get +@ stub ADL_Overdrive5_FanSpeed_Set +@ stub ADL_Overdrive5_ODParameters_Get +@ stub ADL_Overdrive5_ODPerformanceLevels_Get +@ stub ADL_Overdrive5_ODPerformanceLevels_Set +@ stub ADL_Overdrive5_PowerControlAbsValue_Caps +@ stub ADL_Overdrive5_PowerControlAbsValue_Get +@ stub ADL_Overdrive5_PowerControlAbsValue_Set +@ stub ADL_Overdrive5_PowerControlInfo_Get +@ stub ADL_Overdrive5_PowerControl_Caps +@ stub ADL_Overdrive5_PowerControl_Get +@ stub ADL_Overdrive5_PowerControl_Set +@ stub ADL_Overdrive5_Temperature_Get +@ stub ADL_Overdrive5_ThermalDevices_Enum +@ stub ADL_Overdrive6_AdvancedFan_Caps +@ stub ADL_Overdrive6_CapabilitiesEx_Get +@ stub ADL_Overdrive6_Capabilities_Get +@ stub ADL_Overdrive6_CurrentStatus_Get +@ stub ADL_Overdrive6_FanPWMLimitData_Get +@ stub ADL_Overdrive6_FanPWMLimitData_Set +@ stub ADL_Overdrive6_FanPWMLimitRangeInfo_Get +@ stub ADL_Overdrive6_FanSpeed_Get +@ stub ADL_Overdrive6_FanSpeed_Reset +@ stub ADL_Overdrive6_FanSpeed_Set +@ stub ADL_Overdrive6_FuzzyController_Caps +@ stub ADL_Overdrive6_MaxClockAdjust_Get +@ stub ADL_Overdrive6_PowerControlInfo_Get +@ stub ADL_Overdrive6_PowerControl_Caps +@ stub ADL_Overdrive6_PowerControl_Get +@ stub ADL_Overdrive6_PowerControl_Set +@ stub ADL_Overdrive6_StateEx_Get +@ stub ADL_Overdrive6_StateEx_Set +@ stub ADL_Overdrive6_StateInfo_Get +@ stub ADL_Overdrive6_State_Reset +@ stub ADL_Overdrive6_State_Set +@ stub ADL_Overdrive6_TargetTemperatureData_Get +@ stub ADL_Overdrive6_TargetTemperatureData_Set +@ stub ADL_Overdrive6_TargetTemperatureRangeInfo_Get +@ stub ADL_Overdrive6_Temperature_Get +@ stub ADL_Overdrive6_ThermalController_Caps +@ stub ADL_Overdrive6_ThermalLimitUnlock_Get +@ stub ADL_Overdrive6_ThermalLimitUnlock_Set +@ stub ADL_Overdrive6_VoltageControlInfo_Get +@ stub ADL_Overdrive6_VoltageControl_Get +@ stub ADL_Overdrive6_VoltageControl_Set +@ stub ADL_Overdrive_Caps +@ stub ADL_PowerXpress_AncillaryDevices_Get +@ stub ADL_PowerXpress_Config_Caps +@ stub ADL_PowerXpress_ExtendedBatteryMode_Caps +@ stub ADL_PowerXpress_ExtendedBatteryMode_Get +@ stub ADL_PowerXpress_ExtendedBatteryMode_Set +@ stub ADL_PowerXpress_LongIdleDetect_Get +@ stub ADL_PowerXpress_LongIdleDetect_Set +@ stub ADL_PowerXpress_PowerControlMode_Get +@ stub ADL_PowerXpress_PowerControlMode_Set +@ stub ADL_PowerXpress_Scheme_Get +@ stub ADL_PowerXpress_Scheme_Set +@ stub ADL_Remap +@ stub ADL_RemoteDisplay_Destroy +@ stub ADL_RemoteDisplay_Display_Acquire +@ stub ADL_RemoteDisplay_Display_Release +@ stub ADL_RemoteDisplay_Display_Release_All +@ stub ADL_RemoteDisplay_Hdcp20_Create +@ stub ADL_RemoteDisplay_Hdcp20_Destroy +@ stub ADL_RemoteDisplay_Hdcp20_Notify +@ stub ADL_RemoteDisplay_Hdcp20_Process +@ stub ADL_RemoteDisplay_IEPort_Set +@ stub ADL_RemoteDisplay_Initialize +@ stub ADL_RemoteDisplay_Nofitiation_Register +@ stub ADL_RemoteDisplay_Notification_UnRegister +@ stub ADL_RemoteDisplay_Support_Caps +@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_InUse_Get +@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_Info_Get +@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_RadioState_Get +@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Change +@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Get +@ stub ADL_RemoteDisplay_WFDDeviceInfo_Get +@ stub ADL_RemoteDisplay_WFDDeviceName_Change +@ stub ADL_RemoteDisplay_WFDDevice_StatusInfo_Get +@ stub ADL_RemoteDisplay_WFDDiscover_Start +@ stub ADL_RemoteDisplay_WFDDiscover_Stop +@ stub ADL_RemoteDisplay_WFDLink_Connect +@ stub ADL_RemoteDisplay_WFDLink_Creation_Accept +@ stub ADL_RemoteDisplay_WFDLink_Disconnect +@ stub ADL_RemoteDisplay_WFDLink_WPS_Process +@ stub ADL_RemoteDisplay_WFDWDSPSettings_Set +@ stub ADL_RemoteDisplay_WirelessDisplayEnableDisable_Commit +@ stub ADL_ScreenPoint_AudioMappingInfo_Get +@ stub ADL_Stereo3D_2DPackedFormat_Set +@ stub ADL_Stereo3D_3DCursorOffset_Get +@ stub ADL_Stereo3D_3DCursorOffset_Set +@ stub ADL_Stereo3D_CurrentFormat_Get +@ stub ADL_Stereo3D_Info_Get +@ stub ADL_Stereo3D_Modes_Get +@ stub ADL_TV_Standard_Get +@ stub ADL_TV_Standard_Set +@ stub ADL_Win_IsHybridAI +@ stub ADL_Workstation_8BitGrayscale_Get +@ stub ADL_Workstation_8BitGrayscale_Set +@ stub ADL_Workstation_AdapterNumOfGLSyncConnectors_Get +@ stub ADL_Workstation_Caps +@ stub ADL_Workstation_DeepBitDepthX2_Get +@ stub ADL_Workstation_DeepBitDepthX2_Set +@ stub ADL_Workstation_DeepBitDepth_Get +@ stub ADL_Workstation_DeepBitDepth_Set +@ stub ADL_Workstation_DisplayGLSyncMode_Get +@ stub ADL_Workstation_DisplayGLSyncMode_Set +@ stub ADL_Workstation_DisplayGenlockCapable_Get +@ stub ADL_Workstation_ECCData_Get +@ stub ADL_Workstation_ECCX2_Get +@ stub ADL_Workstation_ECC_Caps +@ stub ADL_Workstation_ECC_Get +@ stub ADL_Workstation_ECC_Set +@ stub ADL_Workstation_GLSyncCounters_Get +@ stub ADL_Workstation_GLSyncGenlockConfiguration_Get +@ stub ADL_Workstation_GLSyncGenlockConfiguration_Set +@ stub ADL_Workstation_GLSyncModuleDetect_Get +@ stub ADL_Workstation_GLSyncModuleInfo_Get +@ stub ADL_Workstation_GLSyncPortState_Get +@ stub ADL_Workstation_GLSyncPortState_Set +@ stub ADL_Workstation_GLSyncSupportedTopology_Get +@ stub ADL_Workstation_GlobalEDIDPersistence_Get +@ stub ADL_Workstation_GlobalEDIDPersistence_Set +@ stub ADL_Workstation_LoadBalancing_Caps +@ stub ADL_Workstation_LoadBalancing_Get +@ stub ADL_Workstation_LoadBalancing_Set +@ stub ADL_Workstation_RAS_Get_Error_Counts +@ stub ADL_Workstation_RAS_Get_Features +@ stub ADL_Workstation_RAS_Reset_Error_Counts +@ stub ADL_Workstation_RAS_Set_Features +@ stub ADL_Workstation_SDISegmentList_Get +@ stub ADL_Workstation_SDI_Caps +@ stub ADL_Workstation_SDI_Get +@ stub ADL_Workstation_SDI_Set +@ stub ADL_Workstation_Stereo_Get +@ stub ADL_Workstation_Stereo_Set +@ stub ADL_Workstation_UnsupportedDisplayModes_Enable +@ stub AmdPowerXpressRequestHighPerformance +@ stub Desktop_Detach +@ stub Send +@ stub SendX2 diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c new file mode 100644 index 000000000000..1d840aa5a7b1 --- /dev/null +++ b/dlls/atiadlxx/atiadlxx_main.c @@ -0,0 +1,1077 @@ +/* Headers: https://github.com/GPUOpen-LibrariesAndSDKs/display-library */ + +#include +#include +#include + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "objbase.h" +#include "initguid.h" +#include "wine/debug.h" +#include "cfgmgr32.h" +#include "devpkey.h" +#include "ntddvdeo.h" +#include "math.h" + +#include "dxgi1_6.h" + +#define MAX_GPUS 64 +#define VENDOR_AMD 0x1002 + +#define ADL_OK 0 +#define ADL_ERR -1 +#define ADL_ERR_INVALID_PARAM -3 +#define ADL_ERR_INVALID_ADL_IDX -5 +#define ADL_ERR_NOT_SUPPORTED -8 +#define ADL_ERR_NULL_POINTER -9 +#define ADL_ERR_INVALID_CALLBACK -11 + +#define ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED 0x00000001 +#define ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED 0x00000002 +#define ADL_DISPLAY_DISPLAYINFO_MASK 0x31fff + +#define ADL_ASIC_DISCRETE (1 << 0) +#define ADL_ASIC_MASK 0xAF + +#define ADL_MAX_PATH 256 + +enum ADLPlatForm +{ + GRAPHICS_PLATFORM_DESKTOP = 0, + GRAPHICS_PLATFORM_MOBILE = 1 +}; +#define GRAPHICS_PLATFORM_UNKNOWN -1 + + +WINE_DEFAULT_DEBUG_CHANNEL(atiadlxx); + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) +{ + TRACE("(%p, %u, %p)\n", instance, reason, reserved); + + switch (reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(instance); + break; + } + + return TRUE; +} + +typedef void *(CALLBACK *ADL_MAIN_MALLOC_CALLBACK)(int); + +typedef struct ADLVersionsInfo +{ + char strDriverVer[ADL_MAX_PATH]; + char strCatalystVersion[ADL_MAX_PATH]; + char strCatalystWebLink[ADL_MAX_PATH]; +} ADLVersionsInfo, *LPADLVersionsInfo; + +typedef struct ADLVersionsInfoX2 +{ + char strDriverVer[ADL_MAX_PATH]; + char strCatalystVersion[ADL_MAX_PATH]; + char strCrimsonVersion[ADL_MAX_PATH]; + char strCatalystWebLink[ADL_MAX_PATH]; +} ADLVersionsInfoX2, *LPADLVersionsInfoX2; + +typedef struct ADLAdapterInfo { + int iSize; + int iAdapterIndex; + char strUDID[ADL_MAX_PATH]; + int iBusNumber; + int iDeviceNumber; + int iFunctionNumber; + int iVendorID; + char strAdapterName[ADL_MAX_PATH]; + char strDisplayName[ADL_MAX_PATH]; + int iPresent; + int iExist; + char strDriverPath[ADL_MAX_PATH]; + char strDriverPathExt[ADL_MAX_PATH]; + char strPNPString[ADL_MAX_PATH]; + int iOSDisplayIndex; +} ADLAdapterInfo, *LPADLAdapterInfo; + +typedef struct ADLGraphicCoreInfo +{ + int iGCGen; + + union + { + int iNumCUs; + int iNumWGPs; + }; + + union + { + int iNumPEsPerCU; + int iNumPEsPerWGP; + }; + + int iNumSIMDs; + int iNumROPs; + int iReserved[11]; +} ADLGraphicCoreInfo; + +typedef struct ADLDisplayID +{ + int iDisplayLogicalIndex; + int iDisplayPhysicalIndex; + int iDisplayLogicalAdapterIndex; + int iDisplayPhysicalAdapterIndex; +} ADLDisplayID, *LPADLDisplayID; + +typedef struct ADLDisplayInfo +{ + ADLDisplayID displayID; + int iDisplayControllerIndex; + char strDisplayName[ADL_MAX_PATH]; + char strDisplayManufacturerName[ADL_MAX_PATH]; + int iDisplayType; + int iDisplayOutputType; + int iDisplayConnector; + int iDisplayInfoMask; + int iDisplayInfoValue; +} ADLDisplayInfo, *LPADLDisplayInfo; + +typedef struct ADLCrossfireComb +{ + int iNumLinkAdapter; + int iAdaptLink[3]; +} ADLCrossfireComb; + +typedef struct ADLCrossfireInfo +{ + int iErrorCode; + int iState; + int iSupported; +} ADLCrossfireInfo; + +typedef struct ADLMemoryInfo +{ + long long iMemorySize; + char strMemoryType[ADL_MAX_PATH]; + long long iMemoryBandwidth; +} ADLMemoryInfo, *LPADLMemoryInfo; + +typedef struct ADLDisplayTarget +{ + ADLDisplayID displayID; + int iDisplayMapIndex; + int iDisplayTargetMask; + int iDisplayTargetValue; +} ADLDisplayTarget, *LPADLDisplayTarget; + +typedef struct ADLMode +{ + int iAdapterIndex; + ADLDisplayID displayID; + int iXPos; + int iYPos; + int iXRes; + int iYRes; + int iColourDepth; + float fRefreshRate; + int iOrientation; + int iModeFlag; + int iModeMask; + int iModeValue; +} ADLMode, *LPADLMode; + +typedef struct ADLDisplayMap +{ + int iDisplayMapIndex; + ADLMode displayMode; + int iNumDisplayTarget; + int iFirstDisplayTargetArrayIndex; + int iDisplayMapMask; + int iDisplayMapValue; +} ADLDisplayMap, *LPADLDisplayMap; + +#define ADL_MAX_DISPLAY_NAME 256 + +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB656 0x00000001 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB666 0x00000002 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB888 0x00000004 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB101010 0x00000008 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB161616 0x00000010 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB_RESERVED1 0x00000020 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB_RESERVED2 0x00000040 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB_RESERVED3 0x00000080 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_XRGB_BIAS101010 0x00000100 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR444_8BPCC 0x00000200 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR444_10BPCC 0x00000400 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR444_12BPCC 0x00000800 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR422_8BPCC 0x00001000 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR422_10BPCC 0x00002000 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR422_12BPCC 0x00004000 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR420_8BPCC 0x00008000 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR420_10BPCC 0x00010000 +#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR420_12BPCC 0x00020000 + +#define ADL_TF_sRGB 0x0001 +#define ADL_TF_BT709 0x0002 +#define ADL_TF_PQ2084 0x0004 +#define ADL_TF_PQ2084_INTERIM 0x0008 +#define ADL_TF_LINEAR_0_1 0x0010 +#define ADL_TF_LINEAR_0_125 0x0020 +#define ADL_TF_DOLBYVISION 0x0040 +#define ADL_TF_GAMMA_22 0x0080 + +#define ADL_CS_sRGB 0x0001 +#define ADL_CS_BT601 0x0002 +#define ADL_CS_BT709 0x0004 +#define ADL_CS_BT2020 0x0008 +#define ADL_CS_ADOBE 0x0010 +#define ADL_CS_P3 0x0020 +#define ADL_CS_scRGB_MS_REF 0x0040 +#define ADL_CS_DISPLAY_NATIVE 0x0080 +#define ADL_CS_APP_CONTROL 0x0100 +#define ADL_CS_DOLBYVISION 0x0200 + +typedef struct ADLDDCInfo2 +{ + int ulSize; + int ulSupportsDDC; + int ulManufacturerID; + int ulProductID; + char cDisplayName[ADL_MAX_DISPLAY_NAME]; + int ulMaxHResolution; + int ulMaxVResolution; + int ulMaxRefresh; + int ulPTMCx; + int ulPTMCy; + int ulPTMRefreshRate; + int ulDDCInfoFlag; + int bPackedPixelSupported; + int iPanelPixelFormat; + int ulSerialID; + int ulMinLuminanceData; + int ulAvgLuminanceData; + int ulMaxLuminanceData; + int iSupportedTransferFunction; + int iSupportedColorSpace; + int iNativeDisplayChromaticityRedX; + int iNativeDisplayChromaticityRedY; + int iNativeDisplayChromaticityGreenX; + int iNativeDisplayChromaticityGreenY; + int iNativeDisplayChromaticityBlueX; + int iNativeDisplayChromaticityBlueY; + int iNativeDisplayChromaticityWhitePointX; + int iNativeDisplayChromaticityWhitePointY; + int iDiffuseScreenReflectance; + int iSpecularScreenReflectance; + int iSupportedHDR; + int iFreesyncFlags; + int ulMinLuminanceNoDimmingData; + int ulMaxBacklightMaxLuminanceData; + int ulMinBacklightMaxLuminanceData; + int ulMaxBacklightMinLuminanceData; + int ulMinBacklightMinLuminanceData; + int ulScreenWidth; + int ulScreenHeight; + int iReserved[2]; +} ADLDDCInfo2; + +static const ADLVersionsInfo version = { + "99.19.02-230831a-396538C-AMD-Software-Adrenalin-Edition", + "", + "http://support.amd.com/drivers/xml/driver_09_us.xml", +}; + +static const ADLVersionsInfoX2 version2 = { + "99.19.02-230831a-396538C-AMD-Software-Adrenalin-Edition", + "", + "99.10.2", + "http://support.amd.com/drivers/xml/driver_09_us.xml", +}; + +static void ascii_from_unicode( char *dst, const WCHAR *src ) +{ + while ((*dst++ = *src++)) + ; +} + +DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2); + +struct monitor +{ + UINT32 output_id; + int logical_adapter_index; + int physical_adapter_index; + char display_name[ADL_MAX_PATH]; + DXGI_OUTPUT_DESC1 dxgi_output_desc; + BOOL found_dxgi_output; + DISPLAYCONFIG_SOURCE_MODE mode; + DISPLAYCONFIG_RATIONAL refresh_rate; + DISPLAYCONFIG_ROTATION rotation; +}; + +struct gpu +{ + LUID luid; + char device_string[256]; + char device_path[256]; + struct monitor *displays; + UINT32 vendor_id; + int display_count; + int adapter_count; + int first_adapter_index; + DXGI_ADAPTER_DESC1 dxgi_adapter_desc; +}; + +struct adapter +{ + struct gpu *gpu; + struct monitor *display; + UINT32 source_id; + char gdi_device_name[32]; + char driver_path[256]; + BOOL active; +}; + +typedef struct adl_context +{ + ADL_MAIN_MALLOC_CALLBACK malloc; + + struct gpu *gpus; + int gpu_count; + + struct adapter *adapters; + int adapter_count; +} +*ADL_CONTEXT_HANDLE; + +static ADL_CONTEXT_HANDLE default_ctx; + +int CDECL ADL2_Main_Control_Destroy(ADL_CONTEXT_HANDLE ctx) +{ + int i; + + TRACE("ctx %p.\n", ctx); + + if (!ctx) return ADL_ERR; + if (ctx == default_ctx) default_ctx = NULL; + + for (i = 0; i < ctx->gpu_count; ++i) + free(ctx->gpus[i].displays); + + free(ctx->adapters); + free(ctx->gpus); + free(ctx); + return ADL_OK; +} + +static int init_info(ADL_CONTEXT_HANDLE ctx) +{ + DISPLAYCONFIG_PATH_INFO *paths = NULL; + DISPLAYCONFIG_MODE_INFO *modes = NULL; + DXGI_ADAPTER_DESC1 adapter_desc; + DXGI_OUTPUT_DESC1 output_desc1; + IDXGIFactory1 *dxgi_factory = NULL; + UINT32 path_count, mode_count; + WCHAR *gpu_iface_list = NULL, *p; + IDXGIAdapter1 *dxgi_adapter; + IDXGIOutput *output; + DISPLAY_DEVICEA dd; + IDXGIOutput6 *output6; + unsigned int i, j, k, count; + int err = ADL_ERR; + struct monitor *display; + struct adapter *adapter; + struct gpu *gpu; + char buffer[256]; + WCHAR instance_id[256]; + DEVPROPTYPE type; + DWORD ret; + ULONG size; + + if (FAILED(CreateDXGIFactory1(&IID_IDXGIFactory1, (void**)&dxgi_factory))) + goto done; + + if (CM_Get_Device_Interface_List_SizeW(&size, &GUID_DEVINTERFACE_DISPLAY_ADAPTER, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT)) + goto done; + + gpu_iface_list = malloc(size * sizeof(*gpu_iface_list)); + if (CM_Get_Device_Interface_ListW(&GUID_DEVINTERFACE_DISPLAY_ADAPTER, NULL, gpu_iface_list, size, CM_GET_DEVICE_INTERFACE_LIST_PRESENT)) + goto done; + + /* Get GPUs. */ + p = gpu_iface_list; + count = ctx->adapter_count; + while (*p) + { + DEVINST devinst; + + ascii_from_unicode(buffer, p); + ctx->gpus = realloc(ctx->gpus, (ctx->gpu_count + 1) * sizeof(*ctx->gpus)); + memset(&ctx->gpus[ctx->gpu_count], 0, sizeof(*ctx->gpus)); + strcpy(ctx->gpus[ctx->gpu_count].device_path, buffer); + size = ARRAY_SIZE(instance_id); + if (CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0)) + continue; + if (CM_Locate_DevNodeW(&devinst, instance_id, 0)) + continue; + size = sizeof(ctx->gpus[i].luid); + if (CM_Get_DevNode_PropertyW(devinst, &DEVPROPKEY_GPU_LUID, &type, &ctx->gpus[ctx->gpu_count].luid, &size, 0)) + continue; + + ++ctx->gpu_count; + p += wcslen(p) + 1; + } + ctx->adapter_count = count; + free(gpu_iface_list); + + /* Get adapters and monitors. */ + do + { + if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &path_count, &mode_count)) + goto done; + + paths = realloc(paths, sizeof(*paths) * path_count); + modes = realloc(modes, sizeof(*modes) * mode_count); + + ret = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &path_count, paths, &mode_count, modes, NULL); + } while (ret == ERROR_INSUFFICIENT_BUFFER); + if (ret) goto done; + + for (i = 0; i < path_count; ++i) + { + DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name; + DISPLAYCONFIG_TARGET_DEVICE_NAME target_name; + + for (j = 0; j < ctx->gpu_count; ++j) + { + if (!memcmp(&ctx->gpus[j].luid, &paths[i].sourceInfo.adapterId, sizeof(ctx->gpus[j].luid))) break; + } + if (j == ctx->gpu_count) + { + ERR("Adapter luid %#x:%#x not found in gpu list.\n", + (int)paths[i].sourceInfo.adapterId.HighPart, (int)paths[i].sourceInfo.adapterId.LowPart ); + continue; + } + gpu = &ctx->gpus[j]; + + for (j = 0; j < ctx->adapter_count; ++j) + { + if (ctx->adapters[j].source_id == paths[i].sourceInfo.id) break; + } + if (j == ctx->adapter_count) + { + ctx->adapters = realloc(ctx->adapters, (j + 1) * sizeof(*ctx->adapters)); + adapter = &ctx->adapters[j]; + memset(adapter, 0, sizeof(*ctx->adapters)); + adapter->gpu = gpu; + adapter->source_id = paths[i].sourceInfo.id; + + source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source_name.header.size = sizeof(source_name); + source_name.header.adapterId = paths[i].sourceInfo.adapterId; + source_name.header.id = paths[i].sourceInfo.id; + if (DisplayConfigGetDeviceInfo(&source_name.header)) goto done; + ascii_from_unicode(adapter->gdi_device_name, source_name.viewGdiDeviceName); + + if (!gpu->adapter_count) gpu->first_adapter_index = ctx->adapter_count; + ++ctx->adapter_count; + ++gpu->adapter_count; + } + else adapter = &ctx->adapters[j]; + + for (j = 0; j < gpu->display_count; ++j) + { + if (paths[i].targetInfo.id == gpu->displays[j].output_id) break; + } + + if (j == gpu->display_count) + { + gpu->displays = realloc(gpu->displays, (gpu->display_count + 1) * sizeof(*gpu->displays)); + display = &gpu->displays[gpu->display_count]; + memset(display, 0, sizeof(*gpu->displays)); + display->output_id = paths[i].targetInfo.id; + display->physical_adapter_index = gpu->first_adapter_index; + display->logical_adapter_index = adapter - &ctx->adapters[0]; + target_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + target_name.header.size = sizeof(target_name); + target_name.header.adapterId = paths[i].targetInfo.adapterId; + target_name.header.id = paths[i].targetInfo.id; + if (DisplayConfigGetDeviceInfo(&target_name.header)) goto done; + ascii_from_unicode(display->display_name, target_name.monitorFriendlyDeviceName); + display->mode = modes[paths[i].sourceInfo.modeInfoIdx].sourceMode; + display->refresh_rate = paths[i].targetInfo.refreshRate; + display->rotation = paths[i].targetInfo.rotation; + if (adapter->display) + ERR("Display is already assigned for adapter %s.\n", adapter->gdi_device_name); + adapter->display = display; + adapter->active = TRUE; + ++gpu->display_count; + } + } + + /* Get driver path and device name for adapters. */ + dd.cb = sizeof(dd); + for (i = 0; EnumDisplayDevicesA(NULL, i, &dd, EDD_GET_DEVICE_INTERFACE_NAME); ++i) + { + for (j = 0; j < ctx->adapter_count; ++j) + { + if (stricmp(ctx->adapters[i].gdi_device_name, dd.DeviceName)) continue; + strcpy(ctx->adapters[i].gpu->device_string, dd.DeviceString); + strcpy(ctx->adapters[i].driver_path, dd.DeviceKey); + } + } + + /* Fake adapters for GPUs without outputs. */ + for (i = 0; i < ctx->gpu_count; ++i) + { + gpu = &ctx->gpus[i]; + if (gpu->adapter_count) continue; + ctx->adapters = realloc(ctx->adapters, (ctx->adapter_count + 1) * sizeof(*ctx->adapters)); + adapter = &ctx->adapters[ctx->adapter_count]; + memset(adapter, 0, sizeof(*ctx->adapters)); + adapter->gpu = gpu; + gpu->first_adapter_index = ctx->adapter_count; + ++gpu->adapter_count; + ++ctx->adapter_count; + sprintf(adapter->gdi_device_name, "\\\\.\\DISPLAY%d", ctx->adapter_count); + ERR("No adapter for GPU %s, using fake %s.\n", gpu->device_string, adapter->gdi_device_name); + } + + /* Initialize info queried from dxgi. */ + for (i = 0; !IDXGIFactory1_EnumAdapters1(dxgi_factory, i, &dxgi_adapter); ++i) + { + if (FAILED(IDXGIAdapter1_GetDesc1(dxgi_adapter, &adapter_desc))) + { + IDXGIAdapter1_Release(dxgi_adapter); + continue; + } + + for (j = 0; j < ctx->gpu_count; ++j) + { + if (memcmp(&adapter_desc.AdapterLuid, &ctx->gpus[j].luid, sizeof(adapter_desc.AdapterLuid))) continue; + gpu = &ctx->gpus[j]; + gpu->dxgi_adapter_desc = adapter_desc; + gpu->vendor_id = adapter_desc.VendorId; + if (!gpu->device_string[0]) + ascii_from_unicode(gpu->device_string, adapter_desc.Description); + break; + } + if (j == ctx->gpu_count) + ERR("Could not find gpu for dxgi adapter device %s.\n", debugstr_w(adapter_desc.Description)); + + for (j = 0; !IDXGIAdapter1_EnumOutputs(dxgi_adapter, j, &output); ++j) + { + if (IDXGIOutput_QueryInterface(output, &IID_IDXGIOutput6, (void**)&output6)) + { + IDXGIOutput_Release(output); + continue; + } + if (IDXGIOutput6_GetDesc1(output6, &output_desc1)) + { + IDXGIOutput_Release(output); + IDXGIOutput6_Release(output6); + continue; + } + + ascii_from_unicode(buffer, output_desc1.DeviceName); + for (k = 0; k < ctx->adapter_count; ++k) + { + adapter = &ctx->adapters[k]; + if (stricmp(buffer, adapter->gdi_device_name) || !adapter->display) continue; + adapter->display->dxgi_output_desc = output_desc1; + adapter->display->found_dxgi_output = TRUE; + adapter->active = TRUE; + break; + } + if (k == ctx->adapter_count) + ERR("No adapter found for dxgi output %s.\n", debugstr_w(output_desc1.DeviceName)); + IDXGIOutput6_Release(output6); + IDXGIOutput_Release(output); + } + IDXGIAdapter1_Release(dxgi_adapter); + } + for (i = 0; i < ctx->adapter_count; ++i) + { + if (!(display = ctx->adapters[i].display)) continue; + if (!display->found_dxgi_output) + { + ERR("No dxgi output found for display %d, %s, adapter %d, %s.\n", + i, display->display_name, display->logical_adapter_index, + ctx->adapters[i].gdi_device_name); + } + } + err = ADL_OK; + +done: + free(paths); + free(modes); + if (dxgi_factory) IDXGIFactory1_Release(dxgi_factory); + return err; +} + +int CDECL ADL2_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg, ADL_CONTEXT_HANDLE *ptr) +{ + ADL_CONTEXT_HANDLE ctx; + int ret; + + TRACE("cb %p, arg %d, ptr %p.\n", cb, arg, ptr); + + ctx = calloc( 1, sizeof(**ptr)); + ctx->malloc = cb; + if ((ret = init_info(ctx))) + { + ERR("Initialization failed.\n"); + ADL2_Main_Control_Destroy(ctx); + return ret; + } + if (default_ctx) ADL2_Main_Control_Destroy(default_ctx); + default_ctx = ctx; + *ptr = ctx; + TRACE("-> %p.\n", *ptr); + return ADL_OK; +} + +int CDECL ADL_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg) +{ + TRACE("cb %p, arg %d.\n", cb, arg); + + return ADL2_Main_Control_Create(cb, arg, &default_ctx); +} + +int CDECL ADL_Main_Control_Destroy(void) +{ + TRACE(".\n"); + + return ADL2_Main_Control_Destroy(default_ctx); +} + +int CDECL ADL2_Adapter_NumberOfAdapters_Get(ADL_CONTEXT_HANDLE ctx, int *count) +{ + TRACE("ctx %p, count %p.\n", ctx, count); + + *count = ctx->adapter_count; + TRACE("*count = %d\n", *count); + return ADL_OK; +} + +int CDECL ADL2_Graphics_VersionsX2_Get(ADL_CONTEXT_HANDLE ptr, ADLVersionsInfoX2 *ver) +{ + TRACE("ptr %p, ver %p.\n", ptr, ver); + memcpy(ver, &version2, sizeof(version2)); + return ADL_OK; +} + +int CDECL ADL_Graphics_Versions_Get(ADLVersionsInfo *ver) +{ + TRACE("ver %p.\n", ver); + memcpy(ver, &version, sizeof(version)); + return ADL_OK; +} + +int CDECL ADL_Adapter_NumberOfAdapters_Get(int *count) +{ + TRACE("count %p.\n", count); + + return ADL2_Adapter_NumberOfAdapters_Get(default_ctx, count); +} + +/* yep, seriously */ +static int convert_vendor_id(int id) +{ + char str[16]; + snprintf(str, ARRAY_SIZE(str), "%x", id); + return atoi(str); +} + +static int adapter_info_get(ADL_CONTEXT_HANDLE ctx, ADLAdapterInfo *adapters, int input_size) +{ + int i, count = input_size / sizeof(*adapters); + char buffer[256], *p; + + memset(adapters, 0, input_size); + + for (i = 0; i < count; i++) + { + adapters[i].iSize = sizeof(ADLAdapterInfo); + adapters[i].iAdapterIndex = i; + adapters[i].iOSDisplayIndex = i; + + strcpy(buffer, ctx->adapters[i].gpu->device_path + 4); + if ((p = strrchr(buffer, '#'))) *p = 0; + for (p = buffer; *p; ++p) + if (*p == '#') *p = '\\'; + if (ctx->adapters[i].source_id) + sprintf(adapters[i].strPNPString, "%s&%02d", buffer, ctx->adapters[i].source_id + 1); + else + strcpy(adapters[i].strPNPString, buffer); + strcpy(adapters[i].strUDID, adapters[i].strPNPString); + for (p = adapters[i].strUDID; *p; ++p) + if (*p == '\\') *p = '_'; + *p++ = 'A'; + *p = 0; + + adapters[i].iVendorID = convert_vendor_id(ctx->adapters[i].gpu->vendor_id); + strcpy(adapters[i].strAdapterName, ctx->adapters[i].gpu->device_string); + strcpy(adapters[i].strDisplayName, ctx->adapters[i].gdi_device_name); + strcpy(adapters[i].strDriverPath, ctx->adapters[i].driver_path); + } + return ADL_OK; +} + +int CDECL ADL_Adapter_AdapterInfo_Get(ADLAdapterInfo *adapters, int input_size) +{ + TRACE("adapters %p, input_size %d.\n", adapters, input_size); + + if (!adapters) return ADL_ERR_INVALID_PARAM; + if (input_size != default_ctx->adapter_count * sizeof(ADLAdapterInfo)) return ADL_ERR_INVALID_PARAM; + + return adapter_info_get(default_ctx, adapters, input_size); +} + +int CDECL ADL2_Adapter_AdapterInfoX2_Get(ADL_CONTEXT_HANDLE ctx, ADLAdapterInfo **info) +{ + TRACE("ctx %p, info %p.\n", ctx, info); + + *info = ctx->malloc( ctx->adapter_count * sizeof(**info) ); + return adapter_info_get(ctx, *info, ctx->adapter_count * sizeof(**info)); +} + +int CDECL ADL2_Adapter_Active_Get(ADL_CONTEXT_HANDLE ctx, int adapter_index, int *status) +{ + TRACE("ctx %p, adapter_index %d, status %p.\n", ctx, adapter_index, status); + + if (adapter_index >= ctx->adapter_count) return ADL_ERR_INVALID_ADL_IDX; + *status = ctx->adapters[adapter_index].active; + return ADL_OK; +} + +int CDECL ADL2_Display_DisplayInfo_Get(ADL_CONTEXT_HANDLE ctx, int adapter_index, int *num_displays, ADLDisplayInfo **info, int force_detect) +{ + struct gpu *gpu; + int i; + + TRACE("adapter %d, num_displays %p, info %p.\n", adapter_index, num_displays, info); + + if (info == NULL || num_displays == NULL) return ADL_ERR_NULL_POINTER; + + if (adapter_index >= ctx->adapter_count) return ADL_ERR_INVALID_PARAM; + + gpu = ctx->adapters[adapter_index].gpu; + *num_displays = gpu->display_count; + + *info = ctx->malloc(*num_displays * sizeof(**info)); + memset(*info, 0, *num_displays * sizeof(**info)); + + for (i = 0; i < *num_displays; i++) + { + (*info)[i].displayID.iDisplayLogicalAdapterIndex = gpu->displays[i].logical_adapter_index; + (*info)[i].displayID.iDisplayLogicalIndex = i; + (*info)[i].displayID.iDisplayPhysicalAdapterIndex = gpu->displays[i].physical_adapter_index; + (*info)[i].displayID.iDisplayPhysicalIndex = i; + strcpy((*info)[i].strDisplayName, gpu->displays[i].display_name); + (*info)[i].iDisplayType = 2 /* ADL_DT_LCD_PANEL */; + (*info)[i].iDisplayOutputType = 4 /* ADL_DOT_DIGITAL */; + (*info)[i].iDisplayInfoValue = ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED | ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED; + (*info)[i].iDisplayInfoMask = (*info)[i].iDisplayInfoValue; + } + + return ADL_OK; +} + +int CDECL ADL_Display_DisplayInfo_Get(int adapter_index, int *num_displays, ADLDisplayInfo **info, int force_detect) +{ + TRACE(".\n"); + + return ADL2_Display_DisplayInfo_Get(default_ctx, adapter_index, num_displays, info, force_detect); +} + +static int chroma_value_conv(float v) +{ + return lrintf(v * 10000); +} + +int CDECL ADL2_Display_DDCInfo2_Get(ADL_CONTEXT_HANDLE ctx, int adapter_index, int display_index, ADLDDCInfo2 *info) +{ + DXGI_OUTPUT_DESC1 *desc; + struct monitor *display; + struct gpu *gpu; + FIXME("ctx %p, adapter_index %d, display_index %d, info %p semi-stub.\n", ctx, adapter_index, + display_index, info); + memset(info, 0, sizeof(*info)); + info->ulSize = sizeof(*info); + + if (adapter_index >= ctx->adapter_count) return ADL_ERR_INVALID_PARAM; + gpu = ctx->adapters[adapter_index].gpu; + if (display_index >= gpu->display_count) return ADL_OK; + display = &gpu->displays[display_index]; + + desc = &display->dxgi_output_desc; + info->ulSupportsDDC = 1; + strcpy(info->cDisplayName, display->display_name); + info->iSupportedHDR = (desc->ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); + info->iPanelPixelFormat = ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB888; + info->iSupportedTransferFunction = ADL_TF_sRGB | ADL_TF_LINEAR_0_1; + info->iSupportedColorSpace = ADL_CS_sRGB; + if (info->iSupportedHDR) + { + TRACE("HDR is supported.\n"); + info->iPanelPixelFormat |= ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB101010; + info->iSupportedTransferFunction |= ADL_TF_PQ2084; + info->iSupportedColorSpace |= ADL_CS_BT2020; + } + info->iNativeDisplayChromaticityRedX = chroma_value_conv(desc->RedPrimary[0]); + info->iNativeDisplayChromaticityRedY = chroma_value_conv(desc->RedPrimary[1]); + info->iNativeDisplayChromaticityGreenX = chroma_value_conv(desc->GreenPrimary[0]); + info->iNativeDisplayChromaticityGreenY = chroma_value_conv(desc->GreenPrimary[1]); + info->iNativeDisplayChromaticityBlueX = chroma_value_conv(desc->BluePrimary[0]); + info->iNativeDisplayChromaticityBlueY = chroma_value_conv(desc->BluePrimary[1]); + info->iNativeDisplayChromaticityWhitePointX = chroma_value_conv(desc->WhitePoint[0]); + info->iNativeDisplayChromaticityWhitePointY = chroma_value_conv(desc->WhitePoint[1]); + + info->ulMinLuminanceData = desc->MinLuminance; + info->ulMaxLuminanceData = desc->MaxLuminance; + info->ulAvgLuminanceData = desc->MaxFullFrameLuminance; + return ADL_OK; +} + +int CDECL ADL_Adapter_Crossfire_Caps(int adapter_index, int *preffered, int *num_comb, ADLCrossfireComb** comb) +{ + FIXME("adapter %d, preffered %p, num_comb %p, comb %p stub!\n", adapter_index, preffered, num_comb, comb); + return ADL_ERR; +} + +int CDECL ADL2_Adapter_Crossfire_Caps(ADL_CONTEXT_HANDLE context, int adapter_index, int *preffered, int *num_comb, ADLCrossfireComb** comb) +{ + FIXME("context %p, adapter %d, preffered %p, num_comb %p, comb %p stub!\n", context, adapter_index, preffered, num_comb, comb); + return ADL_ERR; +} + +int CDECL ADL_Adapter_Crossfire_Get(int adapter_index, ADLCrossfireComb *comb, ADLCrossfireInfo *info) +{ + FIXME("adapter %d, comb %p, info %p, stub!\n", adapter_index, comb, info); + return ADL_ERR; +} + +int CDECL ADL2_Adapter_ASICFamilyType_Get(ADL_CONTEXT_HANDLE ctx, int adapter_index, int *asic_type, int *valids) +{ + FIXME("adapter %d, asic_type %p, valids %p, stub.\n", adapter_index, asic_type, valids); + + if (asic_type == NULL || valids == NULL) + return ADL_ERR_NULL_POINTER; + + if (ctx->adapters[adapter_index].gpu->vendor_id != VENDOR_AMD) + return ADL_ERR_NOT_SUPPORTED; + + *asic_type = ADL_ASIC_DISCRETE; + *valids = ADL_ASIC_MASK; + + return ADL_OK; +} + +int CDECL ADL_Adapter_ASICFamilyType_Get(int adapter_index, int *asic_type, int *valids) +{ + TRACE("adapter %d, asic_type %p, valids %p.\n", adapter_index, asic_type, valids); + return ADL2_Adapter_ASICFamilyType_Get(default_ctx, adapter_index, asic_type, valids); +} + +static int get_max_clock(const char *clock, int default_value) +{ + char path[MAX_PATH], line[256]; + FILE *file; + int drm_card, value = 0; + + for (drm_card = 0; drm_card < MAX_GPUS; drm_card++) + { + sprintf(path, "/sys/class/drm/card%d/device/pp_dpm_%s", drm_card, clock); + file = fopen(path, "r"); + + if (file == NULL) + continue; + + while (fgets(line, sizeof(line), file) != NULL) + { + char *number; + + number = strchr(line, ' '); + if (number == NULL) + { + WARN("pp_dpm_%s file has unexpected format\n", clock); + break; + } + + number++; + value = max(strtol(number, NULL, 0), value); + } + } + + if (value != 0) + return value; + + return default_value; +} + +/* documented in the "Linux Specific APIs" section, present and used on Windows */ +/* the name and documentation suggests that this returns current freqs, but it's actually max */ +int CDECL ADL2_Adapter_ObservedClockInfo_Get(ADL_CONTEXT_HANDLE ctx, int adapter_index, int *core_clock, int *memory_clock) +{ + FIXME("ctx %p, adapter %d, core_clock %p, memory_clock %p, stub.\n", ctx, adapter_index, core_clock, memory_clock); + + if (core_clock == NULL || memory_clock == NULL) return ADL_ERR; + if (adapter_index >= ctx->adapter_count) return ADL_ERR_INVALID_ADL_IDX; + if (ctx->adapters[adapter_index].gpu->vendor_id != VENDOR_AMD) return ADL_ERR_INVALID_ADL_IDX; + + /* default values based on RX580 */ + *core_clock = get_max_clock("sclk", 1350); + *memory_clock = get_max_clock("mclk", 2000); + + TRACE("*core_clock: %i, *memory_clock %i\n", *core_clock, *memory_clock); + + return ADL_OK; +} + +int CDECL ADL_Adapter_ObservedClockInfo_Get(int adapter_index, int *core_clock, int *memory_clock) +{ + TRACE("adapter_index %d, core_clock %p, memory_clock %p.\n", adapter_index, core_clock, memory_clock); + + return ADL2_Adapter_ObservedClockInfo_Get(default_ctx, adapter_index, core_clock, memory_clock); +} + + +int CDECL ADL2_Adapter_Graphic_Core_Info_Get(ADL_CONTEXT_HANDLE context, int adapter_index, ADLGraphicCoreInfo *info) +{ + FIXME("context %p, adapter_index %d, info %p stub.\n", context, adapter_index, info); + + memset(info, 0, sizeof(*info)); + info->iNumPEsPerCU = 1000; + info->iNumCUs = 1000; + info->iGCGen = 100; + info->iNumROPs = 10000; + info->iNumSIMDs = 10000; + return ADL_OK; +} + +/* documented in the "Linux Specific APIs" section, present and used on Windows */ +int CDECL ADL2_Adapter_MemoryInfo_Get(ADL_CONTEXT_HANDLE ctx, int adapter_index, ADLMemoryInfo *mem_info) +{ + FIXME("ctx %p, adapter %d, mem_info %p stub.\n", ctx, adapter_index, mem_info); + + if (mem_info == NULL) return ADL_ERR_NULL_POINTER; + if (adapter_index >= ctx->adapter_count) return ADL_ERR_INVALID_ADL_IDX; + if (ctx->adapters[adapter_index].gpu->vendor_id != VENDOR_AMD) return ADL_ERR; + + mem_info->iMemorySize = ctx->adapters[adapter_index].gpu->dxgi_adapter_desc.DedicatedVideoMemory; + mem_info->iMemoryBandwidth = 256000; /* not exposed on Linux, probably needs a lookup table */ + + TRACE("iMemoryBandwidth %s, iMemorySize %s\n", + wine_dbgstr_longlong(mem_info->iMemoryBandwidth), + wine_dbgstr_longlong(mem_info->iMemorySize)); + return ADL_OK; +} + +int CDECL ADL_Adapter_MemoryInfo_Get(int adapter_index, ADLMemoryInfo *mem_info) +{ + TRACE("adapter_index %d, mem_info %p.\n", adapter_index, mem_info); + + return ADL2_Adapter_MemoryInfo_Get(default_ctx, adapter_index, mem_info); +} + +int CDECL ADL2_Graphics_Platform_Get(ADL_CONTEXT_HANDLE ctx, int *platform) +{ + int i; + + FIXME("platform %p, stub.\n", platform); + + *platform = GRAPHICS_PLATFORM_UNKNOWN; + + for (i = 0; i < ctx->gpu_count; ++i) + { + if (ctx->gpus[i].vendor_id == VENDOR_AMD) + { + *platform = GRAPHICS_PLATFORM_DESKTOP; + break; + } + } + + /* NOTE: The real value can be obtained by doing: + * 1. ioctl(DRM_AMDGPU_INFO) with AMDGPU_INFO_DEV_INFO - dev_info.ids_flags & AMDGPU_IDS_FLAGS_FUSION + * 2. VkPhysicalDeviceType() if we ever want to use Vulkan directly + */ + + return ADL_OK; +} + +int CDECL ADL_Graphics_Platform_Get(int *platform) +{ + TRACE("platform %p.\n", platform); + + return ADL2_Graphics_Platform_Get(default_ctx, platform); +} + +int CDECL ADL2_Display_DisplayMapConfig_Get(ADL_CONTEXT_HANDLE ctx, int adapter_index, int *display_map_count, ADLDisplayMap **display_maps, + int *display_target_count, ADLDisplayTarget **display_targets, int options) +{ + struct gpu *gpu; + int i; + + TRACE("ctx %p, adapter_index %d, display_map_count %p, display_maps %p, " + "display_target_count %p, display_targets %p, options %d.\n", + ctx, adapter_index, display_map_count, display_maps, display_target_count, + display_targets, options); + + if (adapter_index >= ctx->adapter_count) return ADL_ERR_INVALID_ADL_IDX; + gpu = ctx->adapters[adapter_index].gpu; + if (!gpu->display_count) return ADL_ERR_NOT_SUPPORTED; + *display_map_count = gpu->display_count; + *display_maps = ctx->malloc(*display_map_count * sizeof(**display_maps)); + memset(*display_maps, 0, *display_map_count * sizeof(**display_maps)); + *display_target_count = gpu->display_count; + *display_targets = ctx->malloc(*display_target_count * sizeof(**display_targets)); + memset(*display_targets, 0, *display_target_count * sizeof(**display_targets)); + + for (i = 0; i < gpu->display_count; ++i) + { + ADLMode *m = (ADLMode *)&(*display_maps)[i].displayMode; + DISPLAYCONFIG_SOURCE_MODE *dc_mode = &gpu->displays[i].mode; + + (*display_maps)[i].iDisplayMapIndex = gpu->displays[i].logical_adapter_index; + (*display_maps)[i].iNumDisplayTarget = 1; + (*display_maps)[i].iFirstDisplayTargetArrayIndex = i; + (*display_maps)[i].iDisplayMapMask = 0xf; + (*display_maps)[i].iDisplayMapValue = 0x4; /* ADL_DISPLAY_DISPLAYMAP_MANNER_SINGLE */ + + m->displayID.iDisplayLogicalAdapterIndex = gpu->displays[i].logical_adapter_index; + m->displayID.iDisplayLogicalIndex = i; + m->iAdapterIndex = gpu->displays[i].logical_adapter_index; + m->iXPos = dc_mode->position.x; + m->iYPos = dc_mode->position.y; + m->iXRes = dc_mode->width; + m->iYRes = dc_mode->height; + m->iColourDepth = 32; + m->fRefreshRate = (float)gpu->displays[i].refresh_rate.Numerator / gpu->displays[i].refresh_rate.Denominator; + m->iOrientation = (gpu->displays[i].rotation - 1) * 90; + m->iModeMask = 0xff; + m->iModeValue = 0x46; + + (*display_targets)[i].displayID = m->displayID; + (*display_targets)[i].iDisplayMapIndex = i; + (*display_targets)[i].iDisplayTargetMask = 1; + (*display_targets)[i].iDisplayTargetValue = 1; + } + return ADL_OK; +} + +int CDECL ADL_Display_DisplayMapConfig_Get(int adapter_index, int *display_map_count, ADLDisplayMap **display_maps, + int *display_target_count, ADLDisplayTarget **display_targets, int options) +{ + TRACE("adapter_index %d, display_map_count %p, display_maps %p, " + "display_target_count %p, display_targets %p, options %d.\n", + adapter_index, display_map_count, display_maps, display_target_count, + display_targets, options); + + return ADL2_Display_DisplayMapConfig_Get(default_ctx, adapter_index, display_map_count, display_maps, + display_target_count, display_targets, options); +} diff --git a/dlls/audioses/Makefile.in b/dlls/audioses/Makefile.in new file mode 100644 index 000000000000..370949ea4fed --- /dev/null +++ b/dlls/audioses/Makefile.in @@ -0,0 +1 @@ +MODULE = audioses.dll diff --git a/dlls/audioses/audioses.spec b/dlls/audioses/audioses.spec new file mode 100644 index 000000000000..a1884e532433 --- /dev/null +++ b/dlls/audioses/audioses.spec @@ -0,0 +1,11 @@ +# @ stub AUDIOSES_1 +# @ stub AUDIOSES_2 +# @ stub AUDIOSES_3 +# @ stub AUDIOSES_4 +# @ stub AUDIOSES_5 +# @ stub DllCanUnloadNow +# @ stub AUDIOSES_7 +# @ stub DllGetActivationFactory +# @ stub DllGetClassObject +# @ stub DllRegisterServer +# @ stub DllUnregisterServer diff --git a/dlls/avifil32/api.c b/dlls/avifil32/api.c index fe0c163cf0a2..f2ed1736882f 100644 --- a/dlls/avifil32/api.c +++ b/dlls/avifil32/api.c @@ -260,6 +260,9 @@ HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode, return hr; } + if (uMode & OF_CREATE) + uMode |= OF_WRITE; + hr = IPersistFile_Load(ppersist, szFile, uMode); IPersistFile_Release(ppersist); if (FAILED(hr)) { diff --git a/dlls/avifil32/avifile.c b/dlls/avifil32/avifile.c index 719d96edf86d..6aae4736c4db 100644 --- a/dlls/avifil32/avifile.c +++ b/dlls/avifil32/avifile.c @@ -1399,9 +1399,19 @@ static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size, DW This->idxFrames[This->lLastFrame].dwChunkLength = size; /* update AVISTREAMINFO structure if necessary */ - if (This->sInfo.dwLength <= This->lLastFrame) - This->sInfo.dwLength = This->lLastFrame + 1; + if (This->sInfo.dwSampleSize) + { + unsigned int block; + size = 0; + for (block = 0; block <= This->lLastFrame; block++) + size += This->idxFrames[block].dwChunkLength; + This->sInfo.dwLength = max(This->sInfo.dwLength, size / This->sInfo.dwSampleSize); + } + else + { + This->sInfo.dwLength = max(This->sInfo.dwLength, This->lLastFrame + 1); + } return AVIERR_OK; } @@ -1989,7 +1999,8 @@ static HRESULT AVIFILE_ReadBlock(IAVIStreamImpl *This, DWORD pos, assert(This != NULL); assert(This->paf != NULL); assert(This->paf->hmmio != NULL); - assert(This->sInfo.dwStart <= pos && pos < This->sInfo.dwLength); + if (!This->sInfo.dwSampleSize) + assert(This->sInfo.dwStart <= pos && pos < This->sInfo.dwLength); assert(pos <= This->lLastFrame); /* should we read as much as block gives us? */ diff --git a/dlls/avifil32/tests/api.c b/dlls/avifil32/tests/api.c index f7571f48b6a8..f737175c0f0d 100644 --- a/dlls/avifil32/tests/api.c +++ b/dlls/avifil32/tests/api.c @@ -771,10 +771,129 @@ static void test_COM_editstream(void) while (IAVIEditStream_Release(edit)); } +static void test_avifile_write(void) +{ + WCHAR fn[MAX_PATH]; + IPersistFile *persist; + PCMWAVEFORMAT afmt; + AVISTREAMINFOW si; + USHORT buffer[64]; + PAVIFILE avifile; + PAVISTREAM stm; + HRESULT hr; + BOOL ret; + + GetTempPathW(MAX_PATH, fn); + wcscat(fn, L"test.avi"); + + hr = CoCreateInstance(&CLSID_AVIFile, NULL, CLSCTX_INPROC, &IID_IAVIFile, (void **)&avifile); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IAVIFile_QueryInterface(avifile, &IID_IPersistFile, (void **)&persist); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IPersistFile_Load(persist, fn, 0); + ok(hr == AVIERR_FILEOPEN, "got %#lx.\n", hr); + /* Consequent load attempt even with better flags will fail with ~0u. */ + hr = IPersistFile_Load(persist, fn, STGM_CREATE | STGM_WRITE); + todo_wine ok(hr == ~0u, "got %#lx.\n", hr); + IPersistFile_Release(persist); + IAVIFile_Release(avifile); + + hr = CoCreateInstance(&CLSID_AVIFile, NULL, CLSCTX_INPROC, &IID_IAVIFile, (void **)&avifile); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IAVIFile_QueryInterface(avifile, &IID_IPersistFile, (void **)&persist); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IPersistFile_Load(persist, fn, STGM_CREATE | STGM_WRITE); + ok(hr == S_OK, "got %#lx.\n", hr); + /* Consequent load attempt will fail with ~0u. */ + hr = IPersistFile_Load(persist, fn, STGM_CREATE | STGM_WRITE); + todo_wine ok(hr == ~0u, "got %#lx.\n", hr); + IPersistFile_Release(persist); + IAVIFile_Release(avifile); + + ret = DeleteFileW(fn); + ok(ret, "got error %lu.\n", GetLastError()); + + hr = CoCreateInstance(&CLSID_AVIFile, NULL, CLSCTX_INPROC, &IID_IAVIFile, (void **)&avifile); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IAVIFile_QueryInterface(avifile, &IID_IPersistFile, (void **)&persist); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IPersistFile_Load(persist, fn, STGM_CREATE); + ok(hr == S_OK, "got %#lx.\n", hr); + + memset(&si, 0, sizeof(si)); + si.fccType = streamtypeAUDIO; + si.dwScale = 1; + si.dwRate = 48000; + si.dwLength = 4; + si.dwQuality = ~0u; + si.dwSampleSize = 4; + hr = IAVIFile_CreateStream(avifile, &stm, &si); + ok(hr == AVIERR_READONLY, "got %#lx.\n", hr); + + IPersistFile_Release(persist); + IAVIFile_Release(avifile); + + ret = DeleteFileW(fn); + ok(ret, "got error %lu.\n", GetLastError()); + + hr = AVIFileOpenW(&avifile, fn, OF_CREATE, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = AVIFileCreateStreamW(avifile, &stm, &si); + ok(hr == S_OK, "got %#lx.\n", hr); + + memset(&afmt, 0, sizeof(afmt)); + afmt.wBitsPerSample = 16; + afmt.wf.wFormatTag = WAVE_FORMAT_PCM; + afmt.wf.nChannels = 2; + afmt.wf.nSamplesPerSec = 44800; + afmt.wf.nAvgBytesPerSec = afmt.wf.nSamplesPerSec * afmt.wf.nChannels; + //afmt.wf.wBitsPerSample = afmt.wf.nChannels * 2 * 8; + afmt.wf.nBlockAlign = afmt.wf.nChannels * 2; + hr = AVIStreamSetFormat(stm, 0, &afmt, sizeof(afmt)); + ok(hr == S_OK, "got %#lx.\n", hr); + + memset(buffer, 0xcc, sizeof(buffer)); + + hr = IAVIStream_Info(stm, &si, sizeof(si)); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(!si.dwLength, "got %lu.\n", si.dwLength); + ok(!si.dwStart, "got %lu.\n", si.dwStart); + ok(!si.dwSuggestedBufferSize, "got %lu.\n", si.dwSuggestedBufferSize); + hr = AVIStreamWrite(stm, 0, 2, buffer, si.dwSampleSize * 2, 0, NULL, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IAVIStream_Info(stm, &si, sizeof(si)); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(si.dwLength == 2, "got %lu.\n", si.dwLength); + ok(!si.dwStart, "got %lu.\n", si.dwStart); + ok(si.dwSuggestedBufferSize == 8, "got %lu.\n", si.dwSuggestedBufferSize); + hr = AVIStreamWrite(stm, 2, 2, buffer, si.dwSampleSize * 2, 0, NULL, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IAVIStream_Info(stm, &si, sizeof(si)); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(si.dwLength == 4, "got %lu.\n", si.dwLength); + ok(!si.dwStart, "got %lu.\n", si.dwStart); + ok(si.dwSuggestedBufferSize == 8, "got %lu.\n", si.dwSuggestedBufferSize); + + hr = AVIStreamWrite(stm, 4, 4, buffer, si.dwSampleSize * 4, 0, NULL, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IAVIStream_Info(stm, &si, sizeof(si)); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(si.dwLength == 8, "got %lu.\n", si.dwLength); + ok(!si.dwStart, "got %lu.\n", si.dwStart); + ok(si.dwSuggestedBufferSize == 16, "got %lu.\n", si.dwSuggestedBufferSize); + + if (hr == S_OK) + IAVIStream_Release(stm); + IAVIFile_Release(avifile); + ret = DeleteFileW(fn); + ok(ret, "got error %lu.\n", GetLastError()); +} + START_TEST(api) { AVIFileInit(); + test_EditStreamSetInfo(); test_AVISaveOptions(); test_default_data(); @@ -784,6 +903,7 @@ START_TEST(api) test_COM(); test_COM_wavfile(); test_COM_editstream(); + test_avifile_write(); AVIFileExit(); } diff --git a/dlls/bcrypt/Makefile.in b/dlls/bcrypt/Makefile.in index 542837b2a7ae..a0ddbd08630e 100644 --- a/dlls/bcrypt/Makefile.in +++ b/dlls/bcrypt/Makefile.in @@ -1,13 +1,11 @@ MODULE = bcrypt.dll -IMPORTS = advapi32 IMPORTLIB = bcrypt +IMPORTS = $(TOMCRYPT_PE_LIBS) advapi32 +EXTRAINCL = $(TOMCRYPT_PE_CFLAGS) UNIXLIB = bcrypt.so -UNIX_CFLAGS = $(GNUTLS_CFLAGS) +UNIX_CFLAGS = $(GNUTLS_CFLAGS) $(GMP_CFLAGS) SOURCES = \ bcrypt_main.c \ gnutls.c \ - md2.c \ - sha256.c \ - sha512.c \ version.rc diff --git a/dlls/bcrypt/bcrypt.spec b/dlls/bcrypt/bcrypt.spec index 90ab7b52fef8..4f481b0bd301 100644 --- a/dlls/bcrypt/bcrypt.spec +++ b/dlls/bcrypt/bcrypt.spec @@ -35,6 +35,7 @@ @ stdcall BCryptHashData(ptr ptr long long) @ stdcall BCryptImportKey(ptr ptr wstr ptr ptr long ptr long long) @ stdcall BCryptImportKeyPair(ptr ptr wstr ptr ptr long long) +@ stdcall BCryptKeyDerivation(ptr ptr ptr long ptr long) @ stdcall BCryptOpenAlgorithmProvider(ptr wstr wstr long) @ stub BCryptQueryContextConfiguration @ stub BCryptQueryContextFunctionConfiguration diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h index 81cab56e2f50..ea6acf5b448b 100644 --- a/dlls/bcrypt/bcrypt_internal.h +++ b/dlls/bcrypt/bcrypt_internal.h @@ -32,77 +32,6 @@ #define MAGIC_DSS1 ('D' | ('S' << 8) | ('S' << 16) | ('1' << 24)) #define MAGIC_DSS2 ('D' | ('S' << 8) | ('S' << 16) | ('2' << 24)) -typedef struct -{ - ULONG64 len; - DWORD h[8]; - UCHAR buf[64]; -} SHA256_CTX; - -void sha256_init(SHA256_CTX *ctx); -void sha256_update(SHA256_CTX *ctx, const UCHAR *buffer, ULONG len); -void sha256_finalize(SHA256_CTX *ctx, UCHAR *buffer); - -typedef struct -{ - ULONG64 len; - ULONG64 h[8]; - UCHAR buf[128]; -} SHA512_CTX; - -void sha512_init(SHA512_CTX *ctx); -void sha512_update(SHA512_CTX *ctx, const UCHAR *buffer, ULONG len); -void sha512_finalize(SHA512_CTX *ctx, UCHAR *buffer); - -void sha384_init(SHA512_CTX *ctx); -#define sha384_update sha512_update -void sha384_finalize(SHA512_CTX *ctx, UCHAR *buffer); - -typedef struct { - unsigned char chksum[16], X[48], buf[16]; - unsigned long curlen; -} MD2_CTX; - -void md2_init(MD2_CTX *ctx); -void md2_update(MD2_CTX *ctx, const unsigned char *buf, ULONG len); -void md2_finalize(MD2_CTX *ctx, unsigned char *hash); - -/* Definitions from advapi32 */ -typedef struct tagMD4_CTX { - unsigned int buf[4]; - unsigned int i[2]; - unsigned char in[64]; - unsigned char digest[16]; -} MD4_CTX; - -VOID WINAPI MD4Init(MD4_CTX *ctx); -VOID WINAPI MD4Update(MD4_CTX *ctx, const unsigned char *buf, unsigned int len); -VOID WINAPI MD4Final(MD4_CTX *ctx); - -typedef struct -{ - unsigned int i[2]; - unsigned int buf[4]; - unsigned char in[64]; - unsigned char digest[16]; -} MD5_CTX; - -VOID WINAPI MD5Init(MD5_CTX *ctx); -VOID WINAPI MD5Update(MD5_CTX *ctx, const unsigned char *buf, unsigned int len); -VOID WINAPI MD5Final(MD5_CTX *ctx); - -typedef struct -{ - ULONG Unknown[6]; - ULONG State[5]; - ULONG Count[2]; - UCHAR Buffer[64]; -} SHA_CTX; - -VOID WINAPI A_SHAInit(SHA_CTX *ctx); -VOID WINAPI A_SHAUpdate(SHA_CTX *ctx, const UCHAR *buffer, UINT size); -VOID WINAPI A_SHAFinal(SHA_CTX *ctx, PULONG result); - #define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0') #define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H') #define MAGIC_KEY (('K' << 24) | ('E' << 16) | ('Y' << 8) | '0') @@ -135,15 +64,20 @@ enum alg_id ALG_ID_DH, ALG_ID_ECDH_P256, ALG_ID_ECDH_P384, + ALG_ID_ECDH_P521, /* signature */ ALG_ID_RSA_SIGN, ALG_ID_ECDSA_P256, ALG_ID_ECDSA_P384, + ALG_ID_ECDSA_P521, ALG_ID_DSA, /* rng */ ALG_ID_RNG, + + /* key derivation */ + ALG_ID_PBKDF2, }; enum chain_mode @@ -176,6 +110,7 @@ struct key_symmetric #define KEY_FLAG_LEGACY_DSA_V2 0x00000001 #define KEY_FLAG_FINALIZED 0x00000002 +#define KEY_FLAG_DH_PARAMS_SET 0x00000004 struct key_asymmetric { @@ -345,4 +280,9 @@ enum key_funcs unix_funcs_count, }; +static inline ULONG len_from_bitlen( ULONG bitlen ) +{ + return (bitlen + 7) / 8; +} + #endif /* __BCRYPT_INTERNAL_H */ diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 3d88430a07e7..0d94ed8bc5b3 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -29,6 +29,7 @@ #include "wincrypt.h" #include "winternl.h" #include "bcrypt.h" +#include "tomcrypt.h" #include "wine/debug.h" #include "bcrypt_internal.h" @@ -117,16 +118,20 @@ builtin_algorithms[] = { BCRYPT_DH_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, { BCRYPT_ECDH_P256_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, { BCRYPT_ECDH_P384_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, + { BCRYPT_ECDH_P521_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, { BCRYPT_RSA_SIGN_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, { BCRYPT_ECDSA_P256_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, { BCRYPT_ECDSA_P384_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, + { BCRYPT_ECDSA_P521_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, { BCRYPT_DSA_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, { BCRYPT_RNG_ALGORITHM, BCRYPT_RNG_INTERFACE, 0, 0, 0 }, + { BCRYPT_PBKDF2_ALGORITHM, BCRYPT_KEY_DERIVATION_INTERFACE, 618, 0, 0 }, }; static inline BOOL is_symmetric_key( const struct key *key ) { - return builtin_algorithms[key->alg_id].class == BCRYPT_CIPHER_INTERFACE; + return builtin_algorithms[key->alg_id].class == BCRYPT_CIPHER_INTERFACE + || builtin_algorithms[key->alg_id].class == BCRYPT_KEY_DERIVATION_INTERFACE; } static inline BOOL is_asymmetric_encryption_key( struct key *key ) @@ -155,6 +160,7 @@ static BOOL match_operation_type( ULONG type, ULONG class ) case BCRYPT_SECRET_AGREEMENT_INTERFACE: return type & BCRYPT_SECRET_AGREEMENT_OPERATION; case BCRYPT_SIGNATURE_INTERFACE: return type & BCRYPT_SIGNATURE_OPERATION; case BCRYPT_RNG_INTERFACE: return type & BCRYPT_RNG_OPERATION; + case BCRYPT_KEY_DERIVATION_INTERFACE: return type & BCRYPT_KEY_DERIVATION_OPERATION; default: break; } return FALSE; @@ -167,7 +173,8 @@ NTSTATUS WINAPI BCryptEnumAlgorithms( ULONG type, ULONG *ret_count, BCRYPT_ALGOR BCRYPT_ASYMMETRIC_ENCRYPTION_OPERATION |\ BCRYPT_SECRET_AGREEMENT_OPERATION |\ BCRYPT_SIGNATURE_OPERATION |\ - BCRYPT_RNG_OPERATION; + BCRYPT_RNG_OPERATION |\ + BCRYPT_KEY_DERIVATION_OPERATION; BCRYPT_ALGORITHM_IDENTIFIER *list; ULONG i, j, count = 0; @@ -242,11 +249,11 @@ static const struct algorithm pseudo_algorithms[] = {{ 0 }}, /* ECDH */ {{ MAGIC_ALG }, ALG_ID_ECDH_P256 }, {{ MAGIC_ALG }, ALG_ID_ECDH_P384 }, - {{ 0 }}, /* ECDH_P512 */ + {{ MAGIC_ALG }, ALG_ID_ECDH_P521 }, {{ MAGIC_ALG }, ALG_ID_DSA }, {{ MAGIC_ALG }, ALG_ID_ECDSA_P256 }, {{ MAGIC_ALG }, ALG_ID_ECDSA_P384 }, - {{ 0 }}, /* ECDSA_P512 */ + {{ MAGIC_ALG }, ALG_ID_ECDSA_P521 }, {{ MAGIC_ALG }, ALG_ID_RSA_SIGN }, }; @@ -427,136 +434,21 @@ NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled) return STATUS_SUCCESS; } -struct hash_impl -{ - union - { - MD2_CTX md2; - MD4_CTX md4; - MD5_CTX md5; - SHA_CTX sha1; - SHA256_CTX sha256; - SHA512_CTX sha512; - } u; -}; - -static NTSTATUS hash_init( struct hash_impl *hash, enum alg_id alg_id ) -{ - switch (alg_id) - { - case ALG_ID_MD2: - md2_init( &hash->u.md2 ); - break; - - case ALG_ID_MD4: - MD4Init( &hash->u.md4 ); - break; - - case ALG_ID_MD5: - MD5Init( &hash->u.md5 ); - break; - - case ALG_ID_SHA1: - A_SHAInit( &hash->u.sha1 ); - break; - - case ALG_ID_SHA256: - sha256_init( &hash->u.sha256 ); - break; - - case ALG_ID_SHA384: - sha384_init( &hash->u.sha512 ); - break; - - case ALG_ID_SHA512: - sha512_init( &hash->u.sha512 ); - break; - - default: - ERR( "unhandled id %u\n", alg_id ); - return STATUS_NOT_IMPLEMENTED; - } - return STATUS_SUCCESS; -} - -static NTSTATUS hash_update( struct hash_impl *hash, enum alg_id alg_id, UCHAR *input, ULONG size ) -{ - switch (alg_id) - { - case ALG_ID_MD2: - md2_update( &hash->u.md2, input, size ); - break; - - case ALG_ID_MD4: - MD4Update( &hash->u.md4, input, size ); - break; - - case ALG_ID_MD5: - MD5Update( &hash->u.md5, input, size ); - break; - - case ALG_ID_SHA1: - A_SHAUpdate( &hash->u.sha1, input, size ); - break; - - case ALG_ID_SHA256: - sha256_update( &hash->u.sha256, input, size ); - break; - - case ALG_ID_SHA384: - sha384_update( &hash->u.sha512, input, size ); - break; - - case ALG_ID_SHA512: - sha512_update( &hash->u.sha512, input, size ); - break; - - default: - ERR( "unhandled id %u\n", alg_id ); - return STATUS_NOT_IMPLEMENTED; - } - return STATUS_SUCCESS; -} - -static NTSTATUS hash_finish( struct hash_impl *hash, enum alg_id alg_id, UCHAR *output ) +static const struct ltc_hash_descriptor *get_hash_descriptor( enum alg_id alg_id ) { switch (alg_id) { - case ALG_ID_MD2: - md2_finalize( &hash->u.md2, output ); - break; - - case ALG_ID_MD4: - MD4Final( &hash->u.md4 ); - memcpy( output, hash->u.md4.digest, 16 ); - break; - - case ALG_ID_MD5: - MD5Final( &hash->u.md5 ); - memcpy( output, hash->u.md5.digest, 16 ); - break; - - case ALG_ID_SHA1: - A_SHAFinal( &hash->u.sha1, (ULONG *)output ); - break; - - case ALG_ID_SHA256: - sha256_finalize( &hash->u.sha256, output ); - break; - - case ALG_ID_SHA384: - sha384_finalize( &hash->u.sha512, output ); - break; - - case ALG_ID_SHA512: - sha512_finalize( &hash->u.sha512, output ); - break; - + case ALG_ID_MD2: return &md2_desc; + case ALG_ID_MD4: return &md4_desc; + case ALG_ID_MD5: return &md5_desc; + case ALG_ID_SHA1: return &sha1_desc; + case ALG_ID_SHA256: return &sha256_desc; + case ALG_ID_SHA384: return &sha384_desc; + case ALG_ID_SHA512: return &sha512_desc; default: ERR( "unhandled id %u\n", alg_id ); - return STATUS_NOT_IMPLEMENTED; + return NULL; } - return STATUS_SUCCESS; } #define HASH_FLAG_HMAC 0x01 @@ -565,11 +457,12 @@ struct hash { struct object hdr; enum alg_id alg_id; + const struct ltc_hash_descriptor *desc; ULONG flags; UCHAR *secret; ULONG secret_len; - struct hash_impl outer; - struct hash_impl inner; + hash_state outer; + hash_state inner; }; #define BLOCK_LENGTH_RC4 1 @@ -748,6 +641,26 @@ static NTSTATUS get_dsa_property( enum chain_mode mode, const WCHAR *prop, UCHAR return STATUS_NOT_IMPLEMENTED; } +static NTSTATUS get_pbkdf2_property( enum chain_mode mode, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size ) +{ + if (!wcscmp( prop, BCRYPT_BLOCK_LENGTH )) return STATUS_NOT_SUPPORTED; + if (!wcscmp( prop, BCRYPT_KEY_LENGTHS )) + { + BCRYPT_KEY_LENGTHS_STRUCT *key_lengths = (void *)buf; + *ret_size = sizeof(*key_lengths); + if (key_lengths && size < *ret_size) return STATUS_BUFFER_TOO_SMALL; + if (key_lengths) + { + key_lengths->dwMinLength = 0; + key_lengths->dwMaxLength = 16384; + key_lengths->dwIncrement = 8; + } + return STATUS_SUCCESS; + } + FIXME( "unsupported property %s\n", debugstr_w(prop) ); + return STATUS_NOT_IMPLEMENTED; +} + static NTSTATUS get_alg_property( const struct algorithm *alg, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size ) { @@ -774,6 +687,9 @@ static NTSTATUS get_alg_property( const struct algorithm *alg, const WCHAR *prop case ALG_ID_DSA: return get_dsa_property( alg->mode, prop, buf, size, ret_size ); + case ALG_ID_PBKDF2: + return get_pbkdf2_property( alg->mode, prop, buf, size, ret_size ); + default: break; } @@ -895,7 +811,7 @@ static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *val if (key->u.a.flags & KEY_FLAG_FINALIZED) return STATUS_INVALID_HANDLE; if (key->alg_id != ALG_ID_DH || size < sizeof(*hdr) || hdr->cbLength != size || - hdr->dwMagic != BCRYPT_DH_PARAMETERS_MAGIC || hdr->cbKeyLength != key->u.a.bitlen / 8) + hdr->dwMagic != BCRYPT_DH_PARAMETERS_MAGIC || hdr->cbKeyLength != len_from_bitlen( key->u.a.bitlen )) return STATUS_INVALID_PARAMETER; params.key = key; @@ -999,43 +915,44 @@ NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHA } } -static NTSTATUS hash_prepare( struct hash *hash ) +static void hash_prepare( struct hash *hash ) { UCHAR buffer[MAX_HASH_BLOCK_BITS / 8] = {0}; int block_bytes, i; - NTSTATUS status; /* initialize hash */ - if ((status = hash_init( &hash->inner, hash->alg_id ))) return status; - if (!(hash->flags & HASH_FLAG_HMAC)) return STATUS_SUCCESS; + hash->desc->init( &hash->inner ); + if (!(hash->flags & HASH_FLAG_HMAC)) return; /* initialize hmac */ - if ((status = hash_init( &hash->outer, hash->alg_id ))) return status; - block_bytes = builtin_algorithms[hash->alg_id].block_bits / 8; + hash->desc->init( &hash->outer ); + block_bytes = hash->desc->blocksize; if (hash->secret_len > block_bytes) { - struct hash_impl temp; - if ((status = hash_init( &temp, hash->alg_id ))) return status; - if ((status = hash_update( &temp, hash->alg_id, hash->secret, hash->secret_len ))) return status; - if ((status = hash_finish( &temp, hash->alg_id, buffer ))) return status; + hash_state temp; + hash->desc->init( &temp ); + hash->desc->process( &temp, hash->secret, hash->secret_len ); + hash->desc->done( &temp, buffer ); } else memcpy( buffer, hash->secret, hash->secret_len ); for (i = 0; i < block_bytes; i++) buffer[i] ^= 0x5c; - if ((status = hash_update( &hash->outer, hash->alg_id, buffer, block_bytes ))) return status; + hash->desc->process( &hash->outer, buffer, block_bytes ); for (i = 0; i < block_bytes; i++) buffer[i] ^= (0x5c ^ 0x36); - return hash_update( &hash->inner, hash->alg_id, buffer, block_bytes ); + hash->desc->process( &hash->inner, buffer, block_bytes ); } static NTSTATUS hash_create( const struct algorithm *alg, UCHAR *secret, ULONG secret_len, ULONG flags, struct hash **ret_hash ) { struct hash *hash; - NTSTATUS status; + const struct ltc_hash_descriptor *desc = get_hash_descriptor( alg->id ); + if (!desc) return STATUS_NOT_IMPLEMENTED; if (!(hash = calloc( 1, sizeof(*hash) ))) return STATUS_NO_MEMORY; hash->hdr.magic = MAGIC_HASH; hash->alg_id = alg->id; + hash->desc = desc; if (alg->flags & BCRYPT_ALG_HANDLE_HMAC_FLAG) hash->flags = HASH_FLAG_HMAC; if ((alg->flags & BCRYPT_HASH_REUSABLE_FLAG) || (flags & BCRYPT_HASH_REUSABLE_FLAG)) hash->flags |= HASH_FLAG_REUSABLE; @@ -1048,13 +965,7 @@ static NTSTATUS hash_create( const struct algorithm *alg, UCHAR *secret, ULONG s memcpy( hash->secret, secret, secret_len ); hash->secret_len = secret_len; - if ((status = hash_prepare( hash ))) - { - free( hash->secret ); - free( hash ); - return status; - } - + hash_prepare( hash ); *ret_hash = hash; return STATUS_SUCCESS; } @@ -1137,28 +1048,26 @@ NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG s if (!hash) return STATUS_INVALID_HANDLE; if (!input) return STATUS_SUCCESS; - return hash_update( &hash->inner, hash->alg_id, input, size ); + if (hash->desc->process( &hash->inner, input, size )) return STATUS_INVALID_PARAMETER; + return STATUS_SUCCESS; } -static NTSTATUS hash_finalize( struct hash *hash, UCHAR *output ) +static void hash_finalize( struct hash *hash, UCHAR *output ) { UCHAR buffer[MAX_HASH_OUTPUT_BYTES]; - ULONG hash_length = builtin_algorithms[hash->alg_id].hash_length; - NTSTATUS status; if (!(hash->flags & HASH_FLAG_HMAC)) { - if ((status = hash_finish( &hash->inner, hash->alg_id, output ))) return status; - if (hash->flags & HASH_FLAG_REUSABLE) return hash_prepare( hash ); - return STATUS_SUCCESS; + hash->desc->done( &hash->inner, output ); + if (hash->flags & HASH_FLAG_REUSABLE) hash_prepare( hash ); + return; } - if ((status = hash_finish( &hash->inner, hash->alg_id, buffer ))) return status; - if ((status = hash_update( &hash->outer, hash->alg_id, buffer, hash_length ))) return status; - if ((status = hash_finish( &hash->outer, hash->alg_id, output ))) return status; + hash->desc->done( &hash->inner, buffer ); + hash->desc->process( &hash->outer, buffer, hash->desc->hashsize ); + hash->desc->done( &hash->outer, output ); - if (hash->flags & HASH_FLAG_REUSABLE) return hash_prepare( hash ); - return STATUS_SUCCESS; + if (hash->flags & HASH_FLAG_REUSABLE) hash_prepare( hash ); } NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags ) @@ -1168,9 +1077,10 @@ NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULON TRACE( "%p, %p, %lu, %#lx\n", handle, output, size, flags ); if (!hash) return STATUS_INVALID_HANDLE; - if (!output || size != builtin_algorithms[hash->alg_id].hash_length) return STATUS_INVALID_PARAMETER; + if (!output || size != hash->desc->hashsize) return STATUS_INVALID_PARAMETER; - return hash_finalize( hash, output ); + hash_finalize( hash, output ); + return STATUS_SUCCESS; } static NTSTATUS hash_single( struct algorithm *alg, UCHAR *secret, ULONG secret_len, UCHAR *input, ULONG input_len, @@ -1180,14 +1090,14 @@ static NTSTATUS hash_single( struct algorithm *alg, UCHAR *secret, ULONG secret_ NTSTATUS status; if ((status = hash_create( alg, secret, secret_len, 0, &hash ))) return status; - if ((status = hash_update( &hash->inner, hash->alg_id, input, input_len ))) + if (input_len && hash->desc->process( &hash->inner, input, input_len )) { hash_destroy( hash ); - return status; + return STATUS_INVALID_PARAMETER; } - status = hash_finalize( hash, output ); + hash_finalize( hash, output ); hash_destroy( hash ); - return status; + return STATUS_SUCCESS; } NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE handle, UCHAR *secret, ULONG secret_len, UCHAR *input, ULONG input_len, @@ -1248,7 +1158,7 @@ static NTSTATUS key_symmetric_set_vector( struct key *key, UCHAR *vector, ULONG return STATUS_SUCCESS; } -static struct key *create_symmetric_key( enum alg_id alg, enum chain_mode mode, ULONG block_size, UCHAR *secret, +static struct key *key_symmetric_create( enum alg_id alg, enum chain_mode mode, ULONG block_size, const UCHAR *secret, ULONG secret_len ) { struct key *ret; @@ -1272,6 +1182,21 @@ static struct key *create_symmetric_key( enum alg_id alg, enum chain_mode mode, return ret; } +static void key_destroy( struct key *key ) +{ + if (is_symmetric_key( key )) + { + UNIX_CALL( key_symmetric_destroy, key ); + free( key->u.s.vector ); + free( key->u.s.secret ); + DeleteCriticalSection( &key->u.s.cs ); + } + else + UNIX_CALL( key_asymmetric_destroy, key ); + + destroy_object( &key->hdr ); +} + static ULONG get_block_size( struct algorithm *alg ) { ULONG ret = 0, size = sizeof(ret); @@ -1279,7 +1204,7 @@ static ULONG get_block_size( struct algorithm *alg ) return ret; } -static NTSTATUS generate_symmetric_key( struct algorithm *alg, BCRYPT_KEY_HANDLE *ret_handle, UCHAR *secret, +static NTSTATUS key_symmetric_generate( struct algorithm *alg, BCRYPT_KEY_HANDLE *ret_handle, const UCHAR *secret, ULONG secret_len ) { BCRYPT_KEY_LENGTHS_STRUCT key_lengths; @@ -1287,8 +1212,15 @@ static NTSTATUS generate_symmetric_key( struct algorithm *alg, BCRYPT_KEY_HANDLE struct key *key; NTSTATUS status; - if (!(block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER; - if (!get_alg_property( alg, BCRYPT_KEY_LENGTHS, (UCHAR *)&key_lengths, sizeof(key_lengths), &size )) + if (alg->id == ALG_ID_PBKDF2 && + !get_alg_property( alg, BCRYPT_KEY_LENGTHS, (UCHAR *)&key_lengths, sizeof(key_lengths), &size )) + { + if (secret_len > key_lengths.dwMaxLength / 8 || secret_len < key_lengths.dwMinLength / 8) + return STATUS_INVALID_PARAMETER; + block_size = secret_len; + } + else if (!(block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER; + else if (!get_alg_property( alg, BCRYPT_KEY_LENGTHS, (UCHAR *)&key_lengths, sizeof(key_lengths), &size )) { if (secret_len > (size = key_lengths.dwMaxLength / 8)) { @@ -1307,7 +1239,7 @@ static NTSTATUS generate_symmetric_key( struct algorithm *alg, BCRYPT_KEY_HANDLE } } - if (!(key = create_symmetric_key( alg->id, alg->mode, block_size, secret, secret_len ))) status = STATUS_NO_MEMORY; + if (!(key = key_symmetric_create( alg->id, alg->mode, block_size, secret, secret_len ))) status = STATUS_NO_MEMORY; else { *ret_handle = key; @@ -1317,102 +1249,203 @@ static NTSTATUS generate_symmetric_key( struct algorithm *alg, BCRYPT_KEY_HANDLE return status; } -static NTSTATUS key_import( struct algorithm *alg, const WCHAR *type, BCRYPT_KEY_HANDLE *key, UCHAR *object, - ULONG object_len, UCHAR *input, ULONG input_len ) +static NTSTATUS key_symmetric_decrypt( struct key *key, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv, + ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags ) { - ULONG len; + struct key_symmetric_set_auth_data_params auth_params; + struct key_symmetric_decrypt_params decrypt_params; + struct key_symmetric_get_tag_params tag_params; + ULONG bytes_left = input_len; + NTSTATUS status; - if (!wcscmp( type, BCRYPT_KEY_DATA_BLOB )) + if (key->u.s.mode == CHAIN_MODE_GCM) { - BCRYPT_KEY_DATA_BLOB_HEADER *header = (BCRYPT_KEY_DATA_BLOB_HEADER *)input; + BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding; + UCHAR tag[16]; - if (input_len < sizeof(BCRYPT_KEY_DATA_BLOB_HEADER)) return STATUS_BUFFER_TOO_SMALL; - if (header->dwMagic != BCRYPT_KEY_DATA_BLOB_MAGIC) return STATUS_INVALID_PARAMETER; - if (header->dwVersion != BCRYPT_KEY_DATA_BLOB_VERSION1) - { - FIXME( "unknown key data blob version %lu\n", header->dwVersion ); - return STATUS_INVALID_PARAMETER; - } - len = header->cbKeyData; - if (len + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) > input_len) return STATUS_INVALID_PARAMETER; + if (!auth_info) return STATUS_INVALID_PARAMETER; + if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER; + if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER; + if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER; - return generate_symmetric_key( alg, key, (UCHAR *)&header[1], len ); - } - else if (!wcscmp( type, BCRYPT_OPAQUE_KEY_BLOB )) - { - if (input_len < sizeof(len)) return STATUS_BUFFER_TOO_SMALL; - len = *(ULONG *)input; - if (len + sizeof(len) > input_len) return STATUS_INVALID_PARAMETER; + if ((status = key_symmetric_set_vector( key, auth_info->pbNonce, auth_info->cbNonce, TRUE ))) + return status; + + *ret_len = input_len; + if (flags & BCRYPT_BLOCK_PADDING) return STATUS_INVALID_PARAMETER; + if (!output) return STATUS_SUCCESS; + if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL; + + auth_params.key = key; + auth_params.auth_data = auth_info->pbAuthData; + auth_params.len = auth_info->cbAuthData; + if ((status = UNIX_CALL( key_symmetric_set_auth_data, &auth_params ))) return status; + + decrypt_params.key = key; + decrypt_params.input = input; + decrypt_params.input_len = input_len; + decrypt_params.output = output; + decrypt_params.output_len = output_len; + if ((status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ))) return status; - return generate_symmetric_key( alg, key, input + sizeof(len), len ); + tag_params.key = key; + tag_params.tag = tag; + tag_params.len = sizeof(tag); + if ((status = UNIX_CALL( key_symmetric_get_tag, &tag_params ))) return status; + if (memcmp( tag, auth_info->pbTag, auth_info->cbTag )) return STATUS_AUTH_TAG_MISMATCH; + + return STATUS_SUCCESS; } - FIXME( "unsupported key type %s\n", debugstr_w(type) ); - return STATUS_NOT_IMPLEMENTED; -} + *ret_len = input_len; -static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size ) -{ - struct key_asymmetric_export_params params; + if (input_len & (key->u.s.block_size - 1)) return STATUS_INVALID_BUFFER_SIZE; + if (!output) return STATUS_SUCCESS; + if (flags & BCRYPT_BLOCK_PADDING) + { + if (output_len + key->u.s.block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL; + if (input_len < key->u.s.block_size) return STATUS_BUFFER_TOO_SMALL; + bytes_left -= key->u.s.block_size; + } + else if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL; - if (!wcscmp( type, BCRYPT_KEY_DATA_BLOB )) + if (key->u.s.mode == CHAIN_MODE_ECB && iv) return STATUS_INVALID_PARAMETER; + if ((status = key_symmetric_set_vector( key, iv, iv_len, flags & BCRYPT_BLOCK_PADDING ))) return status; + + decrypt_params.key = key; + decrypt_params.input = input; + decrypt_params.input_len = key->u.s.block_size; + decrypt_params.output = output; + decrypt_params.output_len = key->u.s.block_size; + while (bytes_left >= key->u.s.block_size) { - BCRYPT_KEY_DATA_BLOB_HEADER *header = (BCRYPT_KEY_DATA_BLOB_HEADER *)output; - ULONG req_size = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->u.s.secret_len; + if ((status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ))) return status; + if (key->u.s.mode == CHAIN_MODE_ECB && (status = key_symmetric_set_vector( key, NULL, 0, TRUE ))) + return status; + bytes_left -= key->u.s.block_size; + decrypt_params.input += key->u.s.block_size; + decrypt_params.output += key->u.s.block_size; + } - *size = req_size; - if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL; - if (output) + if (flags & BCRYPT_BLOCK_PADDING) + { + UCHAR *buf, *dst = decrypt_params.output; + if (!(buf = malloc( key->u.s.block_size ))) return STATUS_NO_MEMORY; + decrypt_params.output = buf; + status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ); + if (!status && buf[ key->u.s.block_size - 1 ] <= key->u.s.block_size) { - header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; - header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; - header->cbKeyData = key->u.s.secret_len; - memcpy( &header[1], key->u.s.secret, key->u.s.secret_len ); + *ret_len -= buf[ key->u.s.block_size - 1 ]; + if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL; + else memcpy( dst, buf, key->u.s.block_size - buf[ key->u.s.block_size - 1 ] ); } - return STATUS_SUCCESS; + else status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */ + free( buf ); } - else if (!wcscmp( type, BCRYPT_OPAQUE_KEY_BLOB )) + + if (!status) { - ULONG len, req_size = sizeof(len) + key->u.s.secret_len; + if (key->u.s.vector && input_len >= key->u.s.vector_len) + { + memcpy( key->u.s.vector, input + input_len - key->u.s.vector_len, key->u.s.vector_len ); + if (iv) memcpy( iv, key->u.s.vector, min( iv_len, key->u.s.vector_len )); + } + else if (key->u.s.vector) + FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); + } - *size = req_size; - if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL; - if (output) + return status; +} + +/* AES Key Wrap Algorithm (RFC3394) */ +static NTSTATUS aes_unwrap( const UCHAR *secret, ULONG secret_len, const UCHAR *cipher, ULONG cipher_len, UCHAR *plain ) +{ + UCHAR a[8], *r, b[16]; + ULONG len, t, i, n = cipher_len / 8; + int j; + struct key *key; + + memcpy( a, cipher, 8 ); + r = plain; + memcpy( r, cipher + 8, 8 * n ); + + if (!(key = key_symmetric_create( ALG_ID_AES, CHAIN_MODE_ECB, 16, secret, secret_len ))) return STATUS_NO_MEMORY; + + for (j = 5; j >= 0; j--) + { + r = plain + (n - 1) * 8; + for (i = n; i >= 1; i--) { - *(ULONG *)output = key->u.s.secret_len; - memcpy( output + sizeof(len), key->u.s.secret, key->u.s.secret_len ); + memcpy( b, a, 8 ); + t = n * j + i; + b[7] ^= t; + b[6] ^= t >> 8; + b[5] ^= t >> 16; + b[4] ^= t >> 24; + + memcpy( b + 8, r, 8 ); + key_symmetric_decrypt( key, b, 16, NULL, NULL, 0, b, 16, &len, 0 ); + memcpy( a, b, 8 ); + memcpy( r, b + 8, 8 ); + r -= 8; } - return STATUS_SUCCESS; } - else if (!wcscmp( type, BCRYPT_DSA_PRIVATE_BLOB ) || !wcscmp( type, LEGACY_DSA_V2_PRIVATE_BLOB ) || - !wcscmp( type, BCRYPT_ECCPRIVATE_BLOB ) || !wcscmp( type, BCRYPT_DH_PRIVATE_BLOB )) + + key_destroy( key ); + + for (i = 0; i < 8; i++) if (a[i] != 0xa6) return STATUS_UNSUCCESSFUL; + return STATUS_SUCCESS; +} + +static NTSTATUS key_import( struct algorithm *alg, struct key *decrypt_key, const WCHAR *type, BCRYPT_KEY_HANDLE *key, + UCHAR *object, ULONG object_len, UCHAR *input, ULONG input_len ) +{ + ULONG len; + NTSTATUS status; + + if (decrypt_key && wcscmp( type, BCRYPT_AES_WRAP_KEY_BLOB )) { - params.key = key; - params.flags = 0; - params.buf = output; - params.len = output_len; - params.ret_len = size; - return UNIX_CALL( key_asymmetric_export, ¶ms ); + FIXME( "decryption of key not supported\n" ); + return STATUS_NOT_IMPLEMENTED; } - else if (!wcscmp( type, BCRYPT_RSAPRIVATE_BLOB ) || !wcscmp( type, BCRYPT_RSAFULLPRIVATE_BLOB )) + + if (!wcscmp( type, BCRYPT_KEY_DATA_BLOB )) { - params.key = key; - params.flags = (wcscmp( type, BCRYPT_RSAPRIVATE_BLOB )) ? KEY_EXPORT_FLAG_RSA_FULL : 0; - params.buf = output; - params.len = output_len; - params.ret_len = size; - return UNIX_CALL( key_asymmetric_export, ¶ms ); + BCRYPT_KEY_DATA_BLOB_HEADER *header = (BCRYPT_KEY_DATA_BLOB_HEADER *)input; + + if (input_len < sizeof(BCRYPT_KEY_DATA_BLOB_HEADER)) return STATUS_BUFFER_TOO_SMALL; + if (header->dwMagic != BCRYPT_KEY_DATA_BLOB_MAGIC) return STATUS_INVALID_PARAMETER; + if (header->dwVersion != BCRYPT_KEY_DATA_BLOB_VERSION1) + { + FIXME( "unknown key data blob version %lu\n", header->dwVersion ); + return STATUS_INVALID_PARAMETER; + } + len = header->cbKeyData; + if (len + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) > input_len) return STATUS_INVALID_PARAMETER; + + return key_symmetric_generate( alg, key, (UCHAR *)&header[1], len ); } - else if (!wcscmp( type, BCRYPT_DSA_PUBLIC_BLOB ) || !wcscmp( type, LEGACY_DSA_V2_PUBLIC_BLOB ) || - !wcscmp( type, BCRYPT_ECCPUBLIC_BLOB ) || !wcscmp( type, BCRYPT_RSAPUBLIC_BLOB ) || - !wcscmp( type, BCRYPT_DH_PUBLIC_BLOB )) + else if (!wcscmp( type, BCRYPT_OPAQUE_KEY_BLOB )) { - params.key = key; - params.flags = KEY_EXPORT_FLAG_PUBLIC; - params.buf = output; - params.len = output_len; - params.ret_len = size; - return UNIX_CALL( key_asymmetric_export, ¶ms ); + if (input_len < sizeof(len)) return STATUS_BUFFER_TOO_SMALL; + len = *(ULONG *)input; + if (len + sizeof(len) > input_len) return STATUS_INVALID_PARAMETER; + + return key_symmetric_generate( alg, key, input + sizeof(len), len ); + } + else if (!wcscmp( type, BCRYPT_AES_WRAP_KEY_BLOB )) + { + UCHAR output[32]; + + if (!decrypt_key || input_len < 8) return STATUS_INVALID_PARAMETER; + + len = input_len - 8; + if (len < BLOCK_LENGTH_AES || len & (BLOCK_LENGTH_AES - 1)) return STATUS_INVALID_PARAMETER; + + if ((status = aes_unwrap( decrypt_key->u.s.secret, decrypt_key->u.s.secret_len, input, len, output ))) + return status; + + return key_symmetric_generate( alg, key, output, len ); } FIXME( "unsupported key type %s\n", debugstr_w(type) ); @@ -1511,132 +1544,140 @@ static NTSTATUS key_symmetric_encrypt( struct key *key, UCHAR *input, ULONG inp memcpy( key->u.s.vector, output + *ret_len - key->u.s.vector_len, key->u.s.vector_len ); if (iv) memcpy( iv, key->u.s.vector, min( iv_len, key->u.s.vector_len )); } - else FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); + else if (key->u.s.vector) + FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); } return status; } -static NTSTATUS key_symmetric_decrypt( struct key *key, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv, - ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags ) +/* AES Key Wrap Algorithm (RFC3394) */ +static NTSTATUS aes_wrap( const UCHAR *secret, ULONG secret_len, const UCHAR *plain, ULONG plain_len, UCHAR *cipher ) { - struct key_symmetric_set_auth_data_params auth_params; - struct key_symmetric_decrypt_params decrypt_params; - struct key_symmetric_get_tag_params tag_params; - ULONG bytes_left = input_len; - NTSTATUS status; - - if (key->u.s.mode == CHAIN_MODE_GCM) - { - BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding; - UCHAR tag[16]; - - if (!auth_info) return STATUS_INVALID_PARAMETER; - if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER; - if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER; - if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER; - - if ((status = key_symmetric_set_vector( key, auth_info->pbNonce, auth_info->cbNonce, TRUE ))) - return status; - - *ret_len = input_len; - if (flags & BCRYPT_BLOCK_PADDING) return STATUS_INVALID_PARAMETER; - if (!output) return STATUS_SUCCESS; - if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL; - - auth_params.key = key; - auth_params.auth_data = auth_info->pbAuthData; - auth_params.len = auth_info->cbAuthData; - if ((status = UNIX_CALL( key_symmetric_set_auth_data, &auth_params ))) return status; - - decrypt_params.key = key; - decrypt_params.input = input; - decrypt_params.input_len = input_len; - decrypt_params.output = output; - decrypt_params.output_len = output_len; - if ((status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ))) return status; + UCHAR *a, *r, b[16]; + ULONG len, t, i, j, n = plain_len / 8; + struct key *key; - tag_params.key = key; - tag_params.tag = tag; - tag_params.len = sizeof(tag); - if ((status = UNIX_CALL( key_symmetric_get_tag, &tag_params ))) return status; - if (memcmp( tag, auth_info->pbTag, auth_info->cbTag )) return STATUS_AUTH_TAG_MISMATCH; + a = cipher; + r = cipher + 8; - return STATUS_SUCCESS; - } + memset( a, 0xa6, 8 ); + memcpy( r, plain, 8 * n ); - *ret_len = input_len; + if (!(key = key_symmetric_create( ALG_ID_AES, CHAIN_MODE_ECB, 16, secret, secret_len ))) return STATUS_NO_MEMORY; - if (input_len & (key->u.s.block_size - 1)) return STATUS_INVALID_BUFFER_SIZE; - if (!output) return STATUS_SUCCESS; - if (flags & BCRYPT_BLOCK_PADDING) + for (j = 0; j <= 5; j++) { - if (output_len + key->u.s.block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL; - if (input_len < key->u.s.block_size) return STATUS_BUFFER_TOO_SMALL; - bytes_left -= key->u.s.block_size; + r = cipher + 8; + for (i = 1; i <= n; i++) + { + memcpy( b, a, 8 ); + memcpy( b + 8, r, 8 ); + key_symmetric_encrypt( key, b, 16, NULL, NULL, 0, b, 16, &len, 0 ); + memcpy( a, b, 8 ); + t = n * j + i; + a[7] ^= t; + a[6] ^= t >> 8; + a[5] ^= t >> 16; + a[4] ^= t >> 24; + memcpy( r, b + 8, 8 ); + r += 8; + } } - else if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL; - if (key->u.s.mode == CHAIN_MODE_ECB && iv) return STATUS_INVALID_PARAMETER; - if ((status = key_symmetric_set_vector( key, iv, iv_len, flags & BCRYPT_BLOCK_PADDING ))) return status; + key_destroy( key ); + return STATUS_SUCCESS; +} - decrypt_params.key = key; - decrypt_params.input = input; - decrypt_params.input_len = key->u.s.block_size; - decrypt_params.output = output; - decrypt_params.output_len = key->u.s.block_size; - while (bytes_left >= key->u.s.block_size) +static NTSTATUS key_export( struct key *key, struct key *encrypt_key, const WCHAR *type, UCHAR *output, + ULONG output_len, ULONG *size ) +{ + struct key_asymmetric_export_params params; + NTSTATUS status; + + if (encrypt_key && wcscmp( type, BCRYPT_AES_WRAP_KEY_BLOB )) { - if ((status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ))) return status; - if (key->u.s.mode == CHAIN_MODE_ECB && (status = key_symmetric_set_vector( key, NULL, 0, TRUE ))) - return status; - bytes_left -= key->u.s.block_size; - decrypt_params.input += key->u.s.block_size; - decrypt_params.output += key->u.s.block_size; + FIXME( "encryption of key not supported\n" ); + return STATUS_NOT_IMPLEMENTED; } - if (flags & BCRYPT_BLOCK_PADDING) + if (!wcscmp( type, BCRYPT_KEY_DATA_BLOB )) { - UCHAR *buf, *dst = decrypt_params.output; - if (!(buf = malloc( key->u.s.block_size ))) return STATUS_NO_MEMORY; - decrypt_params.output = buf; - status = UNIX_CALL( key_symmetric_decrypt, &decrypt_params ); - if (!status && buf[ key->u.s.block_size - 1 ] <= key->u.s.block_size) + BCRYPT_KEY_DATA_BLOB_HEADER *header = (BCRYPT_KEY_DATA_BLOB_HEADER *)output; + ULONG req_size = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key->u.s.secret_len; + + *size = req_size; + if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL; + if (output) { - *ret_len -= buf[ key->u.s.block_size - 1 ]; - if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL; - else memcpy( dst, buf, key->u.s.block_size - buf[ key->u.s.block_size - 1 ] ); + header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; + header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; + header->cbKeyData = key->u.s.secret_len; + memcpy( &header[1], key->u.s.secret, key->u.s.secret_len ); } - else status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */ - free( buf ); + return STATUS_SUCCESS; } - - if (!status) + else if (!wcscmp( type, BCRYPT_OPAQUE_KEY_BLOB )) { - if (key->u.s.vector && input_len >= key->u.s.vector_len) + ULONG len, req_size = sizeof(len) + key->u.s.secret_len; + + *size = req_size; + if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL; + if (output) { - memcpy( key->u.s.vector, input + input_len - key->u.s.vector_len, key->u.s.vector_len ); - if (iv) memcpy( iv, key->u.s.vector, min( iv_len, key->u.s.vector_len )); + *(ULONG *)output = key->u.s.secret_len; + memcpy( output + sizeof(len), key->u.s.secret, key->u.s.secret_len ); } - else FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); + return STATUS_SUCCESS; + } + else if (!wcscmp( type, BCRYPT_DSA_PRIVATE_BLOB ) || !wcscmp( type, LEGACY_DSA_V2_PRIVATE_BLOB ) || + !wcscmp( type, BCRYPT_ECCPRIVATE_BLOB ) || !wcscmp( type, BCRYPT_DH_PRIVATE_BLOB )) + { + params.key = key; + params.flags = 0; + params.buf = output; + params.len = output_len; + params.ret_len = size; + return UNIX_CALL( key_asymmetric_export, ¶ms ); + } + else if (!wcscmp( type, BCRYPT_RSAPRIVATE_BLOB ) || !wcscmp( type, BCRYPT_RSAFULLPRIVATE_BLOB )) + { + params.key = key; + params.flags = (wcscmp( type, BCRYPT_RSAPRIVATE_BLOB )) ? KEY_EXPORT_FLAG_RSA_FULL : 0; + params.buf = output; + params.len = output_len; + params.ret_len = size; + return UNIX_CALL( key_asymmetric_export, ¶ms ); + } + else if (!wcscmp( type, BCRYPT_DSA_PUBLIC_BLOB ) || !wcscmp( type, LEGACY_DSA_V2_PUBLIC_BLOB ) || + !wcscmp( type, BCRYPT_ECCPUBLIC_BLOB ) || !wcscmp( type, BCRYPT_RSAPUBLIC_BLOB ) || + !wcscmp( type, BCRYPT_DH_PUBLIC_BLOB )) + { + params.key = key; + params.flags = KEY_EXPORT_FLAG_PUBLIC; + params.buf = output; + params.len = output_len; + params.ret_len = size; + return UNIX_CALL( key_asymmetric_export, ¶ms ); } + else if (!wcscmp( type, BCRYPT_AES_WRAP_KEY_BLOB )) + { + ULONG req_size = key->u.s.secret_len + 8; - return status; -} + if (!encrypt_key) return STATUS_INVALID_PARAMETER; -static void key_destroy( struct key *key ) -{ - if (is_symmetric_key( key )) - { - UNIX_CALL( key_symmetric_destroy, key ); - free( key->u.s.vector ); - free( key->u.s.secret ); - DeleteCriticalSection( &key->u.s.cs ); + *size = req_size; + if (output) + { + if (output_len < req_size) return STATUS_BUFFER_TOO_SMALL; + if ((status = aes_wrap( encrypt_key->u.s.secret, encrypt_key->u.s.secret_len, key->u.s.secret, key->u.s.secret_len, output ))) + return status; + } + return STATUS_SUCCESS; } - else - UNIX_CALL( key_asymmetric_destroy, key ); - destroy_object( &key->hdr ); + FIXME( "unsupported key type %s\n", debugstr_w(type) ); + return STATUS_NOT_IMPLEMENTED; } static NTSTATUS convert_legacy_rsaprivate_blob( struct algorithm *alg, BCRYPT_RSAKEY_BLOB **rsa_data, @@ -1697,42 +1738,52 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP if (!wcscmp( type, BCRYPT_ECCPUBLIC_BLOB )) { BCRYPT_ECCKEY_BLOB *ecc_blob = (BCRYPT_ECCKEY_BLOB *)input; - DWORD key_size, magic; + DWORD bitlen, magic; if (input_len < sizeof(*ecc_blob)) return STATUS_INVALID_PARAMETER; switch (alg->id) { case ALG_ID_ECDH_P256: - key_size = 32; + bitlen = 256; magic = BCRYPT_ECDH_PUBLIC_P256_MAGIC; break; case ALG_ID_ECDH_P384: - key_size = 48; + bitlen = 384; magic = BCRYPT_ECDH_PUBLIC_P384_MAGIC; break; + case ALG_ID_ECDH_P521: + bitlen = 521; + magic = BCRYPT_ECDH_PUBLIC_P521_MAGIC; + break; + case ALG_ID_ECDSA_P256: - key_size = 32; + bitlen = 256; magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC; break; case ALG_ID_ECDSA_P384: - key_size = 48; + bitlen = 384; magic = BCRYPT_ECDSA_PUBLIC_P384_MAGIC; break; + case ALG_ID_ECDSA_P521: + bitlen = 521; + magic = BCRYPT_ECDSA_PUBLIC_P521_MAGIC; + break; + default: FIXME( "algorithm %u does not yet support importing blob of type %s\n", alg->id, debugstr_w(type) ); return STATUS_NOT_SUPPORTED; } if (ecc_blob->dwMagic != magic) return STATUS_INVALID_PARAMETER; - if (ecc_blob->cbKey != key_size || input_len < sizeof(*ecc_blob) + ecc_blob->cbKey * 2) + if (ecc_blob->cbKey != len_from_bitlen( bitlen ) || input_len < sizeof(*ecc_blob) + ecc_blob->cbKey * 2) return STATUS_INVALID_PARAMETER; - if ((status = key_asymmetric_create( alg->id, key_size * 8, &key ))) return status; + if ((status = key_asymmetric_create( alg->id, bitlen, &key ))) return status; params.key = key; params.flags = KEY_IMPORT_FLAG_PUBLIC; params.buf = input; @@ -1746,37 +1797,52 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP else if (!wcscmp( type, BCRYPT_ECCPRIVATE_BLOB )) { BCRYPT_ECCKEY_BLOB *ecc_blob = (BCRYPT_ECCKEY_BLOB *)input; - DWORD key_size, magic; + DWORD bitlen, magic; if (input_len < sizeof(*ecc_blob)) return STATUS_INVALID_PARAMETER; switch (alg->id) { case ALG_ID_ECDH_P256: - key_size = 32; + bitlen = 256; magic = BCRYPT_ECDH_PRIVATE_P256_MAGIC; break; case ALG_ID_ECDH_P384: - key_size = 48; + bitlen = 384; magic = BCRYPT_ECDH_PRIVATE_P384_MAGIC; break; + case ALG_ID_ECDH_P521: + bitlen = 521; + magic = BCRYPT_ECDH_PRIVATE_P521_MAGIC; + break; + case ALG_ID_ECDSA_P256: - key_size = 32; + bitlen = 256; magic = BCRYPT_ECDSA_PRIVATE_P256_MAGIC; break; + case ALG_ID_ECDSA_P384: + bitlen = 384; + magic = BCRYPT_ECDSA_PRIVATE_P384_MAGIC; + break; + + case ALG_ID_ECDSA_P521: + bitlen = 521; + magic = BCRYPT_ECDSA_PRIVATE_P521_MAGIC; + break; + default: FIXME( "algorithm %u does not yet support importing blob of type %s\n", alg->id, debugstr_w(type) ); return STATUS_NOT_SUPPORTED; } if (ecc_blob->dwMagic != magic) return STATUS_INVALID_PARAMETER; - if (ecc_blob->cbKey != key_size || input_len < sizeof(*ecc_blob) + ecc_blob->cbKey * 3) + if (ecc_blob->cbKey != len_from_bitlen( bitlen ) || input_len < sizeof(*ecc_blob) + ecc_blob->cbKey * 3) return STATUS_INVALID_PARAMETER; - if ((status = key_asymmetric_create( alg->id, key_size * 8, &key ))) return status; + if ((status = key_asymmetric_create( alg->id, bitlen, &key ))) return status; params.key = key; params.flags = 0; params.buf = input; @@ -1882,7 +1948,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP pubkey = (DSSPUBKEY *)(hdr + 1); if (pubkey->magic != MAGIC_DSS2) return STATUS_NOT_SUPPORTED; - if (input_len < sizeof(*hdr) + sizeof(*pubkey) + (pubkey->bitlen / 8) * 2 + 40 + sizeof(DSSSEED)) + if (input_len < sizeof(*hdr) + sizeof(*pubkey) + len_from_bitlen( pubkey->bitlen ) * 2 + 40 + sizeof(DSSSEED)) return STATUS_INVALID_PARAMETER; if ((status = key_asymmetric_create( alg->id, pubkey->bitlen, &key ))) return status; @@ -1915,7 +1981,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP pubkey = (DSSPUBKEY *)(hdr + 1); if (pubkey->magic != MAGIC_DSS1) return STATUS_NOT_SUPPORTED; - size = sizeof(*hdr) + sizeof(*pubkey) + (pubkey->bitlen / 8) * 3 + 20 + sizeof(DSSSEED); + size = sizeof(*hdr) + sizeof(*pubkey) + len_from_bitlen( pubkey->bitlen ) * 3 + 20 + sizeof(DSSSEED); if (input_len < size) return STATUS_INVALID_PARAMETER; if ((status = key_asymmetric_create( alg->id, pubkey->bitlen, &key ))) return status; @@ -1998,7 +2064,7 @@ NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY } if (!alg) return STATUS_INVALID_HANDLE; - if ((status = generate_symmetric_key( alg, ret_handle, secret, secret_len ))) return status; + if ((status = key_symmetric_generate( alg, ret_handle, secret, secret_len ))) return status; TRACE( "returning handle %p\n", *ret_handle ); return STATUS_SUCCESS; } @@ -2034,25 +2100,22 @@ NTSTATUS WINAPI BCryptFinalizeKeyPair( BCRYPT_KEY_HANDLE handle, ULONG flags ) return ret; } -NTSTATUS WINAPI BCryptImportKey( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY_HANDLE decrypt_key, const WCHAR *type, +NTSTATUS WINAPI BCryptImportKey( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY_HANDLE decrypt_key_handle, const WCHAR *type, BCRYPT_KEY_HANDLE *ret_handle, UCHAR *object, ULONG object_len, UCHAR *input, ULONG input_len, ULONG flags ) { struct algorithm *alg = get_alg_object( handle ); + struct key *decrypt_key = NULL; NTSTATUS status; - TRACE( "%p, %p, %s, %p, %p, %lu, %p, %lu, %#lx\n", handle, decrypt_key, debugstr_w(type), ret_handle, object, - object_len, input, input_len, flags ); + TRACE( "%p, %p, %s, %p, %p, %lu, %p, %lu, %#lx\n", handle, decrypt_key_handle, debugstr_w(type), ret_handle, + object, object_len, input, input_len, flags ); if (!alg) return STATUS_INVALID_HANDLE; if (!ret_handle || !type || !input) return STATUS_INVALID_PARAMETER; - if (decrypt_key) - { - FIXME( "decryption of key not yet supported\n" ); - return STATUS_NOT_IMPLEMENTED; - } + if (decrypt_key_handle && !(decrypt_key = get_key_object( decrypt_key_handle ))) return STATUS_INVALID_HANDLE; - if ((status = key_import( alg, type, ret_handle, object, object_len, input, input_len ))) return status; + if ((status = key_import( alg, decrypt_key, type, ret_handle, object, object_len, input, input_len ))) return status; TRACE( "returning handle %p\n", *ret_handle ); return STATUS_SUCCESS; } @@ -2061,19 +2124,16 @@ NTSTATUS WINAPI BCryptExportKey( BCRYPT_KEY_HANDLE export_key_handle, BCRYPT_KEY const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size, ULONG flags ) { struct key *key = get_key_object( export_key_handle ); + struct key *encrypt_key = NULL; TRACE( "%p, %p, %s, %p, %lu, %p, %#lx\n", export_key_handle, encrypt_key_handle, debugstr_w(type), output, output_len, size, flags ); if (!key) return STATUS_INVALID_HANDLE; if (!type || !size) return STATUS_INVALID_PARAMETER; - if (encrypt_key_handle) - { - FIXME( "encryption of key not yet supported\n" ); - return STATUS_NOT_IMPLEMENTED; - } + if (encrypt_key_handle && !(encrypt_key = get_key_object( encrypt_key_handle ))) return STATUS_INVALID_HANDLE; - return key_export( key, type, output, output_len, size ); + return key_export( key, encrypt_key, type, output, output_len, size ); } static NTSTATUS key_duplicate( struct key *key_orig, struct key **ret_key ) @@ -2148,8 +2208,10 @@ static const WCHAR *resolve_blob_type( const WCHAR *type, UCHAR *input, ULONG in { case BCRYPT_ECDH_PUBLIC_P256_MAGIC: case BCRYPT_ECDH_PUBLIC_P384_MAGIC: + case BCRYPT_ECDH_PUBLIC_P521_MAGIC: case BCRYPT_ECDSA_PUBLIC_P256_MAGIC: case BCRYPT_ECDSA_PUBLIC_P384_MAGIC: + case BCRYPT_ECDSA_PUBLIC_P521_MAGIC: return BCRYPT_ECCPUBLIC_BLOB; case BCRYPT_RSAPUBLIC_MAGIC: @@ -2268,11 +2330,6 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp } else { - if (flags & BCRYPT_PAD_NONE) - { - FIXME( "flags %#lx not implemented\n", flags ); - return STATUS_NOT_IMPLEMENTED; - } if (!is_asymmetric_encryption_key( key )) return STATUS_NOT_SUPPORTED; asymmetric_params.input = input; @@ -2315,11 +2372,6 @@ NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp } else { - if (flags & BCRYPT_PAD_NONE) - { - FIXME( "flags %#lx not implemented\n", flags ); - return STATUS_NOT_IMPLEMENTED; - } if (!is_asymmetric_encryption_key( key )) return STATUS_NOT_SUPPORTED; params.key = key; @@ -2368,23 +2420,22 @@ NTSTATUS WINAPI BCryptDeriveKeyCapi( BCRYPT_HASH_HANDLE handle, BCRYPT_ALG_HANDL { struct hash *hash = get_hash_object( handle ); UCHAR buf[MAX_HASH_OUTPUT_BYTES * 2]; - NTSTATUS status; ULONG len; TRACE( "%p, %p, %p, %lu, %#lx\n", handle, halg, key, keylen, flags ); if (!hash) return STATUS_INVALID_HANDLE; if (!key || !keylen) return STATUS_INVALID_PARAMETER; - if (keylen > builtin_algorithms[hash->alg_id].hash_length * 2) return STATUS_INVALID_PARAMETER; + if (keylen > hash->desc->hashsize * 2) return STATUS_INVALID_PARAMETER; if (halg) { FIXME( "algorithm handle not supported\n" ); return STATUS_NOT_IMPLEMENTED; } - if ((status = hash_finalize( hash, buf ))) return status; + hash_finalize( hash, buf ); - len = builtin_algorithms[hash->alg_id].hash_length; + len = hash->desc->hashsize; if (len < keylen) { UCHAR pad1[HMAC_PAD_LEN], pad2[HMAC_PAD_LEN]; @@ -2396,15 +2447,14 @@ NTSTATUS WINAPI BCryptDeriveKeyCapi( BCRYPT_HASH_HANDLE handle, BCRYPT_ALG_HANDL pad2[i] = 0x5c ^ (i < len ? buf[i] : 0); } - if ((status = hash_prepare( hash )) || - (status = hash_update( &hash->inner, hash->alg_id, pad1, sizeof(pad1) )) || - (status = hash_finalize( hash, buf ))) return status; + hash_prepare( hash ); + hash->desc->process( &hash->inner, pad1, sizeof(pad1) ); + hash_finalize( hash, buf ); - if ((status = hash_prepare( hash )) || - (status = hash_update( &hash->inner, hash->alg_id, pad2, sizeof(pad2) )) || - (status = hash_finalize( hash, buf + len ))) return status; + hash_prepare( hash ); + hash->desc->process( &hash->inner, pad2, sizeof(pad2) ); + hash_finalize( hash, buf + len ); } - memcpy( key, buf, keylen ); return STATUS_SUCCESS; } @@ -2412,10 +2462,10 @@ NTSTATUS WINAPI BCryptDeriveKeyCapi( BCRYPT_HASH_HANDLE handle, BCRYPT_ALG_HANDL static NTSTATUS pbkdf2( struct hash *hash, UCHAR *pwd, ULONG pwd_len, UCHAR *salt, ULONG salt_len, ULONGLONG iterations, ULONG i, UCHAR *dst, ULONG hash_len ) { - NTSTATUS status = STATUS_INVALID_PARAMETER; UCHAR bytes[4], *buf; ULONG j, k; + if (!iterations) return STATUS_INVALID_PARAMETER; if (!(buf = malloc( hash_len ))) return STATUS_NO_MEMORY; for (j = 0; j < iterations; j++) @@ -2423,37 +2473,26 @@ static NTSTATUS pbkdf2( struct hash *hash, UCHAR *pwd, ULONG pwd_len, UCHAR *sal if (j == 0) { /* use salt || INT(i) */ - if ((status = hash_update( &hash->inner, hash->alg_id, salt, salt_len ))) + if (salt_len && hash->desc->process( &hash->inner, salt, salt_len )) { free( buf ); - return status; + return STATUS_INVALID_PARAMETER; } bytes[0] = (i >> 24) & 0xff; bytes[1] = (i >> 16) & 0xff; bytes[2] = (i >> 8) & 0xff; bytes[3] = i & 0xff; - status = hash_update( &hash->inner, hash->alg_id, bytes, 4 ); - } - else status = hash_update( &hash->inner, hash->alg_id, buf, hash_len ); /* use U_j */ - - if (status) - { - free( buf ); - return status; - } - - if ((status = hash_finalize( hash, buf ))) - { - free( buf ); - return status; + hash->desc->process( &hash->inner, bytes, 4 ); } + else hash->desc->process( &hash->inner, buf, hash_len ); /* use U_j */ + hash_finalize( hash, buf ); if (j == 0) memcpy( dst, buf, hash_len ); else for (k = 0; k < hash_len; k++) dst[k] ^= buf[k]; } free( buf ); - return status; + return STATUS_SUCCESS; } static NTSTATUS derive_key_pbkdf2( struct algorithm *alg, UCHAR *pwd, ULONG pwd_len, UCHAR *salt, ULONG salt_len, @@ -2527,6 +2566,9 @@ NTSTATUS WINAPI BCryptSecretAgreement( BCRYPT_KEY_HANDLE privkey_handle, BCRYPT_ if (!privkey || !pubkey) return STATUS_INVALID_HANDLE; if (!is_agreement_key( privkey ) || !is_agreement_key( pubkey )) return STATUS_NOT_SUPPORTED; if (!ret_handle) return STATUS_INVALID_PARAMETER; + if (privkey->alg_id != pubkey->alg_id) return STATUS_INVALID_PARAMETER; + if (privkey->alg_id == ALG_ID_DH && !(privkey->u.a.flags & pubkey->u.a.flags & KEY_FLAG_FINALIZED)) return STATUS_INVALID_PARAMETER; + if (privkey->u.a.bitlen != pubkey->u.a.bitlen) return STATUS_INVALID_PARAMETER; if (!(secret = calloc( 1, sizeof(*secret) ))) return STATUS_NO_MEMORY; secret->hdr.magic = MAGIC_SECRET; @@ -2585,42 +2627,47 @@ static NTSTATUS derive_key_raw( struct secret *secret, UCHAR *output, ULONG outp return status; } -static BCRYPT_ALG_HANDLE hash_handle_from_desc( BCryptBufferDesc *desc ) +static struct algorithm *get_hash_alg( BCryptBuffer *buf, BOOL hmac ) { - ULONG i; - if (!desc) return BCRYPT_SHA1_ALG_HANDLE; - for (i = 0; i < desc->cBuffers; i++) - { - if (desc->pBuffers[i].BufferType == KDF_HASH_ALGORITHM) - { - const WCHAR *str = desc->pBuffers[i].pvBuffer; - if (!wcscmp( str, BCRYPT_SHA1_ALGORITHM )) return BCRYPT_SHA1_ALG_HANDLE; - else if (!wcscmp( str, BCRYPT_SHA256_ALGORITHM )) return BCRYPT_SHA256_ALG_HANDLE; - else if (!wcscmp( str, BCRYPT_SHA384_ALGORITHM )) return BCRYPT_SHA384_ALG_HANDLE; - else if (!wcscmp( str, BCRYPT_SHA512_ALGORITHM )) return BCRYPT_SHA512_ALG_HANDLE; - else - { - FIXME( "hash algorithm %s not supported\n", debugstr_w(str) ); - return NULL; - } - } - else FIXME( "buffer type %lu not supported\n", desc->pBuffers[i].BufferType ); - } + const WCHAR *str = buf->pvBuffer; + BCRYPT_ALG_HANDLE handle = NULL; + + if (!wcscmp( str, BCRYPT_SHA1_ALGORITHM )) + handle = hmac ? BCRYPT_HMAC_SHA1_ALG_HANDLE : BCRYPT_SHA1_ALG_HANDLE; + else if (!wcscmp( str, BCRYPT_SHA256_ALGORITHM )) + handle = hmac ? BCRYPT_HMAC_SHA256_ALG_HANDLE : BCRYPT_SHA256_ALG_HANDLE; + else if (!wcscmp( str, BCRYPT_SHA384_ALGORITHM )) + handle = hmac ? BCRYPT_HMAC_SHA384_ALG_HANDLE : BCRYPT_SHA384_ALG_HANDLE; + else if (!wcscmp( str, BCRYPT_SHA512_ALGORITHM )) + handle = hmac ? BCRYPT_HMAC_SHA512_ALG_HANDLE : BCRYPT_SHA512_ALG_HANDLE; - return BCRYPT_SHA1_ALG_HANDLE; + if (handle) return get_alg_object( handle ); + FIXME( "hash algorithm %s not supported\n", debugstr_w(str) ); + return NULL; } static NTSTATUS derive_key_hash( struct secret *secret, BCryptBufferDesc *desc, UCHAR *output, ULONG output_len, ULONG *ret_len ) { struct key_asymmetric_derive_key_params params; - struct algorithm *alg = get_alg_object( hash_handle_from_desc(desc) ); - ULONG hash_len, derived_key_len = secret->privkey->u.a.bitlen / 8; + ULONG hash_len, derived_key_len = len_from_bitlen( secret->privkey->u.a.bitlen ); UCHAR hash_buf[MAX_HASH_OUTPUT_BYTES]; + struct algorithm *alg = NULL; UCHAR *derived_key; NTSTATUS status; + ULONG i; + + for (i = 0; i < (desc ? desc->cBuffers : 0); i++) + { + if (desc->pBuffers[i].BufferType == KDF_HASH_ALGORITHM) + { + alg = get_hash_alg( desc->pBuffers + i, FALSE ); + if (!alg) return STATUS_NOT_SUPPORTED; + } + else FIXME( "buffer type %lu not supported\n", desc->pBuffers[i].BufferType ); + } + if (!alg) alg = get_alg_object( BCRYPT_SHA1_ALG_HANDLE ); - if (!alg) return STATUS_NOT_SUPPORTED; if (!(derived_key = malloc( derived_key_len ))) return STATUS_NO_MEMORY; params.privkey = secret->privkey; @@ -2674,6 +2721,53 @@ NTSTATUS WINAPI BCryptDeriveKey( BCRYPT_SECRET_HANDLE handle, const WCHAR *kdf, return STATUS_NOT_SUPPORTED; } +NTSTATUS WINAPI BCryptKeyDerivation( BCRYPT_KEY_HANDLE handle, BCryptBufferDesc *desc, + UCHAR *output, ULONG output_size, ULONG *ret_len, ULONG flags ) +{ + struct key *key = get_key_object( handle ); + struct algorithm *alg = NULL; + ULONGLONG iter_count = 10000; + ULONG salt_size = 0; + UCHAR *salt = NULL; + NTSTATUS status; + ULONG i; + + TRACE( "%p, %p, %p, %lu, %p, %#lx\n", key, desc, output, output_size, ret_len, flags ); + + if (!key || !desc || !ret_len) return STATUS_INVALID_PARAMETER; + if (key->alg_id != ALG_ID_PBKDF2) + { + FIXME( "unsupported key %d\n", key->alg_id ); + return STATUS_NOT_IMPLEMENTED; + } + + for (i = 0; i < desc->cBuffers; i++) + { + switch (desc->pBuffers[i].BufferType) + { + case KDF_HASH_ALGORITHM: + alg = get_hash_alg( desc->pBuffers + i, TRUE ); + break; + case KDF_SALT: + salt = desc->pBuffers[i].pvBuffer; + salt_size = desc->pBuffers[i].cbBuffer; + break; + case KDF_ITERATION_COUNT: + if (desc->pBuffers[i].cbBuffer != sizeof(ULONGLONG)) return STATUS_INVALID_PARAMETER; + iter_count = *(ULONGLONG *)desc->pBuffers[i].pvBuffer; + break; + default: + FIXME( "buffer type %lu not supported\n", desc->pBuffers[i].BufferType ); + break; + } + } + + status = derive_key_pbkdf2( alg, key->u.s.secret, key->u.s.secret_len, + salt, salt_size, iter_count, output, output_size ); + if (!status) *ret_len = output_size; + return status; +} + BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) { switch (reason) diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 582b868a36e1..eb4189a4ca88 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -48,6 +48,19 @@ #include "wine/debug.h" +#include + +#ifdef HAVE_GMP_H +#include +#endif + +#include +#include + +#ifdef HAVE_GCRYPT_H +#include +#endif + WINE_DEFAULT_DEBUG_CHANNEL(bcrypt); WINE_DECLARE_DEBUG_CHANNEL(winediag); @@ -92,6 +105,11 @@ union key_data gnutls_pubkey_t pubkey; gnutls_dh_params_t dh_params; } a; + struct /* DH */ + { + UCHAR *privkey; + UCHAR *pubkey; + } d; }; C_ASSERT( sizeof(union key_data) <= sizeof(((struct key *)0)->private) ); @@ -100,6 +118,33 @@ static union key_data *key_data( struct key *key ) return (union key_data *)key->private; } +static unsigned int dh_pubkey_len( struct key *key ) +{ + return sizeof(BCRYPT_DH_KEY_BLOB) + key->u.a.bitlen / 8 * 3; +} + +static void dh_key_free( struct key *key ) +{ + free( key_data(key)->d.privkey ); + key_data(key)->d.privkey = NULL; + free( key_data(key)->d.pubkey ); + key_data(key)->d.pubkey = NULL; +} + +static void dh_key_alloc_pub( struct key *key ) +{ + if (key_data(key)->d.pubkey) return; + key_data(key)->d.pubkey = calloc( 1, dh_pubkey_len( key )); +} + +static void dh_key_alloc_priv( struct key *key ) +{ + unsigned int bitlen = key->u.a.bitlen; + + if (key_data(key)->d.privkey) return; + key_data(key)->d.privkey = calloc( 1, bitlen / 8 ); +} + /* Not present in gnutls version < 3.0 */ static int (*pgnutls_cipher_tag)(gnutls_cipher_hd_t, void *, size_t); static int (*pgnutls_cipher_add_auth)(gnutls_cipher_hd_t, const void *, size_t); @@ -166,6 +211,19 @@ static int (*pgnutls_pubkey_import_dh_raw)(gnutls_pubkey_t, const gnutls_dh_para static int (*pgnutls_x509_spki_set_rsa_oaep_params)(gnutls_x509_spki_t, gnutls_digest_algorithm_t, gnutls_datum_t *); static void *libgnutls_handle; + +static int (*pgnutls_dh_params_generate2)(gnutls_dh_params_t dparams, unsigned int bits); +static int (*pgnutls_dh_params_import_raw2)(gnutls_dh_params_t dh_params, const gnutls_datum_t * prime, + const gnutls_datum_t * generator, unsigned key_bits); +static int (*pgnutls_dh_params_export_raw)(gnutls_dh_params_t params, gnutls_datum_t * prime, + gnutls_datum_t * generator, unsigned int *bits); + +static int (*pgnutls_ecdh_compute_key)(gnutls_ecc_curve_t curve, + const gnutls_datum_t *x, const gnutls_datum_t *y, + const gnutls_datum_t *k, + const gnutls_datum_t *peer_x, const gnutls_datum_t *peer_y, + gnutls_datum_t *Z); + #define MAKE_FUNCPTR(f) static typeof(f) * p##f MAKE_FUNCPTR(gnutls_cipher_decrypt2); MAKE_FUNCPTR(gnutls_cipher_deinit); @@ -189,6 +247,44 @@ MAKE_FUNCPTR(gnutls_pubkey_deinit); MAKE_FUNCPTR(gnutls_pubkey_encrypt_data); MAKE_FUNCPTR(gnutls_pubkey_import_privkey); MAKE_FUNCPTR(gnutls_pubkey_init); + +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) +static BOOL dh_supported; +static void *libgmp_handle; + +MAKE_FUNCPTR(mpz_init); +MAKE_FUNCPTR(mpz_clear); +MAKE_FUNCPTR(mpz_cmp); +MAKE_FUNCPTR(_mpz_cmp_ui); +MAKE_FUNCPTR(mpz_sizeinbase); +MAKE_FUNCPTR(mpz_import); +MAKE_FUNCPTR(mpz_export); +MAKE_FUNCPTR(mpz_mod); +MAKE_FUNCPTR(mpz_powm); +MAKE_FUNCPTR(mpz_sub_ui); +#endif + +static BOOL gcrypt_available; + +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) +static void *libgcrypt_handle; + +MAKE_FUNCPTR(gcry_control); +MAKE_FUNCPTR(gcry_check_version); +MAKE_FUNCPTR(gcry_sexp_build); +MAKE_FUNCPTR(gcry_pk_encrypt); +MAKE_FUNCPTR(gcry_pk_decrypt); +MAKE_FUNCPTR(gcry_mpi_new); +MAKE_FUNCPTR(gcry_mpi_print); +MAKE_FUNCPTR(gcry_sexp_release); +MAKE_FUNCPTR(gcry_mpi_release); +MAKE_FUNCPTR(gcry_strsource); +MAKE_FUNCPTR(gcry_strerror); +MAKE_FUNCPTR(gcry_sexp_find_token); +MAKE_FUNCPTR(gcry_sexp_nth_mpi); +MAKE_FUNCPTR(gcry_sexp_nth_data); +#endif + #undef MAKE_FUNCPTR static int compat_gnutls_cipher_tag(gnutls_cipher_hd_t handle, void *tag, size_t tag_size) @@ -418,6 +514,76 @@ static NTSTATUS gnutls_process_attach( void *args ) LOAD_FUNCPTR(gnutls_pubkey_init); #undef LOAD_FUNCPTR +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) +#define LOAD_FUNCPTR_STR(f) #f +#define LOAD_FUNCPTR(f) \ + if (!(p##f = dlsym( libgmp_handle, LOAD_FUNCPTR_STR(f) ))) \ + { \ + ERR( "failed to load %s\n", LOAD_FUNCPTR_STR(f) ); \ + goto fail; \ + } + + if ((libgmp_handle = dlopen( SONAME_LIBGMP, RTLD_NOW ))) + { + LOAD_FUNCPTR(mpz_init); + LOAD_FUNCPTR(mpz_clear); + LOAD_FUNCPTR(mpz_cmp); + LOAD_FUNCPTR(_mpz_cmp_ui); + LOAD_FUNCPTR(mpz_sizeinbase); + LOAD_FUNCPTR(mpz_import); + LOAD_FUNCPTR(mpz_export); + LOAD_FUNCPTR(mpz_mod); + LOAD_FUNCPTR(mpz_powm); + LOAD_FUNCPTR(mpz_sub_ui); + } + else + { + ERR_(winediag)( "failed to load libgmp, no support for DH\n" ); + goto fail; + } +#undef LOAD_FUNCPTR +#undef LOAD_FUNCPTR_STR +#endif + +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) +#define LOAD_FUNCPTR(f) \ + if (!(p##f = dlsym( libgcrypt_handle, #f ))) \ + { \ + WARN( "failed to load %s\n", #f ); \ + gcrypt_available = FALSE; \ + } + + if ((libgcrypt_handle = dlopen( SONAME_LIBGCRYPT, RTLD_NOW ))) + { + gcrypt_available = TRUE; + + LOAD_FUNCPTR(gcry_control); + LOAD_FUNCPTR(gcry_check_version); + LOAD_FUNCPTR(gcry_sexp_build); + LOAD_FUNCPTR(gcry_pk_encrypt); + LOAD_FUNCPTR(gcry_pk_decrypt); + LOAD_FUNCPTR(gcry_mpi_new); + LOAD_FUNCPTR(gcry_mpi_print); + LOAD_FUNCPTR(gcry_sexp_release); + LOAD_FUNCPTR(gcry_mpi_release); + LOAD_FUNCPTR(gcry_strsource); + LOAD_FUNCPTR(gcry_strerror); + LOAD_FUNCPTR(gcry_sexp_find_token); + LOAD_FUNCPTR(gcry_sexp_nth_mpi); + LOAD_FUNCPTR(gcry_sexp_nth_data); + + if (0) + { + pgcry_control(GCRYCTL_SET_VERBOSITY, 9); + pgcry_control(GCRYCTL_SET_DEBUG_FLAGS, ~0u); + } + } + else + WARN("failed to load gcrypt, no support for ECC secret agreement\n"); + +#undef LOAD_FUNCPTR +#endif + #define LOAD_FUNCPTR_OPT(f) \ if (!(p##f = dlsym( libgnutls_handle, #f ))) \ { \ @@ -463,6 +629,39 @@ static NTSTATUS gnutls_process_attach( void *args ) pgnutls_perror( ret ); goto fail; } + if (!(pgnutls_dh_params_init = dlsym( libgnutls_handle, "gnutls_dh_params_init" ))) + { + WARN("gnutls_dh_params_init not found\n"); + } + if (!(pgnutls_dh_params_deinit = dlsym( libgnutls_handle, "gnutls_dh_params_deinit" ))) + { + WARN("gnutls_dh_params_deinit not found\n"); + } + if (!(pgnutls_dh_params_generate2 = dlsym( libgnutls_handle, "gnutls_dh_params_generate2" ))) + { + WARN("gnutls_dh_params_generate2 not found\n"); + } + if (!(pgnutls_dh_params_import_raw2 = dlsym( libgnutls_handle, "gnutls_dh_params_import_raw2" ))) + { + WARN("gnutls_dh_params_import_raw2 not found\n"); + } + if (!(pgnutls_dh_params_export_raw = dlsym( libgnutls_handle, "gnutls_dh_params_export_raw" ))) + { + WARN("gnutls_dh_params_export_raw not found\n"); + } + +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) + dh_supported = pgnutls_dh_params_init && pgnutls_dh_params_generate2 && pgnutls_dh_params_import_raw2 + && libgmp_handle; +#else + ERR_(winediag)("Compiled without DH support.\n"); +#endif + + if (!(pgnutls_ecdh_compute_key = dlsym( libgnutls_handle, "_gnutls_ecdh_compute_key" )) + && !(pgnutls_ecdh_compute_key = dlsym( libgnutls_handle, "gnutls_ecdh_compute_key" ))) + { + WARN("gnutls_ecdh_compute_key not found\n"); + } if (TRACE_ON( bcrypt )) { @@ -477,6 +676,14 @@ static NTSTATUS gnutls_process_attach( void *args ) fail: dlclose( libgnutls_handle ); libgnutls_handle = NULL; + +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) + if (libgmp_handle) + { + dlclose( libgmp_handle ); + libgmp_handle = NULL; + } +#endif return STATUS_DLL_NOT_FOUND; } @@ -489,6 +696,16 @@ static NTSTATUS gnutls_process_detach( void *args ) libgnutls_handle = NULL; } return STATUS_SUCCESS; + +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) + dlclose( libgmp_handle ); + libgmp_handle = NULL; +#endif + +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) + dlclose( libgcrypt_handle ); + libgcrypt_handle = NULL; +#endif } struct buffer @@ -780,7 +997,7 @@ static NTSTATUS key_export_rsa_public( struct key *key, UCHAR *buf, ULONG len, U { BCRYPT_RSAKEY_BLOB *rsa_blob = (BCRYPT_RSAKEY_BLOB *)buf; gnutls_datum_t m, e; - ULONG size = key->u.a.bitlen / 8; + ULONG size = len_from_bitlen( key->u.a.bitlen ); UCHAR *dst; int ret; @@ -835,6 +1052,11 @@ static NTSTATUS key_export_ecc_public( struct key *key, UCHAR *buf, ULONG len, U size = 48; break; + case ALG_ID_ECDH_P521: + magic = BCRYPT_ECDH_PUBLIC_P521_MAGIC; + size = 66; + break; + case ALG_ID_ECDSA_P256: magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC; size = 32; @@ -845,6 +1067,11 @@ static NTSTATUS key_export_ecc_public( struct key *key, UCHAR *buf, ULONG len, U size = 48; break; + case ALG_ID_ECDSA_P521: + magic = BCRYPT_ECDSA_PUBLIC_P521_MAGIC; + size = 66; + break; + default: FIXME( "algorithm %u not supported\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; @@ -861,7 +1088,7 @@ static NTSTATUS key_export_ecc_public( struct key *key, UCHAR *buf, ULONG len, U return STATUS_INTERNAL_ERROR; } - if (curve != GNUTLS_ECC_CURVE_SECP256R1 && curve != GNUTLS_ECC_CURVE_SECP384R1) + if (curve != GNUTLS_ECC_CURVE_SECP256R1 && curve != GNUTLS_ECC_CURVE_SECP384R1 && curve != GNUTLS_ECC_CURVE_SECP521R1) { FIXME( "curve %u not supported\n", curve ); free( x.data ); free( y.data ); @@ -887,7 +1114,7 @@ static NTSTATUS key_export_dsa_public( struct key *key, UCHAR *buf, ULONG len, U { BCRYPT_DSA_KEY_BLOB *dsa_blob = (BCRYPT_DSA_KEY_BLOB *)buf; gnutls_datum_t p, q, g, y; - ULONG size = key->u.a.bitlen / 8; + ULONG size = len_from_bitlen( key->u.a.bitlen ); NTSTATUS status = STATUS_SUCCESS; UCHAR *dst; int ret; @@ -956,7 +1183,7 @@ static NTSTATUS key_export_dsa_capi_public( struct key *key, UCHAR *buf, ULONG l BLOBHEADER *hdr = (BLOBHEADER *)buf; DSSPUBKEY *dsskey; gnutls_datum_t p, q, g, y; - ULONG size = key->u.a.bitlen / 8; + ULONG size = len_from_bitlen( key->u.a.bitlen ); NTSTATUS status = STATUS_SUCCESS; UCHAR *dst; int ret; @@ -1090,6 +1317,183 @@ static gnutls_dh_params_t get_dh_params( gnutls_privkey_t privkey ) return params; } +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) +static NTSTATUS CDECL gen_random(void *buffer, unsigned int length) +{ + unsigned int read_size; + int dev_random; + + dev_random = open("/dev/urandom", O_RDONLY); + if (dev_random == -1) + { + FIXME("couldn't open /dev/urandom.\n"); + return STATUS_INTERNAL_ERROR; + } + + read_size = read(dev_random, buffer, length); + close(dev_random); + if (read_size != length) + { + FIXME("Could not read from /dev/urandom."); + return STATUS_INTERNAL_ERROR; + } + return STATUS_SUCCESS; +} + +static void import_mpz(mpz_t value, const void *input, unsigned int length) +{ + pmpz_import(value, length, 1, 1, 0, 0, input); +} + +static void export_mpz(void *output, unsigned int length, const mpz_t value) +{ + size_t export_length; + unsigned int offset; + + export_length = (pmpz_sizeinbase(value, 2) + 7) / 8; + assert(export_length <= length); + offset = length - export_length; + memset(output, 0, offset); + pmpz_export((BYTE *)output + offset, &export_length, 1, 1, 0, 0, value); + if (!export_length) + { + ERR("Zero export length, value bits %u.\n", (unsigned)pmpz_sizeinbase(value, 2)); + memset((BYTE *)output + offset, 0, length - offset); + } + else + { + assert(export_length + offset == length); + } +} + +static NTSTATUS CDECL key_dh_generate( struct key *key ) +{ + NTSTATUS status = STATUS_SUCCESS; + mpz_t p, psub1, g, privkey, pubkey; + ULONG key_length; + unsigned int i; + int ret; + + if (!dh_supported) + { + ERR("DH is not available.\n"); + return STATUS_NOT_IMPLEMENTED; + } + + if (key->u.a.flags & KEY_FLAG_FINALIZED) + { + WARN( "Key is already finalized.\n" ); + return STATUS_INVALID_HANDLE; + } + + key_length = key->u.a.bitlen / 8; + + if (!(key->u.a.flags & KEY_FLAG_DH_PARAMS_SET)) + { + gnutls_datum_t prime, generator; + gnutls_dh_params_t dh_params; + + if ((ret = pgnutls_dh_params_init( &dh_params ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + dh_key_alloc_pub( key ); + + if ((ret = pgnutls_dh_params_generate2( dh_params, key->u.a.bitlen ))) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( dh_params ); + return STATUS_INTERNAL_ERROR; + } + if ((ret = pgnutls_dh_params_export_raw( dh_params, &prime, &generator, NULL ))) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( dh_params ); + return STATUS_INTERNAL_ERROR; + } + pgnutls_dh_params_deinit( dh_params ); + + + export_gnutls_datum( (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1), key_length, &prime, 1 ); + export_gnutls_datum( (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1) + key_length, + key_length, &generator, 1 ); + free( prime.data ); + free( generator.data ); + + key->u.a.flags |= KEY_FLAG_DH_PARAMS_SET; + } + dh_key_alloc_priv( key ); + + pmpz_init(p); + pmpz_init(psub1); + pmpz_init(g); + pmpz_init(pubkey); + pmpz_init(privkey); + + import_mpz(p, (BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1, key_length); + if (!mpz_sgn(p)) + { + ERR("Got zero modulus.\n"); + status = STATUS_INTERNAL_ERROR; + goto done; + } + pmpz_sub_ui(psub1, p, 1); + + import_mpz(g, (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1) + key_length, key_length); + if (!mpz_sgn(g)) + { + ERR("Got zero generator.\n"); + status = STATUS_INTERNAL_ERROR; + goto done; + } + for (i = 0; i < 3; ++i) + { + if ((status = gen_random(key_data(key)->d.privkey, key_length))) + { + goto done; + } + import_mpz(privkey, key_data(key)->d.privkey, key_length); + + pmpz_mod(privkey, privkey, p); + pmpz_powm(pubkey, g, privkey, p); + if (p_mpz_cmp_ui(pubkey, 1)) + break; + } + if (i == 3) + { + ERR("Could not generate key after 3 iterations.\n"); + status = STATUS_INTERNAL_ERROR; + goto done; + } + + if (pmpz_cmp(pubkey, psub1) >= 0) + { + ERR("pubkey > p - 1.\n"); + status = STATUS_INTERNAL_ERROR; + goto done; + } + + export_mpz(key_data(key)->d.privkey, key_length, privkey); + export_mpz((UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1) + 2 * key_length, key_length, pubkey); + key->u.a.flags |= KEY_FLAG_FINALIZED; + +done: + pmpz_clear(psub1); + pmpz_clear(p); + pmpz_clear(g); + pmpz_clear(pubkey); + pmpz_clear(privkey); + return status; +} +#else +static NTSTATUS CDECL key_dh_generate( struct key *key ) +{ + ERR("Compiled without DH support.\n"); + return STATUS_NOT_IMPLEMENTED; +} +#endif + static NTSTATUS key_asymmetric_generate( void *args ) { struct key *key = args; @@ -1099,7 +1503,7 @@ static NTSTATUS key_asymmetric_generate( void *args ) unsigned int bitlen; if (!libgnutls_handle) return STATUS_INTERNAL_ERROR; - if (key_data(key)->a.privkey) return STATUS_INVALID_HANDLE; + if (key->alg_id != ALG_ID_DH && key_data(key)->a.privkey) return STATUS_INVALID_HANDLE; switch (key->alg_id) { @@ -1110,9 +1514,7 @@ static NTSTATUS key_asymmetric_generate( void *args ) break; case ALG_ID_DH: - pk_alg = GNUTLS_PK_DH; - bitlen = key->u.a.bitlen; - break; + return key_dh_generate( key ); case ALG_ID_DSA: pk_alg = GNUTLS_PK_DSA; @@ -1131,6 +1533,12 @@ static NTSTATUS key_asymmetric_generate( void *args ) bitlen = GNUTLS_CURVE_TO_BITS( GNUTLS_ECC_CURVE_SECP384R1 ); break; + case ALG_ID_ECDH_P521: + case ALG_ID_ECDSA_P521: + pk_alg = GNUTLS_PK_ECC; /* compatible with ECDSA and ECDH */ + bitlen = GNUTLS_CURVE_TO_BITS( GNUTLS_ECC_CURVE_SECP521R1 ); + break; + default: FIXME( "algorithm %u not supported\n", key->alg_id ); return STATUS_NOT_SUPPORTED; @@ -1150,6 +1558,7 @@ static NTSTATUS key_asymmetric_generate( void *args ) if (key->alg_id == ALG_ID_DH && !key_data(key)->a.dh_params && !(key_data(key)->a.dh_params = get_dh_params( privkey ))) { + ERR("gnutls error bitlen %u.\n", bitlen); pgnutls_privkey_deinit( privkey ); return STATUS_INTERNAL_ERROR; } @@ -1186,6 +1595,11 @@ static NTSTATUS key_export_ecc( struct key *key, UCHAR *buf, ULONG len, ULONG *r size = 48; break; + case ALG_ID_ECDH_P521: + magic = BCRYPT_ECDH_PRIVATE_P521_MAGIC; + size = 66; + break; + case ALG_ID_ECDSA_P256: magic = BCRYPT_ECDSA_PRIVATE_P256_MAGIC; size = 32; @@ -1196,6 +1610,11 @@ static NTSTATUS key_export_ecc( struct key *key, UCHAR *buf, ULONG len, ULONG *r size = 48; break; + case ALG_ID_ECDSA_P521: + magic = BCRYPT_ECDSA_PRIVATE_P521_MAGIC; + size = 66; + break; + default: FIXME( "algorithm %u does not yet support exporting ecc blob\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; @@ -1209,7 +1628,7 @@ static NTSTATUS key_export_ecc( struct key *key, UCHAR *buf, ULONG len, ULONG *r return STATUS_INTERNAL_ERROR; } - if (curve != GNUTLS_ECC_CURVE_SECP256R1 && curve != GNUTLS_ECC_CURVE_SECP384R1) + if (curve != GNUTLS_ECC_CURVE_SECP256R1 && curve != GNUTLS_ECC_CURVE_SECP384R1 && curve != GNUTLS_ECC_CURVE_SECP521R1) { FIXME( "curve %u not supported\n", curve ); free( x.data ); free( y.data ); free( d.data ); @@ -1253,6 +1672,11 @@ static NTSTATUS key_import_ecc( struct key *key, UCHAR *buf, ULONG len ) curve = GNUTLS_ECC_CURVE_SECP384R1; break; + case ALG_ID_ECDH_P521: + case ALG_ID_ECDSA_P521: + curve = GNUTLS_ECC_CURVE_SECP521R1; + break; + default: FIXME( "algorithm %u not yet supported\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; @@ -1288,7 +1712,7 @@ static NTSTATUS key_export_rsa( struct key *key, ULONG flags, UCHAR *buf, ULONG { BCRYPT_RSAKEY_BLOB *rsa_blob; gnutls_datum_t m, e, d, p, q, u, e1, e2; - ULONG size = key->u.a.bitlen / 8; + ULONG size = len_from_bitlen( key->u.a.bitlen ); BOOL full = (flags & KEY_EXPORT_FLAG_RSA_FULL); UCHAR *dst; int ret; @@ -1385,7 +1809,7 @@ static NTSTATUS key_export_dsa_capi( struct key *key, UCHAR *buf, ULONG len, ULO BLOBHEADER *hdr; DSSPUBKEY *pubkey; gnutls_datum_t p, q, g, y, x; - ULONG size = key->u.a.bitlen / 8; + ULONG size = len_from_bitlen( key->u.a.bitlen ); UCHAR *dst; int ret; @@ -1458,7 +1882,7 @@ static NTSTATUS key_import_dsa_capi( struct key *key, UCHAR *buf, ULONG len ) } pubkey = (DSSPUBKEY *)(hdr + 1); - if ((size = pubkey->bitlen / 8) > sizeof(p_data)) + if ((size = len_from_bitlen( pubkey->bitlen )) > sizeof(p_data)) { FIXME( "size %u not supported\n", size ); pgnutls_privkey_deinit( handle ); @@ -1518,6 +1942,10 @@ static NTSTATUS key_import_ecc_public( struct key *key, UCHAR *buf, ULONG len ) case ALG_ID_ECDSA_P384: curve = GNUTLS_ECC_CURVE_SECP384R1; break; + case ALG_ID_ECDH_P521: + case ALG_ID_ECDSA_P521: + curve = GNUTLS_ECC_CURVE_SECP521R1; break; + default: FIXME( "algorithm %u not yet supported\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; @@ -1630,7 +2058,7 @@ static NTSTATUS key_import_dsa_capi_public( struct key *key, UCHAR *buf, ULONG l hdr = (BLOBHEADER *)buf; pubkey = (DSSPUBKEY *)(hdr + 1); - size = pubkey->bitlen / 8; + size = len_from_bitlen( pubkey->bitlen ); data = (unsigned char *)(pubkey + 1); p.data = p_data; @@ -1664,178 +2092,88 @@ static NTSTATUS key_import_dsa_capi_public( struct key *key, UCHAR *buf, ULONG l return STATUS_SUCCESS; } -static NTSTATUS key_export_dh_public( struct key *key, UCHAR *buf, ULONG len, ULONG *ret_len ) +static NTSTATUS key_asymmetric_export( void *args ) { - BCRYPT_DH_KEY_BLOB *dh_blob = (BCRYPT_DH_KEY_BLOB *)buf; - ULONG size = key->u.a.bitlen / 8; - gnutls_dh_params_t params; - gnutls_datum_t p, g, y; - UCHAR *dst; - int ret = GNUTLS_E_INVALID_REQUEST; + const struct key_asymmetric_export_params *params = args; + struct key *key = params->key; + unsigned flags = params->flags; - if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } + if (!(key->u.a.flags & KEY_FLAG_FINALIZED)) return STATUS_INVALID_HANDLE; - if ((ret = pgnutls_pubkey_export_dh_raw( key_data(key)->a.pubkey, params, &y, 0 ))) + switch (key->alg_id) { - pgnutls_perror( ret ); - pgnutls_dh_params_deinit( params ); - return STATUS_INTERNAL_ERROR; - } + case ALG_ID_ECDH_P256: + case ALG_ID_ECDH_P384: + case ALG_ID_ECDH_P521: + case ALG_ID_ECDSA_P256: + case ALG_ID_ECDSA_P384: + case ALG_ID_ECDSA_P521: + if (flags & KEY_EXPORT_FLAG_PUBLIC) + return key_export_ecc_public( key, params->buf, params->len, params->ret_len ); + return key_export_ecc( key, params->buf, params->len, params->ret_len ); - if ((ret = pgnutls_dh_params_export_raw( params, &p, &g, NULL )) < 0) - { - pgnutls_perror( ret ); - free( y.data ); - pgnutls_dh_params_deinit( params ); - return STATUS_INTERNAL_ERROR; - } + case ALG_ID_RSA: + case ALG_ID_RSA_SIGN: + if (flags & KEY_EXPORT_FLAG_PUBLIC) + return key_export_rsa_public( key, params->buf, params->len, params->ret_len ); + return key_export_rsa( key, flags, params->buf, params->len, params->ret_len ); - *ret_len = sizeof(*dh_blob) + EXPORT_SIZE(p, size, 1) + EXPORT_SIZE(g, size, 1) + EXPORT_SIZE(y, size, 1); - if (len >= *ret_len && buf) - { - dst = (UCHAR *)(dh_blob + 1); - dst += export_gnutls_datum( dst, size, &p, 1 ); - dst += export_gnutls_datum( dst, size, &g, 1 ); - dst += export_gnutls_datum( dst, size, &y, 1 ); + case ALG_ID_DSA: + if (flags & KEY_EXPORT_FLAG_PUBLIC) + { + if (key->u.a.flags & KEY_FLAG_LEGACY_DSA_V2) + return key_export_dsa_capi_public( key, params->buf, params->len, params->ret_len ); + return key_export_dsa_public( key, params->buf, params->len, params->ret_len ); + } + if (key->u.a.flags & KEY_FLAG_LEGACY_DSA_V2) + return key_export_dsa_capi( key, params->buf, params->len, params->ret_len ); + return STATUS_NOT_IMPLEMENTED; - dh_blob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC; - dh_blob->cbKey = size; - } + case ALG_ID_DH: + if (!(key->u.a.flags & KEY_FLAG_FINALIZED)) + { + WARN( "Key is not finalized.\n" ); + return STATUS_INVALID_HANDLE; + } - free( p.data ); free( g.data ); free( y.data ); - return STATUS_SUCCESS; -} + if (flags & KEY_EXPORT_FLAG_DH_PARAMETERS) + { + BCRYPT_DH_PARAMETER_HEADER *h; + unsigned int data_size; + + data_size = sizeof(BCRYPT_DH_PARAMETER_HEADER) + key->u.a.bitlen / 8 * 2; + if (params->ret_len) *params->ret_len = data_size; + if (!params->buf) return STATUS_SUCCESS; + if (params->len < data_size) return STATUS_BUFFER_TOO_SMALL; + + h = (BCRYPT_DH_PARAMETER_HEADER *)params->buf; + h->cbLength = data_size; + h->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC; + h->cbKeyLength = key->u.a.bitlen / 8; + memcpy( h + 1, (BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1, h->cbKeyLength * 2); + } + else + { + BCRYPT_DH_KEY_BLOB *h = (BCRYPT_DH_KEY_BLOB *)params->buf; + BOOL dh_private = !(flags & KEY_EXPORT_FLAG_PUBLIC); -static NTSTATUS key_export_dh( struct key *key, UCHAR *buf, ULONG len, ULONG *ret_len ) -{ - BCRYPT_DH_KEY_BLOB *dh_blob = (BCRYPT_DH_KEY_BLOB *)buf; - gnutls_datum_t p, g, y, x; - gnutls_dh_params_t params; - ULONG size = key->u.a.bitlen / 8; - UCHAR *dst; - int ret; + if (!key_data(key)->d.pubkey || (dh_private && !key_data(key)->d.privkey)) + return STATUS_INVALID_HANDLE; - if (!key_data(key)->a.privkey) return STATUS_INVALID_PARAMETER; + *params->ret_len = dh_pubkey_len( key ); + if (dh_private) + *params->ret_len += key->u.a.bitlen / 8; - if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } + if (params->len < *params->ret_len) return STATUS_SUCCESS; - if ((ret = pgnutls_privkey_export_dh_raw( key_data(key)->a.privkey, params, &y, &x, 0 ))) - { - pgnutls_perror( ret ); - pgnutls_dh_params_deinit( params ); - return STATUS_INTERNAL_ERROR; - } - - if ((ret = pgnutls_dh_params_export_raw( params, &p, &g, NULL )) < 0) - { - pgnutls_perror( ret ); - free( y.data ); free( x.data ); - pgnutls_dh_params_deinit( params ); - return STATUS_INTERNAL_ERROR; - } - - *ret_len = sizeof(*dh_blob) + EXPORT_SIZE(p, size, 1) + EXPORT_SIZE(g, size, 1) + - EXPORT_SIZE(y, size, 1) + EXPORT_SIZE(x, size, 1); - if (len >= *ret_len && buf) - { - dst = (UCHAR *)(dh_blob + 1); - dst += export_gnutls_datum( dst, size, &p, 1 ); - dst += export_gnutls_datum( dst, size, &g, 1 ); - dst += export_gnutls_datum( dst, size, &y, 1 ); - dst += export_gnutls_datum( dst, size, &x, 1 ); - - dh_blob->dwMagic = BCRYPT_DH_PRIVATE_MAGIC; - dh_blob->cbKey = size; - } - - free( p.data ); free( g.data ); free( y.data ); free( x.data ); - pgnutls_dh_params_deinit( params ); - return STATUS_SUCCESS; -} - -static NTSTATUS key_export_dh_params( struct key *key, UCHAR *buf, ULONG len, ULONG *ret_len ) -{ - BCRYPT_DH_PARAMETER_HEADER *hdr = (BCRYPT_DH_PARAMETER_HEADER *)buf; - unsigned int size = sizeof(*hdr) + key->u.a.bitlen / 8 * 2; - gnutls_datum_t p, g; - NTSTATUS status = STATUS_SUCCESS; - UCHAR *dst; - int ret; - - if (!key_data(key)->a.dh_params) return STATUS_INVALID_PARAMETER; - - if ((ret = pgnutls_dh_params_export_raw( key_data(key)->a.dh_params, &p, &g, NULL ))) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } - - *ret_len = size; - if (len < size) status = STATUS_BUFFER_TOO_SMALL; - else if (buf) - { - hdr->cbLength = size; - hdr->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC; - hdr->cbKeyLength = key->u.a.bitlen / 8; - - dst = (UCHAR *)(hdr + 1); - dst += export_gnutls_datum( dst, hdr->cbKeyLength, &p, 1 ); - dst += export_gnutls_datum( dst, hdr->cbKeyLength, &g, 1 ); - } - - free( p.data ); free( g.data ); - return status; -} + memcpy(params->buf, key_data(key)->d.pubkey, dh_pubkey_len( key )); + if (dh_private) + memcpy(params->buf + dh_pubkey_len( key ), key_data(key)->d.privkey, key->u.a.bitlen / 8); -static NTSTATUS key_asymmetric_export( void *args ) -{ - const struct key_asymmetric_export_params *params = args; - struct key *key = params->key; - unsigned flags = params->flags; - - if (!(key->u.a.flags & KEY_FLAG_FINALIZED)) return STATUS_INVALID_HANDLE; - - switch (key->alg_id) - { - case ALG_ID_ECDH_P256: - case ALG_ID_ECDH_P384: - case ALG_ID_ECDSA_P256: - case ALG_ID_ECDSA_P384: - if (flags & KEY_EXPORT_FLAG_PUBLIC) - return key_export_ecc_public( key, params->buf, params->len, params->ret_len ); - return key_export_ecc( key, params->buf, params->len, params->ret_len ); - - case ALG_ID_RSA: - case ALG_ID_RSA_SIGN: - if (flags & KEY_EXPORT_FLAG_PUBLIC) - return key_export_rsa_public( key, params->buf, params->len, params->ret_len ); - return key_export_rsa( key, flags, params->buf, params->len, params->ret_len ); - - case ALG_ID_DSA: - if (flags & KEY_EXPORT_FLAG_PUBLIC) - { - if (key->u.a.flags & KEY_FLAG_LEGACY_DSA_V2) - return key_export_dsa_capi_public( key, params->buf, params->len, params->ret_len ); - return key_export_dsa_public( key, params->buf, params->len, params->ret_len ); + h->dwMagic = dh_private ? BCRYPT_DH_PRIVATE_MAGIC : BCRYPT_DH_PUBLIC_MAGIC; + h->cbKey = key->u.a.bitlen / 8; } - if (key->u.a.flags & KEY_FLAG_LEGACY_DSA_V2) - return key_export_dsa_capi( key, params->buf, params->len, params->ret_len ); - return STATUS_NOT_IMPLEMENTED; - - case ALG_ID_DH: - if (flags & KEY_EXPORT_FLAG_DH_PARAMETERS) - return key_export_dh_params( key, params->buf, params->len, params->ret_len ); - if (flags & KEY_EXPORT_FLAG_PUBLIC) - return key_export_dh_public( key, params->buf, params->len, params->ret_len ); - return key_export_dh( key, params->buf, params->len, params->ret_len ); + return STATUS_SUCCESS; default: FIXME( "algorithm %u not yet supported\n", key->alg_id ); @@ -1843,144 +2181,6 @@ static NTSTATUS key_asymmetric_export( void *args ) } } -static NTSTATUS key_import_dh_public( struct key *key, UCHAR *buf, ULONG len ) -{ - BCRYPT_DH_KEY_BLOB *dh_blob; - gnutls_dh_params_t params; - gnutls_datum_t p, g, y; - gnutls_pubkey_t handle; - int ret; - - if ((ret = pgnutls_pubkey_init( &handle ))) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } - - if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) - { - pgnutls_perror( ret ); - pgnutls_pubkey_deinit( handle ); - return STATUS_INTERNAL_ERROR; - } - - dh_blob = (BCRYPT_DH_KEY_BLOB *)buf; - p.data = buf + sizeof(*dh_blob); - p.size = dh_blob->cbKey; - g.data = buf + sizeof(*dh_blob) + dh_blob->cbKey; - g.size = dh_blob->cbKey; - y.data = buf + sizeof(*dh_blob) + dh_blob->cbKey * 2; - y.size = dh_blob->cbKey; - - if ((ret = pgnutls_dh_params_import_raw( params, &p, &g )) < 0) - { - pgnutls_perror( ret ); - pgnutls_dh_params_deinit( params ); - pgnutls_pubkey_deinit( handle ); - return STATUS_INTERNAL_ERROR; - } - - if ((ret = pgnutls_pubkey_import_dh_raw( handle, params, &y ))) - { - pgnutls_perror( ret ); - pgnutls_dh_params_deinit( params ); - pgnutls_pubkey_deinit( handle ); - return STATUS_INTERNAL_ERROR; - } - - if (key_data(key)->a.pubkey) pgnutls_pubkey_deinit( key_data(key)->a.pubkey ); - key_data(key)->a.pubkey = handle; - - if (key_data(key)->a.dh_params) pgnutls_dh_params_deinit( key_data(key)->a.dh_params ); - key_data(key)->a.dh_params = params; - return STATUS_SUCCESS; -} - -static NTSTATUS key_import_dh( struct key *key, UCHAR *buf, ULONG len ) -{ - BCRYPT_DH_KEY_BLOB *dh_blob; - gnutls_dh_params_t params; - gnutls_datum_t p, g, y, x; - gnutls_privkey_t handle; - int ret; - - if ((ret = pgnutls_privkey_init( &handle ))) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } - - if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) - { - pgnutls_perror( ret ); - pgnutls_privkey_deinit( handle ); - return STATUS_INTERNAL_ERROR; - } - - dh_blob = (BCRYPT_DH_KEY_BLOB *)buf; - p.data = buf + sizeof(*dh_blob); - p.size = dh_blob->cbKey; - g.data = buf + sizeof(*dh_blob) + dh_blob->cbKey; - g.size = dh_blob->cbKey; - y.data = buf + sizeof(*dh_blob) + dh_blob->cbKey * 2; - y.size = dh_blob->cbKey; - x.data = buf + sizeof(*dh_blob) + dh_blob->cbKey * 3; - x.size = dh_blob->cbKey; - - if ((ret = pgnutls_dh_params_import_raw( params, &p, &g )) < 0) - { - pgnutls_perror( ret ); - pgnutls_dh_params_deinit( params ); - pgnutls_privkey_deinit( handle ); - return STATUS_INTERNAL_ERROR; - } - - if ((ret = pgnutls_privkey_import_dh_raw( handle, params, &y, &x ))) - { - pgnutls_perror( ret ); - pgnutls_dh_params_deinit( params ); - pgnutls_privkey_deinit( handle ); - return STATUS_INTERNAL_ERROR; - } - - if (key_data(key)->a.privkey) pgnutls_privkey_deinit( key_data(key)->a.privkey ); - key_data(key)->a.privkey = handle; - - if (key_data(key)->a.dh_params) pgnutls_dh_params_deinit( key_data(key)->a.dh_params ); - key_data(key)->a.dh_params = params; - return STATUS_SUCCESS; -} - -static NTSTATUS key_import_dh_params( struct key *key, UCHAR *buf, ULONG len ) -{ - BCRYPT_DH_PARAMETER_HEADER *dh_header = (BCRYPT_DH_PARAMETER_HEADER *)buf; - gnutls_dh_params_t params; - gnutls_datum_t p, g; - int ret; - - if ((ret = pgnutls_dh_params_init( ¶ms ))) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } - - p.data = (unsigned char *)(dh_header + 1); - p.size = dh_header->cbKeyLength; - g.data = p.data + dh_header->cbKeyLength; - g.size = dh_header->cbKeyLength; - - if ((ret = pgnutls_dh_params_import_raw( params, &p, &g ))) - { - pgnutls_perror( ret ); - pgnutls_dh_params_deinit( params ); - return STATUS_INTERNAL_ERROR; - } - - if (key_data(key)->a.dh_params) pgnutls_dh_params_deinit( key_data(key)->a.dh_params ); - key_data(key)->a.dh_params = params; - return STATUS_SUCCESS; -} - static NTSTATUS key_asymmetric_import( void *args ) { const struct key_asymmetric_import_params *params = args; @@ -1993,8 +2193,10 @@ static NTSTATUS key_asymmetric_import( void *args ) { case ALG_ID_ECDH_P256: case ALG_ID_ECDH_P384: + case ALG_ID_ECDH_P521: case ALG_ID_ECDSA_P256: case ALG_ID_ECDSA_P384: + case ALG_ID_ECDSA_P521: if (flags & KEY_IMPORT_FLAG_PUBLIC) return key_import_ecc_public( key, params->buf, params->len ); ret = key_import_ecc( key, params->buf, params->len ); @@ -2023,12 +2225,56 @@ static NTSTATUS key_asymmetric_import( void *args ) return STATUS_NOT_IMPLEMENTED; case ALG_ID_DH: + if (key->u.a.flags & KEY_FLAG_FINALIZED) + { + ERR( "Key is alrady finalized.\n" ); + return STATUS_INVALID_HANDLE; + } if (flags & KEY_IMPORT_FLAG_DH_PARAMETERS) - return key_import_dh_params( key, params->buf, params->len ); - if (flags & KEY_IMPORT_FLAG_PUBLIC) - return key_import_dh_public( key, params->buf, params->len ); - ret = key_import_dh( key, params->buf, params->len ); - break; + { + const BCRYPT_DH_PARAMETER_HEADER *h = (const BCRYPT_DH_PARAMETER_HEADER *)params->buf; + ULONG param_size = sizeof(BCRYPT_DH_PARAMETER_HEADER) + key->u.a.bitlen / 8 * 2; + + if (params->len < param_size) return STATUS_BUFFER_TOO_SMALL; + if (!h || h->cbLength != param_size || h->dwMagic != BCRYPT_DH_PARAMETERS_MAGIC + || h->cbKeyLength != key->u.a.bitlen / 8) + return STATUS_INVALID_PARAMETER; + + dh_key_alloc_pub( key ); + memcpy((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1, h + 1, h->cbKeyLength * 2); + key->u.a.flags |= KEY_FLAG_DH_PARAMS_SET; + } + else + { + BCRYPT_DH_KEY_BLOB *h = (BCRYPT_DH_KEY_BLOB *)params->buf; + BOOL dh_private = !(flags & KEY_IMPORT_FLAG_PUBLIC); + ULONG size; + + if (h->dwMagic != (dh_private ? BCRYPT_DH_PRIVATE_MAGIC : BCRYPT_DH_PUBLIC_MAGIC)) + { + WARN("unexpected dwMagic %#x.\n", (int)h->dwMagic); + return STATUS_INVALID_PARAMETER; + } + + size = sizeof(*h) + h->cbKey * 3; + if (dh_private) + size += h->cbKey; + if (params->len != size) return STATUS_INVALID_PARAMETER; + if (h->cbKey * 8 < 512) return STATUS_INVALID_PARAMETER; + + dh_key_alloc_pub( key ); + + memcpy( key_data(key)->d.pubkey, params->buf, dh_pubkey_len( key )); + key->u.a.flags |= KEY_FLAG_DH_PARAMS_SET; + + if (dh_private) + { + dh_key_alloc_priv( key ); + memcpy( key_data(key)->d.privkey, params->buf + sizeof(*h) + h->cbKey * 3, h->cbKey); + } + key->u.a.flags |= KEY_FLAG_FINALIZED; + } + return STATUS_SUCCESS; default: FIXME( "algorithm %u not yet supported\n", key->alg_id ); @@ -2093,6 +2339,7 @@ static NTSTATUS prepare_gnutls_signature( struct key *key, UCHAR *signature, ULO { case ALG_ID_ECDSA_P256: case ALG_ID_ECDSA_P384: + case ALG_ID_ECDSA_P521: case ALG_ID_DSA: return prepare_gnutls_signature_dsa( key, signature, signature_len, gnutls_signature ); @@ -2159,6 +2406,7 @@ static NTSTATUS key_asymmetric_verify( void *args ) { case ALG_ID_ECDSA_P256: case ALG_ID_ECDSA_P384: + case ALG_ID_ECDSA_P521: { if (flags) FIXME( "flags %#x not supported\n", flags ); @@ -2253,6 +2501,7 @@ static unsigned int get_signature_length( enum alg_id id ) { case ALG_ID_ECDSA_P256: return 64; case ALG_ID_ECDSA_P384: return 96; + case ALG_ID_ECDSA_P521: return 132; case ALG_ID_DSA: return 40; default: FIXME( "unhandled algorithm %u\n", id ); @@ -2275,6 +2524,7 @@ static NTSTATUS format_gnutls_signature( enum alg_id type, gnutls_datum_t signat } case ALG_ID_ECDSA_P256: case ALG_ID_ECDSA_P384: + case ALG_ID_ECDSA_P521: case ALG_ID_DSA: { int err; @@ -2341,7 +2591,7 @@ static NTSTATUS key_asymmetric_sign( void *args ) NTSTATUS status; int ret; - if (key->alg_id == ALG_ID_ECDSA_P256 || key->alg_id == ALG_ID_ECDSA_P384) + if (key->alg_id == ALG_ID_ECDSA_P256 || key->alg_id == ALG_ID_ECDSA_P384 || key->alg_id == ALG_ID_ECDSA_P521) { /* With ECDSA, we find the digest algorithm from the hash length, and verify it */ switch (params->input_len) @@ -2428,7 +2678,7 @@ static NTSTATUS key_asymmetric_sign( void *args ) if (!params->output) { - *params->ret_len = key->u.a.bitlen / 8; + *params->ret_len = len_from_bitlen( key->u.a.bitlen ); return STATUS_SUCCESS; } if (!key_data(key)->a.privkey) return STATUS_INVALID_PARAMETER; @@ -2454,8 +2704,15 @@ static NTSTATUS key_asymmetric_destroy( void *args ) { struct key *key = args; - if (key_data(key)->a.privkey) pgnutls_privkey_deinit( key_data(key)->a.privkey ); - if (key_data(key)->a.pubkey) pgnutls_pubkey_deinit( key_data(key)->a.pubkey ); + if (key->alg_id == ALG_ID_DH) + { + dh_key_free( key ); + } + else + { + if (key_data(key)->a.privkey) pgnutls_privkey_deinit( key_data(key)->a.privkey ); + if (key_data(key)->a.pubkey) pgnutls_pubkey_deinit( key_data(key)->a.pubkey ); + } if (key_data(key)->a.dh_params) pgnutls_dh_params_deinit( key_data(key)->a.dh_params ); return STATUS_SUCCESS; } @@ -2497,8 +2754,10 @@ static NTSTATUS dup_privkey( struct key *key_orig, struct key *key_copy ) } case ALG_ID_ECDH_P256: case ALG_ID_ECDH_P384: + case ALG_ID_ECDH_P521: case ALG_ID_ECDSA_P256: case ALG_ID_ECDSA_P384: + case ALG_ID_ECDSA_P521: { gnutls_ecc_curve_t curve; gnutls_datum_t x, y, k; @@ -2508,22 +2767,7 @@ static NTSTATUS dup_privkey( struct key *key_orig, struct key *key_copy ) free( x.data ); free( y.data ); free( k.data ); break; } - case ALG_ID_DH: - { - gnutls_dh_params_t params; - gnutls_datum_t y, x; - if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) break; - if ((ret = pgnutls_privkey_export_dh_raw( key_data(key_orig)->a.privkey, params, &y, &x, 0 )) < 0) - { - pgnutls_dh_params_deinit( params ); - break; - } - ret = pgnutls_privkey_import_dh_raw( privkey, params, &y, &x ); - pgnutls_dh_params_deinit( params ); - free( x.data ); free( y.data ); - break; - } default: ERR( "unhandled algorithm %u\n", key_orig->alg_id ); pgnutls_privkey_deinit( privkey ); @@ -2576,8 +2820,10 @@ static NTSTATUS dup_pubkey( struct key *key_orig, struct key *key_copy ) } case ALG_ID_ECDH_P256: case ALG_ID_ECDH_P384: + case ALG_ID_ECDH_P521: case ALG_ID_ECDSA_P256: case ALG_ID_ECDSA_P384: + case ALG_ID_ECDSA_P521: { gnutls_ecc_curve_t curve; gnutls_datum_t x, y; @@ -2587,22 +2833,6 @@ static NTSTATUS dup_pubkey( struct key *key_orig, struct key *key_copy ) free( x.data ); free( y.data ); break; } - case ALG_ID_DH: - { - gnutls_dh_params_t params; - gnutls_datum_t y; - - if ((ret = pgnutls_dh_params_init( ¶ms )) < 0) break; - if ((ret = pgnutls_pubkey_export_dh_raw( key_data(key_orig)->a.pubkey, params, &y, 0 )) < 0) - { - pgnutls_dh_params_deinit( params ); - break; - } - ret = pgnutls_pubkey_import_dh_raw( pubkey, params, &y ); - pgnutls_dh_params_deinit( params ); - free( y.data ); - break; - } default: ERR( "unhandled algorithm %u\n", key_orig->alg_id ); pgnutls_pubkey_deinit( pubkey ); @@ -2625,6 +2855,23 @@ static NTSTATUS key_asymmetric_duplicate( void *args ) const struct key_asymmetric_duplicate_params *params = args; NTSTATUS status; + if (params->key_orig->alg_id == ALG_ID_DH) + { + union key_data *s = key_data( params->key_orig ); + union key_data *d = key_data( params->key_copy ); + if (s->d.privkey) + { + dh_key_alloc_priv( params->key_copy ); + memcpy( d->d.privkey, s->d.privkey, params->key_orig->u.a.bitlen / 8 ); + } + if (s->d.pubkey) + { + dh_key_alloc_pub( params->key_copy ); + memcpy( d->d.pubkey, s->d.pubkey, dh_pubkey_len( params->key_orig )); + } + return STATUS_SUCCESS; + } + if (key_data(params->key_orig)->a.privkey && (status = dup_privkey( params->key_orig, params->key_copy ))) return status; @@ -2655,6 +2902,8 @@ static NTSTATUS privkey_set_rsa_oaep_params( gnutls_privkey_t key, gnutls_digest return STATUS_SUCCESS; } +static NTSTATUS key_asymmetric_decrypt_gcrypt( void *args ); + static NTSTATUS key_asymmetric_decrypt( void *args ) { const struct key_asymmetric_decrypt_params *params = args; @@ -2662,6 +2911,9 @@ static NTSTATUS key_asymmetric_decrypt( void *args ) NTSTATUS status = STATUS_SUCCESS; int ret; + if (gcrypt_available && (params->flags == BCRYPT_PAD_NONE || params->flags == BCRYPT_PAD_OAEP)) + return key_asymmetric_decrypt_gcrypt( args ); + if (params->key->alg_id == ALG_ID_RSA && params->flags & BCRYPT_PAD_OAEP) { BCRYPT_OAEP_PADDING_INFO *pad = params->padding; @@ -2721,6 +2973,300 @@ static NTSTATUS pubkey_set_rsa_oaep_params( gnutls_pubkey_t key, gnutls_digest_a return STATUS_SUCCESS; } +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) +const char * gcrypt_hash_algorithm_name(LPCWSTR alg_id) +{ + if (!wcscmp( alg_id, BCRYPT_SHA1_ALGORITHM )) return "sha1"; + if (!wcscmp( alg_id, BCRYPT_SHA256_ALGORITHM )) return "sha256"; + if (!wcscmp( alg_id, BCRYPT_SHA384_ALGORITHM )) return "sha384"; + if (!wcscmp( alg_id, BCRYPT_SHA512_ALGORITHM )) return "sha512"; + if (!wcscmp( alg_id, BCRYPT_MD2_ALGORITHM )) return "md2"; + if (!wcscmp( alg_id, BCRYPT_MD5_ALGORITHM )) return "md5"; + return NULL; +} + +static NTSTATUS key_asymmetric_encrypt_gcrypt( void *args ) +{ + const struct key_asymmetric_encrypt_params *params = args; + struct key *key = params->key; + UCHAR *input = params->input; + ULONG input_len = params->input_len; + UCHAR *output = params->output; + ULONG *ret_len = params->ret_len; + void *padding = params->padding; + ULONG flags = params->flags; + BCRYPT_OAEP_PADDING_INFO *oaep_info = padding; + NTSTATUS status; + gcry_sexp_t sexp_pubkey = NULL; + gcry_sexp_t sexp_result = NULL; + gcry_sexp_t sexp_input = NULL; + BCRYPT_RSAKEY_BLOB *rsa_blob; + gcry_sexp_t mpi_a = NULL; + gnutls_datum_t result; + size_t result_len; + gcry_error_t err; + ULONG len; + + if (!gcrypt_available) + { + ERR("Asymmetric encryption not available.\n"); + return STATUS_INTERNAL_ERROR; + } + + if (key->alg_id != ALG_ID_RSA) + { + FIXME("Unsupported algorithm id: %u\n", key->alg_id); + return STATUS_INTERNAL_ERROR; + } + + if (flags == BCRYPT_PAD_NONE && input_len != key->u.a.bitlen / 8) + { + WARN( "Invalid input_len %u for BCRYPT_PAD_NONE.\n", (int)input_len ); + return STATUS_INVALID_PARAMETER; + } + + /* import RSA key */ + if ((status = key_export_rsa_public( key, NULL, 0, &len ))) + { + ERR( "Key export failed.\n" ); + return status; + } + rsa_blob = malloc( len ); + if ((status = key_export_rsa_public( key, (UCHAR *)rsa_blob, len, &len ))) + { + ERR( "Key export failed.\n" ); + return status; + } + err = pgcry_sexp_build(&sexp_pubkey, NULL, + "(public-key(rsa (e %b)(n %b)))", + rsa_blob->cbPublicExp, + (UCHAR *)(rsa_blob + 1), + rsa_blob->cbModulus, + (UCHAR *)(rsa_blob + 1) + rsa_blob->cbPublicExp); + free( rsa_blob ); + if (err) + { + ERR("Failed to build gcrypt public key\n"); + goto done; + } + + /* import input data with necessary padding */ + if (flags == BCRYPT_PAD_PKCS1) + { + err = pgcry_sexp_build(&sexp_input, NULL, + "(data(flags pkcs1)(value %b))", + input_len, + input); + } + else if (flags == BCRYPT_PAD_OAEP) + { + if (oaep_info->pbLabel) + err = pgcry_sexp_build(&sexp_input, NULL, + "(data(flags oaep)(hash-algo %s)(label %b)(value %b))", + gcrypt_hash_algorithm_name(oaep_info->pszAlgId), + oaep_info->cbLabel, + oaep_info->pbLabel, + input_len, + input); + else + err = pgcry_sexp_build(&sexp_input, NULL, + "(data(flags oaep)(hash-algo %s)(value %b))", + gcrypt_hash_algorithm_name(oaep_info->pszAlgId), + input_len, + input); + } + else if (flags == BCRYPT_PAD_NONE) + { + err = pgcry_sexp_build(&sexp_input, NULL, + "(data(flags raw)(value %b))", + input_len, + input); + } + else + { + status = STATUS_INVALID_PARAMETER; + goto done; + } + + if (err) + { + ERR("Failed to build gcrypt padded input data\n"); + goto done; + } + + if ((err = pgcry_pk_encrypt(&sexp_result, sexp_input, sexp_pubkey))) + { + ERR("Failed to encrypt data\n"); + goto done; + } + + mpi_a = pgcry_sexp_find_token(sexp_result, "a", 0); + result.data = (void *)pgcry_sexp_nth_data(mpi_a, 1, &result_len); + + result.size = result_len; + result_len = EXPORT_SIZE(result, key->u.a.bitlen / 8, 1); + *ret_len = result_len; + + if (params->output_len >= result_len) export_gnutls_datum(output, result_len, &result, 1); + else if (params->output_len == 0) status = STATUS_SUCCESS; + else status = STATUS_BUFFER_TOO_SMALL; + +done: + pgcry_sexp_release(sexp_input); + pgcry_sexp_release(sexp_pubkey); + pgcry_sexp_release(sexp_result); + pgcry_sexp_release(mpi_a); + + if (status) + return status; + + if (err) + { + ERR("Error = %s/%s\n", pgcry_strsource (err), pgcry_strerror (err)); + return STATUS_INTERNAL_ERROR; + } + + return STATUS_SUCCESS; +} + +static NTSTATUS key_asymmetric_decrypt_gcrypt( void *args ) +{ + const struct key_asymmetric_encrypt_params *params = args; + gnutls_datum_t m, e, d, p, q, u, e1, e2; + struct key *key = params->key; + UCHAR *input = params->input; + ULONG input_len = params->input_len; + UCHAR *output = params->output; + ULONG *ret_len = params->ret_len; + void *padding = params->padding; + ULONG flags = params->flags; + BCRYPT_OAEP_PADDING_INFO *oaep_info = padding; + NTSTATUS status; + gcry_sexp_t sexp_privkey = NULL; + gcry_sexp_t sexp_result = NULL; + gcry_sexp_t sexp_input = NULL; + gnutls_datum_t result; + size_t result_len; + gcry_error_t err; + int ret; + + if (!gcrypt_available) + { + ERR( "Asymmetric decryption not available.\n" ); + return STATUS_INTERNAL_ERROR; + } + + if (key->alg_id != ALG_ID_RSA) + { + FIXME( "Unsupported algorithm id: %u\n", key->alg_id ); + return STATUS_INTERNAL_ERROR; + } + + if ((ret = pgnutls_privkey_export_rsa_raw( key_data(key)->a.privkey, &m, &e, &d, &p, &q, &u, &e1, &e2 ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + err = pgcry_sexp_build(&sexp_privkey, NULL, + "(private-key(rsa (e %b)(n %b)(d %b)))", + e.size, e.data, + m.size, m.data, + d.size, d.data); + free( m.data ); free( e.data ); free( d.data ); free( p.data ); free( q.data ); free( u.data ); + free( e1.data ); free( e2.data ); + + if (err) + { + ERR( "Failed to build gcrypt private key\n" ); + status = STATUS_INVALID_PARAMETER; + goto done; + } + + if (flags == BCRYPT_PAD_PKCS1) err = pgcry_sexp_build( &sexp_input, NULL, "(enc-val (flags pkcs1)(rsa (a %b)))", input_len, input ); + else if (flags == BCRYPT_PAD_OAEP) + { + if (oaep_info->pbLabel) + err = pgcry_sexp_build( &sexp_input, NULL, + "(enc-val (flags oaep)(hash-algo %s)(label %b)(rsa (a %b)))", + gcrypt_hash_algorithm_name(oaep_info->pszAlgId), + oaep_info->cbLabel, + oaep_info->pbLabel, + input_len, + input ); + else + err = pgcry_sexp_build( &sexp_input, NULL, + "(enc-val (flags oaep)(hash-algo %s)(rsa (a %b)))", + gcrypt_hash_algorithm_name(oaep_info->pszAlgId), + input_len, + input ); + } + else if (flags == BCRYPT_PAD_NONE) err = pgcry_sexp_build( &sexp_input, NULL, "(enc-val (flags raw)(rsa (a %b)))", input_len, input ); + else + { + status = STATUS_INVALID_PARAMETER; + goto done; + } + + if (err) + { + ERR( "Failed to build gcrypt padded input data\n" ); + status = STATUS_INVALID_PARAMETER; + goto done; + } + + if ((err = pgcry_pk_decrypt( &sexp_result, sexp_input, sexp_privkey ))) + { + ERR( "Failed to decrypt data\n" ); + status = STATUS_INVALID_PARAMETER; + goto done; + } + + result.data = (void *)pgcry_sexp_nth_data(sexp_result, 1, &result_len); + result.size = result_len; + if (flags == BCRYPT_PAD_NONE) result_len = EXPORT_SIZE(result, key->u.a.bitlen / 8, 1); + *ret_len = result_len; + + if (params->output_len >= result_len) + { + status = STATUS_SUCCESS; + if (flags == BCRYPT_PAD_NONE) + export_gnutls_datum(output, result_len, &result, 1); + else + memcpy(output, result.data, result_len); + } + else if (params->output_len == 0) status = STATUS_SUCCESS; + else status = STATUS_BUFFER_TOO_SMALL; + +done: + pgcry_sexp_release(sexp_input); + pgcry_sexp_release(sexp_privkey); + pgcry_sexp_release(sexp_result); + + if (status) return status; + + if (err) + { + ERR( "Error %s/%s\n", pgcry_strsource (err), pgcry_strerror (err) ); + return STATUS_INTERNAL_ERROR; + } + + return STATUS_SUCCESS; +} + +#else +static NTSTATUS key_asymmetric_encrypt_gcrypt( void *args ) +{ + ERR("Asymmetric key encryption not supported without gcrypt.\n"); + return STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS key_asymmetric_decrypt_gcrypt( void *args ) +{ + ERR("Asymmetric key encryption not supported without gcrypt.\n"); + return STATUS_NOT_IMPLEMENTED; +} +#endif + static NTSTATUS key_asymmetric_encrypt( void *args ) { const struct key_asymmetric_encrypt_params *params = args; @@ -2730,6 +3276,15 @@ static NTSTATUS key_asymmetric_encrypt( void *args ) if (!key_data(params->key)->a.pubkey) return STATUS_INVALID_HANDLE; + if (params->key->alg_id == ALG_ID_RSA + && (!params->output || len_from_bitlen( params->key->u.a.bitlen ) > params->output_len)) + { + *params->ret_len = len_from_bitlen( params->key->u.a.bitlen ); + return !params->output ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL; + } + if (gcrypt_available && (params->flags == BCRYPT_PAD_NONE || params->flags == BCRYPT_PAD_OAEP)) + return key_asymmetric_encrypt_gcrypt( args ); + if (params->key->alg_id == ALG_ID_RSA && params->flags & BCRYPT_PAD_OAEP) { BCRYPT_OAEP_PADDING_INFO *pad = params->padding; @@ -2769,21 +3324,254 @@ static NTSTATUS key_asymmetric_encrypt( void *args ) return status; } +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) +static NTSTATUS gcrypt_extract_result_into_secret(gcry_sexp_t result, gnutls_datum_t *s) +{ + NTSTATUS status = STATUS_SUCCESS; + gcry_mpi_t fullcoords = NULL; + gcry_sexp_t fragment = NULL; + UCHAR *tmp_buffer = NULL; + gcry_error_t err; + size_t size; + + fragment = pgcry_sexp_find_token( result, "s", 0 ); + if (!fragment) + { + status = STATUS_NO_MEMORY; + goto done; + } + + fullcoords = pgcry_sexp_nth_mpi( fragment, 1, GCRYMPI_FMT_USG ); + if (!fullcoords) + { + status = STATUS_NO_MEMORY; + goto done; + } + + if ((err = pgcry_mpi_print( GCRYMPI_FMT_USG, NULL, 0, &size, fullcoords)) ) + { + ERR("Error = %s/%s.\n", pgcry_strsource( err ), pgcry_strerror( err )); + status = STATUS_INTERNAL_ERROR; + goto done; + } + + tmp_buffer = malloc(size); + if ((err = pgcry_mpi_print( GCRYMPI_FMT_STD, tmp_buffer, size, NULL, fullcoords)) ) + { + ERR( "Error = %s/%s.\n", pgcry_strsource(err), pgcry_strerror(err) ); + status = STATUS_INTERNAL_ERROR; + goto done; + } + + s->size = size / 2; + s->data = malloc( s->size ); + memcpy( s->data, tmp_buffer + size % 2, size / 2 ); + +done: + free( tmp_buffer ); + + pgcry_mpi_release( fullcoords ); + pgcry_sexp_release( fragment ); + + return status; +} +#endif + + static NTSTATUS key_asymmetric_derive_key( void *args ) { const struct key_asymmetric_derive_key_params *params = args; - gnutls_datum_t s; NTSTATUS status = STATUS_SUCCESS; - int ret; + gnutls_datum_t s = { NULL }; + struct key *priv_key; + struct key *peer_key; - if ((ret = pgnutls_privkey_derive_secret( key_data(params->privkey)->a.privkey, - key_data(params->pubkey)->a.pubkey, NULL, &s, 0 ))) + priv_key = params->privkey; + peer_key = params->pubkey; + + switch (priv_key->alg_id) { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; + case ALG_ID_DH: +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) + { + mpz_t p, priv, peer, k; + ULONG key_length; + + if (!dh_supported) + { + ERR("DH is not available.\n"); + return STATUS_NOT_IMPLEMENTED; + } + + if (!(priv_key->u.a.flags & KEY_FLAG_FINALIZED) || !(peer_key->u.a.flags & KEY_FLAG_FINALIZED) + || !key_data(priv_key)->d.privkey) + { + WARN( "Keys are not initialized.\n" ); + return STATUS_INVALID_HANDLE; + } + + key_length = priv_key->u.a.bitlen / 8; + + if (memcmp((BCRYPT_DH_KEY_BLOB *)key_data(priv_key)->d.pubkey + 1, + (BCRYPT_DH_KEY_BLOB *)key_data(peer_key)->d.pubkey + 1, 2 * key_length)) + { + ERR("peer DH paramaters do not match.\n"); + return STATUS_INTERNAL_ERROR; + } + + pmpz_init(p); + pmpz_init(priv); + pmpz_init(peer); + pmpz_init(k); + + import_mpz(p, (BCRYPT_DH_KEY_BLOB *)key_data(priv_key)->d.pubkey + 1, key_length); + if (pmpz_sizeinbase(p, 2) < 2) + { + ERR("Invalid prime.\n"); + pmpz_clear(p); + pmpz_clear(priv); + pmpz_clear(peer); + pmpz_clear(k); + return STATUS_INTERNAL_ERROR; + } + import_mpz(priv, key_data(priv_key)->d.privkey, key_length); + import_mpz(peer, key_data(peer_key)->d.pubkey + sizeof(BCRYPT_DH_KEY_BLOB) + 2 * key_length, key_length); + pmpz_powm(k, peer, priv, p); + + s.size = key_length; + s.data = malloc( s.size ); + export_mpz(s.data, key_length, k); + + pmpz_clear(p); + pmpz_clear(priv); + pmpz_clear(peer); + pmpz_clear(k); + break; + } +#else + ERR_(winediag)("Compiled without DH support.\n"); + return STATUS_NOT_IMPLEMENTED; +#endif + + case ALG_ID_ECDH_P256: + case ALG_ID_ECDH_P384: + case ALG_ID_ECDH_P521: +/* this is necessary since GNUTLS doesn't support ECDH public key encryption, maybe we can replace this when it does: + https://github.com/gnutls/gnutls/blob/cdc4fc288d87f91f974aa23b6e8595a53970ce00/lib/nettle/pk.c#L495 */ +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) + { + gcry_sexp_t xchg_result = NULL; + gcry_sexp_t privkey = NULL; + gcry_sexp_t pubkey = NULL; + const char *pubkey_format; + BCRYPT_ECCKEY_BLOB *h; + UCHAR *privkey_blob; + UCHAR *pubkey_raw; + gcry_error_t err; + ULONG key_length; + NTSTATUS status; + ULONG key_len; + + if (!gcrypt_available) + { + ERR("ECDH secret agreement is not available.\n"); + return STATUS_NOT_IMPLEMENTED; + } + + if (priv_key->alg_id == ALG_ID_ECDH_P256) + { + pubkey_format = "NIST P-256"; + key_length = 32; + } + else if (priv_key->alg_id == ALG_ID_ECDH_P384) + { + pubkey_format = "NIST P-384"; + key_length = 48; + } + else if (priv_key->alg_id == ALG_ID_ECDH_P521) + { + pubkey_format = "NIST P-521"; + key_length = 66; + } + else return STATUS_NOT_IMPLEMENTED; + + if (key_length != len_from_bitlen( priv_key->u.a.bitlen )) + { + ERR( "Key length mismatch, key->u.a.bitlen %u, key_length %u.\n", (int)priv_key->u.a.bitlen, + (int)key_length ); + return STATUS_INVALID_PARAMETER; + } + + if ((status = key_export_ecc( priv_key, NULL, 0, &key_len ))) + return status; + privkey_blob = malloc( key_len ); + if ((status = key_export_ecc( priv_key, privkey_blob, key_len, &key_len ))) + { + free( privkey_blob ); + return status; + } + + if ((status = key_export_ecc_public( peer_key, NULL, 0, &key_len ))) + return status; + h = malloc( key_len ); + if ((status = key_export_ecc_public( peer_key, (UCHAR *)h, key_len, &key_len ))) + { + free( privkey_blob ); + return status; + } + + /* copy public key into temporary buffer so we can prepend 0x04 (to indicate it is uncompressed) */ + pubkey_raw = malloc( (key_length * 2) + 1 ); + pubkey_raw[0] = 0x04; + memcpy( pubkey_raw + 1, h + 1, key_length * 2 ); + free( h ); + + err = pgcry_sexp_build( &pubkey, NULL, "(key-data(public-key(ecdh(curve %s)(q %b))))", pubkey_format, + (key_length * 2) + 1, pubkey_raw ); + free( pubkey_raw ); + if (err) + { + free( privkey_blob ); + ERR( "Failed to build gcrypt public key. err %s/%s\n", pgcry_strsource( err ), pgcry_strerror( err )); + return STATUS_INTERNAL_ERROR; + } + + err = pgcry_sexp_build( &privkey, NULL, "(data(flags raw)(value %b))", key_length, + privkey_blob + sizeof(BCRYPT_ECCKEY_BLOB) + key_length * 2 ); + free( privkey_blob ); + if (err) + { + pgcry_sexp_release( pubkey ); + return STATUS_INTERNAL_ERROR; + } + err = pgcry_pk_encrypt( &xchg_result, privkey, pubkey ); + pgcry_sexp_release( privkey ); + pgcry_sexp_release( pubkey ); + if (err) + { + ERR( "Failed to perform key exchange. err %s/%s\n", pgcry_strsource( err ), pgcry_strerror( err )); + return STATUS_INTERNAL_ERROR; + } + status = gcrypt_extract_result_into_secret( xchg_result, &s ); + pgcry_sexp_release(xchg_result); + if (status) + { + ERR("Failed to extract secret key.\n"); + return status; + } + break; + } +#else + WARN("Compiled without ECC secret support.\n"); + return STATUS_NOT_IMPLEMENTED; +#endif + + default: + ERR( "unhandled algorithm %u\n", priv_key->alg_id ); + return STATUS_INVALID_HANDLE; } - *params->ret_len = EXPORT_SIZE( s, params->privkey->u.a.bitlen / 8, 1 ); + *params->ret_len = EXPORT_SIZE( s, len_from_bitlen( params->privkey->u.a.bitlen ), 1 ); if (params->output) { if (params->output_len < *params->ret_len) status = STATUS_BUFFER_TOO_SMALL; diff --git a/dlls/bcrypt/md2.c b/dlls/bcrypt/md2.c deleted file mode 100644 index 3ff25dad1639..000000000000 --- a/dlls/bcrypt/md2.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * MD2 (RFC 1319) hash function implementation by Tom St Denis - * - * Copyright 2004 Michael Jung - * Based on public domain code by Tom St Denis (tomstdenis@iahu.ca) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* - * This file contains code from the LibTomCrypt cryptographic - * library written by Tom St Denis (tomstdenis@iahu.ca). LibTomCrypt - * is in the public domain. The code in this file is tailored to - * special requirements. Take a look at http://libtomcrypt.org for the - * original version. - */ - -#include -#include "bcrypt_internal.h" - -static const unsigned char PI_SUBST[256] = { - 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, - 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, - 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, - 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, - 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, - 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, - 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, - 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, - 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, - 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, - 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, - 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, - 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, - 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, - 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, - 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, - 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, - 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 -}; - -/* adds 16 bytes to the checksum */ -static void md2_update_chksum(MD2_CTX *md2) -{ - int j; - unsigned char L; - L = md2->chksum[15]; - for (j = 0; j < 16; j++) { - -/* caution, the RFC says its "C[j] = S[M[i*16+j] xor L]" but the reference source code [and test vectors] say - otherwise. -*/ - L = (md2->chksum[j] ^= PI_SUBST[(int)(md2->buf[j] ^ L)] & 255); - } -} - -static void md2_compress(MD2_CTX *md2) -{ - int j, k; - unsigned char t; - - /* copy block */ - for (j = 0; j < 16; j++) { - md2->X[16+j] = md2->buf[j]; - md2->X[32+j] = md2->X[j] ^ md2->X[16+j]; - } - - t = 0; - - /* do 18 rounds */ - for (j = 0; j < 18; j++) { - for (k = 0; k < 48; k++) { - t = (md2->X[k] ^= PI_SUBST[(int)(t & 255)]); - } - t = (t + (unsigned char)j) & 255; - } -} - -void md2_init(MD2_CTX *md2) -{ - /* MD2 uses a zero'ed state... */ - memset(md2->X, 0, sizeof(md2->X)); - memset(md2->chksum, 0, sizeof(md2->chksum)); - memset(md2->buf, 0, sizeof(md2->buf)); - md2->curlen = 0; -} - -void md2_update(MD2_CTX *md2, const unsigned char *buf, ULONG len) -{ - unsigned long n; - - assert(md2->curlen <= sizeof(md2->buf)); - - while (len > 0) { - n = min(len, (16 - md2->curlen)); - memcpy(md2->buf + md2->curlen, buf, (size_t)n); - md2->curlen += n; - buf += n; - len -= n; - - /* is 16 bytes full? */ - if (md2->curlen == 16) { - md2_compress(md2); - md2_update_chksum(md2); - md2->curlen = 0; - } - } -} - -void md2_finalize(MD2_CTX * md2, unsigned char *hash) -{ - unsigned long i, k; - - assert(md2->curlen <= sizeof(md2->buf)); - - /* pad the message */ - k = 16 - md2->curlen; - for (i = md2->curlen; i < 16; i++) { - md2->buf[i] = (unsigned char)k; - } - - /* hash and update */ - md2_compress(md2); - md2_update_chksum(md2); - - /* hash checksum */ - memcpy(md2->buf, md2->chksum, 16); - md2_compress(md2); - - /* output is lower 16 bytes of X */ - memcpy(hash, md2->X, 16); -} diff --git a/dlls/bcrypt/sha256.c b/dlls/bcrypt/sha256.c deleted file mode 100644 index 48c4a48d0317..000000000000 --- a/dlls/bcrypt/sha256.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2016 Michael Müller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - */ - -/* Based on public domain implementation from - https://git.musl-libc.org/cgit/musl/tree/src/crypt/crypt_sha256.c */ - -#include "bcrypt_internal.h" - -static DWORD ror(DWORD n, int k) { return (n >> k) | (n << (32-k)); } -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) ((x & y) | (z & (x | y))) -#define S0(x) (ror(x,2) ^ ror(x,13) ^ ror(x,22)) -#define S1(x) (ror(x,6) ^ ror(x,11) ^ ror(x,25)) -#define R0(x) (ror(x,7) ^ ror(x,18) ^ (x>>3)) -#define R1(x) (ror(x,17) ^ ror(x,19) ^ (x>>10)) - -static const DWORD K[64] = -{ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -static void processblock(SHA256_CTX *ctx, const UCHAR *buffer) -{ - DWORD W[64], t1, t2, a, b, c, d, e, f, g, h; - int i; - - for (i = 0; i < 16; i++) - { - W[i] = (DWORD)buffer[4*i]<<24; - W[i] |= (DWORD)buffer[4*i+1]<<16; - W[i] |= (DWORD)buffer[4*i+2]<<8; - W[i] |= buffer[4*i+3]; - } - - for (; i < 64; i++) - W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16]; - - a = ctx->h[0]; - b = ctx->h[1]; - c = ctx->h[2]; - d = ctx->h[3]; - e = ctx->h[4]; - f = ctx->h[5]; - g = ctx->h[6]; - h = ctx->h[7]; - - for (i = 0; i < 64; i++) - { - t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i]; - t2 = S0(a) + Maj(a,b,c); - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - - ctx->h[0] += a; - ctx->h[1] += b; - ctx->h[2] += c; - ctx->h[3] += d; - ctx->h[4] += e; - ctx->h[5] += f; - ctx->h[6] += g; - ctx->h[7] += h; -} - -static void pad(SHA256_CTX *ctx) -{ - ULONG64 r = ctx->len % 64; - - ctx->buf[r++] = 0x80; - - if (r > 56) - { - memset(ctx->buf + r, 0, 64 - r); - r = 0; - processblock(ctx, ctx->buf); - } - - memset(ctx->buf + r, 0, 56 - r); - ctx->len *= 8; - ctx->buf[56] = ctx->len >> 56; - ctx->buf[57] = ctx->len >> 48; - ctx->buf[58] = ctx->len >> 40; - ctx->buf[59] = ctx->len >> 32; - ctx->buf[60] = ctx->len >> 24; - ctx->buf[61] = ctx->len >> 16; - ctx->buf[62] = ctx->len >> 8; - ctx->buf[63] = ctx->len; - - processblock(ctx, ctx->buf); -} - -void sha256_init(SHA256_CTX *ctx) -{ - ctx->len = 0; - ctx->h[0] = 0x6a09e667; - ctx->h[1] = 0xbb67ae85; - ctx->h[2] = 0x3c6ef372; - ctx->h[3] = 0xa54ff53a; - ctx->h[4] = 0x510e527f; - ctx->h[5] = 0x9b05688c; - ctx->h[6] = 0x1f83d9ab; - ctx->h[7] = 0x5be0cd19; -} - -void sha256_update(SHA256_CTX *ctx, const UCHAR *buffer, ULONG len) -{ - const UCHAR *p = buffer; - ULONG64 r = ctx->len % 64; - - ctx->len += len; - if (r) - { - if (len < 64 - r) - { - memcpy(ctx->buf + r, p, len); - return; - } - memcpy(ctx->buf + r, p, 64 - r); - len -= 64 - r; - p += 64 - r; - processblock(ctx, ctx->buf); - } - for (; len >= 64; len -= 64, p += 64) - processblock(ctx, p); - memcpy(ctx->buf, p, len); -} - -void sha256_finalize(SHA256_CTX *ctx, UCHAR *buffer) -{ - int i; - - pad(ctx); - for (i = 0; i < 8; i++) - { - buffer[4*i] = ctx->h[i] >> 24; - buffer[4*i+1] = ctx->h[i] >> 16; - buffer[4*i+2] = ctx->h[i] >> 8; - buffer[4*i+3] = ctx->h[i]; - } -} diff --git a/dlls/bcrypt/sha512.c b/dlls/bcrypt/sha512.c deleted file mode 100644 index 145b61b659a9..000000000000 --- a/dlls/bcrypt/sha512.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2016 Michael Müller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - */ - -/* Based on public domain implementation from - https://git.musl-libc.org/cgit/musl/tree/src/crypt/crypt_sha512.c */ - -#include "bcrypt_internal.h" - -static ULONG64 ror(ULONG64 n, int k) { return (n >> k) | (n << (64-k)); } -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) ((x & y) | (z & (x | y))) -#define S0(x) (ror(x,28) ^ ror(x,34) ^ ror(x,39)) -#define S1(x) (ror(x,14) ^ ror(x,18) ^ ror(x,41)) -#define R0(x) (ror(x,1) ^ ror(x,8) ^ (x>>7)) -#define R1(x) (ror(x,19) ^ ror(x,61) ^ (x>>6)) -#define ULL(a,b) (((ULONG64)(a) << 32) | (b)) - -static const ULONG64 K[80] = -{ - ULL(0x428a2f98,0xd728ae22), ULL(0x71374491,0x23ef65cd), ULL(0xb5c0fbcf,0xec4d3b2f), ULL(0xe9b5dba5,0x8189dbbc), - ULL(0x3956c25b,0xf348b538), ULL(0x59f111f1,0xb605d019), ULL(0x923f82a4,0xaf194f9b), ULL(0xab1c5ed5,0xda6d8118), - ULL(0xd807aa98,0xa3030242), ULL(0x12835b01,0x45706fbe), ULL(0x243185be,0x4ee4b28c), ULL(0x550c7dc3,0xd5ffb4e2), - ULL(0x72be5d74,0xf27b896f), ULL(0x80deb1fe,0x3b1696b1), ULL(0x9bdc06a7,0x25c71235), ULL(0xc19bf174,0xcf692694), - ULL(0xe49b69c1,0x9ef14ad2), ULL(0xefbe4786,0x384f25e3), ULL(0x0fc19dc6,0x8b8cd5b5), ULL(0x240ca1cc,0x77ac9c65), - ULL(0x2de92c6f,0x592b0275), ULL(0x4a7484aa,0x6ea6e483), ULL(0x5cb0a9dc,0xbd41fbd4), ULL(0x76f988da,0x831153b5), - ULL(0x983e5152,0xee66dfab), ULL(0xa831c66d,0x2db43210), ULL(0xb00327c8,0x98fb213f), ULL(0xbf597fc7,0xbeef0ee4), - ULL(0xc6e00bf3,0x3da88fc2), ULL(0xd5a79147,0x930aa725), ULL(0x06ca6351,0xe003826f), ULL(0x14292967,0x0a0e6e70), - ULL(0x27b70a85,0x46d22ffc), ULL(0x2e1b2138,0x5c26c926), ULL(0x4d2c6dfc,0x5ac42aed), ULL(0x53380d13,0x9d95b3df), - ULL(0x650a7354,0x8baf63de), ULL(0x766a0abb,0x3c77b2a8), ULL(0x81c2c92e,0x47edaee6), ULL(0x92722c85,0x1482353b), - ULL(0xa2bfe8a1,0x4cf10364), ULL(0xa81a664b,0xbc423001), ULL(0xc24b8b70,0xd0f89791), ULL(0xc76c51a3,0x0654be30), - ULL(0xd192e819,0xd6ef5218), ULL(0xd6990624,0x5565a910), ULL(0xf40e3585,0x5771202a), ULL(0x106aa070,0x32bbd1b8), - ULL(0x19a4c116,0xb8d2d0c8), ULL(0x1e376c08,0x5141ab53), ULL(0x2748774c,0xdf8eeb99), ULL(0x34b0bcb5,0xe19b48a8), - ULL(0x391c0cb3,0xc5c95a63), ULL(0x4ed8aa4a,0xe3418acb), ULL(0x5b9cca4f,0x7763e373), ULL(0x682e6ff3,0xd6b2b8a3), - ULL(0x748f82ee,0x5defb2fc), ULL(0x78a5636f,0x43172f60), ULL(0x84c87814,0xa1f0ab72), ULL(0x8cc70208,0x1a6439ec), - ULL(0x90befffa,0x23631e28), ULL(0xa4506ceb,0xde82bde9), ULL(0xbef9a3f7,0xb2c67915), ULL(0xc67178f2,0xe372532b), - ULL(0xca273ece,0xea26619c), ULL(0xd186b8c7,0x21c0c207), ULL(0xeada7dd6,0xcde0eb1e), ULL(0xf57d4f7f,0xee6ed178), - ULL(0x06f067aa,0x72176fba), ULL(0x0a637dc5,0xa2c898a6), ULL(0x113f9804,0xbef90dae), ULL(0x1b710b35,0x131c471b), - ULL(0x28db77f5,0x23047d84), ULL(0x32caab7b,0x40c72493), ULL(0x3c9ebe0a,0x15c9bebc), ULL(0x431d67c4,0x9c100d4c), - ULL(0x4cc5d4be,0xcb3e42b6), ULL(0x597f299c,0xfc657e2a), ULL(0x5fcb6fab,0x3ad6faec), ULL(0x6c44198c,0x4a475817) -}; - -static void processblock(SHA512_CTX *ctx, const UCHAR *buffer) -{ - ULONG64 W[80], t1, t2, a, b, c, d, e, f, g, h; - int i; - - for (i = 0; i < 16; i++) - { - W[i] = (ULONG64)buffer[8*i]<<56; - W[i] |= (ULONG64)buffer[8*i+1]<<48; - W[i] |= (ULONG64)buffer[8*i+2]<<40; - W[i] |= (ULONG64)buffer[8*i+3]<<32; - W[i] |= (ULONG64)buffer[8*i+4]<<24; - W[i] |= (ULONG64)buffer[8*i+5]<<16; - W[i] |= (ULONG64)buffer[8*i+6]<<8; - W[i] |= buffer[8*i+7]; - } - - for (; i < 80; i++) - W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16]; - - a = ctx->h[0]; - b = ctx->h[1]; - c = ctx->h[2]; - d = ctx->h[3]; - e = ctx->h[4]; - f = ctx->h[5]; - g = ctx->h[6]; - h = ctx->h[7]; - - for (i = 0; i < 80; i++) - { - t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i]; - t2 = S0(a) + Maj(a,b,c); - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - - ctx->h[0] += a; - ctx->h[1] += b; - ctx->h[2] += c; - ctx->h[3] += d; - ctx->h[4] += e; - ctx->h[5] += f; - ctx->h[6] += g; - ctx->h[7] += h; -} - -static void pad(SHA512_CTX *ctx) -{ - ULONG64 r = ctx->len % 128; - - ctx->buf[r++] = 0x80; - if (r > 112) - { - memset(ctx->buf + r, 0, 128 - r); - r = 0; - processblock(ctx, ctx->buf); - } - - memset(ctx->buf + r, 0, 120 - r); - ctx->len *= 8; - ctx->buf[120] = ctx->len >> 56; - ctx->buf[121] = ctx->len >> 48; - ctx->buf[122] = ctx->len >> 40; - ctx->buf[123] = ctx->len >> 32; - ctx->buf[124] = ctx->len >> 24; - ctx->buf[125] = ctx->len >> 16; - ctx->buf[126] = ctx->len >> 8; - ctx->buf[127] = ctx->len; - - processblock(ctx, ctx->buf); -} - -void sha512_init(SHA512_CTX *ctx) -{ - ctx->len = 0; - ctx->h[0] = ULL(0x6a09e667,0xf3bcc908); - ctx->h[1] = ULL(0xbb67ae85,0x84caa73b); - ctx->h[2] = ULL(0x3c6ef372,0xfe94f82b); - ctx->h[3] = ULL(0xa54ff53a,0x5f1d36f1); - ctx->h[4] = ULL(0x510e527f,0xade682d1); - ctx->h[5] = ULL(0x9b05688c,0x2b3e6c1f); - ctx->h[6] = ULL(0x1f83d9ab,0xfb41bd6b); - ctx->h[7] = ULL(0x5be0cd19,0x137e2179); -} - -void sha512_update(SHA512_CTX *ctx, const UCHAR *buffer, ULONG len) -{ - const UCHAR *p = buffer; - unsigned r = ctx->len % 128; - - ctx->len += len; - if (r) - { - if (len < 128 - r) - { - memcpy(ctx->buf + r, p, len); - return; - } - memcpy(ctx->buf + r, p, 128 - r); - len -= 128 - r; - p += 128 - r; - processblock(ctx, ctx->buf); - } - - for (; len >= 128; len -= 128, p += 128) - processblock(ctx, p); - - memcpy(ctx->buf, p, len); -} - -void sha512_finalize(SHA512_CTX *ctx, UCHAR *buffer) -{ - int i; - - pad(ctx); - for (i = 0; i < 8; i++) - { - buffer[8*i] = ctx->h[i] >> 56; - buffer[8*i+1] = ctx->h[i] >> 48; - buffer[8*i+2] = ctx->h[i] >> 40; - buffer[8*i+3] = ctx->h[i] >> 32; - buffer[8*i+4] = ctx->h[i] >> 24; - buffer[8*i+5] = ctx->h[i] >> 16; - buffer[8*i+6] = ctx->h[i] >> 8; - buffer[8*i+7] = ctx->h[i]; - } -} - -void sha384_init(SHA512_CTX *ctx) -{ - ctx->len = 0; - ctx->h[0] = ULL(0xcbbb9d5d,0xc1059ed8); - ctx->h[1] = ULL(0x629a292a,0x367cd507); - ctx->h[2] = ULL(0x9159015a,0x3070dd17); - ctx->h[3] = ULL(0x152fecd8,0xf70e5939); - ctx->h[4] = ULL(0x67332667,0xffc00b31); - ctx->h[5] = ULL(0x8eb44a87,0x68581511); - ctx->h[6] = ULL(0xdb0c2e0d,0x64f98fa7); - ctx->h[7] = ULL(0x47b5481d,0xbefa4fa4); -} - -void sha384_finalize(SHA512_CTX *ctx, UCHAR *buffer) -{ - UCHAR buffer512[64]; - - sha512_finalize(ctx, buffer512); - memcpy(buffer, buffer512, 48); -} diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 772d4ecdc5d2..a990750b4624 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -29,6 +29,8 @@ #include "wine/test.h" static NTSTATUS (WINAPI *pBCryptHash)(BCRYPT_ALG_HANDLE, UCHAR *, ULONG, UCHAR *, ULONG, UCHAR *, ULONG); +static NTSTATUS (WINAPI *pBCryptKeyDerivation)(BCRYPT_KEY_HANDLE, + BCryptBufferDesc *, UCHAR *, ULONG, ULONG *, ULONG); static void test_BCryptGenRandom(void) { @@ -486,6 +488,7 @@ static UCHAR dk3[] = "4b007901b765489abead49d926f721d065a429c1"; static UCHAR dk4[] = "364dd6bc200ec7d197f1b85f4a61769010717124"; static UCHAR dk5[] = "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"; static UCHAR dk6[] = "56fa6aa75548099dcc37d7f03425e0c3"; +static UCHAR dk7[] = "8754c32c64b0f524fc50c00f788135de"; static const struct { @@ -503,7 +506,8 @@ static const struct { 8, 4, 4096, 20, password, salt, dk3 }, { 8, 4, 1000000, 20, password, salt, dk4 }, { 24, 36, 4096, 25, long_password, long_salt, dk5 }, - { 9, 5, 4096, 16, password_NUL, salt_NUL, dk6 } + { 9, 5, 4096, 16, password_NUL, salt_NUL, dk6 }, + { 8, 0, 1, 16, password, NULL, dk7 } }; static void test_BcryptDeriveKeyPBKDF2(void) @@ -2074,11 +2078,17 @@ static void test_BCryptDecrypt(void) static void test_key_import_export(void) { + static const UCHAR encrypted_blob[40] = {0x33,0x6e,0x51,0x10, + 0x25,0xba,0xdb,0xce,0xcb,0x25,0x00,0x85,0x51,0xc0,0xfa,0x21, + 0x66,0xdd,0x6d,0x67,0x46,0x76,0x0f,0x8a,0x44,0xe5,0x65,0x31, + 0xcb,0x02,0x52,0x9c,0x69,0x59,0x1a,0xec,0x67,0x27,0x11,0xaa}; UCHAR buffer1[sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + 16]; - UCHAR buffer2[sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + 16], *buf; + UCHAR buffer2[sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + 32], *buf; + UCHAR buffer3[32 + 8], buffer4[sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + 32]; BCRYPT_KEY_DATA_BLOB_HEADER *key_data1 = (void*)buffer1; + BCRYPT_KEY_DATA_BLOB_HEADER *key_data2 = (void*)buffer2; BCRYPT_ALG_HANDLE aes; - BCRYPT_KEY_HANDLE key; + BCRYPT_KEY_HANDLE key, key2, key3; NTSTATUS ret; ULONG size; @@ -2095,16 +2105,49 @@ static void test_key_import_export(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(key != NULL, "key not set\n"); + key_data2->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; + key_data2->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; + key_data2->cbKeyData = 32; + memset(&key_data2[1], 0x22, 32); + key2 = NULL; + ret = BCryptImportKey(aes, NULL, BCRYPT_KEY_DATA_BLOB, &key2, NULL, 0, buffer2, sizeof(buffer2), 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(key2 != NULL, "key not set\n"); + + size = 0; + ret = BCryptExportKey(key2, key, BCRYPT_AES_WRAP_KEY_BLOB, NULL, 0, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == sizeof(buffer3), "got %lu\n", size); + + ret = BCryptExportKey(key2, key, BCRYPT_AES_WRAP_KEY_BLOB, buffer3, size, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(!memcmp(buffer3, encrypted_blob, sizeof(encrypted_blob)), "blobs didn't match\n"); + + key3 = NULL; + ret = BCryptImportKey(aes, key, BCRYPT_AES_WRAP_KEY_BLOB, &key3, NULL, 0, buffer3, sizeof(buffer3), 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(key3 != NULL, "key not set\n"); + + size = 0; + memset(buffer4, 0xff, sizeof(buffer4)); + ret = BCryptExportKey(key3, NULL, BCRYPT_KEY_DATA_BLOB, buffer4, sizeof(buffer4), &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == sizeof(buffer2), "Got %lu\n", size); + ok(!memcmp(buffer4, buffer2, sizeof(buffer2)), "Expected exported key to match imported key\n"); + + BCryptDestroyKey(key3); + BCryptDestroyKey(key2); + size = 0; - ret = BCryptExportKey(key, NULL, BCRYPT_KEY_DATA_BLOB, buffer2, 0, &size, 0); + ret = BCryptExportKey(key, NULL, BCRYPT_KEY_DATA_BLOB, buffer1, 0, &size, 0); ok(ret == STATUS_BUFFER_TOO_SMALL, "got %#lx\n", ret); - ok(size == sizeof(buffer2), "got %lu\n", size); + ok(size == sizeof(buffer1), "got %lu\n", size); size = 0; memset(buffer2, 0xff, sizeof(buffer2)); ret = BCryptExportKey(key, NULL, BCRYPT_KEY_DATA_BLOB, buffer2, sizeof(buffer2), &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); - ok(size == sizeof(buffer2), "Got %lu\n", size); + ok(size == sizeof(buffer1), "Got %lu\n", size); ok(!memcmp(buffer1, buffer2, sizeof(buffer1)), "Expected exported key to match imported key\n"); /* opaque blob */ @@ -2152,6 +2195,27 @@ static BYTE eccPrivkey[] = 0xb9, 0xcd, 0xbe, 0xd4, 0x75, 0x5d, 0x05, 0xe5, 0x83, 0x0c, 0xd3, 0x37, 0x34, 0x15, 0xe3, 0x2c, 0xe5, 0x85, 0x15, 0xa9, 0xee, 0xba, 0x94, 0x03, 0x03, 0x0b, 0x86, 0xea, 0x85, 0x40, 0xbd, 0x35, }; +static BYTE ecc521Privkey[] = +{ + /* X */ + 0x00, 0x5f, 0xea, 0x1e, 0x01, 0xae, 0x69, 0xc3, 0x88, 0x1c, 0xbf, 0x7f, 0x86, 0x1a, 0x48, 0x20, + 0xd3, 0xba, 0xac, 0x9f, 0x1c, 0xc9, 0x99, 0xfa, 0x7d, 0x39, 0xf6, 0xe0, 0xd6, 0x92, 0x97, 0xee, + 0xf6, 0xca, 0x65, 0x40, 0x24, 0xa6, 0xf7, 0x97, 0x17, 0x8c, 0xe1, 0x81, 0x6c, 0x10, 0x92, 0xcd, + 0x41, 0xbc, 0x1c, 0xde, 0x37, 0x4a, 0x21, 0xb9, 0xbc, 0x46, 0x40, 0xa9, 0x91, 0xd9, 0x61, 0x84, + 0x15, 0x33, + /* Y */ + 0x00, 0x31, 0xde, 0xe9, 0x64, 0x9d, 0xb8, 0x43, 0x3a, 0x93, 0x5d, 0xc8, 0x82, 0xec, 0xe4, 0x7f, + 0x83, 0x8d, 0x2c, 0xc7, 0xe8, 0x24, 0x38, 0x5a, 0x81, 0x3d, 0xe6, 0x8d, 0xd4, 0xb1, 0xa0, 0x37, + 0x89, 0xae, 0x1f, 0x81, 0x23, 0x22, 0x8f, 0xd1, 0xe0, 0xc4, 0x6a, 0x99, 0xcc, 0xc8, 0xe4, 0xa0, + 0x65, 0x42, 0x9e, 0xbd, 0xaf, 0x07, 0x79, 0xe8, 0x88, 0xc2, 0xfe, 0xc0, 0x2d, 0x88, 0xd5, 0x3a, + 0xbd, 0xb1, + /* d */ + 0x00, 0x8b, 0xc5, 0xd5, 0x06, 0x3a, 0x1d, 0xd2, 0xf8, 0x26, 0x8e, 0xa2, 0xd3, 0x69, 0x5a, 0xf9, + 0xb6, 0x42, 0x8b, 0x1a, 0x9c, 0x34, 0x04, 0xa6, 0x1d, 0xfc, 0x67, 0xe5, 0x23, 0x71, 0x8e, 0xad, + 0x61, 0x45, 0x4f, 0x00, 0x3e, 0x8f, 0x61, 0xa3, 0xfb, 0xb6, 0x7a, 0x98, 0xf8, 0x27, 0x2c, 0x1b, + 0xa8, 0xda, 0xb7, 0x78, 0xe9, 0xf5, 0x9d, 0xff, 0x6a, 0x07, 0xb0, 0xe2, 0xae, 0x64, 0x15, 0x03, + 0xb3, 0x8a, +}; static BYTE eccPubkey[] = { /* X */ @@ -2175,10 +2239,22 @@ static BYTE certSignature[] = 0xe3, 0x94, 0x15, 0x3b, 0x6c, 0x71, 0x6e, 0x44, 0x22, 0xcb, 0xa0, 0x88, 0xcd, 0x0a, 0x5a, 0x50, 0x29, 0x7c, 0x5c, 0xd6, 0x6c, 0xd2, 0xe0, 0x7f, 0xcd, 0x02, 0x92, 0x21, 0x4c, 0x2c, 0x92, 0xee, }; +static BYTE cert521Signature[] = +{ + 0x01, 0x6b, 0xd6, 0xca, 0xac, 0x28, 0xa8, 0xa9, 0x83, 0x9d, 0xca, 0x13, 0x08, 0xd6, 0xf2, 0x9c, + 0x94, 0x6b, 0x28, 0x6b, 0x93, 0x58, 0x3c, 0x65, 0x54, 0xb4, 0xa6, 0xb8, 0x0d, 0x55, 0xed, 0x4e, + 0xc9, 0x98, 0x26, 0x96, 0x1a, 0xbb, 0x9f, 0x9e, 0x5c, 0xb1, 0x1e, 0x8b, 0x04, 0x82, 0xe6, 0x32, + 0x15, 0x92, 0xcb, 0xfe, 0xe7, 0x53, 0xfc, 0x17, 0xe0, 0xc9, 0x44, 0xf5, 0x1d, 0x37, 0x33, 0x02, + 0xbb, 0x75, 0x01, 0x65, 0x84, 0xab, 0x89, 0xb3, 0x69, 0x56, 0xf4, 0x18, 0xb0, 0xdd, 0xfd, 0x69, + 0xe6, 0x52, 0x1e, 0x75, 0x4f, 0x98, 0xa8, 0x49, 0x88, 0x84, 0x15, 0x58, 0x23, 0x9f, 0x89, 0x06, + 0x73, 0x6b, 0x8c, 0xf9, 0x9a, 0x85, 0x1d, 0xd2, 0xf4, 0x06, 0x65, 0xa5, 0x88, 0x12, 0xa3, 0x4e, + 0xcd, 0x99, 0x06, 0x1b, 0xf8, 0x17, 0xe0, 0xeb, 0xb8, 0x7f, 0x6b, 0x89, 0x47, 0xd2, 0x5d, 0x30, + 0xf4, 0xf6, 0x5f, 0x83, +}; static void test_ECDSA(void) { - BYTE buffer[sizeof(BCRYPT_ECCKEY_BLOB) + sizeof(eccPrivkey)]; + BYTE buffer[sizeof(BCRYPT_ECCKEY_BLOB) + sizeof(ecc521Privkey)]; BCRYPT_ECCKEY_BLOB *ecckey = (void *)buffer; BCRYPT_ALG_HANDLE alg; BCRYPT_KEY_HANDLE key; @@ -2278,6 +2354,67 @@ static void test_ECDSA(void) BCryptDestroyKey(key); BCryptCloseAlgorithmProvider(alg, 0); + + /* P521 */ + status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDSA_P521_ALGORITHM, NULL, 0); + ok(!status, "got %#lx\n", status); + + ecckey->dwMagic = BCRYPT_ECDSA_PUBLIC_P521_MAGIC; + ecckey->cbKey = 66; + size = sizeof(BCRYPT_ECCKEY_BLOB) + ecckey->cbKey * 2; + memcpy(ecckey + 1, ecc521Privkey, ecckey->cbKey * 2); + status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, &key, buffer, size, 0); + ok(!status, "BCryptImportKeyPair failed: %#lx\n", status); + + keylen = 0; + status = BCryptGetProperty(key, BCRYPT_KEY_STRENGTH, (UCHAR *)&keylen, sizeof(keylen), &size, 0); + ok(!status, "got %#lx\n", status); + ok(size == sizeof(keylen), "got %lu\n", size); + ok(keylen == 521, "got %lu\n", keylen); + + memset(buffer, 0xcc, sizeof(buffer)); + status = BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, buffer, sizeof(buffer), &size, 0); + ok(!status, "Got unexpected status %#lx\n", status); + ok(ecckey->dwMagic == BCRYPT_ECDSA_PUBLIC_P521_MAGIC, "Got unexpected magic %#lx.\n", ecckey->dwMagic); + ok(ecckey->cbKey == 66, "got %lu\n", ecckey->cbKey); + ok(!memcmp(ecckey + 1, ecc521Privkey, ecckey->cbKey * 2), "Got unexpected key data.\n"); + + memcpy(buffer, cert521Signature, sizeof(cert521Signature)); + status = BCryptVerifySignature(key, NULL, certHash, sizeof(certHash), buffer, sizeof(cert521Signature), 0); + ok(!status, "BCryptVerifySignature failed: %#lx\n", status); + + ++buffer[5]; + status = BCryptVerifySignature(key, NULL, certHash, sizeof(certHash), buffer, sizeof(cert521Signature), 0); + ok(status == STATUS_INVALID_SIGNATURE, "BCryptVerifySignature failed: %#lx\n", status); + + BCryptDestroyKey(key); + + ecckey->dwMagic = BCRYPT_ECDSA_PRIVATE_P521_MAGIC; + ecckey->cbKey = 66; + memcpy(ecckey + 1, ecc521Privkey, sizeof(ecc521Privkey)); + size = sizeof(*ecckey) + sizeof(ecc521Privkey); + status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPRIVATE_BLOB, &key, buffer, size, 0); + ok(!status, "BCryptImportKeyPair failed: %#lx\n", status); + + memset( buffer, 0xcc, sizeof(buffer) ); + status = BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, buffer, sizeof(buffer), &size, 0); + ok(!status, "Got unexpected status %#lx\n", status); + ok(ecckey->dwMagic == BCRYPT_ECDSA_PUBLIC_P521_MAGIC, "got %#lx\n", ecckey->dwMagic); + ok(ecckey->cbKey == 66, "got %lu\n", ecckey->cbKey); + ok(!memcmp(ecckey + 1, ecc521Privkey, ecckey->cbKey * 2), "Got unexpected key data.\n"); + + size = sizeof(BCRYPT_ECCKEY_BLOB) + sizeof(ecc521Privkey); + memset( buffer, 0xcc, sizeof(buffer) ); + status = BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, buffer, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ecckey = (BCRYPT_ECCKEY_BLOB *)buffer; + ok(ecckey->dwMagic == BCRYPT_ECDSA_PRIVATE_P521_MAGIC, "got %#lx\n", ecckey->dwMagic); + ok(ecckey->cbKey == 66, "got %lu\n", ecckey->cbKey); + ok(size == sizeof(*ecckey) + ecckey->cbKey * 3, "got %lu\n", size); + ok(!memcmp(ecckey + 1, ecc521Privkey, ecckey->cbKey * 3), "Got unexpected key data.\n"); + + BCryptDestroyKey(key); + BCryptCloseAlgorithmProvider(alg, 0); } static UCHAR rsaPublicBlob[] = @@ -2475,20 +2612,25 @@ static void test_rsa_encrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); /* No padding */ - todo_wine { memset(input_no_padding, 0, sizeof(input_no_padding)); + + encrypted_size = 0; + ret = BCryptEncrypt(key, input_no_padding, sizeof(input_no_padding), NULL, NULL, 0, NULL, 0, &encrypted_size, BCRYPT_PAD_NONE); + ok(ret == STATUS_SUCCESS, "got %lx\n", ret); + ok(encrypted_size == 64, "got size of %ld\n", encrypted_size); + strcpy((char *)input_no_padding, "Hello World"); encrypted_size = 0; ret = BCryptEncrypt(key, input_no_padding, sizeof(input_no_padding), NULL, NULL, 0, NULL, 0, &encrypted_size, BCRYPT_PAD_NONE); ok(ret == STATUS_SUCCESS, "got %lx\n", ret); ok(encrypted_size == 64, "got size of %ld\n", encrypted_size); - encrypted_a = malloc(encrypted_size); + encrypted_a = malloc(encrypted_size * 2); memset(encrypted_a, 0, encrypted_size); - encrypted_b = malloc(encrypted_size); + encrypted_b = malloc(encrypted_size * 2); memset(encrypted_b, 0xff, encrypted_size); - ret = BCryptEncrypt(key, input, sizeof(input), NULL, NULL, 0, encrypted_a, encrypted_size, &encrypted_size, BCRYPT_PAD_NONE); + ret = BCryptEncrypt(key, input, sizeof(input), NULL, NULL, 0, encrypted_a, encrypted_size * 2, &encrypted_size, BCRYPT_PAD_NONE); ok(ret == STATUS_INVALID_PARAMETER, "got %lx\n", ret); ret = BCryptEncrypt(key, input_no_padding, sizeof(input_no_padding), NULL, NULL, 0, encrypted_a, 12, &encrypted_size, BCRYPT_PAD_NONE); @@ -2501,21 +2643,20 @@ static void test_rsa_encrypt(void) ret = BCryptEncrypt(key, input_no_padding, sizeof(input_no_padding), NULL, NULL, 0, encrypted_b, encrypted_size, &encrypted_size, BCRYPT_PAD_NONE); ok(ret == STATUS_SUCCESS, "got %lx\n", ret); - } ok(!memcmp(encrypted_a, encrypted_b, encrypted_size), "Both outputs should be the same\n"); ok(!memcmp(encrypted_b, rsa_encrypted_no_padding, encrypted_size), "Data mismatch.\n"); - todo_wine { decrypted_size = 0; ret = BCryptDecrypt(key, encrypted_a, encrypted_size, NULL, NULL, 0, NULL, 0, &decrypted_size, BCRYPT_PAD_NONE); ok(ret == STATUS_SUCCESS, "got %lx\n", ret); ok(decrypted_size == sizeof(input_no_padding), "got %lu\n", decrypted_size); + BCryptDecrypt(key, encrypted_a, encrypted_size, NULL, NULL, 0, decrypted, decrypted_size * 2, &decrypted_size, BCRYPT_PAD_NONE); + ok(!memcmp(decrypted, input_no_padding, sizeof(input_no_padding)), "Decrypted output it's not what expected\n"); ret = BCryptDecrypt(key, encrypted_a, encrypted_size, NULL, NULL, 0, decrypted, decrypted_size, &decrypted_size, BCRYPT_PAD_NONE); ok(ret == STATUS_SUCCESS, "got %lx\n", ret); ok(decrypted_size == sizeof(input_no_padding), "got %lu\n", decrypted_size); ok(!memcmp(decrypted, input_no_padding, sizeof(input_no_padding)), "unexpected output\n"); - } /* PKCS1 Padding */ encrypted_size = 0; @@ -2572,37 +2713,55 @@ static void test_rsa_encrypt(void) ret = BCryptFinalizeKeyPair(key, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); - todo_wine { encrypted_size = 0; ret = BCryptEncrypt(key, input, sizeof(input), &oaep_pad, NULL, 0, NULL, 0, &encrypted_size, BCRYPT_PAD_OAEP); ok(ret == STATUS_SUCCESS, "got %lx\n", ret); ok(encrypted_size == 80, "got size of %ld\n", encrypted_size); - encrypted_a = realloc(encrypted_a, encrypted_size); - memset(encrypted_a, 0, encrypted_size); - encrypted_b = realloc(encrypted_b, encrypted_size); + encrypted_size = 0; + ret = BCryptEncrypt(key, input, sizeof(input), NULL, NULL, 0, NULL, 0, &encrypted_size, BCRYPT_PAD_OAEP); + ok(ret == STATUS_SUCCESS, "got %lx\n", ret); + ok(encrypted_size == 80, "got size of %ld\n", encrypted_size); + + encrypted_a = realloc(encrypted_a, encrypted_size * 2); + memset(encrypted_a, 0, encrypted_size * 2); + encrypted_b = realloc(encrypted_b, encrypted_size * 2); memset(encrypted_b, 0, encrypted_size); - ret = BCryptEncrypt(key, input, sizeof(input), &oaep_pad, NULL, 0, encrypted_a, encrypted_size, &encrypted_size, BCRYPT_PAD_OAEP); + ret = BCryptEncrypt(key, input, sizeof(input), NULL, NULL, 0, NULL, encrypted_size, &encrypted_size, BCRYPT_PAD_OAEP); ok(ret == STATUS_SUCCESS, "got %lx\n", ret); ok(encrypted_size == 80, "got size of %ld\n", encrypted_size); + encrypted_size = 0; + ret = BCryptEncrypt(key, input, sizeof(input), NULL, NULL, 0, encrypted_a, 0, &encrypted_size, BCRYPT_PAD_OAEP); + ok(ret == STATUS_BUFFER_TOO_SMALL, "got %lx\n", ret); + ok(encrypted_size == 80, "got size of %ld\n", encrypted_size); + + ret = BCryptEncrypt(key, input, sizeof(input), &oaep_pad, NULL, 0, encrypted_a, encrypted_size, &encrypted_size, BCRYPT_PAD_OAEP); + todo_wine ok(ret == STATUS_SUCCESS, "got %lx\n", ret); + ok(encrypted_size == 80, "got size of %ld\n", encrypted_size); + ret = BCryptEncrypt(key, input, sizeof(input), &oaep_pad, NULL, 0, encrypted_b, encrypted_size, &encrypted_size, BCRYPT_PAD_OAEP); - ok(ret == STATUS_SUCCESS, "got %lx\n", ret); + todo_wine ok(ret == STATUS_SUCCESS, "got %lx\n", ret); ok(encrypted_size == 80, "got size of %ld\n", encrypted_size); - ok(memcmp(encrypted_a, encrypted_b, encrypted_size), "Both outputs are the same\n"); + todo_wine ok(memcmp(encrypted_a, encrypted_b, encrypted_size), "Both outputs are the same\n"); + + decrypted_size = 0; + memset(decrypted, 0, sizeof(decrypted)); + ret = BCryptDecrypt(key, encrypted_a, encrypted_size, NULL, NULL, 0, NULL, 0, &decrypted_size, BCRYPT_PAD_OAEP); + ok(ret == STATUS_INVALID_PARAMETER, "got %lx\n", ret); + todo_wine { decrypted_size = 0; memset(decrypted, 0, sizeof(decrypted)); ret = BCryptDecrypt(key, encrypted_a, encrypted_size, &oaep_pad, NULL, 0, NULL, 0, &decrypted_size, BCRYPT_PAD_OAEP); ok(ret == STATUS_SUCCESS, "got %lx\n", ret); ok(decrypted_size == sizeof(input), "got %lu\n", decrypted_size); - ret = BCryptDecrypt(key, encrypted_a, encrypted_size, &oaep_pad, NULL, 0, decrypted, decrypted_size, &decrypted_size, BCRYPT_PAD_OAEP); + ret = BCryptDecrypt(key, encrypted_a, encrypted_size, &oaep_pad, NULL, 0, decrypted, decrypted_size * 2, &decrypted_size, BCRYPT_PAD_OAEP); ok(ret == STATUS_SUCCESS, "got %lx\n", ret); ok(decrypted_size == sizeof(input), "got %lu\n", decrypted_size); ok(!memcmp(decrypted, input, sizeof(input)), "unexpected output\n"); - } free(encrypted_a); free(encrypted_b); @@ -2966,57 +3125,38 @@ static void test_RSA_SIGN(void) ok(!ret, "BCryptCloseAlgorithmProvider failed: %#lx\n", ret); } -static BYTE eccprivkey[] = -{ - 0x45, 0x43, 0x4b, 0x32, 0x20, 0x00, 0x00, 0x00, - 0xfb, 0xbd, 0x3d, 0x20, 0x1b, 0x6d, 0x66, 0xb3, 0x7c, 0x9f, 0x89, 0xf3, 0xe4, 0x41, 0x16, 0xa5, - 0x68, 0x52, 0x77, 0xac, 0xab, 0x55, 0xb2, 0x6c, 0xb0, 0x23, 0x55, 0xcb, 0x96, 0x14, 0xfd, 0x0b, - 0x1c, 0xef, 0xdf, 0x07, 0x6d, 0x31, 0xaf, 0x39, 0xce, 0x8c, 0x8f, 0x9d, 0x75, 0xd0, 0x7b, 0xea, - 0x81, 0xdc, 0x40, 0x21, 0x1f, 0x58, 0x22, 0x5f, 0x72, 0x55, 0xfc, 0x58, 0x8a, 0xeb, 0x88, 0x5d, - 0x02, 0x09, 0x90, 0xd2, 0xe3, 0x36, 0xac, 0xfe, 0x83, 0x13, 0x6c, 0x88, 0x1a, 0xab, 0x9b, 0xdd, - 0xaa, 0x8a, 0xee, 0x69, 0x9a, 0x6a, 0x62, 0x86, 0x6a, 0x13, 0x69, 0x88, 0xb7, 0xd5, 0xa3, 0xcd -}; - -static BYTE ecdh_pubkey[] = -{ - 0x45, 0x43, 0x4b, 0x31, 0x20, 0x00, 0x00, 0x00, - 0x07, 0x61, 0x9d, 0x49, 0x63, 0x6b, 0x96, 0x94, 0xd1, 0x8f, 0xd1, 0x48, 0xcc, 0xcf, 0x72, 0x4d, - 0xff, 0x43, 0xf4, 0x97, 0x0f, 0xa3, 0x8a, 0x72, 0xe9, 0xe0, 0xba, 0x87, 0x6d, 0xc3, 0x62, 0x15, - 0xae, 0x65, 0xdd, 0x31, 0x51, 0xfc, 0x3b, 0xc9, 0x59, 0xa1, 0x0a, 0x92, 0x17, 0x2b, 0x64, 0x55, - 0x03, 0x3e, 0x62, 0x1d, 0xac, 0x3e, 0x37, 0x40, 0x6a, 0x4c, 0xb6, 0x21, 0x3f, 0x73, 0x5c, 0xf5 -}; - -/* little endian */ -static BYTE ecdh_secret[] = -{ - 0x48, 0xb0, 0x11, 0xdb, 0x69, 0x4e, 0xb4, 0xf4, 0xf5, 0x3e, 0xe1, 0x9b, 0xca, 0x00, 0x04, 0xc8, - 0x9b, 0x69, 0xaf, 0xd1, 0xaf, 0x1f, 0xc2, 0xd7, 0x83, 0x0a, 0xb7, 0xf8, 0x4f, 0x24, 0x32, 0x8e, -}; - -BCryptBuffer hash_param_buffers[] = -{ -{ - sizeof(BCRYPT_SHA1_ALGORITHM), - KDF_HASH_ALGORITHM, - (void *)BCRYPT_SHA1_ALGORITHM, -} -}; - -BCryptBufferDesc hash_params = +struct ecdh_test { - BCRYPTBUFFER_VERSION, - ARRAY_SIZE(hash_param_buffers), - hash_param_buffers, + const WCHAR *alg; + ULONG bitlen; + BYTE *eccprivkey; + ULONG eccprivkey_len; + BYTE *ecdh_pubkey; + ULONG ecdh_pubkey_len; + BYTE *ecdh_secret; + ULONG ecdh_secret_len; + BYTE *hashed_secret; + DWORD public_magic; + DWORD private_magic; }; -static BYTE hashed_secret[] = +static void test_ECDH_alg(const struct ecdh_test *t) { - 0x1b, 0xe7, 0xbf, 0x0f, 0x65, 0x1e, 0xd0, 0x07, 0xf9, 0xf4, 0x77, 0x48, 0x48, 0x39, 0xd0, 0xf8, - 0xf3, 0xce, 0xfc, 0x89 -}; + BCryptBuffer hash_param_buffers[] = + { + { + sizeof(BCRYPT_SHA1_ALGORITHM), + KDF_HASH_ALGORITHM, + (void *)BCRYPT_SHA1_ALGORITHM, + } + }; -static void test_ECDH(void) -{ + BCryptBufferDesc hash_params = + { + BCRYPTBUFFER_VERSION, + ARRAY_SIZE(hash_param_buffers), + hash_param_buffers, + }; BYTE *buf; BCRYPT_ECCKEY_BLOB *ecckey; BCRYPT_ALG_HANDLE alg; @@ -3025,11 +3165,11 @@ static void test_ECDH(void) NTSTATUS status; ULONG size; - status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDH_P256_ALGORITHM, NULL, 0); + status = BCryptOpenAlgorithmProvider(&alg, t->alg, NULL, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); key = NULL; - status = BCryptGenerateKeyPair(alg, &key, 256, 0); + status = BCryptGenerateKeyPair(alg, &key, t->bitlen, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); ok(key != NULL, "key not set\n"); @@ -3045,8 +3185,8 @@ static void test_ECDH(void) status = BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, buf, size, &size, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); ecckey = (BCRYPT_ECCKEY_BLOB *)buf; - ok(ecckey->dwMagic == BCRYPT_ECDH_PUBLIC_P256_MAGIC, "got %#lx\n", ecckey->dwMagic); - ok(ecckey->cbKey == 32, "got %lu\n", ecckey->cbKey); + ok(ecckey->dwMagic == t->public_magic, "got %#lx\n", ecckey->dwMagic); + ok(ecckey->cbKey == (t->bitlen + 7) / 8, "got %lu\n", ecckey->cbKey); ok(size == sizeof(*ecckey) + ecckey->cbKey * 2, "got %lu\n", size); status = BCryptImportKeyPair(alg, NULL, BCRYPT_PUBLIC_KEY_BLOB, &pubkey, buf, size, 0); @@ -3066,8 +3206,8 @@ static void test_ECDH(void) status = BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, buf, size, &size, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); ecckey = (BCRYPT_ECCKEY_BLOB *)buf; - ok(ecckey->dwMagic == BCRYPT_ECDH_PRIVATE_P256_MAGIC, "got %#lx\n", ecckey->dwMagic); - ok(ecckey->cbKey == 32, "got %lu\n", ecckey->cbKey); + ok(ecckey->dwMagic == t->private_magic, "got %#lx\n", ecckey->dwMagic); + ok(ecckey->cbKey == (t->bitlen + 7) / 8, "got %lu\n", ecckey->cbKey); ok(size == sizeof(*ecckey) + ecckey->cbKey * 3, "got %lu\n", size); status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPRIVATE_BLOB, &privkey, buf, size, 0); @@ -3077,7 +3217,7 @@ static void test_ECDH(void) BCryptDestroyKey(privkey); BCryptDestroyKey(key); - status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPRIVATE_BLOB, &privkey, eccprivkey, sizeof(eccprivkey), 0); + status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPRIVATE_BLOB, &privkey, t->eccprivkey, t->eccprivkey_len, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); size = 0; @@ -3088,11 +3228,11 @@ static void test_ECDH(void) buf = malloc(size); status = BCryptExportKey(privkey, NULL, BCRYPT_ECCPRIVATE_BLOB, buf, size, &size, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); - ok(size == sizeof(eccprivkey), "got %lu\n", size); - ok(!memcmp(buf, eccprivkey, size), "wrong data\n"); + ok(size == t->eccprivkey_len, "got %lu\n", size); + ok(!memcmp(buf, t->eccprivkey, size), "wrong data\n"); free(buf); - status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, &pubkey, ecdh_pubkey, sizeof(ecdh_pubkey), 0); + status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, &pubkey, t->ecdh_pubkey, t->ecdh_pubkey_len, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); status = BCryptSecretAgreement(privkey, pubkey, &secret, 0); @@ -3105,26 +3245,29 @@ static void test_ECDH(void) win_skip("BCRYPT_KDF_RAW_SECRET not supported\n"); goto raw_secret_end; } - todo_wine ok(status == STATUS_SUCCESS, "got %#lx\n", status); - if (status != STATUS_SUCCESS) goto raw_secret_end; + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + + ok(size == (t->bitlen + 7) / 8, "size of secret key incorrect, got %lu, expected 32\n", size); + if (!size) + goto raw_secret_end; + - ok(size == 32, "size of secret key incorrect, got %lu, expected 32\n", size); buf = malloc(size); status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buf, size, &size, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); - ok(!(memcmp(ecdh_secret, buf, size)), "wrong data\n"); + ok(!(memcmp(t->ecdh_secret, buf, size)), "wrong data\n"); free(buf); raw_secret_end: status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &hash_params, NULL, 0, &size, 0); - todo_wine ok (status == STATUS_SUCCESS, "got %#lx\n", status); + ok (status == STATUS_SUCCESS, "got %#lx\n", status); if (status != STATUS_SUCCESS) goto derive_end; ok (size == 20, "got %lu\n", size); buf = malloc(size); status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &hash_params, buf, size, &size, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); - ok(!(memcmp(hashed_secret, buf, size)), "wrong data\n"); + ok(!(memcmp(t->hashed_secret, buf, size)), "wrong data\n"); free(buf); /* ulVersion is not verified */ @@ -3149,40 +3292,144 @@ static void test_ECDH(void) BCryptDestroyKey(pubkey); BCryptDestroyKey(privkey); BCryptCloseAlgorithmProvider(alg, 0); +} - status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDH_P384_ALGORITHM, NULL, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); - - key = NULL; - status = BCryptGenerateKeyPair(alg, &key, 384, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); - ok(key != NULL, "key not set\n"); - - status = BCryptFinalizeKeyPair(key, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); +static void test_ECDH(void) +{ + static BYTE ecc256privkey[] = + { + 0x45, 0x43, 0x4b, 0x32, 0x20, 0x00, 0x00, 0x00, + 0xfb, 0xbd, 0x3d, 0x20, 0x1b, 0x6d, 0x66, 0xb3, 0x7c, 0x9f, 0x89, 0xf3, 0xe4, 0x41, 0x16, 0xa5, + 0x68, 0x52, 0x77, 0xac, 0xab, 0x55, 0xb2, 0x6c, 0xb0, 0x23, 0x55, 0xcb, 0x96, 0x14, 0xfd, 0x0b, + 0x1c, 0xef, 0xdf, 0x07, 0x6d, 0x31, 0xaf, 0x39, 0xce, 0x8c, 0x8f, 0x9d, 0x75, 0xd0, 0x7b, 0xea, + 0x81, 0xdc, 0x40, 0x21, 0x1f, 0x58, 0x22, 0x5f, 0x72, 0x55, 0xfc, 0x58, 0x8a, 0xeb, 0x88, 0x5d, + 0x02, 0x09, 0x90, 0xd2, 0xe3, 0x36, 0xac, 0xfe, 0x83, 0x13, 0x6c, 0x88, 0x1a, 0xab, 0x9b, 0xdd, + 0xaa, 0x8a, 0xee, 0x69, 0x9a, 0x6a, 0x62, 0x86, 0x6a, 0x13, 0x69, 0x88, 0xb7, 0xd5, 0xa3, 0xcd + }; + static BYTE ecdh256_pubkey[] = + { + 0x45, 0x43, 0x4b, 0x31, 0x20, 0x00, 0x00, 0x00, + 0x07, 0x61, 0x9d, 0x49, 0x63, 0x6b, 0x96, 0x94, 0xd1, 0x8f, 0xd1, 0x48, 0xcc, 0xcf, 0x72, 0x4d, + 0xff, 0x43, 0xf4, 0x97, 0x0f, 0xa3, 0x8a, 0x72, 0xe9, 0xe0, 0xba, 0x87, 0x6d, 0xc3, 0x62, 0x15, + 0xae, 0x65, 0xdd, 0x31, 0x51, 0xfc, 0x3b, 0xc9, 0x59, 0xa1, 0x0a, 0x92, 0x17, 0x2b, 0x64, 0x55, + 0x03, 0x3e, 0x62, 0x1d, 0xac, 0x3e, 0x37, 0x40, 0x6a, 0x4c, 0xb6, 0x21, 0x3f, 0x73, 0x5c, 0xf5 + }; + static BYTE ecdh256_secret[] = + { + 0x48, 0xb0, 0x11, 0xdb, 0x69, 0x4e, 0xb4, 0xf4, 0xf5, 0x3e, 0xe1, 0x9b, 0xca, 0x00, 0x04, 0xc8, + 0x9b, 0x69, 0xaf, 0xd1, 0xaf, 0x1f, 0xc2, 0xd7, 0x83, 0x0a, 0xb7, 0xf8, 0x4f, 0x24, 0x32, 0x8e, + }; + static BYTE hashed256_secret[] = + { + 0x1b, 0xe7, 0xbf, 0x0f, 0x65, 0x1e, 0xd0, 0x07, 0xf9, 0xf4, 0x77, 0x48, 0x48, 0x39, 0xd0, 0xf8, + 0xf3, 0xce, 0xfc, 0x89 + }; - size = 0; - status = BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, 0, &size, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); - ok(size, "size not set\n"); + static BYTE ecc384privkey[] = + { + 0x45, 0x43, 0x4b, 0x34, 0x30, 0x00, 0x00, 0x00, + 0xc9, 0xcb, 0x38, 0x54, 0xa1, 0xe2, 0xb6, 0x60, 0x13, 0xd9, 0x45, 0x0d, 0x76, 0x90, 0xf9, 0x49, + 0x75, 0x81, 0x76, 0xac, 0x43, 0x96, 0xc1, 0x04, 0x04, 0xda, 0x76, 0x72, 0xb1, 0x19, 0x38, 0xbd, + 0xaf, 0x96, 0x0c, 0x4e, 0xc3, 0x29, 0x67, 0x91, 0x6c, 0xac, 0xcc, 0x33, 0x51, 0x1f, 0x82, 0xd5, + 0x17, 0xbf, 0xa2, 0x94, 0xd7, 0x15, 0x4f, 0x83, 0xe7, 0xa3, 0xb8, 0x6d, 0xd0, 0x7f, 0xbc, 0x8a, + 0x30, 0x09, 0x9e, 0x13, 0xaa, 0x2e, 0xf6, 0xde, 0x1c, 0x02, 0x4a, 0x65, 0xf6, 0x72, 0xb3, 0xf0, + 0x4f, 0x7f, 0x1a, 0xce, 0x4e, 0x94, 0xc5, 0x98, 0x89, 0x74, 0xad, 0x51, 0x8f, 0x2b, 0x25, 0x17, + 0xdc, 0x4a, 0x54, 0x8a, 0x42, 0xda, 0x30, 0x1a, 0xe3, 0x6d, 0x77, 0x4d, 0x3b, 0x33, 0x9a, 0xe3, + 0x37, 0xd4, 0x06, 0x5b, 0xb3, 0x3f, 0x73, 0xb9, 0x7e, 0x0b, 0x37, 0x02, 0x8b, 0xed, 0x08, 0x10, + 0x03, 0xf8, 0x69, 0xe3, 0x2a, 0x4f, 0xbb, 0x20, 0x6c, 0x5d, 0x24, 0x09, 0x0d, 0xd9, 0x86, 0x32, + }; + static BYTE ecdh384_pubkey[] = + { + 0x45, 0x43, 0x4b, 0x33, 0x30, 0x00, 0x00, 0x00, + 0xd6, 0xc3, 0xef, 0x4a, 0xbb, 0x4c, 0xa2, 0x27, 0xa1, 0x96, 0x03, 0x3b, 0x0a, 0x83, 0x01, 0xff, + 0xeb, 0x9a, 0xf1, 0x06, 0xee, 0x83, 0xce, 0x7c, 0xaa, 0x6b, 0x7c, 0x43, 0x1c, 0x8b, 0x30, 0x82, + 0x99, 0x8f, 0xc4, 0x86, 0x0d, 0x19, 0x16, 0xb6, 0xab, 0xd1, 0x9f, 0xeb, 0xf9, 0x31, 0xda, 0xcd, + 0xb9, 0xf8, 0xea, 0x87, 0xa1, 0x36, 0xaf, 0x10, 0x98, 0x8f, 0x9b, 0xcc, 0x6c, 0xe3, 0x24, 0xb4, + 0x82, 0x37, 0xde, 0x1e, 0x04, 0x53, 0x03, 0xc0, 0x2a, 0x41, 0xe9, 0x50, 0x07, 0x87, 0xb2, 0x60, + 0xe6, 0x32, 0x53, 0x4c, 0x8e, 0xa7, 0x80, 0x0f, 0xad, 0x25, 0x3b, 0x01, 0xa4, 0xd6, 0xe3, 0x54, + }; + static BYTE ecdh384_secret[] = + { + 0x08, 0x8c, 0xd1, 0xfa, 0x57, 0xb6, 0xf9, 0x79, 0x9e, 0x0c, 0x71, 0xc3, 0xcb, 0xa5, 0xb1, 0xfd, + 0xde, 0xbc, 0x6d, 0x7c, 0x8a, 0x5b, 0x26, 0xe8, 0x18, 0x80, 0x61, 0x45, 0x6a, 0x38, 0xf9, 0x13, + 0x2a, 0x8f, 0x4b, 0xfe, 0x75, 0x02, 0x62, 0xe9, 0xb3, 0x6e, 0xc5, 0x52, 0xc9, 0x82, 0x38, 0x53, + }; + static BYTE hashed384_secret[] = + { + 0x78, 0xf8, 0x07, 0xab, 0x00, 0x35, 0xaa, 0x8c, 0x22, 0xd0, 0xe7, 0x06, 0xfc, 0x0b, 0x74, 0x41, + 0xed, 0xdc, 0x16, 0x6c, + }; - buf = malloc(size); - status = BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, buf, size, &size, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); - ecckey = (BCRYPT_ECCKEY_BLOB *)buf; - ok(ecckey->dwMagic == BCRYPT_ECDH_PUBLIC_P384_MAGIC, "got %#lx\n", ecckey->dwMagic); - ok(ecckey->cbKey == 48, "got %lu\n", ecckey->cbKey); - ok(size == sizeof(*ecckey) + ecckey->cbKey * 2, "got %lu\n", size); + static BYTE ecc521privkey[] = + { + 0x45, 0x43, 0x4b, 0x36, 0x42, 0x00, 0x00, 0x00, + 0x01, 0x96, 0xb0, 0x4e, 0x35, 0x6f, 0xbe, 0x00, 0xb6, 0xc3, 0x83, 0x53, 0x92, 0x18, 0xda, 0x86, + 0x9e, 0x4b, 0x0f, 0xb2, 0x0b, 0xc3, 0x9f, 0xd8, 0x9c, 0x18, 0x8a, 0x93, 0x5c, 0x91, 0xb2, 0x4f, + 0x56, 0x7d, 0x0e, 0xf7, 0xf4, 0xdf, 0x91, 0xc6, 0x74, 0x00, 0xc7, 0xb8, 0x59, 0xeb, 0x55, 0xc0, + 0xb5, 0x26, 0x7f, 0x6d, 0x49, 0x53, 0x02, 0x3b, 0x3c, 0xa0, 0x57, 0x1e, 0x1c, 0x7c, 0x5b, 0x08, + 0x23, 0x68, 0x01, 0x47, 0x4d, 0x47, 0xcf, 0x05, 0xfe, 0x18, 0x26, 0x81, 0x9d, 0xb4, 0x34, 0xfa, + 0x50, 0x7e, 0x03, 0x29, 0xa3, 0x6e, 0x90, 0x9c, 0x27, 0x69, 0x66, 0x2c, 0x70, 0x7b, 0xf9, 0xe7, + 0xef, 0xac, 0x27, 0xbf, 0x15, 0x86, 0xf6, 0xff, 0x2d, 0x99, 0x41, 0x9e, 0x36, 0x1f, 0xe9, 0x3a, + 0x99, 0x74, 0x54, 0xf3, 0xc3, 0x08, 0xb1, 0x00, 0x28, 0x84, 0x82, 0x84, 0xe3, 0xf4, 0x32, 0xfd, + 0x48, 0x67, 0xae, 0x08, 0x01, 0xe2, 0x08, 0x1d, 0xeb, 0x27, 0xc2, 0x98, 0x45, 0x8b, 0x33, 0x20, + 0x3b, 0x21, 0x5c, 0x7f, 0x56, 0xbd, 0xa5, 0x99, 0x58, 0xea, 0x19, 0xf8, 0xbc, 0xf1, 0x9e, 0x39, + 0x00, 0xb9, 0x2c, 0x2a, 0xb6, 0x19, 0x3a, 0xaf, 0xea, 0x4b, 0xa6, 0x22, 0xb4, 0x35, 0x09, 0x86, + 0x2e, 0x67, 0xe0, 0xfe, 0x81, 0x0e, 0x6a, 0x68, 0x6a, 0xb3, 0x32, 0x3b, 0xf8, 0x89, 0x45, 0x72, + 0x69, 0xf1, 0xe1, 0x84, 0xd7, 0xed, + }; + static BYTE ecdh521_pubkey[] = + { + 0x45, 0x43, 0x4b, 0x35, 0x42, 0x00, 0x00, 0x00, + 0x00, 0xfd, 0x72, 0xca, 0x31, 0x08, 0x76, 0xd9, 0x08, 0xb7, 0x26, 0x4a, 0x04, 0xbc, 0x73, 0x1a, + 0x04, 0xbb, 0x77, 0xf4, 0xe2, 0xfc, 0x3a, 0x88, 0x0a, 0xa8, 0x72, 0x8f, 0xfc, 0xe9, 0xe3, 0x5f, + 0x73, 0x05, 0xf1, 0x7f, 0x31, 0xee, 0x15, 0x91, 0x36, 0xe9, 0xeb, 0xed, 0xbe, 0x0e, 0x78, 0xa1, + 0x28, 0x4e, 0xc5, 0xcb, 0xba, 0xd8, 0x0c, 0x96, 0x75, 0x44, 0x71, 0x71, 0x00, 0x41, 0x43, 0xdf, + 0x27, 0x91, 0x00, 0x81, 0xcc, 0x56, 0x8d, 0x8e, 0x32, 0xae, 0x78, 0xfb, 0x3e, 0x84, 0x7b, 0x3b, + 0xf8, 0x8e, 0x7b, 0x27, 0x73, 0xa4, 0x11, 0x61, 0x24, 0x40, 0x9b, 0xbe, 0xd3, 0xc3, 0x0e, 0xbb, + 0x26, 0xae, 0x55, 0x58, 0xd1, 0xec, 0x14, 0xd3, 0x13, 0xf2, 0x6b, 0x2b, 0xc3, 0xf9, 0xa4, 0x50, + 0x9e, 0xce, 0xfe, 0x18, 0xa0, 0x8b, 0x10, 0x80, 0x68, 0x72, 0x2e, 0x5c, 0xa0, 0xb3, 0x01, 0x6b, + 0x43, 0x26, 0xad, 0x58, + }; + static BYTE ecdh521_secret[] = + { + 0x2d, 0xab, 0x9f, 0x38, 0x14, 0x5d, 0x49, 0x65, 0x06, 0x22, 0x04, 0xf9, 0xb3, 0x25, 0xca, 0xf9, + 0xe6, 0xdc, 0xc6, 0xe8, 0xf9, 0x0b, 0xbf, 0x3c, 0x9d, 0xf0, 0x08, 0x95, 0x92, 0xdd, 0x92, 0x8a, + 0x95, 0x85, 0xe8, 0x1c, 0x6d, 0x41, 0xb9, 0xe4, 0x7b, 0x7a, 0xa5, 0x68, 0x30, 0x48, 0x8e, 0xc0, + 0xbc, 0x2b, 0xc6, 0xe9, 0x75, 0x9c, 0xed, 0xc3, 0xf5, 0x3a, 0xa3, 0xd7, 0x41, 0xec, 0x28, 0x82, + 0xef, 0x01, + }; + static BYTE hashed521_secret[] = + { + 0x72, 0x39, 0x73, 0x5f, 0xc9, 0x26, 0x1f, 0x8e, 0xe3, 0x30, 0x11, 0xe1, 0x4f, 0xc4, 0x65, 0xc0, + 0xde, 0xf9, 0xe6, 0x6a, + }; - status = BCryptImportKeyPair(alg, NULL, BCRYPT_PUBLIC_KEY_BLOB, &pubkey, buf, size, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); - BCryptDestroyKey(pubkey); + static const struct ecdh_test tests[] = + { + { + BCRYPT_ECDH_P256_ALGORITHM, 256, ecc256privkey, sizeof(ecc256privkey), ecdh256_pubkey, sizeof(ecdh256_pubkey), + ecdh256_secret, sizeof(ecdh256_secret), hashed256_secret, + BCRYPT_ECDH_PUBLIC_P256_MAGIC, BCRYPT_ECDH_PRIVATE_P256_MAGIC, + }, + { + BCRYPT_ECDH_P384_ALGORITHM, 384, ecc384privkey, sizeof(ecc384privkey), ecdh384_pubkey, sizeof(ecdh384_pubkey), + ecdh384_secret, sizeof(ecdh384_secret), hashed384_secret, + BCRYPT_ECDH_PUBLIC_P384_MAGIC, BCRYPT_ECDH_PRIVATE_P384_MAGIC, + }, + { + BCRYPT_ECDH_P521_ALGORITHM, 521, ecc521privkey, sizeof(ecc521privkey), ecdh521_pubkey, sizeof(ecdh521_pubkey), + ecdh521_secret, sizeof(ecdh521_secret), hashed521_secret, + BCRYPT_ECDH_PUBLIC_P521_MAGIC, BCRYPT_ECDH_PRIVATE_P521_MAGIC, + }, + }; + unsigned int i; - status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, &pubkey, buf, size, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); - free(buf); - BCryptDestroyKey(pubkey); - BCryptCloseAlgorithmProvider(alg, 0); + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("%s", debugstr_w(tests[i].alg)); + test_ECDH_alg(&tests[i]); + winetest_pop_context(); + } } static BYTE dh_pubkey[] = @@ -3284,12 +3531,7 @@ static void test_DH(void) ok(key != NULL, "key not set\n"); status = BCryptFinalizeKeyPair(key, 0); - todo_wine ok(status == STATUS_SUCCESS, "got %#lx\n", status); - if (status != STATUS_SUCCESS) - { - BCryptDestroyKey(key); - return; - } + ok(status == STATUS_SUCCESS, "got %#lx\n", status); size = 0; status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, NULL, 0, &size, 0); @@ -3550,6 +3792,32 @@ static void test_BCryptSignHash(void) ret = BCryptCloseAlgorithmProvider(alg, 0); ok(!ret, "got %#lx\n", ret); + + /* ECDSA P521 */ + ret = BCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDSA_P521_ALGORITHM, NULL, 0); + ok(!ret, "got %#lx\n", ret); + + ret = BCryptGenerateKeyPair(alg, &key, 256, 0); + todo_wine ok(ret == STATUS_INVALID_PARAMETER, "got %#lx\n", ret); + ret = BCryptGenerateKeyPair(alg, &key, 522, 0); + todo_wine ok(ret == STATUS_INVALID_PARAMETER, "got %#lx\n", ret); + + ret = BCryptGenerateKeyPair(alg, &key, 521, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ret = BCryptFinalizeKeyPair(key, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + len = 0; + ret = BCryptSignHash(key, NULL, hash, sizeof(hash), sig, sizeof(sig), &len, 0); + ok (!ret, "got %#lx\n", ret); + ok (len == 132, "got %lu\n", len); + + ret = BCryptVerifySignature(key, NULL, hash, sizeof(hash), sig, len, 0); + ok(!ret, "got %#lx\n", ret); + + ret = BCryptDestroyKey(key); + ok(!ret, "got %#lx\n", ret); + ret = BCryptCloseAlgorithmProvider(alg, 0); + ok(!ret, "got %#lx\n", ret); } static void test_BCryptEnumAlgorithms(void) @@ -3981,6 +4249,17 @@ static void test_SecretAgreement(void) { 0x3213db5b, 0x8cc8250b, 0xc829eaab, 0x00933709, 0x68160aa9, 0xfb9f1e20, 0xf92368e6, 0x2b8e18eb, }; + static const struct + { + const WCHAR *alg; + ULONG bitlen; + } + ecdh_algorithms[] = + { + { BCRYPT_ECDH_P256_ALGORITHM, 256 }, + { BCRYPT_ECDH_P384_ALGORITHM, 384 }, + { BCRYPT_ECDH_P521_ALGORITHM, 521 }, + }; static const ULONG length = 1024; BCRYPT_DH_PARAMETER_HEADER *dh_header; BCRYPT_DH_KEY_BLOB *dh_key_blob; @@ -3991,62 +4270,66 @@ static void test_SecretAgreement(void) NTSTATUS status; ULONG size, i; - status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDH_P256_ALGORITHM, NULL, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); + for (i = 0; i < ARRAY_SIZE(ecdh_algorithms); ++i) + { + winetest_push_context("%s", debugstr_w(ecdh_algorithms[i].alg)); + status = BCryptOpenAlgorithmProvider(&alg, ecdh_algorithms[i].alg, NULL, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); - key = NULL; - status = BCryptGenerateKeyPair(alg, &key, 256, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); - ok(key != NULL, "key not set\n"); + key = NULL; + status = BCryptGenerateKeyPair(alg, &key, ecdh_algorithms[i].bitlen, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(key != NULL, "key not set\n"); - status = BCryptFinalizeKeyPair(key, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); + status = BCryptFinalizeKeyPair(key, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); - status = BCryptSecretAgreement(NULL, key, &secret, 0); - ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); + status = BCryptSecretAgreement(NULL, key, &secret, 0); + ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); - status = BCryptSecretAgreement(key, NULL, &secret, 0); - ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); + status = BCryptSecretAgreement(key, NULL, &secret, 0); + ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); - status = BCryptSecretAgreement(key, key, NULL, 0); - ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); + status = BCryptSecretAgreement(key, key, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); - status = BCryptSecretAgreement(key, key, &secret, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); + status = BCryptSecretAgreement(key, key, &secret, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); - status = BCryptDeriveKey(NULL, L"HASH", NULL, NULL, 0, &size, 0); - ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); + status = BCryptDeriveKey(NULL, L"HASH", NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); - status = BCryptDeriveKey(key, L"HASH", NULL, NULL, 0, &size, 0); - ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); + status = BCryptDeriveKey(key, L"HASH", NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); - status = BCryptDeriveKey(secret, NULL, NULL, NULL, 0, &size, 0); - ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); + status = BCryptDeriveKey(secret, NULL, NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); - status = BCryptDeriveKey(secret, L"HASH", NULL, NULL, 0, &size, 0); - todo_wine - ok(status == STATUS_SUCCESS, "got %#lx\n", status); + status = BCryptDeriveKey(secret, L"HASH", NULL, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); - status = BCryptDestroyHash(secret); - ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); + status = BCryptDestroyHash(secret); + ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); - status = BCryptDestroyKey(secret); - ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); + status = BCryptDestroyKey(secret); + ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); - status = BCryptDestroySecret(NULL); - ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); + status = BCryptDestroySecret(NULL); + ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); - status = BCryptDestroySecret(alg); - ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); + status = BCryptDestroySecret(alg); + ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); - status = BCryptDestroySecret(secret); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); + status = BCryptDestroySecret(secret); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); - status = BCryptDestroyKey(key); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); + status = BCryptDestroyKey(key); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); - status = BCryptCloseAlgorithmProvider(alg, 0); - ok(status == STATUS_SUCCESS, "got %#lx\n", status); + status = BCryptCloseAlgorithmProvider(alg, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); + winetest_pop_context(); + } /* DH */ status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_DH_ALGORITHM, NULL, 0); @@ -4064,7 +4347,7 @@ static void test_SecretAgreement(void) BCryptCloseAlgorithmProvider(alg, 0); return; } - todo_wine ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); status = BCryptSecretAgreement(key, key, &secret, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); @@ -4073,7 +4356,7 @@ static void test_SecretAgreement(void) ok(status == STATUS_SUCCESS, "got %#lx\n", status); status = BCryptDeriveKey(secret, L"HASH", NULL, NULL, 0, &size, 0); - todo_wine ok(status == STATUS_SUCCESS, "got %#lx\n", status); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); status = BCryptDestroySecret(secret); ok(status == STATUS_SUCCESS, "got %#lx\n", status); @@ -4329,6 +4612,482 @@ static void test_RC4(void) ok(status == STATUS_SUCCESS, "got %#lx\n", status); } +static void test_PBKDF2(void) +{ + static char salt[] = "cCxuHMEHLibcglJOG88dIw=="; + static ULONGLONG iter_count = 25; + static BCryptBuffer pbkdf2_param_buffers[] = + { + { + sizeof(BCRYPT_SHA1_ALGORITHM), + KDF_HASH_ALGORITHM, + (void *)BCRYPT_SHA1_ALGORITHM, + }, + { + sizeof(salt) - 1, + KDF_SALT, + salt, + }, + { + sizeof(iter_count), + KDF_ITERATION_COUNT, + (void *)&iter_count, + } + }; + static BCryptBufferDesc pbkdf2_params = + { + BCRYPTBUFFER_VERSION, + ARRAY_SIZE(pbkdf2_param_buffers), + pbkdf2_param_buffers, + }; + static UCHAR pbkdf2_hash[] = + { + 0x18, 0xf2, 0x58, 0x0b, 0x92, 0x6e, 0x6d, 0xfe, + 0x55, 0xbb, 0x62, 0x87, 0x5b, 0x1f, 0x61, 0x83, + 0x4d, 0x16, 0xe4, 0x04, 0xcd, 0xab, 0x43, 0x77, + 0x25, 0x3e, 0x1d, 0xb4, 0x95, 0x5f, 0xf7, 0x01, + }; + + BCRYPT_KEY_LENGTHS_STRUCT key_lengths; + BCRYPT_ALG_HANDLE alg; + BCRYPT_KEY_HANDLE key; + NTSTATUS status; + ULONG val, size; + static BYTE buf[32]; + + status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_PBKDF2_ALGORITHM, NULL, 0); + if (status == STATUS_NOT_FOUND) + { + win_skip("PBKDF2 not available\n"); + return; + } + ok(!status, "got %#lx\n", status); + ok(pBCryptKeyDerivation != NULL, "BCryptKeyDerivation not available\n"); + + val = size = 0; + status = BCryptGetProperty(alg, BCRYPT_OBJECT_LENGTH, (UCHAR *)&val, sizeof(val), &size, 0); + ok(!status, "got %#lx\n", status); + ok(val, "got %lu\n", val); + ok(size == sizeof(val), "got %lu\n", size); + + val = size = 0; + status = BCryptGetProperty(alg, BCRYPT_BLOCK_LENGTH, (UCHAR *)&val, sizeof(val), &size, 0); + ok(status == STATUS_NOT_SUPPORTED, "got %#lx\n", status); + + memset(&key_lengths, 0xfe, sizeof(key_lengths)); + size = 0; + status = BCryptGetProperty(alg, BCRYPT_KEY_LENGTHS, (UCHAR *)&key_lengths, sizeof(key_lengths), &size, 0); + ok(!status, "got %#lx\n", status); + ok(size == sizeof(key_lengths), "got %lu\n", size); + ok(key_lengths.dwMinLength == 0, "got %lu\n", key_lengths.dwMinLength); + ok(key_lengths.dwMaxLength == 16384, "got %lu\n", key_lengths.dwMaxLength); + ok(key_lengths.dwIncrement == 8, "got %lu\n", key_lengths.dwIncrement); + + key = 0; + status = BCryptGenerateSymmetricKey(alg, &key, NULL, 0, (UCHAR *)"test", 4, 0); + ok(!status, "got %#lx\n", status); + val = size = 0; + status = BCryptGetProperty(key, BCRYPT_KEY_STRENGTH, (UCHAR *)&val, sizeof(val), &size, 0); + ok(!status, "got %#lx\n", status); + ok(val == strlen("test") * 8, "got %lu\n", val); + + status = pBCryptKeyDerivation(key, &pbkdf2_params, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); + + buf[0] = buf[1] = 'x'; + status = pBCryptKeyDerivation(key, &pbkdf2_params, buf, 1, &size, 0); + ok(!status, "got %#lx\n", status); + ok(size == 1, "size = %lu\n", size); + ok(buf[0] == pbkdf2_hash[0], "buf[0] = %x\n", buf[0]); + ok(buf[1] == 'x', "buf[1] = %x\n", buf[1]); + + memset(buf, 'x', sizeof(buf)); + status = pBCryptKeyDerivation(key, &pbkdf2_params, buf, sizeof(buf), &size, 0); + ok(!status, "got %#lx\n", status); + ok(size == sizeof(buf), "size = %lu\n", size); + ok(!memcmp(buf, pbkdf2_hash, sizeof(pbkdf2_hash)), + "wrong data (%s)\n", wine_dbgstr_an((char *)buf, size)); + + status = BCryptDestroyKey(key); + ok(!status, "got %#lx\n", status); + status = BCryptCloseAlgorithmProvider(alg, 0); + ok(status == STATUS_SUCCESS, "got %#lx\n", status); +} + +static void test_dh_SecretAgreement(void) +{ + static BCryptBuffer hash_param_buffers[] = + { + { + sizeof(BCRYPT_SHA256_ALGORITHM), + KDF_HASH_ALGORITHM, + (void *)BCRYPT_SHA256_ALGORITHM, + } + }; + + static BCryptBufferDesc hash_params = + { + BCRYPTBUFFER_VERSION, + ARRAY_SIZE(hash_param_buffers), + hash_param_buffers, + }; + + static const ULONG private_key_data[] = + { + 0xc4caf69c, 0x57b4db27, 0x36f7135f, 0x5ccba686, 0xc37b8819, 0x1d35c9b2, 0xbb07a1cf, 0x0c5d1c1b, + 0xc79acb10, 0x31dfdabb, 0x702e02b9, 0x1efab345, 0x262a8074, 0x5edf7698, 0x9b9dc630, 0x13c34b93, + 0xacbc928b, 0xb79eed8c, 0x7413dce9, 0xa5521280, 0x88d8e695, 0xa310269f, 0xca7c5719, 0xcd0c775b, + 0x9a6e2cf2, 0x9e235c51, 0xf49db62d, 0x28e72424, 0x4a44da5a, 0x3d98268d, 0x8e4d2be3, 0x254e44e6, + + 0x18a67e55, 0x572e13a1, 0x46f81ca8, 0xc331c9b9, 0xf8fe3dd4, 0x8a889e5a, 0x6c0505fd, 0xbd97a121, + 0xed2dbd67, 0xf39efa8e, 0x36f9c287, 0xf6bbfa6c, 0x461e42ad, 0x17dc170e, 0xc002dc2e, 0x4813d9a4, + 0x0b6fabb8, 0x6a9e1860, 0xa8a8cbd9, 0xb7ed6b5d, 0xabb34d23, 0xf2fbe1fd, 0x8670df1e, 0xba7fa4e6, + 0xf7039712, 0x94448f30, 0xe10c812e, 0x3e311976, 0xcfdd72c4, 0xbdbea98f, 0xc9a540d6, 0x89646d57, + + 0x7ab63b33, 0x03a1e9b6, 0x947f7a9b, 0x5ae59eeb, 0x1d12eb05, 0x3f425d92, 0xe028c6ba, 0xbf90ddc9, + 0xb554f55a, 0x7aeb88b6, 0x4a443a5f, 0xbab35111, 0x82c78a0c, 0x298dd482, 0x02937cb1, 0xc94cdc2e, + 0x59b010eb, 0x3bbc0a2b, 0xd845fee0, 0x04c1d0db, 0x0c8c9424, 0x1cafd4b2, 0x9aa7aed9, 0x6a478486, + 0xa8841fd7, 0xbfeff40a, 0x8fd7bcc5, 0x3bb28977, 0x2b9a7955, 0xa55cd2e4, 0x1b6ad657, 0x067cdf21, + + 0x06f36920, 0x63280e1b, 0xf17d930f, 0xa06e74a8, 0x463b3a6f, 0x2a464507, 0x93f8a982, 0x8f620a7d, + 0xeda32d11, 0x9706a6d4, 0x33dce588, 0x75a1c446, 0x048ab567, 0xd735aafa, 0x806f7c1c, 0xdcb9651a, + 0x26acf3b4, 0x45f91cc9, 0x2a0de6fc, 0xf3c03d0c, 0xf5aee0aa, 0x3eeaaf36, 0x18ccee61, 0x83faa783, + 0x4b2b5250, 0xf4ccea22, 0x5ac0714b, 0x3f0b2bc6, 0x481b13ce, 0x12040ea7, 0x66e0bbed, 0x158e1a67, + }; + static const ULONG raw_shared_secret[] = + { + 0x375d89b5, 0x35a9c270, 0xfbc5ba82, 0x09eb3069, 0xd50965b0, 0xace510f7, 0x981e8731, 0x80a76115, + 0xf386d348, 0xca17b8df, 0x0b0e84ec, 0xf81f756e, 0x5030fa20, 0x03113b71, 0x97b7e879, 0x899b5fae, + 0xe6913299, 0x09270076, 0x39bc813a, 0xde3ef070, 0x65ad5b3a, 0x2b7c4ba4, 0x86c98ef9, 0x3236feaf, + 0x3e0253f7, 0x0489d2dd, 0x97669a3d, 0x50242fca, 0x5d4aecb1, 0xcf2d805f, 0x2258afff, 0x750e92cd, + }; + static const ULONG sha1_shared_secret[] = + { + 0x0babba9c, 0x0bdeacbd, 0x04e36574, 0xdd504dcd, 0x0cd88db0, + }; + static const ULONG sha256_shared_secret[] = + { + 0x3213db5b, 0x8cc8250b, 0xc829eaab, 0x00933709, 0x68160aa9, 0xfb9f1e20, 0xf92368e6, 0x2b8e18eb, + }; + + BCRYPT_DH_PARAMETER_HEADER *dh_header; + BCRYPT_SECRET_HANDLE secret, secret2; + BCRYPT_DH_KEY_BLOB *dh_key_blob; + static const ULONG length = 1024; + BCRYPT_KEY_HANDLE key, key2; + BCRYPT_ALG_HANDLE alg; + UCHAR buffer[2048]; + NTSTATUS status; + unsigned int i; + ULONG size; + + status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_DH_ALGORITHM, NULL, 0); + ok(!status, "got %08lx\n", status); + if (status) + return; + + key = NULL; + + status = BCryptGenerateKeyPair(alg, &key, 256, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + + status = BCryptGenerateKeyPair(alg, &key, length, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(key != NULL, "key not set\n"); + + memset(buffer, 0xcc, sizeof(buffer)); + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptFinalizeKeyPair(key, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + size = 0xdeadbeef; + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, NULL, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_PARAMETER_HEADER) + length / 8 * 2, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, buffer, 28, &size, 0); + ok(status == STATUS_BUFFER_TOO_SMALL, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_PARAMETER_HEADER) + length / 8 * 2, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_PARAMETER_HEADER) + length / 8 * 2, "Got unexpected size %lu.\n", size); + + dh_header = (BCRYPT_DH_PARAMETER_HEADER *)buffer; + ok(dh_header->cbLength == sizeof(*dh_header) + length / 8 * 2, "Got unexpected length %lu.\n", dh_header->cbLength); + ok(dh_header->cbKeyLength == length / 8, "Got unexpected length %lu.\n", dh_header->cbKeyLength); + ok(dh_header->dwMagic == BCRYPT_DH_PARAMETERS_MAGIC, "Got unexpected magic %#lx.\n", dh_header->dwMagic); + + status = BCryptDestroyKey(key); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + dh_key_blob->dwMagic = BCRYPT_DH_PRIVATE_MAGIC; + dh_key_blob->cbKey = length / 8; + memcpy(dh_key_blob + 1, private_key_data, sizeof(private_key_data)); + size = sizeof(buffer); + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PRIVATE_BLOB, &key, buffer, size, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + size = sizeof(*dh_key_blob) + length / 8 * 4; + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PRIVATE_BLOB, &key, buffer, size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptFinalizeKeyPair(key, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + memset(buffer, 0xcc, sizeof(buffer)); + size = 0xdeadbeef; + status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 3, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 3, "Got unexpected size %lu.\n", size); + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + ok(dh_key_blob->dwMagic == BCRYPT_DH_PUBLIC_MAGIC, "Got unexpected magic %#lx.\n", dh_key_blob->dwMagic); + ok(dh_key_blob->cbKey == length / 8, "Got unexpected length %lu.\n", dh_key_blob->cbKey); + ok(!memcmp(dh_key_blob + 1, private_key_data, length / 8 * 3), "Key data does not match.\n"); + + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PUBLIC_BLOB, &key2, buffer, size, 0); + ok(status == STATUS_SUCCESS, "got %#lx.\n", status); + status = BCryptFinalizeKeyPair(key2, 0); + ok(status == STATUS_INVALID_HANDLE, "got %#lx.\n", status); + status = BCryptSecretAgreement(key2, key2, &secret, 0); + todo_wine ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + BCryptDestroyKey(key2); + + status = BCryptGenerateKeyPair(alg, &key2, length, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + dh_header = (BCRYPT_DH_PARAMETER_HEADER *)buffer; + dh_header->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC; + dh_header->cbLength = sizeof(*dh_header) + length / 8 * 2; + dh_header->cbKeyLength = length / 8; + memcpy(dh_header + 1, private_key_data, length / 8 * 2); + status = BCryptSetProperty(key2, BCRYPT_DH_PARAMETERS, buffer, dh_header->cbLength, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptSetProperty(key2, BCRYPT_DH_PARAMETERS, buffer, dh_header->cbLength, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptFinalizeKeyPair(key2, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + if (0) + { + /* Crashes on Windows. */ + BCryptSetProperty(key2, BCRYPT_DH_PARAMETERS, buffer, dh_header->cbLength, 0); + } + + status = BCryptExportKey(key2, NULL, BCRYPT_DH_PUBLIC_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 3, "Got unexpected size %lu.\n", size); + ok(dh_key_blob->dwMagic == BCRYPT_DH_PUBLIC_MAGIC, "Got unexpected dwMagic %#lx.\n", dh_key_blob->dwMagic); + ok(dh_key_blob->cbKey == length / 8, "Got unexpected length %lu.\n", dh_key_blob->cbKey); + ok(!memcmp(dh_key_blob + 1, private_key_data, length / 8 * 2), "DH parameters do not match.\n"); + ok(memcmp((BYTE *)(dh_key_blob + 1) + length / 8 * 2, (BYTE *)private_key_data + length / 8 * 2, length / 8), + "Random public key data matches.\n"); + + memset(buffer, 0xcc, sizeof(buffer)); + status = BCryptExportKey(key, NULL, BCRYPT_DH_PRIVATE_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 4, "Got unexpected size %lu.\n", size); + ok(dh_key_blob->dwMagic == BCRYPT_DH_PRIVATE_MAGIC, "Got unexpected dwMagic %#lx.\n", dh_key_blob->dwMagic); + ok(dh_key_blob->cbKey == length / 8, "Got unexpected length %lu.\n", dh_key_blob->cbKey); + ok(!memcmp(dh_key_blob + 1, private_key_data, length / 8 * 4), "Private key data does not match.\n"); + + status = BCryptSecretAgreement(NULL, key, &secret, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, NULL, &secret, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key, &secret, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDeriveKey(NULL, L"HASH", NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDeriveKey(key, L"HASH", NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDeriveKey(secret, NULL, NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + + size = 0xdeadbeef; + status = BCryptDeriveKey(secret, L"HASH", NULL, NULL, 0, &size, 0); + ok(size == 20, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == length / 8, "Got unexpected size %lu.\n", size); + + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == length / 8, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, raw_shared_secret, size), "Raw shared secret data does not match.\n"); + + size = sizeof(buffer); + memset(buffer, 0xcc, sizeof(buffer)); + status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == 20, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, sha1_shared_secret, sizeof(sha1_shared_secret)), "sha1 shared secret data does not match.\n"); + + size = sizeof(buffer); + status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &hash_params, buffer, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == 32, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, sha256_shared_secret, sizeof(sha256_shared_secret)), "sha1 shared secret data does not match.\n"); + + for (i = size; i < sizeof(buffer); ++i) + if (buffer[i] != 0xcc) + break; + ok(i == sizeof(buffer), "Buffer modified at %i, value %#x.\n", i, buffer[i]); + + status = BCryptDestroySecret(secret); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key2, &secret, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptSecretAgreement(key2, key, &secret2, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer + size, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(!memcmp(buffer, buffer + size, size), "Shared secrets do not match.\n"); + + status = BCryptDestroyHash(secret); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + + status = BCryptDestroyKey(secret); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDestroySecret(NULL); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDestroySecret(alg); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDestroySecret(secret); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDestroyKey(key); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDestroyKey(key2); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptCloseAlgorithmProvider(alg, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); +} + +static void test_dh_SecretAgreement_values(void) +{ + static const ULONG private_key_data[] = + { + 0xffffffff, 0xffffffff, 0xa2da0fc9, 0x34c26821, 0x8b62c6c4, 0xd11cdc80, 0x084e0229, 0x74cc678a, + 0xa6be0b02, 0x229b133b, 0x79084a51, 0xdd04348e, 0xb31995ef, 0x1b433acd, 0x6d0a2b30, 0x37145ff2, + 0x6d35e14f, 0x45c2516d, 0x76b585e4, 0xc67e5e62, 0xe9424cf4, 0x6bed37a6, 0xb65cff0b, 0xedb706f4, + 0xfb6b38ee, 0xa59f895a, 0x11249fae, 0xe61f4b7c, 0x51662849, 0x8153e6ec, 0xffffffff, 0xffffffff, + + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000, + + 0xa0c3c734, 0xc130c92d, 0x5265abf8, 0xff409f17, 0xbcdce187, 0xff64dae3, 0x170560aa, 0xb2423ed8, + 0x9ee5a8b9, 0x92548030, 0x02bba1f9, 0x823e39a4, 0x69c438f5, 0xf91016ac, 0x89bfd166, 0x7f996446, + 0x86224203, 0x15bf689c, 0x619354a4, 0x0c1d3a1f, 0x11bcf3d2, 0x58aae029, 0x41c69824, 0x3fafc179, + 0xa742747c, 0x60658c7a, 0xd3b0bde4, 0x78d3f08b, 0x6cefa061, 0x33752536, 0xe84d4901, 0x48cd73f4, + + 0x8d449700, 0x1f95120e, 0xceb31745, 0x3663177b, 0xbd9bb2d5, 0x9c23c0d9, 0x814d34f8, 0xbc54edb0, + 0xb874659a, 0x3bac8a30, 0xa1f3dd46, 0x1705c900, 0xbc46fefe, 0x7d13875b, 0x3064351a, 0x4bd89a1c, + 0x9e938761, 0x931949db, 0x34490719, 0x84fb08ca, 0xa9dd355a, 0x5b3f5061, 0x2ac96663, 0xc594429e, + 0xbe58395d, 0x2f7d872a, 0x303d37b3, 0xa3a9b606, 0x735a6732, 0xa095bd95, 0x3d55a7c3, 0x00e54635, + }; + static const ULONG peer_key_data[] = + { + 0xffffffff, 0xffffffff, 0xa2da0fc9, 0x34c26821, 0x8b62c6c4, 0xd11cdc80, 0x084e0229, 0x74cc678a, + 0xa6be0b02, 0x229b133b, 0x79084a51, 0xdd04348e, 0xb31995ef, 0x1b433acd, 0x6d0a2b30, 0x37145ff2, + 0x6d35e14f, 0x45c2516d, 0x76b585e4, 0xc67e5e62, 0xe9424cf4, 0x6bed37a6, 0xb65cff0b, 0xedb706f4, + 0xfb6b38ee, 0xa59f895a, 0x11249fae, 0xe61f4b7c, 0x51662849, 0x8153e6ec, 0xffffffff, 0xffffffff, + + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000, + + 0x3bf7404b, 0x6284fffe, 0x97c0d565, 0xd830c658, 0xcc21bf39, 0xcae45bb6, 0x019df7df, 0xbf4cd293, + 0x6bf1989d, 0x78a81f52, 0xa4ed861c, 0x6bacf493, 0xa3e700d1, 0xd06cc206, 0x411b9727, 0x01e9c9ab, + 0x9b7e6efa, 0xf46bb25d, 0xd1027242, 0x6130787c, 0xa7b87d8b, 0xfee41492, 0x50db6213, 0x321199b6, + 0x7dace53a, 0xe8b1ec51, 0x2181b113, 0x3b33e3c0, 0x5b3a2d67, 0xbd34f0c1, 0x7037c542, 0x4a8d5540, + }; + static const ULONG raw_shared_secret[] = + { + 0x0815f37d, 0x19ee74ab, 0x9f63f123, 0xe1b3f10c, 0xbcc9be83, 0xaddf5b9d, 0x28174e72, 0xf8a33825, + 0xfc74e47d, 0x2c950888, 0xf5b776d9, 0xfc712fef, 0x5b213b32, 0x489a9829, 0xfc0a4d1d, 0x6e641d3b, + 0x3bb2ff57, 0x63500318, 0x081ee54f, 0xf33a2805, 0xb3759e98, 0xa9a64afe, 0x964b8897, 0x04691bbc, + 0x80f4aae1, 0x617405ee, 0xab71724d, 0x6c10c214, 0x6f60b96f, 0xdc777b0b, 0x22f40d4f, 0x8a1c4eb5, + }; + + BCRYPT_DH_KEY_BLOB *dh_key_blob; + static const ULONG length = 1024; + BCRYPT_KEY_HANDLE key, key2; + BCRYPT_SECRET_HANDLE secret; + BCRYPT_ALG_HANDLE alg; + UCHAR buffer[2048]; + NTSTATUS status; + ULONG size; + + status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_DH_ALGORITHM, NULL, 0); + ok(!status, "got %08lx\n", status); + + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + dh_key_blob->dwMagic = BCRYPT_DH_PRIVATE_MAGIC; + dh_key_blob->cbKey = length / 8; + memcpy(dh_key_blob + 1, private_key_data, sizeof(private_key_data)); + + size = sizeof(*dh_key_blob) + length / 8 * 4; + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PRIVATE_BLOB, &key, buffer, size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + dh_key_blob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC; + dh_key_blob->cbKey = length / 8; + memcpy(dh_key_blob + 1, peer_key_data, sizeof(peer_key_data)); + + size = sizeof(*dh_key_blob) + length / 8 * 3; + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PUBLIC_BLOB, &key2, buffer, size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key2, &secret, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == length / 8, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, raw_shared_secret, size), "Raw shared secret data does not match.\n"); + + status = BCryptDestroySecret(secret); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDestroyKey(key); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDestroyKey(key2); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); +} + START_TEST(bcrypt) { HMODULE module; @@ -4340,6 +5099,7 @@ START_TEST(bcrypt) return; } pBCryptHash = (void *)GetProcAddress(module, "BCryptHash"); + pBCryptKeyDerivation = (void *)GetProcAddress(module, "BCryptKeyDerivation"); test_BCryptGenRandom(); test_BCryptGetFipsAlgorithmMode(); @@ -4367,6 +5127,9 @@ START_TEST(bcrypt) test_SecretAgreement(); test_rsa_encrypt(); test_RC4(); + test_PBKDF2(); + test_dh_SecretAgreement(); + test_dh_SecretAgreement_values(); FreeLibrary(module); } diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 29de7bbdc55f..5e48ba13b1b6 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -83,10 +83,10 @@ @ stdcall CM_Get_Device_Interface_AliasW(wstr ptr ptr ptr long) setupapi.CM_Get_Device_Interface_AliasW @ stub CM_Get_Device_Interface_Alias_ExA @ stub CM_Get_Device_Interface_Alias_ExW -@ stub CM_Get_Device_Interface_ListA -@ stub CM_Get_Device_Interface_ListW -@ stub CM_Get_Device_Interface_List_ExA -@ stub CM_Get_Device_Interface_List_ExW +@ stdcall CM_Get_Device_Interface_ListA(ptr ptr ptr long long) setupapi.CM_Get_Device_Interface_ListA +@ stdcall CM_Get_Device_Interface_ListW(ptr ptr ptr long long) setupapi.CM_Get_Device_Interface_ListW +@ stdcall CM_Get_Device_Interface_List_ExA(ptr ptr ptr long long ptr) setupapi.CM_Get_Device_Interface_List_ExA +@ stdcall CM_Get_Device_Interface_List_ExW(ptr ptr ptr long long ptr) setupapi.CM_Get_Device_Interface_List_ExW @ stdcall CM_Get_Device_Interface_List_SizeA(ptr ptr str long) setupapi.CM_Get_Device_Interface_List_SizeA @ stdcall CM_Get_Device_Interface_List_SizeW(ptr ptr wstr long) setupapi.CM_Get_Device_Interface_List_SizeW @ stdcall CM_Get_Device_Interface_List_Size_ExA(ptr ptr str long ptr) setupapi.CM_Get_Device_Interface_List_Size_ExA diff --git a/dlls/cfgmgr32/main.c b/dlls/cfgmgr32/main.c index b545d761f686..7f4ee0679ae9 100644 --- a/dlls/cfgmgr32/main.c +++ b/dlls/cfgmgr32/main.c @@ -19,6 +19,11 @@ #include "wine/debug.h" #include "winreg.h" #include "cfgmgr32.h" +#include "winuser.h" +#include "setupapi.h" + +#include "initguid.h" +#include "devpkey.h" WINE_DEFAULT_DEBUG_CHANNEL(setupapi); @@ -76,8 +81,45 @@ CONFIGRET WINAPI CM_Get_Device_Interface_PropertyW( LPCWSTR device_interface, co DEVPROPTYPE *property_type, BYTE *property_buffer, ULONG *property_buffer_size, ULONG flags ) { - FIXME("%s %p %p %p %p %ld stub!\n", debugstr_w(device_interface), property_key, property_type, - property_buffer, property_buffer_size, flags); + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + SP_DEVINFO_DATA device = { sizeof(device) }; + HDEVINFO set; + DWORD err; + BOOL ret; - return CR_CALL_NOT_IMPLEMENTED; + TRACE( "%s %p %p %p %p %ld.\n", debugstr_w(device_interface), property_key, property_type, property_buffer, + property_buffer_size, flags); + + if (!property_key) return CR_FAILURE; + if (!device_interface || !property_type || !property_buffer_size) return CR_INVALID_POINTER; + if (*property_buffer_size && !property_buffer) return CR_INVALID_POINTER; + if (flags) return CR_INVALID_FLAG; + + if (memcmp( property_key, &DEVPKEY_Device_InstanceId, sizeof(*property_key) )) + { + FIXME( "property %s\\%lx.\n", debugstr_guid( &property_key->fmtid ), property_key->pid ); + return CR_NO_SUCH_VALUE; + } + + set = SetupDiCreateDeviceInfoListExW( NULL, NULL, NULL, NULL ); + if (set == INVALID_HANDLE_VALUE) return CR_OUT_OF_MEMORY; + if (!SetupDiOpenDeviceInterfaceW( set, device_interface, 0, &iface )) + { + SetupDiDestroyDeviceInfoList( set ); + TRACE( "No interface %s, err %lu.\n", debugstr_w( device_interface ), GetLastError()); + return CR_NO_SUCH_DEVICE_INTERFACE; + } + if (!SetupDiEnumDeviceInfo( set, 0, &device )) + { + SetupDiDestroyDeviceInfoList( set ); + return CR_FAILURE; + } + ret = SetupDiGetDeviceInstanceIdW( set, &device, (WCHAR *)property_buffer, *property_buffer_size / sizeof(WCHAR), + property_buffer_size ); + err = ret ? 0 : GetLastError(); + SetupDiDestroyDeviceInfoList( set ); + *property_type = DEVPROP_TYPE_STRING; + *property_buffer_size *= sizeof(WCHAR); + if (!err) return CR_SUCCESS; + return err == ERROR_INSUFFICIENT_BUFFER ? CR_BUFFER_SMALL : CR_FAILURE; } diff --git a/dlls/cfgmgr32/tests/Makefile.in b/dlls/cfgmgr32/tests/Makefile.in index 8b836ba3b766..90f5ac496a39 100644 --- a/dlls/cfgmgr32/tests/Makefile.in +++ b/dlls/cfgmgr32/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = cfgmgr32.dll -IMPORTS = cfgmgr32 +IMPORTS = cfgmgr32 setupapi ole32 uuid advapi32 SOURCES = \ cfgmgr32.c diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c index 22344c45afcc..ece23562483c 100644 --- a/dlls/cfgmgr32/tests/cfgmgr32.c +++ b/dlls/cfgmgr32/tests/cfgmgr32.c @@ -17,8 +17,16 @@ */ #include "wine/test.h" -#include "winreg.h" +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "objbase.h" +#include "devguid.h" +#include "initguid.h" +#include "devpkey.h" +#include "setupapi.h" #include "cfgmgr32.h" +#include "ntddvdeo.h" static void test_CM_MapCrToWin32Err(void) { @@ -106,7 +114,342 @@ static void test_CM_MapCrToWin32Err(void) } } +DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2); + +static void test_CM_Get_Device_ID_List(void) +{ + struct + { + WCHAR id[128]; + DEVINST inst; + } + instances[128]; + SP_DEVINFO_DATA device = { sizeof(device) }; + unsigned int i, count, expected_count; + WCHAR wguid_str[64], id[128], *wbuf, *wp; + char guid_str[64], id_a[128], *buf, *p; + DEVINST devinst; + CONFIGRET ret; + HDEVINFO set; + ULONG len; + + StringFromGUID2(&GUID_DEVCLASS_DISPLAY, wguid_str, ARRAY_SIZE(wguid_str)); + wp = wguid_str; + p = guid_str; + while ((*p++ = *wp++)) + ; + + ret = CM_Get_Device_ID_List_SizeW(NULL, wguid_str, CM_GETIDLIST_FILTER_CLASS); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + len = 0xdeadbeef; + ret = CM_Get_Device_ID_List_SizeW(&len, NULL, CM_GETIDLIST_FILTER_CLASS); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ok(!len, "got %#lx.\n", len); + len = 0xdeadbeef; + ret = CM_Get_Device_ID_List_SizeW(&len, L"q", CM_GETIDLIST_FILTER_CLASS); + ok(ret == CR_INVALID_DATA, "got %#lx.\n", ret); + ok(!len, "got %#lx.\n", len); + + ret = CM_Get_Device_ID_List_SizeA(NULL, guid_str, CM_GETIDLIST_FILTER_CLASS); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + len = 0xdeadbeef; + ret = CM_Get_Device_ID_List_SizeA(&len, NULL, CM_GETIDLIST_FILTER_CLASS); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ok(!len, "got %#lx.\n", len); + len = 0xdeadbeef; + ret = CM_Get_Device_ID_List_SizeA(&len, "q", CM_GETIDLIST_FILTER_CLASS); + ok(ret == CR_INVALID_DATA, "got %#lx.\n", ret); + ok(!len, "got %#lx.\n", len); + + len = 0xdeadbeef; + ret = CM_Get_Device_ID_List_SizeW(&len, NULL, 0); + ok(!ret, "got %#lx.\n", ret); + ok(len > 2, "got %#lx.\n", len); + + wbuf = malloc(len * sizeof(*wbuf)); + buf = malloc(len); + + ret = CM_Get_Device_ID_ListW(NULL, wbuf, len, 0); + ok(!ret, "got %#lx.\n", ret); + + len = 0xdeadbeef; + ret = CM_Get_Device_ID_List_SizeW(&len, wguid_str, CM_GETIDLIST_FILTER_CLASS); + ok(!ret, "got %#lx.\n", ret); + ok(len > 2, "got %lu.\n", len); + memset(wbuf, 0xcc, len * sizeof(*wbuf)); + ret = CM_Get_Device_ID_ListW(wguid_str, wbuf, 0, CM_GETIDLIST_FILTER_CLASS); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ok(wbuf[0] == 0xcccc, "got %#x.\n", wbuf[0]); + memset(wbuf, 0xcc, len * sizeof(*wbuf)); + ret = CM_Get_Device_ID_ListW(wguid_str, wbuf, 1, CM_GETIDLIST_FILTER_CLASS); + ok(ret == CR_BUFFER_SMALL, "got %#lx.\n", ret); + ok(!wbuf[0], "got %#x.\n", wbuf[0]); + + len = 0xdeadbeef; + ret = CM_Get_Device_ID_List_SizeA(&len, guid_str, CM_GETIDLIST_FILTER_CLASS); + ok(!ret, "got %#lx.\n", ret); + ok(len > 2, "got %lu.\n", len); + memset(buf, 0x7c, len); + ret = CM_Get_Device_ID_ListA(guid_str, buf, 0, CM_GETIDLIST_FILTER_CLASS); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ok(buf[0] == 0x7c, "got %#x.\n", buf[0]); + memset(buf, 0x7c, len); + ret = CM_Get_Device_ID_ListA(guid_str, buf, 1, CM_GETIDLIST_FILTER_CLASS); + ok(ret == CR_BUFFER_SMALL, "got %#lx.\n", ret); + ok(buf[0] == 0x7c, "got %#x.\n", buf[0]); + + set = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, 0); + ok(set != &GUID_DEVCLASS_DISPLAY, "got error %#lx.\n", GetLastError()); + for (i = 0; SetupDiEnumDeviceInfo(set, i, &device); ++i) + { + ok(i < ARRAY_SIZE(instances), "got %u.\n", i); + ret = SetupDiGetDeviceInstanceIdW(set, &device, instances[i].id, sizeof(instances[i].id), NULL); + ok(ret, "got error %#lx.\n", GetLastError()); + instances[i].inst = device.DevInst; + } + SetupDiDestroyDeviceInfoList(set); + expected_count = i; + ok(expected_count, "got 0.\n"); + + wcscpy(id, L"q"); + devinst = 0xdeadbeef; + ret = CM_Locate_DevNodeW(&devinst, id, 0); + todo_wine_if(ret == CR_NO_SUCH_DEVNODE) ok(ret == CR_INVALID_DEVICE_ID, "got %#lx.\n", ret); + ok(!devinst, "got %#lx.\n", devinst); + + wcscpy(id, instances[0].id); + id[0] = 'Q'; + ret = CM_Locate_DevNodeW(&devinst, id, 0); + ok(ret == CR_NO_SUCH_DEVNODE, "got %#lx.\n", ret); + + for (i = 0; i < expected_count; ++i) + { + DEVPROPTYPE type; + ULONG size; + + *id = 0; + ret = CM_Get_Device_IDW(instances[i].inst, id, ARRAY_SIZE(id), 0); + ok(!ret, "got %#lx.\n", ret); + ok(!wcscmp(id, instances[i].id), "got %s, expected %s.\n", debugstr_w(id), debugstr_w(instances[i].id)); + size = len; + ret = CM_Get_DevNode_PropertyW(instances[i].inst, &DEVPROPKEY_GPU_LUID, &type, wbuf, &size, 0); + ok(!ret, "got %#lx.\n", ret); + ok(type == DEVPROP_TYPE_UINT64, "got %#lx.\n", type); + + devinst = 0xdeadbeef; + ret = CM_Locate_DevNodeW(&devinst, instances[i].id, 0); + ok(!ret, "got %#lx.\n", ret); + ok(devinst == instances[i].inst, "got %#lx, expected %#lx.\n", devinst, instances[i].inst); + p = id_a; + wp = instances[i].id; + while((*p++ = *wp++)) + ; + devinst = 0xdeadbeef; + ret = CM_Locate_DevNodeA(&devinst, id_a, 0); + ok(!ret, "got %#lx.\n", ret); + ok(devinst == instances[i].inst, "got %#lx, expected %#lx.\n", devinst, instances[i].inst); + } + + memset(wbuf, 0xcc, len * sizeof(*wbuf)); + ret = CM_Get_Device_ID_ListW(wguid_str, wbuf, len, CM_GETIDLIST_FILTER_CLASS); + ok(!ret, "got %#lx.\n", ret); + count = 0; + wp = wbuf; + while (*wp) + { + ++count; + ok(!wcsncmp(wp, L"PCI\\", 4), "got %s.\n", debugstr_w(wp)); + wp += wcslen(wp) + 1; + } + ok(count == expected_count, "got %u, expected %u.\n", count, expected_count); + + memset(buf, 0xcc, len * sizeof(*buf)); + ret = CM_Get_Device_ID_ListA(guid_str, buf, len, CM_GETIDLIST_FILTER_CLASS); + ok(!ret, "got %#lx.\n", ret); + count = 0; + p = buf; + while (*p) + { + ++count; + ok(!strncmp(p, "PCI\\", 4), "got %s.\n", debugstr_a(p)); + p += strlen(p) + 1; + } + ok(count == expected_count, "got %u, expected %u.\n", count, expected_count); + + StringFromGUID2(&GUID_DISPLAY_DEVICE_ARRIVAL, wguid_str, ARRAY_SIZE(wguid_str)); + len = 0xdeadbeef; + ret = CM_Get_Device_ID_List_SizeW(&len, wguid_str, CM_GETIDLIST_FILTER_CLASS); + ok(!ret, "got %#lx.\n", ret); + ok(len == 1, "got %lu.\n", len); + memset(wbuf, 0xcc, len * sizeof(*wbuf)); + ret = CM_Get_Device_ID_ListW(wguid_str, wbuf, len, CM_GETIDLIST_FILTER_CLASS); + ok(!ret, "got %#lx.\n", ret); + free(wbuf); + free(buf); +} + +static void check_device_path_casing(const WCHAR *original_path) +{ + HKEY current_key, tmp; + WCHAR *path = wcsdup(original_path); + WCHAR key_name[MAX_PATH]; + WCHAR separator[] = L"#"; + WCHAR *token, *context = NULL; + LSTATUS ret; + DWORD i; + + ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum", ¤t_key); + ok(!ret, "Failed to open enum key: %#lx.\n", ret); + + token = wcstok_s(path + 4, separator, &context); /* skip \\?\ */ + while (token) + { + if (token[0] == L'{' && wcslen(token) == 38) break; /* reached GUID part, done */ + + i = 0; + while (!(ret = RegEnumKeyW(current_key, i++, key_name, ARRAY_SIZE(key_name)))) + { + if(!wcscmp(token, key_name)) + { + ret = RegOpenKeyW(current_key, token, &tmp); + ok(!ret, "Failed to open registry key %s: %#lx.\n", debugstr_w(token), ret); + RegCloseKey(current_key); + current_key = tmp; + break; + } + } + ok(!ret, "Failed to find %s in registry: %#lx.\n", debugstr_w(token), ret); + if (ret) break; + + token = wcstok_s(NULL, separator, &context); + } + + RegCloseKey(current_key); + free(path); +} + +static void test_CM_Get_Device_Interface_List(void) +{ + BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)]; + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data; + SP_DEVINFO_DATA device = { sizeof(device) }; + WCHAR instance_id[256], expected_id[256]; + unsigned int count, count2; + char *buffera, *pa; + WCHAR *buffer, *p; + ULONG size, size2; + DEVPROPTYPE type; + CONFIGRET ret; + HDEVINFO set; + GUID guid; + BOOL bret; + + guid = GUID_DEVINTERFACE_DISPLAY_ADAPTER; + + ret = CM_Get_Device_Interface_List_SizeW(&size, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + ok(!ret, "got %#lx.\n", ret); + + buffer = malloc(size * sizeof(*buffer)); + ret = CM_Get_Device_Interface_ListW( &guid, NULL, buffer, size, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + ok(!ret, "got %#lx.\n", ret); + + ret = CM_Get_Device_Interface_List_SizeA(&size2, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + ok(!ret, "got %#lx.\n", ret); + ok(size2 == size, "got %lu, %lu.\n", size, size2); + buffera = malloc(size2 * sizeof(*buffera)); + ret = CM_Get_Device_Interface_ListA(&guid, NULL, buffera, size2, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + ok(!ret, "got %#lx.\n", ret); + p = malloc(size2 * sizeof(*p)); + pa = buffera; + *p = 0; + while (*pa) + { + MultiByteToWideChar(CP_ACP, 0, pa, -1, p + (pa - buffera), size2 - (pa - buffera)); + pa += strlen(pa) + 1; + } + ok(!memcmp(p, buffer, size * sizeof(*p)), "results differ %s %s.\n", debugstr_w(p), debugstr_w(buffer)); + free(p); + free(buffera); + + iface_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)iface_detail_buffer; + + count = 0; + p = buffer; + while (*p) + { + check_device_path_casing(p); + set = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL); + ok(set != INVALID_HANDLE_VALUE, "got %p.\n", set); + bret = SetupDiOpenDeviceInterfaceW(set, p, 0, &iface); + ok(bret, "got error %lu.\n", GetLastError()); + memset(iface_detail_buffer, 0xcc, sizeof(iface_detail_buffer)); + iface_data->cbSize = sizeof(*iface_data); + bret = SetupDiGetDeviceInterfaceDetailW(set, &iface, iface_data, sizeof(iface_detail_buffer), NULL, &device); + ok(bret, "got error %lu.\n", GetLastError()); + ok(!wcsicmp(iface_data->DevicePath, p), "got %s, expected %s.\n", debugstr_w(p), debugstr_w(iface_data->DevicePath)); + bret = SetupDiGetDeviceInstanceIdW(set, &device, expected_id, ARRAY_SIZE(expected_id), NULL); + ok(bret, "got error %lu.\n", GetLastError()); + SetupDiDestroyDeviceInfoList(set); + + size = 0xdeadbeef; + type = 0xdeadbeef; + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, NULL, &size, 0); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ok(type == 0xdeadbeef, "got type %#lx.\n", type); + ok(size == 0xdeadbeef, "got %#lx.\n", size); + + size = 0; + type = 0xdeadbeef; + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, NULL, &size, 0); + ok(ret == CR_BUFFER_SMALL, "got %#lx.\n", ret); + ok(type == DEVPROP_TYPE_STRING, "got type %#lx.\n", type); + ok(size && size != 0xdeadbeef, "got %#lx.\n", size); + + ret = CM_Get_Device_Interface_PropertyW(p, NULL, &type, (BYTE *)instance_id, &size, 0); + ok(ret == CR_FAILURE, "got %#lx.\n", ret); + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, NULL, (BYTE *)instance_id, &size, 0); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ret = CM_Get_Device_Interface_PropertyW(NULL, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, NULL, 0); + ok(ret == CR_INVALID_POINTER, "got %#lx.\n", ret); + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 1); + ok(ret == CR_INVALID_FLAG, "got %#lx.\n", ret); + + size = 0; + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, NULL, &size, 0); + ok(ret == CR_BUFFER_SMALL, "got %#lx.\n", ret); + + --size; + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0); + ok(ret == CR_BUFFER_SMALL, "got %#lx.\n", ret); + + type = 0xdeadbeef; + ret = CM_Get_Device_Interface_PropertyW(p, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0); + ok(!ret, "got %#lx.\n", ret); + ok(type == DEVPROP_TYPE_STRING, "got type %#lx.\n", type); + ok(!wcsicmp(instance_id, expected_id), "got %s, expected %s.\n", debugstr_w(instance_id), debugstr_w(expected_id)); + p += wcslen(p) + 1; + ++count; + } + + free(buffer); + + set = SetupDiGetClassDevsW(&guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); + ok(set != INVALID_HANDLE_VALUE, "got %p.\n", set); + for (count2 = 0; SetupDiEnumDeviceInterfaces(set, NULL, &guid, count2, &iface); ++count2) + ; + SetupDiDestroyDeviceInfoList(set); + ok(count == count2, "got %u, expected %u.\n", count, count2); + + ret = CM_Get_Device_Interface_PropertyW(L"qqq", &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0); + ok(ret == CR_NO_SUCH_DEVICE_INTERFACE, "got %#lx.\n", ret); +} + START_TEST(cfgmgr32) { test_CM_MapCrToWin32Err(); + test_CM_Get_Device_ID_List(); + test_CM_Get_Device_Interface_List(); } diff --git a/dlls/cng.sys/cng.sys.spec b/dlls/cng.sys/cng.sys.spec index 0a2858579d2a..7d0efbe717fc 100644 --- a/dlls/cng.sys/cng.sys.spec +++ b/dlls/cng.sys/cng.sys.spec @@ -27,7 +27,7 @@ @ stdcall BCryptHashData(ptr ptr long long) bcrypt.BCryptHashData @ stdcall BCryptImportKey(ptr ptr wstr ptr ptr long ptr long long) bcrypt.BCryptImportKey @ stdcall BCryptImportKeyPair(ptr ptr wstr ptr ptr long long) bcrypt.BCryptImportKeyPair -@ stub BCryptKeyDerivation +@ stdcall BCryptKeyDerivation(ptr ptr ptr long ptr long) bcrypt.BCryptKeyDerivation @ stdcall BCryptOpenAlgorithmProvider(ptr wstr wstr long) bcrypt.BCryptOpenAlgorithmProvider @ stub BCryptProcessMultiOperations @ stub BCryptRegisterConfigChangeNotify diff --git a/dlls/combase/apartment.c b/dlls/combase/apartment.c index 85e06a6fd57f..ce1fc72ba1a0 100644 --- a/dlls/combase/apartment.c +++ b/dlls/combase/apartment.c @@ -719,7 +719,7 @@ static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst WCHAR src[MAX_PATH]; DWORD dwLength = dstlen * sizeof(WCHAR); - if ((ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS) + if ((ret = RegQueryValueExW(regdata->u.hkey, L"", NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS) { if (keytype == REG_EXPAND_SZ) { diff --git a/dlls/combase/roapi.c b/dlls/combase/roapi.c index 0f8a94388217..3f33cc1075cd 100644 --- a/dlls/combase/roapi.c +++ b/dlls/combase/roapi.c @@ -124,7 +124,7 @@ HRESULT WINAPI RoInitialize(RO_INIT_TYPE type) { switch (type) { case RO_INIT_SINGLETHREADED: - return CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + return CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); default: FIXME("type %d\n", type); case RO_INIT_MULTITHREADED: @@ -240,6 +240,7 @@ struct agile_reference IStream *marshal_stream; CRITICAL_SECTION cs; IUnknown *obj; + BOOLEAN is_agile; LONG ref; }; @@ -326,6 +327,9 @@ static HRESULT WINAPI agile_ref_Resolve(IAgileReference *iface, REFIID riid, voi TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), obj); + if (impl->is_agile) + return IUnknown_QueryInterface(impl->obj, riid, obj); + EnterCriticalSection(&impl->cs); if (impl->option == AGILEREFERENCE_DELAYEDMARSHAL && impl->marshal_stream == NULL) { @@ -354,6 +358,17 @@ static const IAgileReferenceVtbl agile_ref_vtbl = agile_ref_Resolve, }; +static BOOL object_has_interface(IUnknown *obj, REFIID iid) +{ + IUnknown *unk; + HRESULT hr; + + hr = IUnknown_QueryInterface(obj, iid, (void **)&unk); + if (SUCCEEDED(hr)) + IUnknown_Release(unk); + return SUCCEEDED(hr); +} + /*********************************************************************** * RoGetAgileReference (combase.@) */ @@ -361,7 +376,6 @@ HRESULT WINAPI RoGetAgileReference(enum AgileReferenceOptions option, REFIID rii IAgileReference **agile_reference) { struct agile_reference *impl; - IUnknown *unknown; HRESULT hr; TRACE("(%d, %s, %p, %p).\n", option, debugstr_guid(riid), obj, agile_reference); @@ -375,17 +389,10 @@ HRESULT WINAPI RoGetAgileReference(enum AgileReferenceOptions option, REFIID rii return CO_E_NOTINITIALIZED; } - hr = IUnknown_QueryInterface(obj, riid, (void **)&unknown); - if (FAILED(hr)) + if (!object_has_interface(obj, riid)) return E_NOINTERFACE; - IUnknown_Release(unknown); - - hr = IUnknown_QueryInterface(obj, &IID_INoMarshal, (void **)&unknown); - if (SUCCEEDED(hr)) - { - IUnknown_Release(unknown); + if (object_has_interface(obj, &IID_INoMarshal)) return CO_E_NOT_SUPPORTED; - } impl = calloc(1, sizeof(*impl)); if (!impl) @@ -393,9 +400,15 @@ HRESULT WINAPI RoGetAgileReference(enum AgileReferenceOptions option, REFIID rii impl->IAgileReference_iface.lpVtbl = &agile_ref_vtbl; impl->option = option; + impl->is_agile = object_has_interface(obj, &IID_IAgileObject); impl->ref = 1; - if (option == AGILEREFERENCE_DEFAULT) + if (option == AGILEREFERENCE_DELAYEDMARSHAL || impl->is_agile) + { + impl->obj = obj; + IUnknown_AddRef(impl->obj); + } + else if (option == AGILEREFERENCE_DEFAULT) { if (FAILED(hr = marshal_object_in_agile_reference(impl, riid, obj))) { @@ -403,11 +416,6 @@ HRESULT WINAPI RoGetAgileReference(enum AgileReferenceOptions option, REFIID rii return hr; } } - else if (option == AGILEREFERENCE_DELAYEDMARSHAL) - { - impl->obj = obj; - IUnknown_AddRef(impl->obj); - } InitializeCriticalSection(&impl->cs); diff --git a/dlls/combase/tests/roapi.c b/dlls/combase/tests/roapi.c index 7606c61c1659..923e330e68e7 100644 --- a/dlls/combase/tests/roapi.c +++ b/dlls/combase/tests/roapi.c @@ -22,6 +22,7 @@ #include "winbase.h" #include "winerror.h" #include "winstring.h" +#include "winternl.h" #include "initguid.h" #include "roapi.h" @@ -211,6 +212,28 @@ static DWORD WINAPI mta_init_implicit_thread(void *dummy) return 0; } +enum oletlsflags +{ + OLETLS_UUIDINITIALIZED = 0x2, + OLETLS_DISABLE_OLE1DDE = 0x40, + OLETLS_APARTMENTTHREADED = 0x80, + OLETLS_MULTITHREADED = 0x100, +}; + +struct oletlsdata +{ + void *threadbase; + void *smallocator; + DWORD id; + DWORD flags; +}; + +static DWORD get_oletlsflags(void) +{ + struct oletlsdata *data = NtCurrentTeb()->ReservedForOle; + return data ? data->flags : 0; +} + static void test_implicit_mta(void) { static const struct @@ -246,7 +269,14 @@ static void test_implicit_mta(void) { winetest_push_context("test %u", i); if (tests[i].ro_init) + { + DWORD flags = tests[i].mta ? OLETLS_MULTITHREADED : OLETLS_APARTMENTTHREADED; + hr = RoInitialize(tests[i].mta ? RO_INIT_MULTITHREADED : RO_INIT_SINGLETHREADED); + + flags |= OLETLS_DISABLE_OLE1DDE; + ok((get_oletlsflags() & flags) == flags, "get_oletlsflags() = %lx\n", get_oletlsflags()); + } else hr = CoInitializeEx(NULL, tests[i].mta ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED); ok(hr == S_OK, "got %#lx.\n", hr); @@ -373,6 +403,19 @@ static HRESULT WINAPI unk_no_marshal_QueryInterface(IUnknown *iface, REFIID riid return E_NOINTERFACE; } +static HRESULT WINAPI unk_agile_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IAgileObject)) + { + *ppv = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + return E_NOINTERFACE; +} + static ULONG WINAPI unk_AddRef(IUnknown *iface) { struct unk_impl *impl = impl_from_IUnknown(iface); @@ -399,6 +442,13 @@ static const IUnknownVtbl unk_no_marshal_vtbl = unk_Release }; +static const IUnknownVtbl unk_agile_vtbl = +{ + unk_agile_QueryInterface, + unk_AddRef, + unk_Release +}; + struct test_RoGetAgileReference_thread_param { enum AgileReferenceOptions option; @@ -406,6 +456,7 @@ struct test_RoGetAgileReference_thread_param RO_INIT_TYPE to_type; IAgileReference *agile_reference; IUnknown *unk_obj; + BOOLEAN obj_is_agile; }; static DWORD CALLBACK test_RoGetAgileReference_thread_proc(void *arg) @@ -422,7 +473,12 @@ static DWORD CALLBACK test_RoGetAgileReference_thread_proc(void *arg) hr = IAgileReference_Resolve(param->agile_reference, &IID_IUnknown, (void **)&unknown); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); ok(!!unknown, "Expected pointer not NULL.\n"); - if (param->from_type == RO_INIT_MULTITHREADED && param->to_type == RO_INIT_MULTITHREADED) + if (param->obj_is_agile) + { + ok(unknown == param->unk_obj, "Expected the same object.\n"); + EXPECT_REF(param->unk_obj, 4); + } + else if (param->from_type == RO_INIT_MULTITHREADED && param->to_type == RO_INIT_MULTITHREADED) { ok(unknown == param->unk_obj, "Expected the same object.\n"); todo_wine_if(param->option == AGILEREFERENCE_DEFAULT) @@ -447,6 +503,7 @@ static void test_RoGetAgileReference(void) struct test_RoGetAgileReference_thread_param param; struct unk_impl unk_no_marshal_obj = {{&unk_no_marshal_vtbl}, 1}; struct unk_impl unk_obj = {{&unk_vtbl}, 1}; + struct unk_impl unk_agile_obj = {{&unk_agile_vtbl}, 1}; enum AgileReferenceOptions option; IAgileReference *agile_reference; RO_INIT_TYPE from_type, to_type; @@ -520,6 +577,7 @@ static void test_RoGetAgileReference(void) param.to_type = to_type; param.agile_reference = agile_reference; param.unk_obj = &unk_obj.IUnknown_iface; + param.obj_is_agile = FALSE; thread = CreateThread(NULL, 0, test_RoGetAgileReference_thread_proc, ¶m, 0, NULL); flush_events(); ret = WaitForSingleObject(thread, 100); @@ -531,6 +589,36 @@ static void test_RoGetAgileReference(void) IAgileReference_Release(agile_reference); EXPECT_REF(&unk_obj, 1); + hr = RoGetAgileReference(option, &IID_IUnknown, &unk_agile_obj.IUnknown_iface, &agile_reference); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!!agile_reference, "Got unexpected agile_reference.\n"); + EXPECT_REF(&unk_agile_obj, 2); + + unknown = NULL; + hr = IAgileReference_Resolve(agile_reference, &IID_IUnknown, (void **)&unknown); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!!unknown, "Expected pointer not NULL.\n"); + ok(unknown == &unk_agile_obj.IUnknown_iface, "Expected the same object.\n"); + EXPECT_REF(&unk_agile_obj, 3); + + for (to_type = RO_INIT_SINGLETHREADED; to_type <= RO_INIT_MULTITHREADED; to_type++) + { + param.option = option; + param.from_type = from_type; + param.to_type = to_type; + param.agile_reference = agile_reference; + param.unk_obj = &unk_agile_obj.IUnknown_iface; + param.obj_is_agile = TRUE; + thread = CreateThread(NULL, 0, test_RoGetAgileReference_thread_proc, ¶m, 0, NULL); + flush_events(); + ret = WaitForSingleObject(thread, 100); + ok(!ret, "WaitForSingleObject failed, error %ld.\n", GetLastError()); + } + + IUnknown_Release(unknown); + IAgileReference_Release(agile_reference); + EXPECT_REF(&unk_obj, 1); + RoUninitialize(); winetest_pop_context(); } diff --git a/dlls/comctl32/Makefile.in b/dlls/comctl32/Makefile.in index 8e9a6e44577c..954572964f56 100644 --- a/dlls/comctl32/Makefile.in +++ b/dlls/comctl32/Makefile.in @@ -1,7 +1,7 @@ EXTRADEFS = -D_COMCTL32_ MODULE = comctl32.dll IMPORTLIB = comctl32 -IMPORTS = uuid user32 gdi32 advapi32 imm32 kernelbase +IMPORTS = uuid user32 gdi32 advapi32 imm32 kernelbase oleacc oleaut32 DELAYIMPORTS = winmm uxtheme SOURCES = \ diff --git a/dlls/comctl32/combo.c b/dlls/comctl32/combo.c index 09579952f225..dfa2e1e60fdc 100644 --- a/dlls/comctl32/combo.c +++ b/dlls/comctl32/combo.c @@ -1439,7 +1439,8 @@ static void COMBO_Size( HEADCOMBO *lphc ) static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, BOOL bRedraw ) { lphc->hFont = hFont; - lphc->item_height = combo_get_text_height(lphc); + if (!CB_OWNERDRAWN(lphc)) + lphc->item_height = combo_get_text_height(lphc); /* * Propagate to owned windows. diff --git a/dlls/comctl32/syslink.c b/dlls/comctl32/syslink.c index f5a70e982c3f..0880c0da5279 100644 --- a/dlls/comctl32/syslink.c +++ b/dlls/comctl32/syslink.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define COBJMACROS #include #include #include "windef.h" @@ -27,6 +28,9 @@ #include "winnls.h" #include "commctrl.h" #include "comctl32.h" +#include "oaidl.h" +#include "initguid.h" +#include "oleacc.h" #include "wine/debug.h" #include "wine/list.h" @@ -70,7 +74,17 @@ typedef struct _DOC_ITEM WCHAR Text[1]; /* Text of the document item */ } DOC_ITEM, *PDOC_ITEM; +typedef struct SYSLINK_INFO SYSLINK_INFO; + typedef struct +{ + IAccessible IAccessible_iface; + IOleWindow IOleWindow_iface; + struct SYSLINK_INFO *infoPtr; + LONG refcount; +} SYSLINK_ACC; + +struct SYSLINK_INFO { HWND Self; /* The window handle for this control */ HWND Notify; /* The parent handle to receive notifications */ @@ -85,7 +99,8 @@ typedef struct COLORREF VisitedColor; /* Color of visited links */ WCHAR BreakChar; /* Break Character for the current font */ BOOL IgnoreReturn; /* (infoPtr->Style & LWS_IGNORERETURN) on creation */ -} SYSLINK_INFO; + SYSLINK_ACC *AccessibleImpl; /* IAccessible implementation */ +}; /* Control configuration constants */ @@ -94,6 +109,557 @@ typedef struct #define SL_RIGHTMARGIN (0) #define SL_BOTTOMMARGIN (0) +static inline SYSLINK_ACC *impl_from_IAccessible(IAccessible *iface) +{ + return CONTAINING_RECORD(iface, SYSLINK_ACC, IAccessible_iface); +} + +static inline SYSLINK_ACC *impl_from_IOleWindow(IOleWindow *iface) +{ + return CONTAINING_RECORD(iface, SYSLINK_ACC, IOleWindow_iface); +} + +static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID iid, void **ppv) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IAccessible, iid)) + { + *ppv = &This->IAccessible_iface; + } + else if (IsEqualIID(&IID_IOleWindow, iid)) + { + *ppv = &This->IOleWindow_iface; + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI Accessible_AddRef(IAccessible *iface) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + return InterlockedIncrement(&This->refcount); +} + +static ULONG WINAPI Accessible_Release(IAccessible *iface) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + ULONG ref = InterlockedDecrement(&This->refcount); + + if (ref == 0) + Free(This); + + return ref; +} + +static HRESULT WINAPI Accessible_GetTypeInfo(IAccessible *iface, UINT index, LCID lcid, ITypeInfo **info) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_GetIDsOfNames(IAccessible *iface, REFIID iid, LPOLESTR *names, UINT count, LCID lcid, DISPID *dispid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_Invoke(IAccessible *iface, DISPID dispid, REFIID iid, LCID lcid, + WORD flags, DISPPARAMS *dispparams, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_GetTypeInfoCount(IAccessible *iface, UINT *count) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT Accessible_FindChild(SYSLINK_ACC *This, VARIANT childid, DOC_ITEM** result) +{ + DOC_ITEM *current; + int index; + + if (!This->infoPtr) + { + WARN("control was destroyed\n"); + return E_FAIL; + } + + if (V_VT(&childid) == VT_EMPTY) + index = 0; + else if (V_VT(&childid) == VT_I4) + index = V_I4(&childid); + else { + WARN("not implemented for vt %s\n", debugstr_vt(V_VT(&childid))); + return E_INVALIDARG; + } + + if (index == 0) + { + *result = NULL; + return S_OK; + } + + LIST_FOR_EACH_ENTRY(current, &This->infoPtr->Items, DOC_ITEM, entry) + { + if (current->Type != slLink) + continue; + if (!--index) + { + *result = current; + return S_OK; + } + } + + WARN("index out of range\n"); + return E_INVALIDARG; +} + +static HRESULT WINAPI Accessible_get_accParent(IAccessible *iface, IDispatch** disp) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accChildCount(IAccessible *iface, LONG *count) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + DOC_ITEM *current; + LONG result = 0; + + TRACE("%p\n", iface); + + if (!This->infoPtr) + { + WARN("control was destroyed\n"); + return E_FAIL; + } + + LIST_FOR_EACH_ENTRY(current, &This->infoPtr->Items, DOC_ITEM, entry) + { + if (current->Type == slLink) + result++; + } + + *count = result; + + return S_OK; +} + +static HRESULT WINAPI Accessible_get_accChild(IAccessible *iface, VARIANT childid, IDispatch **disp) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + HRESULT hr; + DOC_ITEM* item; + + TRACE("%p, %s\n", iface, debugstr_variant(&childid)); + + *disp = NULL; + + hr = Accessible_FindChild(This, childid, &item); + if (FAILED(hr)) + return hr; + + if (item) + return S_FALSE; + else + return E_INVALIDARG; +} + +static HRESULT WINAPI Accessible_get_accName(IAccessible *iface, VARIANT childid, BSTR *name) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + HRESULT hr; + DOC_ITEM* item; + BSTR result; + + TRACE("%p, %s\n", iface, debugstr_variant(&childid)); + + if (!name) + return E_POINTER; + + *name = NULL; + + hr = Accessible_FindChild(This, childid, &item); + if (FAILED(hr)) + return hr; + + if (item) + { + result = SysAllocString(item->Text); + if (!result) + return E_OUTOFMEMORY; + } + else + { + UINT total_length = 0, i; + + LIST_FOR_EACH_ENTRY(item, &This->infoPtr->Items, DOC_ITEM, entry) + { + total_length += item->nText; + } + + result = SysAllocStringLen(NULL, total_length); + if (!result) + return E_OUTOFMEMORY; + + i = 0; + LIST_FOR_EACH_ENTRY(item, &This->infoPtr->Items, DOC_ITEM, entry) + { + memcpy(&result[i], item->Text, item->nText * sizeof(*result)); + i += item->nText; + } + } + + *name = result; + + return S_OK; +} + +static HRESULT WINAPI Accessible_get_accValue(IAccessible *iface, VARIANT childid, BSTR *value) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accDescription(IAccessible *iface, VARIANT childid, BSTR *description) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accRole(IAccessible *iface, VARIANT childid, VARIANT *role) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + HRESULT hr; + DOC_ITEM* item; + + TRACE("%p, %s\n", iface, debugstr_variant(&childid)); + + hr = Accessible_FindChild(This, childid, &item); + if (FAILED(hr)) + return hr; + + V_VT(role) = VT_I4; + + if (item) + V_I4(role) = ROLE_SYSTEM_LINK; + else + V_I4(role) = ROLE_SYSTEM_CLIENT; + + return S_OK; +} + +static HRESULT WINAPI Accessible_get_accState(IAccessible *iface, VARIANT childid, VARIANT *state) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + HRESULT hr; + DOC_ITEM* item; + GUITHREADINFO info; + BOOL focused = 0; + + TRACE("%p, %s\n", iface, debugstr_variant(&childid)); + + hr = Accessible_FindChild(This, childid, &item); + if (FAILED(hr)) + return hr; + + V_VT(state) = VT_I4; + V_I4(state) = 0; + + info.cbSize = sizeof(info); + if(GetGUIThreadInfo(0, &info) && info.hwndFocus == This->infoPtr->Self) + focused = 1; + + if (item) + { + V_I4(state) |= STATE_SYSTEM_FOCUSABLE|STATE_SYSTEM_LINKED; + if (focused && (item->u.Link.state & LIS_FOCUSED) == LIS_FOCUSED) + V_I4(state) |= STATE_SYSTEM_FOCUSED; + } + else + { + LONG style = GetWindowLongW(This->infoPtr->Self, GWL_STYLE); + + if (style & WS_DISABLED) + V_I4(state) |= STATE_SYSTEM_UNAVAILABLE; + else + V_I4(state) |= STATE_SYSTEM_FOCUSABLE; + if (!(style & WS_VISIBLE)) + V_I4(state) |= STATE_SYSTEM_INVISIBLE; + if (focused) + V_I4(state) |= STATE_SYSTEM_FOCUSED; + } + + return S_OK; +} + +static HRESULT WINAPI Accessible_get_accHelp(IAccessible *iface, VARIANT childid, BSTR *help) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accHelpTopic(IAccessible *iface, BSTR *helpFile, VARIANT childid, LONG *topic) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accKeyboardShortcut(IAccessible *iface, VARIANT childid, BSTR *shortcut) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accFocus(IAccessible *iface, VARIANT *childid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accSelection(IAccessible *iface, VARIANT *childid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accDefaultAction(IAccessible *iface, VARIANT childid, BSTR *action) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + HRESULT hr; + DOC_ITEM* item; + + TRACE("%p, %s\n", iface, debugstr_variant(&childid)); + + if (!action) + return E_POINTER; + + *action = NULL; + + hr = Accessible_FindChild(This, childid, &item); + if (FAILED(hr)) + return hr; + + if (item) + { + *action = SysAllocString(L"Click"); + if (!*action) + return E_OUTOFMEMORY; + return S_OK; + } + else + { + return S_FALSE; + } +} + +static HRESULT WINAPI Accessible_accSelect(IAccessible *iface, LONG flags, VARIANT childid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_accLocation(IAccessible *iface, LONG *left, LONG *top, LONG *width, LONG *height, VARIANT childid) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + HRESULT hr; + DOC_ITEM* item; + RECT rc = {0}; + POINT point; + + TRACE("%p, %s\n", iface, debugstr_variant(&childid)); + + hr = Accessible_FindChild(This, childid, &item); + if (FAILED(hr)) + return hr; + + if (item) + { + int n = item->nText; + PDOC_TEXTBLOCK block = item->Blocks; + + while (n > 0) + { + UnionRect(&rc, &rc, &block->rc); + n -= block->nChars + block->nSkip; + block++; + } + } + else + { + GetClientRect(This->infoPtr->Self, &rc); + } + + point.x = rc.left; + point.y = rc.top; + MapWindowPoints(This->infoPtr->Self, NULL, &point, 1); + *left = point.x; + *top = point.y; + *width = rc.right - rc.left; + *height = rc.bottom - rc.top; + + TRACE("<-- (%li,%li,%li,%li)\n", *left, *top, *width, *height); + + return S_OK; +} + +static HRESULT WINAPI Accessible_accNavigate(IAccessible *iface, LONG dir, VARIANT start, VARIANT *end) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_accHitTest(IAccessible *iface, LONG left, LONG top, VARIANT* childid) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static LRESULT SYSLINK_SendParentNotify (const SYSLINK_INFO *infoPtr, UINT code, const DOC_ITEM *Link, int iLink); + +static HRESULT WINAPI Accessible_accDoDefaultAction(IAccessible *iface, VARIANT childid) +{ + SYSLINK_ACC *This = impl_from_IAccessible(iface); + HRESULT hr; + DOC_ITEM* item; + + TRACE("%p, %s\n", iface, debugstr_variant(&childid)); + + hr = Accessible_FindChild(This, childid, &item); + if (FAILED(hr)) + return hr; + + if (!item) + /* Not supported for whole control. */ + return E_INVALIDARG; + + SYSLINK_SendParentNotify(This->infoPtr, NM_CLICK, item, V_I4(&childid) - 1); + + return S_OK; +} + +static HRESULT WINAPI Accessible_put_accName(IAccessible *iface, VARIANT childid, BSTR name) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_put_accValue(IAccessible *iface, VARIANT childid, BSTR value) +{ + FIXME("%p\n", iface); + return E_NOTIMPL; +} + +static const IAccessibleVtbl Accessible_Vtbl = { + Accessible_QueryInterface, + Accessible_AddRef, + Accessible_Release, + Accessible_GetTypeInfoCount, + Accessible_GetTypeInfo, + Accessible_GetIDsOfNames, + Accessible_Invoke, + Accessible_get_accParent, + Accessible_get_accChildCount, + Accessible_get_accChild, + Accessible_get_accName, + Accessible_get_accValue, + Accessible_get_accDescription, + Accessible_get_accRole, + Accessible_get_accState, + Accessible_get_accHelp, + Accessible_get_accHelpTopic, + Accessible_get_accKeyboardShortcut, + Accessible_get_accFocus, + Accessible_get_accSelection, + Accessible_get_accDefaultAction, + Accessible_accSelect, + Accessible_accLocation, + Accessible_accNavigate, + Accessible_accHitTest, + Accessible_accDoDefaultAction, + Accessible_put_accName, + Accessible_put_accValue +}; + +static HRESULT WINAPI Accessible_Window_QueryInterface(IOleWindow *iface, REFIID iid, void **ppv) +{ + SYSLINK_ACC *This = impl_from_IOleWindow(iface); + return IAccessible_QueryInterface(&This->IAccessible_iface, iid, ppv); +} + +static ULONG WINAPI Accessible_Window_AddRef(IOleWindow *iface) +{ + SYSLINK_ACC *This = impl_from_IOleWindow(iface); + return IAccessible_AddRef(&This->IAccessible_iface); +} + +static ULONG WINAPI Accessible_Window_Release(IOleWindow *iface) +{ + SYSLINK_ACC *This = impl_from_IOleWindow(iface); + return IAccessible_Release(&This->IAccessible_iface); +} + +static HRESULT WINAPI Accessible_GetWindow(IOleWindow *iface, HWND *hwnd) +{ + SYSLINK_ACC *This = impl_from_IOleWindow(iface); + + TRACE("%p\n", This); + + if (!This->infoPtr) + return E_FAIL; + + *hwnd = This->infoPtr->Self; + return S_OK; +} + +static HRESULT WINAPI Accessible_ContextSensitiveHelp(IOleWindow *This, BOOL fEnterMode) +{ + FIXME("%p\b", This); + return E_NOTIMPL; +} + +static const IOleWindowVtbl Accessible_Window_Vtbl = { + Accessible_Window_QueryInterface, + Accessible_Window_AddRef, + Accessible_Window_Release, + Accessible_GetWindow, + Accessible_ContextSensitiveHelp +}; + +static void Accessible_Create(SYSLINK_INFO* infoPtr) +{ + SYSLINK_ACC *This; + + This = Alloc(sizeof(*This)); + if (!This) return; + + This->IAccessible_iface.lpVtbl = &Accessible_Vtbl; + This->IOleWindow_iface.lpVtbl = &Accessible_Window_Vtbl; + This->infoPtr = infoPtr; + This->refcount = 1; + infoPtr->AccessibleImpl = This; +} + +static void Accessible_WindowDestroyed(SYSLINK_ACC *This) +{ + This->infoPtr = NULL; + IAccessible_Release(&This->IAccessible_iface); +} + /*********************************************************************** * SYSLINK_FreeDocItem * Frees all data and gdi objects associated with a document item @@ -1713,9 +2279,22 @@ static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message, SYSLINK_ClearDoc(infoPtr); if(infoPtr->LinkFont != 0) DeleteObject(infoPtr->LinkFont); SetWindowLongPtrW(hwnd, 0, 0); + if(infoPtr->AccessibleImpl) Accessible_WindowDestroyed(infoPtr->AccessibleImpl); Free (infoPtr); return 0; + case WM_GETOBJECT: + { + if ((DWORD)lParam == (DWORD)OBJID_CLIENT) { + if (!infoPtr->AccessibleImpl) + Accessible_Create(infoPtr); + + if (infoPtr->AccessibleImpl) + return LresultFromObject(&IID_IAccessible, wParam, (IUnknown*)&infoPtr->AccessibleImpl->IAccessible_iface); + } + return DefWindowProcW(hwnd, message, wParam, lParam); + } + case WM_SYSCOLORCHANGE: COMCTL32_RefreshSysColors(); return 0; diff --git a/dlls/comctl32/tests/Makefile.in b/dlls/comctl32/tests/Makefile.in index 0c96203a2f6a..ee7fe6527fef 100644 --- a/dlls/comctl32/tests/Makefile.in +++ b/dlls/comctl32/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = comctl32.dll -IMPORTS = ole32 user32 gdi32 advapi32 imm32 uxtheme +IMPORTS = ole32 user32 gdi32 advapi32 imm32 uxtheme oleacc oleaut32 SOURCES = \ animate.c \ diff --git a/dlls/comctl32/tests/combo.c b/dlls/comctl32/tests/combo.c index 0ba720a03cea..5af530ad5be4 100644 --- a/dlls/comctl32/tests/combo.c +++ b/dlls/comctl32/tests/combo.c @@ -743,17 +743,20 @@ static void test_combo_setitemheight(DWORD style) static void test_combo_setfont(DWORD style) { + unsigned int expected_height, initial_height; HFONT hFont1, hFont2; HWND hCombo; RECT r; int i; + winetest_push_context("style %#lx", style); hCombo = create_combobox(style); hFont1 = CreateFontA(10, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); hFont2 = CreateFontA(8, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Marlett"); GetClientRect(hCombo, &r); - expect_rect(r, 0, 0, 100, get_font_height(GetStockObject(SYSTEM_FONT)) + 8); + initial_height = get_font_height(GetStockObject(SYSTEM_FONT)) + 8; + expect_rect(r, 0, 0, 100, initial_height); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); todo_wine expect_rect(r, 5, 5, 105, 105); @@ -766,24 +769,50 @@ static void test_combo_setfont(DWORD style) { SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE); GetClientRect(hCombo, &r); - expect_rect(r, 0, 0, 100, 18); + expected_height = style & CBS_OWNERDRAWFIXED ? initial_height : 18; + expect_rect(r, 0, 0, 100, expected_height); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); - todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont1))); + + if (style & CBS_OWNERDRAWFIXED) + { + todo_wine expect_rect(r, 5, 5, 105, 105); + } + else + { + todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont1))); + } SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont2, FALSE); GetClientRect(hCombo, &r); - expect_rect(r, 0, 0, 100, 16); + expected_height = style & CBS_OWNERDRAWFIXED ? initial_height : 16; + expect_rect(r, 0, 0, 100, expected_height); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); - todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont2))); + + if (style & CBS_OWNERDRAWFIXED) + { + todo_wine expect_rect(r, 5, 5, 105, 105); + } + else + { + todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont2))); + } SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont1, FALSE); GetClientRect(hCombo, &r); - expect_rect(r, 0, 0, 100, 18); + expected_height = style & CBS_OWNERDRAWFIXED ? initial_height : 18; + expect_rect(r, 0, 0, 100, expected_height); SendMessageA(hCombo, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&r); MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); - todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont1))); + if (style & CBS_OWNERDRAWFIXED) + { + todo_wine expect_rect(r, 5, 5, 105, 105); + } + else + { + todo_wine expect_rect(r, 5, 5, 105, 105 - (get_font_height(GetStockObject(SYSTEM_FONT)) - get_font_height(hFont1))); + } } else { @@ -798,7 +827,12 @@ static void test_combo_setfont(DWORD style) SendMessageA(hCombo, WM_SETFONT, (WPARAM)hFont, FALSE); GetClientRect(hCombo, &r); - ok((r.bottom - r.top) == (height + 8), "Unexpected client rect height.\n"); + if (style & CBS_OWNERDRAWFIXED) + expected_height = initial_height; + else + expected_height = (height + 8); + ok((r.bottom - r.top) == expected_height, "Unexpected client rect height %ld, expected %d.\n", r.bottom - r.top, + expected_height); SendMessageA(hCombo, WM_SETFONT, 0, FALSE); DeleteObject(hFont); } @@ -806,6 +840,7 @@ static void test_combo_setfont(DWORD style) DestroyWindow(hCombo); DeleteObject(hFont1); DeleteObject(hFont2); + winetest_pop_context(); } static LRESULT (CALLBACK *old_parent_proc)(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); @@ -1691,6 +1726,7 @@ START_TEST(combo) test_combo_WS_VSCROLL(); test_combo_setfont(CBS_DROPDOWN); test_combo_setfont(CBS_DROPDOWNLIST); + test_combo_setfont(CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED); test_combo_setitemheight(CBS_DROPDOWN); test_combo_setitemheight(CBS_DROPDOWNLIST); test_combo_CBN_SELCHANGE(); diff --git a/dlls/comctl32/tests/syslink.c b/dlls/comctl32/tests/syslink.c index f6c31d929817..71b87e7b6b5f 100644 --- a/dlls/comctl32/tests/syslink.c +++ b/dlls/comctl32/tests/syslink.c @@ -17,9 +17,13 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define COBJMACROS #include #include +#include +#include + #include "wine/test.h" #include "v6util.h" #include "msg.h" @@ -34,7 +38,46 @@ static int g_link_id; static struct msg_sequence *sequences[NUM_MSG_SEQUENCE]; -static const struct message empty_wnd_seq[] = { +static void CALLBACK msg_winevent_proc(HWINEVENTHOOK hevent, + DWORD event, + HWND hwnd, + LONG object_id, + LONG child_id, + DWORD thread_id, + DWORD event_time) +{ + struct message msg = {0}; + WCHAR class_name[256]; + + /* ignore events not from a syslink control */ + if (!GetClassNameW(hwnd, class_name, ARRAY_SIZE(class_name)) || + wcscmp(class_name, WC_LINK) != 0) + return; + + msg.message = event; + msg.flags = winevent_hook|wparam|lparam; + msg.wParam = object_id; + msg.lParam = child_id; + add_message(sequences, SYSLINK_SEQ_INDEX, &msg); +} + +static void init_winevent_hook(void) { + hwineventhook = SetWinEventHook(EVENT_MIN, EVENT_MAX, GetModuleHandleA(0), msg_winevent_proc, + 0, GetCurrentThreadId(), WINEVENT_INCONTEXT); + if (!hwineventhook) + win_skip( "no win event hook support\n" ); +} + +static void uninit_winevent_hook(void) { + if (!hwineventhook) + return; + + UnhookWinEvent(hwineventhook); + hwineventhook = 0; +} + +static const struct message create_syslink_wnd_seq[] = { + { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, CHILDID_SELF }, {0} }; @@ -60,6 +103,20 @@ static const struct message parent_visible_syslink_wnd_seq[] = { {0} }; +static const struct message settext_syslink_wnd_seq[] = { + { WM_SETTEXT, sent }, + { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_WINDOW, CHILDID_SELF }, + { WM_PAINT, sent }, + { WM_ERASEBKGND, sent|defwinproc|optional }, /* Wine only */ + {0} +}; + +static const struct message parent_settext_syslink_wnd_seq[] = { + { WM_CTLCOLORSTATIC, sent }, + { WM_NOTIFY, sent|wparam|lparam|optional, 0, NM_CUSTOMDRAW }, /* FIXME: Not sent on Wine */ + {0} +}; + /* Try to make sure pending X events have been processed before continuing */ static void flush_events(void) { @@ -97,6 +154,8 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; + if (message == WM_NOTIFY && lParam) + msg.lParam = ((NMHDR*)lParam)->code; add_message(sequences, PARENT_SEQ_INDEX, &msg); } @@ -195,15 +254,24 @@ static void test_create_syslink(void) { HWND hWndSysLink; LONG oldstyle; + LRESULT ret; + LITEM item; /* Create an invisible SysLink control */ flush_sequences(sequences, NUM_MSG_SEQUENCE); hWndSysLink = create_syslink(WS_CHILD | WS_TABSTOP, hWndParent); ok(hWndSysLink != NULL, "Expected non NULL value (le %lu)\n", GetLastError()); flush_events(); - ok_sequence(sequences, SYSLINK_SEQ_INDEX, empty_wnd_seq, "create SysLink", FALSE); + ok_sequence(sequences, SYSLINK_SEQ_INDEX, create_syslink_wnd_seq, "create SysLink", FALSE); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_create_syslink_wnd_seq, "create SysLink (parent)", TRUE); + /* Get first item */ + item.mask = LIF_ITEMINDEX|LIF_ITEMID|LIF_URL; + item.iLink = 0; + ret = SendMessageW(hWndSysLink, LM_GETITEM, 0, (LPARAM)&item); + ok(ret == 1, "LM_GETITEM failed\n"); + ok(!wcscmp(item.szUrl, L"link1"), "unexpected url %s\n", debugstr_w(item.szUrl)); + /* Make the SysLink control visible */ flush_sequences(sequences, NUM_MSG_SEQUENCE); oldstyle = GetWindowLongA(hWndSysLink, GWL_STYLE); @@ -213,6 +281,20 @@ static void test_create_syslink(void) ok_sequence(sequences, SYSLINK_SEQ_INDEX, visible_syslink_wnd_seq, "visible SysLink", TRUE); ok_sequence(sequences, PARENT_SEQ_INDEX, parent_visible_syslink_wnd_seq, "visible SysLink (parent)", TRUE); + /* Change contents */ + flush_sequences(sequences, NUM_MSG_SEQUENCE); + SetWindowTextW(hWndSysLink, L"Head link Tail"); + flush_events(); + ok_sequence(sequences, SYSLINK_SEQ_INDEX, settext_syslink_wnd_seq, "SetWindowText", FALSE); + ok_sequence(sequences, PARENT_SEQ_INDEX, parent_settext_syslink_wnd_seq, "SetWindowText (parent)", FALSE); + + /* Get first item */ + item.mask = LIF_ITEMINDEX|LIF_ITEMID|LIF_URL; + item.iLink = 0; + ret = SendMessageW(hWndSysLink, LM_GETITEM, 0, (LPARAM)&item); + ok(ret == 1, "LM_GETITEM failed\n"); + ok(!wcscmp(item.szUrl, L"link"), "unexpected url %s\n", debugstr_w(item.szUrl)); + DestroyWindow(hWndSysLink); } @@ -275,6 +357,213 @@ static void test_link_id(void) DestroyWindow(hwnd); } +static void wait_link_click(DWORD timeout) +{ + DWORD start_time = GetTickCount(); + DWORD time_waited; + + if (g_link_id == -1) + flush_events(); + + while (g_link_id == -1 && (time_waited = GetTickCount() - start_time) < timeout) + { + MsgWaitForMultipleObjects(0, NULL, FALSE, timeout - time_waited, QS_ALLEVENTS); + flush_events(); + } +} + +static void test_msaa(void) +{ + HWND hwnd, ret_hwnd; + HRESULT hr; + LRESULT lr; + IAccessible *acc; + VARIANT varChild, varResult; + BSTR name; + LONG left, top, width, height, hwnd_left, hwnd_top, count=0; + IDispatch *child; + IOleWindow *ole_window; + + hwnd = create_syslink(WS_CHILD | WS_TABSTOP | WS_VISIBLE, hWndParent); + ok(hwnd != NULL, "Failed to create SysLink window.\n"); + + lr = SendMessageA(hwnd, WM_GETOBJECT, 0, OBJID_CLIENT); + ok(lr != 0, "No IAccessible object\n"); + if (lr == 0) + { + DestroyWindow(hwnd); + return; + } + + hr = ObjectFromLresult(lr, &IID_IAccessible, 0, (void**)&acc); + ok(hr == S_OK, "ObjectFromLresult failed, hr=%lx", hr); + + VariantInit(&varChild); + VariantInit(&varResult); + + V_VT(&varChild) = VT_I4; + V_I4(&varChild) = CHILDID_SELF; + + hr = IAccessible_get_accRole(acc, varChild, &varResult); + ok(hr == S_OK, "accRole failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accRole returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == ROLE_SYSTEM_CLIENT, "accRole returned %li\n", V_I4(&varResult)); + + VariantClear(&varResult); + hr = IAccessible_get_accState(acc, varChild, &varResult); + ok(hr == S_OK, "accState failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accState returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == STATE_SYSTEM_FOCUSABLE, "accState returned %li\n", V_I4(&varResult)); + + hr = IAccessible_get_accName(acc, varChild, &name); + ok(hr == S_OK, "accName failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) { + ok(!!name && !wcscmp(name, L"Head Name1 Middle Name2 Tail"), + "unexpected name %s\n", debugstr_w(name)); + SysFreeString(name); + } + + hr = IAccessible_get_accDefaultAction(acc, varChild, &name); + ok(hr == S_FALSE, "accDefaultAction failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) + ok(!name, "unexpected default action %s\n", debugstr_w(name)); + + hr = IAccessible_accDoDefaultAction(acc, varChild); + ok(hr == E_INVALIDARG, "accDoDefaultAction should fail, hr=%lx\n", hr); + + hr = IAccessible_accLocation(acc, &left, &top, &width, &height, varChild); + ok(hr == S_OK, "accLocation failed, hr=%lx\n", hr); + hwnd_left = left; + hwnd_top = top; + + hr = IAccessible_get_accChildCount(acc, &count); + ok(hr == S_OK, "accChildCount failed, hr=%lx\n", hr); + ok(count == 2, "accChildCount returned %li\n", count); + + /* child 1 */ + V_I4(&varChild) = 1; + hr = IAccessible_get_accChild(acc, varChild, &child); + ok(hr == S_FALSE, "accChild hr=%lx\n", hr); + ok(!child, "accChild returned IDispatch\n"); + + hr = IAccessible_get_accRole(acc, varChild, &varResult); + ok(hr == S_OK, "accRole failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accRole returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == ROLE_SYSTEM_LINK, "accRole returned %li\n", V_I4(&varResult)); + + VariantClear(&varResult); + hr = IAccessible_get_accState(acc, varChild, &varResult); + ok(hr == S_OK, "accState failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accState returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == (STATE_SYSTEM_FOCUSABLE|STATE_SYSTEM_LINKED), "accState returned %li\n", V_I4(&varResult)); + + hr = IAccessible_get_accName(acc, varChild, &name); + ok(hr == S_OK, "accName failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) { + ok(!!name && !wcscmp(name, L"Name1"), + "unexpected name %s\n", debugstr_w(name)); + SysFreeString(name); + } + + hr = IAccessible_get_accDefaultAction(acc, varChild, &name); + ok(hr == S_OK, "accDefaultAction failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) + { + if (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH) + { + skip("Non-English locale (test with hardcoded 'Click')\n"); + } + else + { + ok(!!name && !wcscmp(name, L"Click"), + "unexpected name %s\n", debugstr_w(name)); + } + SysFreeString(name); + } + + g_link_id = -1; + hr = IAccessible_accDoDefaultAction(acc, varChild); + ok(hr == S_OK, "accDoDefaultAction failed, hr=%lx\n", hr); + wait_link_click(500); + ok(g_link_id == 0, "Got unexpected link id %d.\n", g_link_id); + + g_link_id = -1; + hr = IAccessible_accLocation(acc, &left, &top, &width, &height, varChild); + ok(hr == S_OK, "accLocation failed, hr=%lx\n", hr); + SendMessageA(hwnd, WM_LBUTTONDOWN, 1, MAKELPARAM(left - hwnd_left + width / 2, top - hwnd_top + height / 2)); + SendMessageA(hwnd, WM_LBUTTONUP, 0, MAKELPARAM(left - hwnd_left + width / 2, top - hwnd_top + height / 2)); + ok(g_link_id == 0, "Got unexpected link id %d.\n", g_link_id); + + /* child 2 */ + V_I4(&varChild) = 2; + hr = IAccessible_get_accChild(acc, varChild, &child); + ok(hr == S_FALSE, "accChild hr=%lx\n", hr); + ok(!child, "accChild returned IDispatch\n"); + + hr = IAccessible_get_accRole(acc, varChild, &varResult); + ok(hr == S_OK, "accRole failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accRole returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == ROLE_SYSTEM_LINK, "accRole returned %li\n", V_I4(&varResult)); + + VariantClear(&varResult); + hr = IAccessible_get_accState(acc, varChild, &varResult); + ok(hr == S_OK, "accState failed, hr=%lx\n", hr); + ok(V_VT(&varResult) == VT_I4, "accState returned vt=%x\n", V_VT(&varResult)); + ok(V_I4(&varResult) == (STATE_SYSTEM_FOCUSABLE|STATE_SYSTEM_LINKED), "accState returned %li\n", V_I4(&varResult)); + + hr = IAccessible_get_accName(acc, varChild, &name); + ok(hr == S_OK, "accName failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) { + ok(!!name && !wcscmp(name, L"Name2"), + "unexpected name %s\n", debugstr_w(name)); + SysFreeString(name); + } + + hr = IAccessible_get_accDefaultAction(acc, varChild, &name); + ok(hr == S_OK, "accDefaultAction failed, hr=%lx\n", hr); + if (SUCCEEDED(hr)) + { + if (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH) + { + skip("Non-English locale (test with hardcoded 'Click')\n"); + } + else + { + ok(!!name && !wcscmp(name, L"Click"), + "unexpected name %s\n", debugstr_w(name)); + } + SysFreeString(name); + } + + g_link_id = -1; + hr = IAccessible_accDoDefaultAction(acc, varChild); + ok(hr == S_OK, "accDoDefaultAction failed, hr=%lx\n", hr); + wait_link_click(500); + ok(g_link_id == 1, "Got unexpected link id %d.\n", g_link_id); + + g_link_id = -1; + hr = IAccessible_accLocation(acc, &left, &top, &width, &height, varChild); + ok(hr == S_OK, "accLocation failed, hr=%lx\n", hr); + SendMessageA(hwnd, WM_LBUTTONDOWN, 1, MAKELPARAM(left - hwnd_left + width / 2, top - hwnd_top + height / 2)); + SendMessageA(hwnd, WM_LBUTTONUP, 0, MAKELPARAM(left - hwnd_left + width / 2, top - hwnd_top + height / 2)); + ok(g_link_id == 1, "Got unexpected link id %d.\n", g_link_id); + + hr = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ole_window); + ok(hr == S_OK, "QueryInterface failed, hr=%lx\n", hr); + + if (SUCCEEDED(hr)) { + hr = IOleWindow_GetWindow(ole_window, &ret_hwnd); + ok(hr == S_OK, "GetWindow failed, hr=%lx\n", hr); + ok(ret_hwnd == hwnd, "GetWindow returned wrong hwnd\n"); + + IOleWindow_Release(ole_window); + } + + IAccessible_Release(acc); + + DestroyWindow(hwnd); +} + START_TEST(syslink) { ULONG_PTR ctx_cookie; @@ -295,6 +584,8 @@ START_TEST(syslink) init_msg_sequences(sequences, NUM_MSG_SEQUENCE); + init_winevent_hook(); + /* Create parent window */ hWndParent = create_parent_window(); ok(hWndParent != NULL, "Failed to create parent Window!\n"); @@ -304,6 +595,9 @@ START_TEST(syslink) test_LM_GETIDEALHEIGHT(); test_LM_GETIDEALSIZE(); test_link_id(); + test_msaa(); + + uninit_winevent_hook(); DestroyWindow(hWndParent); unload_v6_module(ctx_cookie, hCtx); diff --git a/dlls/comctl32/trackbar.c b/dlls/comctl32/trackbar.c index f2cb2a07a8df..936f88c9fbe7 100644 --- a/dlls/comctl32/trackbar.c +++ b/dlls/comctl32/trackbar.c @@ -2012,6 +2012,11 @@ TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_GETDLGCODE: return DLGC_WANTARROWS; + case WM_GETOBJECT: + if ((LONG)lParam == OBJID_QUERYCLASSNAMEIDX) + return 0x10012; + return 0; + case WM_KEYDOWN: return TRACKBAR_KeyDown (infoPtr, (INT)wParam); diff --git a/dlls/crypt32/chain.c b/dlls/crypt32/chain.c index 5e4288eda374..fa74ade13d64 100644 --- a/dlls/crypt32/chain.c +++ b/dlls/crypt32/chain.c @@ -2707,6 +2707,7 @@ static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain, switch (revocationStatus.dwError) { + case CRYPT_E_REVOCATION_OFFLINE: case CRYPT_E_NO_REVOCATION_CHECK: case CRYPT_E_NO_REVOCATION_DLL: case CRYPT_E_NOT_IN_REVOCATION_DATABASE: @@ -2716,9 +2717,6 @@ static void CRYPT_VerifyChainRevocation(PCERT_CHAIN_CONTEXT chain, error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN | CERT_TRUST_IS_OFFLINE_REVOCATION; break; - case CRYPT_E_REVOCATION_OFFLINE: - error = CERT_TRUST_IS_OFFLINE_REVOCATION; - break; case CRYPT_E_REVOKED: error = CERT_TRUST_IS_REVOKED; break; @@ -2991,6 +2989,24 @@ static void find_element_with_error(PCCERT_CHAIN_CONTEXT chain, DWORD error, } } +static BOOL find_chain_first_element_with_error(PCCERT_CHAIN_CONTEXT chain, DWORD error, LONG *chain_idx, + LONG *element_idx) +{ + unsigned int i; + + for (i = 0; i < chain->cChain; i++) + { + if (!chain->rgpChain[i]->cElement) continue; + if (chain->rgpChain[i]->rgpElement[0]->TrustStatus.dwErrorStatus & error) + { + *chain_idx = i; + *element_idx = 0; + return TRUE; + } + } + return FALSE; +} + static BOOL WINAPI verify_base_policy(LPCSTR szPolicyOID, PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, PCERT_CHAIN_POLICY_STATUS pPolicyStatus) @@ -3503,7 +3519,7 @@ static BOOL WINAPI verify_ssl_policy(LPCSTR szPolicyOID, } else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE && - !(checks & SECURITY_FLAG_IGNORE_WRONG_USAGE)) + !(checks & SECURITY_FLAG_IGNORE_WRONG_USAGE) && !(baseChecks & CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG)) { pPolicyStatus->dwError = CERT_E_WRONG_USAGE; find_element_with_error(pChainContext, @@ -3513,19 +3529,18 @@ static BOOL WINAPI verify_ssl_policy(LPCSTR szPolicyOID, else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED && !(checks & SECURITY_FLAG_IGNORE_REVOCATION)) { - pPolicyStatus->dwError = CERT_E_REVOKED; + pPolicyStatus->dwError = CRYPT_E_REVOKED; find_element_with_error(pChainContext, CERT_TRUST_IS_REVOKED, &pPolicyStatus->lChainIndex, &pPolicyStatus->lElementIndex); } else if (pChainContext->TrustStatus.dwErrorStatus & - CERT_TRUST_IS_OFFLINE_REVOCATION && - !(checks & SECURITY_FLAG_IGNORE_REVOCATION)) + CERT_TRUST_REVOCATION_STATUS_UNKNOWN && + !(checks & SECURITY_FLAG_IGNORE_REVOCATION) && !(baseChecks & CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG) + && find_chain_first_element_with_error(pChainContext, CERT_TRUST_REVOCATION_STATUS_UNKNOWN, + &pPolicyStatus->lChainIndex, &pPolicyStatus->lElementIndex)) { - pPolicyStatus->dwError = CERT_E_REVOCATION_FAILURE; - find_element_with_error(pChainContext, - CERT_TRUST_IS_OFFLINE_REVOCATION, &pPolicyStatus->lChainIndex, - &pPolicyStatus->lElementIndex); + pPolicyStatus->dwError = CRYPT_E_REVOCATION_OFFLINE; } else if (pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT) diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h index 827594d84891..a5aeae631688 100644 --- a/dlls/crypt32/crypt32_private.h +++ b/dlls/crypt32/crypt32_private.h @@ -349,10 +349,12 @@ WINECRYPT_CERTSTORE *CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara); void CRYPT_ImportSystemRootCertsToReg(void); -BOOL CRYPT_SerializeContextsToReg(HKEY key, DWORD flags, const WINE_CONTEXT_INTERFACE *contextInterface, - HCERTSTORE memStore); +BOOL CRYPT_SerializeContextToReg(HKEY key, DWORD flags, const WINE_CONTEXT_INTERFACE *context_iface, + const void *context); void CRYPT_RegReadSerializedFromReg(HKEY key, DWORD contextType, HCERTSTORE store, DWORD disposition); +void CRYPT_RegDeleteFromReg(HKEY key, const BYTE *sha1_hash); +void CRYPT_HashToStr(const BYTE *hash, LPWSTR asciiHash); DWORD CRYPT_IsCertificateSelfSigned(const CERT_CONTEXT *cert); diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c index cfdeef5380aa..2deacc1cb151 100644 --- a/dlls/crypt32/decode.c +++ b/dlls/crypt32/decode.c @@ -6507,7 +6507,7 @@ static BOOL CRYPT_AsnDecodeOCSPBasicResponseEntry(const BYTE *pbEncoded, DWORD c { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(OCSP_BASIC_RESPONSE_ENTRY, NextUpdate), CRYPT_AsnDecodeOCSPNextUpdate, sizeof(FILETIME), TRUE, FALSE, 0, 0 }, - { ASN_CONTEXT | ASN_CONSTRUCTOR /* FIXME */, offsetof(OCSP_BASIC_RESPONSE_ENTRY, cExtension), + { ASN_CONTEXT | ASN_CONSTRUCTOR | 1 /* FIXME */, offsetof(OCSP_BASIC_RESPONSE_ENTRY, cExtension), CRYPT_AsnDecodeCertExtensions, FINALMEMBERSIZE(OCSP_BASIC_RESPONSE_ENTRY, cExtension), TRUE, TRUE, offsetof(OCSP_BASIC_RESPONSE_ENTRY, rgExtension), 0 }, }; @@ -6722,7 +6722,7 @@ static BOOL WINAPI CRYPT_AsnDecodeOCSPBasicResponse(DWORD dwCertEncodingType, { ASN_SEQUENCEOF, offsetof(OCSP_BASIC_RESPONSE_INFO, cResponseEntry), CRYPT_AsnDecodeOCSPBasicResponseEntriesArray, MEMBERSIZE(OCSP_BASIC_RESPONSE_INFO, cResponseEntry, cExtension), TRUE, TRUE, offsetof(OCSP_BASIC_RESPONSE_INFO, rgResponseEntry) }, - { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(OCSP_BASIC_RESPONSE_INFO, cExtension), + { ASN_CONTEXT | ASN_CONSTRUCTOR | 1, offsetof(OCSP_BASIC_RESPONSE_INFO, cExtension), CRYPT_AsnDecodeCertExtensions, FINALMEMBERSIZE(OCSP_BASIC_RESPONSE_INFO, cExtension), TRUE, TRUE, offsetof(OCSP_BASIC_RESPONSE_INFO, rgExtension), 0 }, }; diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c index 5e6d59a1f581..0525eda7a803 100644 --- a/dlls/crypt32/msg.c +++ b/dlls/crypt32/msg.c @@ -946,10 +946,10 @@ static BOOL CSignedMsgData_ConstructSignerHandles(CSignedMsgData *msg_data, } ret = CryptCreateHash(*crypt_prov, algID, 0, 0, - &msg_data->signerHandles->contentHash); + &msg_data->signerHandles[signerIndex].contentHash); if (ret && msg_data->info->rgSignerInfo[signerIndex].AuthAttrs.cAttr > 0) ret = CryptCreateHash(*crypt_prov, algID, 0, 0, - &msg_data->signerHandles->authAttrHash); + &msg_data->signerHandles[signerIndex].authAttrHash); return ret; } @@ -1181,6 +1181,7 @@ typedef struct _CSignedEncodeMsg LPSTR innerOID; CRYPT_DATA_BLOB data; CSignedMsgData msg_data; + HCRYPTPROV prov[]; } CSignedEncodeMsg; static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg) @@ -1197,6 +1198,10 @@ static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg) for (i = 0; i < msg->msg_data.info->cSignerInfo; i++) CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]); CSignedMsgData_CloseHandles(&msg->msg_data); + if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) + for (i = 0; i < msg->msg_data.info->cSignerInfo; i++) + if (msg->prov[i]) + CryptReleaseContext(msg->prov[i], 0); CryptMemFree(msg->msg_data.info->signerKeySpec); CryptMemFree(msg->msg_data.info->rgSignerInfo); CryptMemFree(msg->msg_data.info); @@ -1357,7 +1362,7 @@ static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags, PCMSG_STREAM_INFO pStreamInfo) { const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *info = pvMsgEncodeInfo; - DWORD i; + DWORD i, saved_prov_count = 0; CSignedEncodeMsg *msg; if (info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO) && @@ -1375,7 +1380,9 @@ static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags, for (i = 0; i < info->cSigners; i++) if (!CRYPT_IsValidSigner(&info->rgSigners[i])) return NULL; - msg = CryptMemAlloc(sizeof(CSignedEncodeMsg)); + if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) + saved_prov_count = info->cSigners; + msg = CryptMemAlloc(offsetof(CSignedEncodeMsg, prov) + sizeof(HCRYPTPROV) * saved_prov_count); if (msg) { BOOL ret = TRUE; @@ -1424,19 +1431,18 @@ static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags, ret = FALSE; for (i = 0; ret && i < msg->msg_data.info->cSignerInfo; i++) { - if (info->rgSigners[i].SignerId.dwIdChoice == - CERT_ID_KEY_IDENTIFIER) + if (info->rgSigners[i].cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS) && + info->rgSigners[i].SignerId.dwIdChoice == CERT_ID_KEY_IDENTIFIER) msg->msg_data.info->version = CMSG_SIGNED_DATA_V3; ret = CSignerInfo_Construct( &msg->msg_data.info->rgSignerInfo[i], &info->rgSigners[i]); if (ret) { + if (saved_prov_count) + msg->prov[i] = info->rgSigners[i].hCryptProv; ret = CSignedMsgData_ConstructSignerHandles( &msg->msg_data, i, &info->rgSigners[i].hCryptProv, &dwFlags); - if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) - CryptReleaseContext(info->rgSigners[i].hCryptProv, - 0); } msg->msg_data.info->signerKeySpec[i] = info->rgSigners[i].dwKeySpec; @@ -3199,6 +3205,8 @@ static BOOL CDecodeSignedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType, { if (dwIndex >= msg->u.signed_data.info->cSignerInfo) SetLastError(CRYPT_E_INVALID_INDEX); + else if (!msg->u.signed_data.info->rgSignerInfo[dwIndex].AuthAttrs.cAttr) + SetLastError(CRYPT_E_ATTRIBUTES_MISSING); else ret = CRYPT_CopyAttr(pvData, pcbData, &msg->u.signed_data.info->rgSignerInfo[dwIndex].AuthAttrs); @@ -3211,6 +3219,8 @@ static BOOL CDecodeSignedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType, { if (dwIndex >= msg->u.signed_data.info->cSignerInfo) SetLastError(CRYPT_E_INVALID_INDEX); + else if (!msg->u.signed_data.info->rgSignerInfo[dwIndex].UnauthAttrs.cAttr) + SetLastError(CRYPT_E_ATTRIBUTES_MISSING); else ret = CRYPT_CopyAttr(pvData, pcbData, &msg->u.signed_data.info->rgSignerInfo[dwIndex].UnauthAttrs); diff --git a/dlls/crypt32/regstore.c b/dlls/crypt32/regstore.c index 8567604c39b7..218a7ea32697 100644 --- a/dlls/crypt32/regstore.c +++ b/dlls/crypt32/regstore.c @@ -45,7 +45,7 @@ typedef struct _WINE_REGSTOREINFO struct list ctlsToDelete; } WINE_REGSTOREINFO; -static void CRYPT_HashToStr(const BYTE *hash, LPWSTR asciiHash) +void CRYPT_HashToStr(const BYTE *hash, LPWSTR asciiHash) { DWORD i; @@ -197,7 +197,36 @@ static BOOL CRYPT_WriteSerializedToReg(HKEY key, DWORD flags, const BYTE *hash, return ret; } -BOOL CRYPT_SerializeContextsToReg(HKEY key, DWORD flags, +BOOL CRYPT_SerializeContextToReg(HKEY key, DWORD flags, const WINE_CONTEXT_INTERFACE *context_iface, + const void *context) +{ + BYTE hash[20]; + DWORD hash_size = sizeof(hash); + DWORD size = 0; + BYTE *buf; + BOOL ret; + + if (!context_iface->getProp(context, CERT_HASH_PROP_ID, hash, &hash_size)) + return FALSE; + + context_iface->serialize(context, 0, NULL, &size); + if (!size) + return FALSE; + + if (!(buf = CryptMemAlloc(size))) + return FALSE; + + if (!(context_iface->serialize(context, 0, buf, &size))) + { + CryptMemFree(buf); + return FALSE; + } + ret = CRYPT_WriteSerializedToReg(key, flags, hash, buf, size); + CryptMemFree(buf); + return ret; +} + +static BOOL CRYPT_SerializeContextsToReg(HKEY key, DWORD flags, const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore) { const void *context = NULL; @@ -205,38 +234,22 @@ BOOL CRYPT_SerializeContextsToReg(HKEY key, DWORD flags, do { context = contextInterface->enumContextsInStore(memStore, context); - if (context) - { - BYTE hash[20]; - DWORD hashSize = sizeof(hash); - - ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash, - &hashSize); - if (ret) - { - DWORD size = 0; - LPBYTE buf = NULL; - - ret = contextInterface->serialize(context, 0, NULL, &size); - if (size) - buf = CryptMemAlloc(size); - if (buf) - { - ret = contextInterface->serialize(context, 0, buf, &size); - if (ret) - ret = CRYPT_WriteSerializedToReg(key, flags, hash, buf, size); - } - CryptMemFree(buf); - } - } - else - ret = TRUE; + ret = !context || CRYPT_SerializeContextToReg(key, flags, contextInterface, context); } while (ret && context != NULL); if (context) Context_Release(context_from_ptr(context)); return ret; } +void CRYPT_RegDeleteFromReg(HKEY key, const BYTE *sha1_hash) +{ + WCHAR hash[20 * 2 + 1]; + + CRYPT_HashToStr(sha1_hash, hash); + TRACE("Removing %s\n", debugstr_w(hash)); + RegDeleteKeyW(key, hash); +} + static BOOL CRYPT_RegWriteToReg(WINE_REGSTOREINFO *store) { static const WCHAR * const subKeys[] = { L"Certificates", L"CRLs", L"CTLs" }; @@ -258,22 +271,12 @@ static BOOL CRYPT_RegWriteToReg(WINE_REGSTOREINFO *store) if (listToDelete[i]) { WINE_HASH_TO_DELETE *toDelete, *next; - WCHAR asciiHash[20 * 2 + 1]; EnterCriticalSection(&store->cs); LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i], WINE_HASH_TO_DELETE, entry) { - LONG rc; - - CRYPT_HashToStr(toDelete->hash, asciiHash); - TRACE("Removing %s\n", debugstr_w(asciiHash)); - rc = RegDeleteKeyW(key, asciiHash); - if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND) - { - SetLastError(rc); - ret = FALSE; - } + CRYPT_RegDeleteFromReg(key, toDelete->hash); list_remove(&toDelete->entry); CryptMemFree(toDelete); } diff --git a/dlls/crypt32/rootstore.c b/dlls/crypt32/rootstore.c index cfddcc143ace..4c215d449432 100644 --- a/dlls/crypt32/rootstore.c +++ b/dlls/crypt32/rootstore.c @@ -58,6 +58,7 @@ static const char *trust_status_to_str(DWORD status) { CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT, "excluded name constraint" }, { CERT_TRUST_IS_OFFLINE_REVOCATION, "revocation server offline" }, { CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY, "no issuance policy" }, + { CERT_TRUST_IS_PARTIAL_CHAIN, "partial chain" }, }; static char buf[1024]; int i, pos = 0; @@ -98,74 +99,89 @@ static const char *get_cert_common_name(PCCERT_CONTEXT cert) return name; } -static void check_and_store_certs(HCERTSTORE cached, HCERTSTORE new, HCERTSTORE to) +static void get_cert_context_hash( const CERT_CONTEXT *cert, BYTE *sha1_hash, WCHAR *hash_str ) +{ + DWORD size; + + size = 20; + CertGetCertificateContextProperty( cert, CERT_HASH_PROP_ID, sha1_hash, &size ); + CRYPT_HashToStr( sha1_hash, hash_str ); +} + +static void mark_cert_imported( HKEY import_key, const CERT_CONTEXT *cert ) +{ + WCHAR hash_str[20 * 2 + 1]; + BYTE sha1_hash[20]; + DWORD value = 1; + + get_cert_context_hash( cert, sha1_hash, hash_str ); + RegSetValueExW( import_key, hash_str, 0, REG_DWORD, (BYTE *)&value, sizeof(value) ); +} + +static void check_and_store_certs( HCERTSTORE cached, HKEY key, HKEY import_key ) { DWORD root_count = 0; - CERT_CHAIN_ENGINE_CONFIG chainEngineConfig = - { sizeof(chainEngineConfig), 0 }; + CERT_CHAIN_ENGINE_CONFIG chainEngineConfig = { sizeof(chainEngineConfig), 0 }; HCERTCHAINENGINE engine; + PCCERT_CONTEXT cert = NULL; TRACE("\n"); - CertDuplicateStore(to); - engine = CRYPT_CreateChainEngine(to, CERT_SYSTEM_STORE_CURRENT_USER, &chainEngineConfig); - if (engine) + if (!(engine = CRYPT_CreateChainEngine( cached, CERT_SYSTEM_STORE_CURRENT_USER, &chainEngineConfig ))) + return; + + while ((cert = CertEnumCertificatesInStore( cached, cert ))) { - PCCERT_CONTEXT cert = NULL; + const DWORD allowed_errors = CERT_TRUST_IS_UNTRUSTED_ROOT | CERT_TRUST_IS_NOT_VALID_FOR_USAGE + | CERT_TRUST_INVALID_BASIC_CONSTRAINTS | CERT_TRUST_IS_NOT_TIME_VALID; + CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; + PCCERT_CHAIN_CONTEXT chain; + DWORD size; + int is_new; + BOOL ret; + + size = sizeof(is_new); + if (!CertGetCertificateContextProperty( cert, CERT_FIRST_USER_PROP_ID, &is_new, &size )) + { + ERR( "CERT_FIRST_USER_PROP_ID property absent for cert %p.\n", cert ); + continue; + } + if (!is_new) + continue; - do { - cert = CertEnumCertificatesInStore(new, cert); - if (cert) - { - CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; - PCCERT_CHAIN_CONTEXT chain; - BOOL ret; - - ret = CertGetCertificateChain(engine, cert, NULL, cached, - &chainPara, CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL, NULL, &chain); - if (!ret) - TRACE("rejecting %s: %s\n", get_cert_common_name(cert), - "chain creation failed"); - else - { - DWORD allowedErrors = CERT_TRUST_IS_UNTRUSTED_ROOT | - CERT_TRUST_IS_NOT_VALID_FOR_USAGE | - CERT_TRUST_INVALID_BASIC_CONSTRAINTS | - CERT_TRUST_IS_NOT_TIME_VALID; - - /* The certificate chain verification only allows certain - * invalid CA certs if they're installed locally: CA - * certs missing the key usage extension, and CA certs - * missing the basic constraints extension. Of course - * there's a chicken and egg problem: we have to accept - * them here in order for them to be accepted later. - * Expired, locally installed certs are also allowed here, - * because we don't know (yet) what date will be checked - * for an item signed by one of these certs. - * Thus, accept certs with any of the allowed errors. - */ - if (chain->TrustStatus.dwErrorStatus & ~allowedErrors) - TRACE("rejecting %s: %s\n", get_cert_common_name(cert), - trust_status_to_str(chain->TrustStatus.dwErrorStatus & - ~CERT_TRUST_IS_UNTRUSTED_ROOT)); - else - { - DWORD i, j; - - for (i = 0; i < chain->cChain; i++) - for (j = 0; j < chain->rgpChain[i]->cElement; j++) - if (CertAddCertificateContextToStore(to, - chain->rgpChain[i]->rgpElement[j]->pCertContext, - CERT_STORE_ADD_NEW, NULL)) - root_count++; - } - CertFreeCertificateChain(chain); - } - } - } while (cert); - CertFreeCertificateChainEngine(engine); + ret = CertGetCertificateChain( engine, cert, NULL, NULL, &chainPara, CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL, NULL, &chain ); + if (!ret) + { + TRACE( "rejecting %s: chain creation failed.\n", get_cert_common_name( cert )); + continue; + } + + /* The certificate chain verification only allows certain + * invalid CA certs if they're installed locally: CA + * certs missing the key usage extension, and CA certs + * missing the basic constraints extension. Of course + * there's a chicken and egg problem: we have to accept + * them here in order for them to be accepted later. + * Expired, locally installed certs are also allowed here, + * because we don't know (yet) what date will be checked + * for an item signed by one of these certs. + * Thus, accept certs with any of the allowed errors. + */ + if (chain->TrustStatus.dwErrorStatus & ~allowed_errors) + TRACE( "rejecting %s: %s\n", get_cert_common_name(cert), + trust_status_to_str( chain->TrustStatus.dwErrorStatus & ~CERT_TRUST_IS_UNTRUSTED_ROOT )); + else + { + /* Clear custom property so it is not serialized and seen by apps. */ + CertSetCertificateContextProperty( cert, CERT_FIRST_USER_PROP_ID, 0, NULL ); + mark_cert_imported( import_key, cert ); + CRYPT_SerializeContextToReg( key, 0, pCertInterface, cert ); + root_count++; + } + CertFreeCertificateChain(chain); } - TRACE("Added %ld root certificates\n", root_count); + CertFreeCertificateChainEngine( engine ); + TRACE( "Added %ld root certificates\n", root_count ); } static const BYTE authenticode[] = { @@ -595,26 +611,32 @@ static const struct CONST_BLOB { { rootcertauthority2011, sizeof(rootcertauthority2011) }, }; -static void add_ms_root_certs(HCERTSTORE to, HCERTSTORE cached) +static void add_ms_root_certs(HKEY key, HCERTSTORE cached) { PCCERT_CONTEXT cert, existing; DWORD i; + int is_new; + const CRYPT_DATA_BLOB exists_blob = { sizeof(is_new), (BYTE *)&is_new }; TRACE("\n"); for (i = 0; i < ARRAY_SIZE(msRootCerts); i++) { - if (!CertAddEncodedCertificateToStore(to, X509_ASN_ENCODING, - msRootCerts[i].pb, msRootCerts[i].cb, CERT_STORE_ADD_NEW, &cert)) + if (!(cert = CertCreateCertificateContext(X509_ASN_ENCODING, msRootCerts[i].pb, msRootCerts[i].cb))) { WARN("adding root cert %ld failed: %08lx\n", i, GetLastError()); continue; } if ((existing = CertFindCertificateInStore(cached, X509_ASN_ENCODING, 0, CERT_FIND_EXISTING, cert, NULL))) { - CertDeleteCertificateFromStore(existing); + is_new = 0; + CertSetCertificateContextProperty(existing, CERT_FIRST_USER_PROP_ID, 0, &exists_blob); CertFreeCertificateContext(existing); } + else + { + CRYPT_SerializeContextToReg(key, 0, pCertInterface, cert); + } CertFreeCertificateContext(cert); } } @@ -624,9 +646,8 @@ static void add_ms_root_certs(HCERTSTORE to, HCERTSTORE cached) * adding redundant certificates, e.g. when both a certificate bundle and * individual certificates exist in the same directory. */ -static void read_trusted_roots_from_known_locations(HCERTSTORE store, HCERTSTORE cached, BOOL *delete) +static void sync_trusted_roots_from_known_locations( HKEY key, HCERTSTORE cached ) { - HCERTSTORE new; DWORD needed, size; struct enum_root_certs_params params = { NULL, 2048, &needed }; HCRYPTPROV prov; @@ -634,17 +655,34 @@ static void read_trusted_roots_from_known_locations(HCERTSTORE store, HCERTSTORE BYTE hashval[20]; DWORD hashlen; CRYPT_HASH_BLOB hash_blob = { sizeof(hashval), hashval }; - CRYPT_DATA_BLOB exists_blob = { 0, NULL }; + int is_new; + CRYPT_DATA_BLOB exists_blob = { sizeof(is_new), (BYTE *)&is_new }; PCCERT_CONTEXT cert, existing; - unsigned int existing_count = 0, new_count = 0; - unsigned int cached_count = 0; + unsigned int existing_count = 0, new_count = 0, deleted_count = 0; + BYTE sha1_hash[20]; + HKEY import_key; + WCHAR hash_str[20 * 2 + 1]; + DWORD value; + + if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Wine\\HostImportedCertificates", 0, KEY_ALL_ACCESS, &import_key )) + { + if (RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Wine\\HostImportedCertificates_tmp", 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &import_key, NULL )) + return; - new = CertOpenStore( CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL ); - if (!new) return; + /* If the key is absent existing certificates were added by an older Wine version, mark all cached certificates + * as imported (as it was previously assumed) so they can be deleted when are deleted on host. */ + cert = NULL; + while ((cert = CertEnumCertificatesInStore( cached, cert ))) + mark_cert_imported( import_key, cert ); - existing = NULL; - while ((existing = CertEnumCertificatesInStore( cached, existing ))) - ++cached_count; + if ((value = RegRenameKey( import_key, NULL, L"HostImportedCertificates" ))) + { + ERR( "Error renaming key %#lx.\n", value ); + RegCloseKey( import_key ); + return; + } + } CryptAcquireContextW( &prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ); params.buffer = CryptMemAlloc( params.size ); @@ -669,6 +707,7 @@ static void read_trusted_roots_from_known_locations(HCERTSTORE store, HCERTSTORE * is found among host imports. */ if (!CertGetCertificateContextProperty( existing, CERT_FIRST_USER_PROP_ID, NULL, &size )) { + is_new = 0; if (!CertSetCertificateContextProperty( existing, CERT_FIRST_USER_PROP_ID, 0, &exists_blob )) ERR( "Failed to set property.\n" ); ++existing_count; @@ -676,9 +715,9 @@ static void read_trusted_roots_from_known_locations(HCERTSTORE store, HCERTSTORE CertFreeCertificateContext( existing ); continue; } - CertAddEncodedCertificateToStore( new, X509_ASN_ENCODING, params.buffer, needed, CERT_STORE_ADD_ALWAYS, &cert ); - /* Add to cached so we can catch duplicates and check_and_store_certs() has the full chains. */ - CertAddCertificateContextToStore( cached, cert, CERT_STORE_ADD_ALWAYS, NULL ); + + CertAddEncodedCertificateToStore( cached, X509_ASN_ENCODING, params.buffer, needed, CERT_STORE_ADD_ALWAYS, &cert ); + is_new = 1; if (!CertSetCertificateContextProperty( cert, CERT_FIRST_USER_PROP_ID, 0, &exists_blob )) ERR("Failed to set property.\n"); CertFreeCertificateContext( cert ); @@ -687,61 +726,42 @@ static void read_trusted_roots_from_known_locations(HCERTSTORE store, HCERTSTORE CryptMemFree( params.buffer ); CryptReleaseContext( prov, 0 ); - if (existing_count < cached_count) + cert = NULL; + while ((cert = CertEnumCertificatesInStore( cached, cert ))) { - /* Some certs were removed on host. Clean up the cache and add all the certificates so cert chains - * get revalidated. The certs present on host are now in 'cached' store and are marked with - * CERT_FIRST_USER_PROP_ID property. */ - TRACE( "Some keys were removed, reimporting, cached %u, existing %u, new %u.\n", - cached_count, existing_count, new_count ); - *delete = TRUE; - existing_count = 0; - existing = NULL; - while ((existing = CertEnumCertificatesInStore( cached, existing ))) + if (CertGetCertificateContextProperty( cert, CERT_FIRST_USER_PROP_ID, NULL, &size )) + continue; + + get_cert_context_hash( cert, sha1_hash, hash_str ); + size = sizeof(value); + if (RegQueryValueExW( import_key, hash_str, NULL, NULL, (BYTE *)&value, &size )) { - if (!CertGetCertificateContextProperty( existing, CERT_FIRST_USER_PROP_ID, NULL, &size )) - continue; - CertAddCertificateContextToStore( new, existing, CERT_STORE_ADD_NEW, NULL ); - ++new_count; + TRACE( "key %s is not imported, not deleting.\n", debugstr_w(hash_str) ); + continue; } - } - if (new_count) - { - /* Clear custom property so it is not serialized and seen by apps. */ + ++deleted_count; + CRYPT_RegDeleteFromReg( key, sha1_hash ); + RegDeleteValueW( import_key, hash_str ); + /* Delete from cached so deleted certs do not participate in chain verification. */ + CertDeleteCertificateFromStore( cert ); + /* Restart enumeration as it is broken by deleting cert from store. */ + CertFreeCertificateContext( cert ); cert = NULL; - while ((cert = CertEnumCertificatesInStore( new, cert ))) - CertSetCertificateContextProperty( cert, CERT_FIRST_USER_PROP_ID, 0, NULL ); - check_and_store_certs( cached, new, store ); } - CertCloseStore( new, 0 ); - TRACE( "existing %u, new %u.\n", existing_count, new_count ); -} - -static HCERTSTORE create_root_store(HCERTSTORE cached, BOOL *delete) -{ - HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, - X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); - - - *delete = FALSE; - if (memStore) - { - add_ms_root_certs(memStore, cached); - read_trusted_roots_from_known_locations(memStore, cached, delete); - } + if (new_count) + check_and_store_certs( cached, key, import_key ); - TRACE("returning %p\n", memStore); - return memStore; + RegCloseKey( import_key ); + TRACE( "existing %u, deleted %u, new %u.\n", existing_count, deleted_count, new_count ); } void CRYPT_ImportSystemRootCertsToReg(void) { - HCERTSTORE store = NULL, reg = NULL; + HCERTSTORE cached = NULL; HKEY key = NULL; LONG rc; HANDLE hsem; - BOOL delete; static BOOL root_certs_imported = FALSE; @@ -766,27 +786,18 @@ void CRYPT_ImportSystemRootCertsToReg(void) if (rc) goto done; - if (!(reg = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL))) + if (!(cached = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL))) { ERR("Failed to create memory store.\n"); goto done; } - CRYPT_RegReadSerializedFromReg(key, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, reg, CERT_STORE_ADD_ALWAYS); - - if (!(store = create_root_store(reg, &delete))) - { - ERR("Failed to create root store\n"); - goto done; - } - if (delete && RegDeleteTreeW(key, NULL)) - ERR("Error deleting key.\n"); - if (!CRYPT_SerializeContextsToReg(key, 0, pCertInterface, store)) - ERR("Failed to import system certs into registry, %08lx\n", GetLastError()); + CRYPT_RegReadSerializedFromReg(key, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, cached, CERT_STORE_ADD_ALWAYS); + add_ms_root_certs(key, cached); + sync_trusted_roots_from_known_locations(key, cached); done: RegCloseKey(key); - CertCloseStore(store, 0); - CertCloseStore(reg, 0); + CertCloseStore(cached, 0); root_certs_imported = TRUE; ReleaseSemaphore(hsem, 1, NULL); CloseHandle(hsem); diff --git a/dlls/crypt32/sip.c b/dlls/crypt32/sip.c index 132f491b2f1e..d9da19b62728 100644 --- a/dlls/crypt32/sip.c +++ b/dlls/crypt32/sip.c @@ -562,10 +562,11 @@ static WINE_SIP_PROVIDER *CRYPT_GetCachedSIP(const GUID *pgSubject) LIST_FOR_EACH_ENTRY(provider, &providers, WINE_SIP_PROVIDER, entry) { if (IsEqualGUID(pgSubject, &provider->subject)) + { + ret = provider; break; + } } - if (provider && IsEqualGUID(pgSubject, &provider->subject)) - ret = provider; LeaveCriticalSection(&providers_cs); return ret; } diff --git a/dlls/crypt32/tests/chain.c b/dlls/crypt32/tests/chain.c index 9717b184c147..5522ab4f01ba 100644 --- a/dlls/crypt32/tests/chain.c +++ b/dlls/crypt32/tests/chain.c @@ -5376,10 +5376,141 @@ static void testVerifyCertChainPolicy(void) check_msroot_policy(); } +static void test_VerifyCertChainPolicy_flags(void) +{ + static const struct + { + DWORD trust_status; + unsigned int index; + DWORD policy_flags; + DWORD ssl_policy_flags; + DWORD expected_error; + } + tests[] = + { + { CERT_TRUST_REVOCATION_STATUS_UNKNOWN | CERT_TRUST_IS_OFFLINE_REVOCATION, 0, 0, 0, CRYPT_E_REVOCATION_OFFLINE }, + /* CERT_TRUST_REVOCATION_STATUS_UNKNOWN is only checked on the end certificate. */ + { CERT_TRUST_REVOCATION_STATUS_UNKNOWN | CERT_TRUST_IS_OFFLINE_REVOCATION, 1, 0, 0, ERROR_SUCCESS }, + { CERT_TRUST_REVOCATION_STATUS_UNKNOWN | CERT_TRUST_IS_OFFLINE_REVOCATION, 2, 0, 0, ERROR_SUCCESS }, + { CERT_TRUST_REVOCATION_STATUS_UNKNOWN | CERT_TRUST_IS_OFFLINE_REVOCATION, 0, CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG, 0, 0 }, + { CERT_TRUST_REVOCATION_STATUS_UNKNOWN | CERT_TRUST_IS_OFFLINE_REVOCATION, 0, CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG, 0, CRYPT_E_REVOCATION_OFFLINE }, + { CERT_TRUST_REVOCATION_STATUS_UNKNOWN | CERT_TRUST_IS_OFFLINE_REVOCATION, 0, CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG, 0, CRYPT_E_REVOCATION_OFFLINE }, + { CERT_TRUST_REVOCATION_STATUS_UNKNOWN | CERT_TRUST_IS_OFFLINE_REVOCATION, 0, CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG, 0, CRYPT_E_REVOCATION_OFFLINE }, + /* CERT_TRUST_IS_OFFLINE_REVOCATION is ignored. */ + { CERT_TRUST_IS_OFFLINE_REVOCATION, 0, 0, 0, ERROR_SUCCESS }, + { CERT_TRUST_IS_OFFLINE_REVOCATION, 1, 0, 0, ERROR_SUCCESS }, + { CERT_TRUST_IS_OFFLINE_REVOCATION, 2, 0, 0, ERROR_SUCCESS }, + { CERT_TRUST_REVOCATION_STATUS_UNKNOWN, 0, 0, 0, CRYPT_E_REVOCATION_OFFLINE }, + /* CERT_TRUST_REVOCATION_STATUS_UNKNOWN is only checked on the end certificate. */ + { CERT_TRUST_REVOCATION_STATUS_UNKNOWN, 1, 0, 0, ERROR_SUCCESS }, + { CERT_TRUST_REVOCATION_STATUS_UNKNOWN, 2, 0, 0, ERROR_SUCCESS }, + { CERT_TRUST_REVOCATION_STATUS_UNKNOWN, 0, CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG, 0, 0 }, + + { CERT_TRUST_IS_REVOKED, 0, 0, 0, CRYPT_E_REVOKED }, + { CERT_TRUST_IS_REVOKED, 1, 0, 0, CRYPT_E_REVOKED }, + { CERT_TRUST_IS_REVOKED, 2, 0, 0, CRYPT_E_REVOKED }, + + { CERT_TRUST_IS_NOT_VALID_FOR_USAGE, 0, 0, 0, CERT_E_WRONG_USAGE }, + { CERT_TRUST_IS_NOT_VALID_FOR_USAGE, 1, 0, 0, CERT_E_WRONG_USAGE }, + { CERT_TRUST_IS_NOT_VALID_FOR_USAGE, 2, 0, 0, CERT_E_WRONG_USAGE }, + { CERT_TRUST_IS_NOT_VALID_FOR_USAGE, 0, 0, SECURITY_FLAG_IGNORE_WRONG_USAGE, ERROR_SUCCESS }, + { CERT_TRUST_IS_NOT_VALID_FOR_USAGE, 0, CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG, 0, ERROR_SUCCESS }, + + { CERT_TRUST_IS_SELF_SIGNED, 0, 0, 0, TRUST_E_CERT_SIGNATURE }, + { CERT_TRUST_IS_SELF_SIGNED, 1, 0, 0, TRUST_E_CERT_SIGNATURE }, + { CERT_TRUST_IS_SELF_SIGNED, 2, 0, 0, TRUST_E_CERT_SIGNATURE }, + { CERT_TRUST_IS_SELF_SIGNED, 2, 0, SECURITY_FLAG_IGNORE_UNKNOWN_CA, TRUST_E_CERT_SIGNATURE }, + { CERT_TRUST_IS_SELF_SIGNED, 2, CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG, 0, TRUST_E_CERT_SIGNATURE }, + }; + + BOOL ret; + PCCERT_CONTEXT cert; + CERT_CHAIN_PARA para = { 0 }; + PCCERT_CHAIN_CONTEXT chain; + FILETIME fileTime; + HCERTSTORE store; + static char one_two_three[] = "1.2.3"; + LPSTR oids[1]; + SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_para; + CERT_CHAIN_POLICY_PARA policy_para; + CERT_CHAIN_POLICY_STATUS status; + CERT_REVOCATION_INFO rev_info[3]; + unsigned int i; + + store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); + CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, geotrust_global_ca, + sizeof(geotrust_global_ca), CERT_STORE_ADD_ALWAYS, NULL); + CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, google_internet_authority, + sizeof(google_internet_authority), CERT_STORE_ADD_ALWAYS, NULL); + cert = CertCreateCertificateContext(X509_ASN_ENCODING, google_com, sizeof(google_com)); + SystemTimeToFileTime(&oct2009, &fileTime); + memset(¶, 0, sizeof(para)); + para.cbSize = sizeof(para); + oids[0] = one_two_three; + para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; + para.RequestedUsage.Usage.rgpszUsageIdentifier = oids; + para.RequestedUsage.Usage.cUsageIdentifier = 1; + ret = CertGetCertificateChain(NULL, cert, &fileTime, store, ¶, CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY, NULL, &chain); + ok(ret, "got error %#lx.\n", GetLastError()); + ok(chain->cChain == 1, "got %lu.\n", chain->cChain); + ok(chain->rgpChain[0]->cElement == 3, "got %lu.\n", chain->rgpChain[0]->cElement); + + memset(&policy_para, 0, sizeof(policy_para)); + policy_para.cbSize = sizeof(policy_para); + memset(&ssl_para, 0, sizeof(ssl_para)); + ssl_para.cbSize = sizeof(ssl_para); + ssl_para.dwAuthType = AUTHTYPE_SERVER; + ssl_para.pwszServerName = (WCHAR *)L"www.google.com"; + policy_para.pvExtraPolicyPara = &ssl_para; + status.cbSize = sizeof(status); + + for (i = 0; i < chain->rgpChain[0]->cElement; ++i) + { + chain->rgpChain[0]->rgpElement[i]->TrustStatus.dwErrorStatus = 0; + memset(&rev_info[i], 0, sizeof(rev_info[i])); + rev_info[i].cbSize = sizeof(rev_info); + chain->rgpChain[0]->rgpElement[i]->pRevocationInfo = &rev_info[i]; + } + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("test %u", i); + *(DWORD *)&chain->TrustStatus.dwErrorStatus = tests[i].trust_status; + chain->rgpChain[0]->TrustStatus.dwErrorStatus = chain->TrustStatus.dwErrorStatus; + chain->rgpChain[0]->rgpElement[tests[i].index]->TrustStatus.dwErrorStatus = chain->TrustStatus.dwErrorStatus; + policy_para.dwFlags = tests[i].policy_flags; + ssl_para.cbSize = sizeof(ssl_para); + ssl_para.fdwChecks = tests[i].ssl_policy_flags; + policy_para.pvExtraPolicyPara = &ssl_para; + ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain, &policy_para, &status); + ok(ret, "got error %#lx.\n", GetLastError()); + ok(status.dwError == tests[i].expected_error, "got %#lx, expected %#lx.\n", status.dwError, tests[i].expected_error); + if (status.dwError) + { + ok(!status.lChainIndex, "got %ld.\n", status.lChainIndex); + ok(status.lElementIndex == tests[i].index, "got %ld.\n", status.lElementIndex); + } + else + { + ok(status.lChainIndex == -1, "got %ld.\n", status.lChainIndex); + ok(status.lElementIndex == -1, "got %ld.\n", status.lElementIndex); + } + chain->rgpChain[0]->rgpElement[tests[i].index]->TrustStatus.dwErrorStatus = 0; + winetest_pop_context(); + } + for (i = 0; i < chain->rgpChain[0]->cElement; ++i) + chain->rgpChain[0]->rgpElement[i]->pRevocationInfo = NULL; + + CertFreeCertificateChain(chain); + CertFreeCertificateContext(cert); + CertCloseStore(store, 0); +} + START_TEST(chain) { testCreateCertChainEngine(); testVerifyCertChainPolicy(); testGetCertChain(); test_CERT_CHAIN_PARA_cbSize(); + test_VerifyCertChainPolicy_flags(); } diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c index b5db9cf7d0d3..c6c461999e6e 100644 --- a/dlls/crypt32/tests/encode.c +++ b/dlls/crypt32/tests/encode.c @@ -8847,6 +8847,7 @@ static const BYTE ocsp_basic_signed_response_with_cert[] = static void test_decodeOCSPBasicSignedResponseInfo(DWORD dwEncoding) { OCSP_BASIC_SIGNED_RESPONSE_INFO *info; + OCSP_BASIC_RESPONSE_INFO *b; DWORD size; BOOL ret; @@ -8875,12 +8876,25 @@ static void test_decodeOCSPBasicSignedResponseInfo(DWORD dwEncoding) ok(!info->SignatureInfo.cCertEncoded, "got %lu\n", info->SignatureInfo.cCertEncoded); ok(!info->SignatureInfo.rgCertEncoded, "got %p\n", info->SignatureInfo.rgCertEncoded); + + + ret = CryptDecodeObjectEx(dwEncoding, OCSP_BASIC_RESPONSE, info->ToBeSigned.pbData, info->ToBeSigned.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, &b, &size); + ok(ret, "got %08lx\n", GetLastError()); + ok(!b->cExtension, "got %lu.\n", b->cExtension); + LocalFree(b); LocalFree(info); size = 0; ret = CryptDecodeObjectEx(dwEncoding, OCSP_BASIC_SIGNED_RESPONSE, ocsp_basic_signed_response_with_cert, sizeof(ocsp_basic_signed_response_with_cert), CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); ok(ret, "got %08lx\n", GetLastError()); + + ret = CryptDecodeObjectEx(dwEncoding, OCSP_BASIC_RESPONSE, info->ToBeSigned.pbData, info->ToBeSigned.cbData, + CRYPT_DECODE_ALLOC_FLAG, NULL, &b, &size); + ok(ret, "got %08lx\n", GetLastError()); + ok(b->cExtension == 1, "got %lu.\n", b->cExtension); + LocalFree(b); LocalFree(info); } diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c index fa48d978e178..ef9c05d46f49 100644 --- a/dlls/crypt32/tests/msg.c +++ b/dlls/crypt32/tests/msg.c @@ -2808,6 +2808,17 @@ static void test_decode_msg_get_param(void) compare_signer_info((CMSG_SIGNER_INFO *)buf, &signer); CryptMemFree(buf); } + size = 0; + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, NULL, &size); + ok(!ret, "CryptMsgGetParam succeeded unexpectedly\n"); + ok(GetLastError() == CRYPT_E_ATTRIBUTES_MISSING, "unexpected error %08lx\n", GetLastError()); + ok(size == 0, "unexpected size: %lu\n", size); + SetLastError(0xdeadbeef); + ret = CryptMsgGetParam(msg, CMSG_SIGNER_AUTH_ATTR_PARAM, 0, NULL, &size); + ok(!ret, "CryptMsgGetParam succeeded unexpectedly\n"); + ok(GetLastError() == CRYPT_E_ATTRIBUTES_MISSING, "unexpected error %08lx\n", GetLastError()); + ok(size == 0, "unexpected size: %lu\n", size); /* Getting the CMS signer info of a PKCS7 message is possible. */ size = 0; ret = CryptMsgGetParam(msg, CMSG_CMS_SIGNER_INFO_PARAM, 0, NULL, &size); diff --git a/dlls/crypt32/unixlib.c b/dlls/crypt32/unixlib.c index 5a255442fdff..5e65302ac9a1 100644 --- a/dlls/crypt32/unixlib.c +++ b/dlls/crypt32/unixlib.c @@ -625,6 +625,7 @@ static const char * const CRYPT_knownLocations[] = { static void load_root_certs(void) { + const char *additional_dir; unsigned int i; #ifdef __APPLE__ @@ -662,6 +663,9 @@ static void load_root_certs(void) for (i = 0; i < ARRAY_SIZE(CRYPT_knownLocations) && list_empty(&root_cert_list); i++) import_certs_from_path( CRYPT_knownLocations[i], TRUE ); + + if ((additional_dir = getenv( "WINE_ADDITIONAL_CERTS_DIR" ))) + import_certs_from_path( additional_dir, TRUE ); } static NTSTATUS enum_root_certs( void *args ) diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c index 1068dd268685..1200416af583 100644 --- a/dlls/cryptnet/cryptnet_main.c +++ b/dlls/cryptnet/cryptnet_main.c @@ -2028,11 +2028,12 @@ static DWORD handle_ocsp_response(const CERT_INFO *cert, const CERT_INFO *issuer static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WCHAR *base_url, const CERT_REVOCATION_PARA *revpara, FILETIME *next_update) { - HINTERNET ses, con, req = NULL; + HINTERNET ses = NULL, con = NULL, req = NULL; BYTE *request_data = NULL, *response_data = NULL; - DWORD size, flags, status, request_len, response_len, count, ret = CRYPT_E_REVOCATION_OFFLINE; + DWORD size, status, request_len, response_len, count, ret = CRYPT_E_REVOCATION_OFFLINE; + DWORD flags = INTERNET_FLAG_KEEP_CONNECTION; URL_COMPONENTSW comp; - WCHAR *url; + WCHAR *url = NULL; if (!revpara || !revpara->pIssuerCert) { @@ -2043,8 +2044,11 @@ static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WC return CRYPT_E_REVOCATION_OFFLINE; url = build_request_url(base_url, request_data, request_len); - LocalFree(request_data); - if (!url) return CRYPT_E_REVOCATION_OFFLINE; + if (!url) + { + ret = CRYPT_E_REVOCATION_OFFLINE; + goto done; + } memset(&comp, 0, sizeof(comp)); comp.dwStructSize = sizeof(comp); @@ -2052,31 +2056,33 @@ static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WC comp.dwUrlPathLength = ~0u; if (!InternetCrackUrlW(url, 0, 0, &comp)) { - free(url); - return CRYPT_E_REVOCATION_OFFLINE; + ret = CRYPT_E_REVOCATION_OFFLINE; + goto done; } switch (comp.nScheme) { case INTERNET_SCHEME_HTTP: - flags = 0; break; case INTERNET_SCHEME_HTTPS: - flags = INTERNET_FLAG_SECURE; + flags |= INTERNET_FLAG_SECURE; break; default: FIXME("scheme %u not supported\n", comp.nScheme); - free(url); - return ERROR_NOT_SUPPORTED; + ret = ERROR_NOT_SUPPORTED; + goto done; } - if (!(ses = InternetOpenW(L"CryptoAPI", 0, NULL, NULL, 0))) return GetLastError(); + if (!(ses = InternetOpenW(L"CryptoAPI", 0, NULL, NULL, 0))) + { + ret = GetLastError(); + goto done; + } comp.lpszHostName[comp.dwHostNameLength] = 0; if (!(con = InternetConnectW(ses, comp.lpszHostName, comp.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0))) { - free(url); - InternetCloseHandle(ses); - return GetLastError(); + ret = GetLastError(); + goto done; } comp.lpszHostName[comp.dwHostNameLength] = '/'; if (!(req = HttpOpenRequestW(con, NULL, comp.lpszUrlPath, NULL, NULL, NULL, flags, 0)) || @@ -2084,13 +2090,40 @@ static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WC size = sizeof(status); if (!HttpQueryInfoW(req, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL)) goto done; - if (status != HTTP_STATUS_OK) + if (status == HTTP_STATUS_OK) { - WARN("request status %lu\n", status); - goto done; + size = sizeof(response_len); + if (!HttpQueryInfoW(req, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_CONTENT_LENGTH, &response_len, &size, 0) || + !response_len || !(response_data = malloc(response_len)) || + !InternetReadFile(req, response_data, response_len, &count) || count != response_len) goto done; + + ret = handle_ocsp_response(cert->pCertInfo, revpara->pIssuerCert->pCertInfo, response_data, response_len, + next_update); } + if (ret == ERROR_SUCCESS || ret == CRYPT_E_REVOKED) goto done; - size = sizeof(response_len); + WARN("GET OCSP request failed, status %lu, ret %#lx, retrying with POST.\n", status, ret); + InternetCloseHandle(req); + req = NULL; + free(response_data); + response_data = NULL; + memset(&comp, 0, sizeof(comp)); + comp.dwStructSize = sizeof(comp); + comp.dwHostNameLength = ~0u; + comp.dwUrlPathLength = ~0u; + if (!InternetCrackUrlW(base_url, 0, 0, &comp)) + { + ret = CRYPT_E_REVOCATION_OFFLINE; + goto done; + } + flags &= ~INTERNET_FLAG_KEEP_CONNECTION; + if (!(req = HttpOpenRequestW(con, L"POST", comp.lpszUrlPath, NULL, NULL, NULL, flags, 0)) || + !HttpSendRequestW(req, L"Content-Type: application/ocsp-request\0", -1, request_data, request_len)) goto done; + if (status != HTTP_STATUS_OK) + { + WARN("request status %lu.\n", status); + goto done; + } if (!HttpQueryInfoW(req, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_CONTENT_LENGTH, &response_len, &size, 0) || !response_len || !(response_data = malloc(response_len)) || !InternetReadFile(req, response_data, response_len, &count) || count != response_len) goto done; @@ -2099,6 +2132,7 @@ static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WC next_update); done: + LocalFree(request_data); free(url); free(response_data); InternetCloseHandle(req); @@ -2127,7 +2161,15 @@ static DWORD verify_cert_revocation_from_aia_ext(const CRYPT_DATA_BLOB *value, c { const WCHAR *url = aia->rgAccDescr[i].AccessLocation.pwszURL; TRACE("OCSP URL = %s\n", debugstr_w(url)); - error = verify_cert_revocation_with_ocsp(cert, url, pRevPara, next_update); + if (dwFlags & CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION) + { + TRACE("Cache only revocation, returning CRYPT_E_REVOCATION_OFFLINE.\n"); + error = CRYPT_E_REVOCATION_OFFLINE; + } + else + { + error = verify_cert_revocation_with_ocsp(cert, url, pRevPara, next_update); + } } else { diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index 75da15c99a56..f613cee47c50 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -1668,6 +1668,15 @@ static void STDMETHODCALLTYPE d2d_device_context_SetTextRenderingParams(ID2D1Dev TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params); + { + const char *sgi = getenv("SteamGameId"); + if (sgi && !strcmp(sgi, "1416260")) + { + FIXME("HACK: ignoring params.\n"); + return; + } + } + if (context->target.type == D2D_TARGET_COMMAND_LIST) d2d_command_list_set_text_rendering_params(context->target.command_list, text_rendering_params); @@ -3772,6 +3781,7 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, " if (position < p_low)\n" " return c_low;\n" "\n" + " [loop]\n" " for (i = 1; i < stop_count; ++i)\n" " {\n" " p_high = gradient.Load(i * 2).x;\n" diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index 9c5b35faafa6..b88a01814151 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -2046,6 +2046,64 @@ static void draw_color_quad_(unsigned int line, struct d3d11_test_context *conte draw_quad_vs_(line, context, vs_code, vs_code_size); } +static BOOL CALLBACK enum_first_current_thread_window_proc(HWND hwnd, LPARAM lparam) +{ + if (GetWindowThreadProcessId(hwnd, NULL) == GetCurrentThreadId()) + { + *(HWND *)lparam = hwnd; + return FALSE; + } + return TRUE; +} + +static void test_create_device_child(void) +{ + DXGI_SWAP_CHAIN_DESC swapchain_desc; + HWND hwnd, result_hwnd; + ID3D11Device *device; + HRESULT hr; + + /* Unity expects the first window in the current thread to be its game window, not DXGI device window */ + hwnd = CreateWindowW(L"static", L"", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL); + + /* Create a device without a device window in windowed mode */ + swapchain_desc.BufferDesc.Width = 800; + swapchain_desc.BufferDesc.Height = 600; + swapchain_desc.BufferDesc.RefreshRate.Numerator = 60; + swapchain_desc.BufferDesc.RefreshRate.Denominator = 60; + swapchain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + swapchain_desc.SampleDesc.Count = 1; + swapchain_desc.SampleDesc.Quality = 0; + swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapchain_desc.BufferCount = 1; + swapchain_desc.OutputWindow = NULL; + swapchain_desc.Windowed = TRUE; + swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + swapchain_desc.Flags = 0; + hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, + &swapchain_desc, NULL, &device, NULL, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + EnumWindows(enum_first_current_thread_window_proc, (LPARAM)&result_hwnd); + ok(result_hwnd == hwnd, "Got unexpected window %p.\n", result_hwnd); + + ID3D11Device_Release(device); + + /* Create a device without a device window in fullscreen mode */ + swapchain_desc.Windowed = FALSE; + hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, + &swapchain_desc, NULL, &device, NULL, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + EnumWindows(enum_first_current_thread_window_proc, (LPARAM)&result_hwnd); + ok(result_hwnd == hwnd, "Got unexpected window %p.\n", result_hwnd); + + ID3D11Device_Release(device); + DestroyWindow(hwnd); +} + static void test_create_device(void) { static const D3D_FEATURE_LEVEL default_feature_levels[] = @@ -2060,8 +2118,11 @@ static void test_create_device(void) D3D_FEATURE_LEVEL feature_level, supported_feature_level; DXGI_SWAP_CHAIN_DESC swapchain_desc, obtained_desc; ID3D11DeviceContext *immediate_context; + char **argv, cmd[MAX_PATH]; IDXGISwapChain *swapchain; + PROCESS_INFORMATION info; ID3D11Device *device; + STARTUPINFOA startup; ULONG refcount; HWND window; HRESULT hr; @@ -2268,6 +2329,19 @@ static void test_create_device(void) ok(!immediate_context, "Got unexpected immediate context pointer %p.\n", immediate_context); DestroyWindow(window); + + /* Test that creating a swapchain without a device window shouldn't create a fallback device + * window that's on top of normal windows at creation. Run the tests in a new process to avoid + * interference from windows in the current process */ + winetest_get_mainargs(&argv); + sprintf(cmd, "%s d3d11 test_create_device_child", argv[0]); + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + ok(CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info), "CreateProcess failed.\n"); + + wait_child_process(info.hProcess); + CloseHandle(info.hProcess); + CloseHandle(info.hThread); } static void test_device_interfaces(const D3D_FEATURE_LEVEL feature_level) @@ -36588,6 +36662,13 @@ START_TEST(d3d11) HMODULE wined3d; char **argv; + argc = winetest_get_mainargs(&argv); + if (argc == 3 && !strcmp(argv[2], "test_create_device_child")) + { + test_create_device_child(); + return; + } + if ((wined3d = GetModuleHandleA("wined3d.dll"))) { enum wined3d_renderer (CDECL *p_wined3d_get_renderer)(void); @@ -36604,7 +36685,6 @@ START_TEST(d3d11) if (sizeof(void *) == 4 && !strcmp(winetest_platform, "wine")) use_mt = FALSE; - argc = winetest_get_mainargs(&argv); for (i = 2; i < argc; ++i) { if (!strcmp(argv[i], "--validate")) diff --git a/dlls/d3dcompiler_43/tests/hlsl_d3d11.c b/dlls/d3dcompiler_43/tests/hlsl_d3d11.c index 309ba6b2663e..9fdd786e1aa6 100644 --- a/dlls/d3dcompiler_43/tests/hlsl_d3d11.c +++ b/dlls/d3dcompiler_43/tests/hlsl_d3d11.c @@ -1117,14 +1117,8 @@ static void test_semantic_reflection(void) { winetest_push_context("Test %u", i); - todo_wine_if (i > 6) code = compile_shader_flags(tests[i].source, tests[i].target, + code = compile_shader_flags(tests[i].source, tests[i].target, tests[i].legacy ? D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY : 0); - if (!code) - { - winetest_pop_context(); - continue; - } - hr = D3DReflect(ID3D10Blob_GetBufferPointer(code), ID3D10Blob_GetBufferSize(code), &IID_ID3D11ShaderReflection, (void **)&reflection); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); diff --git a/dlls/d3dcompiler_43/tests/hlsl_d3d9.c b/dlls/d3dcompiler_43/tests/hlsl_d3d9.c index 95ba6d286d88..3f930e53758a 100644 --- a/dlls/d3dcompiler_43/tests/hlsl_d3d9.c +++ b/dlls/d3dcompiler_43/tests/hlsl_d3d9.c @@ -1164,18 +1164,14 @@ static void test_samplers(void) { hr = IDirect3DDevice9_Clear(test_context.device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 0, 0), 1.0f, 0); ok(hr == D3D_OK, "Test %u: Got unexpected hr %#lx.\n", i, hr); - todo_wine_if (i > 2) ps_code = compile_shader(tests[i], "ps_2_0", 0); - if (ps_code) - { - draw_quad(test_context.device, ps_code); + draw_quad(test_context.device, ps_code); - v = get_color_vec4(test_context.device, 0, 0); - ok(compare_vec4(&v, 1.0f, 0.0f, 1.0f, 0.0f, 0), - "Test %u: Got unexpected value {%.8e, %.8e, %.8e, %.8e}.\n", i, v.x, v.y, v.z, v.w); + v = get_color_vec4(test_context.device, 0, 0); + ok(compare_vec4(&v, 1.0f, 0.0f, 1.0f, 0.0f, 0), + "Test %u: Got unexpected value {%.8e, %.8e, %.8e, %.8e}.\n", i, v.x, v.y, v.z, v.w); - ID3D10Blob_Release(ps_code); - } + ID3D10Blob_Release(ps_code); } IDirect3DTexture9_Release(texture); @@ -1835,7 +1831,7 @@ static void test_hlsl_double(void) #if D3D_COMPILER_VERSION >= 46 todo_wine ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); #else - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); #endif if (FAILED(hr)) { diff --git a/dlls/d3dx10_43/Makefile.in b/dlls/d3dx10_43/Makefile.in index 3d755499749d..8a0e6d182627 100644 --- a/dlls/d3dx10_43/Makefile.in +++ b/dlls/d3dx10_43/Makefile.in @@ -1,6 +1,8 @@ +EXTRADEFS = -DD3DX_D3D_VERSION=10 MODULE = d3dx10_43.dll IMPORTLIB = d3dx10 -IMPORTS = d3d10_1 d3dcompiler dxguid uuid gdi32 +IMPORTS = d3d10_1 d3dcompiler dxguid uuid gdi32 ole32 +PARENTSRC = ../d3dx9_36 DELAYIMPORTS = windowscodecs EXTRADLLFLAGS = -Wb,--prefer-native @@ -8,6 +10,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ async.c \ compiler.c \ + d3dx_helpers.c \ d3dx10_43_main.c \ font.c \ mesh.c \ diff --git a/dlls/d3dx10_43/async.c b/dlls/d3dx10_43/async.c index 626278868040..4c5c7a654371 100644 --- a/dlls/d3dx10_43/async.c +++ b/dlls/d3dx10_43/async.c @@ -88,36 +88,6 @@ static const ID3DX10DataLoaderVtbl memorydataloadervtbl = memorydataloader_Destroy }; -HRESULT load_file(const WCHAR *path, void **data, DWORD *size) -{ - DWORD read_len; - HANDLE file; - BOOL ret; - - file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (file == INVALID_HANDLE_VALUE) - return D3D10_ERROR_FILE_NOT_FOUND; - - *size = GetFileSize(file, NULL); - *data = malloc(*size); - if (!*data) - { - CloseHandle(file); - return E_OUTOFMEMORY; - } - - ret = ReadFile(file, *data, *size, &read_len, NULL); - CloseHandle(file); - if (!ret || read_len != *size) - { - WARN("Failed to read file contents.\n"); - free(*data); - return E_FAIL; - } - return S_OK; -} - static HRESULT WINAPI filedataloader_Load(ID3DX10DataLoader *iface) { struct asyncdataloader *loader = impl_from_ID3DX10DataLoader(iface); @@ -173,63 +143,6 @@ static const ID3DX10DataLoaderVtbl filedataloadervtbl = filedataloader_Destroy }; -static HRESULT load_resource_initA(HMODULE module, const char *resource, HRSRC *rsrc) -{ - if (!(*rsrc = FindResourceA(module, resource, (const char *)RT_RCDATA))) - *rsrc = FindResourceA(module, resource, (const char *)RT_BITMAP); - if (!*rsrc) - { - WARN("Failed to find resource.\n"); - return D3DX10_ERR_INVALID_DATA; - } - return S_OK; -} - -static HRESULT load_resource_initW(HMODULE module, const WCHAR *resource, HRSRC *rsrc) -{ - if (!(*rsrc = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA))) - *rsrc = FindResourceW(module, resource, (const WCHAR *)RT_BITMAP); - if (!*rsrc) - { - WARN("Failed to find resource.\n"); - return D3DX10_ERR_INVALID_DATA; - } - return S_OK; -} - -static HRESULT load_resource(HMODULE module, HRSRC rsrc, void **data, DWORD *size) -{ - HGLOBAL hglobal; - - if (!(*size = SizeofResource(module, rsrc))) - return D3DX10_ERR_INVALID_DATA; - if (!(hglobal = LoadResource(module, rsrc))) - return D3DX10_ERR_INVALID_DATA; - if (!(*data = LockResource(hglobal))) - return D3DX10_ERR_INVALID_DATA; - return S_OK; -} - -HRESULT load_resourceA(HMODULE module, const char *resource, void **data, DWORD *size) -{ - HRESULT hr; - HRSRC rsrc; - - if (FAILED((hr = load_resource_initA(module, resource, &rsrc)))) - return hr; - return load_resource(module, rsrc, data, size); -} - -HRESULT load_resourceW(HMODULE module, const WCHAR *resource, void **data, DWORD *size) -{ - HRESULT hr; - HRSRC rsrc; - - if ((FAILED(hr = load_resource_initW(module, resource, &rsrc)))) - return hr; - return load_resource(module, rsrc, data, size); -} - static HRESULT WINAPI resourcedataloader_Load(ID3DX10DataLoader *iface) { struct asyncdataloader *loader = impl_from_ID3DX10DataLoader(iface); @@ -322,6 +235,7 @@ struct texture_processor { ID3DX10DataProcessor ID3DX10DataProcessor_iface; ID3D10Device *device; + D3DX10_IMAGE_INFO img_info; D3DX10_IMAGE_LOAD_INFO load_info; D3D10_SUBRESOURCE_DATA *resource_data; }; @@ -378,6 +292,63 @@ static ID3DX10DataProcessorVtbl texture_processor_vtbl = texture_processor_Destroy }; +struct srv_processor +{ + ID3DX10DataProcessor ID3DX10DataProcessor_iface; + ID3DX10DataProcessor *texture_processor; +}; + +static inline struct srv_processor *srv_processor_from_ID3DX10DataProcessor(ID3DX10DataProcessor *iface) +{ + return CONTAINING_RECORD(iface, struct srv_processor, ID3DX10DataProcessor_iface); +} + +static HRESULT WINAPI srv_processor_Process(ID3DX10DataProcessor *iface, void *data, SIZE_T size) +{ + struct srv_processor *processor = srv_processor_from_ID3DX10DataProcessor(iface); + + TRACE("iface %p, data %p, size %Iu.\n", iface, data, size); + + return ID3DX10DataProcessor_Process(processor->texture_processor, data, size); +} + +static HRESULT WINAPI srv_processor_CreateDeviceObject(ID3DX10DataProcessor *iface, void **object) +{ + struct srv_processor *processor = srv_processor_from_ID3DX10DataProcessor(iface); + struct texture_processor *tex_processor = texture_processor_from_ID3DX10DataProcessor(processor->texture_processor); + ID3D10Resource *texture_resource; + HRESULT hr; + + TRACE("iface %p, object %p.\n", iface, object); + + hr = ID3DX10DataProcessor_CreateDeviceObject(processor->texture_processor, (void **)&texture_resource); + if (FAILED(hr)) + return hr; + + hr = ID3D10Device_CreateShaderResourceView(tex_processor->device, texture_resource, NULL, + (ID3D10ShaderResourceView **)object); + ID3D10Resource_Release(texture_resource); + return hr; +} + +static HRESULT WINAPI srv_processor_Destroy(ID3DX10DataProcessor *iface) +{ + struct srv_processor *processor = srv_processor_from_ID3DX10DataProcessor(iface); + + TRACE("iface %p.\n", iface); + + ID3DX10DataProcessor_Destroy(processor->texture_processor); + free(processor); + return S_OK; +} + +static ID3DX10DataProcessorVtbl srv_processor_vtbl = +{ + srv_processor_Process, + srv_processor_CreateDeviceObject, + srv_processor_Destroy +}; + HRESULT WINAPI D3DX10CompileFromMemory(const char *data, SIZE_T data_size, const char *filename, const D3D10_SHADER_MACRO *defines, ID3D10Include *include, const char *entry_point, const char *target, UINT sflags, UINT eflags, ID3DX10ThreadPump *pump, ID3D10Blob **shader, @@ -595,7 +566,35 @@ HRESULT WINAPI D3DX10CreateAsyncTextureProcessor(ID3D10Device *device, object->device = device; ID3D10Device_AddRef(device); init_load_info(load_info, &object->load_info); + if (!object->load_info.pSrcInfo) + object->load_info.pSrcInfo = &object->img_info; + + *processor = &object->ID3DX10DataProcessor_iface; + return S_OK; +} + +HRESULT WINAPI D3DX10CreateAsyncShaderResourceViewProcessor(ID3D10Device *device, + D3DX10_IMAGE_LOAD_INFO *load_info, ID3DX10DataProcessor **processor) +{ + struct srv_processor *object; + HRESULT hr; + + TRACE("device %p, load_info %p, processor %p.\n", device, load_info, processor); + + if (!device || !processor) + return E_INVALIDARG; + + object = calloc(1, sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + hr = D3DX10CreateAsyncTextureProcessor(device, load_info, &object->texture_processor); + if (FAILED(hr)) + { + free(object); + return hr; + } + object->ID3DX10DataProcessor_iface.lpVtbl = &srv_processor_vtbl; *processor = &object->ID3DX10DataProcessor_iface; return S_OK; } diff --git a/dlls/d3dx10_43/d3dx10_43.spec b/dlls/d3dx10_43/d3dx10_43.spec index 2359c7c6f02b..fb753183f9ce 100644 --- a/dlls/d3dx10_43/d3dx10_43.spec +++ b/dlls/d3dx10_43/d3dx10_43.spec @@ -15,7 +15,7 @@ @ stdcall D3DX10CreateAsyncResourceLoaderA(long str ptr) @ stdcall D3DX10CreateAsyncResourceLoaderW(long wstr ptr) @ stub D3DX10CreateAsyncShaderPreprocessProcessor(str ptr ptr ptr ptr ptr) -@ stub D3DX10CreateAsyncShaderResourceViewProcessor(ptr ptr ptr) +@ stdcall D3DX10CreateAsyncShaderResourceViewProcessor(ptr ptr ptr) @ stdcall D3DX10CreateAsyncTextureInfoProcessor(ptr ptr) @ stdcall D3DX10CreateAsyncTextureProcessor(ptr ptr ptr) @ stdcall D3DX10CreateDevice(ptr long long long ptr) @@ -35,11 +35,11 @@ @ stdcall D3DX10CreateFontIndirectW(ptr ptr ptr) @ stdcall D3DX10CreateFontW(ptr long long long long long long long long long wstr ptr) @ stdcall D3DX10CreateMesh(ptr ptr long str long long long ptr) -@ stub D3DX10CreateShaderResourceViewFromFileA(ptr str ptr ptr ptr ptr) -@ stub D3DX10CreateShaderResourceViewFromFileW(ptr wstr ptr ptr ptr ptr) -@ stub D3DX10CreateShaderResourceViewFromMemory(ptr ptr long ptr ptr ptr ptr) -@ stub D3DX10CreateShaderResourceViewFromResourceA(ptr long str ptr ptr ptr ptr) -@ stub D3DX10CreateShaderResourceViewFromResourceW(ptr long wstr ptr ptr ptr ptr) +@ stdcall D3DX10CreateShaderResourceViewFromFileA(ptr str ptr ptr ptr ptr) +@ stdcall D3DX10CreateShaderResourceViewFromFileW(ptr wstr ptr ptr ptr ptr) +@ stdcall D3DX10CreateShaderResourceViewFromMemory(ptr ptr long ptr ptr ptr ptr) +@ stdcall D3DX10CreateShaderResourceViewFromResourceA(ptr long str ptr ptr ptr ptr) +@ stdcall D3DX10CreateShaderResourceViewFromResourceW(ptr long wstr ptr ptr ptr ptr) @ stub D3DX10CreateSkinInfo(ptr) @ stdcall D3DX10CreateSprite(ptr long ptr) @ stdcall D3DX10CreateTextureFromFileA(ptr str ptr ptr ptr ptr) @@ -61,9 +61,9 @@ @ stub D3DX10PreprocessShaderFromResourceA(long str str ptr ptr ptr ptr ptr) @ stub D3DX10PreprocessShaderFromResourceW(long wstr wstr ptr ptr ptr ptr ptr) @ stub D3DX10SHProjectCubeMap(long ptr ptr ptr ptr) -@ stub D3DX10SaveTextureToFileA(ptr ptr str) -@ stub D3DX10SaveTextureToFileW(ptr ptr wstr) -@ stub D3DX10SaveTextureToMemory(ptr ptr ptr long) +@ stdcall D3DX10SaveTextureToFileA(ptr ptr str) +@ stdcall D3DX10SaveTextureToFileW(ptr ptr wstr) +@ stdcall D3DX10SaveTextureToMemory(ptr ptr ptr long) @ stdcall D3DX10UnsetAllDeviceObjects(ptr) @ stdcall D3DXBoxBoundProbe(ptr ptr ptr ptr) d3dx9_36.D3DXBoxBoundProbe @ stdcall D3DXColorAdjustContrast(ptr ptr float) d3dx9_36.D3DXColorAdjustContrast diff --git a/dlls/d3dx10_43/d3dx10_43_main.c b/dlls/d3dx10_43/d3dx10_43_main.c index ec7407508d30..9e44714fc6dd 100644 --- a/dlls/d3dx10_43/d3dx10_43_main.c +++ b/dlls/d3dx10_43/d3dx10_43_main.c @@ -148,13 +148,6 @@ HRESULT WINAPI D3DX10CreateDeviceAndSwapChain(IDXGIAdapter *adapter, D3D10_DRIVE D3D10_1_SDK_VERSION, desc, swapchain, (ID3D10Device1 **)device); } -HRESULT WINAPI D3DX10FilterTexture(ID3D10Resource *texture, UINT src_level, UINT filter) -{ - FIXME("texture %p, src_level %u, filter %#x stub!\n", texture, src_level, filter); - - return E_NOTIMPL; -} - HRESULT WINAPI D3DX10GetFeatureLevel1(ID3D10Device *device, ID3D10Device1 **device1) { TRACE("device %p, device1 %p.\n", device, device1); @@ -168,11 +161,3 @@ D3DX_CPU_OPTIMIZATION WINAPI D3DXCpuOptimizations(BOOL enable) return D3DX_NOT_OPTIMIZED; } - -HRESULT WINAPI D3DX10LoadTextureFromTexture(ID3D10Resource *src_texture, D3DX10_TEXTURE_LOAD_INFO *load_info, - ID3D10Resource *dst_texture) -{ - FIXME("src_texture %p, load_info %p, dst_texture %p stub!\n", src_texture, load_info, dst_texture); - - return E_NOTIMPL; -} diff --git a/dlls/d3dx10_43/dxhelpers.h b/dlls/d3dx10_43/dxhelpers.h index 50d509973cda..ae44c836482e 100644 --- a/dlls/d3dx10_43/dxhelpers.h +++ b/dlls/d3dx10_43/dxhelpers.h @@ -16,11 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -extern HRESULT load_file(const WCHAR *path, void **data, DWORD *size); -extern HRESULT load_resourceA(HMODULE module, const char *resource, - void **data, DWORD *size); -extern HRESULT load_resourceW(HMODULE module, const WCHAR *resource, - void **data, DWORD *size); +#include "../d3dx9_36/d3dx_helpers.h" extern HRESULT get_image_info(const void *data, SIZE_T size, D3DX10_IMAGE_INFO *img_info); diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c index f7f2e2e32f8f..52eebc355736 100644 --- a/dlls/d3dx10_43/tests/d3dx10.c +++ b/dlls/d3dx10_43/tests/d3dx10.c @@ -18,9 +18,12 @@ #define COBJMACROS #include "initguid.h" +#include "wincodec.h" #include "d3d10_1.h" #include "d3dx10.h" +#include "wine/wined3d.h" #include "wine/test.h" +#include #define D3DERR_INVALIDCALL 0x8876086c @@ -38,20 +41,39 @@ #define DDS_PIXELFORMAT 0x00001000 #define DDS_MIPMAPCOUNT 0x00020000 #define DDS_LINEARSIZE 0x00080000 +#define DDS_DEPTH 0x00800000 /* dds_header.caps */ #define DDSCAPS_ALPHA 0x00000002 +#define DDS_CAPS_COMPLEX 0x00000008 #define DDS_CAPS_TEXTURE 0x00001000 +#define DDSCAPS_MIPMAP 0x00400000 + +/* dds_header.caps2 */ +#define DDS_CAPS2_VOLUME 0x00200000 +#define DDS_CAPS2_CUBEMAP 0x00000200 +#define DDS_CAPS2_CUBEMAP_POSITIVEX 0x00000400 +#define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x00000800 +#define DDS_CAPS2_CUBEMAP_POSITIVEY 0x00001000 +#define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x00002000 +#define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x00004000 +#define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x00008000 +#define DDS_CAPS2_CUBEMAP_ALL_FACES ( DDS_CAPS2_CUBEMAP_POSITIVEX | DDS_CAPS2_CUBEMAP_NEGATIVEX \ + | DDS_CAPS2_CUBEMAP_POSITIVEY | DDS_CAPS2_CUBEMAP_NEGATIVEY \ + | DDS_CAPS2_CUBEMAP_POSITIVEZ | DDS_CAPS2_CUBEMAP_NEGATIVEZ ) /* dds_pixel_format.flags */ #define DDS_PF_ALPHA 0x00000001 #define DDS_PF_ALPHA_ONLY 0x00000002 #define DDS_PF_FOURCC 0x00000004 +#define DDS_PF_INDEXED 0x00000020 #define DDS_PF_RGB 0x00000040 #define DDS_PF_LUMINANCE 0x00020000 #define DDS_PF_BUMPLUMINANCE 0x00040000 #define DDS_PF_BUMPDUDV 0x00080000 +static bool wined3d_opengl; + struct dds_pixel_format { DWORD size; @@ -82,6 +104,16 @@ struct dds_header DWORD reserved2; }; +#define DDS_RESOURCE_MISC_TEXTURECUBE 0x04 +struct dds_header_dxt10 +{ + uint32_t dxgi_format; + uint32_t resource_dimension; + uint32_t misc_flag; + uint32_t array_size; + uint32_t misc_flags2; +}; + static void fill_dds_header(struct dds_header *header) { memset(header, 0, sizeof(*header)); @@ -102,6 +134,35 @@ static void fill_dds_header(struct dds_header *header) header->caps = DDS_CAPS_TEXTURE; } +static void set_dxt10_dds_header(struct dds_header *header, uint32_t append_flags, uint32_t width, uint32_t height, + uint32_t depth, uint32_t mip_levels, uint32_t pitch, uint32_t caps, uint32_t caps2) +{ + memset(header, 0, sizeof(*header)); + + header->size = sizeof(*header); + header->flags = DDS_CAPS | DDS_PIXELFORMAT | append_flags; + header->height = height; + header->width = width; + header->depth = depth; + header->miplevels = mip_levels; + header->pitch_or_linear_size = pitch; + header->pixel_format.size = sizeof(header->pixel_format); + header->pixel_format.flags = DDS_PF_FOURCC; + header->pixel_format.fourcc = MAKEFOURCC('D','X','1','0'); + header->caps = caps; + header->caps2 = caps2; +} + +static void set_dds_header_dxt10(struct dds_header_dxt10 *dxt10, DXGI_FORMAT format, uint32_t resource_dimension, + uint32_t misc_flag, uint32_t array_size, uint32_t misc_flags2) +{ + dxt10->dxgi_format = format; + dxt10->resource_dimension = resource_dimension; + dxt10->misc_flag = misc_flag; + dxt10->array_size = array_size; + dxt10->misc_flags2 = misc_flags2; +} + /* 1x1 1bpp bmp image */ static const BYTE test_bmp_1bpp[] = { @@ -676,6 +737,68 @@ static const BYTE test_dds_volume_data[] = 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x87, 0x0f, 0x78, 0x05, 0x05, 0x50, 0x50, }; +/* + * 4x4x4 24-bit volume dds, 3 mipmaps. Level 0 is red, level 1 is green, level 2 is + * blue. + */ +static const uint8_t dds_volume_24bit_4_4_4[] = +{ + 0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x0f,0x10,0x82,0x00,0x04,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00, + 0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0x00 +}; + +/* + * 8x8 24-bit dds, 4 mipmaps. Level 0 is red, level 1 is green, level 2 is + * blue, and level 3 is black. + */ +static const uint8_t dds_24bit_8_8[] = +{ + 0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x0a,0x00,0x08,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00 +}; + /* 1x1 wmp image */ static const BYTE test_wmp[] = { @@ -737,135 +860,316 @@ static const struct test_image unsigned int size; const BYTE *expected_data; D3DX10_IMAGE_INFO expected_info; + D3D10_SRV_DIMENSION expected_srv_dimension; } test_image[] = { { test_bmp_1bpp, sizeof(test_bmp_1bpp), test_bmp_1bpp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_bmp_4bpp, sizeof(test_bmp_4bpp), test_bmp_4bpp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_bmp_8bpp, sizeof(test_bmp_8bpp), test_bmp_8bpp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_bmp_16bpp, sizeof(test_bmp_16bpp), test_bmp_16bpp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_bmp_24bpp, sizeof(test_bmp_24bpp), test_bmp_24bpp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_bmp_32bpp_xrgb, sizeof(test_bmp_32bpp_xrgb), test_bmp_32bpp_xrgb_data, - {2, 2, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP} + {2, 2, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_bmp_32bpp_argb, sizeof(test_bmp_32bpp_argb), test_bmp_32bpp_argb_data, - {2, 2, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP} + {2, 2, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_BMP}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_png_8bpp_gray, sizeof(test_png_8bpp_gray), test_png_8bpp_gray_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_PNG} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_PNG}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_jpg, sizeof(test_jpg), test_jpg_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_JPG} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_JPG}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_gif, sizeof(test_gif), test_gif_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_GIF} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_GIF}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_tiff, sizeof(test_tiff), test_tiff_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_TIFF} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_TIFF}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_alpha, sizeof(test_dds_alpha), test_dds_alpha_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_luminance, sizeof(test_dds_luminance), test_dds_luminance_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_16bpp, sizeof(test_dds_16bpp), test_dds_16bpp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_24bpp, sizeof(test_dds_24bpp), test_dds_24bpp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_32bpp, sizeof(test_dds_32bpp), test_dds_32bpp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_64bpp, sizeof(test_dds_64bpp), test_dds_64bpp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R16G16B16A16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R16G16B16A16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_96bpp, sizeof(test_dds_96bpp), test_dds_96bpp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R32G32B32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R32G32B32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_128bpp, sizeof(test_dds_128bpp), test_dds_128bpp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R32G32B32A32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R32G32B32A32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_dxt1, sizeof(test_dds_dxt1), test_dds_dxt1_data, - {4, 4, 1, 1, 1, 0, DXGI_FORMAT_BC1_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {4, 4, 1, 1, 1, 0, DXGI_FORMAT_BC1_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_dxt1_4x8, sizeof(test_dds_dxt1_4x8), test_dds_dxt1_4x8_data, - {4, 8, 1, 1, 4, 0, DXGI_FORMAT_BC1_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {4, 8, 1, 1, 4, 0, DXGI_FORMAT_BC1_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_dxt2, sizeof(test_dds_dxt2), test_dds_dxt2_data, - {4, 4, 1, 1, 3, 0, DXGI_FORMAT_BC2_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {4, 4, 1, 1, 3, 0, DXGI_FORMAT_BC2_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_dxt3, sizeof(test_dds_dxt3), test_dds_dxt3_data, - {1, 3, 1, 1, 2, 0, DXGI_FORMAT_BC2_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {1, 3, 1, 1, 2, 0, DXGI_FORMAT_BC2_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_dxt4, sizeof(test_dds_dxt4), test_dds_dxt4_data, - {4, 4, 1, 1, 3, 0, DXGI_FORMAT_BC3_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {4, 4, 1, 1, 3, 0, DXGI_FORMAT_BC3_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_dxt5, sizeof(test_dds_dxt5), test_dds_dxt5_data, - {4, 2, 1, 1, 1, 0, DXGI_FORMAT_BC3_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {4, 2, 1, 1, 1, 0, DXGI_FORMAT_BC3_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_dxt5_8x8, sizeof(test_dds_dxt5_8x8), test_dds_dxt5_8x8_data, - {8, 8, 1, 1, 4, 0, DXGI_FORMAT_BC3_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {8, 8, 1, 1, 4, 0, DXGI_FORMAT_BC3_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_bc4, sizeof(test_dds_bc4), test_dds_bc4_data, - {4, 4, 1, 1, 3, 0, DXGI_FORMAT_BC4_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {4, 4, 1, 1, 3, 0, DXGI_FORMAT_BC4_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_bc5, sizeof(test_dds_bc5), test_dds_bc5_data, - {6, 3, 1, 1, 3, 0, DXGI_FORMAT_BC5_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {6, 3, 1, 1, 3, 0, DXGI_FORMAT_BC5_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE2D }, { test_dds_cube, sizeof(test_dds_cube), test_dds_cube_data, - {4, 4, 1, 6, 3, 0x4, DXGI_FORMAT_BC1_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS} + {4, 4, 1, 6, 3, 0x4, DXGI_FORMAT_BC1_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURECUBE }, { test_dds_volume, sizeof(test_dds_volume), test_dds_volume_data, - {4, 4, 2, 1, 3, 0, DXGI_FORMAT_BC2_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, D3DX10_IFF_DDS} + {4, 4, 2, 1, 3, 0, DXGI_FORMAT_BC2_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, D3DX10_IFF_DDS}, + D3D10_SRV_DIMENSION_TEXTURE3D }, { test_wmp, sizeof(test_wmp), test_wmp_data, - {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_WMP} + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_WMP}, + D3D10_SRV_DIMENSION_TEXTURE2D + }, +}; + +static const struct test_image_load_info +{ + const uint8_t *data; + uint32_t size; + D3DX10_IMAGE_LOAD_INFO load_info; + HRESULT expected_hr; + + D3D10_SRV_DIMENSION expected_srv_dimension; + D3D10_RESOURCE_DIMENSION expected_type; + union + { + D3D10_TEXTURE2D_DESC desc_2d; + D3D10_TEXTURE3D_DESC desc_3d; + } expected_resource_desc; + D3DX10_IMAGE_INFO expected_info; + BOOL todo_resource_desc; +} +test_image_load_info[] = +{ + /* + * FirstMipLevel set to 1 - Does not match D3DX_SKIP_DDS_MIP_LEVELS + * behavior from d3dx9, image info values represent mip level 0, and + * texture values are pulled from this. The texture data is loaded + * starting from the specified mip level, however. + */ + { + dds_volume_24bit_4_4_4, sizeof(dds_volume_24bit_4_4_4), + { D3DX10_FROM_FILE, D3DX10_DEFAULT, 0, 1, D3DX10_DEFAULT, (D3D10_USAGE)D3DX10_DEFAULT, + D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT }, + S_OK, D3D10_SRV_DIMENSION_TEXTURE3D, D3D10_RESOURCE_DIMENSION_TEXTURE3D, + { .desc_3d = { 4, 4, 4, 3, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 } }, + { 4, 4, 4, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, D3DX10_IFF_DDS }, + }, + /* + * Autogen mips misc flag specified. In the case of a cube texture image, + * the autogen mips flag is OR'd against D3D10_RESOURCE_MISC_TEXTURECUBE, + * even if it isn't specified. + */ + { + test_dds_cube, sizeof(test_dds_cube), + { D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, (D3D10_USAGE)D3DX10_DEFAULT, + (D3D10_BIND_SHADER_RESOURCE | D3D10_BIND_RENDER_TARGET), D3DX10_DEFAULT, D3D10_RESOURCE_MISC_GENERATE_MIPS, + DXGI_FORMAT_R8G8B8A8_UNORM, D3DX10_DEFAULT, D3DX10_DEFAULT }, + S_OK, D3D10_SRV_DIMENSION_TEXTURECUBE, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + { .desc_2d = { 4, 4, 3, 6, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, + (D3D10_BIND_SHADER_RESOURCE | D3D10_BIND_RENDER_TARGET), 0, + (D3D10_RESOURCE_MISC_GENERATE_MIPS | D3D10_RESOURCE_MISC_TEXTURECUBE) } }, + { 4, 4, 1, 6, 3, DDS_RESOURCE_MISC_TEXTURECUBE, DXGI_FORMAT_BC1_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3DX10_IFF_DDS }, + }, + /* + * Even with the autogen mips misc flag specified, the mip levels argument + * of load info is respected. + */ + { + test_dds_cube, sizeof(test_dds_cube), + { D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, 2, (D3D10_USAGE)D3DX10_DEFAULT, + (D3D10_BIND_SHADER_RESOURCE | D3D10_BIND_RENDER_TARGET), D3DX10_DEFAULT, D3D10_RESOURCE_MISC_GENERATE_MIPS, + DXGI_FORMAT_R8G8B8A8_UNORM, D3DX10_DEFAULT, D3DX10_DEFAULT }, + S_OK, D3D10_SRV_DIMENSION_TEXTURECUBE, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + { .desc_2d = { 4, 4, 2, 6, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, + (D3D10_BIND_SHADER_RESOURCE | D3D10_BIND_RENDER_TARGET), 0, + (D3D10_RESOURCE_MISC_GENERATE_MIPS | D3D10_RESOURCE_MISC_TEXTURECUBE) } }, + { 4, 4, 1, 6, 3, DDS_RESOURCE_MISC_TEXTURECUBE, DXGI_FORMAT_BC1_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3DX10_IFF_DDS }, + }, +}; + +static const struct test_invalid_image_load_info +{ + const uint8_t *data; + uint32_t size; + D3DX10_IMAGE_LOAD_INFO load_info; + HRESULT expected_hr; + HRESULT expected_process_hr; + HRESULT expected_create_device_object_hr; + BOOL todo_hr; + BOOL todo_process_hr; + BOOL todo_create_device_object_hr; +} +test_invalid_image_load_info[] = +{ + /* + * A depth value that isn't D3DX10_FROM_FILE/D3DX10_DEFAULT/0 on a 2D + * texture results in failure. + */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX10_DEFAULT, D3DX10_DEFAULT, 2, D3DX10_DEFAULT, D3DX10_DEFAULT, (D3D10_USAGE)D3DX10_DEFAULT, + D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT }, + E_FAIL, E_FAIL, + }, + /* Invalid filter value. */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, (D3D10_USAGE)D3DX10_DEFAULT, + D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, 7, D3DX10_DEFAULT }, + D3DERR_INVALIDCALL, D3DERR_INVALIDCALL, + }, + /* Invalid mipfilter value, only checked if mips are generated. */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, (D3D10_USAGE)D3DX10_DEFAULT, + D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, 7 }, + S_OK, S_OK, S_OK + }, + /* Invalid mipfilter value. */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { 2, 2, D3DX10_DEFAULT, D3DX10_DEFAULT, 2, (D3D10_USAGE)D3DX10_DEFAULT, + D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, 7 }, + D3DERR_INVALIDCALL, D3DERR_INVALIDCALL, + }, + /* + * Usage/BindFlags/CpuAccessFlags are validated in the call to + * CreateDeviceObject(). + */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3D10_CPU_ACCESS_READ, D3D10_USAGE_DYNAMIC, + D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT }, + E_INVALIDARG, S_OK, E_INVALIDARG, + }, + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3D10_USAGE_DEFAULT, + D3D10_BIND_DEPTH_STENCIL, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT }, + E_INVALIDARG, S_OK, E_INVALIDARG, + }, + /* + * D3D10_RESOURCE_MISC_GENERATE_MIPS requires binding as a shader resource + * and a render target. + */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3D10_USAGE_DEFAULT, + D3DX10_DEFAULT, D3DX10_DEFAULT, D3D10_RESOURCE_MISC_GENERATE_MIPS, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT }, + E_INVALIDARG, S_OK, E_INVALIDARG, + }, + /* Can't set the cube texture flag if the image isn't a cube texture. */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3D10_USAGE_DEFAULT, + D3DX10_DEFAULT, D3DX10_DEFAULT, D3D10_RESOURCE_MISC_TEXTURECUBE, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT }, + E_INVALIDARG, S_OK, E_INVALIDARG }, }; + static WCHAR temp_dir[MAX_PATH]; static DXGI_FORMAT block_compressed_formats[] = @@ -890,6 +1194,22 @@ static BOOL is_block_compressed(DXGI_FORMAT format) return FALSE; } +static BOOL dxgi_format_is_8bpp_rgba(DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + return TRUE; + default: + return FALSE; + } +} + static unsigned int get_bpp_from_format(DXGI_FORMAT format) { switch (format) @@ -1276,7 +1596,138 @@ static void check_image_info(D3DX10_IMAGE_INFO *image_info, const struct test_im image_info->ImageFileFormat, image->expected_info.ImageFileFormat); } -static ID3D10Texture2D *get_texture2d_readback(ID3D10Texture2D *texture) +#define check_image_info_values(info, width, height, depth, array_size, mip_levels, misc_flags, format, resource_dimension, \ + image_file_format, wine_todo) \ + check_image_info_values_(__LINE__, info, width, height, depth, array_size, mip_levels, misc_flags, format, resource_dimension, \ + image_file_format, wine_todo) +static inline void check_image_info_values_(uint32_t line, const D3DX10_IMAGE_INFO *info, uint32_t width, + uint32_t height, uint32_t depth, uint32_t array_size, uint32_t mip_levels, uint32_t misc_flags, + DXGI_FORMAT format, D3D10_RESOURCE_DIMENSION resource_dimension, D3DX10_IMAGE_FILE_FORMAT image_file_format, + BOOL wine_todo) +{ + const D3DX10_IMAGE_INFO expected_info = { width, height, depth, array_size, mip_levels, misc_flags, format, + resource_dimension, image_file_format }; + BOOL matched; + + matched = !memcmp(&expected_info, info, sizeof(*info)); + todo_wine_if(wine_todo) ok_(__FILE__, line)(matched, "Got unexpected image info values.\n"); + if (matched) + return; + + todo_wine_if(wine_todo && info->Width != width) + ok_(__FILE__, line)(info->Width == width, "Expected width %u, got %u.\n", width, info->Width); + todo_wine_if(wine_todo && info->Height != height) + ok_(__FILE__, line)(info->Height == height, "Expected height %u, got %u.\n", height, info->Height); + todo_wine_if(wine_todo && info->Depth != depth) + ok_(__FILE__, line)(info->Depth == depth, "Expected depth %u, got %u.\n", depth, info->Depth); + todo_wine_if(wine_todo && info->ArraySize != array_size) + ok_(__FILE__, line)(info->ArraySize == array_size, "Expected array_size %u, got %u.\n", array_size, + info->ArraySize); + todo_wine_if(wine_todo && info->MipLevels != mip_levels) + ok_(__FILE__, line)(info->MipLevels == mip_levels, "Expected mip_levels %u, got %u.\n", mip_levels, + info->MipLevels); + todo_wine_if(wine_todo && info->MiscFlags != misc_flags) + ok_(__FILE__, line)(info->MiscFlags == misc_flags, "Expected misc_flags %u, got %u.\n", misc_flags, + info->MiscFlags); + ok_(__FILE__, line)(info->Format == format, "Expected texture format %d, got %d.\n", format, info->Format); + todo_wine_if(wine_todo && info->ResourceDimension != resource_dimension) + ok_(__FILE__, line)(info->ResourceDimension == resource_dimension, "Expected resource_dimension %d, got %d.\n", + resource_dimension, info->ResourceDimension); + ok_(__FILE__, line)(info->ImageFileFormat == image_file_format, "Expected image_file_format %d, got %d.\n", + image_file_format, info->ImageFileFormat); +} + +#define check_texture2d_desc_values(desc, width, height, mip_levels, array_size, format, sample_count, sample_quality, \ + usage, bind_flags, cpu_access_flags, misc_flags, wine_todo) \ + check_texture2d_desc_values_(__LINE__, desc, width, height, mip_levels, array_size, format, sample_count, sample_quality, \ + usage, bind_flags, cpu_access_flags, misc_flags, wine_todo) +static inline void check_texture2d_desc_values_(uint32_t line, const D3D10_TEXTURE2D_DESC *desc, uint32_t width, + uint32_t height, uint32_t mip_levels, uint32_t array_size, DXGI_FORMAT format, uint32_t sample_count, + uint32_t sample_quality, D3D10_USAGE usage, uint32_t bind_flags, uint32_t cpu_access_flags, uint32_t misc_flags, + BOOL wine_todo) +{ + const D3D10_TEXTURE2D_DESC expected_desc = { width, height, mip_levels, array_size, format, { sample_count, sample_quality }, + usage, bind_flags, cpu_access_flags, misc_flags }; + BOOL matched; + + matched = !memcmp(&expected_desc, desc, sizeof(*desc)); + todo_wine_if(wine_todo) ok_(__FILE__, line)(matched, "Got unexpected 2D texture desc values.\n"); + if (matched) + return; + + todo_wine_if(wine_todo && desc->Width != width) + ok_(__FILE__, line)(desc->Width == width, "Expected width %u, got %u.\n", width, desc->Width); + todo_wine_if(wine_todo && desc->Height != height) + ok_(__FILE__, line)(desc->Height == height, "Expected height %u, got %u.\n", height, desc->Height); + todo_wine_if(wine_todo && desc->ArraySize != array_size) + ok_(__FILE__, line)(desc->ArraySize == array_size, "Expected array_size %u, got %u.\n", array_size, + desc->ArraySize); + todo_wine_if(wine_todo && desc->MipLevels != mip_levels) + ok_(__FILE__, line)(desc->MipLevels == mip_levels, "Expected mip_levels %u, got %u.\n", mip_levels, + desc->MipLevels); + ok_(__FILE__, line)(desc->Format == format, "Expected texture format %#x, got %#x.\n", format, desc->Format); + todo_wine_if(wine_todo && desc->SampleDesc.Count != sample_count) + ok_(__FILE__, line)(desc->SampleDesc.Count == sample_count, "Expected sample_count %u, got %u.\n", sample_count, + desc->SampleDesc.Count); + todo_wine_if(wine_todo && desc->SampleDesc.Quality != sample_quality) + ok_(__FILE__, line)(desc->SampleDesc.Quality == sample_quality, "Expected sample_quality %u, got %u.\n", sample_quality, + desc->SampleDesc.Quality); + todo_wine_if(wine_todo && desc->Usage != usage) + ok_(__FILE__, line)(desc->Usage == usage, "Expected usage %u, got %u.\n", usage, + desc->Usage); + todo_wine_if(wine_todo && desc->BindFlags != bind_flags) + ok_(__FILE__, line)(desc->BindFlags == bind_flags, "Expected bind_flags %#x, got %#x.\n", bind_flags, + desc->BindFlags); + todo_wine_if(wine_todo && desc->CPUAccessFlags != cpu_access_flags) + ok_(__FILE__, line)(desc->CPUAccessFlags == cpu_access_flags, "Expected cpu_access_flags %#x, got %#x.\n", + cpu_access_flags, desc->CPUAccessFlags); + todo_wine_if(wine_todo && desc->MiscFlags != misc_flags) + ok_(__FILE__, line)(desc->MiscFlags == misc_flags, "Expected misc_flags %#x, got %#x.\n", misc_flags, + desc->MiscFlags); +} + +#define check_texture3d_desc_values(desc, width, height, depth, mip_levels, format, usage, bind_flags, cpu_access_flags, \ + misc_flags, wine_todo) \ + check_texture3d_desc_values_(__LINE__, desc, width, height, depth, mip_levels, format, usage, bind_flags, \ + cpu_access_flags, misc_flags, wine_todo) +static inline void check_texture3d_desc_values_(uint32_t line, const D3D10_TEXTURE3D_DESC *desc, uint32_t width, + uint32_t height, uint32_t depth, uint32_t mip_levels, DXGI_FORMAT format, D3D10_USAGE usage, uint32_t bind_flags, + uint32_t cpu_access_flags, uint32_t misc_flags, BOOL wine_todo) +{ + const D3D10_TEXTURE3D_DESC expected_desc = { width, height, depth, mip_levels, format, usage, bind_flags, + cpu_access_flags, misc_flags }; + BOOL matched; + + matched = !memcmp(&expected_desc, desc, sizeof(*desc)); + todo_wine_if(wine_todo) ok_(__FILE__, line)(matched, "Got unexpected 3D texture desc values.\n"); + if (matched) + return; + + todo_wine_if(wine_todo && desc->Width != width) + ok_(__FILE__, line)(desc->Width == width, "Expected width %u, got %u.\n", width, desc->Width); + todo_wine_if(wine_todo && desc->Height != height) + ok_(__FILE__, line)(desc->Height == height, "Expected height %u, got %u.\n", height, desc->Height); + todo_wine_if(wine_todo && desc->Depth != depth) + ok_(__FILE__, line)(desc->Depth == depth, "Expected depth %u, got %u.\n", depth, desc->Depth); + todo_wine_if(wine_todo && desc->MipLevels != mip_levels) + ok_(__FILE__, line)(desc->MipLevels == mip_levels, "Expected mip_levels %u, got %u.\n", mip_levels, + desc->MipLevels); + ok_(__FILE__, line)(desc->Format == format, "Expected texture format %#x, got %#x.\n", format, desc->Format); + todo_wine_if(wine_todo && desc->Usage != usage) + ok_(__FILE__, line)(desc->Usage == usage, "Expected usage %u, got %u.\n", usage, + desc->Usage); + todo_wine_if(wine_todo && desc->BindFlags != bind_flags) + ok_(__FILE__, line)(desc->BindFlags == bind_flags, "Expected bind_flags %#x, got %#x.\n", bind_flags, + desc->BindFlags); + todo_wine_if(wine_todo && desc->CPUAccessFlags != cpu_access_flags) + ok_(__FILE__, line)(desc->CPUAccessFlags == cpu_access_flags, "Expected cpu_access_flags %#x, got %#x.\n", + cpu_access_flags, desc->CPUAccessFlags); + todo_wine_if(wine_todo && desc->MiscFlags != misc_flags) + ok_(__FILE__, line)(desc->MiscFlags == misc_flags, "Expected misc_flags %#x, got %#x.\n", misc_flags, + desc->MiscFlags); +} + +static ID3D10Texture2D *get_texture2d_readback_iface(ID3D10Texture2D *texture) { D3D10_TEXTURE2D_DESC desc; ID3D10Texture2D *readback; @@ -1302,7 +1753,7 @@ static ID3D10Texture2D *get_texture2d_readback(ID3D10Texture2D *texture) return readback; } -static ID3D10Texture3D *get_texture3d_readback(ID3D10Texture3D *texture) +static ID3D10Texture3D *get_texture3d_readback_iface(ID3D10Texture3D *texture) { D3D10_TEXTURE3D_DESC desc; ID3D10Texture3D *readback; @@ -1328,6 +1779,125 @@ static ID3D10Texture3D *get_texture3d_readback(ID3D10Texture3D *texture) return readback; } +#define check_test_image_load_info_resource(resource, image_load_info) \ + check_test_image_load_info_resource_(__LINE__, resource, image_load_info) +static void check_test_image_load_info_resource_(uint32_t line, ID3D10Resource *resource, + const struct test_image_load_info *image_load_info) +{ + D3D10_RESOURCE_DIMENSION resource_dimension; + HRESULT hr; + + ID3D10Resource_GetType(resource, &resource_dimension); + ok(resource_dimension == image_load_info->expected_type, "Got unexpected ResourceDimension %u, expected %u.\n", + resource_dimension, image_load_info->expected_type); + + switch (resource_dimension) + { + case D3D10_RESOURCE_DIMENSION_TEXTURE2D: + { + const D3D10_TEXTURE2D_DESC *expected_desc_2d = &image_load_info->expected_resource_desc.desc_2d; + D3D10_TEXTURE2D_DESC desc_2d; + ID3D10Texture2D *tex_2d; + + hr = ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture2D, (void **)&tex_2d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID3D10Texture2D_GetDesc(tex_2d, &desc_2d); + check_texture2d_desc_values_(line, &desc_2d, expected_desc_2d->Width, expected_desc_2d->Height, + expected_desc_2d->MipLevels, expected_desc_2d->ArraySize, expected_desc_2d->Format, + expected_desc_2d->SampleDesc.Count, expected_desc_2d->SampleDesc.Quality, expected_desc_2d->Usage, + expected_desc_2d->BindFlags, expected_desc_2d->CPUAccessFlags, expected_desc_2d->MiscFlags, + image_load_info->todo_resource_desc); + ID3D10Texture2D_Release(tex_2d); + break; + } + + case D3D10_RESOURCE_DIMENSION_TEXTURE3D: + { + const D3D10_TEXTURE3D_DESC *expected_desc_3d = &image_load_info->expected_resource_desc.desc_3d; + D3D10_TEXTURE3D_DESC desc_3d; + ID3D10Texture3D *tex_3d; + + hr = ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture3D, (void **)&tex_3d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID3D10Texture3D_GetDesc(tex_3d, &desc_3d); + check_texture3d_desc_values_(line, &desc_3d, expected_desc_3d->Width, expected_desc_3d->Height, + expected_desc_3d->Depth, expected_desc_3d->MipLevels, expected_desc_3d->Format, expected_desc_3d->Usage, + expected_desc_3d->BindFlags, expected_desc_3d->CPUAccessFlags, expected_desc_3d->MiscFlags, + image_load_info->todo_resource_desc); + ID3D10Texture3D_Release(tex_3d); + break; + } + + default: + break; + } +} + +#define check_test_image_load_info_srv(srv, image_load_info) \ + check_test_image_load_info_srv_(__LINE__, srv, image_load_info) +static void check_test_image_load_info_srv_(uint32_t line, ID3D10ShaderResourceView *srv, + const struct test_image_load_info *image_load_info) +{ + D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc; + ID3D10Resource *resource; + + ID3D10ShaderResourceView_GetDesc(srv, &srv_desc); + ok_(__FILE__, line)(srv_desc.ViewDimension == image_load_info->expected_srv_dimension, "Got unexpected ViewDimension %u, expected %u.\n", + srv_desc.ViewDimension, image_load_info->expected_srv_dimension); + if (srv_desc.ViewDimension != image_load_info->expected_srv_dimension) + return; + + ID3D10ShaderResourceView_GetResource(srv, &resource); + check_test_image_load_info_resource_(line, resource, image_load_info); + ID3D10Resource_Release(resource); + switch (srv_desc.ViewDimension) + { + case D3D10_SRV_DIMENSION_TEXTURE2D: + ok_(__FILE__, line)(srv_desc.Format == image_load_info->expected_resource_desc.desc_2d.Format, + "Got unexpected Format %u, expected %u.\n", srv_desc.Format, image_load_info->expected_resource_desc.desc_2d.Format); + ok_(__FILE__, line)(!srv_desc.Texture2D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture2D.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture2D.MipLevels == image_load_info->expected_resource_desc.desc_2d.MipLevels, + "Unexpected MipLevels %u.\n", srv_desc.Texture2D.MipLevels); + break; + + case D3D10_SRV_DIMENSION_TEXTURE2DARRAY: + ok_(__FILE__, line)(srv_desc.Format == image_load_info->expected_resource_desc.desc_2d.Format, + "Got unexpected Format %u, expected %u.\n", srv_desc.Format, image_load_info->expected_resource_desc.desc_2d.Format); + ok_(__FILE__, line)(!srv_desc.Texture2DArray.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture2DArray.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture2DArray.MipLevels == image_load_info->expected_resource_desc.desc_2d.MipLevels, + "Unexpected MipLevels %u.\n", srv_desc.Texture2DArray.MipLevels); + ok_(__FILE__, line)(!srv_desc.Texture2DArray.FirstArraySlice, "Unexpected FirstArraySlice %u.\n", + srv_desc.Texture2DArray.FirstArraySlice); + ok_(__FILE__, line)(srv_desc.Texture2DArray.ArraySize == image_load_info->expected_resource_desc.desc_2d.ArraySize, + "Unexpected ArraySize %u.\n", srv_desc.Texture2DArray.ArraySize); + break; + + case D3D10_SRV_DIMENSION_TEXTURECUBE: + ok_(__FILE__, line)(srv_desc.Format == image_load_info->expected_resource_desc.desc_2d.Format, + "Got unexpected Format %u, expected %u.\n", srv_desc.Format, image_load_info->expected_resource_desc.desc_2d.Format); + ok_(__FILE__, line)(!srv_desc.TextureCube.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.TextureCube.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.TextureCube.MipLevels == image_load_info->expected_resource_desc.desc_2d.MipLevels, + "Unexpected MipLevels %u.\n", srv_desc.TextureCube.MipLevels); + break; + + case D3D10_SRV_DIMENSION_TEXTURE3D: + ok_(__FILE__, line)(srv_desc.Format == image_load_info->expected_resource_desc.desc_3d.Format, + "Got unexpected Format %u, expected %u.\n", srv_desc.Format, image_load_info->expected_resource_desc.desc_3d.Format); + ok_(__FILE__, line)(!srv_desc.Texture3D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture3D.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture3D.MipLevels == image_load_info->expected_resource_desc.desc_3d.MipLevels, + "Unexpected MipLevels %u.\n", srv_desc.Texture3D.MipLevels); + break; + + default: + ok_(__FILE__, line)(0, "Unexpected ViewDimension %u.\n", srv_desc.ViewDimension); + break; + } +} + static void check_resource_info(ID3D10Resource *resource, const struct test_image *image, unsigned int line) { unsigned int expected_mip_levels, expected_width, expected_height, max_dimension; @@ -1354,10 +1924,9 @@ static void check_resource_info(ID3D10Resource *resource, const struct test_imag } ID3D10Resource_GetType(resource, &resource_dimension); - todo_wine_if (image->expected_info.ResourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE3D) - ok(resource_dimension == image->expected_info.ResourceDimension, - "Got unexpected ResourceDimension %u, expected %u.\n", - resource_dimension, image->expected_info.ResourceDimension); + ok(resource_dimension == image->expected_info.ResourceDimension, + "Got unexpected ResourceDimension %u, expected %u.\n", + resource_dimension, image->expected_info.ResourceDimension); switch (resource_dimension) { @@ -1371,7 +1940,6 @@ static void check_resource_info(ID3D10Resource *resource, const struct test_imag ok_(__FILE__, line)(desc_2d.Height == expected_height, "Got unexpected Height %u, expected %u.\n", desc_2d.Height, expected_height); - todo_wine_if(expected_mip_levels != image->expected_info.MipLevels) ok_(__FILE__, line)(desc_2d.MipLevels == expected_mip_levels, "Got unexpected MipLevels %u, expected %u.\n", desc_2d.MipLevels, expected_mip_levels); @@ -1452,7 +2020,7 @@ static void check_texture2d_data(ID3D10Texture2D *texture, const struct test_ima BOOL line_match; HRESULT hr; - readback = get_texture2d_readback(texture); + readback = get_texture2d_readback_iface(texture); ok_(__FILE__, line)(readback != NULL, "Failed to get texture readback.\n"); if (!readback) return; @@ -1482,7 +2050,7 @@ static void check_texture2d_data(ID3D10Texture2D *texture, const struct test_ima { line_match = !memcmp(expected_data + stride * i, (BYTE *)map.pData + map.RowPitch * i, stride); - todo_wine_if(is_block_compressed(image->expected_info.Format) + todo_wine_if(is_block_compressed(image->expected_info.Format) && image->data != test_dds_dxt5 && (image->expected_info.Width % 4 != 0 || image->expected_info.Height % 4 != 0)) ok_(__FILE__, line)(line_match, "Data mismatch for line %u, array slice %u.\n", i, array_slice); if (!line_match) @@ -1506,7 +2074,7 @@ static void check_texture3d_data(ID3D10Texture3D *texture, const struct test_ima BOOL line_match; HRESULT hr; - readback = get_texture3d_readback(texture); + readback = get_texture3d_readback_iface(texture); ok_(__FILE__, line)(readback != NULL, "Failed to get texture readback.\n"); if (!readback) return; @@ -1550,7 +2118,10 @@ static void check_resource_data(ID3D10Resource *resource, const struct test_imag if (SUCCEEDED(ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture3D, (void **)&texture3d))) { - check_texture3d_data(texture3d, image, line); + if (wined3d_opengl && is_block_compressed(image->expected_info.Format)) + skip("Skipping compressed format 3D texture readback test.\n"); + else + check_texture3d_data(texture3d, image, line); ID3D10Texture3D_Release(texture3d); } else if (SUCCEEDED(ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture2D, (void **)&texture2d))) @@ -1564,6 +2135,246 @@ static void check_resource_data(ID3D10Resource *resource, const struct test_imag } } +static void check_shader_resource_view_info(ID3D10ShaderResourceView *srv, const struct test_image *image, uint32_t line) +{ + uint32_t expected_mip_levels, expected_width, expected_height, max_dimension; + D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc; + ID3D10Resource *resource; + + expected_width = image->expected_info.Width; + expected_height = image->expected_info.Height; + if (is_block_compressed(image->expected_info.Format)) + { + expected_width = (expected_width + 3) & ~3; + expected_height = (expected_height + 3) & ~3; + } + expected_mip_levels = 0; + max_dimension = max(max(expected_width, expected_height), image->expected_info.Depth); + while (max_dimension) + { + ++expected_mip_levels; + max_dimension >>= 1; + } + + ID3D10ShaderResourceView_GetDesc(srv, &srv_desc); + ok_(__FILE__, line)(srv_desc.Format == image->expected_info.Format, "Got unexpected Format %u, expected %u.\n", + srv_desc.Format, image->expected_info.Format); + ok_(__FILE__, line)(srv_desc.ViewDimension == image->expected_srv_dimension, "Got unexpected ViewDimension %u, expected %u.\n", + srv_desc.ViewDimension, image->expected_srv_dimension); + if (srv_desc.ViewDimension != image->expected_srv_dimension) + return; + + ID3D10ShaderResourceView_GetResource(srv, &resource); + check_resource_info(resource, image, line); + check_resource_data(resource, image, line); + ID3D10Resource_Release(resource); + + switch (srv_desc.ViewDimension) + { + case D3D10_SRV_DIMENSION_TEXTURE2D: + ok_(__FILE__, line)(!srv_desc.Texture2D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture2D.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture2D.MipLevels == expected_mip_levels, "Unexpected MipLevels %u.\n", + srv_desc.Texture2D.MipLevels); + break; + + case D3D10_SRV_DIMENSION_TEXTURE2DARRAY: + ok_(__FILE__, line)(!srv_desc.Texture2DArray.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture2DArray.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture2DArray.MipLevels == expected_mip_levels, "Unexpected MipLevels %u.\n", + srv_desc.Texture2DArray.MipLevels); + ok_(__FILE__, line)(!srv_desc.Texture2DArray.FirstArraySlice, "Unexpected FirstArraySlice %u.\n", + srv_desc.Texture2DArray.FirstArraySlice); + ok_(__FILE__, line)(srv_desc.Texture2DArray.ArraySize == image->expected_info.ArraySize, "Unexpected ArraySize %u.\n", + srv_desc.Texture2DArray.ArraySize); + break; + + case D3D10_SRV_DIMENSION_TEXTURECUBE: + ok_(__FILE__, line)(!srv_desc.TextureCube.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.TextureCube.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.TextureCube.MipLevels == expected_mip_levels, "Unexpected MipLevels %u.\n", + srv_desc.TextureCube.MipLevels); + break; + + case D3D10_SRV_DIMENSION_TEXTURE3D: + ok_(__FILE__, line)(!srv_desc.Texture3D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture3D.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture3D.MipLevels == expected_mip_levels, "Unexpected MipLevels %u.\n", + srv_desc.Texture3D.MipLevels); + break; + + default: + ok_(__FILE__, line)(0, "Unexpected ViewDimension %u.\n", srv_desc.ViewDimension); + break; + } +} + +/* + * Taken from the d3d10core tests. If there's a missing resource type or + * texture format checking function, check to see if it exists there first. + */ +struct resource_readback +{ + D3D10_RESOURCE_DIMENSION dimension; + ID3D10Resource *resource; + D3D10_MAPPED_TEXTURE3D map_desc; + uint32_t width, height, depth, sub_resource_idx; +}; + +static void get_texture_readback(ID3D10Texture2D *texture, uint32_t sub_resource_idx, + struct resource_readback *rb) +{ + D3D10_TEXTURE2D_DESC texture_desc; + D3D10_MAPPED_TEXTURE2D map_desc; + uint32_t miplevel; + ID3D10Device *device; + HRESULT hr; + + memset(rb, 0, sizeof(*rb)); + rb->dimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; + + ID3D10Texture2D_GetDevice(texture, &device); + + ID3D10Texture2D_GetDesc(texture, &texture_desc); + texture_desc.Usage = D3D10_USAGE_STAGING; + texture_desc.BindFlags = 0; + texture_desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; + texture_desc.MiscFlags = 0; + if (FAILED(hr = ID3D10Device_CreateTexture2D(device, &texture_desc, NULL, (ID3D10Texture2D **)&rb->resource))) + { + trace("Failed to create texture, hr %#lx.\n", hr); + ID3D10Device_Release(device); + return; + } + + miplevel = sub_resource_idx % texture_desc.MipLevels; + rb->width = max(1, texture_desc.Width >> miplevel); + rb->height = max(1, texture_desc.Height >> miplevel); + rb->depth = 1; + rb->sub_resource_idx = sub_resource_idx; + + ID3D10Device_CopyResource(device, rb->resource, (ID3D10Resource *)texture); + if (FAILED(hr = ID3D10Texture2D_Map((ID3D10Texture2D *)rb->resource, sub_resource_idx, + D3D10_MAP_READ, 0, &map_desc))) + { + trace("Failed to map sub-resource %u, hr %#lx.\n", sub_resource_idx, hr); + ID3D10Resource_Release(rb->resource); + rb->resource = NULL; + } + rb->map_desc.pData = map_desc.pData; + rb->map_desc.RowPitch = map_desc.RowPitch; + rb->map_desc.DepthPitch = 0; + + ID3D10Device_Release(device); +} + +static void *get_readback_data(struct resource_readback *rb, uint32_t x, uint32_t y, unsigned byte_width) +{ + return (uint8_t *)rb->map_desc.pData + y * rb->map_desc.RowPitch + x * byte_width; +} + +static uint32_t get_readback_u32(struct resource_readback *rb, uint32_t x, uint32_t y) +{ + return *(uint32_t *)get_readback_data(rb, x, y, sizeof(uint32_t)); +} + +static uint32_t get_readback_color(struct resource_readback *rb, uint32_t x, uint32_t y) +{ + return get_readback_u32(rb, x, y); +} + +static void release_resource_readback(struct resource_readback *rb) +{ + switch (rb->dimension) + { + case D3D10_RESOURCE_DIMENSION_BUFFER: + ID3D10Buffer_Unmap((ID3D10Buffer *)rb->resource); + break; + case D3D10_RESOURCE_DIMENSION_TEXTURE1D: + ID3D10Texture1D_Unmap((ID3D10Texture1D *)rb->resource, rb->sub_resource_idx); + break; + case D3D10_RESOURCE_DIMENSION_TEXTURE2D: + ID3D10Texture2D_Unmap((ID3D10Texture2D *)rb->resource, rb->sub_resource_idx); + break; + case D3D10_RESOURCE_DIMENSION_TEXTURE3D: + ID3D10Texture3D_Unmap((ID3D10Texture3D *)rb->resource, rb->sub_resource_idx); + break; + default: + trace("Unhandled resource dimension %#x.\n", rb->dimension); + break; + } + ID3D10Resource_Release(rb->resource); +} + +static BOOL compare_color(uint32_t c1, uint32_t c2, uint8_t max_diff) +{ + return compare_uint(c1 & 0xff, c2 & 0xff, max_diff) + && compare_uint((c1 >> 8) & 0xff, (c2 >> 8) & 0xff, max_diff) + && compare_uint((c1 >> 16) & 0xff, (c2 >> 16) & 0xff, max_diff) + && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff); +} + +#define check_readback_data_color(a, b, c, d) check_readback_data_color_(__LINE__, a, b, c, d) +static void check_readback_data_color_(uint32_t line, struct resource_readback *rb, + const RECT *rect, uint32_t expected_color, uint8_t max_diff) +{ + unsigned int x = 0, y = 0, color = 0; + BOOL all_match = FALSE; + RECT default_rect; + + if (!rect) + { + SetRect(&default_rect, 0, 0, rb->width, rb->height); + rect = &default_rect; + } + + for (y = rect->top; y < rect->bottom; ++y) + { + for (x = rect->left; x < rect->right; ++x) + { + color = get_readback_color(rb, x, y); + if (!compare_color(color, expected_color, max_diff)) + goto done; + } + } + all_match = TRUE; + +done: + ok_(__FILE__, line)(all_match, + "Got 0x%08x, expected 0x%08x at (%u, %u), sub-resource %u.\n", + color, expected_color, x, y, rb->sub_resource_idx); +} + +#define check_texture_sub_resource_color(a, b, c, d, e) check_texture_sub_resource_color_(__LINE__, a, b, c, d, e) +static void check_texture_sub_resource_color_(uint32_t line, ID3D10Texture2D *texture, + uint32_t sub_resource_idx, const RECT *rect, uint32_t expected_color, uint8_t max_diff) +{ + struct resource_readback rb; + + get_texture_readback(texture, sub_resource_idx, &rb); + check_readback_data_color_(line, &rb, rect, expected_color, max_diff); + release_resource_readback(&rb); +} + +static void set_d3dx10_image_load_info(D3DX10_IMAGE_LOAD_INFO *info, uint32_t width, uint32_t height, uint32_t depth, + uint32_t first_mip_level, uint32_t mip_levels, D3D10_USAGE usage, uint32_t bind_flags, uint32_t cpu_access_flags, + uint32_t misc_flags, DXGI_FORMAT format, uint32_t filter, uint32_t mip_filter, D3DX10_IMAGE_INFO *src_info) +{ + info->Width = width; + info->Height = height; + info->Depth = depth; + info->FirstMipLevel = first_mip_level; + info->MipLevels = mip_levels; + info->Usage = usage; + info->BindFlags = bind_flags; + info->CpuAccessFlags = cpu_access_flags; + info->MiscFlags = misc_flags; + info->Format = format; + info->Filter = filter; + info->MipFilter = mip_filter; + info->pSrcInfo = src_info; +} + static void test_D3DX10UnsetAllDeviceObjects(void) { static const D3D10_INPUT_ELEMENT_DESC layout_desc[] = @@ -2384,49 +3195,169 @@ static void test_D3DX10CreateAsyncTextureProcessor(void) winetest_pop_context(); } - CoUninitialize(); + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + D3DX10_IMAGE_LOAD_INFO load_info = test_load_info->load_info; - ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); -} + winetest_push_context("Test %u", i); -static DWORD main_tid; -static DWORD io_tid; + hr = D3DX10CreateAsyncTextureProcessor(device, &load_info, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); -struct data_object -{ - ID3DX10DataLoader ID3DX10DataLoader_iface; - ID3DX10DataProcessor ID3DX10DataProcessor_iface; + hr = ID3DX10DataProcessor_Process(dp, (void *)test_load_info->data, test_load_info->size); + todo_wine_if(test_load_info->todo_process_hr) + ok(hr == test_load_info->expected_process_hr, "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + resource = NULL; + hr = ID3DX10DataProcessor_CreateDeviceObject(dp, (void **)&resource); + todo_wine_if(test_load_info->todo_create_device_object_hr) + ok(hr == test_load_info->expected_create_device_object_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10Resource_Release(resource); + } - HANDLE load_started; - HANDLE load_done; - HANDLE decompress_done; - HRESULT load_ret; + hr = ID3DX10DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - DWORD process_tid; -}; + winetest_pop_context(); + } -static struct data_object *data_object_from_ID3DX10DataLoader(ID3DX10DataLoader *iface) -{ - return CONTAINING_RECORD(iface, struct data_object, ID3DX10DataLoader_iface); + CoUninitialize(); + + ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); } -static LONG data_loader_load_count; -static WINAPI HRESULT data_loader_Load(ID3DX10DataLoader *iface) +static void test_D3DX10CreateAsyncShaderResourceViewProcessor(void) { - struct data_object *data_object = data_object_from_ID3DX10DataLoader(iface); - DWORD ret; + ID3D10ShaderResourceView *resource_view; + ID3DX10DataProcessor *dp; + ID3D10Device *device; + HRESULT hr; + uint32_t i; - ok(InterlockedDecrement(&data_loader_load_count) >= 0, "Got unexpected call.\n"); + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + return; + } - if (!io_tid) - io_tid = GetCurrentThreadId(); - ok(io_tid != main_tid, "Load called in main thread.\n"); - ok(io_tid == GetCurrentThreadId(), "Load called in wrong thread.\n"); + CoInitialize(NULL); - SetEvent(data_object->load_started); - ret = WaitForSingleObject(data_object->load_done, INFINITE); - ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx.\n", ret); - return data_object->load_ret; + hr = D3DX10CreateAsyncShaderResourceViewProcessor(device, NULL, NULL); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX10CreateAsyncShaderResourceViewProcessor(NULL, NULL, &dp); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX10CreateAsyncShaderResourceViewProcessor(device, NULL, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX10DataProcessor_Process(dp, (void *)test_image[0].data, 0); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX10DataProcessor_Process(dp, NULL, test_image[0].size); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX10DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + + hr = D3DX10CreateAsyncShaderResourceViewProcessor(device, NULL, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX10DataProcessor_Process(dp, (void *)test_image[i].data, test_image[i].size); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX10_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + hr = ID3DX10DataProcessor_CreateDeviceObject(dp, (void **)&resource_view); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + check_shader_resource_view_info(resource_view, test_image + i, __LINE__); + ID3D10ShaderResourceView_Release(resource_view); + } + + hr = ID3DX10DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + D3DX10_IMAGE_LOAD_INFO load_info = test_load_info->load_info; + + winetest_push_context("Test %u", i); + + hr = D3DX10CreateAsyncShaderResourceViewProcessor(device, &load_info, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX10DataProcessor_Process(dp, (void *)test_load_info->data, test_load_info->size); + todo_wine_if(test_load_info->todo_process_hr) + ok(hr == test_load_info->expected_process_hr, "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + resource_view = NULL; + hr = ID3DX10DataProcessor_CreateDeviceObject(dp, (void **)&resource_view); + todo_wine_if(test_load_info->todo_create_device_object_hr) + ok(hr == test_load_info->expected_create_device_object_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10ShaderResourceView_Release(resource_view); + } + + hr = ID3DX10DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + winetest_pop_context(); + } + + CoUninitialize(); + + ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); +} + +static DWORD main_tid; +static DWORD io_tid; + +struct data_object +{ + ID3DX10DataLoader ID3DX10DataLoader_iface; + ID3DX10DataProcessor ID3DX10DataProcessor_iface; + + HANDLE load_started; + HANDLE load_done; + HANDLE decompress_done; + HRESULT load_ret; + + DWORD process_tid; +}; + +static struct data_object *data_object_from_ID3DX10DataLoader(ID3DX10DataLoader *iface) +{ + return CONTAINING_RECORD(iface, struct data_object, ID3DX10DataLoader_iface); +} + +static LONG data_loader_load_count; +static WINAPI HRESULT data_loader_Load(ID3DX10DataLoader *iface) +{ + struct data_object *data_object = data_object_from_ID3DX10DataLoader(iface); + DWORD ret; + + ok(InterlockedDecrement(&data_loader_load_count) >= 0, "Got unexpected call.\n"); + + if (!io_tid) + io_tid = GetCurrentThreadId(); + ok(io_tid != main_tid, "Load called in main thread.\n"); + ok(io_tid == GetCurrentThreadId(), "Load called in wrong thread.\n"); + + SetEvent(data_object->load_started); + ret = WaitForSingleObject(data_object->load_done, INFINITE); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx.\n", ret); + return data_object->load_ret; } static LONG data_loader_decompress_count; @@ -2771,6 +3702,7 @@ static void check_dds_pixel_format_(unsigned int line, DWORD flags, DWORD fourcc { DWORD magic; struct dds_header header; + PALETTEENTRY palette[256]; BYTE data[256]; } dds; @@ -2794,6 +3726,338 @@ static void check_dds_pixel_format_(unsigned int line, DWORD flags, DWORD fourcc } } +#define check_dds_pixel_format_unsupported(flags, fourcc, bpp, rmask, gmask, bmask, amask, expected_hr) \ + check_dds_pixel_format_unsupported_(__LINE__, flags, fourcc, bpp, rmask, gmask, bmask, amask, expected_hr) +static void check_dds_pixel_format_unsupported_(unsigned int line, DWORD flags, DWORD fourcc, DWORD bpp, + DWORD rmask, DWORD gmask, DWORD bmask, DWORD amask, HRESULT expected_hr) +{ + D3DX10_IMAGE_INFO info; + HRESULT hr; + struct + { + DWORD magic; + struct dds_header header; + PALETTEENTRY palette[256]; + BYTE data[256]; + } dds; + + dds.magic = MAKEFOURCC('D','D','S',' '); + fill_dds_header(&dds.header); + dds.header.pixel_format.flags = flags; + dds.header.pixel_format.fourcc = fourcc; + dds.header.pixel_format.bpp = bpp; + dds.header.pixel_format.rmask = rmask; + dds.header.pixel_format.gmask = gmask; + dds.header.pixel_format.bmask = bmask; + dds.header.pixel_format.amask = amask; + memset(dds.data, 0, sizeof(dds.data)); + + hr = D3DX10GetImageInfoFromMemory(&dds, sizeof(dds), NULL, &info, NULL); + ok_(__FILE__, line)(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr); +} + +#define check_dds_dxt10_format(format, expected_format, wine_todo) \ + check_dds_dxt10_format_(__LINE__, format, expected_format, wine_todo) +static void check_dds_dxt10_format_(uint32_t line, DXGI_FORMAT format, DXGI_FORMAT expected_format, BOOL wine_todo) +{ + const uint32_t stride = (4 * get_bpp_from_format(format) + 7) / 8; + D3DX10_IMAGE_INFO info; + HRESULT hr; + struct + { + DWORD magic; + struct dds_header header; + struct dds_header_dxt10 dxt10; + BYTE data[256]; + } dds; + + dds.magic = MAKEFOURCC('D','D','S',' '); + set_dxt10_dds_header(&dds.header, 0, 4, 4, 1, 1, stride, 0, 0); + set_dds_header_dxt10(&dds.dxt10, format, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0); + + hr = D3DX10GetImageInfoFromMemory(&dds, sizeof(dds), NULL, &info, NULL); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx for DXGI format %#x.\n", hr, format); + if (SUCCEEDED(hr)) + { + todo_wine_if(wine_todo) ok_(__FILE__, line)(info.Format == expected_format, "Unexpected format %#x, expected %#x.\n", + info.Format, expected_format); + } +} + +#define check_dds_dxt10_format_unsupported(format, expected_hr) \ + check_dds_dxt10_format_unsupported_(__LINE__, format, expected_hr) +static void check_dds_dxt10_format_unsupported_(uint32_t line, DXGI_FORMAT format, HRESULT expected_hr) +{ + const uint32_t stride = (4 * get_bpp_from_format(format) + 7) / 8; + D3DX10_IMAGE_INFO info; + HRESULT hr; + struct + { + DWORD magic; + struct dds_header header; + struct dds_header_dxt10 dxt10; + BYTE data[256]; + } dds; + + dds.magic = MAKEFOURCC('D','D','S',' '); + set_dxt10_dds_header(&dds.header, 0, 4, 4, 1, 1, stride, 0, 0); + set_dds_header_dxt10(&dds.dxt10, format, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0); + + hr = D3DX10GetImageInfoFromMemory(&dds, sizeof(dds), NULL, &info, NULL); + ok_(__FILE__, line)(hr == expected_hr, "Got unexpected hr %#lx for DXGI format %#x.\n", hr, format); +} + +static void test_legacy_dds_header_image_info(void) +{ + struct expected + { + HRESULT hr; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t array_size; + uint32_t mip_levels; + uint32_t misc_flags; + DXGI_FORMAT format; + D3D10_RESOURCE_DIMENSION resource_dimension; + }; + static const struct + { + uint32_t flags; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t row_pitch; + uint32_t mip_levels; + uint32_t caps; + uint32_t caps2; + struct expected expected; + uint32_t pixel_data_size; + } tests[] = + { + /* + * Only DDS header size is validated on d3dx10, unlike d3dx9 where image pixel size + * is as well. + */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT), 4, 4, 1, (4 * 4), 3, 0, 0, + { S_OK, 4, 4, 1, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, }, 0 }, + /* Depth value set to 4, but no caps bits are set. Depth is ignored. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT), 4, 4, 4, (4 * 4), 3, 0, 0, + { S_OK, 4, 4, 1, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, }, 292 }, + /* The volume texture caps2 field is ignored. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT), 4, 4, 4, (4 * 4), 3, + (DDS_CAPS_TEXTURE | DDS_CAPS_COMPLEX), DDS_CAPS2_VOLUME, + { S_OK, 4, 4, 1, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, }, 292 }, + /* + * The DDS_DEPTH flag is the only thing checked to determine if a DDS + * file represents a 3D texture. + */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT | DDS_DEPTH), 4, 4, 4, (4 * 4), 3, + 0, 0, + { S_OK, 4, 4, 4, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, }, 292 }, + /* Even if the depth field is set to 0, it's still a 3D texture. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT | DDS_DEPTH), 4, 4, 0, (4 * 4), 3, + 0, 0, + { S_OK, 4, 4, 1, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, }, 292 }, + /* The DDS_DEPTH flag overrides cubemap caps. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT | DDS_DEPTH), 4, 4, 4, (4 * 4), 3, + (DDS_CAPS_TEXTURE | DDS_CAPS_COMPLEX), (DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES), + { S_OK, 4, 4, 4, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, }, 292 }, + /* Cubemap where width field does not equal height. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT), 4, 5, 1, (4 * 4), 1, + (DDS_CAPS_TEXTURE | DDS_CAPS_COMPLEX), (DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES), + { S_OK, 4, 5, 1, 6, 1, D3D10_RESOURCE_MISC_TEXTURECUBE, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, }, (80 * 6) }, + /* Partial cubemaps are not supported. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT), 4, 4, 1, (4 * 4), 1, + (DDS_CAPS_TEXTURE | DDS_CAPS_COMPLEX), (DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_POSITIVEX), + { E_FAIL, }, (64 * 6) }, + }; + D3DX10_IMAGE_INFO info; + unsigned int i; + struct + { + DWORD magic; + struct dds_header header; + } dds; + HRESULT hr; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + const uint32_t file_size = sizeof(dds) + tests[i].pixel_data_size; + + winetest_push_context("Test %u", i); + + dds.magic = MAKEFOURCC('D','D','S',' '); + fill_dds_header(&dds.header); + dds.header.flags = tests[i].flags; + dds.header.width = tests[i].width; + dds.header.height = tests[i].height; + dds.header.depth = tests[i].depth; + dds.header.pitch_or_linear_size = tests[i].row_pitch; + dds.header.miplevels = tests[i].mip_levels; + dds.header.caps = tests[i].caps; + dds.header.caps2 = tests[i].caps2; + + memset(&info, 0, sizeof(info)); + hr = D3DX10GetImageInfoFromMemory(&dds, file_size, NULL, &info, NULL); + ok(hr == tests[i].expected.hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr) && SUCCEEDED(tests[i].expected.hr)) + check_image_info_values(&info, tests[i].expected.width, tests[i].expected.height, + tests[i].expected.depth, tests[i].expected.array_size, tests[i].expected.mip_levels, + tests[i].expected.misc_flags, tests[i].expected.format, + tests[i].expected.resource_dimension, D3DX10_IFF_DDS, FALSE); + + winetest_pop_context(); + } + + /* + * Image size (e.g, the size of the pixels) isn't validated, but header + * size is. + */ + dds.magic = MAKEFOURCC('D','D','S',' '); + fill_dds_header(&dds.header); + + hr = D3DX10GetImageInfoFromMemory(&dds, sizeof(dds) - 1, NULL, &info, NULL); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + hr = D3DX10GetImageInfoFromMemory(&dds, sizeof(dds), NULL, &info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +} + +static void test_dxt10_dds_header_image_info(void) +{ + struct expected + { + HRESULT hr; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t array_size; + uint32_t mip_levels; + uint32_t misc_flags; + DXGI_FORMAT format; + D3D10_RESOURCE_DIMENSION resource_dimension; + }; + static const struct + { + uint32_t append_flags; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t row_pitch; + uint32_t mip_levels; + uint32_t caps; + uint32_t caps2; + struct dds_header_dxt10 dxt10; + struct expected expected; + uint32_t pixel_data_size; + BOOL todo_hr; + } dxt10_tests[] = + { + /* File size validation isn't done on d3dx10. */ + { 0, 4, 4, 0, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0, }, + { S_OK, 4, 4, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, }, 0 }, + /* + * Setting the misc_flags2 field to anything other than 0 results in + * E_FAIL. + */ + { 0, 4, 4, 0, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 1, }, + { E_FAIL }, (4 * 4 * 4) }, + /* + * The misc_flags field isn't passed through directly, only the + * cube texture flag is (if it's set). + */ + { 0, 4, 4, 0, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0xfffffffb, 1, 0, }, + { S_OK, 4, 4, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, }, (4 * 4 * 4) }, + /* Resource dimension field of the header isn't validated. */ + { 0, 4, 4, 0, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, 500, 0, 1, 0, }, + { S_OK, 4, 4, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, 500, }, (4 * 4 * 4), .todo_hr = TRUE }, + /* Depth value of 2, but D3D10_RESOURCE_DIMENSION_TEXTURE2D. */ + { DDS_DEPTH, 4, 4, 2, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0, }, + { S_OK, 4, 4, 2, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, }, (4 * 4 * 4 * 2) }, + /* Depth field value is ignored if DDS_DEPTH isn't set. */ + { 0, 4, 4, 2, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0, }, + { S_OK, 4, 4, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, }, (4 * 4 * 4 * 2) }, + /* + * 3D texture with an array size larger than 1. Technically there's no + * such thing as a 3D texture array, but it succeeds. + */ + { DDS_DEPTH, 4, 4, 2, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 2, 0, }, + { S_OK, 4, 4, 2, 2, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, }, (4 * 4 * 4 * 2 * 2) }, + /* Cubemap caps are ignored for DXT10 files. */ + { 0, 4, 4, 1, (4 * 4), 1, 0, DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0, }, + { S_OK, 4, 4, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D }, (4 * 4 * 4 * 6) }, + /* Array size value is multiplied by 6 for cubemap files. */ + { 0, 4, 4, 1, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 2, 0, }, + { S_OK, 4, 4, 1, 12, 1, D3D10_RESOURCE_MISC_TEXTURECUBE, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D }, (4 * 4 * 4 * 12) }, + /* Resource dimension is validated for cube textures. */ + { 0, 4, 4, 1, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, DDS_RESOURCE_MISC_TEXTURECUBE, 2, 0, }, + { E_FAIL }, (4 * 4 * 4 * 12) }, + /* 1D Texture cube, invalid. */ + { 0, 4, 4, 1, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, DDS_RESOURCE_MISC_TEXTURECUBE, 2, 0, }, + { E_FAIL }, (4 * 4 * 4 * 12) }, + }; + D3DX10_IMAGE_INFO info; + unsigned int i; + struct + { + DWORD magic; + struct dds_header header; + struct dds_header_dxt10 dxt10; + } dds; + HRESULT hr; + + for (i = 0; i < ARRAY_SIZE(dxt10_tests); ++i) + { + const uint32_t file_size = sizeof(dds) + dxt10_tests[i].pixel_data_size; + + winetest_push_context("Test %u", i); + + dds.magic = MAKEFOURCC('D','D','S',' '); + set_dxt10_dds_header(&dds.header, dxt10_tests[i].append_flags, dxt10_tests[i].width, dxt10_tests[i].height, + dxt10_tests[i].depth, dxt10_tests[i].mip_levels, dxt10_tests[i].row_pitch, dxt10_tests[i].caps, + dxt10_tests[i].caps2); + dds.dxt10 = dxt10_tests[i].dxt10; + + memset(&info, 0, sizeof(info)); + hr = D3DX10GetImageInfoFromMemory(&dds, file_size, NULL, &info, NULL); + todo_wine_if(dxt10_tests[i].todo_hr) ok(hr == dxt10_tests[i].expected.hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr) && SUCCEEDED(dxt10_tests[i].expected.hr)) + check_image_info_values(&info, dxt10_tests[i].expected.width, dxt10_tests[i].expected.height, + dxt10_tests[i].expected.depth, dxt10_tests[i].expected.array_size, dxt10_tests[i].expected.mip_levels, + dxt10_tests[i].expected.misc_flags, dxt10_tests[i].expected.format, + dxt10_tests[i].expected.resource_dimension, D3DX10_IFF_DDS, FALSE); + + winetest_pop_context(); + } + + /* + * Image size (e.g, the size of the pixels) isn't validated, but header + * size is. + */ + dds.magic = MAKEFOURCC('D','D','S',' '); + set_dxt10_dds_header(&dds.header, dxt10_tests[0].append_flags, dxt10_tests[0].width, dxt10_tests[0].height, + dxt10_tests[0].depth, dxt10_tests[0].mip_levels, dxt10_tests[0].row_pitch, dxt10_tests[0].caps, dxt10_tests[0].caps2); + dds.dxt10 = dxt10_tests[0].dxt10; + + hr = D3DX10GetImageInfoFromMemory(&dds, sizeof(dds) - 1, NULL, &info, NULL); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + hr = D3DX10GetImageInfoFromMemory(&dds, sizeof(dds), NULL, &info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +} + static void test_get_image_info(void) { static const WCHAR test_resource_name[] = L"resource.data"; @@ -2842,7 +4106,7 @@ static void test_get_image_info(void) /* 2 bpp is not a valid bit count. */ hr2 = 0xdeadbeef; hr = D3DX10GetImageInfoFromMemory(test_bmp_2bpp, sizeof(test_bmp_2bpp), NULL, &image_info, &hr2); - todo_wine ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); for (i = 0; i < ARRAY_SIZE(test_image); ++i) @@ -2936,6 +4200,56 @@ static void test_get_image_info(void) check_dds_pixel_format(DDS_PF_LUMINANCE, 0, 16, 0xffff, 0, 0, 0, DXGI_FORMAT_R16G16B16A16_UNORM); check_dds_pixel_format(DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 16, 0x00ff, 0, 0, 0xff00, DXGI_FORMAT_R8G8B8A8_UNORM); check_dds_pixel_format(DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x0f, 0, 0, 0xf0, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_INDEXED, 0, 8, 0, 0, 0, 0, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_INDEXED | DDS_PF_ALPHA, 0, 16, 0, 0, 0, 0xff00, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, 0x24, 0, 0, 0, 0, 0, DXGI_FORMAT_R16G16B16A16_UNORM); /* D3DFMT_A16B16G16R16 */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x6e, 0, 0, 0, 0, 0, DXGI_FORMAT_R16G16B16A16_SNORM); /* D3DFMT_Q16W16V16U16 */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x6f, 0, 0, 0, 0, 0, DXGI_FORMAT_R16_FLOAT); /* D3DFMT_R16F */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x70, 0, 0, 0, 0, 0, DXGI_FORMAT_R16G16_FLOAT); /* D3DFMT_G16R16F */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x71, 0, 0, 0, 0, 0, DXGI_FORMAT_R16G16B16A16_FLOAT); /* D3DFMT_A16B16G16R16F */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x72, 0, 0, 0, 0, 0, DXGI_FORMAT_R32_FLOAT); /* D3DFMT_R32F */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x73, 0, 0, 0, 0, 0, DXGI_FORMAT_R32G32_FLOAT); /* D3DFMT_G32R32F */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x74, 0, 0, 0, 0, 0, DXGI_FORMAT_R32G32B32A32_FLOAT); /* D3DFMT_A32B32G32R32F */ + + /* Test for DDS pixel formats that are valid on d3dx9, but not d3dx10. */ + check_dds_pixel_format_unsupported(DDS_PF_FOURCC, MAKEFOURCC('U','Y','V','Y'), 0, 0, 0, 0, 0, E_FAIL); + check_dds_pixel_format_unsupported(DDS_PF_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0, E_FAIL); + /* Bumpmap formats aren't supported. */ + check_dds_pixel_format_unsupported(DDS_PF_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0, 0, E_FAIL); + check_dds_pixel_format_unsupported(DDS_PF_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0, 0, E_FAIL); + check_dds_pixel_format_unsupported(DDS_PF_BUMPDUDV, 0, 32, 0xff, 0xff00, 0x00ff0000, 0xff000000, E_FAIL); + check_dds_pixel_format_unsupported(DDS_PF_BUMPLUMINANCE, 0, 32, 0x0000ff, 0x00ff00, 0xff0000, 0, E_FAIL); + + /* Newer fourCC formats. */ + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC4_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC5_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC4_SNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC5_SNORM); + /* ATI1 is unsupported, but ATI2 is supported. */ + check_dds_pixel_format_unsupported(DDS_PF_FOURCC, MAKEFOURCC('A','T','I','1'), 0, 0, 0, 0, 0, E_FAIL); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('A','T','I','2'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC5_UNORM); + + check_dds_dxt10_format_unsupported(DXGI_FORMAT_B5G6R5_UNORM, E_FAIL); + check_dds_dxt10_format_unsupported(DXGI_FORMAT_B5G5R5A1_UNORM, E_FAIL); + /* Formats that are newer than d3d10. */ + check_dds_dxt10_format_unsupported(DXGI_FORMAT_BC6H_UF16, E_FAIL); + check_dds_dxt10_format_unsupported(DXGI_FORMAT_BC6H_SF16, E_FAIL); + check_dds_dxt10_format_unsupported(DXGI_FORMAT_BC7_UNORM, E_FAIL); + check_dds_dxt10_format_unsupported(DXGI_FORMAT_B4G4R4A4_UNORM, E_FAIL); + + /* + * These formats should map 1:1 from the DXT10 header, unlike legacy DDS + * file equivalents. + */ + check_dds_dxt10_format(DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, FALSE); + check_dds_dxt10_format(DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM, FALSE); + check_dds_dxt10_format(DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, FALSE); + check_dds_dxt10_format(DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_B8G8R8X8_UNORM, FALSE); + check_dds_dxt10_format(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, FALSE); + check_dds_dxt10_format(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, FALSE); + + test_legacy_dds_header_image_info(); + test_dxt10_dds_header_image_info(); /* D3DX10GetImageInfoFromResource tests */ @@ -2993,14 +4307,19 @@ static void test_get_image_info(void) static void test_create_texture(void) { + static const uint32_t dds_24bit_8_8_mip_level_expected[] = { 0xff0000ff, 0xff00ff00, 0xffff0000, 0xff000000 }; static const WCHAR test_resource_name[] = L"resource.data"; static const WCHAR test_filename[] = L"image.data"; + D3D10_TEXTURE2D_DESC tex_2d_desc; + D3DX10_IMAGE_LOAD_INFO load_info; + D3DX10_IMAGE_INFO img_info; ID3D10Resource *resource; + ID3D10Texture2D *tex_2d; HMODULE resource_module; ID3D10Device *device; WCHAR path[MAX_PATH]; + uint32_t i, mip_level; HRESULT hr, hr2; - unsigned int i; device = create_device(); if (!device) @@ -3067,47 +4386,155 @@ static void test_create_texture(void) winetest_pop_context(); } - hr2 = 0xdeadbeef; - add_work_item_count = 0; - hr = D3DX10CreateTextureFromMemory(device, test_image[0].data, test_image[0].size, - NULL, &thread_pump, &resource, &hr2); - ok(add_work_item_count == 1, "Got unexpected add_work_item_count %u.\n", add_work_item_count); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - check_resource_info(resource, test_image, __LINE__); - check_resource_data(resource, test_image, __LINE__); - ID3D10Resource_Release(resource); - - /* D3DX10CreateTextureFromFile tests */ - - hr2 = 0xdeadbeef; - hr = D3DX10CreateTextureFromFileW(device, NULL, NULL, NULL, &resource, &hr2); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); - ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); - hr2 = 0xdeadbeef; - hr = D3DX10CreateTextureFromFileW(device, L"deadbeef", NULL, NULL, &resource, &hr2); - ok(hr == D3D10_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); - ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - hr2 = 0xdeadbeef; - hr = D3DX10CreateTextureFromFileA(device, NULL, NULL, NULL, &resource, &hr2); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); - ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); - hr2 = 0xdeadbeef; - hr = D3DX10CreateTextureFromFileA(device, "deadbeef", NULL, NULL, &resource, &hr2); - ok(hr == D3D10_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); - ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - - for (i = 0; i < ARRAY_SIZE(test_image); ++i) + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + winetest_push_context("Test %u", i); - create_file(test_filename, test_image[i].data, test_image[i].size, path); hr2 = 0xdeadbeef; - hr = D3DX10CreateTextureFromFileW(device, path, NULL, NULL, &resource, &hr2); + load_info = test_load_info->load_info; + hr = D3DX10CreateTextureFromMemory(device, test_load_info->data, test_load_info->size, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX10_IFF_WMP), - "Got unexpected hr %#lx.\n", hr); - if (hr == S_OK) + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10Resource_Release(resource); + + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(test_image_load_info); ++i) + { + const struct test_image_load_info *test_load_info = &test_image_load_info[i]; + + winetest_push_context("Test %u", i); + + load_info = test_load_info->load_info; + load_info.pSrcInfo = &img_info; + + resource = NULL; + hr2 = 0xdeadbeef; + hr = D3DX10CreateTextureFromMemory(device, test_load_info->data, test_load_info->size, &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + check_test_image_load_info_resource(resource, test_load_info); + ID3D10Resource_Release(resource); + } + + winetest_pop_context(); + } + + /* Check behavior of the FirstMipLevel argument. */ + for (i = 0; i < 2; ++i) + { + winetest_push_context("FirstMipLevel %u", i); + memset(&img_info, 0, sizeof(img_info)); + set_d3dx10_image_load_info(&load_info, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, i, D3DX10_FROM_FILE, + D3D10_USAGE_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, + D3DX10_DEFAULT, &img_info); + + resource = NULL; + hr2 = 0xdeadbeef; + hr = D3DX10CreateTextureFromMemory(device, dds_24bit_8_8, sizeof(dds_24bit_8_8), &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3DX10_IFF_DDS, FALSE); + + hr = ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture2D, (void **)&tex_2d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ID3D10Texture2D_GetDesc(tex_2d, &tex_2d_desc); + check_texture2d_desc_values(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0, FALSE); + for (mip_level = 0; mip_level < 4; ++mip_level) + { + winetest_push_context("MipLevel %u", mip_level); + check_texture_sub_resource_color(tex_2d, mip_level, NULL, + dds_24bit_8_8_mip_level_expected[min(3, mip_level + i)], 0); + winetest_pop_context(); + } + + ID3D10Texture2D_Release(tex_2d); + ID3D10Resource_Release(resource); + winetest_pop_context(); + } + + /* + * If FirstMipLevel is set to a value that is larger than the total number + * of mip levels in the image, it falls back to 0. + */ + memset(&img_info, 0, sizeof(img_info)); + set_d3dx10_image_load_info(&load_info, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, 5, D3DX10_FROM_FILE, + D3D10_USAGE_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, + D3DX10_DEFAULT, &img_info); + + resource = NULL; + hr2 = 0xdeadbeef; + hr = D3DX10CreateTextureFromMemory(device, dds_24bit_8_8, sizeof(dds_24bit_8_8), &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3DX10_IFF_DDS, FALSE); + + hr = ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture2D, (void **)&tex_2d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID3D10Texture2D_GetDesc(tex_2d, &tex_2d_desc); + check_texture2d_desc_values(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0, FALSE); + for (mip_level = 0; mip_level < 4; ++mip_level) + { + winetest_push_context("MipLevel %u", mip_level); + check_texture_sub_resource_color(tex_2d, mip_level, NULL, dds_24bit_8_8_mip_level_expected[mip_level], 0); + winetest_pop_context(); + } + + ID3D10Texture2D_Release(tex_2d); + ID3D10Resource_Release(resource); + + hr2 = 0xdeadbeef; + add_work_item_count = 0; + hr = D3DX10CreateTextureFromMemory(device, test_image[0].data, test_image[0].size, + NULL, &thread_pump, &resource, &hr2); + ok(add_work_item_count == 1, "Got unexpected add_work_item_count %u.\n", add_work_item_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + check_resource_info(resource, test_image, __LINE__); + check_resource_data(resource, test_image, __LINE__); + ID3D10Resource_Release(resource); + + /* D3DX10CreateTextureFromFile tests */ + + hr2 = 0xdeadbeef; + hr = D3DX10CreateTextureFromFileW(device, NULL, NULL, NULL, &resource, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX10CreateTextureFromFileW(device, L"deadbeef", NULL, NULL, &resource, &hr2); + ok(hr == D3D10_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX10CreateTextureFromFileA(device, NULL, NULL, NULL, &resource, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX10CreateTextureFromFileA(device, "deadbeef", NULL, NULL, &resource, &hr2); + ok(hr == D3D10_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + create_file(test_filename, test_image[i].data, test_image[i].size, path); + + hr2 = 0xdeadbeef; + hr = D3DX10CreateTextureFromFileW(device, path, NULL, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX10_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) { check_resource_info(resource, test_image + i, __LINE__); check_resource_data(resource, test_image + i, __LINE__); @@ -3130,6 +4557,31 @@ static void test_create_texture(void) winetest_pop_context(); } + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + + winetest_push_context("Test %u", i); + create_file(test_filename, test_image[i].data, test_image[i].size, path); + load_info = test_load_info->load_info; + + hr2 = 0xdeadbeef; + hr = D3DX10CreateTextureFromFileW(device, path, &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10Resource_Release(resource); + + hr = D3DX10CreateTextureFromFileA(device, get_str_a(path), &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10Resource_Release(resource); + + delete_file(test_filename); + winetest_pop_context(); + } + /* D3DX10CreateTextureFromResource tests */ hr2 = 0xdeadbeef; @@ -3189,1463 +4641,4507 @@ static void test_create_texture(void) winetest_pop_context(); } + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + + winetest_push_context("Test %u", i); + resource_module = create_resource_module(test_resource_name, test_load_info->data, test_load_info->size); + load_info = test_load_info->load_info; + + hr2 = 0xdeadbeef; + hr = D3DX10CreateTextureFromResourceW(device, resource_module, + test_resource_name, &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10Resource_Release(resource); + + hr2 = 0xdeadbeef; + hr = D3DX10CreateTextureFromResourceA(device, resource_module, + get_str_a(test_resource_name), &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10Resource_Release(resource); + + delete_resource_module(test_resource_name, resource_module); + winetest_pop_context(); + } + CoUninitialize(); ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); } -#define check_rect(rect, left, top, right, bottom) _check_rect(__LINE__, rect, left, top, right, bottom) -static inline void _check_rect(unsigned int line, const RECT *rect, int left, int top, int right, int bottom) -{ - ok_(__FILE__, line)(rect->left == left, "Unexpected rect.left %ld\n", rect->left); - ok_(__FILE__, line)(rect->top == top, "Unexpected rect.top %ld\n", rect->top); - ok_(__FILE__, line)(rect->right == right, "Unexpected rect.right %ld\n", rect->right); - ok_(__FILE__, line)(rect->bottom == bottom, "Unexpected rect.bottom %ld\n", rect->bottom); -} - -static void test_font(void) +static void test_create_shader_resource_view(void) { - static const WCHAR testW[] = L"test"; - static const char long_text[] = "Example text to test clipping and other related things"; - static const WCHAR long_textW[] = L"Example text to test clipping and other related things"; - static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} }; - static const D3DXCOLOR color = { 1.0f, 0.0f, 1.0f, 0.0f }; - static const D3DXCOLOR white = { 1.0f, 1.0f, 1.0f, 0.0f }; - static const struct - { - int font_height; - unsigned int expected_size; - unsigned int expected_levels; - } - tests[] = - { - { 2, 32, 2 }, - { 6, 128, 4 }, - { 10, 256, 5 }, - { 12, 256, 5 }, - { 72, 256, 8 }, - { 250, 256, 9 }, - { 258, 512, 10 }, - { 512, 512, 10 }, - }; - const unsigned int size = ARRAY_SIZE(testW); - TEXTMETRICA metrics, expmetrics; - D3D10_TEXTURE2D_DESC texture_desc; - ID3D10Device *device, *device2; + static const uint32_t dds_24bit_8_8_mip_level_expected[] = { 0xff0000ff, 0xff00ff00, 0xffff0000, 0xff000000 }; + static const WCHAR test_resource_name[] = L"resource.data"; + static const WCHAR test_filename[] = L"image.data"; + D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc; + D3D10_TEXTURE2D_DESC tex_2d_desc; + D3DX10_IMAGE_LOAD_INFO load_info; ID3D10ShaderResourceView *srv; - GLYPHMETRICS glyph_metrics; - int ref, i, height, count; - ID3D10Texture2D *texture; + D3DX10_IMAGE_INFO img_info; ID3D10Resource *resource; - D3DX10_FONT_DESCA desc; - ID3DX10Sprite *sprite; - RECT rect, blackbox; - ID3DX10Font *font; - TEXTMETRICW tm; - POINT cellinc; - HRESULT hr; - WORD glyph; - BOOL ret; - HDC hdc; - char c; + ID3D10Texture2D *tex_2d; + HMODULE resource_module; + ID3D10Device *device; + WCHAR path[MAX_PATH]; + uint32_t i, mip_level; + HRESULT hr, hr2; - if (!(device = create_device())) + device = create_device(); + if (!device) { skip("Failed to create device, skipping tests.\n"); return; } - ref = get_refcount(device); - hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); - ok(hr == S_OK, "Failed to create a font, hr %#lx.\n", hr); - ok(ref < get_refcount(device), "Unexpected device refcount.\n"); - ID3DX10Font_Release(font); - ok(ref == get_refcount(device), "Unexpected device refcount.\n"); + CoInitialize(NULL); - /* Zero size */ - hr = D3DX10CreateFontA(device, 0, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); - ok(hr == S_OK, "Failed to create a font, hr %#lx.\n", hr); - ID3DX10Font_Release(font); + /* D3DX10CreateShaderResourceViewFromMemory tests. */ + srv = (ID3D10ShaderResourceView *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromMemory(NULL, test_bmp_1bpp, sizeof(test_bmp_1bpp), NULL, NULL, &srv, &hr2); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + ok(srv == (ID3D10ShaderResourceView *)0xdeadbeef, "Got unexpected srv %p.\n", srv); - /* Unspecified font name */ - hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, NULL, &font); - ok(hr == S_OK, "Failed to create a font, hr %#lx.\n", hr); - ID3DX10Font_Release(font); + srv = (ID3D10ShaderResourceView *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromMemory(device, NULL, 0, NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + ok(srv == (ID3D10ShaderResourceView *)0xdeadbeef, "Got unexpected srv %p.\n", srv); - /* Empty font name */ - hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "", &font); - ok(hr == S_OK, "Failed to create a font, hr %#lx.\n", hr); - ID3DX10Font_Release(font); + srv = (ID3D10ShaderResourceView *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromMemory(device, NULL, sizeof(test_bmp_1bpp), NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + ok(srv == (ID3D10ShaderResourceView *)0xdeadbeef, "Got unexpected srv %p.\n", srv); - hr = D3DX10CreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + srv = (ID3D10ShaderResourceView *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromMemory(device, test_bmp_1bpp, 0, NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(srv == (ID3D10ShaderResourceView *)0xdeadbeef, "Got unexpected srv %p.\n", srv); - hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", NULL); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + srv = (ID3D10ShaderResourceView *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromMemory(device, test_bmp_1bpp, sizeof(test_bmp_1bpp) - 1, NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(srv == (ID3D10ShaderResourceView *)0xdeadbeef, "Got unexpected srv %p.\n", srv); - hr = D3DX10CreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", NULL); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); - /* D3DX10CreateFontIndirect */ - desc.Height = 12; - desc.Width = 0; - desc.Weight = FW_DONTCARE; - desc.MipLevels = 0; - desc.Italic = FALSE; - desc.CharSet = DEFAULT_CHARSET; - desc.OutputPrecision = OUT_DEFAULT_PRECIS; - desc.Quality = DEFAULT_QUALITY; - desc.PitchAndFamily = DEFAULT_PITCH; - strcpy(desc.FaceName, "Tahoma"); - hr = D3DX10CreateFontIndirectA(device, &desc, &font); - ok(hr == S_OK, "Failed to create a font, hr %#lx.\n", hr); - ID3DX10Font_Release(font); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromMemory(device, test_image[i].data, test_image[i].size, NULL, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX10_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + check_shader_resource_view_info(srv, test_image + i, __LINE__); + ID3D10ShaderResourceView_Release(srv); + } - hr = D3DX10CreateFontIndirectA(NULL, &desc, &font); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - - hr = D3DX10CreateFontIndirectA(device, NULL, &font); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - - hr = D3DX10CreateFontIndirectA(device, &desc, NULL); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - - /* GetDevice */ - hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = ID3DX10Font_GetDevice(font, NULL); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + winetest_pop_context(); + } - hr = ID3DX10Font_GetDevice(font, &device2); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ID3D10Device_Release(device2); + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; - ID3DX10Font_Release(font); + winetest_push_context("Test %u", i); - /* GetDesc */ - hr = D3DX10CreateFontA(device, 12, 8, FW_BOLD, 2, TRUE, ANSI_CHARSET, OUT_RASTER_PRECIS, - ANTIALIASED_QUALITY, VARIABLE_PITCH, "Tahoma", &font); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr2 = 0xdeadbeef; + load_info = test_load_info->load_info; + hr = D3DX10CreateShaderResourceViewFromMemory(device, test_load_info->data, test_load_info->size, &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10ShaderResourceView_Release(srv); - hr = ID3DX10Font_GetDescA(font, NULL); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + winetest_pop_context(); + } - hr = ID3DX10Font_GetDescA(font, &desc); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < ARRAY_SIZE(test_image_load_info); ++i) + { + const struct test_image_load_info *test_load_info = &test_image_load_info[i]; - ok(desc.Height == 12, "Unexpected height %d.\n", desc.Height); - ok(desc.Width == 8, "Unexpected width %u.\n", desc.Width); - ok(desc.Weight == FW_BOLD, "Unexpected weight %u.\n", desc.Weight); - ok(desc.MipLevels == 2, "Unexpected miplevels %u.\n", desc.MipLevels); - ok(desc.Italic == TRUE, "Unexpected italic %#x.\n", desc.Italic); - ok(desc.CharSet == ANSI_CHARSET, "Unexpected charset %u.\n", desc.CharSet); - ok(desc.OutputPrecision == OUT_RASTER_PRECIS, "Unexpected output precision %u.\n", desc.OutputPrecision); - ok(desc.Quality == ANTIALIASED_QUALITY, "Unexpected quality %u.\n", desc.Quality); - ok(desc.PitchAndFamily == VARIABLE_PITCH, "Unexpected pitch and family %#x.\n", desc.PitchAndFamily); - ok(!strcmp(desc.FaceName, "Tahoma"), "Unexpected facename %s.\n", debugstr_a(desc.FaceName)); + winetest_push_context("Test %u", i); - ID3DX10Font_Release(font); + load_info = test_load_info->load_info; + load_info.pSrcInfo = &img_info; - /* GetDC + GetTextMetrics */ - hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + srv = NULL; + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromMemory(device, test_load_info->data, test_load_info->size, &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + check_test_image_load_info_srv(srv, test_load_info); + ID3D10ShaderResourceView_Release(srv); + } - hdc = ID3DX10Font_GetDC(font); - ok(!!hdc, "Unexpected hdc %p.\n", hdc); + winetest_pop_context(); + } - ret = GetTextMetricsA(hdc, &expmetrics); - ok(ret, "Unexpected ret %#x.\n", ret); + /* Check behavior of the FirstMipLevel argument. */ + for (i = 0; i < 2; ++i) + { + winetest_push_context("FirstMipLevel %u", i); + memset(&img_info, 0, sizeof(img_info)); + set_d3dx10_image_load_info(&load_info, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, i, D3DX10_FROM_FILE, + D3D10_USAGE_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, + D3DX10_DEFAULT, &img_info); - ret = ID3DX10Font_GetTextMetricsA(font, &metrics); - ok(ret, "Unexpected ret %#x.\n", ret); + srv = NULL; + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromMemory(device, dds_24bit_8_8, sizeof(dds_24bit_8_8), &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3DX10_IFF_DDS, FALSE); - ok(metrics.tmHeight == expmetrics.tmHeight, "Unexpected height %ld, expected %ld.\n", - metrics.tmHeight, expmetrics.tmHeight); - ok(metrics.tmAscent == expmetrics.tmAscent, "Unexpected ascent %ld, expected %ld.\n", - metrics.tmAscent, expmetrics.tmAscent); - ok(metrics.tmDescent == expmetrics.tmDescent, "Unexpected descent %ld, expected %ld.\n", - metrics.tmDescent, expmetrics.tmDescent); - ok(metrics.tmInternalLeading == expmetrics.tmInternalLeading, "Unexpected internal leading %ld, expected %ld.\n", - metrics.tmInternalLeading, expmetrics.tmInternalLeading); - ok(metrics.tmExternalLeading == expmetrics.tmExternalLeading, "Unexpected external leading %ld, expected %ld.\n", - metrics.tmExternalLeading, expmetrics.tmExternalLeading); - ok(metrics.tmAveCharWidth == expmetrics.tmAveCharWidth, "Unexpected average char width %ld, expected %ld.\n", - metrics.tmAveCharWidth, expmetrics.tmAveCharWidth); - ok(metrics.tmMaxCharWidth == expmetrics.tmMaxCharWidth, "Unexpected maximum char width %ld, expected %ld.\n", - metrics.tmMaxCharWidth, expmetrics.tmMaxCharWidth); - ok(metrics.tmWeight == expmetrics.tmWeight, "Unexpected weight %ld, expected %ld.\n", - metrics.tmWeight, expmetrics.tmWeight); - ok(metrics.tmOverhang == expmetrics.tmOverhang, "Unexpected overhang %ld, expected %ld.\n", - metrics.tmOverhang, expmetrics.tmOverhang); - ok(metrics.tmDigitizedAspectX == expmetrics.tmDigitizedAspectX, "Unexpected digitized x aspect %ld, expected %ld.\n", - metrics.tmDigitizedAspectX, expmetrics.tmDigitizedAspectX); - ok(metrics.tmDigitizedAspectY == expmetrics.tmDigitizedAspectY, "Unexpected digitized y aspect %ld, expected %ld.\n", - metrics.tmDigitizedAspectY, expmetrics.tmDigitizedAspectY); - ok(metrics.tmFirstChar == expmetrics.tmFirstChar, "Unexpected first char %u, expected %u.\n", - metrics.tmFirstChar, expmetrics.tmFirstChar); - ok(metrics.tmLastChar == expmetrics.tmLastChar, "Unexpected last char %u, expected %u.\n", - metrics.tmLastChar, expmetrics.tmLastChar); - ok(metrics.tmDefaultChar == expmetrics.tmDefaultChar, "Unexpected default char %u, expected %u.\n", - metrics.tmDefaultChar, expmetrics.tmDefaultChar); - ok(metrics.tmBreakChar == expmetrics.tmBreakChar, "Unexpected break char %u, expected %u.\n", - metrics.tmBreakChar, expmetrics.tmBreakChar); - ok(metrics.tmItalic == expmetrics.tmItalic, "Unexpected italic %u, expected %u.\n", - metrics.tmItalic, expmetrics.tmItalic); - ok(metrics.tmUnderlined == expmetrics.tmUnderlined, "Unexpected underlined %u, expected %u.\n", - metrics.tmUnderlined, expmetrics.tmUnderlined); - ok(metrics.tmStruckOut == expmetrics.tmStruckOut, "Unexpected struck out %u, expected %u.\n", - metrics.tmStruckOut, expmetrics.tmStruckOut); - ok(metrics.tmPitchAndFamily == expmetrics.tmPitchAndFamily, "Unexpected pitch and family %u, expected %u.\n", - metrics.tmPitchAndFamily, expmetrics.tmPitchAndFamily); - ok(metrics.tmCharSet == expmetrics.tmCharSet, "Unexpected charset %u, expected %u.\n", - metrics.tmCharSet, expmetrics.tmCharSet); + ID3D10ShaderResourceView_GetDesc(srv, &srv_desc); + ok(srv_desc.ViewDimension == D3D10_SRV_DIMENSION_TEXTURE2D, "Got unexpected ViewDimension %u.\n", srv_desc.ViewDimension); + ok(srv_desc.Format == img_info.Format, "Got unexpected Format %#x.\n", srv_desc.Format); + ok(!srv_desc.Texture2D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", srv_desc.Texture2D.MostDetailedMip); + ok(srv_desc.Texture2D.MipLevels == img_info.MipLevels, "Unexpected MipLevels %u.\n", srv_desc.Texture2D.MipLevels); - ID3DX10Font_Release(font); + ID3D10ShaderResourceView_GetResource(srv, &resource); + hr = ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture2D, (void **)&tex_2d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - /* PreloadText */ - hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ID3D10Texture2D_GetDesc(tex_2d, &tex_2d_desc); + check_texture2d_desc_values(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0, FALSE); + for (mip_level = 0; mip_level < 4; ++mip_level) + { + winetest_push_context("MipLevel %u", mip_level); + check_texture_sub_resource_color(tex_2d, mip_level, NULL, + dds_24bit_8_8_mip_level_expected[min(3, mip_level + i)], 0); + winetest_pop_context(); + } - hr = ID3DX10Font_PreloadTextA(font, NULL, -1); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_PreloadTextA(font, NULL, 0); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_PreloadTextA(font, NULL, 1); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_PreloadTextA(font, "test", -1); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_PreloadTextA(font, "", 0); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_PreloadTextA(font, "", -1); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ID3D10Texture2D_Release(tex_2d); + ID3D10Resource_Release(resource); + ID3D10ShaderResourceView_Release(srv); + winetest_pop_context(); + } - hr = ID3DX10Font_PreloadTextW(font, NULL, -1); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_PreloadTextW(font, NULL, 0); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_PreloadTextW(font, NULL, 1); - ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_PreloadTextW(font, testW, -1); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_PreloadTextW(font, L"", 0); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_PreloadTextW(font, L"", -1); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* + * If FirstMipLevel is set to a value that is larger than the total number + * of mip levels in the image, it falls back to 0. + */ + memset(&img_info, 0, sizeof(img_info)); + set_d3dx10_image_load_info(&load_info, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, 5, D3DX10_FROM_FILE, + D3D10_USAGE_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, + D3DX10_DEFAULT, &img_info); - ID3DX10Font_Release(font); + resource = NULL; + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromMemory(device, dds_24bit_8_8, sizeof(dds_24bit_8_8), &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3DX10_IFF_DDS, FALSE); - /* GetGlyphData, PreloadGlyphs, PreloadCharacters */ - hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ID3D10ShaderResourceView_GetDesc(srv, &srv_desc); + ok(srv_desc.ViewDimension == D3D10_SRV_DIMENSION_TEXTURE2D, "Got unexpected ViewDimension %u.\n", srv_desc.ViewDimension); + ok(srv_desc.Format == img_info.Format, "Got unexpected Format %#x.\n", srv_desc.Format); + ok(!srv_desc.Texture2D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", srv_desc.Texture2D.MostDetailedMip); + ok(srv_desc.Texture2D.MipLevels == img_info.MipLevels, "Unexpected MipLevels %u.\n", srv_desc.Texture2D.MipLevels); - hdc = ID3DX10Font_GetDC(font); - ok(!!hdc, "Unexpected hdc %p.\n", hdc); + ID3D10ShaderResourceView_GetResource(srv, &resource); + hr = ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture2D, (void **)&tex_2d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID3D10Texture2D_GetDesc(tex_2d, &tex_2d_desc); + check_texture2d_desc_values(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0, FALSE); + for (mip_level = 0; mip_level < 4; ++mip_level) + { + winetest_push_context("MipLevel %u", mip_level); + check_texture_sub_resource_color(tex_2d, mip_level, NULL, dds_24bit_8_8_mip_level_expected[mip_level], 0); + winetest_pop_context(); + } - hr = ID3DX10Font_GetGlyphData(font, 0, NULL, &blackbox, &cellinc); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_GetGlyphData(font, 0, &srv, NULL, &cellinc); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - ID3D10ShaderResourceView_Release(srv); - hr = ID3DX10Font_GetGlyphData(font, 0, &srv, &blackbox, NULL); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - ID3D10ShaderResourceView_Release(srv); + ID3D10Texture2D_Release(tex_2d); + ID3D10Resource_Release(resource); + ID3D10ShaderResourceView_Release(srv); - hr = ID3DX10Font_PreloadCharacters(font, 'b', 'a'); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Font_PreloadGlyphs(font, 1, 0); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr2 = 0xdeadbeef; + add_work_item_count = 0; + hr = D3DX10CreateShaderResourceViewFromMemory(device, test_image[0].data, test_image[0].size, + NULL, &thread_pump, &srv, &hr2); + ok(add_work_item_count == 1, "Got unexpected add_work_item_count %u.\n", add_work_item_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + check_shader_resource_view_info(srv, test_image, __LINE__); + ID3D10ShaderResourceView_Release(srv); - hr = ID3DX10Font_PreloadCharacters(font, 'a', 'a'); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* D3DX10CreateShaderResourceViewFromFile tests */ + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromFileW(device, NULL, NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromFileW(device, L"deadbeef", NULL, NULL, &srv, &hr2); + ok(hr == D3D10_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromFileA(device, NULL, NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromFileA(device, "deadbeef", NULL, NULL, &srv, &hr2); + ok(hr == D3D10_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - for (c = 'b'; c <= 'z'; ++c) + for (i = 0; i < ARRAY_SIZE(test_image); ++i) { - winetest_push_context("Character %c", c); - count = GetGlyphIndicesA(hdc, &c, 1, &glyph, 0); - ok(count != GDI_ERROR, "Unexpected count %u.\n", count); + winetest_push_context("Test %u", i); + create_file(test_filename, test_image[i].data, test_image[i].size, path); - hr = ID3DX10Font_GetGlyphData(font, glyph, &srv, &blackbox, &cellinc); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromFileW(device, path, NULL, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX10_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + check_shader_resource_view_info(srv, test_image + i, __LINE__); + ID3D10ShaderResourceView_Release(srv); + } - if (FAILED(hr)) + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromFileA(device, get_str_a(path), NULL, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX10_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) { - winetest_pop_context(); - break; + check_shader_resource_view_info(srv, test_image + i, __LINE__); + ID3D10ShaderResourceView_Release(srv); } - ID3D10ShaderResourceView_GetResource(srv, &resource); - hr = ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture2D, (void **)&texture); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ID3D10Resource_Release(resource); + delete_file(test_filename); + winetest_pop_context(); + } - ID3D10Texture2D_GetDesc(texture, &texture_desc); - ok(texture_desc.Width == 256, "Unexpected width %u.\n", texture_desc.Width); - ok(texture_desc.Height == 256, "Unexpected height %u.\n", texture_desc.Height); - ok(texture_desc.MipLevels == 5, "Unexpected miplevels %u.\n", texture_desc.MipLevels); - ok(texture_desc.ArraySize == 1, "Unexpected array size %u.\n", texture_desc.ArraySize); - ok(texture_desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", - texture_desc.Format); - ok(texture_desc.SampleDesc.Count == 1, "Unexpected samples count %u.\n", - texture_desc.SampleDesc.Count); - ok(texture_desc.SampleDesc.Quality == 0, "Unexpected quality level %u.\n", - texture_desc.SampleDesc.Quality); - ok(texture_desc.Usage == 0, "Unexpected usage %#x.\n", texture_desc.Usage); - ok(texture_desc.BindFlags == D3D10_BIND_SHADER_RESOURCE, "Unexpected bind flags %#x.\n", - texture_desc.BindFlags); - ok(texture_desc.CPUAccessFlags == 0, "Unexpected access flags %#x.\n", - texture_desc.CPUAccessFlags); - ok(texture_desc.MiscFlags == 0, "Unexpected misc flags %#x.\n", texture_desc.MiscFlags); + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; - count = GetGlyphOutlineW(hdc, glyph, GGO_GLYPH_INDEX | GGO_METRICS, &glyph_metrics, 0, NULL, &mat); - ok(count != GDI_ERROR, "Unexpected count %#x.\n", count); + winetest_push_context("Test %u", i); + create_file(test_filename, test_image[i].data, test_image[i].size, path); + load_info = test_load_info->load_info; - ret = ID3DX10Font_GetTextMetricsW(font, &tm); - ok(ret, "Unexpected ret %#x.\n", ret); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromFileW(device, path, &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10ShaderResourceView_Release(srv); - todo_wine ok(blackbox.right - blackbox.left == glyph_metrics.gmBlackBoxX + 2, "Got %ld, expected %d.\n", - blackbox.right - blackbox.left, glyph_metrics.gmBlackBoxX + 2); - todo_wine ok(blackbox.bottom - blackbox.top == glyph_metrics.gmBlackBoxY + 2, "Got %ld, expected %d.\n", - blackbox.bottom - blackbox.top, glyph_metrics.gmBlackBoxY + 2); - ok(cellinc.x == glyph_metrics.gmptGlyphOrigin.x - 1, "Got %ld, expected %ld.\n", - cellinc.x, glyph_metrics.gmptGlyphOrigin.x - 1); - ok(cellinc.y == tm.tmAscent - glyph_metrics.gmptGlyphOrigin.y - 1, "Got %ld, expected %ld.\n", - cellinc.y, tm.tmAscent - glyph_metrics.gmptGlyphOrigin.y - 1); + hr = D3DX10CreateShaderResourceViewFromFileA(device, get_str_a(path), &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10ShaderResourceView_Release(srv); - ID3D10Texture2D_Release(texture); + delete_file(test_filename); winetest_pop_context(); } - hr = ID3DX10Font_PreloadCharacters(font, 'a', 'z'); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - -#if D3DX10_SDK_VERSION > 34 - /* Test multiple textures. - * Native d3dx10_34.dll shows signs of memory corruption in this call. */ - hr = ID3DX10Font_PreloadGlyphs(font, 0, 1000); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -#endif - - /* Test glyphs that are not rendered */ - for (glyph = 1; glyph < 4; ++glyph) - { - srv = (void *)0xdeadbeef; - hr = ID3DX10Font_GetGlyphData(font, glyph, &srv, &blackbox, &cellinc); - todo_wine { - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!srv, "Unexpected resource view %p.\n", srv); - } - } - - ID3DX10Font_Release(font); + /* D3DX10CreateShaderResourceViewFromResource tests */ + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromResourceW(device, NULL, NULL, NULL, NULL, &srv, &hr2); + ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromResourceW(device, NULL, L"deadbeef", NULL, NULL, &srv, &hr2); + ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromResourceA(device, NULL, NULL, NULL, NULL, &srv, &hr2); + ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromResourceA(device, NULL, "deadbeef", NULL, NULL, &srv, &hr2); + ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); - c = 'a'; - for (i = 0; i < ARRAY_SIZE(tests); ++i) + for (i = 0; i < ARRAY_SIZE(test_image); ++i) { winetest_push_context("Test %u", i); - hr = D3DX10CreateFontA(device, tests[i].font_height, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hdc = ID3DX10Font_GetDC(font); - ok(!!hdc, "Unexpected hdc %p.\n", hdc); - - count = GetGlyphIndicesA(hdc, &c, 1, &glyph, 0); - ok(count != GDI_ERROR, "Unexpected count %u.\n", count); + resource_module = create_resource_module(test_resource_name, test_image[i].data, test_image[i].size); - hr = ID3DX10Font_GetGlyphData(font, glyph, &srv, NULL, NULL); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromResourceW(device, resource_module, L"deadbeef", NULL, NULL, &srv, &hr2); + ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); - if (FAILED(hr)) + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromResourceW(device, resource_module, + test_resource_name, NULL, NULL, &srv, &hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX10_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + if (hr == S_OK) { - ID3DX10Font_Release(font); - winetest_pop_context(); - break; + check_shader_resource_view_info(srv, test_image + i, __LINE__); + ID3D10ShaderResourceView_Release(srv); } - ID3D10ShaderResourceView_GetResource(srv, &resource); - hr = ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture2D, (void **)&texture); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ID3D10Resource_Release(resource); - - ID3D10Texture2D_GetDesc(texture, &texture_desc); - - ok(texture_desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", - texture_desc.Format); - ok(texture_desc.Usage == 0, "Unexpected usage %#x.\n", texture_desc.Usage); - ok(texture_desc.Width == tests[i].expected_size, "Unexpected width %u.\n", texture_desc.Width); - ok(texture_desc.Height == tests[i].expected_size, "Unexpected height %u.\n", texture_desc.Height); - ok(texture_desc.CPUAccessFlags == 0, "Unexpected access flags %#x.\n", - texture_desc.CPUAccessFlags); - ok(texture_desc.BindFlags == D3D10_BIND_SHADER_RESOURCE, "Unexpected bind flags %#x.\n", - texture_desc.BindFlags); - - ID3D10Texture2D_Release(texture); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromResourceA(device, resource_module, + get_str_a(test_resource_name), NULL, NULL, &srv, &hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX10_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + if (hr == S_OK) + { + check_shader_resource_view_info(srv, test_image + i, __LINE__); + ID3D10ShaderResourceView_Release(srv); + } - /* DrawText */ - hr = D3DX10CreateSprite(device, 0, &sprite); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - SetRect(&rect, 0, 0, 640, 480); + delete_resource_module(test_resource_name, resource_module); + winetest_pop_context(); + } - hr = ID3DX10Sprite_Begin(sprite, 0); - ok (hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; - height = ID3DX10Font_DrawTextW(font, sprite, testW, -1, &rect, DT_TOP, white); - ok(height == tests[i].font_height, "Unexpected height %u.\n", height); - height = ID3DX10Font_DrawTextW(font, sprite, testW, size, &rect, DT_TOP, white); - ok(height == tests[i].font_height, "Unexpected height %u.\n", height); - height = ID3DX10Font_DrawTextW(font, sprite, testW, size, &rect, DT_RIGHT, white); - ok(height == tests[i].font_height, "Unexpected height %u.\n", height); - height = ID3DX10Font_DrawTextW(font, sprite, testW, size, &rect, DT_LEFT | DT_NOCLIP, white); - ok(height == tests[i].font_height, "Unexpected height %u.\n", height); + winetest_push_context("Test %u", i); + resource_module = create_resource_module(test_resource_name, test_load_info->data, test_load_info->size); + load_info = test_load_info->load_info; - SetRectEmpty(&rect); - height = ID3DX10Font_DrawTextW(font, sprite, testW, size, &rect, - DT_LEFT | DT_CALCRECT, white); - ok(height == tests[i].font_height, "Unexpected height %u.\n", height); - ok(!rect.left, "Unexpected rect left %ld.\n", rect.left); - ok(!rect.top, "Unexpected rect top %ld.\n", rect.top); - ok(rect.right, "Unexpected rect right %ld.\n", rect.right); - ok(rect.bottom == tests[i].font_height, "Unexpected rect bottom %ld.\n", rect.bottom); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromResourceW(device, resource_module, + test_resource_name, &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10ShaderResourceView_Release(srv); - hr = ID3DX10Sprite_End(sprite); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ID3DX10Sprite_Release(sprite); + hr2 = 0xdeadbeef; + hr = D3DX10CreateShaderResourceViewFromResourceA(device, resource_module, + get_str_a(test_resource_name), &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10ShaderResourceView_Release(srv); - ID3DX10Font_Release(font); + delete_resource_module(test_resource_name, resource_module); winetest_pop_context(); } - if (!strcmp(winetest_platform, "wine")) - return; + CoUninitialize(); - /* DrawText */ - hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); +} - SetRect(&rect, 10, 10, 200, 200); - height = ID3DX10Font_DrawTextA(font, NULL, "test", -2, &rect, 0, color); - ok(height == 12, "Unexpected height %d.\n", height); - height = ID3DX10Font_DrawTextA(font, NULL, "test", -1, &rect, 0, color); - ok(height == 12, "Unexpected height %d.\n", height); +#define check_rect(rect, left, top, right, bottom) _check_rect(__LINE__, rect, left, top, right, bottom) +static inline void _check_rect(unsigned int line, const RECT *rect, int left, int top, int right, int bottom) +{ + ok_(__FILE__, line)(rect->left == left, "Unexpected rect.left %ld\n", rect->left); + ok_(__FILE__, line)(rect->top == top, "Unexpected rect.top %ld\n", rect->top); + ok_(__FILE__, line)(rect->right == right, "Unexpected rect.right %ld\n", rect->right); + ok_(__FILE__, line)(rect->bottom == bottom, "Unexpected rect.bottom %ld\n", rect->bottom); +} - height = ID3DX10Font_DrawTextA(font, NULL, "test", 0, &rect, 0, color); - ok(height == 0, "Unexpected height %d.\n", height); +static void test_font(void) +{ + static const WCHAR testW[] = L"test"; + static const char long_text[] = "Example text to test clipping and other related things"; + static const WCHAR long_textW[] = L"Example text to test clipping and other related things"; + static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} }; + static const D3DXCOLOR color = { 1.0f, 0.0f, 1.0f, 0.0f }; + static const D3DXCOLOR white = { 1.0f, 1.0f, 1.0f, 0.0f }; + static const struct + { + int font_height; + unsigned int expected_size; + unsigned int expected_levels; + } + tests[] = + { + { 2, 32, 2 }, + { 6, 128, 4 }, + { 10, 256, 5 }, + { 12, 256, 5 }, + { 72, 256, 8 }, + { 250, 256, 9 }, + { 258, 512, 10 }, + { 512, 512, 10 }, + }; + const unsigned int size = ARRAY_SIZE(testW); + TEXTMETRICA metrics, expmetrics; + D3D10_TEXTURE2D_DESC texture_desc; + ID3D10Device *device, *device2; + ID3D10ShaderResourceView *srv; + GLYPHMETRICS glyph_metrics; + int ref, i, height, count; + ID3D10Texture2D *texture; + ID3D10Resource *resource; + D3DX10_FONT_DESCA desc; + ID3DX10Sprite *sprite; + RECT rect, blackbox; + ID3DX10Font *font; + TEXTMETRICW tm; + POINT cellinc; + HRESULT hr; + WORD glyph; + BOOL ret; + HDC hdc; + char c; - height = ID3DX10Font_DrawTextA(font, NULL, "test", 1, &rect, 0, color); - ok(height == 12, "Unexpected height %d.\n", height); + if (!(device = create_device())) + { + skip("Failed to create device, skipping tests.\n"); + return; + } - height = ID3DX10Font_DrawTextA(font, NULL, "test", 2, &rect, 0, color); - ok(height == 12, "Unexpected height %d.\n", height); + ref = get_refcount(device); + hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); + ok(hr == S_OK, "Failed to create a font, hr %#lx.\n", hr); + ok(ref < get_refcount(device), "Unexpected device refcount.\n"); + ID3DX10Font_Release(font); + ok(ref == get_refcount(device), "Unexpected device refcount.\n"); - height = ID3DX10Font_DrawTextA(font, NULL, "", 0, &rect, 0, color); - ok(height == 0, "Unexpected height %d.\n", height); + /* Zero size */ + hr = D3DX10CreateFontA(device, 0, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); + ok(hr == S_OK, "Failed to create a font, hr %#lx.\n", hr); + ID3DX10Font_Release(font); - height = ID3DX10Font_DrawTextA(font, NULL, "", -1, &rect, 0, color); - ok(height == 0, "Unexpected height %d.\n", height); + /* Unspecified font name */ + hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, NULL, &font); + ok(hr == S_OK, "Failed to create a font, hr %#lx.\n", hr); + ID3DX10Font_Release(font); - height = ID3DX10Font_DrawTextA(font, NULL, "test", -1, NULL, 0, color); - ok(height == 12, "Unexpected height %d.\n", height); + /* Empty font name */ + hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "", &font); + ok(hr == S_OK, "Failed to create a font, hr %#lx.\n", hr); + ID3DX10Font_Release(font); - height = ID3DX10Font_DrawTextA(font, NULL, "test", -1, NULL, DT_CALCRECT, color); - ok(height == 12, "Unexpected height %d.\n", height); + hr = D3DX10CreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextA(font, NULL, NULL, -1, NULL, 0, color); - ok(height == 0, "Unexpected height %d.\n", height); + hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", NULL); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - SetRect(&rect, 10, 10, 50, 50); + hr = D3DX10CreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", NULL); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextA(font, NULL, long_text, -1, &rect, DT_WORDBREAK, color); - ok(height == 60, "Unexpected height %d.\n", height); + /* D3DX10CreateFontIndirect */ + desc.Height = 12; + desc.Width = 0; + desc.Weight = FW_DONTCARE; + desc.MipLevels = 0; + desc.Italic = FALSE; + desc.CharSet = DEFAULT_CHARSET; + desc.OutputPrecision = OUT_DEFAULT_PRECIS; + desc.Quality = DEFAULT_QUALITY; + desc.PitchAndFamily = DEFAULT_PITCH; + strcpy(desc.FaceName, "Tahoma"); + hr = D3DX10CreateFontIndirectA(device, &desc, &font); + ok(hr == S_OK, "Failed to create a font, hr %#lx.\n", hr); + ID3DX10Font_Release(font); - height = ID3DX10Font_DrawTextA(font, NULL, long_text, -1, &rect, DT_WORDBREAK | DT_NOCLIP, color); - ok(height == 96, "Unexpected height %d.\n", height); + hr = D3DX10CreateFontIndirectA(NULL, &desc, &font); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - SetRect(&rect, 10, 10, 200, 200); + hr = D3DX10CreateFontIndirectA(device, NULL, &font); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, testW, -1, &rect, 0, color); - ok(height == 12, "Unexpected height %d.\n", height); + hr = D3DX10CreateFontIndirectA(device, &desc, NULL); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, testW, 0, &rect, 0, color); - ok(height == 0, "Unexpected height %d.\n", height); + /* GetDevice */ + hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, testW, 1, &rect, 0, color); - ok(height == 12, "Unexpected height %d.\n", height); + hr = ID3DX10Font_GetDevice(font, NULL); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, testW, 2, &rect, 0, color); - ok(height == 12, "Unexpected height %d.\n", height); + hr = ID3DX10Font_GetDevice(font, &device2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ID3D10Device_Release(device2); - height = ID3DX10Font_DrawTextW(font, NULL, L"", 0, &rect, 0, color); - ok(height == 0, "Unexpected height %d.\n", height); + ID3DX10Font_Release(font); - height = ID3DX10Font_DrawTextW(font, NULL, L"", -1, &rect, 0, color); - ok(height == 0, "Unexpected height %d.\n", height); + /* GetDesc */ + hr = D3DX10CreateFontA(device, 12, 8, FW_BOLD, 2, TRUE, ANSI_CHARSET, OUT_RASTER_PRECIS, + ANTIALIASED_QUALITY, VARIABLE_PITCH, "Tahoma", &font); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, testW, -1, NULL, 0, color); - ok(height == 12, "Unexpected height %d.\n", height); + hr = ID3DX10Font_GetDescA(font, NULL); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, testW, -1, NULL, DT_CALCRECT, color); - ok(height == 12, "Unexpected height %d.\n", height); + hr = ID3DX10Font_GetDescA(font, &desc); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, NULL, -1, NULL, 0, color); - ok(height == 0, "Unexpected height %d.\n", height); + ok(desc.Height == 12, "Unexpected height %d.\n", desc.Height); + ok(desc.Width == 8, "Unexpected width %u.\n", desc.Width); + ok(desc.Weight == FW_BOLD, "Unexpected weight %u.\n", desc.Weight); + ok(desc.MipLevels == 2, "Unexpected miplevels %u.\n", desc.MipLevels); + ok(desc.Italic == TRUE, "Unexpected italic %#x.\n", desc.Italic); + ok(desc.CharSet == ANSI_CHARSET, "Unexpected charset %u.\n", desc.CharSet); + ok(desc.OutputPrecision == OUT_RASTER_PRECIS, "Unexpected output precision %u.\n", desc.OutputPrecision); + ok(desc.Quality == ANTIALIASED_QUALITY, "Unexpected quality %u.\n", desc.Quality); + ok(desc.PitchAndFamily == VARIABLE_PITCH, "Unexpected pitch and family %#x.\n", desc.PitchAndFamily); + ok(!strcmp(desc.FaceName, "Tahoma"), "Unexpected facename %s.\n", debugstr_a(desc.FaceName)); - SetRect(&rect, 10, 10, 50, 50); + ID3DX10Font_Release(font); - height = ID3DX10Font_DrawTextW(font, NULL, long_textW, -1, &rect, DT_WORDBREAK, color); - ok(height == 60, "Unexpected height %d.\n", height); + /* GetDC + GetTextMetrics */ + hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, long_textW, -1, &rect, DT_WORDBREAK | DT_NOCLIP, color); - ok(height == 96, "Unexpected height %d.\n", height); + hdc = ID3DX10Font_GetDC(font); + ok(!!hdc, "Unexpected hdc %p.\n", hdc); - height = ID3DX10Font_DrawTextW(font, NULL, L"a\na", -1, NULL, 0, color); - ok(height == 24, "Unexpected height %d.\n", height); + ret = GetTextMetricsA(hdc, &expmetrics); + ok(ret, "Unexpected ret %#x.\n", ret); - height = ID3DX10Font_DrawTextW(font, NULL, L"a\na", -1, &rect, 0, color); - ok(height == 24, "Unexpected height %d.\n", height); + ret = ID3DX10Font_GetTextMetricsA(font, &metrics); + ok(ret, "Unexpected ret %#x.\n", ret); - height = ID3DX10Font_DrawTextW(font, NULL, L"a\r\na", -1, &rect, 0, color); - ok(height == 24, "Unexpected height %d.\n", height); + ok(metrics.tmHeight == expmetrics.tmHeight, "Unexpected height %ld, expected %ld.\n", + metrics.tmHeight, expmetrics.tmHeight); + ok(metrics.tmAscent == expmetrics.tmAscent, "Unexpected ascent %ld, expected %ld.\n", + metrics.tmAscent, expmetrics.tmAscent); + ok(metrics.tmDescent == expmetrics.tmDescent, "Unexpected descent %ld, expected %ld.\n", + metrics.tmDescent, expmetrics.tmDescent); + ok(metrics.tmInternalLeading == expmetrics.tmInternalLeading, "Unexpected internal leading %ld, expected %ld.\n", + metrics.tmInternalLeading, expmetrics.tmInternalLeading); + ok(metrics.tmExternalLeading == expmetrics.tmExternalLeading, "Unexpected external leading %ld, expected %ld.\n", + metrics.tmExternalLeading, expmetrics.tmExternalLeading); + ok(metrics.tmAveCharWidth == expmetrics.tmAveCharWidth, "Unexpected average char width %ld, expected %ld.\n", + metrics.tmAveCharWidth, expmetrics.tmAveCharWidth); + ok(metrics.tmMaxCharWidth == expmetrics.tmMaxCharWidth, "Unexpected maximum char width %ld, expected %ld.\n", + metrics.tmMaxCharWidth, expmetrics.tmMaxCharWidth); + ok(metrics.tmWeight == expmetrics.tmWeight, "Unexpected weight %ld, expected %ld.\n", + metrics.tmWeight, expmetrics.tmWeight); + ok(metrics.tmOverhang == expmetrics.tmOverhang, "Unexpected overhang %ld, expected %ld.\n", + metrics.tmOverhang, expmetrics.tmOverhang); + ok(metrics.tmDigitizedAspectX == expmetrics.tmDigitizedAspectX, "Unexpected digitized x aspect %ld, expected %ld.\n", + metrics.tmDigitizedAspectX, expmetrics.tmDigitizedAspectX); + ok(metrics.tmDigitizedAspectY == expmetrics.tmDigitizedAspectY, "Unexpected digitized y aspect %ld, expected %ld.\n", + metrics.tmDigitizedAspectY, expmetrics.tmDigitizedAspectY); + ok(metrics.tmFirstChar == expmetrics.tmFirstChar, "Unexpected first char %u, expected %u.\n", + metrics.tmFirstChar, expmetrics.tmFirstChar); + ok(metrics.tmLastChar == expmetrics.tmLastChar, "Unexpected last char %u, expected %u.\n", + metrics.tmLastChar, expmetrics.tmLastChar); + ok(metrics.tmDefaultChar == expmetrics.tmDefaultChar, "Unexpected default char %u, expected %u.\n", + metrics.tmDefaultChar, expmetrics.tmDefaultChar); + ok(metrics.tmBreakChar == expmetrics.tmBreakChar, "Unexpected break char %u, expected %u.\n", + metrics.tmBreakChar, expmetrics.tmBreakChar); + ok(metrics.tmItalic == expmetrics.tmItalic, "Unexpected italic %u, expected %u.\n", + metrics.tmItalic, expmetrics.tmItalic); + ok(metrics.tmUnderlined == expmetrics.tmUnderlined, "Unexpected underlined %u, expected %u.\n", + metrics.tmUnderlined, expmetrics.tmUnderlined); + ok(metrics.tmStruckOut == expmetrics.tmStruckOut, "Unexpected struck out %u, expected %u.\n", + metrics.tmStruckOut, expmetrics.tmStruckOut); + ok(metrics.tmPitchAndFamily == expmetrics.tmPitchAndFamily, "Unexpected pitch and family %u, expected %u.\n", + metrics.tmPitchAndFamily, expmetrics.tmPitchAndFamily); + ok(metrics.tmCharSet == expmetrics.tmCharSet, "Unexpected charset %u, expected %u.\n", + metrics.tmCharSet, expmetrics.tmCharSet); - height = ID3DX10Font_DrawTextW(font, NULL, L"a\ra", -1, &rect, 0, color); - ok(height == 12, "Unexpected height %d.\n", height); + ID3DX10Font_Release(font); - height = ID3DX10Font_DrawTextW(font, NULL, L"a\na", -1, &rect, DT_SINGLELINE, color); - ok(height == 12, "Unexpected height %d.\n", height); + /* PreloadText */ + hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, L"a\naaaaa aaaa", -1, &rect, DT_SINGLELINE, color); - ok(height == 12, "Unexpected height %d.\n", height); + hr = ID3DX10Font_PreloadTextA(font, NULL, -1); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_PreloadTextA(font, NULL, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_PreloadTextA(font, NULL, 1); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_PreloadTextA(font, "test", -1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_PreloadTextA(font, "", 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_PreloadTextA(font, "", -1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, L"a\naaaaa aaaa", -1, &rect, 0, color); - ok(height == 24, "Unexpected height %d.\n", height); + hr = ID3DX10Font_PreloadTextW(font, NULL, -1); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_PreloadTextW(font, NULL, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_PreloadTextW(font, NULL, 1); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_PreloadTextW(font, testW, -1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_PreloadTextW(font, L"", 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_PreloadTextW(font, L"", -1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, L"a\naaaaa aaaa", -1, &rect, DT_WORDBREAK, color); - ok(height == 36, "Unexpected height %d.\n", height); + ID3DX10Font_Release(font); - height = ID3DX10Font_DrawTextW(font, NULL, L"a\naaaaa aaaa", -1, &rect, DT_WORDBREAK | DT_SINGLELINE, color); - ok(height == 12, "Unexpected height %d.\n", height); + /* GetGlyphData, PreloadGlyphs, PreloadCharacters */ + hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, L"1\n2\n3\n4\n5\n6", -1, &rect, 0, color); - ok(height == 48, "Unexpected height %d.\n", height); + hdc = ID3DX10Font_GetDC(font); + ok(!!hdc, "Unexpected hdc %p.\n", hdc); - height = ID3DX10Font_DrawTextW(font, NULL, L"1\n2\n3\n4\n5\n6", -1, &rect, DT_NOCLIP, color); - ok(height == 72, "Unexpected height %d.\n", height); + hr = ID3DX10Font_GetGlyphData(font, 0, NULL, &blackbox, &cellinc); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_GetGlyphData(font, 0, &srv, NULL, &cellinc); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10ShaderResourceView_Release(srv); + hr = ID3DX10Font_GetGlyphData(font, 0, &srv, &blackbox, NULL); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D10ShaderResourceView_Release(srv); - height = ID3DX10Font_DrawTextW(font, NULL, L"\t\t\t\t\t\t\t\t\t\t", -1, &rect, DT_WORDBREAK, color); - ok(height == 0, "Unexpected height %d.\n", height); + hr = ID3DX10Font_PreloadCharacters(font, 'b', 'a'); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Font_PreloadGlyphs(font, 1, 0); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, L"\t\t\t\t\t\t\t\t\t\ta", -1, &rect, DT_WORDBREAK, color); - ok(height == 12, "Unexpected height %d.\n", height); + hr = ID3DX10Font_PreloadCharacters(font, 'a', 'a'); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, L"\taaaaaaaaaa", -1, &rect, DT_WORDBREAK, color); - ok(height == 24, "Unexpected height %d.\n", height); + for (c = 'b'; c <= 'z'; ++c) + { + winetest_push_context("Character %c", c); + count = GetGlyphIndicesA(hdc, &c, 1, &glyph, 0); + ok(count != GDI_ERROR, "Unexpected count %u.\n", count); - height = ID3DX10Font_DrawTextW(font, NULL, L"\taaaaaaaaaa", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, color); - ok(height == 36, "Unexpected height %d.\n", height); + hr = ID3DX10Font_GetGlyphData(font, glyph, &srv, &blackbox, &cellinc); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, L"\taaa\taaa\taaa", -1, &rect, DT_WORDBREAK, color); - ok(height == 24, "Unexpected height %d.\n", height); + if (FAILED(hr)) + { + winetest_pop_context(); + break; + } - height = ID3DX10Font_DrawTextW(font, NULL, L"\taaa\taaa\taaa", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, color); - ok(height == 48, "Unexpected height %d.\n", height); + ID3D10ShaderResourceView_GetResource(srv, &resource); + hr = ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture2D, (void **)&texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ID3D10Resource_Release(resource); - height = ID3DX10Font_DrawTextW(font, NULL, L"\t\t\t\t\t\t\t\t\t\t", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, color); - ok(height == 60, "Unexpected height %d.\n", height); + ID3D10Texture2D_GetDesc(texture, &texture_desc); + ok(texture_desc.Width == 256, "Unexpected width %u.\n", texture_desc.Width); + ok(texture_desc.Height == 256, "Unexpected height %u.\n", texture_desc.Height); + ok(texture_desc.MipLevels == 5, "Unexpected miplevels %u.\n", texture_desc.MipLevels); + ok(texture_desc.ArraySize == 1, "Unexpected array size %u.\n", texture_desc.ArraySize); + ok(texture_desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", + texture_desc.Format); + ok(texture_desc.SampleDesc.Count == 1, "Unexpected samples count %u.\n", + texture_desc.SampleDesc.Count); + ok(texture_desc.SampleDesc.Quality == 0, "Unexpected quality level %u.\n", + texture_desc.SampleDesc.Quality); + ok(texture_desc.Usage == 0, "Unexpected usage %#x.\n", texture_desc.Usage); + ok(texture_desc.BindFlags == D3D10_BIND_SHADER_RESOURCE, "Unexpected bind flags %#x.\n", + texture_desc.BindFlags); + ok(texture_desc.CPUAccessFlags == 0, "Unexpected access flags %#x.\n", + texture_desc.CPUAccessFlags); + ok(texture_desc.MiscFlags == 0, "Unexpected misc flags %#x.\n", texture_desc.MiscFlags); - height = ID3DX10Font_DrawTextW(font, NULL, L"a\ta", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, color); - ok(height == 12, "Unexpected height %d.\n", height); + count = GetGlyphOutlineW(hdc, glyph, GGO_GLYPH_INDEX | GGO_METRICS, &glyph_metrics, 0, NULL, &mat); + ok(count != GDI_ERROR, "Unexpected count %#x.\n", count); - height = ID3DX10Font_DrawTextW(font, NULL, L"a\ta\ta", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, color); - ok(height == 24, "Unexpected height %d.\n", height); + ret = ID3DX10Font_GetTextMetricsW(font, &tm); + ok(ret, "Unexpected ret %#x.\n", ret); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaaaaaaaaaaaaaaaaaa", -1, &rect, DT_WORDBREAK, color); - ok(height == 36, "Unexpected height %d.\n", height); + todo_wine ok(blackbox.right - blackbox.left == glyph_metrics.gmBlackBoxX + 2, "Got %ld, expected %d.\n", + blackbox.right - blackbox.left, glyph_metrics.gmBlackBoxX + 2); + todo_wine ok(blackbox.bottom - blackbox.top == glyph_metrics.gmBlackBoxY + 2, "Got %ld, expected %d.\n", + blackbox.bottom - blackbox.top, glyph_metrics.gmBlackBoxY + 2); + ok(cellinc.x == glyph_metrics.gmptGlyphOrigin.x - 1, "Got %ld, expected %ld.\n", + cellinc.x, glyph_metrics.gmptGlyphOrigin.x - 1); + ok(cellinc.y == tm.tmAscent - glyph_metrics.gmptGlyphOrigin.y - 1, "Got %ld, expected %ld.\n", + cellinc.y, tm.tmAscent - glyph_metrics.gmptGlyphOrigin.y - 1); - height = ID3DX10Font_DrawTextW(font, NULL, L"a a", -1, &rect, DT_WORDBREAK, color); - ok(height == 36, "Unexpected height %d.\n", height); + ID3D10Texture2D_Release(texture); + winetest_pop_context(); + } - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK, color); - ok(height == 36, "Unexpected height %d.\n", height); + hr = ID3DX10Font_PreloadCharacters(font, 'a', 'z'); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_RIGHT, color); - ok(height == 36, "Unexpected height %d.\n", height); +#if D3DX10_SDK_VERSION > 34 + /* Test multiple textures. + * Native d3dx10_34.dll shows signs of memory corruption in this call. */ + hr = ID3DX10Font_PreloadGlyphs(font, 0, 1000); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +#endif - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CENTER, color); - ok(height == 36, "Unexpected height %d.\n", height); + /* Test glyphs that are not rendered */ + for (glyph = 1; glyph < 4; ++glyph) + { + srv = (void *)0xdeadbeef; + hr = ID3DX10Font_GetGlyphData(font, glyph, &srv, &blackbox, &cellinc); + todo_wine { + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!srv, "Unexpected resource view %p.\n", srv); + } + } - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM, color); - ok(height == 40, "Unexpected height %d.\n", height); + ID3DX10Font_Release(font); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER, color); - ok(height == 32, "Unexpected height %d.\n", height); + c = 'a'; + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("Test %u", i); + hr = D3DX10CreateFontA(device, tests[i].font_height, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT, color); - ok(height == 24, "Unexpected height %d.\n", height); + hdc = ID3DX10Font_GetDC(font); + ok(!!hdc, "Unexpected hdc %p.\n", hdc); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER, color); - ok(height == 24, "Unexpected height %d.\n", height); + count = GetGlyphIndicesA(hdc, &c, 1, &glyph, 0); + ok(count != GDI_ERROR, "Unexpected count %u.\n", count); - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 10, 30, 34); + hr = ID3DX10Font_GetGlyphData(font, glyph, &srv, NULL, NULL); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, -10, 10, 10, 34); + if (FAILED(hr)) + { + ID3DX10Font_Release(font); + winetest_pop_context(); + break; + } - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 10, -10, 30, 14); + ID3D10ShaderResourceView_GetResource(srv, &resource); + hr = ID3D10Resource_QueryInterface(resource, &IID_ID3D10Texture2D, (void **)&texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ID3D10Resource_Release(resource); - SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 10, 30, 34); + ID3D10Texture2D_GetDesc(texture, &texture_desc); - SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 10, 30, 34); + ok(texture_desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", + texture_desc.Format); + ok(texture_desc.Usage == 0, "Unexpected usage %#x.\n", texture_desc.Usage); + ok(texture_desc.Width == tests[i].expected_size, "Unexpected width %u.\n", texture_desc.Width); + ok(texture_desc.Height == tests[i].expected_size, "Unexpected height %u.\n", texture_desc.Height); + ok(texture_desc.CPUAccessFlags == 0, "Unexpected access flags %#x.\n", + texture_desc.CPUAccessFlags); + ok(texture_desc.BindFlags == D3D10_BIND_SHADER_RESOURCE, "Unexpected bind flags %#x.\n", + texture_desc.BindFlags); - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 10, 30, 34); + ID3D10Texture2D_Release(texture); - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, -10, 10, 10, 34); + /* DrawText */ + hr = D3DX10CreateSprite(device, 0, &sprite); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + SetRect(&rect, 0, 0, 640, 480); - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 10, -10, 30, 14); + hr = ID3DX10Sprite_Begin(sprite, 0); + ok (hr == S_OK, "Unexpected hr %#lx.\n", hr); - SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 12, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 10, 53, 22); + height = ID3DX10Font_DrawTextW(font, sprite, testW, -1, &rect, DT_TOP, white); + ok(height == tests[i].font_height, "Unexpected height %u.\n", height); + height = ID3DX10Font_DrawTextW(font, sprite, testW, size, &rect, DT_TOP, white); + ok(height == tests[i].font_height, "Unexpected height %u.\n", height); + height = ID3DX10Font_DrawTextW(font, sprite, testW, size, &rect, DT_RIGHT, white); + ok(height == tests[i].font_height, "Unexpected height %u.\n", height); + height = ID3DX10Font_DrawTextW(font, sprite, testW, size, &rect, DT_LEFT | DT_NOCLIP, white); + ok(height == tests[i].font_height, "Unexpected height %u.\n", height); - SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 10, 30, 34); + SetRectEmpty(&rect); + height = ID3DX10Font_DrawTextW(font, sprite, testW, size, &rect, + DT_LEFT | DT_CALCRECT, white); + ok(height == tests[i].font_height, "Unexpected height %u.\n", height); + ok(!rect.left, "Unexpected rect left %ld.\n", rect.left); + ok(!rect.top, "Unexpected rect top %ld.\n", rect.top); + ok(rect.right, "Unexpected rect right %ld.\n", rect.right); + ok(rect.bottom == tests[i].font_height, "Unexpected rect bottom %ld.\n", rect.bottom); - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, color); - ok(height == 40, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 26, 30, 50); + hr = ID3DX10Sprite_End(sprite); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ID3DX10Sprite_Release(sprite); - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, color); - ok(height == 40, "Unexpected height %d.\n", height); - check_rect(&rect, -10, 26, 10, 50); + ID3DX10Font_Release(font); + winetest_pop_context(); + } - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, color); - ok(height == 40, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 6, 30, 30); + if (!strcmp(winetest_platform, "wine")) + return; - SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, color); - ok(height == 40, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 26, 30, 50); + /* DrawText */ + hr = D3DX10CreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, color); - ok(height == -40, "Unexpected height %d.\n", height); - check_rect(&rect, 10, -54, 30, -30); + SetRect(&rect, 10, 10, 200, 200); - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 40, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 26, 30, 50); + height = ID3DX10Font_DrawTextA(font, NULL, "test", -2, &rect, 0, color); + ok(height == 12, "Unexpected height %d.\n", height); - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 40, "Unexpected height %d.\n", height); - check_rect(&rect, -10, 26, 10, 50); + height = ID3DX10Font_DrawTextA(font, NULL, "test", -1, &rect, 0, color); + ok(height == 12, "Unexpected height %d.\n", height); - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 40, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 6, 30, 30); + height = ID3DX10Font_DrawTextA(font, NULL, "test", 0, &rect, 0, color); + ok(height == 0, "Unexpected height %d.\n", height); - SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 40, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 38, 53, 50); + height = ID3DX10Font_DrawTextA(font, NULL, "test", 1, &rect, 0, color); + ok(height == 12, "Unexpected height %d.\n", height); - SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == -40, "Unexpected height %d.\n", height); - check_rect(&rect, 10, -54, 30, -30); + height = ID3DX10Font_DrawTextA(font, NULL, "test", 2, &rect, 0, color); + ok(height == 12, "Unexpected height %d.\n", height); - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 18, 30, 42); + height = ID3DX10Font_DrawTextA(font, NULL, "", 0, &rect, 0, color); + ok(height == 0, "Unexpected height %d.\n", height); - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, -10, 18, 10, 42); + height = ID3DX10Font_DrawTextA(font, NULL, "", -1, &rect, 0, color); + ok(height == 0, "Unexpected height %d.\n", height); - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 10, -2, 30, 22); + height = ID3DX10Font_DrawTextA(font, NULL, "test", -1, NULL, 0, color); + ok(height == 12, "Unexpected height %d.\n", height); - SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 18, 30, 42); + height = ID3DX10Font_DrawTextA(font, NULL, "test", -1, NULL, DT_CALCRECT, color); + ok(height == 12, "Unexpected height %d.\n", height); - SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, color); - ok(height == -8, "Unexpected height %d.\n", height); - check_rect(&rect, 10, -22, 30, 2); + height = ID3DX10Font_DrawTextA(font, NULL, NULL, -1, NULL, 0, color); + ok(height == 0, "Unexpected height %d.\n", height); SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 18, 30, 42); - - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, -10, 18, 10, 42); - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 10, -2, 30, 22); + height = ID3DX10Font_DrawTextA(font, NULL, long_text, -1, &rect, DT_WORDBREAK, color); + ok(height == 60, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextA(font, NULL, long_text, -1, &rect, DT_WORDBREAK | DT_NOCLIP, color); + ok(height == 96, "Unexpected height %d.\n", height); + + SetRect(&rect, 10, 10, 200, 200); + + height = ID3DX10Font_DrawTextW(font, NULL, testW, -1, &rect, 0, color); + ok(height == 12, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, testW, 0, &rect, 0, color); + ok(height == 0, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, testW, 1, &rect, 0, color); + ok(height == 12, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, testW, 2, &rect, 0, color); + ok(height == 12, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"", 0, &rect, 0, color); + ok(height == 0, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"", -1, &rect, 0, color); + ok(height == 0, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, testW, -1, NULL, 0, color); + ok(height == 12, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, testW, -1, NULL, DT_CALCRECT, color); + ok(height == 12, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, NULL, -1, NULL, 0, color); + ok(height == 0, "Unexpected height %d.\n", height); + + SetRect(&rect, 10, 10, 50, 50); + + height = ID3DX10Font_DrawTextW(font, NULL, long_textW, -1, &rect, DT_WORDBREAK, color); + ok(height == 60, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, long_textW, -1, &rect, DT_WORDBREAK | DT_NOCLIP, color); + ok(height == 96, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a\na", -1, NULL, 0, color); + ok(height == 24, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a\na", -1, &rect, 0, color); + ok(height == 24, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a\r\na", -1, &rect, 0, color); + ok(height == 24, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a\ra", -1, &rect, 0, color); + ok(height == 12, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a\na", -1, &rect, DT_SINGLELINE, color); + ok(height == 12, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a\naaaaa aaaa", -1, &rect, DT_SINGLELINE, color); + ok(height == 12, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a\naaaaa aaaa", -1, &rect, 0, color); + ok(height == 24, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a\naaaaa aaaa", -1, &rect, DT_WORDBREAK, color); + ok(height == 36, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a\naaaaa aaaa", -1, &rect, DT_WORDBREAK | DT_SINGLELINE, color); + ok(height == 12, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"1\n2\n3\n4\n5\n6", -1, &rect, 0, color); + ok(height == 48, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"1\n2\n3\n4\n5\n6", -1, &rect, DT_NOCLIP, color); + ok(height == 72, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"\t\t\t\t\t\t\t\t\t\t", -1, &rect, DT_WORDBREAK, color); + ok(height == 0, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"\t\t\t\t\t\t\t\t\t\ta", -1, &rect, DT_WORDBREAK, color); + ok(height == 12, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"\taaaaaaaaaa", -1, &rect, DT_WORDBREAK, color); + ok(height == 24, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"\taaaaaaaaaa", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, color); + ok(height == 36, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"\taaa\taaa\taaa", -1, &rect, DT_WORDBREAK, color); + ok(height == 24, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"\taaa\taaa\taaa", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, color); + ok(height == 48, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"\t\t\t\t\t\t\t\t\t\t", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, color); + ok(height == 60, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a\ta", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, color); + ok(height == 12, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a\ta\ta", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, color); + ok(height == 24, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaaaaaaaaaaaaaaaaaa", -1, &rect, DT_WORDBREAK, color); + ok(height == 36, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"a a", -1, &rect, DT_WORDBREAK, color); + ok(height == 36, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK, color); + ok(height == 36, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_RIGHT, color); + ok(height == 36, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CENTER, color); + ok(height == 36, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM, color); + ok(height == 40, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER, color); + ok(height == 32, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT, color); + ok(height == 24, "Unexpected height %d.\n", height); + + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER, color); + ok(height == 24, "Unexpected height %d.\n", height); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, -10, 10, 10, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 10, -10, 30, 14); SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 26, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 24, 53, 36); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, -10, 10, 10, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 10, -10, 30, 14); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 12, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 53, 22); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, color); + ok(height == 40, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 26, 30, 50); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, color); + ok(height == 40, "Unexpected height %d.\n", height); + check_rect(&rect, -10, 26, 10, 50); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, color); + ok(height == 40, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 6, 30, 30); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, color); + ok(height == 40, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 26, 30, 50); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, color); + ok(height == -40, "Unexpected height %d.\n", height); + check_rect(&rect, 10, -54, 30, -30); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 40, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 26, 30, 50); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 40, "Unexpected height %d.\n", height); + check_rect(&rect, -10, 26, 10, 50); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 40, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 6, 30, 30); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 40, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 38, 53, 50); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == -40, "Unexpected height %d.\n", height); + check_rect(&rect, 10, -54, 30, -30); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 18, 30, 42); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, -10, 18, 10, 42); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 10, -2, 30, 22); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 18, 30, 42); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, color); ok(height == -8, "Unexpected height %d.\n", height); check_rect(&rect, 10, -22, 30, 2); SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 30, 10, 50, 34); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 18, 30, 42); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, -10, 18, 10, 42); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 10, -2, 30, 22); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 26, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 24, 53, 36); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == -8, "Unexpected height %d.\n", height); + check_rect(&rect, 10, -22, 30, 2); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 30, 10, 50, 34); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 30, -10, 50, 14); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, -50, 10, -30, 34); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 30, 10, 50, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 30, 10, 50, 34); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 30, -10, 50, 14); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 12, "Unexpected height %d.\n", height); + check_rect(&rect, -73, 10, -30, 22); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 30, 10, 50, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 20, 10, 40, 34); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 0, 10, 20, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 20, -10, 40, 14); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, -20, 10, 0, 34); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 20, 10, 40, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 20, 10, 40, 34); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 0, 10, 20, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 20, -10, 40, 14); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 12, "Unexpected height %d.\n", height); + check_rect(&rect, -31, 10, 12, 22); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 24, "Unexpected height %d.\n", height); + check_rect(&rect, 20, 10, 40, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 20, 18, 40, 42); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 20, 18, 40, 42); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 0, 18, 20, 42); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 20, -2, 40, 22); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, -20, 18, 0, 42); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); + ok(height == -8, "Unexpected height %d.\n", height); + check_rect(&rect, 20, -22, 40, 2); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 20, 18, 40, 42); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 20, 18, 40, 42); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 0, 18, 20, 42); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 32, "Unexpected height %d.\n", height); + check_rect(&rect, 20, -2, 40, 22); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == 26, "Unexpected height %d.\n", height); + check_rect(&rect, -31, 24, 12, 36); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); + ok(height == -8, "Unexpected height %d.\n", height); + check_rect(&rect, 20, -22, 40, 2); + + ID3DX10Font_Release(font); +} + +static void test_sprite(void) +{ + ID3D10ShaderResourceView *srv1, *srv2; + ID3D10Texture2D *texture1, *texture2; + D3D10_TEXTURE2D_DESC texture_desc; + ID3D10Device *device, *device2; + D3DX10_SPRITE sprite_desc; + ID3DX10Sprite *sprite; + D3DXMATRIX mat, mat2; + ULONG refcount; + HRESULT hr; + static const D3DXMATRIX identity = + { + ._11 = 1.0f, + ._22 = 1.0f, + ._33 = 1.0f, + ._44 = 1.0f, + }; + + if (!(device = create_device())) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + texture_desc.Width = 64; + texture_desc.Height = 64; + texture_desc.MipLevels = 1; + texture_desc.ArraySize = 1; + texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + texture_desc.SampleDesc.Count = 1; + texture_desc.SampleDesc.Quality = 0; + texture_desc.Usage = D3D10_USAGE_DEFAULT; + texture_desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; + texture_desc.CPUAccessFlags = 0; + texture_desc.MiscFlags = 0; + + hr = ID3D10Device_CreateTexture2D(device, &texture_desc, NULL, &texture1); + ok(SUCCEEDED(hr), "Failed to create texture, hr %#lx.\n", hr); + + hr = ID3D10Device_CreateTexture2D(device, &texture_desc, NULL, &texture2); + ok(SUCCEEDED(hr), "Failed to create texture, hr %#lx.\n", hr); + + hr = ID3D10Device_CreateShaderResourceView(device, (ID3D10Resource *)texture1, NULL, &srv1); + ok(SUCCEEDED(hr), "Failed to create srv, hr %#lx.\n", hr); + + hr = ID3D10Device_CreateShaderResourceView(device, (ID3D10Resource *)texture1, NULL, &srv2); + ok(SUCCEEDED(hr), "Failed to create srv, hr %#lx.\n", hr); + + hr = D3DX10CreateSprite(device, 0, NULL); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + + hr = D3DX10CreateSprite(NULL, 0, &sprite); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + + hr = D3DX10CreateSprite(device, 0, &sprite); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* GetDevice */ + hr = ID3DX10Sprite_GetDevice(sprite, NULL); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + hr = ID3DX10Sprite_GetDevice(sprite, &device2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(device == device2, "Unexpected device.\n"); + + ID3D10Device_Release(device2); + + /* Projection transform */ + hr = ID3DX10Sprite_GetProjectionTransform(sprite, NULL); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Sprite_GetProjectionTransform(sprite, &mat); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!memcmp(&mat, &identity, sizeof(mat)), "Unexpected projection transform.\n"); + + /* Set a transform and test if it gets returned correctly */ + mat.m[0][0] = 2.1f; mat.m[0][1] = 6.5f; mat.m[0][2] =-9.6f; mat.m[0][3] = 1.7f; + mat.m[1][0] = 4.2f; mat.m[1][1] =-2.5f; mat.m[1][2] = 2.1f; mat.m[1][3] = 5.5f; + mat.m[2][0] =-2.6f; mat.m[2][1] = 0.3f; mat.m[2][2] = 8.6f; mat.m[2][3] = 8.4f; + mat.m[3][0] = 6.7f; mat.m[3][1] =-5.1f; mat.m[3][2] = 6.1f; mat.m[3][3] = 2.2f; + + hr = ID3DX10Sprite_SetProjectionTransform(sprite, NULL); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + hr = ID3DX10Sprite_SetProjectionTransform(sprite, &mat); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = ID3DX10Sprite_GetProjectionTransform(sprite, &mat2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!memcmp(&mat, &mat2, sizeof(mat)), "Unexpected matrix.\n"); + + /* View transform */ + hr = ID3DX10Sprite_SetViewTransform(sprite, NULL); + todo_wine + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + hr = ID3DX10Sprite_SetViewTransform(sprite, &mat); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Begin */ + hr = ID3DX10Sprite_Begin(sprite, 0); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Flush/End */ + hr = ID3DX10Sprite_Flush(sprite); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = ID3DX10Sprite_End(sprite); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* May not be called before next Begin */ + hr = ID3DX10Sprite_Flush(sprite); + todo_wine + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + hr = ID3DX10Sprite_End(sprite); + todo_wine + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + /* Draw */ + hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, NULL, 0); + todo_wine + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + memset(&sprite_desc, 0, sizeof(sprite_desc)); + hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, &sprite_desc, 0); + todo_wine + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, &sprite_desc, 1); + todo_wine + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + hr = ID3DX10Sprite_Begin(sprite, 0); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + memset(&sprite_desc, 0, sizeof(sprite_desc)); + hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, &sprite_desc, 1); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + sprite_desc.pTexture = srv1; + hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, &sprite_desc, 1); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = ID3DX10Sprite_Flush(sprite); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = ID3DX10Sprite_Flush(sprite); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = ID3DX10Sprite_End(sprite); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* D3DX10_SPRITE_ADDREF_TEXTURES */ + hr = ID3DX10Sprite_Begin(sprite, D3DX10_SPRITE_ADDREF_TEXTURES); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + memset(&sprite_desc, 0, sizeof(sprite_desc)); + sprite_desc.pTexture = srv1; + + refcount = get_refcount(srv1); + hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, &sprite_desc, 1); +todo_wine { + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(get_refcount(srv1) > refcount, "Unexpected refcount.\n"); +} + + hr = ID3DX10Sprite_Flush(sprite); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(get_refcount(srv1) == refcount, "Unexpected refcount.\n"); + + hr = ID3DX10Sprite_End(sprite); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + ID3DX10Sprite_Release(sprite); + ID3D10Texture2D_Release(texture1); + ID3D10Texture2D_Release(texture2); + ID3D10ShaderResourceView_Release(srv1); + ID3D10ShaderResourceView_Release(srv2); + + refcount = ID3D10Device_Release(device); + ok(!refcount, "Unexpected refcount.\n"); +} + +static void test_create_effect_from_memory(void) +{ + ID3D10Device *device; + ID3D10Effect *effect; + ID3D10Blob *errors; + ULONG refcount; + HRESULT hr; + + if (!(device = create_device())) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + /* Test NULL data. */ + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromMemory(NULL, 0, NULL, NULL, NULL, NULL, + 0x0, 0x0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + /* Test NULL device. */ + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromMemory(test_fx, sizeof(test_fx), NULL, NULL, NULL, NULL, + 0x0, 0x0, NULL, NULL, NULL, &effect, &errors, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + /* Test creating effect from compiled shader. */ + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromMemory(test_fx, sizeof(test_fx), NULL, NULL, NULL, NULL, + 0x0, 0x0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!errors, "Got unexpected errors %p.\n", errors); + ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + effect->lpVtbl->Release(effect); + + /* Test creating effect from source without setting profile. */ + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromMemory(test_fx_source, strlen(test_fx_source) + 1, NULL, NULL, NULL, NULL, + 0x0, 0x0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(!!errors && errors != (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + if (errors && errors != (ID3D10Blob *)0xdeadbeef) + ID3D10Blob_Release(errors); + + /* Test creating effect from source. */ + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromMemory(test_fx_source, strlen(test_fx_source) + 1, NULL, NULL, NULL, "fx_4_0", + 0x0, 0x0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!errors, "Got unexpected errors %p.\n", errors); + ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + effect->lpVtbl->Release(effect); + + refcount = ID3D10Device_Release(device); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); +} + +static void test_create_effect_from_file(void) +{ + static const WCHAR *test_file_name = L"test.fx"; + WCHAR path[MAX_PATH]; + ID3D10Device *device; + ID3D10Effect *effect; + ID3D10Blob *errors; + ULONG refcount; + HRESULT hr; + + if (!(device = create_device())) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + /* Test NULL file name. */ + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromFileW(NULL, NULL, NULL, NULL, 0x0, 0x0, + device, NULL, NULL, &effect, &errors, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromFileA(NULL, NULL, NULL, NULL, 0x0, 0x0, + device, NULL, NULL, &effect, &errors, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + /* Test non-existent file. */ + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromFileW(L"deadbeef", NULL, NULL, NULL, 0x0, 0x0, + device, NULL, NULL, &effect, &errors, NULL); + ok(hr == D3D10_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(!errors, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromFileA("deadbeef", NULL, NULL, NULL, 0x0, 0x0, + device, NULL, NULL, &effect, &errors, NULL); + ok(hr == D3D10_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + todo_wine ok(!errors, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + /* Test creating effect from compiled shader file. */ + create_file(test_file_name, test_fx, sizeof(test_fx), path); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromFileW(path, NULL, NULL, NULL, 0x0, 0x0, + device, NULL, NULL, &effect, &errors, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!errors, "Got unexpected errors %p.\n", errors); + ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + effect->lpVtbl->Release(effect); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromFileA(get_str_a(path), NULL, NULL, NULL, 0x0, 0x0, + device, NULL, NULL, &effect, &errors, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!errors, "Got unexpected errors %p.\n", errors); + ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + effect->lpVtbl->Release(effect); + + delete_file(test_file_name); + + /* Test creating effect from source file. */ + create_file(test_file_name, test_fx_source, strlen(test_fx_source) + 1, path); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromFileW(path, NULL, NULL, "fx_4_0", 0x0, 0x0, + device, NULL, NULL, &effect, &errors, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!errors, "Got unexpected errors %p.\n", errors); + ok(effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + effect->lpVtbl->Release(effect); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromFileA(get_str_a(path), NULL, NULL, "fx_4_0", 0x0, 0x0, + device, NULL, NULL, &effect, &errors, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!errors, "Got unexpected errors %p.\n", errors); + ok(effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + effect->lpVtbl->Release(effect); + + delete_file(test_file_name); + + refcount = ID3D10Device_Release(device); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); +} + +static void test_create_effect_from_resource(void) +{ + static const WCHAR *test_resource_name = L"test.fx"; + HMODULE resource_module; + ID3D10Device *device; + ID3D10Effect *effect; + ID3D10Blob *errors; + ULONG refcount; + HRESULT hr; + + if (!(device = create_device())) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + /* Test NULL module. */ + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromResourceW(NULL, NULL, NULL, NULL, NULL, NULL, + 0, 0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromResourceA(NULL, NULL, NULL, NULL, NULL, NULL, + 0, 0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + /* Test NULL resource name. */ + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromResourceW(GetModuleHandleW(NULL), NULL, NULL, NULL, NULL, NULL, + 0, 0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromResourceA(GetModuleHandleA(NULL), NULL, NULL, NULL, NULL, NULL, + 0, 0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + /* Test non-existent resource name. */ + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromResourceW(GetModuleHandleW(NULL), L"deadbeef", NULL, NULL, NULL, NULL, + 0, 0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromResourceA(GetModuleHandleA(NULL), "deadbeef", NULL, NULL, NULL, NULL, + 0, 0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); + ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + + /* Test creating effect from compiled shader resource. */ + resource_module = create_resource_module(test_resource_name, test_fx, sizeof(test_fx)); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromResourceW(resource_module, test_resource_name, NULL, NULL, NULL, NULL, + 0, 0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!errors, "Got unexpected errors %p.\n", errors); + ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + effect->lpVtbl->Release(effect); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromResourceA(resource_module, get_str_a(test_resource_name), NULL, NULL, NULL, NULL, + 0, 0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!errors, "Got unexpected errors %p.\n", errors); + ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + effect->lpVtbl->Release(effect); + + delete_resource_module(test_resource_name, resource_module); + + /* Test creating effect from source resource. */ + resource_module = create_resource_module(test_resource_name, test_fx_source, strlen(test_fx_source) + 1); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromResourceW(resource_module, test_resource_name, NULL, NULL, NULL, "fx_4_0", + 0, 0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!errors, "Got unexpected errors %p.\n", errors); + ok(effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + effect->lpVtbl->Release(effect); + + errors = (ID3D10Blob *)0xdeadbeef; + effect = (ID3D10Effect *)0xdeadbeef; + hr = D3DX10CreateEffectFromResourceA(resource_module, get_str_a(test_resource_name), NULL, NULL, NULL, "fx_4_0", + 0, 0, device, NULL, NULL, &effect, &errors, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!errors, "Got unexpected errors %p.\n", errors); + ok(effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + effect->lpVtbl->Release(effect); + + delete_resource_module(test_resource_name, resource_module); + + refcount = ID3D10Device_Release(device); + ok(!refcount, "Got unexpected refcount %lu.\n", refcount); +} + +static void test_preprocess_shader(void) +{ + static const char shader_source[] = + "float4 main()\n" + "{\n" + " return float4(1.0);\n" + "}\n"; + ID3D10Blob *preprocessed, *errors; + HRESULT hr, hr2; + + hr2 = 0xdeadbeef; + hr = D3DX10PreprocessShaderFromMemory(NULL, 0, NULL, NULL, NULL, + NULL, &preprocessed, &errors, &hr2); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Unexpected hr2 %#lx.\n", hr2); + + hr2 = 0xdeadbeef; + hr = D3DX10PreprocessShaderFromMemory(shader_source, strlen(shader_source), NULL, NULL, NULL, + NULL, &preprocessed, &errors, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!preprocessed, "Unexpected preprocessed %p.\n", preprocessed); + ok(!errors, "Unexpected errors %p.\n", errors); + ID3D10Blob_Release(preprocessed); + + hr2 = 0xdeadbeef; + hr = D3DX10PreprocessShaderFromMemory(shader_source, strlen(shader_source), NULL, NULL, NULL, + NULL, &preprocessed, &errors, &hr2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Unexpected hr2 %#lx.\n", hr2); + ok(!!preprocessed, "Unexpected preprocessed %p.\n", preprocessed); + ok(!errors, "Unexpected errors %p.\n", errors); + ID3D10Blob_Release(preprocessed); +} + +/* + * 4x4 RGBA cubemap with faces in the following order: blue, green, red, + * green/blue, red/blue, red/green. + */ +static const uint8_t rgba_4_4_cubemap[] = +{ + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff, + 0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff, + 0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff, + 0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff, + 0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff, + 0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff, + 0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff, + 0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff, + 0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, + 0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, + 0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, + 0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, +}; + +/* + * 8x8 (BC1-BC3) image data, four 4x4 blocks: + * +-----+-----+ + * |Blue |Green| + * | | | + * +-----+-----+ + * |Red |Black| + * | | | + * +-----+-----+ + */ +static const uint8_t bc1_8_8[] = +{ + 0x1f,0x00,0x1f,0x00,0xaa,0xaa,0xaa,0xaa,0xe0,0x07,0xe0,0x07,0xaa,0xaa,0xaa,0xaa, + 0x00,0xf8,0x00,0xf8,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, +}; + +static const uint8_t bc2_8_8[] = +{ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x1f,0x00,0xaa,0xaa,0xaa,0xaa, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x07,0xe0,0x07,0xaa,0xaa,0xaa,0xaa, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0x00,0xf8,0xaa,0xaa,0xaa,0xaa, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, +}; + +static const uint8_t bc3_8_8[] = +{ + 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00, + 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x07,0xe0,0x07,0x00,0x00,0x00,0x00, + 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0x00, + 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t bc1_to_bc3_8_8_decompressed[] = +{ + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff, +}; + +static const uint8_t bc4_unorm_8_8[] = +{ + 0xff,0xff,0x49,0x92,0x24,0x49,0x92,0x24,0x80,0x80,0x49,0x92,0x24,0x49,0x92,0x24, + 0x00,0x00,0x49,0x92,0x24,0x49,0x92,0x24,0x40,0x40,0x49,0x92,0x24,0x49,0x92,0x24, +}; + +static const uint8_t r8_unorm_8_8_decompressed[] = +{ + 0xff,0xff,0xff,0xff,0x80,0x80,0x80,0x80,0xff,0xff,0xff,0xff,0x80,0x80,0x80,0x80, + 0xff,0xff,0xff,0xff,0x80,0x80,0x80,0x80,0xff,0xff,0xff,0xff,0x80,0x80,0x80,0x80, + 0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40, + 0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40, +}; - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 10, 30, 34); +static const uint8_t bc5_unorm_8_8[] = +{ + 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xdf,0xdf,0x00,0x00,0x00,0x00,0x00,0x00, + 0xbf,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x9f,0x9f,0x00,0x00,0x00,0x00,0x00,0x00, + 0x7f,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x5f,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3f,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, +}; - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 30, -10, 50, 14); +static const uint8_t r8g8_unorm_8_8_decompressed[] = +{ + 0xff,0xdf,0xff,0xdf,0xff,0xdf,0xff,0xdf,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f, + 0xff,0xdf,0xff,0xdf,0xff,0xdf,0xff,0xdf,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f, + 0xff,0xdf,0xff,0xdf,0xff,0xdf,0xff,0xdf,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f, + 0xff,0xdf,0xff,0xdf,0xff,0xdf,0xff,0xdf,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f, + 0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, + 0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, + 0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, + 0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, +}; - SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, -50, 10, -30, 34); +/* + * DXGI_FORMAT_BC{4,5}_SNORM compression/decompression is bugged in + * native D3DX10/D3DX11. When decompressing, it seems to read the decompressed + * 8-bit channel values as signed normalized integers, but then clamps them to the + * unsigned normalized integer range. That means 0x00-0x7f present unique values, + * but anything from 0x80-0xff just gives the equivalent of 0x00. When this gets + * converted to an SNORM format such as DXGI_FORMAT_R8_SNORM, it gets mapped + * to the SNORM range, where 0x00 is -1.0f, and 0x7f is 1.0f. So effectively, + * it ends up with half of the range. + */ +static const uint8_t bc4_snorm_8_8[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00, + 0x7f,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x5f,0x00,0x00,0x00,0x00,0x00,0x00, +}; - SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 30, 10, 50, 34); +static const uint8_t r8_snorm_8_8_decompressed[] = +{ + 0x81,0x81,0x81,0x81,0xc1,0xc1,0xc1,0xc1,0x81,0x81,0x81,0x81,0xc1,0xc1,0xc1,0xc1, + 0x81,0x81,0x81,0x81,0xc1,0xc1,0xc1,0xc1,0x81,0x81,0x81,0x81,0xc1,0xc1,0xc1,0xc1, + 0x7F,0x7F,0x7F,0x7F,0x3F,0x3F,0x3F,0x3F,0x7F,0x7F,0x7F,0x7F,0x3F,0x3F,0x3F,0x3F, + 0x7F,0x7F,0x7F,0x7F,0x3F,0x3F,0x3F,0x3F,0x7F,0x7F,0x7F,0x7F,0x3F,0x3F,0x3F,0x3F, +}; - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 30, 10, 50, 34); +static const uint8_t bc5_snorm_8_8[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x1f,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x2f,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3e,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x4e,0x4e,0x00,0x00,0x00,0x00,0x00,0x00, + 0x5d,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0x6d,0x00,0x00,0x00,0x00,0x00,0x00, +}; - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 10, 10, 30, 34); +static const uint8_t r8g8_snorm_8_8_decompressed[] = +{ + 0x81,0xa1,0x81,0xa1,0x81,0xa1,0x81,0xa1,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf, + 0x81,0xa1,0x81,0xa1,0x81,0xa1,0x81,0xa1,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf, + 0x81,0xa1,0x81,0xa1,0x81,0xa1,0x81,0xa1,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf, + 0x81,0xa1,0x81,0xa1,0x81,0xa1,0x81,0xa1,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf, + 0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b, + 0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b, + 0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b, + 0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b, +}; - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 30, -10, 50, 14); +static const uint8_t rgba_unorm_4_4[] = +{ + 0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0xff, + 0x14,0x24,0x34,0x44,0x54,0x64,0x74,0x84,0x94,0xa4,0xb4,0xc4,0xd4,0xe4,0xf4,0xff, + 0x18,0x28,0x38,0x48,0x58,0x68,0x78,0x88,0x98,0xa8,0xb8,0xc8,0xd8,0xe8,0xf8,0xff, + 0x1c,0x2c,0x3c,0x4c,0x5c,0x6c,0x7c,0x8c,0x9c,0xac,0xbc,0xcc,0xdc,0xec,0xfc,0xff, +}; - SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 12, "Unexpected height %d.\n", height); - check_rect(&rect, -73, 10, -30, 22); +static const uint8_t rgba_snorm_4_4[] = +{ + 0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1,0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x7f, + 0x95,0xa5,0xb5,0xc5,0xd5,0xe5,0xf5,0x04,0x14,0x24,0x34,0x44,0x54,0x64,0x74,0x7f, + 0x99,0xa9,0xb9,0xc9,0xd9,0xe9,0xf9,0x08,0x18,0x28,0x38,0x48,0x58,0x68,0x78,0x7f, + 0x9d,0xad,0xbd,0xcd,0xdd,0xed,0xfd,0x0c,0x1c,0x2c,0x3c,0x4c,0x5c,0x6c,0x7c,0x7f, +}; - SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 30, 10, 50, 34); +/* Conversion to/from uint/sint. */ +static const uint8_t rgba_uint_4_4[] = +{ + 0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c,0x20,0x24,0x28,0x2c,0x30,0x34,0x38,0x3c, + 0x40,0x44,0x48,0x4c,0x50,0x54,0x58,0x5c,0x60,0x64,0x68,0x6c,0x70,0x74,0x78,0x7c, + 0x80,0x84,0x88,0x8c,0x90,0x94,0x98,0x9c,0xa0,0xa4,0xa8,0xac,0xb0,0xb4,0xb8,0xbc, + 0xc0,0xc4,0xc8,0xcc,0xd0,0xd4,0xd8,0xdc,0xe0,0xe4,0xe8,0xec,0xf0,0xf4,0xf8,0xfc, +}; - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 20, 10, 40, 34); +static const uint8_t rgba_uint_to_sint_4_4[] = +{ + 0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c,0x20,0x24,0x28,0x2c,0x30,0x34,0x38,0x3c, + 0x40,0x44,0x48,0x4c,0x50,0x54,0x58,0x5c,0x60,0x64,0x68,0x6c,0x70,0x74,0x78,0x7c, + 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, + 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, +}; - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 0, 10, 20, 34); +static const uint8_t rgba_sint_4_4[] = +{ + 0x80,0x84,0x88,0x8c,0x90,0x94,0x98,0x9c,0xa0,0xa4,0xa8,0xac,0xb0,0xb4,0xb8,0xbc, + 0xc0,0xc4,0xc8,0xcc,0xd0,0xd4,0xd8,0xdc,0xe0,0xe4,0xe8,0xec,0xf0,0xf4,0xf8,0xfc, + 0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c,0x20,0x24,0x28,0x2c,0x30,0x34,0x38,0x3c, + 0x40,0x44,0x48,0x4c,0x50,0x54,0x58,0x5c,0x60,0x64,0x68,0x6c,0x70,0x74,0x78,0x7c, +}; - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 20, -10, 40, 14); +static const uint8_t rgba_sint_to_uint_4_4[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c,0x20,0x24,0x28,0x2c,0x30,0x34,0x38,0x3c, + 0x40,0x44,0x48,0x4c,0x50,0x54,0x58,0x5c,0x60,0x64,0x68,0x6c,0x70,0x74,0x78,0x7c, +}; - SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, -20, 10, 0, 34); +/* Conversion to/from SRGB. */ +static const uint8_t rgba_unorm_srgb_4_4[] = +{ + 0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0xff, + 0x14,0x24,0x34,0x44,0x54,0x64,0x74,0x84,0x94,0xa4,0xb4,0xc4,0xd4,0xe4,0xf4,0xff, + 0x18,0x28,0x38,0x48,0x58,0x68,0x78,0x88,0x98,0xa8,0xb8,0xc8,0xd8,0xe8,0xf8,0xff, + 0x1c,0x2c,0x3c,0x4c,0x5c,0x6c,0x7c,0x8c,0x9c,0xac,0xbc,0xcc,0xdc,0xec,0xfc,0xff, +}; - SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 20, 10, 40, 34); +static const uint8_t rgba_unorm_srgb_to_unorm_non_srgb_4_4[] = +{ + 0x01,0x03,0x06,0x40,0x14,0x1e,0x2a,0x80,0x49,0x5b,0x71,0xc0,0xa3,0xc0,0xdf,0xff, + 0x01,0x03,0x08,0x44,0x16,0x21,0x2d,0x84,0x4d,0x61,0x77,0xc4,0xaa,0xc7,0xe7,0xff, + 0x01,0x04,0x09,0x48,0x19,0x23,0x31,0x88,0x52,0x66,0x7c,0xc8,0xb1,0xcf,0xf0,0xff, + 0x02,0x05,0x0b,0x4c,0x1b,0x27,0x34,0x8c,0x57,0x6b,0x82,0xcc,0xb8,0xd7,0xf8,0xff, +}; - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 20, 10, 40, 34); +static const uint8_t rgba_unorm_non_srgb_4_4[] = +{ + 0x00,0x20,0x50,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0xff, + 0x00,0x24,0x54,0x44,0x54,0x64,0x74,0x84,0x94,0xa4,0xb4,0xc4,0xd4,0xe4,0xf4,0xff, + 0x00,0x28,0x58,0x48,0x58,0x68,0x78,0x88,0x98,0xa8,0xb8,0xc8,0xd8,0xe8,0xf8,0xff, + 0x00,0x2c,0x5c,0x4c,0x5c,0x6c,0x7c,0x8c,0x9c,0xac,0xbc,0xcc,0xdc,0xec,0xfc,0xff, +}; - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 0, 10, 20, 34); +static const uint8_t rgba_unorm_non_srgb_to_unorm_srgb_4_4[] = +{ + 0x00,0x63,0x97,0x40,0x97,0xa4,0xaf,0x80,0xc5,0xce,0xd7,0xc0,0xe8,0xf0,0xf8,0xff, + 0x00,0x69,0x9a,0x44,0x9a,0xa7,0xb2,0x84,0xc7,0xd1,0xda,0xc4,0xea,0xf2,0xfa,0xff, + 0x00,0x6e,0x9d,0x48,0x9d,0xaa,0xb5,0x88,0xca,0xd3,0xdc,0xc8,0xec,0xf4,0xfc,0xff, + 0x00,0x73,0xa0,0x4c,0xa0,0xad,0xb8,0x8c,0xcc,0xd5,0xde,0xcc,0xee,0xf6,0xfe,0xff, +}; - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 20, -10, 40, 14); +static const struct test_texture_format_conversion +{ + D3D10_TEXTURE2D_DESC src_desc; + const uint8_t *src_data; - SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 12, "Unexpected height %d.\n", height); - check_rect(&rect, -31, 10, 12, 22); + DXGI_FORMAT dst_format; + const uint8_t *expected_dst_data; - SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 24, "Unexpected height %d.\n", height); - check_rect(&rect, 20, 10, 40, 34); + uint8_t max_diff; + BOOL todo_hr; + BOOL todo_data; +} +test_texture_format_conversion[] = +{ + { + { 8, 8, 1, 1, DXGI_FORMAT_BC1_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + bc1_8_8, DXGI_FORMAT_R8G8B8A8_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC2_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + bc2_8_8, DXGI_FORMAT_R8G8B8A8_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC3_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + bc3_8_8, DXGI_FORMAT_R8G8B8A8_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC4_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + bc4_unorm_8_8, DXGI_FORMAT_R8_UNORM, r8_unorm_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC4_SNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + bc4_snorm_8_8, DXGI_FORMAT_R8_SNORM, r8_snorm_8_8_decompressed, .todo_data = TRUE + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC5_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + bc5_unorm_8_8, DXGI_FORMAT_R8G8_UNORM, r8g8_unorm_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC5_SNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + bc5_snorm_8_8, DXGI_FORMAT_R8G8_SNORM, r8g8_snorm_8_8_decompressed, .todo_data = TRUE + }, + { + { 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + /* + * Wine's UNORM->SNORM conversion doesn't always match Window's, + * worst case is a difference of +/- 1. + */ + rgba_unorm_4_4, DXGI_FORMAT_R8G8B8A8_SNORM, rgba_snorm_4_4, .max_diff = 1 + }, + { + { 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_UINT, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + rgba_uint_4_4, DXGI_FORMAT_R8G8B8A8_SINT, rgba_uint_to_sint_4_4, .todo_hr = TRUE + }, + { + { 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_SINT, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + rgba_sint_4_4, DXGI_FORMAT_R8G8B8A8_UINT, rgba_sint_to_uint_4_4, .todo_hr = TRUE + }, + { + { 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + rgba_unorm_srgb_4_4, DXGI_FORMAT_R8G8B8A8_UNORM, rgba_unorm_srgb_to_unorm_non_srgb_4_4, .max_diff = 3 + }, + { + { 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + rgba_unorm_non_srgb_4_4, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, rgba_unorm_non_srgb_to_unorm_srgb_4_4, .max_diff = 2 + }, +}; - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 20, 18, 40, 42); +static const struct test_texture_compression +{ + D3D10_TEXTURE2D_DESC src_desc; + DXGI_FORMAT compressed_format; + const BYTE *src_data; +} +test_texture_compression[] = +{ + { + { 8, 8, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + DXGI_FORMAT_BC1_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + DXGI_FORMAT_BC2_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + DXGI_FORMAT_BC3_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_R8_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + DXGI_FORMAT_BC4_UNORM, r8_unorm_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_R8G8_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 }, + DXGI_FORMAT_BC5_UNORM, r8g8_unorm_8_8_decompressed + }, +}; - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 20, 18, 40, 42); +#define check_texture_data_level(tex_pixels, tex_row_pitch, tex_slice_pitch, width, height, depth, format, exp_pixels, max_diff, wine_todo) \ + check_texture_data_level_(tex_pixels, tex_row_pitch, tex_slice_pitch, width, height, depth, format, exp_pixels, max_diff, wine_todo, __LINE__) +static void check_texture_data_level_(const uint8_t *tex_pixels, uint32_t tex_row_pitch, uint32_t tex_slice_pitch, uint32_t width, + uint32_t height, uint32_t depth, DXGI_FORMAT format, const uint8_t *exp_pixels, uint8_t max_diff, BOOL wine_todo, uint32_t line) +{ + uint32_t line_height, exp_row_pitch, exp_slice_pitch, i, j, k; + BOOL line_match = FALSE; - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 0, 18, 20, 42); + line_height = 1; + exp_row_pitch = (width * get_bpp_from_format(format) + 7) / 8; + exp_slice_pitch = exp_row_pitch * height; + if (is_block_compressed(format)) + { + exp_row_pitch *= 4; + line_height = 4; + } - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 20, -2, 40, 22); + for (i = 0; i < depth; ++i) + { + const uint8_t *exp_slice = exp_pixels + (i * (exp_slice_pitch)); + const uint8_t *pixel_slice = tex_pixels + (i * tex_slice_pitch); - SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, -20, 18, 0, 42); + for (j = 0; j < height; j += line_height) + { + if (dxgi_format_is_8bpp_rgba(format)) + { + for (k = 0; k < width; ++k) + { + const uint32_t exp_pixel = ((const uint32_t *)(exp_slice + j * exp_row_pitch))[k]; + const uint32_t tex_pixel = ((const uint32_t *)(pixel_slice + j * tex_row_pitch))[k]; + const BOOL pixel_match = compare_color(tex_pixel, exp_pixel, max_diff); + + todo_wine_if(wine_todo) ok_(__FILE__, line)(pixel_match, "Data mismatch for pixel (%ux%ux%u).\n", k, j, i); + line_match = pixel_match; + if (!pixel_match) + break; + } + } + else + { + line_match = !memcmp(exp_slice + exp_row_pitch * (j / line_height), + pixel_slice + tex_row_pitch * (j / line_height), exp_row_pitch); + todo_wine_if(wine_todo) ok_(__FILE__, line)(line_match, "Data mismatch for line %u, slice %u.\n", j, i); + } + if (!line_match) + break; + } + } +} - SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, color); - ok(height == -8, "Unexpected height %d.\n", height); - check_rect(&rect, 20, -22, 40, 2); +static void set_d3dx10_texture_load_info(D3DX10_TEXTURE_LOAD_INFO *load_info, D3D10_BOX *src_box, D3D10_BOX *dst_box, + uint32_t src_first_mip, uint32_t dst_first_mip, uint32_t num_mips, uint32_t src_first_element, + uint32_t dst_first_element, uint32_t num_elems, uint32_t filter, uint32_t mip_filter) +{ + load_info->pSrcBox = src_box; + load_info->pDstBox = dst_box; + load_info->SrcFirstMip = src_first_mip; + load_info->DstFirstMip = dst_first_mip; + load_info->NumMips = num_mips; + load_info->SrcFirstElement = src_first_element; + load_info->DstFirstElement = dst_first_element; + load_info->NumElements = num_elems; + load_info->Filter = filter; + load_info->MipFilter = mip_filter; +} - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 20, 18, 40, 42); +static void set_d3d10_2d_texture_desc(D3D10_TEXTURE2D_DESC *desc, uint32_t width, uint32_t height, uint32_t mip_levels, + uint32_t array_size, DXGI_FORMAT format, uint32_t sample_count, uint32_t sample_quality, uint32_t usage, + uint32_t bind_flags, uint32_t cpu_access_flags, uint32_t misc_flags) +{ + desc->Width = width; + desc->Height = height; + desc->MipLevels = mip_levels; + desc->ArraySize = array_size; + desc->Format = format; + desc->SampleDesc.Count = sample_count; + desc->SampleDesc.Quality = sample_quality; + desc->Usage = usage; + desc->BindFlags = bind_flags; + desc->CPUAccessFlags = cpu_access_flags; + desc->MiscFlags = misc_flags; +} - SetRect(&rect, 10, 10, 50, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 20, 18, 40, 42); +static void init_subresource_data(D3D10_SUBRESOURCE_DATA *subresources, const void *data, uint32_t width, uint32_t height, + uint32_t depth, uint32_t mip_levels, uint32_t array_size, DXGI_FORMAT format) +{ + const uint8_t *pixel_ptr = data; + uint32_t i, j; - SetRect(&rect, -10, 10, 30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 0, 18, 20, 42); + for (i = 0; i < array_size; ++i) + { + uint32_t tmp_width, tmp_height, tmp_depth; - SetRect(&rect, 10, -10, 50, 30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 32, "Unexpected height %d.\n", height); - check_rect(&rect, 20, -2, 40, 22); + tmp_width = width; + tmp_height = height; + tmp_depth = depth; + for (j = 0; j < mip_levels; ++j) + { + D3D10_SUBRESOURCE_DATA *subresource = &subresources[(i * mip_levels) + j]; + + subresource->pSysMem = pixel_ptr; + subresource->SysMemPitch = (tmp_width * get_bpp_from_format(format) + 7) / 8; + subresource->SysMemSlicePitch = subresource->SysMemPitch * tmp_height; + if (is_block_compressed(format)) + subresource->SysMemPitch *= 4; + pixel_ptr += (subresource->SysMemSlicePitch * tmp_depth); + + tmp_width = max(tmp_width / 2, 1); + tmp_height = max(tmp_height / 2, 1); + tmp_depth = max(tmp_depth / 2, 1); + } + } +} - SetRect(&rect, 10, 10, -30, 50); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == 26, "Unexpected height %d.\n", height); - check_rect(&rect, -31, 24, 12, 36); +static uint8_t *init_buffer_color(uint8_t *buf, uint32_t color, uint32_t width, uint32_t height, uint32_t depth) +{ + uint32_t i, total_pixels = width * height * depth; + uint32_t *color_buf = (uint32_t *)buf; - SetRect(&rect, 10, 10, 50, -30); - height = ID3DX10Font_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, color); - ok(height == -8, "Unexpected height %d.\n", height); - check_rect(&rect, 20, -22, 40, 2); + for (i = 0; i < total_pixels; ++i) + color_buf[i] = color; + return buf + (total_pixels * 4); +} - ID3DX10Font_Release(font); +static void set_texture_sub_resource_color(ID3D10Device *device, ID3D10Resource *rsrc, uint32_t idx, uint32_t color, + uint32_t width, uint32_t height, uint32_t depth) +{ + uint8_t tmp_buf[1024]; + + init_buffer_color(tmp_buf, color, width, height, depth); + ID3D10Device_UpdateSubresource(device, rsrc, idx, NULL, (const void *)tmp_buf, width * sizeof(color), + width * height * sizeof(color)); } -static void test_sprite(void) +static void test_D3DX10LoadTextureFromTexture(void) { - ID3D10ShaderResourceView *srv1, *srv2; - ID3D10Texture2D *texture1, *texture2; - D3D10_TEXTURE2D_DESC texture_desc; - ID3D10Device *device, *device2; - D3DX10_SPRITE sprite_desc; - ID3DX10Sprite *sprite; - D3DXMATRIX mat, mat2; - ULONG refcount; + static const uint32_t test_cubemap_face_colors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffffff00, 0xffff00ff, 0xff00ffff }; + static const uint32_t test_tex_2d_array_colors[] = { 0xff0000ff, 0xff00ff00, 0xffff0000, 0xff000000 }; + D3D10_SUBRESOURCE_DATA sub_resource_data[6] = { 0 }; + D3DX10_TEXTURE_LOAD_INFO load_info; + ID3D10Texture2D *tex_2d, *tex2_2d; + D3D10_TEXTURE2D_DESC tex_2d_desc; + uint8_t tmp_buf[1024], *tmp_ptr; + ID3D10Device *device; + RECT tmp_rect; + uint32_t i; HRESULT hr; - static const D3DXMATRIX identity = - { - ._11 = 1.0f, - ._22 = 1.0f, - ._33 = 1.0f, - ._44 = 1.0f, - }; - if (!(device = create_device())) + device = create_device(); + if (!device) { skip("Failed to create device, skipping tests.\n"); return; - } - - texture_desc.Width = 64; - texture_desc.Height = 64; - texture_desc.MipLevels = 1; - texture_desc.ArraySize = 1; - texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - texture_desc.SampleDesc.Count = 1; - texture_desc.SampleDesc.Quality = 0; - texture_desc.Usage = D3D10_USAGE_DEFAULT; - texture_desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; - texture_desc.CPUAccessFlags = 0; - texture_desc.MiscFlags = 0; + } - hr = ID3D10Device_CreateTexture2D(device, &texture_desc, NULL, &texture1); - ok(SUCCEEDED(hr), "Failed to create texture, hr %#lx.\n", hr); + CoInitialize(NULL); - hr = ID3D10Device_CreateTexture2D(device, &texture_desc, NULL, &texture2); - ok(SUCCEEDED(hr), "Failed to create texture, hr %#lx.\n", hr); + /* + * Tests that still need to be written: + * -pSrcBox/pDstBox, how they behave WRT mip levels, too large, too small. + * -3D texture test. + */ + + /* 8x8 2D texture array with 2 elements and 2 mip levels. */ + tmp_ptr = tmp_buf; + for (i = 0; i < ARRAY_SIZE(test_tex_2d_array_colors); ++i) + tmp_ptr = init_buffer_color(tmp_ptr, test_tex_2d_array_colors[i], !(i & 0x1) ? 8 : 4, !(i & 0x1) ? 8 : 4, 1); + + set_d3d10_2d_texture_desc(&tex_2d_desc, 8, 8, 2, 2, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); + hr = ID3D10Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < ARRAY_SIZE(test_tex_2d_array_colors); ++i) + check_texture_sub_resource_color(tex_2d, i, NULL, test_tex_2d_array_colors[i], 0); + + /* 8x8 2D texture with 4 mip levels. */ + memset(tmp_buf, 0xff, sizeof(tmp_buf)); + set_d3d10_2d_texture_desc(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); + hr = ID3D10Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 4; ++i) + check_texture_sub_resource_color(tex2_2d, i, NULL, 0xffffffff, 0); + + /* + * If a NULL load info argument is supplied, the default D3DX10_TEXTURE_LOAD_INFO + * values are used. The first 2 mip levels from tex_2d are loaded, and + * the last 2 mip levels of tex2_2d are generated from mip level 1. + */ + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, NULL, (ID3D10Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 4; ++i) + check_texture_sub_resource_color(tex2_2d, i, NULL, test_tex_2d_array_colors[min(i, 1)], 0); - hr = ID3D10Device_CreateShaderResourceView(device, (ID3D10Resource *)texture1, NULL, &srv1); - ok(SUCCEEDED(hr), "Failed to create srv, hr %#lx.\n", hr); + /* Invalid Filter argument. */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, 0, 0, 0, 9, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - hr = ID3D10Device_CreateShaderResourceView(device, (ID3D10Resource *)texture1, NULL, &srv2); - ok(SUCCEEDED(hr), "Failed to create srv, hr %#lx.\n", hr); + /* Filter argument of 0 is invalid. */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - hr = D3DX10CreateSprite(device, 0, NULL); + /* Invalid MipFilter argument. */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, 0, 0, 0, D3DX10_DEFAULT, 9); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - hr = D3DX10CreateSprite(NULL, 0, &sprite); + /* MipFilter argument is only validated if mip levels are generated. */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 2, 0, 0, 0, D3DX10_DEFAULT, 9); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* + * Cannot use the same source/destination texture with matching first mip + * level and array element. + */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, 0, 0, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex_2d); ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - hr = D3DX10CreateSprite(device, 0, &sprite); + /* Same first mip level, different first element. */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, 0, 1, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 2; ++i) + check_texture_sub_resource_color(tex_2d, 2 + i, NULL, test_tex_2d_array_colors[i], 0); - /* GetDevice */ - hr = ID3DX10Sprite_GetDevice(sprite, NULL); - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + /* Restore values. */ + for (i = 0; i < ARRAY_SIZE(test_tex_2d_array_colors); ++i) + { + set_texture_sub_resource_color(device, (ID3D10Resource *)tex_2d, i, test_tex_2d_array_colors[i], !(i & 0x1) ? 8 : 4, + !(i & 0x1) ? 8 : 4, 1); + check_texture_sub_resource_color(tex_2d, i, NULL, test_tex_2d_array_colors[i], 0); + } - hr = ID3DX10Sprite_GetDevice(sprite, &device2); + /* Same first array element, but different FirstMips. */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 1, 0, 0, 0, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(device == device2, "Unexpected device.\n"); + for (i = 0; i < 4; ++i) + check_texture_sub_resource_color(tex_2d, i, NULL, test_tex_2d_array_colors[(i < 2) ? 0 : 2], 0); - ID3D10Device_Release(device2); + for (i = 0; i < ARRAY_SIZE(test_tex_2d_array_colors); ++i) + { + set_texture_sub_resource_color(device, (ID3D10Resource *)tex_2d, i, test_tex_2d_array_colors[i], !(i & 0x1) ? 8 : 4, + !(i & 0x1) ? 8 : 4, 1); + check_texture_sub_resource_color(tex_2d, i, NULL, test_tex_2d_array_colors[i], 0); + } - /* Projection transform */ - hr = ID3DX10Sprite_GetProjectionTransform(sprite, NULL); - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Sprite_GetProjectionTransform(sprite, &mat); + /* + * If SrcFirstElement/DstFirstElement are greater than the total number of + * elements, element 0 is used. + */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 2, 2, 0, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!memcmp(&mat, &identity, sizeof(mat)), "Unexpected projection transform.\n"); + for (i = 0; i < 2; ++i) + check_texture_sub_resource_color(tex2_2d, i, NULL, test_tex_2d_array_colors[i], 0); - /* Set a transform and test if it gets returned correctly */ - mat.m[0][0] = 2.1f; mat.m[0][1] = 6.5f; mat.m[0][2] =-9.6f; mat.m[0][3] = 1.7f; - mat.m[1][0] = 4.2f; mat.m[1][1] =-2.5f; mat.m[1][2] = 2.1f; mat.m[1][3] = 5.5f; - mat.m[2][0] =-2.6f; mat.m[2][1] = 0.3f; mat.m[2][2] = 8.6f; mat.m[2][3] = 8.4f; - mat.m[3][0] = 6.7f; mat.m[3][1] =-5.1f; mat.m[3][2] = 6.1f; mat.m[3][3] = 2.2f; + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 2, 1, 0, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 2; ++i) + check_texture_sub_resource_color(tex2_2d, i, NULL, test_tex_2d_array_colors[2 + i], 0); - hr = ID3DX10Sprite_SetProjectionTransform(sprite, NULL); - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 4; ++i) + { + set_texture_sub_resource_color(device, (ID3D10Resource *)tex2_2d, i, 0xff000000 | (0xff << (8 * i)), 8 >> i, 8 >> i, 1); + check_texture_sub_resource_color(tex2_2d, i, NULL, 0xff000000 | (0xff << (8 * i)), 0); + } - hr = ID3DX10Sprite_SetProjectionTransform(sprite, &mat); + /* DstFirstElement value tests. */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 2, 0, 2, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex2_2d, &load_info, (ID3D10Resource *)tex_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 2; ++i) + check_texture_sub_resource_color(tex_2d, i, NULL, 0xff000000 | (0xff << (8 * i)), 0); + for (i = 0; i < 2; ++i) + check_texture_sub_resource_color(tex_2d, 2 + i, NULL, test_tex_2d_array_colors[2 + i], 0); - hr = ID3DX10Sprite_GetProjectionTransform(sprite, &mat2); + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 2, 0, 1, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex2_2d, &load_info, (ID3D10Resource *)tex_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!memcmp(&mat, &mat2, sizeof(mat)), "Unexpected matrix.\n"); + for (i = 0; i < 4; ++i) + check_texture_sub_resource_color(tex_2d, i, NULL, !(i & 0x01) ? 0xff0000ff : 0xff00ff00, 0); - /* View transform */ - hr = ID3DX10Sprite_SetViewTransform(sprite, NULL); - todo_wine - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 4; ++i) + { + set_texture_sub_resource_color(device, (ID3D10Resource *)tex_2d, i, test_tex_2d_array_colors[i], !(i & 0x1) ? 8 : 4, + !(i & 0x1) ? 8 : 4, 1); + check_texture_sub_resource_color(tex_2d, i, NULL, test_tex_2d_array_colors[i], 0); - hr = ID3DX10Sprite_SetViewTransform(sprite, &mat); - todo_wine + set_texture_sub_resource_color(device, (ID3D10Resource *)tex2_2d, i, 0xff000000 | (0xff << (8 * i)), 8 >> i, 8 >> i, 1); + check_texture_sub_resource_color(tex2_2d, i, NULL, 0xff000000 | (0xff << (8 * i)), 0); + } + + /* + * If SrcFirstMip is greater than the total number of mip levels, the + * final mip level is used, E.g, if SrcFirstMip is set to 3, but the + * texture only has 2 mip levels, mip level 2 is used. + */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 2, 0, 1, 0, 0, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex2_2d, 0, NULL, test_tex_2d_array_colors[1], 0); - /* Begin */ - hr = ID3DX10Sprite_Begin(sprite, 0); - todo_wine + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 1, 0, 0, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex2_2d, 0, NULL, test_tex_2d_array_colors[0], 0); - /* Flush/End */ - hr = ID3DX10Sprite_Flush(sprite); - todo_wine + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 1, 0, 1, 0, 0, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex2_2d, 0, NULL, test_tex_2d_array_colors[1], 0); + + /* + * If DstFirstMip is greater than the total number of mips, nothing is + * loaded. + */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 5, 1, 0, 0, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex2_2d, 0, NULL, test_tex_2d_array_colors[1], 0); + check_texture_sub_resource_color(tex2_2d, 3, NULL, 0xff000000, 0); - hr = ID3DX10Sprite_End(sprite); - todo_wine + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 3, 1, 0, 0, 0, D3DX10_DEFAULT, D3DX10_DEFAULT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex2_2d, 3, NULL, test_tex_2d_array_colors[0], 0); - /* May not be called before next Begin */ - hr = ID3DX10Sprite_Flush(sprite); - todo_wine - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); - hr = ID3DX10Sprite_End(sprite); - todo_wine - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + ID3D10Texture2D_Release(tex2_2d); + ID3D10Texture2D_Release(tex_2d); - /* Draw */ - hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, NULL, 0); - todo_wine - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < ARRAY_SIZE(test_texture_format_conversion); ++i) + { + const struct test_texture_format_conversion *test = &test_texture_format_conversion[i]; + const D3D10_TEXTURE2D_DESC *src_desc = &test->src_desc; + D3D10_TEXTURE2D_DESC tmp_desc = test->src_desc; + ID3D10Texture2D *src_texture, *dst_texture; + D3D10_MAPPED_TEXTURE2D map = { 0 }; + + winetest_push_context("Texture format conversion test %u", i); + src_texture = dst_texture = NULL; + + init_subresource_data(sub_resource_data, test->src_data, src_desc->Width, src_desc->Height, 1, + src_desc->MipLevels, src_desc->ArraySize, src_desc->Format); + hr = ID3D10Device_CreateTexture2D(device, src_desc, sub_resource_data, &src_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_texture; - memset(&sprite_desc, 0, sizeof(sprite_desc)); - hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, &sprite_desc, 0); - todo_wine - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + tmp_desc.Format = test->dst_format; + tmp_desc.Usage = D3D10_USAGE_STAGING; + tmp_desc.BindFlags = 0; + tmp_desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; + hr = ID3D10Device_CreateTexture2D(device, &tmp_desc, NULL, &dst_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_texture; - hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, &sprite_desc, 1); - todo_wine - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)src_texture, NULL, (ID3D10Resource *)dst_texture); + todo_wine_if(test->todo_hr) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_texture; - hr = ID3DX10Sprite_Begin(sprite, 0); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ID3D10Texture2D_Map(dst_texture, 0, D3D10_MAP_READ, 0, &map); + ok(hr == S_OK, "Failed to map destination texture, hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_texture; + + check_texture_data_level(map.pData, map.RowPitch, 0, tmp_desc.Width, tmp_desc.Height, 1, test->dst_format, + test->expected_dst_data, test->max_diff, test->todo_data); +cleanup_next_texture: + if (src_texture) + ID3D10Texture2D_Release(src_texture); + if (map.pData) + ID3D10Texture2D_Unmap(dst_texture, 0); + if (dst_texture) + ID3D10Texture2D_Release(dst_texture); + winetest_pop_context(); + } - memset(&sprite_desc, 0, sizeof(sprite_desc)); - hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, &sprite_desc, 1); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* + * Texture compression tests. Rather than checking against compressed values + * (which we're unlikely to match due to differences in compression + * algorithms), we'll: + * Load our uncompressed source texture into a compressed destination texture. + * Load our compressed destination texture into a new decompressed destination texture. + * Check that the data in the new decompressed texture matches the + * original data. + */ + for (i = 0; i < ARRAY_SIZE(test_texture_compression); ++i) + { + const struct test_texture_compression *test = &test_texture_compression[i]; + const D3D10_TEXTURE2D_DESC *src_desc = &test->src_desc; + ID3D10Texture2D *src_texture, *dst_texture; + D3D10_TEXTURE2D_DESC tmp_desc = *src_desc; + D3D10_MAPPED_TEXTURE2D map = { 0 }; + + winetest_push_context("Texture compression test %u", i); + src_texture = dst_texture = NULL; + + /* Create the uncompressed source texture. */ + init_subresource_data(sub_resource_data, (const void *)test->src_data, src_desc->Width, src_desc->Height, 1, + src_desc->MipLevels, src_desc->ArraySize, src_desc->Format); + hr = ID3D10Device_CreateTexture2D(device, src_desc, sub_resource_data, &src_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; - sprite_desc.pTexture = srv1; - hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, &sprite_desc, 1); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* Create the compressed destination texture. */ + tmp_desc.Format = test->compressed_format; + hr = ID3D10Device_CreateTexture2D(device, &tmp_desc, NULL, &dst_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; - hr = ID3DX10Sprite_Flush(sprite); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* Load the uncompressed source into the compressed destination. */ + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)src_texture, NULL, (ID3D10Resource *)dst_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; + + ID3D10Texture2D_Release(src_texture); + src_texture = dst_texture; + + /* Now create the uncompressed destination texture to decompress into. */ + tmp_desc = *src_desc; + tmp_desc.Usage = D3D10_USAGE_STAGING; + tmp_desc.BindFlags = 0; + tmp_desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; + memset(tmp_buf, 0, sizeof(tmp_buf)); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, src_desc->Width, src_desc->Height, 1, + src_desc->MipLevels, src_desc->ArraySize, src_desc->Format); + hr = ID3D10Device_CreateTexture2D(device, &tmp_desc, sub_resource_data, &dst_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; - hr = ID3DX10Sprite_Flush(sprite); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)src_texture, NULL, (ID3D10Resource *)dst_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; - hr = ID3DX10Sprite_End(sprite); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ID3D10Texture2D_Map(dst_texture, 0, D3D10_MAP_READ, 0, &map); + ok(hr == S_OK, "Failed to map destination texture, hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; + + check_texture_data_level(map.pData, map.RowPitch, 0, tmp_desc.Width, tmp_desc.Height, 1, tmp_desc.Format, + test->src_data, 0, FALSE); +cleanup_next_compressed_texture: + if (src_texture) + ID3D10Texture2D_Release(src_texture); + if (map.pData) + ID3D10Texture2D_Unmap(dst_texture, 0); + if (dst_texture) + ID3D10Texture2D_Release(dst_texture); + winetest_pop_context(); + } - /* D3DX10_SPRITE_ADDREF_TEXTURES */ - hr = ID3DX10Sprite_Begin(sprite, D3DX10_SPRITE_ADDREF_TEXTURES); - todo_wine - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* + * Use D3DX10LoadTextureFromTexture to generate mip levels. Some games + * (Total War: Shogun 2) do this instead of using D3DX10FilterTexture. + */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 1, 2, 0, 0, 1, D3DX10_FILTER_POINT, D3DX10_FILTER_NONE); + set_d3d10_2d_texture_desc(&tex_2d_desc, 8, 8, 3, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0); - memset(&sprite_desc, 0, sizeof(sprite_desc)); - sprite_desc.pTexture = srv1; + memset(tmp_buf, 0, sizeof(tmp_buf)); + memcpy(tmp_buf, bc1_to_bc3_8_8_decompressed, sizeof(bc1_to_bc3_8_8_decompressed)); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); - refcount = get_refcount(srv1); - hr = ID3DX10Sprite_DrawSpritesBuffered(sprite, &sprite_desc, 1); -todo_wine { + hr = ID3D10Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(get_refcount(srv1) > refcount, "Unexpected refcount.\n"); -} + check_texture_sub_resource_color(tex_2d, 1, NULL, 0x00000000, 0); + check_texture_sub_resource_color(tex_2d, 2, NULL, 0x00000000, 0); - hr = ID3DX10Sprite_Flush(sprite); - todo_wine + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(get_refcount(srv1) == refcount, "Unexpected refcount.\n"); - hr = ID3DX10Sprite_End(sprite); - todo_wine + SetRect(&tmp_rect, 0, 0, 2, 2); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xffff0000, 0); + SetRect(&tmp_rect, 2, 0, 4, 2); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff00ff00, 0); + SetRect(&tmp_rect, 0, 2, 2, 4); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff0000ff, 0); + SetRect(&tmp_rect, 2, 2, 4, 4); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff000000, 0); + + SetRect(&tmp_rect, 0, 0, 1, 1); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xffff0000, 0); + SetRect(&tmp_rect, 1, 0, 2, 1); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff00ff00, 0); + SetRect(&tmp_rect, 0, 1, 1, 2); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff0000ff, 0); + SetRect(&tmp_rect, 1, 1, 2, 2); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff000000, 0); + + ID3D10Texture2D_Release(tex_2d); + + /* Cubemap. */ + set_d3d10_2d_texture_desc(&tex_2d_desc, 4, 4, 1, 6, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, D3D10_RESOURCE_MISC_TEXTURECUBE); + init_subresource_data(sub_resource_data, (const void *)rgba_4_4_cubemap, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); + + hr = ID3D10Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex_2d); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 6; ++i) + check_texture_sub_resource_color(tex_2d, i, NULL, test_cubemap_face_colors[i], 0); - ID3DX10Sprite_Release(sprite); - ID3D10Texture2D_Release(texture1); - ID3D10Texture2D_Release(texture2); - ID3D10ShaderResourceView_Release(srv1); - ID3D10ShaderResourceView_Release(srv2); + /* Load individual faces of a cubemap texture into a non-cubemap texture. */ + set_d3d10_2d_texture_desc(&tex_2d_desc, 4, 4, 3, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0); + hr = ID3D10Device_CreateTexture2D(device, &tex_2d_desc, NULL, &tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - refcount = ID3D10Device_Release(device); - ok(!refcount, "Unexpected refcount.\n"); + for (i = 0; i < 6; ++i) + { + /* On top of loading individual faces, we'll also generate mips. */ + set_d3dx10_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, i, 0, 1, D3DX10_FILTER_POINT, D3DX10_FILTER_POINT); + hr = D3DX10LoadTextureFromTexture((ID3D10Resource *)tex_2d, &load_info, (ID3D10Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + check_texture_sub_resource_color(tex2_2d, 0, NULL, test_cubemap_face_colors[i], 0); + check_texture_sub_resource_color(tex2_2d, 1, NULL, test_cubemap_face_colors[i], 0); + check_texture_sub_resource_color(tex2_2d, 2, NULL, test_cubemap_face_colors[i], 0); + } + + ID3D10Texture2D_Release(tex2_2d); + ID3D10Texture2D_Release(tex_2d); + + CoUninitialize(); + + ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); } -static void test_create_effect_from_memory(void) +static void test_D3DX10FilterTexture(void) { + D3D10_SUBRESOURCE_DATA sub_resource_data[4] = { 0 }; + D3D10_TEXTURE2D_DESC tex_2d_desc; + ID3D10Texture2D *tex_2d; + uint8_t tmp_buf[1024]; ID3D10Device *device; - ID3D10Effect *effect; - ID3D10Blob *errors; - ULONG refcount; + RECT tmp_rect; HRESULT hr; - if (!(device = create_device())) + device = create_device(); + if (!device) { skip("Failed to create device, skipping tests.\n"); return; } - /* Test NULL data. */ - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromMemory(NULL, 0, NULL, NULL, NULL, NULL, - 0x0, 0x0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); - ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + CoInitialize(NULL); - /* Test NULL device. */ - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromMemory(test_fx, sizeof(test_fx), NULL, NULL, NULL, NULL, - 0x0, 0x0, NULL, NULL, NULL, &effect, &errors, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); - ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + set_d3d10_2d_texture_desc(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0); + memset(tmp_buf, 0, sizeof(tmp_buf)); + memcpy(tmp_buf, bc1_to_bc3_8_8_decompressed, sizeof(bc1_to_bc3_8_8_decompressed)); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); - /* Test creating effect from compiled shader. */ - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromMemory(test_fx, sizeof(test_fx), NULL, NULL, NULL, NULL, - 0x0, 0x0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(!errors, "Got unexpected errors %p.\n", errors); - ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - effect->lpVtbl->Release(effect); + hr = ID3D10Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex_2d, 1, NULL, 0x00000000, 0); + check_texture_sub_resource_color(tex_2d, 2, NULL, 0x00000000, 0); + check_texture_sub_resource_color(tex_2d, 3, NULL, 0x00000000, 0); - /* Test creating effect from source without setting profile. */ - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromMemory(test_fx_source, strlen(test_fx_source) + 1, NULL, NULL, NULL, NULL, - 0x0, 0x0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(!!errors && errors != (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - if (errors && errors != (ID3D10Blob *)0xdeadbeef) - ID3D10Blob_Release(errors); + /* Invalid filter arguments. */ + hr = D3DX10FilterTexture((ID3D10Resource *)tex_2d, 0, 0); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - /* Test creating effect from source. */ - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromMemory(test_fx_source, strlen(test_fx_source) + 1, NULL, NULL, NULL, "fx_4_0", - 0x0, 0x0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(!errors, "Got unexpected errors %p.\n", errors); - ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - effect->lpVtbl->Release(effect); + hr = D3DX10FilterTexture((ID3D10Resource *)tex_2d, 0, 9); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); - refcount = ID3D10Device_Release(device); - ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + /* + * Filter argument isn't validated if src_level argument is greater than + * total mip levels. + */ + hr = D3DX10FilterTexture((ID3D10Resource *)tex_2d, 5, 9); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DX10FilterTexture((ID3D10Resource *)tex_2d, 0, D3DX10_FILTER_POINT); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + SetRect(&tmp_rect, 0, 0, 2, 2); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xffff0000, 0); + SetRect(&tmp_rect, 2, 0, 4, 2); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff00ff00, 0); + SetRect(&tmp_rect, 0, 2, 2, 4); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff0000ff, 0); + SetRect(&tmp_rect, 2, 2, 4, 4); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff000000, 0); + + SetRect(&tmp_rect, 0, 0, 1, 1); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xffff0000, 0); + SetRect(&tmp_rect, 1, 0, 2, 1); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff00ff00, 0); + SetRect(&tmp_rect, 0, 1, 1, 2); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff0000ff, 0); + SetRect(&tmp_rect, 1, 1, 2, 2); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff000000, 0); + + check_texture_sub_resource_color(tex_2d, 3, NULL, 0xffff0000, 0); + + ID3D10Texture2D_Release(tex_2d); + + CoUninitialize(); + + ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); } -static void test_create_effect_from_file(void) +static HRESULT d3d10_create_texture_1d(ID3D10Device *device, uint32_t width, uint32_t mip_levels, uint32_t array_size, + DXGI_FORMAT format, D3D10_USAGE usage, uint32_t bind_flags, uint32_t cpu_access_flags, uint32_t misc_flags, + ID3D10Texture1D **tex) { - static const WCHAR *test_file_name = L"test.fx"; - WCHAR path[MAX_PATH]; - ID3D10Device *device; - ID3D10Effect *effect; - ID3D10Blob *errors; - ULONG refcount; + const D3D10_TEXTURE1D_DESC desc = { width, mip_levels, array_size, format, usage, bind_flags, cpu_access_flags, + misc_flags }; + + return ID3D10Device_CreateTexture1D(device, &desc, NULL, tex); +} + +static HRESULT d3d10_create_texture_2d(ID3D10Device *device, uint32_t width, uint32_t height, uint32_t mip_levels, + uint32_t array_size, DXGI_FORMAT format, uint32_t sample_count, uint32_t sample_quality, D3D10_USAGE usage, + uint32_t bind_flags, uint32_t cpu_access_flags, uint32_t misc_flags, ID3D10Texture2D **tex) +{ + const D3D10_TEXTURE2D_DESC desc = { width, height, mip_levels, array_size, format, { sample_count, sample_quality }, + usage, bind_flags, cpu_access_flags, misc_flags }; + + return ID3D10Device_CreateTexture2D(device, &desc, NULL, tex); +} + +static HRESULT d3d10_create_texture_3d(ID3D10Device *device, uint32_t width, uint32_t height, uint32_t depth, + uint32_t mip_levels, DXGI_FORMAT format, D3D10_USAGE usage, uint32_t bind_flags, uint32_t cpu_access_flags, + uint32_t misc_flags, ID3D10Texture3D **tex) +{ + const D3D10_TEXTURE3D_DESC desc = { width, height, depth, mip_levels, format, usage, bind_flags, cpu_access_flags, + misc_flags }; + + return ID3D10Device_CreateTexture3D(device, &desc, NULL, tex); +} + +enum texture_type +{ + TEXTURE_2D, + TEXTURE_2D_ARRAY, + TEXTURE_3D, + TEXTURE_CUBE, + TEXTURE_1D, + TEXTURE_1D_ARRAY, + TEXTURE_TYPE_COUNT, +}; + +static void test_save_texture_to_dds(ID3D10Device *device) +{ + struct dds_expected + { + struct dds_header header; + struct dds_header_dxt10 dxt10; + BOOL todo; + }; + static const struct + { + DXGI_FORMAT format; + struct dds_expected dds_expected[TEXTURE_TYPE_COUNT]; + } save_tests[] = + { + { DXGI_FORMAT_R8G8B8A8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0xff, 0xff00, 0xff0000, 0xff000000 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0xff, 0xff00, 0xff0000, 0xff000000 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0xff, 0xff00, 0xff0000, 0xff000000 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R10G10B10A2_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0xffc00, 0x3ff, 0xc0000000 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R10G10B10A2_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0xffc00, 0x3ff, 0xc0000000 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0xffc00, 0x3ff, 0xc0000000 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R10G10B10A2_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R10G10B10A2_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16G16B16A16_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x24, 64, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 64, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x24, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x24, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16G16_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB, 0, 32, 0xffff, 0xffff0000, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_RGB, 0, 32, 0xffff, 0xffff0000, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB, 0, 32, 0xffff, 0xffff0000, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_A8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 8, 8, 4, { 0 }, + { 32, DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + /* 5. */ + { DXGI_FORMAT_R16_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6f, 16, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6f, 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6f, 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16G16_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x70, 32, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x70, 32, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x70, 32, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x71, 64, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 64, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x71, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x71, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R32_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x72, 32, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x72, 32, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x72, 32, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R32G32_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x73, 64, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 64, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x73, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x73, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + /* 10. */ + { DXGI_FORMAT_R32G32B32A32_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 128, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x74, 128, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 128, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32A32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 128, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x74, 128, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 128, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x74, 128, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 128, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32A32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 128, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32A32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_G8R8_G8B8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B'), 16, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_G8R8_G8B8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B'), 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B'), 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_G8R8_G8B8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_G8R8_G8B8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R8G8_B8G8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G'), 16, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_B8G8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G'), 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G'), 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_B8G8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_B8G8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_BC1_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1'), 4, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC1_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1'), 4, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1'), 4, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + { DXGI_FORMAT_BC2_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3'), 4, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC2_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3'), 4, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3'), 4, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + /* 15. */ + { DXGI_FORMAT_BC3_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5'), 8, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC3_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + { DXGI_FORMAT_BC4_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','U'), 8, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC4_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','U'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','U'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + { DXGI_FORMAT_BC4_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC4_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + { DXGI_FORMAT_BC5_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('A','T','I','2'), 8, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC5_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('A','T','I','2'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('A','T','I','2'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + { DXGI_FORMAT_BC5_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','5','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC5_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','5','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','5','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + /* 20. */ + { DXGI_FORMAT_R16G16B16A16_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6e, 64, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 64, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6e, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6e, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 8, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R8_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 8, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + /* 25. */ + { DXGI_FORMAT_R8G8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8G8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8G8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R32G32B32_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 96, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 96, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 96, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 96, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 96, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 96, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_BC1_UNORM_SRGB, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC1_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC1_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_BC1_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_BC1_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + } + }, + { DXGI_FORMAT_BC2_UNORM_SRGB, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC2_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC2_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_BC2_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_BC2_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + } + }, + /* 30. */ + { DXGI_FORMAT_BC3_UNORM_SRGB, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC3_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC3_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_BC3_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_BC3_UNORM_SRGB, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + } + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R8G8_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8G8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8G8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16G16_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R16G16_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R16G16_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_SNORM, D3D10_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + }; + D3DX10_IMAGE_INFO img_info; + ID3D10Resource *tex; + ID3D10Blob *buffer; + unsigned int i, j; HRESULT hr; + struct + { + DWORD magic; + struct dds_header header; + struct dds_header_dxt10 dxt10; + } *dds; - if (!(device = create_device())) + for (i = 0; i < ARRAY_SIZE(save_tests); ++i) { - skip("Failed to create device, skipping tests.\n"); - return; + if (!strcmp(winetest_platform, "wine") && (save_tests[i].format == DXGI_FORMAT_G8R8_G8B8_UNORM + || save_tests[i].format == DXGI_FORMAT_R8G8_B8G8_UNORM)) + { + skip("Skipping unsupported texture format on Wine.\n"); + continue; + } + + winetest_push_context("Test %u", i); + for (j = 0; j < TEXTURE_TYPE_COUNT; ++j) + { + const struct dds_expected *dds_expected = &save_tests[i].dds_expected[j]; + + /* Cannot create a block compressed 1D texture. */ + if (is_block_compressed(save_tests[i].format) && (j >= TEXTURE_1D)) + continue; + + switch (j) + { + case TEXTURE_1D: + hr = d3d10_create_texture_1d(device, 8, 4, 1, save_tests[i].format, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0, (ID3D10Texture1D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case TEXTURE_1D_ARRAY: + hr = d3d10_create_texture_1d(device, 8, 4, 2, save_tests[i].format, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0, (ID3D10Texture1D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case TEXTURE_2D: + hr = d3d10_create_texture_2d(device, 8, 8, 4, 1, save_tests[i].format, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0, (ID3D10Texture2D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case TEXTURE_2D_ARRAY: + hr = d3d10_create_texture_2d(device, 8, 8, 4, 2, save_tests[i].format, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0, (ID3D10Texture2D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case TEXTURE_3D: + hr = d3d10_create_texture_3d(device, 8, 8, 8, 4, save_tests[i].format, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0, (ID3D10Texture3D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case TEXTURE_CUBE: + hr = d3d10_create_texture_2d(device, 8, 8, 4, 6, save_tests[i].format, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, D3D10_RESOURCE_MISC_TEXTURECUBE, (ID3D10Texture2D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + } + + if (FAILED(hr)) + continue; + + winetest_push_context("Texture type %u", j); + hr = D3DX10SaveTextureToMemory(tex, D3DX10_IFF_DDS, &buffer, 0); + todo_wine_if(dds_expected->todo) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + dds = ID3D10Blob_GetBufferPointer(buffer); + + hr = D3DX10GetImageInfoFromMemory(ID3D10Blob_GetBufferPointer(buffer), ID3D10Blob_GetBufferSize(buffer), NULL, + &img_info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!memcmp(&dds_expected->header, &dds->header, sizeof(dds->header)), "Header mismatch.\n"); + if (dds->header.pixel_format.fourcc == MAKEFOURCC('D','X','1','0')) + ok(!memcmp(&dds_expected->dxt10, &dds->dxt10, sizeof(dds->dxt10)), "DXT10 header mismatch.\n"); + switch (j) + { + case TEXTURE_1D: + check_image_info_values(&img_info, 8, 1, 1, 1, 4, 0, save_tests[i].format, + D3D10_RESOURCE_DIMENSION_TEXTURE1D, D3DX10_IFF_DDS, FALSE); + break; + + case TEXTURE_1D_ARRAY: + check_image_info_values(&img_info, 8, 1, 1, 2, 4, 0, save_tests[i].format, + D3D10_RESOURCE_DIMENSION_TEXTURE1D, D3DX10_IFF_DDS, FALSE); + break; + + case TEXTURE_2D: + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, save_tests[i].format, + D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS, FALSE); + break; + + case TEXTURE_2D_ARRAY: + check_image_info_values(&img_info, 8, 8, 1, 2, 4, 0, save_tests[i].format, + D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS, FALSE); + break; + + case TEXTURE_3D: + check_image_info_values(&img_info, 8, 8, 8, 1, 4, 0, save_tests[i].format, + D3D10_RESOURCE_DIMENSION_TEXTURE3D, D3DX10_IFF_DDS, FALSE); + break; + + case TEXTURE_CUBE: + check_image_info_values(&img_info, 8, 8, 1, 6, 4, D3D10_RESOURCE_MISC_TEXTURECUBE, + save_tests[i].format, D3D10_RESOURCE_DIMENSION_TEXTURE2D, D3DX10_IFF_DDS, FALSE); + break; + } + + ID3D10Blob_Release(buffer); + } + ID3D10Resource_Release(tex); + winetest_pop_context(); + } + winetest_pop_context(); } +} - /* Test NULL file name. */ - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromFileW(NULL, NULL, NULL, NULL, 0x0, 0x0, - device, NULL, NULL, &effect, &errors, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); - ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); +static void check_image_wic_pixel_format(IWICImagingFactory *factory, const void *data, unsigned int size, + const GUID *expected_fmt, BOOL todo) +{ + IWICBitmapFrameDecode *frame = NULL; + IWICBitmapDecoder *decoder = NULL; + IWICStream *stream = NULL; + HRESULT hr; + GUID fmt; - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromFileA(NULL, NULL, NULL, NULL, 0x0, 0x0, - device, NULL, NULL, &effect, &errors, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); - ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + hr = IWICImagingFactory_CreateStream(factory, &stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - /* Test non-existent file. */ - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromFileW(L"deadbeef", NULL, NULL, NULL, 0x0, 0x0, - device, NULL, NULL, &effect, &errors, NULL); - ok(hr == D3D10_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(!errors, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + hr = IWICStream_InitializeFromMemory(stream, (BYTE *)data, size); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromFileA("deadbeef", NULL, NULL, NULL, 0x0, 0x0, - device, NULL, NULL, &effect, &errors, NULL); - ok(hr == D3D10_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(!errors, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream *)stream, NULL, 0, &decoder); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - /* Test creating effect from compiled shader file. */ - create_file(test_file_name, test_fx, sizeof(test_fx), path); + hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromFileW(path, NULL, NULL, NULL, 0x0, 0x0, - device, NULL, NULL, &effect, &errors, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(!errors, "Got unexpected errors %p.\n", errors); - ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - effect->lpVtbl->Release(effect); + hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &fmt); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(todo) ok(IsEqualGUID(expected_fmt, &fmt), "Unexpected WIC format %s.\n", debugstr_guid(&fmt)); - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromFileA(get_str_a(path), NULL, NULL, NULL, 0x0, 0x0, - device, NULL, NULL, &effect, &errors, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(!errors, "Got unexpected errors %p.\n", errors); - ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - effect->lpVtbl->Release(effect); + IWICBitmapFrameDecode_Release(frame); + IWICBitmapDecoder_Release(decoder); + IWICStream_Release(stream); +} - delete_file(test_file_name); +static void test_save_texture_to_iffs(ID3D10Device *device) +{ + static const enum D3DX10_IMAGE_FILE_FORMAT test_iffs[] = { D3DX10_IFF_BMP, D3DX10_IFF_JPG, D3DX10_IFF_PNG, + D3DX10_IFF_TIFF, D3DX10_IFF_GIF, D3DX10_IFF_WMP }; + static const char *test_iff_str[] = { "D3DX10_IFF_BMP", "D3DX10_IFF_JPG", "D3DX10_IFF_PNG", + "D3DX10_IFF_TIFF", "D3DX10_IFF_GIF", "D3DX10_IFF_WMP" }; + struct wic_expected + { + const GUID *fmt; + BOOL todo; + }; + static const struct + { + DXGI_FORMAT format; + BOOL supported; + struct wic_expected wic_expected[ARRAY_SIZE(test_iffs)]; + } save_tests[] = + { + { DXGI_FORMAT_R8G8B8A8_UNORM, TRUE, + { { &GUID_WICPixelFormat32bppBGR, FALSE }, + { &GUID_WICPixelFormat24bppBGR, FALSE }, + { &GUID_WICPixelFormat32bppBGRA, FALSE }, + { &GUID_WICPixelFormat32bppBGRA, FALSE }, + { NULL }, + { &GUID_WICPixelFormat32bppBGRA, FALSE }, + }, + }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, TRUE, + { { &GUID_WICPixelFormat64bppRGBAFixedPoint, TRUE }, + { &GUID_WICPixelFormat24bppBGR, FALSE }, + { &GUID_WICPixelFormat64bppRGBA, FALSE }, + { &GUID_WICPixelFormat64bppRGBA, FALSE }, + { NULL }, + { &GUID_WICPixelFormat64bppRGBAHalf, FALSE }, + }, + }, + { DXGI_FORMAT_R32G32B32A32_FLOAT, TRUE, + { { &GUID_WICPixelFormat64bppRGBAFixedPoint, TRUE }, + { &GUID_WICPixelFormat24bppBGR, FALSE }, + { &GUID_WICPixelFormat64bppRGBA, FALSE }, + { &GUID_WICPixelFormat64bppRGBA, FALSE }, + { NULL }, + { &GUID_WICPixelFormat128bppRGBAFloat, FALSE }, + }, + }, + { DXGI_FORMAT_R16_UNORM, TRUE, + { { &GUID_WICPixelFormat64bppRGBAFixedPoint, TRUE }, + { &GUID_WICPixelFormat8bppGray, FALSE }, + { &GUID_WICPixelFormat16bppGray, FALSE }, + { &GUID_WICPixelFormat16bppGray, FALSE }, + { NULL }, + { &GUID_WICPixelFormat16bppGrayFixedPoint, FALSE }, + }, + }, + { DXGI_FORMAT_R10G10B10A2_UNORM, FALSE }, + { DXGI_FORMAT_R16G16B16A16_UNORM, FALSE }, + { DXGI_FORMAT_R16G16_UNORM, FALSE }, + { DXGI_FORMAT_A8_UNORM, FALSE }, + { DXGI_FORMAT_R16_FLOAT, FALSE }, + { DXGI_FORMAT_R16G16_FLOAT, FALSE }, + { DXGI_FORMAT_R32_FLOAT, FALSE }, + { DXGI_FORMAT_R32G32_FLOAT, FALSE }, + { DXGI_FORMAT_G8R8_G8B8_UNORM, FALSE }, + { DXGI_FORMAT_R8G8_B8G8_UNORM, FALSE }, + { DXGI_FORMAT_BC1_UNORM, FALSE }, + { DXGI_FORMAT_BC2_UNORM, FALSE }, + { DXGI_FORMAT_BC3_UNORM, FALSE }, + { DXGI_FORMAT_BC4_UNORM, FALSE }, + { DXGI_FORMAT_BC4_SNORM, FALSE }, + { DXGI_FORMAT_BC5_UNORM, FALSE }, + { DXGI_FORMAT_BC5_SNORM, FALSE }, + { DXGI_FORMAT_R16G16B16A16_SNORM, FALSE }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, FALSE }, + { DXGI_FORMAT_R8_UNORM, FALSE }, + { DXGI_FORMAT_R8_SNORM, FALSE }, + { DXGI_FORMAT_R8G8_UNORM, FALSE }, + { DXGI_FORMAT_R32G32B32_FLOAT, FALSE }, + { DXGI_FORMAT_BC1_UNORM_SRGB, FALSE }, + { DXGI_FORMAT_BC2_UNORM_SRGB, FALSE }, + { DXGI_FORMAT_BC3_UNORM_SRGB, FALSE }, + { DXGI_FORMAT_R8G8B8A8_SNORM, FALSE }, + { DXGI_FORMAT_R8G8_SNORM, FALSE }, + { DXGI_FORMAT_R16G16_SNORM, FALSE }, + }; + IWICImagingFactory *factory = NULL; + D3DX10_IMAGE_INFO img_info; + ID3D10Resource *tex; + ID3D10Blob *buffer; + unsigned int i, j; + HRESULT hr; - /* Test creating effect from source file. */ - create_file(test_file_name, test_fx_source, strlen(test_fx_source) + 1, path); + hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICImagingFactory, (void **)&factory); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromFileW(path, NULL, NULL, "fx_4_0", 0x0, 0x0, - device, NULL, NULL, &effect, &errors, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(!errors, "Got unexpected errors %p.\n", errors); - ok(effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - effect->lpVtbl->Release(effect); + for (i = 0; i < ARRAY_SIZE(save_tests); ++i) + { + if (!strcmp(winetest_platform, "wine") && (save_tests[i].format == DXGI_FORMAT_G8R8_G8B8_UNORM + || save_tests[i].format == DXGI_FORMAT_R8G8_B8G8_UNORM)) + { + skip("Skipping unsupported format on Wine.\n"); + continue; + } - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromFileA(get_str_a(path), NULL, NULL, "fx_4_0", 0x0, 0x0, - device, NULL, NULL, &effect, &errors, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(!errors, "Got unexpected errors %p.\n", errors); - ok(effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - effect->lpVtbl->Release(effect); + hr = d3d10_create_texture_2d(device, 8, 8, 4, 1, save_tests[i].format, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0, (ID3D10Texture2D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + continue; - delete_file(test_file_name); + winetest_push_context("Test %u", i); + for (j = 0; j < ARRAY_SIZE(test_iffs); ++j) + { + const HRESULT expected_hr = save_tests[i].supported ? S_OK : E_FAIL; + + winetest_push_context("Image format %s", test_iff_str[j]); + hr = D3DX10SaveTextureToMemory(tex, test_iffs[j], &buffer, 0); + + /* GIF saving is never supported, regardless of texture format. */ + if (test_iffs[j] == D3DX10_IFF_GIF) + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + else + todo_wine_if(test_iffs[j] == D3DX10_IFF_WMP) ok(hr == expected_hr, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + check_image_wic_pixel_format(factory, ID3D10Blob_GetBufferPointer(buffer), ID3D10Blob_GetBufferSize(buffer), + save_tests[i].wic_expected[j].fmt, save_tests[i].wic_expected[j].todo); + + hr = D3DX10GetImageInfoFromMemory(ID3D10Blob_GetBufferPointer(buffer), ID3D10Blob_GetBufferSize(buffer), NULL, + &img_info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + check_image_info_values(&img_info, 8, 8, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, + D3D10_RESOURCE_DIMENSION_TEXTURE2D, test_iffs[j], FALSE); + ID3D10Blob_Release(buffer); + } + winetest_pop_context(); + } - refcount = ID3D10Device_Release(device); - ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + ID3D10Resource_Release(tex); + winetest_pop_context(); + } + IWICImagingFactory_Release(factory); } -static void test_create_effect_from_resource(void) +static void test_save_texture(void) { - static const WCHAR *test_resource_name = L"test.fx"; - HMODULE resource_module; + D3D10_SUBRESOURCE_DATA sub_resource_data[4] = { 0 }; + D3D10_TEXTURE2D_DESC tex_2d_desc; + D3DX10_IMAGE_INFO img_info; + ID3D10Texture2D *tex_2d; + uint8_t tmp_buf[1024]; ID3D10Device *device; - ID3D10Effect *effect; - ID3D10Blob *errors; - ULONG refcount; + ID3D10Blob *buffer; HRESULT hr; - if (!(device = create_device())) + device = create_device(); + if (!device) { skip("Failed to create device, skipping tests.\n"); return; } - /* Test NULL module. */ - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromResourceW(NULL, NULL, NULL, NULL, NULL, NULL, - 0, 0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); - ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromResourceA(NULL, NULL, NULL, NULL, NULL, NULL, - 0, 0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); - ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - - /* Test NULL resource name. */ - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromResourceW(GetModuleHandleW(NULL), NULL, NULL, NULL, NULL, NULL, - 0, 0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); - ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + CoInitialize(NULL); - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromResourceA(GetModuleHandleA(NULL), NULL, NULL, NULL, NULL, NULL, - 0, 0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); - ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + test_save_texture_to_dds(device); + test_save_texture_to_iffs(device); - /* Test non-existent resource name. */ - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromResourceW(GetModuleHandleW(NULL), L"deadbeef", NULL, NULL, NULL, NULL, - 0, 0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); - ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + set_d3d10_2d_texture_desc(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D10_USAGE_DEFAULT, + D3D10_BIND_SHADER_RESOURCE, 0, 0); + memset(tmp_buf, 0, sizeof(tmp_buf)); + memcpy(tmp_buf, bc1_to_bc3_8_8_decompressed, sizeof(bc1_to_bc3_8_8_decompressed)); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromResourceA(GetModuleHandleA(NULL), "deadbeef", NULL, NULL, NULL, NULL, - 0, 0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == D3DX10_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); - ok(errors == (ID3D10Blob *)0xdeadbeef, "Got unexpected errors %p.\n", errors); - ok(effect == (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); + hr = ID3D10Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - /* Test creating effect from compiled shader resource. */ - resource_module = create_resource_module(test_resource_name, test_fx, sizeof(test_fx)); + hr = D3DX10SaveTextureToMemory((ID3D10Resource *)tex_2d, D3DX10_IFF_DDS, &buffer, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromResourceW(resource_module, test_resource_name, NULL, NULL, NULL, NULL, - 0, 0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(!errors, "Got unexpected errors %p.\n", errors); - ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - effect->lpVtbl->Release(effect); + hr = D3DX10GetImageInfoFromMemory(ID3D10Blob_GetBufferPointer(buffer), ID3D10Blob_GetBufferSize(buffer), NULL, + &img_info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3DX10_IFF_DDS, FALSE); + ID3D10Blob_Release(buffer); - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromResourceA(resource_module, get_str_a(test_resource_name), NULL, NULL, NULL, NULL, - 0, 0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(!errors, "Got unexpected errors %p.\n", errors); - ok(!!effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - effect->lpVtbl->Release(effect); + hr = D3DX10SaveTextureToFileA((ID3D10Resource *)tex_2d, D3DX10_IFF_DDS, "test_a.dds"); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - delete_resource_module(test_resource_name, resource_module); + hr = D3DX10GetImageInfoFromFileA("test_a.dds", NULL, &img_info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3DX10_IFF_DDS, FALSE); + DeleteFileA("test_a.dds"); - /* Test creating effect from source resource. */ - resource_module = create_resource_module(test_resource_name, test_fx_source, strlen(test_fx_source) + 1); + hr = D3DX10SaveTextureToFileW((ID3D10Resource *)tex_2d, D3DX10_IFF_DDS, L"test_w.dds"); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromResourceW(resource_module, test_resource_name, NULL, NULL, NULL, "fx_4_0", - 0, 0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(!errors, "Got unexpected errors %p.\n", errors); - ok(effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - effect->lpVtbl->Release(effect); + hr = D3DX10GetImageInfoFromFileW(L"test_w.dds", NULL, &img_info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3DX10_IFF_DDS, FALSE); + DeleteFileW(L"test_w.dds"); - errors = (ID3D10Blob *)0xdeadbeef; - effect = (ID3D10Effect *)0xdeadbeef; - hr = D3DX10CreateEffectFromResourceA(resource_module, get_str_a(test_resource_name), NULL, NULL, NULL, "fx_4_0", - 0, 0, device, NULL, NULL, &effect, &errors, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(!errors, "Got unexpected errors %p.\n", errors); - ok(effect && effect != (ID3D10Effect *)0xdeadbeef, "Got unexpected effect %p.\n", effect); - effect->lpVtbl->Release(effect); + ID3D10Texture2D_Release(tex_2d); - delete_resource_module(test_resource_name, resource_module); + CoUninitialize(); - refcount = ID3D10Device_Release(device); - ok(!refcount, "Got unexpected refcount %lu.\n", refcount); + ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); } -static void test_preprocess_shader(void) +START_TEST(d3dx10) { - static const char shader_source[] = - "float4 main()\n" - "{\n" - " return float4(1.0);\n" - "}\n"; - ID3D10Blob *preprocessed, *errors; - HRESULT hr, hr2; - - hr2 = 0xdeadbeef; - hr = D3DX10PreprocessShaderFromMemory(NULL, 0, NULL, NULL, NULL, - NULL, &preprocessed, &errors, &hr2); - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); - ok(hr2 == 0xdeadbeef, "Unexpected hr2 %#lx.\n", hr2); + HMODULE wined3d; - hr2 = 0xdeadbeef; - hr = D3DX10PreprocessShaderFromMemory(shader_source, strlen(shader_source), NULL, NULL, NULL, - NULL, &preprocessed, &errors, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!!preprocessed, "Unexpected preprocessed %p.\n", preprocessed); - ok(!errors, "Unexpected errors %p.\n", errors); - ID3D10Blob_Release(preprocessed); + if ((wined3d = GetModuleHandleA("wined3d.dll"))) + { + enum wined3d_renderer (CDECL *p_wined3d_get_renderer)(void); - hr2 = 0xdeadbeef; - hr = D3DX10PreprocessShaderFromMemory(shader_source, strlen(shader_source), NULL, NULL, NULL, - NULL, &preprocessed, &errors, &hr2); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(hr == hr2, "Unexpected hr2 %#lx.\n", hr2); - ok(!!preprocessed, "Unexpected preprocessed %p.\n", preprocessed); - ok(!errors, "Unexpected errors %p.\n", errors); - ID3D10Blob_Release(preprocessed); -} + if ((p_wined3d_get_renderer = (void *)GetProcAddress(wined3d, "wined3d_get_renderer")) + && p_wined3d_get_renderer() == WINED3D_RENDERER_OPENGL) + wined3d_opengl = true; + } -START_TEST(d3dx10) -{ test_D3DX10UnsetAllDeviceObjects(); test_D3DX10CreateAsyncMemoryLoader(); test_D3DX10CreateAsyncFileLoader(); test_D3DX10CreateAsyncResourceLoader(); test_D3DX10CreateAsyncTextureInfoProcessor(); test_D3DX10CreateAsyncTextureProcessor(); + test_D3DX10CreateAsyncShaderResourceViewProcessor(); test_D3DX10CreateThreadPump(); + test_D3DX10LoadTextureFromTexture(); + test_D3DX10FilterTexture(); test_get_image_info(); test_create_texture(); + test_create_shader_resource_view(); + test_save_texture(); test_font(); test_sprite(); test_create_effect_from_memory(); diff --git a/dlls/d3dx10_43/texture.c b/dlls/d3dx10_43/texture.c index b925a07dd088..0ae7c0a654b0 100644 --- a/dlls/d3dx10_43/texture.c +++ b/dlls/d3dx10_43/texture.c @@ -17,265 +17,16 @@ */ #include "wine/debug.h" +#include "assert.h" #define COBJMACROS #include "d3d10_1.h" #include "d3dx10.h" -#include "wincodec.h" #include "dxhelpers.h" WINE_DEFAULT_DEBUG_CHANNEL(d3dx); -HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT sdk_version, IWICImagingFactory **imaging_factory); - -static const struct -{ - const GUID *wic_container_guid; - D3DX10_IMAGE_FILE_FORMAT d3dx_file_format; -} -file_formats[] = -{ - { &GUID_ContainerFormatBmp, D3DX10_IFF_BMP }, - { &GUID_ContainerFormatJpeg, D3DX10_IFF_JPG }, - { &GUID_ContainerFormatPng, D3DX10_IFF_PNG }, - { &GUID_ContainerFormatDds, D3DX10_IFF_DDS }, - { &GUID_ContainerFormatTiff, D3DX10_IFF_TIFF }, - { &GUID_ContainerFormatGif, D3DX10_IFF_GIF }, - { &GUID_ContainerFormatWmp, D3DX10_IFF_WMP }, -}; - -static const struct -{ - const GUID *wic_guid; - DXGI_FORMAT dxgi_format; -} -wic_pixel_formats[] = -{ - { &GUID_WICPixelFormatBlackWhite, DXGI_FORMAT_R1_UNORM }, - { &GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM }, - { &GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM }, - { &GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM }, - { &GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT }, - { &GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT }, - { &GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM }, - { &GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM }, - { &GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM }, - { &GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM }, - { &GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM }, - { &GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM }, - { &GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, - { &GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM }, - { &GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT }, - { &GUID_WICPixelFormat96bppRGBFloat, DXGI_FORMAT_R32G32B32_FLOAT }, - { &GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT } -}; - -static D3DX10_IMAGE_FILE_FORMAT wic_container_guid_to_file_format(GUID *container_format) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(file_formats); ++i) - { - if (IsEqualGUID(file_formats[i].wic_container_guid, container_format)) - return file_formats[i].d3dx_file_format; - } - return D3DX10_IFF_FORCE_DWORD; -} - -static const GUID *dxgi_format_to_wic_guid(DXGI_FORMAT format) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); ++i) - { - if (wic_pixel_formats[i].dxgi_format == format) - return wic_pixel_formats[i].wic_guid; - } - - return NULL; -} - -static D3D10_RESOURCE_DIMENSION wic_dimension_to_d3dx10_dimension(WICDdsDimension wic_dimension) -{ - switch (wic_dimension) - { - case WICDdsTexture1D: - return D3D10_RESOURCE_DIMENSION_TEXTURE1D; - case WICDdsTexture2D: - case WICDdsTextureCube: - return D3D10_RESOURCE_DIMENSION_TEXTURE2D; - case WICDdsTexture3D: - return D3D10_RESOURCE_DIMENSION_TEXTURE3D; - default: - return D3D10_RESOURCE_DIMENSION_UNKNOWN; - } -} - -static unsigned int get_bpp_from_format(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_R32G32B32A32_TYPELESS: - case DXGI_FORMAT_R32G32B32A32_FLOAT: - case DXGI_FORMAT_R32G32B32A32_UINT: - case DXGI_FORMAT_R32G32B32A32_SINT: - return 128; - case DXGI_FORMAT_R32G32B32_TYPELESS: - case DXGI_FORMAT_R32G32B32_FLOAT: - case DXGI_FORMAT_R32G32B32_UINT: - case DXGI_FORMAT_R32G32B32_SINT: - return 96; - case DXGI_FORMAT_R16G16B16A16_TYPELESS: - case DXGI_FORMAT_R16G16B16A16_FLOAT: - case DXGI_FORMAT_R16G16B16A16_UNORM: - case DXGI_FORMAT_R16G16B16A16_UINT: - case DXGI_FORMAT_R16G16B16A16_SNORM: - case DXGI_FORMAT_R16G16B16A16_SINT: - case DXGI_FORMAT_R32G32_TYPELESS: - case DXGI_FORMAT_R32G32_FLOAT: - case DXGI_FORMAT_R32G32_UINT: - case DXGI_FORMAT_R32G32_SINT: - case DXGI_FORMAT_R32G8X24_TYPELESS: - case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: - case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: - case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: - case DXGI_FORMAT_Y416: - case DXGI_FORMAT_Y210: - case DXGI_FORMAT_Y216: - return 64; - case DXGI_FORMAT_R10G10B10A2_TYPELESS: - case DXGI_FORMAT_R10G10B10A2_UNORM: - case DXGI_FORMAT_R10G10B10A2_UINT: - case DXGI_FORMAT_R11G11B10_FLOAT: - case DXGI_FORMAT_R8G8B8A8_TYPELESS: - case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - case DXGI_FORMAT_R8G8B8A8_UINT: - case DXGI_FORMAT_R8G8B8A8_SNORM: - case DXGI_FORMAT_R8G8B8A8_SINT: - case DXGI_FORMAT_R16G16_TYPELESS: - case DXGI_FORMAT_R16G16_FLOAT: - case DXGI_FORMAT_R16G16_UNORM: - case DXGI_FORMAT_R16G16_UINT: - case DXGI_FORMAT_R16G16_SNORM: - case DXGI_FORMAT_R16G16_SINT: - case DXGI_FORMAT_R32_TYPELESS: - case DXGI_FORMAT_D32_FLOAT: - case DXGI_FORMAT_R32_FLOAT: - case DXGI_FORMAT_R32_UINT: - case DXGI_FORMAT_R32_SINT: - case DXGI_FORMAT_R24G8_TYPELESS: - case DXGI_FORMAT_D24_UNORM_S8_UINT: - case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: - case DXGI_FORMAT_X24_TYPELESS_G8_UINT: - case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: - case DXGI_FORMAT_R8G8_B8G8_UNORM: - case DXGI_FORMAT_G8R8_G8B8_UNORM: - case DXGI_FORMAT_B8G8R8A8_UNORM: - case DXGI_FORMAT_B8G8R8X8_UNORM: - case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: - case DXGI_FORMAT_B8G8R8A8_TYPELESS: - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - case DXGI_FORMAT_B8G8R8X8_TYPELESS: - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - case DXGI_FORMAT_AYUV: - case DXGI_FORMAT_Y410: - case DXGI_FORMAT_YUY2: - return 32; - case DXGI_FORMAT_P010: - case DXGI_FORMAT_P016: - return 24; - case DXGI_FORMAT_R8G8_TYPELESS: - case DXGI_FORMAT_R8G8_UNORM: - case DXGI_FORMAT_R8G8_UINT: - case DXGI_FORMAT_R8G8_SNORM: - case DXGI_FORMAT_R8G8_SINT: - case DXGI_FORMAT_R16_TYPELESS: - case DXGI_FORMAT_R16_FLOAT: - case DXGI_FORMAT_D16_UNORM: - case DXGI_FORMAT_R16_UNORM: - case DXGI_FORMAT_R16_UINT: - case DXGI_FORMAT_R16_SNORM: - case DXGI_FORMAT_R16_SINT: - case DXGI_FORMAT_B5G6R5_UNORM: - case DXGI_FORMAT_B5G5R5A1_UNORM: - case DXGI_FORMAT_A8P8: - case DXGI_FORMAT_B4G4R4A4_UNORM: - return 16; - case DXGI_FORMAT_NV12: - case DXGI_FORMAT_420_OPAQUE: - case DXGI_FORMAT_NV11: - return 12; - case DXGI_FORMAT_R8_TYPELESS: - case DXGI_FORMAT_R8_UNORM: - case DXGI_FORMAT_R8_UINT: - case DXGI_FORMAT_R8_SNORM: - case DXGI_FORMAT_R8_SINT: - case DXGI_FORMAT_A8_UNORM: - case DXGI_FORMAT_AI44: - case DXGI_FORMAT_IA44: - case DXGI_FORMAT_P8: - case DXGI_FORMAT_BC2_TYPELESS: - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: - case DXGI_FORMAT_BC3_TYPELESS: - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: - case DXGI_FORMAT_BC5_TYPELESS: - case DXGI_FORMAT_BC5_UNORM: - case DXGI_FORMAT_BC5_SNORM: - case DXGI_FORMAT_BC6H_TYPELESS: - case DXGI_FORMAT_BC6H_UF16: - case DXGI_FORMAT_BC6H_SF16: - case DXGI_FORMAT_BC7_TYPELESS: - case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: - return 8; - case DXGI_FORMAT_BC1_TYPELESS: - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: - case DXGI_FORMAT_BC4_TYPELESS: - case DXGI_FORMAT_BC4_UNORM: - case DXGI_FORMAT_BC4_SNORM: - return 4; - case DXGI_FORMAT_R1_UNORM: - return 1; - default: - return 0; - } -} - -static DXGI_FORMAT get_d3dx10_dds_format(DXGI_FORMAT format) -{ - static const struct - { - DXGI_FORMAT src; - DXGI_FORMAT dst; - } - format_map[] = - { - {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM}, - {DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM}, - {DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM}, - {DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM}, - {DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM}, - {DXGI_FORMAT_B5G5R5A1_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM}, - {DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM}, - {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM}, - {DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM}, - }; - - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(format_map); ++i) - { - if (format == format_map[i].src) - return format_map[i].dst; - } - return format; -} - HRESULT WINAPI D3DX10GetImageInfoFromFileA(const char *src_file, ID3DX10ThreadPump *pump, D3DX10_IMAGE_INFO *info, HRESULT *result) { @@ -423,92 +174,79 @@ HRESULT WINAPI D3DX10GetImageInfoFromResourceW(HMODULE module, const WCHAR *reso return hr; } -HRESULT get_image_info(const void *data, SIZE_T size, D3DX10_IMAGE_INFO *img_info) +static HRESULT d3dx10_image_info_from_d3dx_image(D3DX10_IMAGE_INFO *info, struct d3dx_image *image) { - IWICBitmapFrameDecode *frame = NULL; - IWICImagingFactory *factory = NULL; - IWICDdsDecoder *dds_decoder = NULL; - IWICBitmapDecoder *decoder = NULL; - WICDdsParameters dds_params; - IWICStream *stream = NULL; - unsigned int frame_count; - GUID container_format; - HRESULT hr; + DXGI_FORMAT format; + HRESULT hr = S_OK; - WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory); - IWICImagingFactory_CreateStream(factory, &stream); - hr = IWICStream_InitializeFromMemory(stream, (BYTE *)data, size); - if (FAILED(hr)) + memset(info, 0, sizeof(*info)); + if (image->image_file_format == D3DX_IMAGE_FILE_FORMAT_DDS_DXT10) { - WARN("Failed to initialize stream.\n"); - goto end; + format = dxgi_format_from_dxt10_dds_d3dx_pixel_format_id(image->format); + info->ImageFileFormat = D3DX10_IFF_DDS; } - hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream *)stream, NULL, 0, &decoder); - if (FAILED(hr)) - goto end; - - hr = IWICBitmapDecoder_GetContainerFormat(decoder, &container_format); - if (FAILED(hr)) - goto end; - img_info->ImageFileFormat = wic_container_guid_to_file_format(&container_format); - if (img_info->ImageFileFormat == D3DX10_IFF_FORCE_DWORD) + else { - hr = E_FAIL; - WARN("Unsupported image file format %s.\n", debugstr_guid(&container_format)); - goto end; + if (image->image_file_format == D3DX_IMAGE_FILE_FORMAT_DDS) + format = dxgi_format_from_legacy_dds_d3dx_pixel_format_id(image->format); + else + format = DXGI_FORMAT_R8G8B8A8_UNORM; + info->ImageFileFormat = (D3DX10_IMAGE_FILE_FORMAT)image->image_file_format; } - hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count); - if (FAILED(hr) || !frame_count) - goto end; - hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); - if (FAILED(hr)) - goto end; - hr = IWICBitmapFrameDecode_GetSize(frame, &img_info->Width, &img_info->Height); - if (FAILED(hr)) - goto end; + if (format == DXGI_FORMAT_UNKNOWN) + { + WARN("Tried to load file with unsupported d3dx_pixel_format_id %#x.\n", image->format); + return E_FAIL; + } - if (img_info->ImageFileFormat == D3DX10_IFF_DDS) + if (info->ImageFileFormat == D3DX10_IFF_FORCE_DWORD) { - hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICDdsDecoder, (void **)&dds_decoder); - if (FAILED(hr)) - goto end; - hr = IWICDdsDecoder_GetParameters(dds_decoder, &dds_params); - if (FAILED(hr)) - goto end; - img_info->ArraySize = dds_params.ArraySize; - img_info->Depth = dds_params.Depth; - img_info->MipLevels = dds_params.MipLevels; - img_info->ResourceDimension = wic_dimension_to_d3dx10_dimension(dds_params.Dimension); - img_info->Format = get_d3dx10_dds_format(dds_params.DxgiFormat); - img_info->MiscFlags = 0; - if (dds_params.Dimension == WICDdsTextureCube) - { - img_info->MiscFlags = D3D10_RESOURCE_MISC_TEXTURECUBE; - img_info->ArraySize *= 6; - } + ERR("Unsupported d3dx image file.\n"); + return E_FAIL; } - else + + info->Width = image->size.width; + info->Height = image->size.height; + info->Depth = image->size.depth; + info->ArraySize = image->layer_count; + info->MipLevels = image->mip_levels; + info->Format = format; + switch (image->resource_type) { - img_info->ArraySize = 1; - img_info->Depth = 1; - img_info->MipLevels = 1; - img_info->ResourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; - img_info->Format = DXGI_FORMAT_R8G8B8A8_UNORM; - img_info->MiscFlags = 0; + case D3DX_RESOURCE_TYPE_TEXTURE_2D: + info->ResourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; + break; + + case D3DX_RESOURCE_TYPE_CUBE_TEXTURE: + info->ResourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; + info->MiscFlags |= D3D10_RESOURCE_MISC_TEXTURECUBE; + break; + + case D3DX_RESOURCE_TYPE_TEXTURE_3D: + info->ResourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D; + break; + + default: + ERR("Unhandled resource type %d.\n", image->resource_type); + hr = E_FAIL; + break; } -end: - if (dds_decoder) - IWICDdsDecoder_Release(dds_decoder); - if (frame) - IWICBitmapFrameDecode_Release(frame); - if (decoder) - IWICBitmapDecoder_Release(decoder); - if (stream) - IWICStream_Release(stream); - if (factory) - IWICImagingFactory_Release(factory); + return hr; +} + +HRESULT get_image_info(const void *data, SIZE_T size, D3DX10_IMAGE_INFO *img_info) +{ + struct d3dx_image image; + HRESULT hr; + + if (!data || !size) + return E_FAIL; + + hr = d3dx_image_init(data, size, &image, 0, D3DX_IMAGE_INFO_ONLY | D3DX_IMAGE_SUPPORT_DXT10); + if (SUCCEEDED(hr)) + hr = d3dx10_image_info_from_d3dx_image(img_info, &image); if (hr != S_OK) { @@ -560,9 +298,12 @@ static HRESULT create_texture(ID3D10Device *device, const void *data, SIZE_T siz { D3D10_SUBRESOURCE_DATA *resource_data; D3DX10_IMAGE_LOAD_INFO load_info_copy; + D3DX10_IMAGE_INFO img_info; HRESULT hr; init_load_info(load_info, &load_info_copy); + if (load_info_copy.pSrcInfo == NULL) + load_info_copy.pSrcInfo = &img_info; if (FAILED((hr = load_texture_data(data, size, &load_info_copy, &resource_data)))) return hr; @@ -750,302 +491,272 @@ void init_load_info(const D3DX10_IMAGE_LOAD_INFO *load_info, D3DX10_IMAGE_LOAD_I out->pSrcInfo = NULL; } -static HRESULT dds_get_frame_info(IWICDdsFrameDecode *frame, const D3DX10_IMAGE_INFO *img_info, - WICDdsFormatInfo *format_info, unsigned int *stride, unsigned int *frame_size) +static HRESULT d3dx_create_subresource_data_for_texture(uint32_t width, uint32_t height, uint32_t depth, + uint32_t mip_levels, uint32_t layer_count, const struct pixel_format_desc *fmt_desc, + D3D10_SUBRESOURCE_DATA **out_sub_rsrc_data, uint8_t **pixel_data) { - unsigned int width, height; - HRESULT hr; + uint8_t *sub_rsrc_data = NULL, *pixels_ptr; + uint32_t i, j, pixels_size, pixels_offset; + D3D10_SUBRESOURCE_DATA *sub_rsrcs = NULL; + HRESULT hr = S_OK; - if (FAILED(hr = IWICDdsFrameDecode_GetFormatInfo(frame, format_info))) - return hr; - if (FAILED(hr = IWICDdsFrameDecode_GetSizeInBlocks(frame, &width, &height))) - return hr; + *pixel_data = NULL; + *out_sub_rsrc_data = NULL; - if (img_info->Format == format_info->DxgiFormat) - { - *stride = width * format_info->BytesPerBlock; - *frame_size = *stride * height; - } - else + pixels_offset = (sizeof(*sub_rsrcs) * mip_levels * layer_count); + pixels_size = d3dx_calculate_layer_pixels_size(fmt_desc->format, width, height, depth, mip_levels) * layer_count; + if (!(sub_rsrc_data = malloc(pixels_size + pixels_offset))) + return E_FAIL; + + sub_rsrcs = (D3D10_SUBRESOURCE_DATA *)sub_rsrc_data; + pixels_ptr = sub_rsrc_data + pixels_offset; + for (i = 0; i < layer_count; ++i) { - width *= format_info->BlockWidth; - height *= format_info->BlockHeight; - *stride = (width * get_bpp_from_format(img_info->Format) + 7) / 8; - *frame_size = *stride * height; - } - return S_OK; -} + struct volume size = { width, height, depth }; -static HRESULT convert_image(IWICImagingFactory *factory, IWICBitmapFrameDecode *frame, - const GUID *dst_format, unsigned int stride, unsigned int frame_size, BYTE *buffer) -{ - IWICFormatConverter *converter; - BOOL can_convert; - GUID src_format; - HRESULT hr; + for (j = 0; j < mip_levels; ++j) + { + uint32_t row_pitch, slice_pitch; - if (FAILED(hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &src_format))) - return hr; + hr = d3dx_calculate_pixels_size(fmt_desc->format, size.width, size.height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + break; - if (IsEqualGUID(&src_format, dst_format)) - { - if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, stride, frame_size, buffer))) - return hr; - return S_OK; - } + sub_rsrcs[i * mip_levels + j].pSysMem = pixels_ptr; + sub_rsrcs[i * mip_levels + j].SysMemPitch = row_pitch; + sub_rsrcs[i * mip_levels + j].SysMemSlicePitch = slice_pitch; - if (FAILED(hr = IWICImagingFactory_CreateFormatConverter(factory, &converter))) - return hr; - if (FAILED(hr = IWICFormatConverter_CanConvert(converter, &src_format, dst_format, &can_convert))) - { - IWICFormatConverter_Release(converter); - return hr; - } - if (!can_convert) - { - WARN("Format converting %s to %s is not supported by WIC.\n", - debugstr_guid(&src_format), debugstr_guid(dst_format)); - IWICFormatConverter_Release(converter); - return E_NOTIMPL; + pixels_ptr += slice_pitch * size.depth; + d3dx_get_next_mip_level_size(&size); + } } - if (FAILED(hr = IWICFormatConverter_Initialize(converter, (IWICBitmapSource *)frame, dst_format, - WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom))) + + if (SUCCEEDED(hr)) { - IWICFormatConverter_Release(converter); - return hr; + *pixel_data = sub_rsrc_data + pixels_offset; + *out_sub_rsrc_data = sub_rsrcs; + sub_rsrc_data = NULL; } - hr = IWICFormatConverter_CopyPixels(converter, NULL, stride, frame_size, buffer); - IWICFormatConverter_Release(converter); + + free(sub_rsrc_data); return hr; } HRESULT load_texture_data(const void *data, SIZE_T size, D3DX10_IMAGE_LOAD_INFO *load_info, D3D10_SUBRESOURCE_DATA **resource_data) { - unsigned int stride, frame_size, i, j; - IWICDdsFrameDecode *dds_frame = NULL; - IWICBitmapFrameDecode *frame = NULL; - IWICImagingFactory *factory = NULL; - IWICDdsDecoder *dds_decoder = NULL; - IWICBitmapDecoder *decoder = NULL; - BYTE *res_data = NULL, *buffer; + const struct pixel_format_desc *fmt_desc, *src_desc; + uint32_t i, j, loaded_mip_levels, max_mip_levels; + D3D10_SUBRESOURCE_DATA *sub_rsrcs = NULL; D3DX10_IMAGE_INFO img_info; - IWICStream *stream = NULL; - const GUID *dst_format; + struct d3dx_image image; + uint8_t *pixels_ptr; HRESULT hr; - if (load_info->Width != D3DX10_DEFAULT) - FIXME("load_info->Width is ignored.\n"); - if (load_info->Height != D3DX10_DEFAULT) - FIXME("load_info->Height is ignored.\n"); - if (load_info->Depth != D3DX10_DEFAULT) - FIXME("load_info->Depth is ignored.\n"); - if (load_info->FirstMipLevel != D3DX10_DEFAULT) - FIXME("load_info->FirstMipLevel is ignored.\n"); - if (load_info->MipLevels != D3DX10_DEFAULT) - FIXME("load_info->MipLevels is ignored.\n"); - if (load_info->Usage != D3DX10_DEFAULT) - FIXME("load_info->Usage is ignored.\n"); - if (load_info->BindFlags != D3DX10_DEFAULT) - FIXME("load_info->BindFlags is ignored.\n"); - if (load_info->CpuAccessFlags != D3DX10_DEFAULT) - FIXME("load_info->CpuAccessFlags is ignored.\n"); - if (load_info->MiscFlags != D3DX10_DEFAULT) - FIXME("load_info->MiscFlags is ignored.\n"); - if (load_info->Format != D3DX10_DEFAULT) - FIXME("load_info->Format is ignored.\n"); - if (load_info->Filter != D3DX10_DEFAULT) - FIXME("load_info->Filter is ignored.\n"); - if (load_info->MipFilter != D3DX10_DEFAULT) - FIXME("load_info->MipFilter is ignored.\n"); - if (load_info->pSrcInfo) - FIXME("load_info->pSrcInfo is ignored.\n"); + if (!data || !size) + return E_FAIL; - if (FAILED(D3DX10GetImageInfoFromMemory(data, size, NULL, &img_info, NULL))) + if (FAILED(hr = d3dx_handle_filter(&load_info->Filter))) + { + ERR("Invalid filter argument %#x.\n", load_info->Filter); + return hr; + } + + hr = d3dx_image_init(data, size, &image, 0, D3DX_IMAGE_SUPPORT_DXT10); + if (FAILED(hr)) return E_FAIL; + + hr = d3dx10_image_info_from_d3dx_image(&img_info, &image); + if (FAILED(hr)) + { + WARN("Invalid or unsupported image file, hr %#lx.\n", hr); + hr = E_FAIL; + goto end; + } + if ((!(img_info.MiscFlags & D3D10_RESOURCE_MISC_TEXTURECUBE) || img_info.ArraySize != 6) && img_info.ArraySize != 1) { FIXME("img_info.ArraySize = %u not supported.\n", img_info.ArraySize); - return E_NOTIMPL; + hr = E_NOTIMPL; + goto end; } - - if (FAILED(hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory))) - goto end; - if (FAILED(hr = IWICImagingFactory_CreateStream(factory, &stream))) + if (load_info->FirstMipLevel == D3DX10_DEFAULT || (load_info->FirstMipLevel >= img_info.MipLevels)) + load_info->FirstMipLevel = 0; + if (load_info->Format == D3DX10_DEFAULT || load_info->Format == DXGI_FORMAT_FROM_FILE) + load_info->Format = img_info.Format; + fmt_desc = get_d3dx_pixel_format_info(d3dx_pixel_format_id_from_dxgi_format(load_info->Format)); + if (fmt_desc->format == D3DX_PIXEL_FORMAT_COUNT) + { + FIXME("Unknown DXGI format supplied, %#x.\n", load_info->Format); + hr = E_NOTIMPL; goto end; - if (FAILED(hr = IWICStream_InitializeFromMemory(stream, (BYTE *)data, size))) + } + + /* Potentially round up width/height to align with block size. */ + if (!load_info->Width || load_info->Width == D3DX10_FROM_FILE || load_info->Width == D3DX10_DEFAULT) + load_info->Width = (img_info.Width + fmt_desc->block_width - 1) & ~(fmt_desc->block_width - 1); + if (!load_info->Height || load_info->Height == D3DX10_FROM_FILE || load_info->Height == D3DX10_DEFAULT) + load_info->Height = (img_info.Height + fmt_desc->block_height - 1) & ~(fmt_desc->block_height - 1); + + if (!load_info->Depth || load_info->Depth == D3DX10_FROM_FILE || load_info->Depth == D3DX10_DEFAULT) + load_info->Depth = img_info.Depth; + if ((load_info->Depth > 1) && (img_info.ResourceDimension != D3D10_RESOURCE_DIMENSION_TEXTURE3D)) + { + hr = E_FAIL; goto end; - if (FAILED(hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream *)stream, NULL, 0, &decoder))) + } + + max_mip_levels = d3dx_get_max_mip_levels_for_size(load_info->Width, load_info->Height, load_info->Depth); + if (!load_info->MipLevels || load_info->MipLevels == D3DX10_DEFAULT || load_info->MipLevels == D3DX10_FROM_FILE) + load_info->MipLevels = (load_info->MipLevels == D3DX10_FROM_FILE) ? img_info.MipLevels : max_mip_levels; + load_info->MipLevels = min(max_mip_levels, load_info->MipLevels); + + hr = d3dx_create_subresource_data_for_texture(load_info->Width, load_info->Height, load_info->Depth, + load_info->MipLevels, img_info.ArraySize, fmt_desc, &sub_rsrcs, &pixels_ptr); + if (FAILED(hr)) goto end; - if (img_info.ImageFileFormat == D3DX10_IFF_DDS) + src_desc = get_d3dx_pixel_format_info(image.format); + loaded_mip_levels = min((img_info.MipLevels - load_info->FirstMipLevel), load_info->MipLevels); + for (i = 0; i < img_info.ArraySize; ++i) { - WICDdsFormatInfo format_info; - size_t size = 0; - - if (FAILED(hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICDdsDecoder, (void **)&dds_decoder))) - goto end; + struct volume dst_size = { load_info->Width, load_info->Height, load_info->Depth }; - for (i = 0; i < img_info.ArraySize; ++i) + for (j = 0; j < loaded_mip_levels; ++j) { - for (j = 0; j < img_info.MipLevels; ++j) - { - if (FAILED(hr = IWICDdsDecoder_GetFrame(dds_decoder, i, j, 0, &frame))) - goto end; - if (FAILED(hr = IWICBitmapFrameDecode_QueryInterface(frame, - &IID_IWICDdsFrameDecode, (void **)&dds_frame))) - goto end; - if (FAILED(hr = dds_get_frame_info(dds_frame, &img_info, &format_info, &stride, &frame_size))) - goto end; + D3D10_SUBRESOURCE_DATA *sub_rsrc = &sub_rsrcs[i * load_info->MipLevels + j]; + const RECT unaligned_rect = { 0, 0, dst_size.width, dst_size.height }; + struct d3dx_pixels src_pixels, dst_pixels; - if (!i && !j) - { - img_info.Width = (img_info.Width + format_info.BlockWidth - 1) & ~(format_info.BlockWidth - 1); - img_info.Height = (img_info.Height + format_info.BlockHeight - 1) & ~(format_info.BlockHeight - 1); - } + hr = d3dx_image_get_pixels(&image, i, j + load_info->FirstMipLevel, &src_pixels); + if (FAILED(hr)) + goto end; - size += sizeof(**resource_data) + frame_size; + set_d3dx_pixels(&dst_pixels, sub_rsrc->pSysMem, sub_rsrc->SysMemPitch, sub_rsrc->SysMemSlicePitch, NULL, + dst_size.width, dst_size.height, dst_size.depth, &unaligned_rect); - IWICDdsFrameDecode_Release(dds_frame); - dds_frame = NULL; - IWICBitmapFrameDecode_Release(frame); - frame = NULL; - } + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, src_desc, load_info->Filter, 0); + if (FAILED(hr)) + goto end; + + d3dx_get_next_mip_level_size(&dst_size); } + } + + if (loaded_mip_levels < load_info->MipLevels) + { + struct volume base_level_size = { load_info->Width, load_info->Height, load_info->Depth }; - if (!(res_data = malloc(size))) + if (FAILED(hr = d3dx_handle_filter(&load_info->MipFilter))) { - hr = E_FAIL; + ERR("Invalid mip filter argument %#x.\n", load_info->MipFilter); goto end; } - *resource_data = (D3D10_SUBRESOURCE_DATA *)res_data; - size = 0; + d3dx_get_mip_level_size(&base_level_size, loaded_mip_levels - 1); for (i = 0; i < img_info.ArraySize; ++i) { - for (j = 0; j < img_info.MipLevels; ++j) + struct volume src_size, dst_size; + + src_size = dst_size = base_level_size; + for (j = (loaded_mip_levels - 1); j < (load_info->MipLevels - 1); ++j) { - if (FAILED(hr = IWICDdsDecoder_GetFrame(dds_decoder, i, j, 0, &frame))) - goto end; - if (FAILED(hr = IWICBitmapFrameDecode_QueryInterface(frame, - &IID_IWICDdsFrameDecode, (void **)&dds_frame))) - goto end; - if (FAILED(hr = dds_get_frame_info(dds_frame, &img_info, &format_info, &stride, &frame_size))) + D3D10_SUBRESOURCE_DATA *dst_data = &sub_rsrcs[i * load_info->MipLevels + j + 1]; + D3D10_SUBRESOURCE_DATA *src_data = &sub_rsrcs[i * load_info->MipLevels + j]; + const RECT src_unaligned_rect = { 0, 0, src_size.width, src_size.height }; + struct d3dx_pixels src_pixels, dst_pixels; + RECT dst_unaligned_rect; + + d3dx_get_next_mip_level_size(&dst_size); + SetRect(&dst_unaligned_rect, 0, 0, dst_size.width, dst_size.height); + set_d3dx_pixels(&dst_pixels, dst_data->pSysMem, dst_data->SysMemPitch, dst_data->SysMemSlicePitch, NULL, + dst_size.width, dst_size.height, dst_size.depth, &dst_unaligned_rect); + set_d3dx_pixels(&src_pixels, src_data->pSysMem, src_data->SysMemPitch, src_data->SysMemSlicePitch, NULL, + src_size.width, src_size.height, src_size.depth, &src_unaligned_rect); + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, fmt_desc, load_info->MipFilter, 0); + if (FAILED(hr)) goto end; - buffer = res_data + sizeof(**resource_data) * img_info.ArraySize * img_info.MipLevels + size; - size += frame_size; - - if (img_info.Format == format_info.DxgiFormat) - { - if (FAILED(hr = IWICDdsFrameDecode_CopyBlocks(dds_frame, NULL, stride, frame_size, buffer))) - goto end; - } - else - { - if (!(dst_format = dxgi_format_to_wic_guid(img_info.Format))) - { - hr = E_FAIL; - FIXME("Unsupported DXGI format %#x.\n", img_info.Format); - goto end; - } - if (FAILED(hr = convert_image(factory, frame, dst_format, stride, frame_size, buffer))) - goto end; - } - - IWICDdsFrameDecode_Release(dds_frame); - dds_frame = NULL; - IWICBitmapFrameDecode_Release(frame); - frame = NULL; - - (*resource_data)[i * img_info.MipLevels + j].pSysMem = buffer; - (*resource_data)[i * img_info.MipLevels + j].SysMemPitch = stride; - (*resource_data)[i * img_info.MipLevels + j].SysMemSlicePitch = frame_size; + src_size = dst_size; } } } - else - { - if (FAILED(hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame))) - goto end; - - stride = (img_info.Width * get_bpp_from_format(img_info.Format) + 7) / 8; - frame_size = stride * img_info.Height; - - if (!(res_data = malloc(sizeof(**resource_data) + frame_size))) - { - hr = E_FAIL; - goto end; - } - buffer = res_data + sizeof(**resource_data); - - if (!(dst_format = dxgi_format_to_wic_guid(img_info.Format))) - { - hr = E_FAIL; - FIXME("Unsupported DXGI format %#x.\n", img_info.Format); - goto end; - } - if (FAILED(hr = convert_image(factory, frame, dst_format, stride, frame_size, buffer))) - goto end; - - *resource_data = (D3D10_SUBRESOURCE_DATA *)res_data; - (*resource_data)->pSysMem = buffer; - (*resource_data)->SysMemPitch = stride; - (*resource_data)->SysMemSlicePitch = frame_size; - } - load_info->Width = img_info.Width; - load_info->Height = img_info.Height; - load_info->MipLevels = img_info.MipLevels; - load_info->Format = img_info.Format; - load_info->Usage = D3D10_USAGE_DEFAULT; - load_info->BindFlags = D3D10_BIND_SHADER_RESOURCE; - load_info->MiscFlags = img_info.MiscFlags; - - res_data = NULL; - hr = S_OK; + if (load_info->pSrcInfo) + *load_info->pSrcInfo = img_info; + load_info->Usage = (load_info->Usage == D3DX10_DEFAULT) ? D3D10_USAGE_DEFAULT : load_info->Usage; + load_info->BindFlags = (load_info->BindFlags == D3DX10_DEFAULT) ? D3D10_BIND_SHADER_RESOURCE : load_info->BindFlags; + load_info->CpuAccessFlags = (load_info->CpuAccessFlags == D3DX10_DEFAULT) ? 0 : load_info->CpuAccessFlags; + load_info->MiscFlags = (load_info->MiscFlags == D3DX10_DEFAULT) ? 0 : load_info->MiscFlags; + load_info->MiscFlags |= img_info.MiscFlags; + *resource_data = sub_rsrcs; + sub_rsrcs = NULL; end: - if (dds_decoder) - IWICDdsDecoder_Release(dds_decoder); - if (dds_frame) - IWICDdsFrameDecode_Release(dds_frame); - free(res_data); - if (frame) - IWICBitmapFrameDecode_Release(frame); - if (decoder) - IWICBitmapDecoder_Release(decoder); - if (stream) - IWICStream_Release(stream); - if (factory) - IWICImagingFactory_Release(factory); + d3dx_image_cleanup(&image); + free(sub_rsrcs); return hr; } HRESULT create_d3d_texture(ID3D10Device *device, D3DX10_IMAGE_LOAD_INFO *load_info, D3D10_SUBRESOURCE_DATA *resource_data, ID3D10Resource **texture) { - D3D10_TEXTURE2D_DESC texture_2d_desc; - ID3D10Texture2D *texture_2d; HRESULT hr; - memset(&texture_2d_desc, 0, sizeof(texture_2d_desc)); - texture_2d_desc.Width = load_info->Width; - texture_2d_desc.Height = load_info->Height; - texture_2d_desc.MipLevels = load_info->MipLevels; - texture_2d_desc.ArraySize = load_info->MiscFlags & D3D10_RESOURCE_MISC_TEXTURECUBE ? 6 : 1; - texture_2d_desc.Format = load_info->Format; - texture_2d_desc.SampleDesc.Count = 1; - texture_2d_desc.Usage = load_info->Usage; - texture_2d_desc.BindFlags = load_info->BindFlags; - texture_2d_desc.MiscFlags = load_info->MiscFlags; - - if (FAILED(hr = ID3D10Device_CreateTexture2D(device, &texture_2d_desc, resource_data, &texture_2d))) - return hr; + *texture = NULL; + switch (load_info->pSrcInfo->ResourceDimension) + { + case D3D10_RESOURCE_DIMENSION_TEXTURE2D: + { + D3D10_TEXTURE2D_DESC texture_2d_desc = { 0 }; + ID3D10Texture2D *texture_2d; + + texture_2d_desc.Width = load_info->Width; + texture_2d_desc.Height = load_info->Height; + texture_2d_desc.MipLevels = load_info->MipLevels; + texture_2d_desc.ArraySize = load_info->pSrcInfo->ArraySize; + texture_2d_desc.Format = load_info->Format; + texture_2d_desc.SampleDesc.Count = 1; + texture_2d_desc.Usage = load_info->Usage; + texture_2d_desc.BindFlags = load_info->BindFlags; + texture_2d_desc.CPUAccessFlags = load_info->CpuAccessFlags; + texture_2d_desc.MiscFlags = load_info->MiscFlags; + + if (FAILED(hr = ID3D10Device_CreateTexture2D(device, &texture_2d_desc, resource_data, &texture_2d))) + return hr; + *texture = (ID3D10Resource *)texture_2d; + break; + } + + case D3D10_RESOURCE_DIMENSION_TEXTURE3D: + { + D3D10_TEXTURE3D_DESC texture_3d_desc = { 0 }; + ID3D10Texture3D *texture_3d; + + texture_3d_desc.Width = load_info->Width; + texture_3d_desc.Height = load_info->Height; + texture_3d_desc.Depth = load_info->Depth; + texture_3d_desc.MipLevels = load_info->MipLevels; + texture_3d_desc.Format = load_info->Format; + texture_3d_desc.Usage = load_info->Usage; + texture_3d_desc.BindFlags = load_info->BindFlags; + texture_3d_desc.CPUAccessFlags = load_info->CpuAccessFlags; + texture_3d_desc.MiscFlags = load_info->MiscFlags; + + if (FAILED(hr = ID3D10Device_CreateTexture3D(device, &texture_3d_desc, resource_data, &texture_3d))) + return hr; + *texture = (ID3D10Resource *)texture_3d; + break; + } + + default: + FIXME("Unhandled resource dimension %d.\n", load_info->pSrcInfo->ResourceDimension); + return E_NOTIMPL; + } - *texture = (ID3D10Resource *)texture_2d; return S_OK; } @@ -1087,3 +798,926 @@ HRESULT WINAPI D3DX10CreateTextureFromMemory(ID3D10Device *device, const void *s *hresult = hr; return hr; } + +/* + * D3DX10CreateShaderResourceView variants. + */ +HRESULT WINAPI D3DX10CreateShaderResourceViewFromFileA(ID3D10Device *device, const char *src_file, + D3DX10_IMAGE_LOAD_INFO *load_info, ID3DX10ThreadPump *pump, ID3D10ShaderResourceView **srv, HRESULT *hresult) +{ + WCHAR *buffer; + int str_len; + HRESULT hr; + + TRACE("device %p, src_file %s, load_info %p, pump %p, srv %p, hresult %p.\n", + device, debugstr_a(src_file), load_info, pump, srv, hresult); + + if (!device) + return E_INVALIDARG; + if (!src_file) + return E_FAIL; + + if (!(str_len = MultiByteToWideChar(CP_ACP, 0, src_file, -1, NULL, 0))) + return HRESULT_FROM_WIN32(GetLastError()); + + if (!(buffer = malloc(str_len * sizeof(*buffer)))) + return E_OUTOFMEMORY; + + MultiByteToWideChar(CP_ACP, 0, src_file, -1, buffer, str_len); + hr = D3DX10CreateShaderResourceViewFromFileW(device, buffer, load_info, pump, srv, hresult); + + free(buffer); + + return hr; +} + +HRESULT WINAPI D3DX10CreateShaderResourceViewFromFileW(ID3D10Device *device, const WCHAR *src_file, + D3DX10_IMAGE_LOAD_INFO *load_info, ID3DX10ThreadPump *pump, ID3D10ShaderResourceView **srv, HRESULT *hresult) +{ + ID3D10Resource *texture; + void *buffer = NULL; + DWORD size = 0; + HRESULT hr; + + TRACE("device %p, src_file %s, load_info %p, pump %p, srv %p, hresult %p.\n", + device, debugstr_w(src_file), load_info, pump, srv, hresult); + + if (!device) + return E_INVALIDARG; + if (!src_file) + return E_FAIL; + + if (pump) + { + ID3DX10DataProcessor *processor; + ID3DX10DataLoader *loader; + + if (FAILED((hr = D3DX10CreateAsyncFileLoaderW(src_file, &loader)))) + return hr; + if (FAILED((hr = D3DX10CreateAsyncShaderResourceViewProcessor(device, load_info, &processor)))) + { + ID3DX10DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX10ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)srv)))) + { + ID3DX10DataLoader_Destroy(loader); + ID3DX10DataProcessor_Destroy(processor); + } + return hr; + } + + if (SUCCEEDED((hr = load_file(src_file, &buffer, &size)))) + { + hr = create_texture(device, buffer, size, load_info, &texture); + if (SUCCEEDED(hr)) + { + hr = ID3D10Device_CreateShaderResourceView(device, texture, NULL, srv); + ID3D10Resource_Release(texture); + } + free(buffer); + } + if (hresult) + *hresult = hr; + return hr; +} + +HRESULT WINAPI D3DX10CreateShaderResourceViewFromResourceA(ID3D10Device *device, HMODULE module, const char *resource, + D3DX10_IMAGE_LOAD_INFO *load_info, ID3DX10ThreadPump *pump, ID3D10ShaderResourceView **srv, HRESULT *hresult) +{ + ID3D10Resource *texture; + void *buffer; + DWORD size; + HRESULT hr; + + TRACE("device %p, module %p, resource %s, load_info %p, pump %p, srv %p, hresult %p.\n", + device, module, debugstr_a(resource), load_info, pump, srv, hresult); + + if (!device) + return E_INVALIDARG; + + if (pump) + { + ID3DX10DataProcessor *processor; + ID3DX10DataLoader *loader; + + if (FAILED((hr = D3DX10CreateAsyncResourceLoaderA(module, resource, &loader)))) + return hr; + if (FAILED((hr = D3DX10CreateAsyncShaderResourceViewProcessor(device, load_info, &processor)))) + { + ID3DX10DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX10ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)srv)))) + { + ID3DX10DataLoader_Destroy(loader); + ID3DX10DataProcessor_Destroy(processor); + } + return hr; + } + + if (FAILED((hr = load_resourceA(module, resource, &buffer, &size)))) + return hr; + hr = create_texture(device, buffer, size, load_info, &texture); + if (SUCCEEDED(hr)) + { + hr = ID3D10Device_CreateShaderResourceView(device, texture, NULL, srv); + ID3D10Resource_Release(texture); + } + if (hresult) + *hresult = hr; + return hr; +} + +HRESULT WINAPI D3DX10CreateShaderResourceViewFromResourceW(ID3D10Device *device, HMODULE module, const WCHAR *resource, + D3DX10_IMAGE_LOAD_INFO *load_info, ID3DX10ThreadPump *pump, ID3D10ShaderResourceView **srv, HRESULT *hresult) +{ + ID3D10Resource *texture; + void *buffer; + DWORD size; + HRESULT hr; + + TRACE("device %p, module %p, resource %s, load_info %p, pump %p, srv %p, hresult %p.\n", + device, module, debugstr_w(resource), load_info, pump, srv, hresult); + + if (!device) + return E_INVALIDARG; + + if (pump) + { + ID3DX10DataProcessor *processor; + ID3DX10DataLoader *loader; + + if (FAILED((hr = D3DX10CreateAsyncResourceLoaderW(module, resource, &loader)))) + return hr; + if (FAILED((hr = D3DX10CreateAsyncShaderResourceViewProcessor(device, load_info, &processor)))) + { + ID3DX10DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX10ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)srv)))) + { + ID3DX10DataLoader_Destroy(loader); + ID3DX10DataProcessor_Destroy(processor); + } + return hr; + } + + if (FAILED((hr = load_resourceW(module, resource, &buffer, &size)))) + return hr; + hr = create_texture(device, buffer, size, load_info, &texture); + if (SUCCEEDED(hr)) + { + hr = ID3D10Device_CreateShaderResourceView(device, texture, NULL, srv); + ID3D10Resource_Release(texture); + } + if (hresult) + *hresult = hr; + return hr; +} + +HRESULT WINAPI D3DX10CreateShaderResourceViewFromMemory(ID3D10Device *device, const void *src_data, SIZE_T src_data_size, + D3DX10_IMAGE_LOAD_INFO *load_info, ID3DX10ThreadPump *pump, ID3D10ShaderResourceView **srv, HRESULT *hresult) +{ + ID3D10Resource *texture; + HRESULT hr; + + TRACE("device %p, src_data %p, src_data_size %Iu, load_info %p, pump %p, srv %p, hresult %p.\n", + device, src_data, src_data_size, load_info, pump, srv, hresult); + + if (!device) + return E_INVALIDARG; + if (!src_data) + return E_FAIL; + + if (pump) + { + ID3DX10DataProcessor *processor; + ID3DX10DataLoader *loader; + + if (FAILED((hr = D3DX10CreateAsyncMemoryLoader(src_data, src_data_size, &loader)))) + return hr; + if (FAILED((hr = D3DX10CreateAsyncShaderResourceViewProcessor(device, load_info, &processor)))) + { + ID3DX10DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX10ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)srv)))) + { + ID3DX10DataLoader_Destroy(loader); + ID3DX10DataProcessor_Destroy(processor); + } + return hr; + } + + hr = create_texture(device, src_data, src_data_size, load_info, &texture); + if (SUCCEEDED(hr)) + { + hr = ID3D10Device_CreateShaderResourceView(device, texture, NULL, srv); + ID3D10Resource_Release(texture); + } + if (hresult) + *hresult = hr; + return hr; +} + +struct d3d10_texture_resource +{ + D3D10_RESOURCE_DIMENSION texture_dimension; + union + { + ID3D10Resource *tex_rsrc; + ID3D10Texture2D *tex_2d; + ID3D10Texture3D *tex_3d; + } iface; + struct volume size; + uint32_t mip_levels; + uint32_t layer_count; +}; + +struct d3d10_texture +{ + ID3D10Device *device; + struct d3d10_texture_resource texture; + struct d3d10_texture_resource staging_texture; + + const struct pixel_format_desc *fmt_desc; + D3D10_MAP map_flags; + D3D10_BOX texture_box; + BOOL is_cubemap; + + uint32_t first_layer; + uint32_t first_mip_level; +}; + +static void set_d3d10_box(D3D10_BOX *box, uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t front, + uint32_t back) +{ + box->left = left; + box->top = top; + box->right = right; + box->bottom = bottom; + box->front = front; + box->back = back; +} + +static const char *debug_d3d10_box(const struct D3D10_BOX *box) +{ + if (!box) + return "(null)"; + return wine_dbg_sprintf("(%ux%ux%u)-(%ux%ux%u)", box->left, box->top, box->front, box->right, box->bottom, box->back); +} + +static void d3d10_box_get_mip_level(D3D10_BOX *box, uint32_t level) +{ + uint32_t i; + + for (i = 0; i < level; ++i) + { + set_d3d10_box(box, (box->left ? (box->left / 2) : 0), (box->top ? (box->top / 2) : 0), + max(box->right / 2, 1), max(box->bottom / 2, 1), + (box->front ? (box->front / 2) : 0), max(box->back / 2, 1)); + } +} + +static uint32_t d3d10_get_resource_mip_levels(ID3D10Resource *rsrc) +{ + D3D10_RESOURCE_DIMENSION rsrc_dim; + uint32_t mip_levels = 0; + HRESULT hr; + + ID3D10Resource_GetType(rsrc, &rsrc_dim); + switch (rsrc_dim) + { + case D3D10_RESOURCE_DIMENSION_TEXTURE2D: + { + D3D10_TEXTURE2D_DESC desc; + ID3D10Texture2D *tex_2d; + + hr = ID3D10Resource_QueryInterface(rsrc, &IID_ID3D10Texture2D, (void **)&tex_2d); + if (FAILED(hr)) + break; + + ID3D10Texture2D_GetDesc(tex_2d, &desc); + ID3D10Texture2D_Release(tex_2d); + mip_levels = desc.MipLevels; + break; + } + + case D3D10_RESOURCE_DIMENSION_TEXTURE3D: + { + D3D10_TEXTURE3D_DESC desc; + ID3D10Texture3D *tex_3d; + + hr = ID3D10Resource_QueryInterface(rsrc, &IID_ID3D10Texture3D, (void **)&tex_3d); + if (FAILED(hr)) + break; + + ID3D10Texture3D_GetDesc(tex_3d, &desc); + ID3D10Texture3D_Release(tex_3d); + mip_levels = desc.MipLevels; + break; + } + + default: + break; + } + + return mip_levels; +} + +static HRESULT d3dx_d3d10_texture_init(ID3D10Resource *tex_rsrc, uint32_t first_layer, uint32_t first_mip_level, + D3D10_MAP map_flags, D3D10_BOX *tex_box, struct d3d10_texture *texture) +{ + struct d3d10_texture_resource *staging_tex_rsrc = &texture->staging_texture; + struct d3d10_texture_resource *src_tex_rsrc = &texture->texture; + HRESULT hr; + + ID3D10Resource_GetDevice(tex_rsrc, &texture->device); + if (!texture->device) + { + ERR("Failed to get device from texture resource.\n"); + return E_FAIL; + } + + texture->map_flags = map_flags; + ID3D10Resource_GetType(tex_rsrc, &src_tex_rsrc->texture_dimension); + switch (src_tex_rsrc->texture_dimension) + { + case D3D10_RESOURCE_DIMENSION_TEXTURE2D: + { + D3D10_TEXTURE2D_DESC desc; + + hr = ID3D10Resource_QueryInterface(tex_rsrc, &IID_ID3D10Texture2D, (void **)&src_tex_rsrc->iface.tex_2d); + if (FAILED(hr)) + return hr; + + ID3D10Texture2D_GetDesc(src_tex_rsrc->iface.tex_2d, &desc); + if (map_flags != D3D10_MAP_READ && (first_mip_level >= desc.MipLevels)) + return S_FALSE; + + texture->fmt_desc = get_d3dx_pixel_format_info(d3dx_pixel_format_id_from_dxgi_format(desc.Format)); + if (texture->fmt_desc->format == D3DX_PIXEL_FORMAT_COUNT) + { + FIXME("Unknown DXGI format supplied, %#x.\n", desc.Format); + return E_NOTIMPL; + } + + set_volume_struct(&src_tex_rsrc->size, desc.Width, desc.Height, 1); + src_tex_rsrc->mip_levels = desc.MipLevels; + src_tex_rsrc->layer_count = desc.ArraySize; + + texture->first_mip_level = min((desc.MipLevels - 1), first_mip_level); + texture->first_layer = first_layer >= desc.ArraySize ? 0 : first_layer; + texture->is_cubemap = !!(desc.MiscFlags & D3D10_RESOURCE_MISC_TEXTURECUBE); + + staging_tex_rsrc->texture_dimension = src_tex_rsrc->texture_dimension; + staging_tex_rsrc->size = src_tex_rsrc->size; + d3dx_get_mip_level_size(&staging_tex_rsrc->size, texture->first_mip_level); + staging_tex_rsrc->mip_levels = src_tex_rsrc->mip_levels - texture->first_mip_level; + staging_tex_rsrc->layer_count = 1; + + /* Create the staging texture. */ + desc.Usage = D3D10_USAGE_STAGING; + desc.BindFlags = desc.MiscFlags = 0; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; + if (map_flags != D3D10_MAP_READ) + desc.CPUAccessFlags |= D3D10_CPU_ACCESS_WRITE; + desc.ArraySize = 1; + desc.MipLevels = staging_tex_rsrc->mip_levels; + desc.Width = staging_tex_rsrc->size.width; + desc.Height = staging_tex_rsrc->size.height; + + hr = ID3D10Device_CreateTexture2D(texture->device, &desc, NULL, &staging_tex_rsrc->iface.tex_2d); + if (FAILED(hr)) + return hr; + break; + } + + case D3D10_RESOURCE_DIMENSION_TEXTURE3D: + { + D3D10_TEXTURE3D_DESC desc; + + hr = ID3D10Resource_QueryInterface(tex_rsrc, &IID_ID3D10Texture3D, (void **)&src_tex_rsrc->iface.tex_3d); + if (FAILED(hr)) + return hr; + + ID3D10Texture3D_GetDesc(src_tex_rsrc->iface.tex_3d, &desc); + if (map_flags != D3D10_MAP_READ && (first_mip_level >= desc.MipLevels)) + return S_FALSE; + + texture->fmt_desc = get_d3dx_pixel_format_info(d3dx_pixel_format_id_from_dxgi_format(desc.Format)); + if (texture->fmt_desc->format == D3DX_PIXEL_FORMAT_COUNT) + { + FIXME("Unknown DXGI format supplied, %#x.\n", desc.Format); + return E_NOTIMPL; + } + + set_volume_struct(&src_tex_rsrc->size, desc.Width, desc.Height, desc.Depth); + src_tex_rsrc->mip_levels = desc.MipLevels; + src_tex_rsrc->layer_count = 1; + + texture->first_mip_level = min((desc.MipLevels - 1), first_mip_level); + if (first_layer) + WARN("Specified a non zero FirstElement argument on a 3D texture.\n"); + texture->first_layer = 0; + + staging_tex_rsrc->texture_dimension = src_tex_rsrc->texture_dimension; + staging_tex_rsrc->size = src_tex_rsrc->size; + d3dx_get_mip_level_size(&staging_tex_rsrc->size, texture->first_mip_level); + staging_tex_rsrc->mip_levels = src_tex_rsrc->mip_levels - texture->first_mip_level; + staging_tex_rsrc->layer_count = 1; + + /* Create the staging texture. */ + desc.Usage = D3D10_USAGE_STAGING; + desc.BindFlags = desc.MiscFlags = 0; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; + if (map_flags != D3D10_MAP_READ) + desc.CPUAccessFlags |= D3D10_CPU_ACCESS_WRITE; + desc.MipLevels = staging_tex_rsrc->mip_levels; + desc.Width = staging_tex_rsrc->size.width; + desc.Height = staging_tex_rsrc->size.height; + desc.Depth = staging_tex_rsrc->size.depth; + + hr = ID3D10Device_CreateTexture3D(texture->device, &desc, NULL, &staging_tex_rsrc->iface.tex_3d); + if (FAILED(hr)) + return hr; + break; + } + + default: + FIXME("Unhandled resource dimension %u.\n", src_tex_rsrc->texture_dimension); + return E_NOTIMPL; + } + + if (tex_box) + texture->texture_box = *tex_box; + else + set_d3d10_box(&texture->texture_box, 0, 0, staging_tex_rsrc->size.width, staging_tex_rsrc->size.height, 0, + staging_tex_rsrc->size.depth); + + return S_OK; +} + +static void d3dx_d3d10_texture_release(struct d3d10_texture *texture) +{ + if (texture->device) + ID3D10Device_Release(texture->device); + if (texture->texture.iface.tex_rsrc) + ID3D10Resource_Release(texture->texture.iface.tex_rsrc); + if (texture->staging_texture.iface.tex_rsrc) + ID3D10Resource_Release(texture->staging_texture.iface.tex_rsrc); +} + +static HRESULT d3dx_d3d10_texture_map(struct d3d10_texture *texture, uint32_t layer, uint32_t mip_level, + struct d3dx_pixels *pixels) +{ + struct d3d10_texture_resource *staging_tex_rsrc = &texture->staging_texture; + struct d3d10_texture_resource *src_tex_rsrc = &texture->texture; + uint32_t row_pitch, slice_pitch, sub_rsrc_idx; + D3D10_BOX tmp_box = texture->texture_box; + const void *data = NULL; + HRESULT hr; + + d3d10_box_get_mip_level(&tmp_box, mip_level); + sub_rsrc_idx = (src_tex_rsrc->mip_levels * (texture->first_layer + layer)) + (mip_level + texture->first_mip_level); + ID3D10Device_CopySubresourceRegion(texture->device, staging_tex_rsrc->iface.tex_rsrc, mip_level, 0, 0, 0, + src_tex_rsrc->iface.tex_rsrc, sub_rsrc_idx, NULL); + switch (src_tex_rsrc->texture_dimension) + { + case D3D10_RESOURCE_DIMENSION_TEXTURE2D: + { + D3D10_MAPPED_TEXTURE2D map = { 0 }; + + hr = ID3D10Texture2D_Map(staging_tex_rsrc->iface.tex_2d, mip_level, texture->map_flags, 0, &map); + if (FAILED(hr)) + break; + data = map.pData; + row_pitch = map.RowPitch; + slice_pitch = 0; + break; + } + + case D3D10_RESOURCE_DIMENSION_TEXTURE3D: + { + D3D10_MAPPED_TEXTURE3D map = { 0 }; + + hr = ID3D10Texture3D_Map(staging_tex_rsrc->iface.tex_3d, mip_level, texture->map_flags, 0, &map); + if (FAILED(hr)) + break; + data = map.pData; + row_pitch = map.RowPitch; + slice_pitch = map.DepthPitch; + break; + } + + default: + break; + } + + if (!data) + return E_FAIL; + + TRACE("Mapping layer %u, mip level %u, box %s.\n", texture->first_layer + layer, texture->first_mip_level + mip_level, + debug_d3d10_box(&tmp_box)); + return d3dx_pixels_init(data, row_pitch, slice_pitch, NULL, texture->fmt_desc->format, tmp_box.left, tmp_box.top, + tmp_box.right, tmp_box.bottom, tmp_box.front, tmp_box.back, pixels); +} + +static void d3dx_d3d10_texture_unmap(struct d3d10_texture *texture, uint32_t layer, uint32_t mip_level) +{ + struct d3d10_texture_resource *staging_tex_rsrc = &texture->staging_texture; + struct d3d10_texture_resource *src_tex_rsrc = &texture->texture; + uint32_t sub_rsrc_idx; + + switch (src_tex_rsrc->texture_dimension) + { + case D3D10_RESOURCE_DIMENSION_TEXTURE2D: + { + ID3D10Texture2D_Unmap(staging_tex_rsrc->iface.tex_2d, mip_level); + break; + } + + case D3D10_RESOURCE_DIMENSION_TEXTURE3D: + { + ID3D10Texture3D_Unmap(staging_tex_rsrc->iface.tex_3d, mip_level); + break; + } + + default: + break; + } + + if (texture->map_flags == D3D10_MAP_READ) + return; + + sub_rsrc_idx = (src_tex_rsrc->mip_levels * (texture->first_layer + layer)) + (mip_level + texture->first_mip_level); + ID3D10Device_CopySubresourceRegion(texture->device, src_tex_rsrc->iface.tex_rsrc, sub_rsrc_idx, 0, 0, 0, + staging_tex_rsrc->iface.tex_rsrc, mip_level, NULL); +} + +static const D3DX10_TEXTURE_LOAD_INFO default_load_info = { NULL, NULL, 0, 0, D3DX10_DEFAULT, 0, 0, D3DX10_DEFAULT, + D3DX10_DEFAULT, D3DX10_DEFAULT }; +HRESULT WINAPI D3DX10LoadTextureFromTexture(ID3D10Resource *src_texture, D3DX10_TEXTURE_LOAD_INFO *load_info, + ID3D10Resource *dst_texture) +{ + D3DX10_TEXTURE_LOAD_INFO info = (load_info) ? *load_info : default_load_info; + struct d3d10_texture src_tex = { 0 }; + struct d3d10_texture dst_tex = { 0 }; + uint32_t i, j, loaded_mip_levels; + HRESULT hr; + + TRACE("src_texture %p, load_info %p, dst_texture %p.\n", src_texture, load_info, dst_texture); + + if (!src_texture || !dst_texture) + return E_INVALIDARG; + + if (!info.Filter || FAILED(hr = d3dx_handle_filter(&info.Filter))) + { + ERR("Invalid filter argument %#x.\n", info.Filter); + return D3DERR_INVALIDCALL; + } + + hr = d3dx_d3d10_texture_init(src_texture, info.SrcFirstElement, info.SrcFirstMip, D3D10_MAP_READ, info.pSrcBox, &src_tex); + if (FAILED(hr)) + goto end; + + hr = d3dx_d3d10_texture_init(dst_texture, info.DstFirstElement, info.DstFirstMip, D3D10_MAP_READ_WRITE, info.pDstBox, &dst_tex); + if (hr == S_FALSE || FAILED(hr)) + goto end; + + if ((src_texture == dst_texture) && ((src_tex.first_layer == dst_tex.first_layer) && + (src_tex.first_mip_level == dst_tex.first_mip_level))) + { + hr = D3DERR_INVALIDCALL; + goto end; + } + + if (!info.NumMips || info.NumMips == D3DX10_DEFAULT) + info.NumMips = dst_tex.staging_texture.mip_levels; + info.NumMips = min(info.NumMips, dst_tex.staging_texture.mip_levels); + if (!info.NumElements || info.NumElements == D3DX10_DEFAULT) + info.NumElements = min(src_tex.texture.layer_count, dst_tex.texture.layer_count); + info.NumElements = min(info.NumElements, min(src_tex.texture.layer_count, dst_tex.texture.layer_count)); + loaded_mip_levels = min(info.NumMips, src_tex.staging_texture.mip_levels); + for (i = 0; i < info.NumElements; ++i) + { + for (j = 0; j < loaded_mip_levels; ++j) + { + struct d3dx_pixels src_pixels, dst_pixels; + + hr = d3dx_d3d10_texture_map(&src_tex, i, j, &src_pixels); + if (FAILED(hr)) + goto end; + + hr = d3dx_d3d10_texture_map(&dst_tex, i, j, &dst_pixels); + if (FAILED(hr)) + { + d3dx_d3d10_texture_unmap(&src_tex, i, j); + goto end; + } + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_tex.fmt_desc, &src_pixels, src_tex.fmt_desc, info.Filter, 0); + d3dx_d3d10_texture_unmap(&src_tex, i, j); + d3dx_d3d10_texture_unmap(&dst_tex, i, j); + if (FAILED(hr)) + { + WARN("Failed with hr %#lx.\n", hr); + goto end; + } + } + } + + if (loaded_mip_levels < info.NumMips) + { + if (!info.MipFilter || FAILED(hr = d3dx_handle_filter(&info.MipFilter))) + { + ERR("Invalid mip filter argument %#x.\n", info.MipFilter); + hr = D3DERR_INVALIDCALL; + goto end; + } + + for (i = 0; i < info.NumElements; ++i) + { + for (j = loaded_mip_levels; j < info.NumMips; ++j) + { + struct d3dx_pixels src_pixels, dst_pixels; + + hr = d3dx_d3d10_texture_map(&dst_tex, i, j - 1, &src_pixels); + if (FAILED(hr)) + break; + + hr = d3dx_d3d10_texture_map(&dst_tex, i, j, &dst_pixels); + if (SUCCEEDED(hr)) + { + hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_tex.fmt_desc, &src_pixels, dst_tex.fmt_desc, info.MipFilter, 0); + d3dx_d3d10_texture_unmap(&dst_tex, i, j); + } + d3dx_d3d10_texture_unmap(&dst_tex, i, j - 1); + if (FAILED(hr)) + goto end; + } + } + } + +end: + d3dx_d3d10_texture_release(&src_tex); + d3dx_d3d10_texture_release(&dst_tex); + return SUCCEEDED(hr) ? S_OK : hr; +} + +HRESULT WINAPI D3DX10FilterTexture(ID3D10Resource *texture, UINT src_level, UINT filter) +{ + D3DX10_TEXTURE_LOAD_INFO load_info = { NULL, NULL, src_level, src_level + 1, 0, 0, 0, 0, filter, filter }; + + TRACE("texture %p, src_level %u, filter %#x.\n", texture, src_level, filter); + + if (d3d10_get_resource_mip_levels(texture) <= src_level) + return S_OK; + + return D3DX10LoadTextureFromTexture(texture, &load_info, texture); +} + +HRESULT WINAPI D3DX10SaveTextureToFileW(ID3D10Resource *texture, D3DX10_IMAGE_FILE_FORMAT format, const WCHAR *filename) +{ + ID3D10Blob *buffer; + HRESULT hr; + + TRACE("texture %p, format %u, filename %s stub!\n", texture, format, debugstr_w(filename)); + + if (!filename) + return E_FAIL; + + hr = D3DX10SaveTextureToMemory(texture, format, &buffer, 0); + if (SUCCEEDED(hr)) + { + hr = write_buffer_to_file(filename, buffer); + ID3D10Blob_Release(buffer); + } + + return hr; +} + +HRESULT WINAPI D3DX10SaveTextureToFileA(ID3D10Resource *texture, D3DX10_IMAGE_FILE_FORMAT format, const char *filename) +{ + WCHAR *buffer; + int str_len; + HRESULT hr; + + TRACE("texture %p, format %u, filename %s.\n", texture, format, debugstr_a(filename)); + + if (!filename) + return E_FAIL; + + str_len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0); + if (!str_len) + return HRESULT_FROM_WIN32(GetLastError()); + + buffer = malloc(str_len * sizeof(*buffer)); + if (!buffer) + return E_OUTOFMEMORY; + + MultiByteToWideChar(CP_ACP, 0, filename, -1, buffer, str_len); + hr = D3DX10SaveTextureToFileW(texture, format, buffer); + free(buffer); + return hr; +} + +static HRESULT d3dx10_get_save_format_for_file_format(D3DX10_IMAGE_FILE_FORMAT iff, enum d3dx_pixel_format_id src_fmt, + enum d3dx_pixel_format_id *save_fmt) +{ + *save_fmt = D3DX_PIXEL_FORMAT_COUNT; + switch (iff) + { + case D3DX10_IFF_JPG: + switch (src_fmt) + { + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM: + case D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT: + case D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT: + *save_fmt = D3DX_PIXEL_FORMAT_B8G8R8_UNORM; + break; + + case D3DX_PIXEL_FORMAT_R16_UNORM: + *save_fmt = D3DX_PIXEL_FORMAT_L8_UNORM; + break; + + default: + return E_FAIL; + } + break; + + case D3DX10_IFF_PNG: + case D3DX10_IFF_TIFF: + switch (src_fmt) + { + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM: + *save_fmt = D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; + break; + + case D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT: + case D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT: + *save_fmt = D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM; + break; + + case D3DX_PIXEL_FORMAT_R16_UNORM: + *save_fmt = D3DX_PIXEL_FORMAT_L16_UNORM; + break; + + default: + return E_FAIL; + } + break; + + case D3DX10_IFF_BMP: + switch (src_fmt) + { + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM: + *save_fmt = D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM; + break; + + case D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT: + case D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT: + case D3DX_PIXEL_FORMAT_R16_UNORM: + FIXME("Encoding of BMP files to WICPixelFormat64bppRGBAFixedPoint unimplemented, using default instead.\n"); + *save_fmt = D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM; + break; + + default: + return E_FAIL; + } + break; + + case D3DX10_IFF_WMP: + FIXME("Saving to WMP is currently unimplemented.\n"); + return E_NOTIMPL; + + default: + assert(0); + break; + } + + return S_OK; +} + +HRESULT WINAPI D3DX10SaveTextureToMemory(ID3D10Resource *texture, D3DX10_IMAGE_FILE_FORMAT format, ID3D10Blob **buffer, + UINT flags) +{ + const struct pixel_format_desc *fmt_desc = NULL; + struct d3d10_texture src_tex = { 0 }; + enum d3dx_resource_type d3dx_rtype; + D3D10_RESOURCE_DIMENSION rsrc_dim; + struct d3dx_image image = { 0 }; + ID3D10Blob *out_buffer; + unsigned int i, j; + HRESULT hr; + + TRACE("texture %p, format %u, buffer %p, flags %#x.\n", texture, format, buffer, flags); + + if (!texture || !buffer || format == D3DX10_IFF_GIF) + return E_INVALIDARG; + + out_buffer = *buffer = NULL; + if (format == D3DX10_IFF_WMP) + { + FIXME("Saving to file format %u is currently unimplemented.\n", format); + return E_NOTIMPL; + } + + ID3D10Resource_GetType(texture, &rsrc_dim); + switch (rsrc_dim) + { + case D3D10_RESOURCE_DIMENSION_TEXTURE2D: + d3dx_rtype = D3DX_RESOURCE_TYPE_TEXTURE_2D; + break; + + case D3D10_RESOURCE_DIMENSION_TEXTURE3D: + d3dx_rtype = D3DX_RESOURCE_TYPE_TEXTURE_3D; + break; + + default: + FIXME("Currently only 2D and 3D texture saving is supported.\n"); + return E_NOTIMPL; + } + + if (format != D3DX10_IFF_DDS && rsrc_dim != D3D10_RESOURCE_DIMENSION_TEXTURE2D) + return E_INVALIDARG; + + hr = d3dx_d3d10_texture_init(texture, 0, 0, D3D10_MAP_READ, NULL, &src_tex); + if (FAILED(hr)) + return hr; + + if (format != D3DX10_IFF_DDS) + { + enum d3dx_pixel_format_id dst_format; + struct d3dx_pixels src_pixels; + + hr = d3dx10_get_save_format_for_file_format(format, src_tex.fmt_desc->format, &dst_format); + if (FAILED(hr)) + goto exit; + + hr = d3dx_d3d10_texture_map(&src_tex, 0, 0, &src_pixels); + if (FAILED(hr)) + goto exit; + + hr = d3dx_save_pixels_to_memory(&src_pixels, src_tex.fmt_desc, (enum d3dx_image_file_format)format, dst_format, + &out_buffer); + d3dx_d3d10_texture_unmap(&src_tex, 0, 0); + if (SUCCEEDED(hr)) + *buffer = out_buffer; + else + WARN("Failed with hr %#lx.\n", hr); + + goto exit; + } + + if (src_tex.is_cubemap) + d3dx_rtype = D3DX_RESOURCE_TYPE_CUBE_TEXTURE; + + hr = d3dx_create_dds_file_blob(src_tex.fmt_desc->format, NULL, d3dx_rtype, &src_tex.texture.size, + src_tex.texture.mip_levels, src_tex.texture.layer_count, TRUE, &out_buffer); + if (FAILED(hr)) + { + FIXME("Failed to create dds file with hr %#lx.\n", hr); + goto exit; + } + + hr = d3dx_image_init(ID3D10Blob_GetBufferPointer(out_buffer), ID3D10Blob_GetBufferSize(out_buffer), &image, 0, + D3DX_IMAGE_SUPPORT_DXT10); + if (FAILED(hr)) + goto exit; + + fmt_desc = get_d3dx_pixel_format_info(image.format); + for (i = 0; i < image.layer_count; ++i) + { + for (j = 0; j < image.mip_levels; ++j) + { + struct d3dx_pixels src_pixels, dst_pixels; + + hr = d3dx_image_get_pixels(&image, i, j, &dst_pixels); + if (FAILED(hr)) + goto exit; + + hr = d3dx_d3d10_texture_map(&src_tex, i, j, &src_pixels); + if (FAILED(hr)) + goto exit; + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, src_tex.fmt_desc, D3DX_FILTER_NONE, 0); + d3dx_d3d10_texture_unmap(&src_tex, i, j); + if (FAILED(hr)) + { + WARN("Failed with hr %#lx.\n", hr); + goto exit; + } + } + } + + if (SUCCEEDED(hr)) + *buffer = out_buffer; + +exit: + if (out_buffer && *buffer != out_buffer) + ID3D10Blob_Release(out_buffer); + d3dx_d3d10_texture_release(&src_tex); + return SUCCEEDED(hr) ? S_OK : hr; +} diff --git a/dlls/d3dx11_42/Makefile.in b/dlls/d3dx11_42/Makefile.in index 985fc1c59c27..c833ce178184 100644 --- a/dlls/d3dx11_42/Makefile.in +++ b/dlls/d3dx11_42/Makefile.in @@ -1,13 +1,10 @@ EXTRADEFS = -DD3DX11_SDK_VERSION=42 MODULE = d3dx11_42.dll IMPORTLIB = d3dx11_42 -IMPORTS = d3dcompiler -PARENTSRC = ../d3dx11_43 +IMPORTS = d3dcompiler d3dx11 EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ - async.c \ - main.c \ - texture.c \ + d3dx11_42_main.c \ version.rc diff --git a/dlls/d3dx11_42/d3dx11_42.spec b/dlls/d3dx11_42/d3dx11_42.spec index 2d93b8d760ab..c7bc2e30778b 100644 --- a/dlls/d3dx11_42/d3dx11_42.spec +++ b/dlls/d3dx11_42/d3dx11_42.spec @@ -1,44 +1,44 @@ @ stdcall D3DX11CheckVersion(long long) -@ stdcall D3DX11CompileFromFileA(str ptr ptr str str long long ptr ptr ptr ptr) -@ stdcall D3DX11CompileFromFileW(wstr ptr ptr str str long long ptr ptr ptr ptr) -@ stdcall D3DX11CompileFromMemory(ptr long str ptr ptr str str long long ptr ptr ptr ptr) +@ stdcall -import D3DX11CompileFromFileA(str ptr ptr str str long long ptr ptr ptr ptr) +@ stdcall -import D3DX11CompileFromFileW(wstr ptr ptr str str long long ptr ptr ptr ptr) +@ stdcall -import D3DX11CompileFromMemory(ptr long str ptr ptr str str long long ptr ptr ptr ptr) @ stub D3DX11CompileFromResourceA @ stub D3DX11CompileFromResourceW @ stub D3DX11ComputeNormalMap @ stub D3DX11CreateAsyncCompilerProcessor -@ stdcall D3DX11CreateAsyncFileLoaderA(str ptr) -@ stdcall D3DX11CreateAsyncFileLoaderW(wstr ptr) -@ stdcall D3DX11CreateAsyncMemoryLoader(ptr long ptr) -@ stdcall D3DX11CreateAsyncResourceLoaderA(long str ptr) -@ stdcall D3DX11CreateAsyncResourceLoaderW(long wstr ptr) +@ stdcall -import D3DX11CreateAsyncFileLoaderA(str ptr) +@ stdcall -import D3DX11CreateAsyncFileLoaderW(wstr ptr) +@ stdcall -import D3DX11CreateAsyncMemoryLoader(ptr long ptr) +@ stdcall -import D3DX11CreateAsyncResourceLoaderA(long str ptr) +@ stdcall -import D3DX11CreateAsyncResourceLoaderW(long wstr ptr) @ stub D3DX11CreateAsyncShaderPreprocessProcessor -@ stub D3DX11CreateAsyncShaderResourceViewProcessor -@ stub D3DX11CreateAsyncTextureInfoProcessor -@ stub D3DX11CreateAsyncTextureProcessor -@ stub D3DX11CreateShaderResourceViewFromFileA -@ stub D3DX11CreateShaderResourceViewFromFileW -@ stdcall D3DX11CreateShaderResourceViewFromMemory(ptr ptr long ptr ptr ptr ptr) -@ stub D3DX11CreateShaderResourceViewFromResourceA -@ stub D3DX11CreateShaderResourceViewFromResourceW -@ stdcall D3DX11CreateTextureFromFileA(ptr str ptr ptr ptr ptr) -@ stdcall D3DX11CreateTextureFromFileW(ptr wstr ptr ptr ptr ptr) -@ stdcall D3DX11CreateTextureFromMemory(ptr ptr long ptr ptr ptr ptr) -@ stub D3DX11CreateTextureFromResourceA -@ stub D3DX11CreateTextureFromResourceW -@ stub D3DX11CreateThreadPump -@ stdcall D3DX11FilterTexture(ptr ptr long long) -@ stdcall D3DX11GetImageInfoFromFileA(str ptr ptr ptr) -@ stdcall D3DX11GetImageInfoFromFileW(wstr ptr ptr ptr) -@ stdcall D3DX11GetImageInfoFromMemory(ptr long ptr ptr ptr) -@ stub D3DX11GetImageInfoFromResourceA -@ stub D3DX11GetImageInfoFromResourceW -@ stdcall D3DX11LoadTextureFromTexture(ptr ptr ptr ptr) +@ stdcall -import D3DX11CreateAsyncShaderResourceViewProcessor(ptr ptr ptr) +@ stdcall -import D3DX11CreateAsyncTextureInfoProcessor(ptr ptr) +@ stdcall -import D3DX11CreateAsyncTextureProcessor(ptr ptr ptr) +@ stdcall -import D3DX11CreateShaderResourceViewFromFileA(ptr str ptr ptr ptr ptr) +@ stdcall -import D3DX11CreateShaderResourceViewFromFileW(ptr wstr ptr ptr ptr ptr) +@ stdcall -import D3DX11CreateShaderResourceViewFromMemory(ptr ptr long ptr ptr ptr ptr) +@ stdcall -import D3DX11CreateShaderResourceViewFromResourceA(ptr long str ptr ptr ptr ptr) +@ stdcall -import D3DX11CreateShaderResourceViewFromResourceW(ptr long wstr ptr ptr ptr ptr) +@ stdcall -import D3DX11CreateTextureFromFileA(ptr str ptr ptr ptr ptr) +@ stdcall -import D3DX11CreateTextureFromFileW(ptr wstr ptr ptr ptr ptr) +@ stdcall -import D3DX11CreateTextureFromMemory(ptr ptr long ptr ptr ptr ptr) +@ stdcall -import D3DX11CreateTextureFromResourceA(ptr long str ptr ptr ptr ptr) +@ stdcall -import D3DX11CreateTextureFromResourceW(ptr long wstr ptr ptr ptr ptr) +@ stdcall -import D3DX11CreateThreadPump(long long ptr) +@ stdcall -import D3DX11FilterTexture(ptr ptr long long) +@ stdcall -import D3DX11GetImageInfoFromFileA(str ptr ptr ptr) +@ stdcall -import D3DX11GetImageInfoFromFileW(wstr ptr ptr ptr) +@ stdcall -import D3DX11GetImageInfoFromMemory(ptr long ptr ptr ptr) +@ stdcall -import D3DX11GetImageInfoFromResourceA(long str ptr ptr ptr) +@ stdcall -import D3DX11GetImageInfoFromResourceW(long wstr ptr ptr ptr) +@ stdcall -import D3DX11LoadTextureFromTexture(ptr ptr ptr ptr) @ stub D3DX11PreprocessShaderFromFileA @ stub D3DX11PreprocessShaderFromFileW @ stub D3DX11PreprocessShaderFromMemory @ stub D3DX11PreprocessShaderFromResourceA @ stub D3DX11PreprocessShaderFromResourceW @ stub D3DX11SHProjectCubeMap -@ stdcall D3DX11SaveTextureToFileA(ptr ptr long str) -@ stdcall D3DX11SaveTextureToFileW(ptr ptr long wstr) -@ stdcall D3DX11SaveTextureToMemory(ptr ptr long ptr long) +@ stdcall -import D3DX11SaveTextureToFileA(ptr ptr long str) +@ stdcall -import D3DX11SaveTextureToFileW(ptr ptr long wstr) +@ stdcall -import D3DX11SaveTextureToMemory(ptr ptr long ptr long) diff --git a/dlls/d3dx11_42/d3dx11_42_main.c b/dlls/d3dx11_42/d3dx11_42_main.c new file mode 100644 index 000000000000..2ac4f8837992 --- /dev/null +++ b/dlls/d3dx11_42/d3dx11_42_main.c @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Connor McAdams for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "d3dx11.h" +#include "d3dx11core.h" +#include "d3dx11tex.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3dx); + +BOOL WINAPI D3DX11CheckVersion(UINT d3d_sdk_ver, UINT d3dx_sdk_ver) +{ + TRACE("d3d_sdk_ver %u, d3dx_sdk_ver %u.\n", d3d_sdk_ver, d3dx_sdk_ver); + + return d3d_sdk_ver == D3D11_SDK_VERSION && d3dx_sdk_ver == D3DX11_SDK_VERSION; +} + diff --git a/dlls/d3dx11_42/tests/Makefile.in b/dlls/d3dx11_42/tests/Makefile.in index f18be76d9d5d..277099fb873b 100644 --- a/dlls/d3dx11_42/tests/Makefile.in +++ b/dlls/d3dx11_42/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = d3dx11_42.dll -IMPORTS = d3dx11_42 +IMPORTS = d3dx11_42 ole32 gdi32 PARENTSRC = ../../d3dx11_43/tests SOURCES = \ diff --git a/dlls/d3dx11_43/Makefile.in b/dlls/d3dx11_43/Makefile.in index 762987a89adc..be0a311305e3 100644 --- a/dlls/d3dx11_43/Makefile.in +++ b/dlls/d3dx11_43/Makefile.in @@ -1,12 +1,15 @@ -EXTRADEFS = -DD3DX11_SDK_VERSION=43 +EXTRADEFS = -DD3DX11_SDK_VERSION=43 -DD3DX_D3D_VERSION=11 MODULE = d3dx11_43.dll IMPORTLIB = d3dx11 -IMPORTS = d3dcompiler +IMPORTS = d3dcompiler ole32 +PARENTSRC = ../d3dx9_36 +DELAYIMPORTS = windowscodecs EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ async.c \ - main.c \ + d3dx_helpers.c \ + d3dx11_43_main.c \ texture.c \ version.rc diff --git a/dlls/d3dx11_43/async.c b/dlls/d3dx11_43/async.c index 074a8529e4ef..776a5c806922 100644 --- a/dlls/d3dx11_43/async.c +++ b/dlls/d3dx11_43/async.c @@ -16,10 +16,14 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define COBJMACROS #include "d3dx11.h" #include "d3dcompiler.h" +#include "dxhelpers.h" +#include "winternl.h" #include "wine/debug.h" +#include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL(d3dx); @@ -40,7 +44,7 @@ struct asyncdataloader } resource; } u; void *data; - SIZE_T size; + DWORD size; }; static inline struct asyncdataloader *impl_from_ID3DX11DataLoader(ID3DX11DataLoader *iface) @@ -86,35 +90,15 @@ static const ID3DX11DataLoaderVtbl memorydataloadervtbl = static HRESULT WINAPI filedataloader_Load(ID3DX11DataLoader *iface) { struct asyncdataloader *loader = impl_from_ID3DX11DataLoader(iface); - DWORD size, read_len; - HANDLE file; void *data; - BOOL ret; + DWORD size; + HRESULT hr; TRACE("iface %p.\n", iface); /* Always buffer file contents, even if Load() was already called. */ - file = CreateFileW(loader->u.file.path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (file == INVALID_HANDLE_VALUE) - return D3D11_ERROR_FILE_NOT_FOUND; - - size = GetFileSize(file, NULL); - data = malloc(size); - if (!data) - { - CloseHandle(file); - return E_OUTOFMEMORY; - } - - ret = ReadFile(file, data, size, &read_len, NULL); - CloseHandle(file); - if (!ret) - { - ERR("Failed to read file contents.\n"); - free(data); - return E_FAIL; - } + if (FAILED((hr = load_file(loader->u.file.path, &data, &size)))) + return hr; free(loader->data); loader->data = data; @@ -161,24 +145,14 @@ static const ID3DX11DataLoaderVtbl filedataloadervtbl = static HRESULT WINAPI resourcedataloader_Load(ID3DX11DataLoader *iface) { struct asyncdataloader *loader = impl_from_ID3DX11DataLoader(iface); - HGLOBAL hglobal; TRACE("iface %p.\n", iface); if (loader->data) return S_OK; - hglobal = LoadResource(loader->u.resource.module, loader->u.resource.rsrc); - if (!hglobal) - { - ERR("Failed to load resource.\n"); - return E_FAIL; - } - - loader->data = LockResource(hglobal); - loader->size = SizeofResource(loader->u.resource.module, loader->u.resource.rsrc); - - return S_OK; + return load_resource(loader->u.resource.module, loader->u.resource.rsrc, + &loader->data, &loader->size); } static HRESULT WINAPI resourcedataloader_Decompress(ID3DX11DataLoader *iface, void **data, SIZE_T *size) @@ -214,6 +188,166 @@ static const ID3DX11DataLoaderVtbl resourcedataloadervtbl = resourcedataloader_Destroy }; +struct texture_info_processor +{ + ID3DX11DataProcessor ID3DX11DataProcessor_iface; + D3DX11_IMAGE_INFO *info; +}; + +static inline struct texture_info_processor *impl_from_ID3DX11DataProcessor(ID3DX11DataProcessor *iface) +{ + return CONTAINING_RECORD(iface, struct texture_info_processor, ID3DX11DataProcessor_iface); +} + +static HRESULT WINAPI texture_info_processor_Process(ID3DX11DataProcessor *iface, void *data, SIZE_T size) +{ + struct texture_info_processor *processor = impl_from_ID3DX11DataProcessor(iface); + + TRACE("iface %p, data %p, size %Iu.\n", iface, data, size); + return get_image_info(data, size, processor->info); +} + +static HRESULT WINAPI texture_info_processor_CreateDeviceObject(ID3DX11DataProcessor *iface, void **object) +{ + TRACE("iface %p, object %p.\n", iface, object); + return S_OK; +} + +static HRESULT WINAPI texture_info_processor_Destroy(ID3DX11DataProcessor *iface) +{ + struct texture_info_processor *processor = impl_from_ID3DX11DataProcessor(iface); + + TRACE("iface %p.\n", iface); + + free(processor); + return S_OK; +} + +static ID3DX11DataProcessorVtbl texture_info_processor_vtbl = +{ + texture_info_processor_Process, + texture_info_processor_CreateDeviceObject, + texture_info_processor_Destroy +}; + +struct texture_processor +{ + ID3DX11DataProcessor ID3DX11DataProcessor_iface; + ID3D11Device *device; + D3DX11_IMAGE_INFO img_info; + D3DX11_IMAGE_LOAD_INFO load_info; + D3D11_SUBRESOURCE_DATA *resource_data; +}; + +static inline struct texture_processor *texture_processor_from_ID3DX11DataProcessor(ID3DX11DataProcessor *iface) +{ + return CONTAINING_RECORD(iface, struct texture_processor, ID3DX11DataProcessor_iface); +} + +static HRESULT WINAPI texture_processor_Process(ID3DX11DataProcessor *iface, void *data, SIZE_T size) +{ + struct texture_processor *processor = texture_processor_from_ID3DX11DataProcessor(iface); + + TRACE("iface %p, data %p, size %Iu.\n", iface, data, size); + + if (processor->resource_data) + { + WARN("Called multiple times.\n"); + free(processor->resource_data); + processor->resource_data = NULL; + } + return load_texture_data(data, size, &processor->load_info, &processor->resource_data); +} + +static HRESULT WINAPI texture_processor_CreateDeviceObject(ID3DX11DataProcessor *iface, void **object) +{ + struct texture_processor *processor = texture_processor_from_ID3DX11DataProcessor(iface); + + TRACE("iface %p, object %p.\n", iface, object); + + if (!processor->resource_data) + return E_FAIL; + + return create_d3d_texture(processor->device, &processor->load_info, + processor->resource_data, (ID3D11Resource **)object); +} + +static HRESULT WINAPI texture_processor_Destroy(ID3DX11DataProcessor *iface) +{ + struct texture_processor *processor = texture_processor_from_ID3DX11DataProcessor(iface); + + TRACE("iface %p.\n", iface); + + ID3D11Device_Release(processor->device); + free(processor->resource_data); + free(processor); + return S_OK; +} + +static ID3DX11DataProcessorVtbl texture_processor_vtbl = +{ + texture_processor_Process, + texture_processor_CreateDeviceObject, + texture_processor_Destroy +}; + +struct srv_processor +{ + ID3DX11DataProcessor ID3DX11DataProcessor_iface; + ID3DX11DataProcessor *texture_processor; +}; + +static inline struct srv_processor *srv_processor_from_ID3DX11DataProcessor(ID3DX11DataProcessor *iface) +{ + return CONTAINING_RECORD(iface, struct srv_processor, ID3DX11DataProcessor_iface); +} + +static HRESULT WINAPI srv_processor_Process(ID3DX11DataProcessor *iface, void *data, SIZE_T size) +{ + struct srv_processor *processor = srv_processor_from_ID3DX11DataProcessor(iface); + + TRACE("iface %p, data %p, size %Iu.\n", iface, data, size); + + return ID3DX11DataProcessor_Process(processor->texture_processor, data, size); +} + +static HRESULT WINAPI srv_processor_CreateDeviceObject(ID3DX11DataProcessor *iface, void **object) +{ + struct srv_processor *processor = srv_processor_from_ID3DX11DataProcessor(iface); + struct texture_processor *tex_processor = texture_processor_from_ID3DX11DataProcessor(processor->texture_processor); + ID3D11Resource *texture_resource; + HRESULT hr; + + TRACE("iface %p, object %p.\n", iface, object); + + hr = ID3DX11DataProcessor_CreateDeviceObject(processor->texture_processor, (void **)&texture_resource); + if (FAILED(hr)) + return hr; + + hr = ID3D11Device_CreateShaderResourceView(tex_processor->device, texture_resource, NULL, + (ID3D11ShaderResourceView **)object); + ID3D11Resource_Release(texture_resource); + return hr; +} + +static HRESULT WINAPI srv_processor_Destroy(ID3DX11DataProcessor *iface) +{ + struct srv_processor *processor = srv_processor_from_ID3DX11DataProcessor(iface); + + TRACE("iface %p.\n", iface); + + ID3DX11DataProcessor_Destroy(processor->texture_processor); + free(processor); + return S_OK; +} + +static ID3DX11DataProcessorVtbl srv_processor_vtbl = +{ + srv_processor_Process, + srv_processor_CreateDeviceObject, + srv_processor_Destroy +}; + HRESULT WINAPI D3DX11CompileFromMemory(const char *data, SIZE_T data_size, const char *filename, const D3D10_SHADER_MACRO *defines, ID3D10Include *include, const char *entry_point, const char *target, UINT sflags, UINT eflags, ID3DX11ThreadPump *pump, ID3D10Blob **shader, @@ -350,6 +484,7 @@ HRESULT WINAPI D3DX11CreateAsyncResourceLoaderA(HMODULE module, const char *reso { struct asyncdataloader *object; HRSRC rsrc; + HRESULT hr; TRACE("module %p, resource %s, loader %p.\n", module, debugstr_a(resource), loader); @@ -360,11 +495,10 @@ HRESULT WINAPI D3DX11CreateAsyncResourceLoaderA(HMODULE module, const char *reso if (!object) return E_OUTOFMEMORY; - if (!(rsrc = FindResourceA(module, resource, (const char *)RT_RCDATA))) + if (FAILED((hr = load_resource_initA(module, resource, &rsrc)))) { - WARN("Failed to find resource.\n"); free(object); - return D3DX11_ERR_INVALID_DATA; + return hr; } object->ID3DX11DataLoader_iface.lpVtbl = &resourcedataloadervtbl; @@ -382,6 +516,7 @@ HRESULT WINAPI D3DX11CreateAsyncResourceLoaderW(HMODULE module, const WCHAR *res { struct asyncdataloader *object; HRSRC rsrc; + HRESULT hr; TRACE("module %p, resource %s, loader %p.\n", module, debugstr_w(resource), loader); @@ -392,11 +527,10 @@ HRESULT WINAPI D3DX11CreateAsyncResourceLoaderW(HMODULE module, const WCHAR *res if (!object) return E_OUTOFMEMORY; - if (!(rsrc = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA))) + if (FAILED((hr = load_resource_initW(module, resource, &rsrc)))) { - WARN("Failed to find resource.\n"); free(object); - return D3DX11_ERR_INVALID_DATA; + return hr; } object->ID3DX11DataLoader_iface.lpVtbl = &resourcedataloadervtbl; @@ -409,3 +543,554 @@ HRESULT WINAPI D3DX11CreateAsyncResourceLoaderW(HMODULE module, const WCHAR *res return S_OK; } + +HRESULT WINAPI D3DX11CreateAsyncTextureInfoProcessor(D3DX11_IMAGE_INFO *info, ID3DX11DataProcessor **processor) +{ + struct texture_info_processor *object; + + TRACE("info %p, processor %p.\n", info, processor); + + if (!processor) + return E_INVALIDARG; + + object = malloc(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->ID3DX11DataProcessor_iface.lpVtbl = &texture_info_processor_vtbl; + object->info = info; + + *processor = &object->ID3DX11DataProcessor_iface; + return S_OK; +} + +HRESULT WINAPI D3DX11CreateAsyncTextureProcessor(ID3D11Device *device, + D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11DataProcessor **processor) +{ + struct texture_processor *object; + + TRACE("device %p, load_info %p, processor %p.\n", device, load_info, processor); + + if (!device || !processor) + return E_INVALIDARG; + + object = calloc(1, sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->ID3DX11DataProcessor_iface.lpVtbl = &texture_processor_vtbl; + object->device = device; + ID3D11Device_AddRef(device); + init_load_info(load_info, &object->load_info); + if (!object->load_info.pSrcInfo) + object->load_info.pSrcInfo = &object->img_info; + + *processor = &object->ID3DX11DataProcessor_iface; + return S_OK; +} + +HRESULT WINAPI D3DX11CreateAsyncShaderResourceViewProcessor(ID3D11Device *device, + D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11DataProcessor **processor) +{ + struct srv_processor *object; + HRESULT hr; + + TRACE("device %p, load_info %p, processor %p.\n", device, load_info, processor); + + if (!device || !processor) + return E_INVALIDARG; + + object = calloc(1, sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + hr = D3DX11CreateAsyncTextureProcessor(device, load_info, &object->texture_processor); + if (FAILED(hr)) + { + free(object); + return hr; + } + object->ID3DX11DataProcessor_iface.lpVtbl = &srv_processor_vtbl; + *processor = &object->ID3DX11DataProcessor_iface; + return S_OK; +} + +struct work_item +{ + struct list entry; + + ID3DX11DataLoader *loader; + ID3DX11DataProcessor *processor; + HRESULT *result; + void **object; +}; + +static inline void work_item_free(struct work_item *work_item, BOOL cancel) +{ + ID3DX11DataLoader_Destroy(work_item->loader); + ID3DX11DataProcessor_Destroy(work_item->processor); + if (cancel && work_item->result) + *work_item->result = S_FALSE; + free(work_item); +} + +#define THREAD_PUMP_EXITING UINT_MAX +struct thread_pump +{ + ID3DX11ThreadPump ID3DX11ThreadPump_iface; + LONG refcount; + + LONG processing_count; + + SRWLOCK io_lock; + CONDITION_VARIABLE io_cv; + unsigned int io_count; + struct list io_queue; + + SRWLOCK proc_lock; + CONDITION_VARIABLE proc_cv; + unsigned int proc_count; + struct list proc_queue; + + SRWLOCK device_lock; + unsigned int device_count; + struct list device_queue; + + unsigned int thread_count; + HANDLE threads[1]; +}; + +static inline struct thread_pump *impl_from_ID3DX11ThreadPump(ID3DX11ThreadPump *iface) +{ + return CONTAINING_RECORD(iface, struct thread_pump, ID3DX11ThreadPump_iface); +} + +static HRESULT WINAPI thread_pump_QueryInterface(ID3DX11ThreadPump *iface, REFIID riid, void **out) +{ + TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualGUID(riid, &IID_ID3DX11ThreadPump) + || IsEqualGUID(riid, &IID_IUnknown)) + { + ID3DX11ThreadPump_AddRef(iface); + *out = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI thread_pump_AddRef(ID3DX11ThreadPump *iface) +{ + struct thread_pump *thread_pump = impl_from_ID3DX11ThreadPump(iface); + ULONG refcount = InterlockedIncrement(&thread_pump->refcount); + + TRACE("%p increasing refcount to %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI thread_pump_Release(ID3DX11ThreadPump *iface) +{ + struct thread_pump *thread_pump = impl_from_ID3DX11ThreadPump(iface); + ULONG refcount = InterlockedDecrement(&thread_pump->refcount); + struct work_item *item, *next; + struct list list; + unsigned int i; + + TRACE("%p decreasing refcount to %lu.\n", iface, refcount); + + if (!refcount) + { + AcquireSRWLockExclusive(&thread_pump->io_lock); + thread_pump->io_count = THREAD_PUMP_EXITING; + ReleaseSRWLockExclusive(&thread_pump->io_lock); + WakeAllConditionVariable(&thread_pump->io_cv); + + AcquireSRWLockExclusive(&thread_pump->proc_lock); + thread_pump->proc_count = THREAD_PUMP_EXITING; + ReleaseSRWLockExclusive(&thread_pump->proc_lock); + WakeAllConditionVariable(&thread_pump->proc_cv); + + AcquireSRWLockExclusive(&thread_pump->device_lock); + thread_pump->device_count = THREAD_PUMP_EXITING; + ReleaseSRWLockExclusive(&thread_pump->device_lock); + + for (i = 0; i < thread_pump->thread_count; ++i) + { + if (!thread_pump->threads[i]) + continue; + + WaitForSingleObject(thread_pump->threads[i], INFINITE); + CloseHandle(thread_pump->threads[i]); + } + + list_init(&list); + list_move_tail(&list, &thread_pump->io_queue); + list_move_tail(&list, &thread_pump->proc_queue); + list_move_tail(&list, &thread_pump->device_queue); + LIST_FOR_EACH_ENTRY_SAFE(item, next, &list, struct work_item, entry) + { + list_remove(&item->entry); + work_item_free(item, TRUE); + } + + free(thread_pump); + } + + return refcount; +} + +static HRESULT WINAPI thread_pump_AddWorkItem(ID3DX11ThreadPump *iface, ID3DX11DataLoader *loader, + ID3DX11DataProcessor *processor, HRESULT *result, void **object) +{ + struct thread_pump *thread_pump = impl_from_ID3DX11ThreadPump(iface); + struct work_item *work_item; + + TRACE("iface %p, loader %p, processor %p, result %p, object %p.\n", + iface, loader, processor, result, object); + + work_item = malloc(sizeof(*work_item)); + if (!work_item) + return E_OUTOFMEMORY; + + work_item->loader = loader; + work_item->processor = processor; + work_item->result = result; + work_item->object = object; + + if (object) + *object = NULL; + + InterlockedIncrement(&thread_pump->processing_count); + AcquireSRWLockExclusive(&thread_pump->io_lock); + ++thread_pump->io_count; + list_add_tail(&thread_pump->io_queue, &work_item->entry); + ReleaseSRWLockExclusive(&thread_pump->io_lock); + WakeConditionVariable(&thread_pump->io_cv); + return S_OK; +} + +static UINT WINAPI thread_pump_GetWorkItemCount(ID3DX11ThreadPump *iface) +{ + struct thread_pump *thread_pump = impl_from_ID3DX11ThreadPump(iface); + UINT ret; + + TRACE("iface %p.\n", iface); + + AcquireSRWLockExclusive(&thread_pump->device_lock); + ret = thread_pump->processing_count + thread_pump->device_count; + ReleaseSRWLockExclusive(&thread_pump->device_lock); + return ret; +} + +static HRESULT WINAPI thread_pump_WaitForAllItems(ID3DX11ThreadPump *iface) +{ + struct thread_pump *thread_pump = impl_from_ID3DX11ThreadPump(iface); + HRESULT hr; + LONG v; + + TRACE("iface %p.\n", iface); + + for (;;) + { + if (FAILED((hr = ID3DX11ThreadPump_ProcessDeviceWorkItems(iface, UINT_MAX)))) + return hr; + + AcquireSRWLockExclusive(&thread_pump->device_lock); + if (thread_pump->device_count) + { + ReleaseSRWLockExclusive(&thread_pump->device_lock); + continue; + } + v = thread_pump->processing_count; + ReleaseSRWLockExclusive(&thread_pump->device_lock); + if (!v) + break; + + RtlWaitOnAddress(&thread_pump->processing_count, &v, sizeof(v), NULL); + } + + return S_OK; +} + +static HRESULT WINAPI thread_pump_ProcessDeviceWorkItems(ID3DX11ThreadPump *iface, UINT count) +{ + struct thread_pump *thread_pump = impl_from_ID3DX11ThreadPump(iface); + struct work_item *work_item; + HRESULT hr; + UINT i; + + TRACE("iface %p, count %u.\n", iface, count); + + for (i = 0; i < count; ++i) + { + AcquireSRWLockExclusive(&thread_pump->device_lock); + if (!thread_pump->device_count) + { + ReleaseSRWLockExclusive(&thread_pump->device_lock); + break; + } + + --thread_pump->device_count; + work_item = LIST_ENTRY(list_head(&thread_pump->device_queue), struct work_item, entry); + list_remove(&work_item->entry); + ReleaseSRWLockExclusive(&thread_pump->device_lock); + + hr = ID3DX11DataProcessor_CreateDeviceObject(work_item->processor, work_item->object); + if (work_item->result) + *work_item->result = hr; + work_item_free(work_item, FALSE); + } + + return S_OK; +} + +static void purge_list(struct list *list, LONG *count) +{ + struct work_item *work_item; + + while (!list_empty(list)) + { + work_item = LIST_ENTRY(list_head(list), struct work_item, entry); + list_remove(&work_item->entry); + work_item_free(work_item, TRUE); + + if (count && !InterlockedDecrement(count)) + RtlWakeAddressAll(count); + } +} + +static HRESULT WINAPI thread_pump_PurgeAllItems(ID3DX11ThreadPump *iface) +{ + struct thread_pump *thread_pump = impl_from_ID3DX11ThreadPump(iface); + LONG v; + + TRACE("iface %p.\n", iface); + + for (;;) + { + AcquireSRWLockExclusive(&thread_pump->io_lock); + purge_list(&thread_pump->io_queue, &thread_pump->processing_count); + thread_pump->io_count = 0; + ReleaseSRWLockExclusive(&thread_pump->io_lock); + + AcquireSRWLockExclusive(&thread_pump->proc_lock); + purge_list(&thread_pump->proc_queue, &thread_pump->processing_count); + thread_pump->proc_count = 0; + ReleaseSRWLockExclusive(&thread_pump->proc_lock); + + AcquireSRWLockExclusive(&thread_pump->device_lock); + purge_list(&thread_pump->device_queue, NULL); + thread_pump->device_count = 0; + v = thread_pump->processing_count; + ReleaseSRWLockExclusive(&thread_pump->device_lock); + if (!v) + break; + + RtlWaitOnAddress(&thread_pump->processing_count, &v, sizeof(v), NULL); + } + + return S_OK; +} + +static HRESULT WINAPI thread_pump_GetQueueStatus(ID3DX11ThreadPump *iface, + UINT *io_queue, UINT *process_queue, UINT *device_queue) +{ + struct thread_pump *thread_pump = impl_from_ID3DX11ThreadPump(iface); + + TRACE("iface %p, io_queue %p, process_queue %p, device_queue %p.\n", + iface, io_queue, process_queue, device_queue); + + *io_queue = thread_pump->io_count; + *process_queue = thread_pump->proc_count; + *device_queue = thread_pump->device_count; + return S_OK; +} + +static const ID3DX11ThreadPumpVtbl thread_pump_vtbl = +{ + thread_pump_QueryInterface, + thread_pump_AddRef, + thread_pump_Release, + thread_pump_AddWorkItem, + thread_pump_GetWorkItemCount, + thread_pump_WaitForAllItems, + thread_pump_ProcessDeviceWorkItems, + thread_pump_PurgeAllItems, + thread_pump_GetQueueStatus +}; + +static DWORD WINAPI io_thread(void *arg) +{ + struct thread_pump *thread_pump = arg; + struct work_item *work_item; + HRESULT hr; + + TRACE("%p thread started.\n", thread_pump); + + for (;;) + { + AcquireSRWLockExclusive(&thread_pump->io_lock); + + while (!thread_pump->io_count) + SleepConditionVariableSRW(&thread_pump->io_cv, &thread_pump->io_lock, INFINITE, 0); + + if (thread_pump->io_count == THREAD_PUMP_EXITING) + { + ReleaseSRWLockExclusive(&thread_pump->io_lock); + return 0; + } + + --thread_pump->io_count; + work_item = LIST_ENTRY(list_head(&thread_pump->io_queue), struct work_item, entry); + list_remove(&work_item->entry); + ReleaseSRWLockExclusive(&thread_pump->io_lock); + + if (FAILED(hr = ID3DX11DataLoader_Load(work_item->loader))) + { + if (work_item->result) + *work_item->result = hr; + work_item_free(work_item, FALSE); + if (!InterlockedDecrement(&thread_pump->processing_count)) + RtlWakeAddressAll(&thread_pump->processing_count); + continue; + } + + AcquireSRWLockExclusive(&thread_pump->proc_lock); + if (thread_pump->proc_count == THREAD_PUMP_EXITING) + { + ReleaseSRWLockExclusive(&thread_pump->proc_lock); + work_item_free(work_item, TRUE); + return 0; + } + + list_add_tail(&thread_pump->proc_queue, &work_item->entry); + ++thread_pump->proc_count; + ReleaseSRWLockExclusive(&thread_pump->proc_lock); + WakeConditionVariable(&thread_pump->proc_cv); + } + return 0; +} + +static DWORD WINAPI proc_thread(void *arg) +{ + struct thread_pump *thread_pump = arg; + struct work_item *work_item; + SIZE_T size; + void *data; + HRESULT hr; + + TRACE("%p thread started.\n", thread_pump); + + for (;;) + { + AcquireSRWLockExclusive(&thread_pump->proc_lock); + + while (!thread_pump->proc_count) + SleepConditionVariableSRW(&thread_pump->proc_cv, &thread_pump->proc_lock, INFINITE, 0); + + if (thread_pump->proc_count == THREAD_PUMP_EXITING) + { + ReleaseSRWLockExclusive(&thread_pump->proc_lock); + return 0; + } + + --thread_pump->proc_count; + work_item = LIST_ENTRY(list_head(&thread_pump->proc_queue), struct work_item, entry); + list_remove(&work_item->entry); + ReleaseSRWLockExclusive(&thread_pump->proc_lock); + + if (FAILED(hr = ID3DX11DataLoader_Decompress(work_item->loader, &data, &size))) + { + if (work_item->result) + *work_item->result = hr; + work_item_free(work_item, FALSE); + if (!InterlockedDecrement(&thread_pump->processing_count)) + RtlWakeAddressAll(&thread_pump->processing_count); + continue; + } + + if (thread_pump->device_count == THREAD_PUMP_EXITING) + { + work_item_free(work_item, TRUE); + return 0; + } + + if (FAILED(hr = ID3DX11DataProcessor_Process(work_item->processor, data, size))) + { + if (work_item->result) + *work_item->result = hr; + work_item_free(work_item, FALSE); + if (!InterlockedDecrement(&thread_pump->processing_count)) + RtlWakeAddressAll(&thread_pump->processing_count); + continue; + } + + AcquireSRWLockExclusive(&thread_pump->device_lock); + if (thread_pump->device_count == THREAD_PUMP_EXITING) + { + ReleaseSRWLockExclusive(&thread_pump->device_lock); + work_item_free(work_item, TRUE); + return 0; + } + + list_add_tail(&thread_pump->device_queue, &work_item->entry); + ++thread_pump->device_count; + InterlockedDecrement(&thread_pump->processing_count); + RtlWakeAddressAll(&thread_pump->processing_count); + ReleaseSRWLockExclusive(&thread_pump->device_lock); + } + return 0; +} + +HRESULT WINAPI D3DX11CreateThreadPump(UINT io_threads, UINT proc_threads, ID3DX11ThreadPump **pump) +{ + struct thread_pump *object; + unsigned int i; + + TRACE("io_threads %u, proc_threads %u, pump %p.\n", io_threads, proc_threads, pump); + + if (io_threads >= 1024 || proc_threads >= 1024) + return E_FAIL; + + if (!io_threads) + io_threads = 1; + if (!proc_threads) + { + SYSTEM_INFO info; + + GetSystemInfo(&info); + proc_threads = info.dwNumberOfProcessors; + } + + if (!(object = calloc(1, FIELD_OFFSET(struct thread_pump, threads[io_threads + proc_threads])))) + return E_OUTOFMEMORY; + + object->ID3DX11ThreadPump_iface.lpVtbl = &thread_pump_vtbl; + object->refcount = 1; + InitializeSRWLock(&object->io_lock); + InitializeConditionVariable(&object->io_cv); + list_init(&object->io_queue); + InitializeSRWLock(&object->proc_lock); + InitializeConditionVariable(&object->proc_cv); + list_init(&object->proc_queue); + InitializeSRWLock(&object->device_lock); + list_init(&object->device_queue); + object->thread_count = io_threads + proc_threads; + + for (i = 0; i < object->thread_count; ++i) + { + object->threads[i] = CreateThread(NULL, 0, i < io_threads ? io_thread : proc_thread, object, 0, NULL); + if (!object->threads[i]) + { + ID3DX11ThreadPump_Release(&object->ID3DX11ThreadPump_iface); + return E_FAIL; + } + } + + *pump = &object->ID3DX11ThreadPump_iface; + return S_OK; +} diff --git a/dlls/d3dx11_43/d3dx11_43.spec b/dlls/d3dx11_43/d3dx11_43.spec index 2d93b8d760ab..5212532e0e4f 100644 --- a/dlls/d3dx11_43/d3dx11_43.spec +++ b/dlls/d3dx11_43/d3dx11_43.spec @@ -12,26 +12,26 @@ @ stdcall D3DX11CreateAsyncResourceLoaderA(long str ptr) @ stdcall D3DX11CreateAsyncResourceLoaderW(long wstr ptr) @ stub D3DX11CreateAsyncShaderPreprocessProcessor -@ stub D3DX11CreateAsyncShaderResourceViewProcessor -@ stub D3DX11CreateAsyncTextureInfoProcessor -@ stub D3DX11CreateAsyncTextureProcessor -@ stub D3DX11CreateShaderResourceViewFromFileA -@ stub D3DX11CreateShaderResourceViewFromFileW +@ stdcall D3DX11CreateAsyncShaderResourceViewProcessor(ptr ptr ptr) +@ stdcall D3DX11CreateAsyncTextureInfoProcessor(ptr ptr) +@ stdcall D3DX11CreateAsyncTextureProcessor(ptr ptr ptr) +@ stdcall D3DX11CreateShaderResourceViewFromFileA(ptr str ptr ptr ptr ptr) +@ stdcall D3DX11CreateShaderResourceViewFromFileW(ptr wstr ptr ptr ptr ptr) @ stdcall D3DX11CreateShaderResourceViewFromMemory(ptr ptr long ptr ptr ptr ptr) -@ stub D3DX11CreateShaderResourceViewFromResourceA -@ stub D3DX11CreateShaderResourceViewFromResourceW +@ stdcall D3DX11CreateShaderResourceViewFromResourceA(ptr long str ptr ptr ptr ptr) +@ stdcall D3DX11CreateShaderResourceViewFromResourceW(ptr long wstr ptr ptr ptr ptr) @ stdcall D3DX11CreateTextureFromFileA(ptr str ptr ptr ptr ptr) @ stdcall D3DX11CreateTextureFromFileW(ptr wstr ptr ptr ptr ptr) @ stdcall D3DX11CreateTextureFromMemory(ptr ptr long ptr ptr ptr ptr) -@ stub D3DX11CreateTextureFromResourceA -@ stub D3DX11CreateTextureFromResourceW -@ stub D3DX11CreateThreadPump +@ stdcall D3DX11CreateTextureFromResourceA(ptr long str ptr ptr ptr ptr) +@ stdcall D3DX11CreateTextureFromResourceW(ptr long wstr ptr ptr ptr ptr) +@ stdcall D3DX11CreateThreadPump(long long ptr) @ stdcall D3DX11FilterTexture(ptr ptr long long) @ stdcall D3DX11GetImageInfoFromFileA(str ptr ptr ptr) @ stdcall D3DX11GetImageInfoFromFileW(wstr ptr ptr ptr) @ stdcall D3DX11GetImageInfoFromMemory(ptr long ptr ptr ptr) -@ stub D3DX11GetImageInfoFromResourceA -@ stub D3DX11GetImageInfoFromResourceW +@ stdcall D3DX11GetImageInfoFromResourceA(long str ptr ptr ptr) +@ stdcall D3DX11GetImageInfoFromResourceW(long wstr ptr ptr ptr) @ stdcall D3DX11LoadTextureFromTexture(ptr ptr ptr ptr) @ stub D3DX11PreprocessShaderFromFileA @ stub D3DX11PreprocessShaderFromFileW diff --git a/dlls/d3dx11_43/d3dx11_43_main.c b/dlls/d3dx11_43/d3dx11_43_main.c new file mode 100644 index 000000000000..c327b5c54404 --- /dev/null +++ b/dlls/d3dx11_43/d3dx11_43_main.c @@ -0,0 +1,35 @@ +/* + * Copyright 2013 Detlef Riekenberg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "objbase.h" + +#include "d3dx11.h" +#include "d3dx11core.h" +#include "d3dx11tex.h" + +BOOL WINAPI D3DX11CheckVersion(UINT d3d_sdk_ver, UINT d3dx_sdk_ver) +{ + return d3d_sdk_ver == D3D11_SDK_VERSION && d3dx_sdk_ver == D3DX11_SDK_VERSION; +} diff --git a/dlls/d3dx11_43/dxhelpers.h b/dlls/d3dx11_43/dxhelpers.h new file mode 100644 index 000000000000..498b30a590cc --- /dev/null +++ b/dlls/d3dx11_43/dxhelpers.h @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Connor McAdams for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "../d3dx9_36/d3dx_helpers.h" + +HRESULT get_image_info(const void *data, SIZE_T size, D3DX11_IMAGE_INFO *img_info); + +void init_load_info(const D3DX11_IMAGE_LOAD_INFO *load_info, + D3DX11_IMAGE_LOAD_INFO *out); +/* Returns array of D3D11_SUBRESOURCE_DATA structures followed by textures data. */ +HRESULT load_texture_data(const void *data, SIZE_T size, D3DX11_IMAGE_LOAD_INFO *load_info, + D3D11_SUBRESOURCE_DATA **resource_data); +HRESULT create_d3d_texture(ID3D11Device *device, D3DX11_IMAGE_LOAD_INFO *load_info, + D3D11_SUBRESOURCE_DATA *resource_data, ID3D11Resource **texture); diff --git a/dlls/d3dx11_43/main.c b/dlls/d3dx11_43/main.c deleted file mode 100644 index 5dad027864fe..000000000000 --- a/dlls/d3dx11_43/main.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013 Detlef Riekenberg - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - */ - -#include - -#define COBJMACROS -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "objbase.h" - -#include "d3dx11.h" -#include "d3dx11core.h" -#include "d3dx11tex.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(d3dx); - -BOOL WINAPI D3DX11CheckVersion(UINT d3d_sdk_ver, UINT d3dx_sdk_ver) -{ - return d3d_sdk_ver == D3D11_SDK_VERSION && d3dx_sdk_ver == D3DX11_SDK_VERSION; -} - -HRESULT WINAPI D3DX11FilterTexture(ID3D11DeviceContext *context, ID3D11Resource *texture, UINT src_level, UINT filter) -{ - FIXME("context %p, texture %p, src_level %u, filter %#x stub!\n", context, texture, src_level, filter); - - return E_NOTIMPL; -} - -HRESULT WINAPI D3DX11GetImageInfoFromFileA(const char *filename, ID3DX11ThreadPump *pump, D3DX11_IMAGE_INFO *img_info, - HRESULT *hresult) -{ - FIXME("filename %s, pump %p, img_info %p, hresult %p stub!\n", debugstr_a(filename), pump, img_info, hresult); - - if (!filename) - return E_FAIL; - - return E_NOTIMPL; -} - -HRESULT WINAPI D3DX11GetImageInfoFromFileW(const WCHAR *filename, ID3DX11ThreadPump *pump, D3DX11_IMAGE_INFO *img_info, - HRESULT *hresult) -{ - FIXME("filename %s, pump %p, img_info %p, hresult %p stub!\n", debugstr_w(filename), pump, img_info, hresult); - - if (!filename) - return E_FAIL; - - return E_NOTIMPL; -} - -HRESULT WINAPI D3DX11GetImageInfoFromMemory(const void *src_data, SIZE_T src_data_size, ID3DX11ThreadPump *pump, - D3DX11_IMAGE_INFO *img_info, HRESULT *hresult) -{ - FIXME("src_data %p, src_data_size %Iu, pump %p, img_info %p, hresult %p stub!\n", - src_data, src_data_size, pump, img_info, hresult); - - return E_NOTIMPL; -} diff --git a/dlls/d3dx11_43/tests/Makefile.in b/dlls/d3dx11_43/tests/Makefile.in index 3283e251bdd0..4225e0896551 100644 --- a/dlls/d3dx11_43/tests/Makefile.in +++ b/dlls/d3dx11_43/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = d3dx11_43.dll -IMPORTS = d3dx11 +IMPORTS = d3dx11 ole32 gdi32 SOURCES = \ d3dx11.c diff --git a/dlls/d3dx11_43/tests/d3dx11.c b/dlls/d3dx11_43/tests/d3dx11.c index 16c0f0bc03e1..faca88f52fc5 100644 --- a/dlls/d3dx11_43/tests/d3dx11.c +++ b/dlls/d3dx11_43/tests/d3dx11.c @@ -18,9 +18,17 @@ #define COBJMACROS #include "initguid.h" +#include "wincodec.h" #include "d3d11.h" #include "d3dx11.h" +#include "wine/wined3d.h" #include "wine/test.h" +#include + +#define D3DERR_INVALIDCALL 0x8876086c +#define DDS_RESOURCE_MISC_TEXTURECUBE 0x04 + +static bool wined3d_opengl; #ifndef MAKEFOURCC #define MAKEFOURCC(ch0, ch1, ch2, ch3) \ @@ -28,6 +36,274 @@ ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 )) #endif +static DXGI_FORMAT block_compressed_formats[] = +{ + DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB, + DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB, + DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM, + DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM, + DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_BC6H_SF16, + DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM_SRGB +}; + +static BOOL is_block_compressed(DXGI_FORMAT format) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(block_compressed_formats); ++i) + if (format == block_compressed_formats[i]) + return TRUE; + + return FALSE; +} + +static BOOL dxgi_format_is_8bpp_rgba(DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + return TRUE; + default: + return FALSE; + } +} + +static uint32_t get_bpp_from_format(DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return 128; + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + return 96; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + return 64; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_YUY2: + return 32; + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + return 24; + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_A8P8: + case DXGI_FORMAT_B4G4R4A4_UNORM: + return 16; + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_NV11: + return 12; + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return 8; + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + return 4; + case DXGI_FORMAT_R1_UNORM: + return 1; + default: + return 0; + } +} + +static HRESULT WINAPI D3DX11ThreadPump_QueryInterface(ID3DX11ThreadPump *iface, REFIID riid, void **out) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static ULONG WINAPI D3DX11ThreadPump_AddRef(ID3DX11ThreadPump *iface) +{ + return 2; +} + +static ULONG WINAPI D3DX11ThreadPump_Release(ID3DX11ThreadPump *iface) +{ + return 1; +} + +static int add_work_item_count = 1; + +static HRESULT WINAPI D3DX11ThreadPump_AddWorkItem(ID3DX11ThreadPump *iface, ID3DX11DataLoader *loader, + ID3DX11DataProcessor *processor, HRESULT *result, void **object) +{ + SIZE_T size; + void *data; + HRESULT hr; + + ok(!add_work_item_count++, "unexpected call\n"); + + hr = ID3DX11DataLoader_Load(loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataLoader_Decompress(loader, &data, &size); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataProcessor_Process(processor, data, size); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataProcessor_CreateDeviceObject(processor, object); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataProcessor_Destroy(processor); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataLoader_Destroy(loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + if (result) *result = S_OK; + return S_OK; +} + +static UINT WINAPI D3DX11ThreadPump_GetWorkItemCount(ID3DX11ThreadPump *iface) +{ + ok(0, "unexpected call\n"); + return 0; +} + +static HRESULT WINAPI D3DX11ThreadPump_WaitForAllItems(ID3DX11ThreadPump *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI D3DX11ThreadPump_ProcessDeviceWorkItems(ID3DX11ThreadPump *iface, UINT count) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI D3DX11ThreadPump_PurgeAllItems(ID3DX11ThreadPump *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI D3DX11ThreadPump_GetQueueStatus(ID3DX11ThreadPump *iface, UINT *queue, + UINT *processqueue, UINT *devicequeue) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static ID3DX11ThreadPumpVtbl D3DX11ThreadPumpVtbl = +{ + D3DX11ThreadPump_QueryInterface, + D3DX11ThreadPump_AddRef, + D3DX11ThreadPump_Release, + D3DX11ThreadPump_AddWorkItem, + D3DX11ThreadPump_GetWorkItemCount, + D3DX11ThreadPump_WaitForAllItems, + D3DX11ThreadPump_ProcessDeviceWorkItems, + D3DX11ThreadPump_PurgeAllItems, + D3DX11ThreadPump_GetQueueStatus +}; +static ID3DX11ThreadPump thread_pump = { &D3DX11ThreadPumpVtbl }; + +static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff) +{ + unsigned int diff = x > y ? x - y : y - x; + + return diff <= max_diff; +} + /* 1x1 bmp (1 bpp) */ static const unsigned char bmp_1bpp[] = { @@ -249,305 +525,2359 @@ static const unsigned char noimage[4] = 0x11,0x22,0x33,0x44 }; -static WCHAR temp_dir[MAX_PATH]; +/* 1x1 1bpp bmp image */ +static const BYTE test_bmp_1bpp[] = +{ + 0x42, 0x4d, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xf1, 0xf2, 0xf3, 0x80, 0xf4, 0xf5, 0xf6, 0x81, 0x00, 0x00, + 0x00, 0x00 +}; +static const BYTE test_bmp_1bpp_data[] = +{ + 0xf3, 0xf2, 0xf1, 0xff +}; -static BOOL create_file(const WCHAR *filename, const char *data, unsigned int size, WCHAR *out_path) +/* 1x1 4bpp bmp image */ +static const BYTE test_bmp_4bpp[] = { - WCHAR path[MAX_PATH]; - DWORD written; - HANDLE file; + 0x42, 0x4d, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xf1, 0xf2, 0xf3, 0x80, 0xf4, 0xf5, 0xf6, 0x81, 0x00, 0x00, + 0x00, 0x00 +}; +static const BYTE test_bmp_4bpp_data[] = +{ + 0xf3, 0xf2, 0xf1, 0xff +}; - if (!temp_dir[0]) - GetTempPathW(ARRAY_SIZE(temp_dir), temp_dir); - lstrcpyW(path, temp_dir); - lstrcatW(path, filename); +/* 1x1 8bpp bmp image */ +static const BYTE test_bmp_8bpp[] = +{ + 0x42, 0x4d, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xf1, 0xf2, 0xf3, 0x80, 0xf4, 0xf5, 0xf6, 0x81, 0x00, 0x00, + 0x00, 0x00 +}; +static const BYTE test_bmp_8bpp_data[] = +{ + 0xf3, 0xf2, 0xf1, 0xff +}; - file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if (file == INVALID_HANDLE_VALUE) - return FALSE; +/* 1x1 16bpp bmp image */ +static const BYTE test_bmp_16bpp[] = +{ + 0x42, 0x4d, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x42, 0x00, 0x00, 0x00, 0x00 +}; +static const BYTE test_bmp_16bpp_data[] = +{ + 0x84, 0x84, 0x73, 0xff +}; - if (WriteFile(file, data, size, &written, NULL)) - { - CloseHandle(file); +/* 1x1 24bpp bmp image */ +static const BYTE test_bmp_24bpp[] = +{ + 0x42, 0x4d, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x84, 0x84, 0x00, 0x00, 0x00 +}; +static const BYTE test_bmp_24bpp_data[] = +{ + 0x84, 0x84, 0x73, 0xff +}; - if (out_path) - lstrcpyW(out_path, path); - return TRUE; - } +/* 2x2 32bpp XRGB bmp image */ +static const BYTE test_bmp_32bpp_xrgb[] = +{ + 0x42, 0x4d, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xb0, 0xc0, 0x00, 0xa1, 0xb1, 0xc1, 0x00, 0xa2, 0xb2, + 0xc2, 0x00, 0xa3, 0xb3, 0xc3, 0x00 +}; +static const BYTE test_bmp_32bpp_xrgb_data[] = +{ + 0xc2, 0xb2, 0xa2, 0xff, 0xc3, 0xb3, 0xa3, 0xff, 0xc0, 0xb0, 0xa0, 0xff, 0xc1, 0xb1, 0xa1, 0xff - CloseHandle(file); - return FALSE; -} +}; -static void delete_file(const WCHAR *filename) +/* 2x2 32bpp ARGB bmp image */ +static const BYTE test_bmp_32bpp_argb[] = { - WCHAR path[MAX_PATH]; + 0x42, 0x4d, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xb0, 0xc0, 0x00, 0xa1, 0xb1, 0xc1, 0x00, 0xa2, 0xb2, + 0xc2, 0x00, 0xa3, 0xb3, 0xc3, 0x01 +}; +static const BYTE test_bmp_32bpp_argb_data[] = +{ + 0xc2, 0xb2, 0xa2, 0xff, 0xc3, 0xb3, 0xa3, 0xff, 0xc0, 0xb0, 0xa0, 0xff, 0xc1, 0xb1, 0xa1, 0xff - lstrcpyW(path, temp_dir); - lstrcatW(path, filename); - DeleteFileW(path); -} +}; -static BOOL create_directory(const WCHAR *dir) +/* 1x1 8bpp gray png image */ +static const BYTE test_png_8bpp_gray[] = { - WCHAR path[MAX_PATH]; + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x7e, 0x9b, + 0x55, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0x0f, 0x00, 0x01, + 0x01, 0x01, 0x00, 0x1b, 0xb6, 0xee, 0x56, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82 +}; +static const BYTE test_png_8bpp_gray_data[] = +{ + 0xff, 0xff, 0xff, 0xff +}; - lstrcpyW(path, temp_dir); - lstrcatW(path, dir); - return CreateDirectoryW(path, NULL); -} +/* 1x1 jpg image */ +static const BYTE test_jpg[] = +{ + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x01, 0x2c, + 0x01, 0x2c, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, + 0x0b, 0x09, 0x0c, 0x11, 0x0f, 0x12, 0x12, 0x11, 0x0f, 0x11, 0x11, 0x13, 0x16, 0x1c, 0x17, 0x13, + 0x14, 0x1a, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1a, 0x1d, 0x1d, 0x1f, 0x1f, 0x1f, 0x13, 0x17, + 0x22, 0x24, 0x22, 0x1e, 0x24, 0x1c, 0x1e, 0x1f, 0x1e, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x05, 0x05, + 0x05, 0x07, 0x06, 0x07, 0x0e, 0x08, 0x08, 0x0e, 0x1e, 0x14, 0x11, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0xff, 0xc0, + 0x00, 0x11, 0x08, 0x00, 0x01, 0x00, 0x01, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, + 0x01, 0xff, 0xc4, 0x00, 0x15, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xc4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc4, + 0x00, 0x14, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xc4, 0x00, 0x14, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, + 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xb2, 0xc0, 0x07, 0xff, 0xd9 +}; +static const BYTE test_jpg_data[] = +{ + 0xff, 0xff, 0xff, 0xff +}; -static void delete_directory(const WCHAR *dir) +/* 1x1 gif image */ +static const BYTE test_gif[] = { - WCHAR path[MAX_PATH]; + 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x01, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, + 0x01, 0x00, 0x3b +}; +static const BYTE test_gif_data[] = +{ + 0xff, 0xff, 0xff, 0xff +}; - lstrcpyW(path, temp_dir); - lstrcatW(path, dir); - RemoveDirectoryW(path); -} +/* 1x1 tiff image */ +static const BYTE test_tiff[] = +{ + 0x49, 0x49, 0x2a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xfe, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x02, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x03, 0x01, + 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x01, 0x02, 0x00, 0x1b, 0x00, 0x00, 0x00, 0xd8, 0x00, + 0x00, 0x00, 0x11, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x12, 0x01, + 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x01, 0x03, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x16, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x17, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1a, 0x01, + 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x05, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x28, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x6d, 0x65, + 0x68, 0x2f, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, + 0x69, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, + 0x00, 0x00, 0x00, 0x01 +}; +static const BYTE test_tiff_data[] = +{ + 0x00, 0x00, 0x00, 0xff +}; -static void test_D3DX11CreateAsyncMemoryLoader(void) +/* 1x1 alpha dds image */ +static const BYTE test_dds_alpha[] = { - ID3DX11DataLoader *loader; - SIZE_T size; - DWORD data; - HRESULT hr; - void *ptr; + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff +}; +static const BYTE test_dds_alpha_data[] = +{ + 0xff +}; - hr = D3DX11CreateAsyncMemoryLoader(NULL, 0, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); +/* 1x1 luminance dds image */ +static const BYTE test_dds_luminance[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82 +}; +static const BYTE test_dds_luminance_data[] = +{ + 0x82, 0x82, 0x82, 0xff +}; - hr = D3DX11CreateAsyncMemoryLoader(NULL, 0, &loader); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); +/* 1x1 16bpp dds image */ +static const BYTE test_dds_16bpp[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, + 0xe0, 0x03, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x42 +}; +static const BYTE test_dds_16bpp_data[] = +{ + 0x84, 0x84, 0x73, 0xff +}; - hr = D3DX11CreateAsyncMemoryLoader(&data, 0, &loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +/* 1x1 24bpp dds image */ +static const BYTE test_dds_24bpp[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x81, 0x83 +}; +static const BYTE test_dds_24bpp_data[] = +{ + 0x83, 0x81, 0x70, 0xff +}; - size = 100; - hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(ptr == &data, "Got data pointer %p, original %p.\n", ptr, &data); - ok(!size, "Got unexpected data size.\n"); +/* 1x1 32bpp dds image */ +static const BYTE test_dds_32bpp[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x81, 0x83, 0xff +}; +static const BYTE test_dds_32bpp_data[] = +{ + 0x83, 0x81, 0x70, 0xff +}; - /* Load() is no-op. */ - hr = ID3DX11DataLoader_Load(loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +/* 1x1 64bpp dds image */ +static const BYTE test_dds_64bpp[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x0f, 0x10, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x83, 0x81, 0x81, 0x70, 0x70, 0xff, 0xff +}; +static const BYTE test_dds_64bpp_data[] = +{ + 0x83, 0x83, 0x81, 0x81, 0x70, 0x70, 0xff, 0xff +}; - hr = ID3DX11DataLoader_Destroy(loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +/* 1x1 96bpp dds image */ +static const BYTE test_dds_96bpp[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x0f, 0x10, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x44, 0x58, 0x31, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x84, 0x83, 0x03, 0x3f, 0x82, 0x81, 0x01, 0x3f, 0xe2, 0xe0, 0xe0, 0x3e +}; +static const BYTE test_dds_96bpp_data[] = +{ + 0x84, 0x83, 0x03, 0x3f, 0x82, 0x81, 0x01, 0x3f, 0xe2, 0xe0, 0xe0, 0x3e +}; - data = 0; - hr = D3DX11CreateAsyncMemoryLoader(&data, sizeof(data), &loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +/* 1x1 128bpp dds image */ +static const BYTE test_dds_128bpp[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x0f, 0x10, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x84, 0x83, 0x03, 0x3f, 0x82, 0x81, 0x01, 0x3f, 0xe2, 0xe0, 0xe0, 0x3e, 0x00, 0x00, 0x80, 0x3f +}; +static const BYTE test_dds_128bpp_data[] = +{ + 0x84, 0x83, 0x03, 0x3f, 0x82, 0x81, 0x01, 0x3f, 0xe2, 0xe0, 0xe0, 0x3e, 0x00, 0x00, 0x80, 0x3f - /* Load() is no-op. */ - hr = ID3DX11DataLoader_Load(loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +}; - hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(ptr == &data, "Got data pointer %p, original %p.\n", ptr, &data); - ok(size == sizeof(data), "Got unexpected data size.\n"); +/* 4x4 DXT1 dds image */ +static const BYTE test_dds_dxt1[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x44, 0x58, 0x54, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x31, 0xf5, 0xbc, 0xe3, 0x6e, 0x2a, 0x3a +}; +static const BYTE test_dds_dxt1_data[] = +{ + 0x2a, 0x31, 0xf5, 0xbc, 0xe3, 0x6e, 0x2a, 0x3a +}; - hr = ID3DX11DataLoader_Destroy(loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); -} +/* 4x8 DXT1 dds image */ +static const BYTE test_dds_dxt1_4x8[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x0a, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x44, 0x58, 0x54, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x92, 0xce, 0x09, 0x7a, 0x5d, 0xdd, 0xa7, 0x26, 0x55, 0xde, 0xaf, 0x52, 0xbc, 0xf8, 0x6c, 0x44, + 0x53, 0xbd, 0x8b, 0x72, 0x55, 0x33, 0x88, 0xaa, 0xb2, 0x9c, 0x6c, 0x93, 0x55, 0x00, 0x55, 0x00, + 0x0f, 0x9c, 0x0f, 0x9c, 0x00, 0x00, 0x00, 0x00, +}; +static const BYTE test_dds_dxt1_4x8_data[] = +{ + 0x92, 0xce, 0x09, 0x7a, 0x5d, 0xdd, 0xa7, 0x26, 0x55, 0xde, 0xaf, 0x52, 0xbc, 0xf8, 0x6c, 0x44, +}; -static void create_testfile(WCHAR *path, const void *data, int data_len) +/* 4x4 DXT2 dds image */ +static const BYTE test_dds_dxt2[] = { - DWORD written; - HANDLE file; - BOOL ret; + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x44, 0x58, 0x54, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xde, 0xc4, 0x10, 0x2f, 0xbf, 0xff, 0x7b, + 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x53, 0x00, 0x00, 0x52, 0x52, 0x55, 0x55, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x59, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55 +}; +static const BYTE test_dds_dxt2_data[] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xde, 0xc4, 0x10, 0x2f, 0xbf, 0xff, 0x7b - GetTempPathW(MAX_PATH, path); - lstrcatW(path, L"asyncloader.data"); +}; - file = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); - ok(file != INVALID_HANDLE_VALUE, "Test file creation failed, at %s, error %ld.\n", - wine_dbgstr_w(path), GetLastError()); +/* 1x3 DXT3 dds image */ +static const BYTE test_dds_dxt3[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x44, 0x58, 0x54, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x92, 0x38, 0x84, 0x00, 0xff, 0x55, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x53, 0x8b, 0x53, 0x8b, 0x00, 0x00, 0x00, 0x00 +}; +static const BYTE test_dds_dxt3_data[] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4e, 0x92, 0xd6, 0x83, 0x00, 0xaa, 0x55, 0x55 - ret = WriteFile(file, data, data_len, &written, NULL); - ok(ret, "Write to test file failed.\n"); +}; - CloseHandle(file); -} +/* 4x4 DXT4 dds image */ +static const BYTE test_dds_dxt4[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x44, 0x58, 0x54, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xde, 0xc4, 0x10, 0x2f, 0xbf, 0xff, 0x7b, + 0xff, 0x00, 0x40, 0x02, 0x24, 0x49, 0x92, 0x24, 0x57, 0x53, 0x00, 0x00, 0x52, 0x52, 0x55, 0x55, + 0xff, 0x00, 0x48, 0x92, 0x24, 0x49, 0x92, 0x24, 0xce, 0x59, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55 +}; +static const BYTE test_dds_dxt4_data[] = +{ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xde, 0xc4, 0x10, 0x2f, 0xbf, 0xff, 0x7b -static void test_D3DX11CreateAsyncFileLoader(void) +}; + +/* 4x2 DXT5 dds image */ +static const BYTE test_dds_dxt5[] = { - static const char test_data1[] = "test data"; - static const char test_data2[] = "more test data"; - ID3DX11DataLoader *loader; - WCHAR path[MAX_PATH]; - SIZE_T size; - HRESULT hr; - void *ptr; - BOOL ret; - - hr = D3DX11CreateAsyncFileLoaderA(NULL, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x44, 0x58, 0x54, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x87, 0x0f, 0x78, 0x05, 0x05, 0x50, 0x50 +}; +static const BYTE test_dds_dxt5_data[] = +{ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x87, 0x0f, 0x78, 0x05, 0x05, 0x05, 0x05 - hr = D3DX11CreateAsyncFileLoaderA(NULL, &loader); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); +}; - hr = D3DX11CreateAsyncFileLoaderA("nonexistentfilename", &loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +/* 8x8 DXT5 dds image */ +static const BYTE test_dds_dxt5_8x8[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x0a, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x44, 0x58, 0x54, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x8a, 0x72, 0x39, 0x5e, 0x5e, 0xfa, 0xa8, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xd7, 0xd5, 0x4a, 0x2d, 0x2d, 0xad, 0xfd, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x9a, 0x73, 0x83, 0xa0, 0xf0, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x5b, 0x06, 0x19, 0x00, 0xe8, 0x78, 0x58, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0xbe, 0x8c, 0x49, 0x35, 0xb5, 0xff, 0x7f, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x84, 0xab, 0x59, 0x11, 0xff, 0x11, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x6a, 0xf0, 0x6a, 0x00, 0x00, 0x00, 0x00, +}; +static const BYTE test_dds_dxt5_8x8_data[] = +{ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x8a, 0x72, 0x39, 0x5e, 0x5e, 0xfa, 0xa8, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xd7, 0xd5, 0x4a, 0x2d, 0x2d, 0xad, 0xfd, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x9a, 0x73, 0x83, 0xa0, 0xf0, 0x78, 0x78, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x5b, 0x06, 0x19, 0x00, 0xe8, 0x78, 0x58, +}; - hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); +/* 4x4 BC4 dds image */ +static const BYTE test_dds_bc4[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x42, 0x43, 0x34, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd9, 0x15, 0xbc, 0x41, 0x5b, 0xa3, 0x3d, 0x3a, 0x8f, 0x3d, 0x45, 0x81, 0x20, 0x45, 0x81, 0x20, + 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const BYTE test_dds_bc4_data[] = +{ + 0xd9, 0x15, 0xbc, 0x41, 0x5b, 0xa3, 0x3d, 0x3a +}; - hr = ID3DX11DataLoader_Load(loader); - ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); +/* 6x3 BC5 dds image */ +static const BYTE test_dds_bc5[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x42, 0x43, 0x35, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9f, 0x28, 0x73, 0xac, 0xd5, 0x80, 0xaa, 0xd5, 0x70, 0x2c, 0x4e, 0xd6, 0x76, 0x1d, 0xd6, 0x76, + 0xd5, 0x0f, 0xc3, 0x50, 0x96, 0xcf, 0x53, 0x96, 0xdf, 0x16, 0xc3, 0x50, 0x96, 0xcf, 0x53, 0x96, + 0x83, 0x55, 0x08, 0x83, 0x30, 0x08, 0x83, 0x30, 0x79, 0x46, 0x31, 0x1c, 0xc3, 0x31, 0x1c, 0xc3, + 0x6d, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const BYTE test_dds_bc5_data[] = +{ + 0x95, 0x35, 0xe2, 0xa3, 0xf5, 0xd2, 0x28, 0x68, 0x65, 0x32, 0x7c, 0x4e, 0xdb, 0xe4, 0x56, 0x0a, + 0xb9, 0x33, 0xaf, 0xf0, 0x52, 0xbe, 0xed, 0x27, 0xb4, 0x2e, 0xa6, 0x60, 0x4e, 0xb6, 0x5d, 0x3f - hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); +}; - hr = ID3DX11DataLoader_Destroy(loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +/* 4x4 DXT1 cube map */ +static const BYTE test_dds_cube[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x44, 0x58, 0x54, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x40, 0x00, + 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7, 0x32, 0x96, 0x0b, 0x7b, 0xcc, 0x55, 0xcc, 0x55, + 0x0e, 0x84, 0x0e, 0x84, 0x00, 0x00, 0x00, 0x00, 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7, + 0x32, 0x96, 0x0b, 0x7b, 0xcc, 0x55, 0xcc, 0x55, 0x0e, 0x84, 0x0e, 0x84, 0x00, 0x00, 0x00, 0x00, + 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7, 0x32, 0x96, 0x0b, 0x7b, 0xcc, 0x55, 0xcc, 0x55, + 0x0e, 0x84, 0x0e, 0x84, 0x00, 0x00, 0x00, 0x00, 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7, + 0x32, 0x96, 0x0b, 0x7b, 0xcc, 0x55, 0xcc, 0x55, 0x0e, 0x84, 0x0e, 0x84, 0x00, 0x00, 0x00, 0x00, + 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7, 0x32, 0x96, 0x0b, 0x7b, 0xcc, 0x55, 0xcc, 0x55, + 0x0e, 0x84, 0x0e, 0x84, 0x00, 0x00, 0x00, 0x00, 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7, + 0x32, 0x96, 0x0b, 0x7b, 0xcc, 0x55, 0xcc, 0x55, 0x0e, 0x84, 0x0e, 0x84, 0x00, 0x00, 0x00, 0x00 +}; +static const BYTE test_dds_cube_data[] = +{ + 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7, + 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7, + 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7, + 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7, + 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7, + 0xf5, 0xa7, 0x08, 0x69, 0x74, 0xc0, 0xbf, 0xd7 +}; - /* Test file sharing using dummy empty file. */ - create_testfile(path, test_data1, sizeof(test_data1)); +/* 4x4x2 DXT3 volume dds, 2 mipmaps */ +static const BYTE test_dds_volume[] = +{ + 0x44, 0x44, 0x53, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x07, 0x10, 0x8a, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x44, 0x58, 0x54, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x40, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x87, 0x0f, 0x78, 0x05, 0x05, 0x50, 0x50, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x87, 0x0f, 0x78, 0x05, 0x05, 0x50, 0x50, + 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0xcf, 0x79, 0x01, 0x54, 0x5c, 0x5c, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x84, 0xef, 0x7b, 0xaa, 0xab, 0xab, 0xab +}; +static const BYTE test_dds_volume_data[] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x87, 0x0f, 0x78, 0x05, 0x05, 0x50, 0x50, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x87, 0x0f, 0x78, 0x05, 0x05, 0x50, 0x50, +}; - hr = D3DX11CreateAsyncFileLoaderW(path, &loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +/* + * 4x4x4 24-bit volume dds, 3 mipmaps. Level 0 is red, level 1 is green, level 2 is + * blue. + */ +static const uint8_t dds_volume_24bit_4_4_4[] = +{ + 0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x0f,0x10,0x82,0x00,0x04,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00, + 0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0x00 +}; - ret = DeleteFileW(path); - ok(ret, "Got unexpected ret %#x, error %ld.\n", ret, GetLastError()); +/* + * 8x8 24-bit dds, 4 mipmaps. Level 0 is red, level 1 is green, level 2 is + * blue, and level 3 is black. + */ +static const uint8_t dds_24bit_8_8[] = +{ + 0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x0a,0x00,0x08,0x00,0x00,0x00, + 0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00 +}; - /* File was removed before Load(). */ - hr = ID3DX11DataLoader_Load(loader); - ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); +/* 1x1 wmp image */ +static const BYTE test_wmp[] = +{ + 0x49, 0x49, 0xbc, 0x01, 0x20, 0x00, 0x00, 0x00, 0x24, 0xc3, 0xdd, 0x6f, 0x03, 0x4e, 0xfe, 0x4b, + 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x01, 0xbc, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0xbc, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbc, 0x04, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x81, 0xbc, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x82, 0xbc, 0x0b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x25, 0x06, 0xc0, 0x42, 0x83, 0xbc, + 0x0b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x25, 0x06, 0xc0, 0x42, 0xc0, 0xbc, 0x04, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0xc1, 0xbc, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x92, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x4d, 0x50, 0x48, 0x4f, 0x54, 0x4f, 0x00, 0x11, 0x45, + 0xc0, 0x71, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xc0, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x25, 0xff, 0xff, 0x00, 0x00, 0x01, + 0x01, 0xc8, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x10, 0x10, 0xa6, 0x18, 0x8c, 0x21, + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x4e, 0x0f, 0x3a, 0x4c, 0x94, 0x9d, 0xba, 0x79, 0xe7, 0x38, + 0x4c, 0xcf, 0x14, 0xc3, 0x43, 0x91, 0x88, 0xfb, 0xdc, 0xe0, 0x7c, 0x34, 0x70, 0x9b, 0x28, 0xa9, + 0x18, 0x74, 0x62, 0x87, 0x8e, 0xe4, 0x68, 0x5f, 0xb9, 0xcc, 0x0e, 0xe1, 0x8c, 0x76, 0x3a, 0x9b, + 0x82, 0x76, 0x71, 0x13, 0xde, 0x50, 0xd4, 0x2d, 0xc2, 0xda, 0x1e, 0x3b, 0xa6, 0xa1, 0x62, 0x7b, + 0xca, 0x1a, 0x85, 0x4b, 0x6e, 0x74, 0xec, 0x60 +}; +static const BYTE test_wmp_data[] = +{ + 0xff, 0xff, 0xff, 0xff +}; - /* Create it again. */ - create_testfile(path, test_data1, sizeof(test_data1)); - hr = ID3DX11DataLoader_Load(loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +static const struct test_image +{ + const BYTE *data; + unsigned int size; + const BYTE *expected_data; + D3DX11_IMAGE_INFO expected_info; + D3D11_SRV_DIMENSION expected_srv_dimension; +} +test_image[] = +{ + { + test_bmp_1bpp, sizeof(test_bmp_1bpp), test_bmp_1bpp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_BMP}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_bmp_4bpp, sizeof(test_bmp_4bpp), test_bmp_4bpp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_BMP}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_bmp_8bpp, sizeof(test_bmp_8bpp), test_bmp_8bpp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_BMP}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_bmp_16bpp, sizeof(test_bmp_16bpp), test_bmp_16bpp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_BMP}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_bmp_24bpp, sizeof(test_bmp_24bpp), test_bmp_24bpp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_BMP}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_bmp_32bpp_xrgb, sizeof(test_bmp_32bpp_xrgb), test_bmp_32bpp_xrgb_data, + {2, 2, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_BMP}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_bmp_32bpp_argb, sizeof(test_bmp_32bpp_argb), test_bmp_32bpp_argb_data, + {2, 2, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_BMP}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_png_8bpp_gray, sizeof(test_png_8bpp_gray), test_png_8bpp_gray_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_PNG}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_jpg, sizeof(test_jpg), test_jpg_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_JPG}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_gif, sizeof(test_gif), test_gif_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_GIF}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_tiff, sizeof(test_tiff), test_tiff_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_TIFF}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_alpha, sizeof(test_dds_alpha), test_dds_alpha_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_luminance, sizeof(test_dds_luminance), test_dds_luminance_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_16bpp, sizeof(test_dds_16bpp), test_dds_16bpp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_24bpp, sizeof(test_dds_24bpp), test_dds_24bpp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_32bpp, sizeof(test_dds_32bpp), test_dds_32bpp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_64bpp, sizeof(test_dds_64bpp), test_dds_64bpp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R16G16B16A16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_96bpp, sizeof(test_dds_96bpp), test_dds_96bpp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R32G32B32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_128bpp, sizeof(test_dds_128bpp), test_dds_128bpp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R32G32B32A32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_dxt1, sizeof(test_dds_dxt1), test_dds_dxt1_data, + {4, 4, 1, 1, 1, 0, DXGI_FORMAT_BC1_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_dxt1_4x8, sizeof(test_dds_dxt1_4x8), test_dds_dxt1_4x8_data, + {4, 8, 1, 1, 4, 0, DXGI_FORMAT_BC1_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_dxt2, sizeof(test_dds_dxt2), test_dds_dxt2_data, + {4, 4, 1, 1, 3, 0, DXGI_FORMAT_BC2_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_dxt3, sizeof(test_dds_dxt3), test_dds_dxt3_data, + {1, 3, 1, 1, 2, 0, DXGI_FORMAT_BC2_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_dxt4, sizeof(test_dds_dxt4), test_dds_dxt4_data, + {4, 4, 1, 1, 3, 0, DXGI_FORMAT_BC3_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_dxt5, sizeof(test_dds_dxt5), test_dds_dxt5_data, + {4, 2, 1, 1, 1, 0, DXGI_FORMAT_BC3_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_dxt5_8x8, sizeof(test_dds_dxt5_8x8), test_dds_dxt5_8x8_data, + {8, 8, 1, 1, 4, 0, DXGI_FORMAT_BC3_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_bc4, sizeof(test_dds_bc4), test_dds_bc4_data, + {4, 4, 1, 1, 3, 0, DXGI_FORMAT_BC4_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_bc5, sizeof(test_dds_bc5), test_dds_bc5_data, + {6, 3, 1, 1, 3, 0, DXGI_FORMAT_BC5_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, + { + test_dds_cube, sizeof(test_dds_cube), test_dds_cube_data, + {4, 4, 1, 6, 3, 0x4, DXGI_FORMAT_BC1_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURECUBE + }, + { + test_dds_volume, sizeof(test_dds_volume), test_dds_volume_data, + {4, 4, 2, 1, 3, 0, DXGI_FORMAT_BC2_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, D3DX11_IFF_DDS}, + D3D11_SRV_DIMENSION_TEXTURE3D + }, + { + test_wmp, sizeof(test_wmp), test_wmp_data, + {1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_WMP}, + D3D11_SRV_DIMENSION_TEXTURE2D + }, +}; - /* Already loaded. */ - hr = ID3DX11DataLoader_Load(loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +static const struct test_image_load_info +{ + const uint8_t *data; + uint32_t size; + D3DX11_IMAGE_LOAD_INFO load_info; + HRESULT expected_hr; + + D3D11_SRV_DIMENSION expected_srv_dimension; + D3D11_RESOURCE_DIMENSION expected_type; + union + { + D3D11_TEXTURE2D_DESC desc_2d; + D3D11_TEXTURE3D_DESC desc_3d; + } expected_resource_desc; + D3DX11_IMAGE_INFO expected_info; + BOOL todo_resource_desc; +} +test_image_load_info[] = +{ + /* + * FirstMipLevel set to 1 - Does not match D3DX_SKIP_DDS_MIP_LEVELS + * behavior from d3dx9, image info values represent mip level 0, and + * texture values are pulled from this. The texture data is loaded + * starting from the specified mip level, however. + */ + { + dds_volume_24bit_4_4_4, sizeof(dds_volume_24bit_4_4_4), + { D3DX11_FROM_FILE, D3DX11_DEFAULT, 0, 1, D3DX11_DEFAULT, (D3D11_USAGE)D3DX11_DEFAULT, + D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT }, + S_OK, D3D11_SRV_DIMENSION_TEXTURE3D, D3D11_RESOURCE_DIMENSION_TEXTURE3D, + { .desc_3d = { 4, 4, 4, 3, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 } }, + { 4, 4, 4, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, D3DX11_IFF_DDS }, + }, + /* + * Autogen mips misc flag specified. In the case of a cube texture image, + * the autogen mips flag is OR'd against D3D11_RESOURCE_MISC_TEXTURECUBE, + * even if it isn't specified. + */ + { + test_dds_cube, sizeof(test_dds_cube), + { D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, (D3D11_USAGE)D3DX11_DEFAULT, + (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET), D3DX11_DEFAULT, D3D11_RESOURCE_MISC_GENERATE_MIPS, + DXGI_FORMAT_R8G8B8A8_UNORM, D3DX11_DEFAULT, D3DX11_DEFAULT }, + S_OK, D3D11_SRV_DIMENSION_TEXTURECUBE, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + { .desc_2d = { 4, 4, 3, 6, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, + (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET), 0, + (D3D11_RESOURCE_MISC_GENERATE_MIPS | D3D11_RESOURCE_MISC_TEXTURECUBE) } }, + { 4, 4, 1, 6, 3, DDS_RESOURCE_MISC_TEXTURECUBE, DXGI_FORMAT_BC1_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS }, + }, + /* + * Even with the autogen mips misc flag specified, the mip levels argument + * of load info is respected. + */ + { + test_dds_cube, sizeof(test_dds_cube), + { D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, 2, (D3D11_USAGE)D3DX11_DEFAULT, + (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET), D3DX11_DEFAULT, D3D11_RESOURCE_MISC_GENERATE_MIPS, + DXGI_FORMAT_R8G8B8A8_UNORM, D3DX11_DEFAULT, D3DX11_DEFAULT }, + S_OK, D3D11_SRV_DIMENSION_TEXTURECUBE, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + { .desc_2d = { 4, 4, 2, 6, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, + (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET), 0, + (D3D11_RESOURCE_MISC_GENERATE_MIPS | D3D11_RESOURCE_MISC_TEXTURECUBE) } }, + { 4, 4, 1, 6, 3, DDS_RESOURCE_MISC_TEXTURECUBE, DXGI_FORMAT_BC1_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS }, + }, +}; - ret = DeleteFileW(path); - ok(ret, "Got unexpected ret %#x, error %ld.\n", ret, GetLastError()); +static const struct test_invalid_image_load_info +{ + const uint8_t *data; + uint32_t size; + D3DX11_IMAGE_LOAD_INFO load_info; + HRESULT expected_hr; + HRESULT expected_process_hr; + HRESULT expected_create_device_object_hr; + BOOL todo_hr; + BOOL todo_process_hr; + BOOL todo_create_device_object_hr; +} +test_invalid_image_load_info[] = +{ + /* + * A depth value that isn't D3DX11_FROM_FILE/D3DX11_DEFAULT/0 on a 2D + * texture results in failure. + */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX11_DEFAULT, D3DX11_DEFAULT, 2, D3DX11_DEFAULT, D3DX11_DEFAULT, (D3D11_USAGE)D3DX11_DEFAULT, + D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT }, + E_FAIL, E_FAIL, + }, + /* Invalid filter value. */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, (D3D11_USAGE)D3DX11_DEFAULT, + D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, 7, D3DX11_DEFAULT }, + D3DERR_INVALIDCALL, D3DERR_INVALIDCALL, + }, + /* Invalid mipfilter value, only checked if mips are generated. */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, (D3D11_USAGE)D3DX11_DEFAULT, + D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, 7 }, + S_OK, S_OK, S_OK + }, + /* Invalid mipfilter value. */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { 2, 2, D3DX11_DEFAULT, D3DX11_DEFAULT, 2, (D3D11_USAGE)D3DX11_DEFAULT, + D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, 7 }, + D3DERR_INVALIDCALL, D3DERR_INVALIDCALL, + }, + /* + * Usage/BindFlags/CpuAccessFlags are validated in the call to + * CreateDeviceObject(). + */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3D11_CPU_ACCESS_READ, D3D11_USAGE_DYNAMIC, + D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT }, + E_INVALIDARG, S_OK, E_INVALIDARG, + }, + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3D11_USAGE_DEFAULT, + D3D11_BIND_DEPTH_STENCIL, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT }, + E_INVALIDARG, S_OK, E_INVALIDARG, + }, + /* + * D3D11_RESOURCE_MISC_GENERATE_MIPS requires binding as a shader resource + * and a render target. + */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3D11_USAGE_DEFAULT, + D3DX11_DEFAULT, D3DX11_DEFAULT, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT }, + E_INVALIDARG, S_OK, E_INVALIDARG, + }, + /* Can't set the cube texture flag if the image isn't a cube texture. */ + { + test_dds_32bpp, sizeof(test_dds_32bpp), + { D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3D11_USAGE_DEFAULT, + D3DX11_DEFAULT, D3DX11_DEFAULT, D3D11_RESOURCE_MISC_TEXTURECUBE, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT }, + E_INVALIDARG, S_OK, E_INVALIDARG + }, +}; - /* Already loaded, file removed. */ - hr = ID3DX11DataLoader_Load(loader); - ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); +static void check_image_info(D3DX11_IMAGE_INFO *image_info, const struct test_image *image, unsigned int line) +{ + ok_(__FILE__, line)(image_info->Width == image->expected_info.Width, + "Got unexpected Width %u, expected %u.\n", + image_info->Width, image->expected_info.Width); + ok_(__FILE__, line)(image_info->Height == image->expected_info.Height, + "Got unexpected Height %u, expected %u.\n", + image_info->Height, image->expected_info.Height); + ok_(__FILE__, line)(image_info->Depth == image->expected_info.Depth, + "Got unexpected Depth %u, expected %u.\n", + image_info->Depth, image->expected_info.Depth); + ok_(__FILE__, line)(image_info->ArraySize == image->expected_info.ArraySize, + "Got unexpected ArraySize %u, expected %u.\n", + image_info->ArraySize, image->expected_info.ArraySize); + ok_(__FILE__, line)(image_info->MipLevels == image->expected_info.MipLevels, + "Got unexpected MipLevels %u, expected %u.\n", + image_info->MipLevels, image->expected_info.MipLevels); + ok_(__FILE__, line)(image_info->MiscFlags == image->expected_info.MiscFlags, + "Got unexpected MiscFlags %#x, expected %#x.\n", + image_info->MiscFlags, image->expected_info.MiscFlags); + ok_(__FILE__, line)(image_info->Format == image->expected_info.Format, + "Got unexpected Format %#x, expected %#x.\n", + image_info->Format, image->expected_info.Format); + ok_(__FILE__, line)(image_info->ResourceDimension == image->expected_info.ResourceDimension, + "Got unexpected ResourceDimension %u, expected %u.\n", + image_info->ResourceDimension, image->expected_info.ResourceDimension); + ok_(__FILE__, line)(image_info->ImageFileFormat == image->expected_info.ImageFileFormat, + "Got unexpected ImageFileFormat %u, expected %u.\n", + image_info->ImageFileFormat, image->expected_info.ImageFileFormat); +} - /* Decompress still works. */ - ptr = NULL; - hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(ptr != NULL, "Got unexpected ptr %p.\n", ptr); - ok(size == sizeof(test_data1), "Got unexpected decompressed size.\n"); - if (size == sizeof(test_data1)) - ok(!memcmp(ptr, test_data1, size), "Got unexpected file data.\n"); +#define check_image_info_values(info, width, height, depth, array_size, mip_levels, misc_flags, format, resource_dimension, \ + image_file_format, wine_todo) \ + check_image_info_values_(__LINE__, info, width, height, depth, array_size, mip_levels, misc_flags, format, resource_dimension, \ + image_file_format, wine_todo) +static inline void check_image_info_values_(uint32_t line, const D3DX11_IMAGE_INFO *info, uint32_t width, + uint32_t height, uint32_t depth, uint32_t array_size, uint32_t mip_levels, uint32_t misc_flags, + DXGI_FORMAT format, D3D11_RESOURCE_DIMENSION resource_dimension, D3DX11_IMAGE_FILE_FORMAT image_file_format, + BOOL wine_todo) +{ + const D3DX11_IMAGE_INFO expected_info = { width, height, depth, array_size, mip_levels, misc_flags, format, + resource_dimension, image_file_format }; + BOOL matched; - /* Create it again, with different data. */ - create_testfile(path, test_data2, sizeof(test_data2)); + matched = !memcmp(&expected_info, info, sizeof(*info)); + todo_wine_if(wine_todo) ok_(__FILE__, line)(matched, "Got unexpected image info values.\n"); + if (matched) + return; - hr = ID3DX11DataLoader_Load(loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(wine_todo && info->Width != width) + ok_(__FILE__, line)(info->Width == width, "Expected width %u, got %u.\n", width, info->Width); + todo_wine_if(wine_todo && info->Height != height) + ok_(__FILE__, line)(info->Height == height, "Expected height %u, got %u.\n", height, info->Height); + todo_wine_if(wine_todo && info->Depth != depth) + ok_(__FILE__, line)(info->Depth == depth, "Expected depth %u, got %u.\n", depth, info->Depth); + todo_wine_if(wine_todo && info->ArraySize != array_size) + ok_(__FILE__, line)(info->ArraySize == array_size, "Expected array_size %u, got %u.\n", array_size, + info->ArraySize); + todo_wine_if(wine_todo && info->MipLevels != mip_levels) + ok_(__FILE__, line)(info->MipLevels == mip_levels, "Expected mip_levels %u, got %u.\n", mip_levels, + info->MipLevels); + todo_wine_if(wine_todo && info->MiscFlags != misc_flags) + ok_(__FILE__, line)(info->MiscFlags == misc_flags, "Expected misc_flags %u, got %u.\n", misc_flags, + info->MiscFlags); + ok_(__FILE__, line)(info->Format == format, "Expected texture format %d, got %d.\n", format, info->Format); + todo_wine_if(wine_todo && info->ResourceDimension != resource_dimension) + ok_(__FILE__, line)(info->ResourceDimension == resource_dimension, "Expected resource_dimension %d, got %d.\n", + resource_dimension, info->ResourceDimension); + ok_(__FILE__, line)(info->ImageFileFormat == image_file_format, "Expected image_file_format %d, got %d.\n", + image_file_format, info->ImageFileFormat); +} - ptr = NULL; - hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(ptr != NULL, "Got unexpected ptr %p.\n", ptr); - ok(size == sizeof(test_data2), "Got unexpected decompressed size.\n"); - if (size == sizeof(test_data2)) - ok(!memcmp(ptr, test_data2, size), "Got unexpected file data.\n"); +#define check_texture2d_desc_values(desc, width, height, mip_levels, array_size, format, sample_count, sample_quality, \ + usage, bind_flags, cpu_access_flags, misc_flags, wine_todo) \ + check_texture2d_desc_values_(__LINE__, desc, width, height, mip_levels, array_size, format, sample_count, sample_quality, \ + usage, bind_flags, cpu_access_flags, misc_flags, wine_todo) +static inline void check_texture2d_desc_values_(uint32_t line, const D3D11_TEXTURE2D_DESC *desc, uint32_t width, + uint32_t height, uint32_t mip_levels, uint32_t array_size, DXGI_FORMAT format, uint32_t sample_count, + uint32_t sample_quality, D3D11_USAGE usage, uint32_t bind_flags, uint32_t cpu_access_flags, uint32_t misc_flags, + BOOL wine_todo) +{ + const D3D11_TEXTURE2D_DESC expected_desc = { width, height, mip_levels, array_size, format, { sample_count, sample_quality }, + usage, bind_flags, cpu_access_flags, misc_flags }; + BOOL matched; - hr = ID3DX11DataLoader_Destroy(loader); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + matched = !memcmp(&expected_desc, desc, sizeof(*desc)); + todo_wine_if(wine_todo) ok_(__FILE__, line)(matched, "Got unexpected 2D texture desc values.\n"); + if (matched) + return; - ret = DeleteFileW(path); - ok(ret, "Got unexpected ret %#x, error %ld.\n", ret, GetLastError()); + todo_wine_if(wine_todo && desc->Width != width) + ok_(__FILE__, line)(desc->Width == width, "Expected width %u, got %u.\n", width, desc->Width); + todo_wine_if(wine_todo && desc->Height != height) + ok_(__FILE__, line)(desc->Height == height, "Expected height %u, got %u.\n", height, desc->Height); + todo_wine_if(wine_todo && desc->ArraySize != array_size) + ok_(__FILE__, line)(desc->ArraySize == array_size, "Expected array_size %u, got %u.\n", array_size, + desc->ArraySize); + todo_wine_if(wine_todo && desc->MipLevels != mip_levels) + ok_(__FILE__, line)(desc->MipLevels == mip_levels, "Expected mip_levels %u, got %u.\n", mip_levels, + desc->MipLevels); + ok_(__FILE__, line)(desc->Format == format, "Expected texture format %#x, got %#x.\n", format, desc->Format); + todo_wine_if(wine_todo && desc->SampleDesc.Count != sample_count) + ok_(__FILE__, line)(desc->SampleDesc.Count == sample_count, "Expected sample_count %u, got %u.\n", sample_count, + desc->SampleDesc.Count); + todo_wine_if(wine_todo && desc->SampleDesc.Quality != sample_quality) + ok_(__FILE__, line)(desc->SampleDesc.Quality == sample_quality, "Expected sample_quality %u, got %u.\n", sample_quality, + desc->SampleDesc.Quality); + todo_wine_if(wine_todo && desc->Usage != usage) + ok_(__FILE__, line)(desc->Usage == usage, "Expected usage %u, got %u.\n", usage, + desc->Usage); + todo_wine_if(wine_todo && desc->BindFlags != bind_flags) + ok_(__FILE__, line)(desc->BindFlags == bind_flags, "Expected bind_flags %#x, got %#x.\n", bind_flags, + desc->BindFlags); + todo_wine_if(wine_todo && desc->CPUAccessFlags != cpu_access_flags) + ok_(__FILE__, line)(desc->CPUAccessFlags == cpu_access_flags, "Expected cpu_access_flags %#x, got %#x.\n", + cpu_access_flags, desc->CPUAccessFlags); + todo_wine_if(wine_todo && desc->MiscFlags != misc_flags) + ok_(__FILE__, line)(desc->MiscFlags == misc_flags, "Expected misc_flags %#x, got %#x.\n", misc_flags, + desc->MiscFlags); } -static void test_D3DX11CreateAsyncResourceLoader(void) +#define check_texture3d_desc_values(desc, width, height, depth, mip_levels, format, usage, bind_flags, cpu_access_flags, \ + misc_flags, wine_todo) \ + check_texture3d_desc_values_(__LINE__, desc, width, height, depth, mip_levels, format, usage, bind_flags, \ + cpu_access_flags, misc_flags, wine_todo) +static inline void check_texture3d_desc_values_(uint32_t line, const D3D11_TEXTURE3D_DESC *desc, uint32_t width, + uint32_t height, uint32_t depth, uint32_t mip_levels, DXGI_FORMAT format, D3D11_USAGE usage, uint32_t bind_flags, + uint32_t cpu_access_flags, uint32_t misc_flags, BOOL wine_todo) { - ID3DX11DataLoader *loader; - HRESULT hr; + const D3D11_TEXTURE3D_DESC expected_desc = { width, height, depth, mip_levels, format, usage, bind_flags, + cpu_access_flags, misc_flags }; + BOOL matched; - hr = D3DX11CreateAsyncResourceLoaderA(NULL, NULL, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + matched = !memcmp(&expected_desc, desc, sizeof(*desc)); + todo_wine_if(wine_todo) ok_(__FILE__, line)(matched, "Got unexpected 3D texture desc values.\n"); + if (matched) + return; - hr = D3DX11CreateAsyncResourceLoaderA(NULL, NULL, &loader); - ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(wine_todo && desc->Width != width) + ok_(__FILE__, line)(desc->Width == width, "Expected width %u, got %u.\n", width, desc->Width); + todo_wine_if(wine_todo && desc->Height != height) + ok_(__FILE__, line)(desc->Height == height, "Expected height %u, got %u.\n", height, desc->Height); + todo_wine_if(wine_todo && desc->Depth != depth) + ok_(__FILE__, line)(desc->Depth == depth, "Expected depth %u, got %u.\n", depth, desc->Depth); + todo_wine_if(wine_todo && desc->MipLevels != mip_levels) + ok_(__FILE__, line)(desc->MipLevels == mip_levels, "Expected mip_levels %u, got %u.\n", mip_levels, + desc->MipLevels); + ok_(__FILE__, line)(desc->Format == format, "Expected texture format %#x, got %#x.\n", format, desc->Format); + todo_wine_if(wine_todo && desc->Usage != usage) + ok_(__FILE__, line)(desc->Usage == usage, "Expected usage %u, got %u.\n", usage, + desc->Usage); + todo_wine_if(wine_todo && desc->BindFlags != bind_flags) + ok_(__FILE__, line)(desc->BindFlags == bind_flags, "Expected bind_flags %#x, got %#x.\n", bind_flags, + desc->BindFlags); + todo_wine_if(wine_todo && desc->CPUAccessFlags != cpu_access_flags) + ok_(__FILE__, line)(desc->CPUAccessFlags == cpu_access_flags, "Expected cpu_access_flags %#x, got %#x.\n", + cpu_access_flags, desc->CPUAccessFlags); + todo_wine_if(wine_todo && desc->MiscFlags != misc_flags) + ok_(__FILE__, line)(desc->MiscFlags == misc_flags, "Expected misc_flags %#x, got %#x.\n", misc_flags, + desc->MiscFlags); +} - hr = D3DX11CreateAsyncResourceLoaderA(NULL, "noname", &loader); - ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); +/* + * Taken from the d3d11 tests. If there's a missing resource type or + * texture format checking function, check to see if it exists there first. + */ +struct resource_readback +{ + ID3D11Resource *resource; + D3D11_MAPPED_SUBRESOURCE map_desc; + ID3D11DeviceContext *immediate_context; + uint32_t width, height, depth, sub_resource_idx; +}; - hr = D3DX11CreateAsyncResourceLoaderW(NULL, NULL, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); +static void init_resource_readback(ID3D11Resource *resource, ID3D11Resource *readback_resource, + uint32_t width, uint32_t height, uint32_t depth, uint32_t sub_resource_idx, + ID3D11Device *device, struct resource_readback *rb) +{ + HRESULT hr; - hr = D3DX11CreateAsyncResourceLoaderW(NULL, NULL, &loader); - ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + rb->resource = readback_resource; + rb->width = width; + rb->height = height; + rb->depth = depth; + rb->sub_resource_idx = sub_resource_idx; - hr = D3DX11CreateAsyncResourceLoaderW(NULL, L"noname", &loader); - ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ID3D11Device_GetImmediateContext(device, &rb->immediate_context); + + ID3D11DeviceContext_CopyResource(rb->immediate_context, rb->resource, resource); + if (FAILED(hr = ID3D11DeviceContext_Map(rb->immediate_context, + rb->resource, sub_resource_idx, D3D11_MAP_READ, 0, &rb->map_desc))) + { + trace("Failed to map resource, hr %#lx.\n", hr); + ID3D11Resource_Release(rb->resource); + rb->resource = NULL; + ID3D11DeviceContext_Release(rb->immediate_context); + rb->immediate_context = NULL; + } } -static HRESULT WINAPI test_d3dinclude_open(ID3DInclude *iface, D3D_INCLUDE_TYPE include_type, - const char *filename, const void *parent_data, const void **data, UINT *bytes) +static void get_texture_readback(ID3D11Texture2D *texture, uint32_t sub_resource_idx, + struct resource_readback *rb) { - static const char include1[] = - "#define LIGHT float4(0.0f, 0.2f, 0.5f, 1.0f)\n"; - static const char include2[] = - "#include \"include1.h\"\n" - "float4 light_color = LIGHT;\n"; - char *buffer; + D3D11_TEXTURE2D_DESC texture_desc; + ID3D11Resource *rb_texture; + uint32_t miplevel; + ID3D11Device *device; + HRESULT hr; - trace("filename %s.\n", filename); - trace("parent_data %p: %s.\n", parent_data, parent_data ? (char *)parent_data : "(null)"); + memset(rb, 0, sizeof(*rb)); - if (!strcmp(filename, "include1.h")) - { - buffer = malloc(strlen(include1)); - memcpy(buffer, include1, strlen(include1)); - *bytes = strlen(include1); - ok(include_type == D3D_INCLUDE_LOCAL, "Unexpected include type %d.\n", include_type); - ok(!strncmp(include2, parent_data, strlen(include2)), - "Unexpected parent_data value.\n"); - } - else if (!strcmp(filename, "include\\include2.h")) + ID3D11Texture2D_GetDevice(texture, &device); + + ID3D11Texture2D_GetDesc(texture, &texture_desc); + texture_desc.Usage = D3D11_USAGE_STAGING; + texture_desc.BindFlags = 0; + texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + texture_desc.MiscFlags = 0; + if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, (ID3D11Texture2D **)&rb_texture))) { - buffer = malloc(strlen(include2)); - memcpy(buffer, include2, strlen(include2)); - *bytes = strlen(include2); - ok(!parent_data, "Unexpected parent_data value.\n"); - ok(include_type == D3D_INCLUDE_LOCAL, "Unexpected include type %d.\n", include_type); + trace("Failed to create texture, hr %#lx.\n", hr); + ID3D11Device_Release(device); + return; } - else + + miplevel = sub_resource_idx % texture_desc.MipLevels; + init_resource_readback((ID3D11Resource *)texture, rb_texture, + max(1, texture_desc.Width >> miplevel), + max(1, texture_desc.Height >> miplevel), + 1, sub_resource_idx, device, rb); + + ID3D11Device_Release(device); +} + +static void get_texture3d_readback(ID3D11Texture3D *texture, unsigned int sub_resource_idx, + struct resource_readback *rb) +{ + D3D11_TEXTURE3D_DESC texture_desc; + ID3D11Resource *rb_texture; + unsigned int miplevel; + ID3D11Device *device; + HRESULT hr; + + memset(rb, 0, sizeof(*rb)); + + ID3D11Texture3D_GetDevice(texture, &device); + + ID3D11Texture3D_GetDesc(texture, &texture_desc); + texture_desc.Usage = D3D11_USAGE_STAGING; + texture_desc.BindFlags = 0; + texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + texture_desc.MiscFlags = 0; + if (FAILED(hr = ID3D11Device_CreateTexture3D(device, &texture_desc, NULL, (ID3D11Texture3D **)&rb_texture))) { - ok(0, "Unexpected #include for file %s.\n", filename); - return E_INVALIDARG; + trace("Failed to create texture, hr %#lx.\n", hr); + ID3D11Device_Release(device); + return; } - *data = buffer; - return S_OK; + miplevel = sub_resource_idx % texture_desc.MipLevels; + init_resource_readback((ID3D11Resource *)texture, rb_texture, + max(1, texture_desc.Width >> miplevel), + max(1, texture_desc.Height >> miplevel), + max(1, texture_desc.Depth >> miplevel), + sub_resource_idx, device, rb); + + ID3D11Device_Release(device); } -static HRESULT WINAPI test_d3dinclude_close(ID3DInclude *iface, const void *data) +static void *get_readback_data(struct resource_readback *rb, + uint32_t x, uint32_t y, uint32_t z, unsigned byte_width) { - free((void *)data); - return S_OK; + return (uint8_t *)rb->map_desc.pData + z * rb->map_desc.DepthPitch + y * rb->map_desc.RowPitch + x * byte_width; } -static const struct ID3DIncludeVtbl test_d3dinclude_vtbl = +static uint32_t get_readback_u32(struct resource_readback *rb, uint32_t x, uint32_t y, uint32_t z) { - test_d3dinclude_open, - test_d3dinclude_close -}; + return *(uint32_t *)get_readback_data(rb, x, y, z, sizeof(uint32_t)); +} -struct test_d3dinclude +static uint32_t get_readback_color(struct resource_readback *rb, uint32_t x, uint32_t y, uint32_t z) { - ID3DInclude ID3DInclude_iface; -}; + return get_readback_u32(rb, x, y, z); +} -static void test_D3DX11CompileFromFile(void) +static void release_resource_readback(struct resource_readback *rb) { - struct test_d3dinclude include = {{&test_d3dinclude_vtbl}}; - WCHAR filename[MAX_PATH], directory[MAX_PATH]; + ID3D11DeviceContext_Unmap(rb->immediate_context, rb->resource, rb->sub_resource_idx); + ID3D11Resource_Release(rb->resource); + ID3D11DeviceContext_Release(rb->immediate_context); +} + +static BOOL compare_color(uint32_t c1, uint32_t c2, uint8_t max_diff) +{ + return compare_uint(c1 & 0xff, c2 & 0xff, max_diff) + && compare_uint((c1 >> 8) & 0xff, (c2 >> 8) & 0xff, max_diff) + && compare_uint((c1 >> 16) & 0xff, (c2 >> 16) & 0xff, max_diff) + && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff); +} + +#define check_readback_data_color(a, b, c, d) check_readback_data_color_(__LINE__, a, b, c, d) +static void check_readback_data_color_(uint32_t line, struct resource_readback *rb, + const RECT *rect, uint32_t expected_color, uint8_t max_diff) +{ + uint32_t x = 0, y = 0, z = 0, color = 0; + BOOL all_match = FALSE; + RECT default_rect; + + if (!rect) + { + SetRect(&default_rect, 0, 0, rb->width, rb->height); + rect = &default_rect; + } + + for (z = 0; z < rb->depth; ++z) + { + for (y = rect->top; y < rect->bottom; ++y) + { + for (x = rect->left; x < rect->right; ++x) + { + color = get_readback_color(rb, x, y, z); + if (!compare_color(color, expected_color, max_diff)) + goto done; + } + } + } + all_match = TRUE; + +done: + ok_(__FILE__, line)(all_match, + "Got 0x%08x, expected 0x%08x at (%u, %u, %u), sub-resource %u.\n", + color, expected_color, x, y, z, rb->sub_resource_idx); +} + +#define check_texture_sub_resource_color(a, b, c, d, e) check_texture_sub_resource_color_(__LINE__, a, b, c, d, e) +static void check_texture_sub_resource_color_(uint32_t line, ID3D11Texture2D *texture, + uint32_t sub_resource_idx, const RECT *rect, uint32_t expected_color, uint8_t max_diff) +{ + struct resource_readback rb; + + get_texture_readback(texture, sub_resource_idx, &rb); + check_readback_data_color_(line, &rb, rect, expected_color, max_diff); + release_resource_readback(&rb); +} + +static void set_d3dx11_image_load_info(D3DX11_IMAGE_LOAD_INFO *info, uint32_t width, uint32_t height, uint32_t depth, + uint32_t first_mip_level, uint32_t mip_levels, D3D11_USAGE usage, uint32_t bind_flags, uint32_t cpu_access_flags, + uint32_t misc_flags, DXGI_FORMAT format, uint32_t filter, uint32_t mip_filter, D3DX11_IMAGE_INFO *src_info) +{ + info->Width = width; + info->Height = height; + info->Depth = depth; + info->FirstMipLevel = first_mip_level; + info->MipLevels = mip_levels; + info->Usage = usage; + info->BindFlags = bind_flags; + info->CpuAccessFlags = cpu_access_flags; + info->MiscFlags = misc_flags; + info->Format = format; + info->Filter = filter; + info->MipFilter = mip_filter; + info->pSrcInfo = src_info; +} + +#define check_test_image_load_info_resource(resource, image_load_info) \ + check_test_image_load_info_resource_(__LINE__, resource, image_load_info) +static void check_test_image_load_info_resource_(uint32_t line, ID3D11Resource *resource, + const struct test_image_load_info *image_load_info) +{ + D3D11_RESOURCE_DIMENSION resource_dimension; + HRESULT hr; + + ID3D11Resource_GetType(resource, &resource_dimension); + ok(resource_dimension == image_load_info->expected_type, "Got unexpected ResourceDimension %u, expected %u.\n", + resource_dimension, image_load_info->expected_type); + + switch (resource_dimension) + { + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: + { + const D3D11_TEXTURE2D_DESC *expected_desc_2d = &image_load_info->expected_resource_desc.desc_2d; + D3D11_TEXTURE2D_DESC desc_2d; + ID3D11Texture2D *tex_2d; + + hr = ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture2D, (void **)&tex_2d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID3D11Texture2D_GetDesc(tex_2d, &desc_2d); + check_texture2d_desc_values_(line, &desc_2d, expected_desc_2d->Width, expected_desc_2d->Height, + expected_desc_2d->MipLevels, expected_desc_2d->ArraySize, expected_desc_2d->Format, + expected_desc_2d->SampleDesc.Count, expected_desc_2d->SampleDesc.Quality, expected_desc_2d->Usage, + expected_desc_2d->BindFlags, expected_desc_2d->CPUAccessFlags, expected_desc_2d->MiscFlags, + image_load_info->todo_resource_desc); + ID3D11Texture2D_Release(tex_2d); + break; + } + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: + { + const D3D11_TEXTURE3D_DESC *expected_desc_3d = &image_load_info->expected_resource_desc.desc_3d; + D3D11_TEXTURE3D_DESC desc_3d; + ID3D11Texture3D *tex_3d; + + hr = ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture3D, (void **)&tex_3d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID3D11Texture3D_GetDesc(tex_3d, &desc_3d); + check_texture3d_desc_values_(line, &desc_3d, expected_desc_3d->Width, expected_desc_3d->Height, + expected_desc_3d->Depth, expected_desc_3d->MipLevels, expected_desc_3d->Format, expected_desc_3d->Usage, + expected_desc_3d->BindFlags, expected_desc_3d->CPUAccessFlags, expected_desc_3d->MiscFlags, + image_load_info->todo_resource_desc); + ID3D11Texture3D_Release(tex_3d); + break; + } + + default: + break; + } +} + +#define check_test_image_load_info_srv(srv, image_load_info) \ + check_test_image_load_info_srv_(__LINE__, srv, image_load_info) +static void check_test_image_load_info_srv_(uint32_t line, ID3D11ShaderResourceView *srv, + const struct test_image_load_info *image_load_info) +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc; + ID3D11Resource *resource; + + ID3D11ShaderResourceView_GetDesc(srv, &srv_desc); + ok_(__FILE__, line)(srv_desc.ViewDimension == image_load_info->expected_srv_dimension, "Got unexpected ViewDimension %u, expected %u.\n", + srv_desc.ViewDimension, image_load_info->expected_srv_dimension); + if (srv_desc.ViewDimension != image_load_info->expected_srv_dimension) + return; + + ID3D11ShaderResourceView_GetResource(srv, &resource); + check_test_image_load_info_resource_(line, resource, image_load_info); + ID3D11Resource_Release(resource); + switch (srv_desc.ViewDimension) + { + case D3D11_SRV_DIMENSION_TEXTURE2D: + ok_(__FILE__, line)(srv_desc.Format == image_load_info->expected_resource_desc.desc_2d.Format, + "Got unexpected Format %u, expected %u.\n", srv_desc.Format, image_load_info->expected_resource_desc.desc_2d.Format); + ok_(__FILE__, line)(!srv_desc.Texture2D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture2D.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture2D.MipLevels == image_load_info->expected_resource_desc.desc_2d.MipLevels, + "Unexpected MipLevels %u.\n", srv_desc.Texture2D.MipLevels); + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + ok_(__FILE__, line)(srv_desc.Format == image_load_info->expected_resource_desc.desc_2d.Format, + "Got unexpected Format %u, expected %u.\n", srv_desc.Format, image_load_info->expected_resource_desc.desc_2d.Format); + ok_(__FILE__, line)(!srv_desc.Texture2DArray.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture2DArray.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture2DArray.MipLevels == image_load_info->expected_resource_desc.desc_2d.MipLevels, + "Unexpected MipLevels %u.\n", srv_desc.Texture2DArray.MipLevels); + ok_(__FILE__, line)(!srv_desc.Texture2DArray.FirstArraySlice, "Unexpected FirstArraySlice %u.\n", + srv_desc.Texture2DArray.FirstArraySlice); + ok_(__FILE__, line)(srv_desc.Texture2DArray.ArraySize == image_load_info->expected_resource_desc.desc_2d.ArraySize, + "Unexpected ArraySize %u.\n", srv_desc.Texture2DArray.ArraySize); + break; + + case D3D11_SRV_DIMENSION_TEXTURECUBE: + ok_(__FILE__, line)(srv_desc.Format == image_load_info->expected_resource_desc.desc_2d.Format, + "Got unexpected Format %u, expected %u.\n", srv_desc.Format, image_load_info->expected_resource_desc.desc_2d.Format); + ok_(__FILE__, line)(!srv_desc.TextureCube.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.TextureCube.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.TextureCube.MipLevels == image_load_info->expected_resource_desc.desc_2d.MipLevels, + "Unexpected MipLevels %u.\n", srv_desc.TextureCube.MipLevels); + break; + + case D3D11_SRV_DIMENSION_TEXTURE3D: + ok_(__FILE__, line)(srv_desc.Format == image_load_info->expected_resource_desc.desc_3d.Format, + "Got unexpected Format %u, expected %u.\n", srv_desc.Format, image_load_info->expected_resource_desc.desc_3d.Format); + ok_(__FILE__, line)(!srv_desc.Texture3D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture3D.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture3D.MipLevels == image_load_info->expected_resource_desc.desc_3d.MipLevels, + "Unexpected MipLevels %u.\n", srv_desc.Texture3D.MipLevels); + break; + + default: + ok_(__FILE__, line)(0, "Unexpected ViewDimension %u.\n", srv_desc.ViewDimension); + break; + } +} + +static void check_resource_info(ID3D11Resource *resource, const struct test_image *image, uint32_t line) +{ + unsigned int expected_mip_levels, expected_width, expected_height, max_dimension; + D3D11_RESOURCE_DIMENSION resource_dimension; + D3D11_TEXTURE2D_DESC desc_2d; + D3D11_TEXTURE3D_DESC desc_3d; + ID3D11Texture2D *texture_2d; + ID3D11Texture3D *texture_3d; + HRESULT hr; + + expected_width = image->expected_info.Width; + expected_height = image->expected_info.Height; + if (is_block_compressed(image->expected_info.Format)) + { + expected_width = (expected_width + 3) & ~3; + expected_height = (expected_height + 3) & ~3; + } + expected_mip_levels = 0; + max_dimension = max(expected_width, expected_height); + while (max_dimension) + { + ++expected_mip_levels; + max_dimension >>= 1; + } + + ID3D11Resource_GetType(resource, &resource_dimension); + ok(resource_dimension == image->expected_info.ResourceDimension, + "Got unexpected ResourceDimension %u, expected %u.\n", + resource_dimension, image->expected_info.ResourceDimension); + + switch (resource_dimension) + { + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: + hr = ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture2D, (void **)&texture_2d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID3D11Texture2D_GetDesc(texture_2d, &desc_2d); + ok_(__FILE__, line)(desc_2d.Width == expected_width, + "Got unexpected Width %u, expected %u.\n", + desc_2d.Width, expected_width); + ok_(__FILE__, line)(desc_2d.Height == expected_height, + "Got unexpected Height %u, expected %u.\n", + desc_2d.Height, expected_height); + ok_(__FILE__, line)(desc_2d.MipLevels == expected_mip_levels, + "Got unexpected MipLevels %u, expected %u.\n", + desc_2d.MipLevels, expected_mip_levels); + ok_(__FILE__, line)(desc_2d.ArraySize == image->expected_info.ArraySize, + "Got unexpected ArraySize %u, expected %u.\n", + desc_2d.ArraySize, image->expected_info.ArraySize); + ok_(__FILE__, line)(desc_2d.Format == image->expected_info.Format, + "Got unexpected Format %u, expected %u.\n", + desc_2d.Format, image->expected_info.Format); + ok_(__FILE__, line)(desc_2d.SampleDesc.Count == 1, + "Got unexpected SampleDesc.Count %u, expected %u\n", + desc_2d.SampleDesc.Count, 1); + ok_(__FILE__, line)(desc_2d.SampleDesc.Quality == 0, + "Got unexpected SampleDesc.Quality %u, expected %u\n", + desc_2d.SampleDesc.Quality, 0); + ok_(__FILE__, line)(desc_2d.Usage == D3D11_USAGE_DEFAULT, + "Got unexpected Usage %u, expected %u\n", + desc_2d.Usage, D3D11_USAGE_DEFAULT); + ok_(__FILE__, line)(desc_2d.BindFlags == D3D11_BIND_SHADER_RESOURCE, + "Got unexpected BindFlags %#x, expected %#x\n", + desc_2d.BindFlags, D3D11_BIND_SHADER_RESOURCE); + ok_(__FILE__, line)(desc_2d.CPUAccessFlags == 0, + "Got unexpected CPUAccessFlags %#x, expected %#x\n", + desc_2d.CPUAccessFlags, 0); + ok_(__FILE__, line)(desc_2d.MiscFlags == image->expected_info.MiscFlags, + "Got unexpected MiscFlags %#x, expected %#x.\n", + desc_2d.MiscFlags, image->expected_info.MiscFlags); + + ID3D11Texture2D_Release(texture_2d); + break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: + hr = ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture3D, (void **)&texture_3d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID3D11Texture3D_GetDesc(texture_3d, &desc_3d); + ok_(__FILE__, line)(desc_3d.Width == expected_width, + "Got unexpected Width %u, expected %u.\n", + desc_3d.Width, expected_width); + ok_(__FILE__, line)(desc_3d.Height == expected_height, + "Got unexpected Height %u, expected %u.\n", + desc_3d.Height, expected_height); + ok_(__FILE__, line)(desc_3d.Depth == image->expected_info.Depth, + "Got unexpected Depth %u, expected %u.\n", + desc_3d.Depth, image->expected_info.Depth); + ok_(__FILE__, line)(desc_3d.MipLevels == expected_mip_levels, + "Got unexpected MipLevels %u, expected %u.\n", + desc_3d.MipLevels, expected_mip_levels); + ok_(__FILE__, line)(desc_3d.Format == image->expected_info.Format, + "Got unexpected Format %u, expected %u.\n", + desc_3d.Format, image->expected_info.Format); + ok_(__FILE__, line)(desc_3d.Usage == D3D11_USAGE_DEFAULT, + "Got unexpected Usage %u, expected %u\n", + desc_3d.Usage, D3D11_USAGE_DEFAULT); + ok_(__FILE__, line)(desc_3d.BindFlags == D3D11_BIND_SHADER_RESOURCE, + "Got unexpected BindFlags %#x, expected %#x\n", + desc_3d.BindFlags, D3D11_BIND_SHADER_RESOURCE); + ok_(__FILE__, line)(desc_3d.CPUAccessFlags == 0, + "Got unexpected CPUAccessFlags %#x, expected %#x\n", + desc_3d.CPUAccessFlags, 0); + ok_(__FILE__, line)(desc_3d.MiscFlags == image->expected_info.MiscFlags, + "Got unexpected MiscFlags %#x, expected %#x.\n", + desc_3d.MiscFlags, image->expected_info.MiscFlags); + ID3D11Texture3D_Release(texture_3d); + break; + + default: + break; + } +} + +static void check_texture2d_data(ID3D11Texture2D *texture, const struct test_image *image, unsigned int line) +{ + unsigned int width, height, stride, i, array_slice; + struct resource_readback rb; + D3D11_TEXTURE2D_DESC desc; + const BYTE *expected_data; + BOOL line_match; + + ID3D11Texture2D_GetDesc(texture, &desc); + width = desc.Width; + height = desc.Height; + stride = (width * get_bpp_from_format(desc.Format) + 7) / 8; + if (is_block_compressed(desc.Format)) + { + stride *= 4; + height /= 4; + } + + expected_data = image->expected_data; + for (array_slice = 0; array_slice < desc.ArraySize; ++array_slice) + { + get_texture_readback(texture, array_slice * desc.MipLevels, &rb); + for (i = 0; i < height; ++i) + { + const uint8_t *rb_data = get_readback_data(&rb, 0, i, 0, 0); + + line_match = !memcmp(expected_data + stride * i, rb_data, stride); + todo_wine_if(is_block_compressed(image->expected_info.Format) && image->data != test_dds_dxt5 + && (image->expected_info.Width % 4 != 0 || image->expected_info.Height % 4 != 0)) + ok_(__FILE__, line)(line_match, "Data mismatch for line %u, array slice %u.\n", i, array_slice); + if (!line_match) + break; + } + expected_data += stride * height; + release_resource_readback(&rb); + } +} + +static void check_texture3d_data(ID3D11Texture3D *texture, const struct test_image *image, unsigned int line) +{ + unsigned int width, height, depth, stride, i, j; + struct resource_readback rb; + D3D11_TEXTURE3D_DESC desc; + const BYTE *expected_data; + BOOL line_match; + + ID3D11Texture3D_GetDesc(texture, &desc); + width = desc.Width; + height = desc.Height; + depth = desc.Depth; + stride = (width * get_bpp_from_format(desc.Format) + 7) / 8; + if (is_block_compressed(desc.Format)) + { + stride *= 4; + height /= 4; + } + + expected_data = image->expected_data; + get_texture3d_readback(texture, 0, &rb); + for (j = 0; j < depth; ++j) + { + const BYTE *expected_data_slice = expected_data + ((stride * height) * j); + + for (i = 0; i < height; ++i) + { + const uint8_t *rb_data = get_readback_data(&rb, 0, i, j, 0); + + line_match = !memcmp(expected_data_slice + stride * i, rb_data, stride); + ok_(__FILE__, line)(line_match, "Data mismatch for line %u.\n", i); + if (!line_match) + { + for (unsigned int k = 0; k < stride; ++k) + trace("%02x\n", *((BYTE *)get_readback_data(&rb, k, i, j, 1))); + break; + } + } + } + release_resource_readback(&rb); +} + +static void check_resource_data(ID3D11Resource *resource, const struct test_image *image, unsigned int line) +{ + ID3D11Texture3D *texture3d; + ID3D11Texture2D *texture2d; + + if (SUCCEEDED(ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture3D, (void **)&texture3d))) + { + if (wined3d_opengl && is_block_compressed(image->expected_info.Format)) + skip("Skipping compressed format 3D texture readback test.\n"); + else + check_texture3d_data(texture3d, image, line); + ID3D11Texture3D_Release(texture3d); + } + else if (SUCCEEDED(ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture2D, (void **)&texture2d))) + { + check_texture2d_data(texture2d, image, line); + ID3D11Texture2D_Release(texture2d); + } + else + { + ok(0, "Failed to get 2D or 3D texture interface.\n"); + } +} + +static void check_shader_resource_view_info(ID3D11ShaderResourceView *srv, const struct test_image *image, uint32_t line) +{ + uint32_t expected_mip_levels, expected_width, expected_height, max_dimension; + D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc; + ID3D11Resource *resource; + + expected_width = image->expected_info.Width; + expected_height = image->expected_info.Height; + if (is_block_compressed(image->expected_info.Format)) + { + expected_width = (expected_width + 3) & ~3; + expected_height = (expected_height + 3) & ~3; + } + expected_mip_levels = 0; + max_dimension = max(max(expected_width, expected_height), image->expected_info.Depth); + while (max_dimension) + { + ++expected_mip_levels; + max_dimension >>= 1; + } + + ID3D11ShaderResourceView_GetDesc(srv, &srv_desc); + ok_(__FILE__, line)(srv_desc.Format == image->expected_info.Format, "Got unexpected Format %u, expected %u.\n", + srv_desc.Format, image->expected_info.Format); + ok_(__FILE__, line)(srv_desc.ViewDimension == image->expected_srv_dimension, "Got unexpected ViewDimension %u, expected %u.\n", + srv_desc.ViewDimension, image->expected_srv_dimension); + if (srv_desc.ViewDimension != image->expected_srv_dimension) + return; + + ID3D11ShaderResourceView_GetResource(srv, &resource); + check_resource_info(resource, image, line); + check_resource_data(resource, image, line); + ID3D11Resource_Release(resource); + + switch (srv_desc.ViewDimension) + { + case D3D11_SRV_DIMENSION_TEXTURE2D: + ok_(__FILE__, line)(!srv_desc.Texture2D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture2D.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture2D.MipLevels == expected_mip_levels, "Unexpected MipLevels %u.\n", + srv_desc.Texture2D.MipLevels); + break; + + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + ok_(__FILE__, line)(!srv_desc.Texture2DArray.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture2DArray.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture2DArray.MipLevels == expected_mip_levels, "Unexpected MipLevels %u.\n", + srv_desc.Texture2DArray.MipLevels); + ok_(__FILE__, line)(!srv_desc.Texture2DArray.FirstArraySlice, "Unexpected FirstArraySlice %u.\n", + srv_desc.Texture2DArray.FirstArraySlice); + ok_(__FILE__, line)(srv_desc.Texture2DArray.ArraySize == image->expected_info.ArraySize, "Unexpected ArraySize %u.\n", + srv_desc.Texture2DArray.ArraySize); + break; + + case D3D11_SRV_DIMENSION_TEXTURECUBE: + ok_(__FILE__, line)(!srv_desc.TextureCube.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.TextureCube.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.TextureCube.MipLevels == expected_mip_levels, "Unexpected MipLevels %u.\n", + srv_desc.TextureCube.MipLevels); + break; + + case D3D11_SRV_DIMENSION_TEXTURE3D: + ok_(__FILE__, line)(!srv_desc.Texture3D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", + srv_desc.Texture3D.MostDetailedMip); + ok_(__FILE__, line)(srv_desc.Texture3D.MipLevels == expected_mip_levels, "Unexpected MipLevels %u.\n", + srv_desc.Texture3D.MipLevels); + break; + + default: + ok_(__FILE__, line)(0, "Unexpected ViewDimension %u.\n", srv_desc.ViewDimension); + break; + } +} + +static WCHAR temp_dir[MAX_PATH]; + +static char *get_str_a(const WCHAR *wstr) +{ + static char buffer[MAX_PATH]; + + WideCharToMultiByte(CP_ACP, 0, wstr, -1, buffer, sizeof(buffer), NULL, NULL); + return buffer; +} + +static BOOL create_file(const WCHAR *filename, const void *data, unsigned int size, WCHAR *out_path) +{ + WCHAR path[MAX_PATH]; + DWORD written; + HANDLE file; + + if (!temp_dir[0]) + GetTempPathW(ARRAY_SIZE(temp_dir), temp_dir); + lstrcpyW(path, temp_dir); + lstrcatW(path, filename); + + file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) + return FALSE; + + if (WriteFile(file, data, size, &written, NULL)) + { + CloseHandle(file); + + if (out_path) + lstrcpyW(out_path, path); + return TRUE; + } + + CloseHandle(file); + return FALSE; +} + +static void delete_file(const WCHAR *filename) +{ + WCHAR path[MAX_PATH]; + + lstrcpyW(path, temp_dir); + lstrcatW(path, filename); + DeleteFileW(path); +} + +static HMODULE create_resource_module(const WCHAR *filename, const void *data, unsigned int size) +{ + WCHAR resource_module_path[MAX_PATH], current_module_path[MAX_PATH]; + HANDLE resource; + HMODULE module; + BOOL ret; + + if (!temp_dir[0]) + GetTempPathW(ARRAY_SIZE(temp_dir), temp_dir); + lstrcpyW(resource_module_path, temp_dir); + lstrcatW(resource_module_path, filename); + + GetModuleFileNameW(NULL, current_module_path, ARRAY_SIZE(current_module_path)); + ret = CopyFileW(current_module_path, resource_module_path, FALSE); + ok(ret, "CopyFileW failed, error %lu.\n", GetLastError()); + SetFileAttributesW(resource_module_path, FILE_ATTRIBUTE_NORMAL); + + resource = BeginUpdateResourceW(resource_module_path, TRUE); + UpdateResourceW(resource, (LPCWSTR)RT_RCDATA, filename, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), (void *)data, size); + EndUpdateResourceW(resource, FALSE); + + module = LoadLibraryExW(resource_module_path, NULL, LOAD_LIBRARY_AS_DATAFILE); + + return module; +} + +static void delete_resource_module(const WCHAR *filename, HMODULE module) +{ + WCHAR path[MAX_PATH]; + + FreeLibrary(module); + + lstrcpyW(path, temp_dir); + lstrcatW(path, filename); + DeleteFileW(path); +} + +static BOOL create_directory(const WCHAR *dir) +{ + WCHAR path[MAX_PATH]; + + lstrcpyW(path, temp_dir); + lstrcatW(path, dir); + return CreateDirectoryW(path, NULL); +} + +static void delete_directory(const WCHAR *dir) +{ + WCHAR path[MAX_PATH]; + + lstrcpyW(path, temp_dir); + lstrcatW(path, dir); + RemoveDirectoryW(path); +} + +static ID3D11Device *create_device(void) +{ + HRESULT (WINAPI *pD3D11CreateDevice)(IDXGIAdapter *, D3D_DRIVER_TYPE, HMODULE, UINT, const D3D_FEATURE_LEVEL *, + UINT, UINT, ID3D11Device **, D3D_FEATURE_LEVEL *, ID3D11DeviceContext **); + HMODULE d3d11_mod = LoadLibraryA("d3d11.dll"); + ID3D11Device *device; + + + if (!d3d11_mod) + { + win_skip("d3d11.dll not present\n"); + return NULL; + } + + pD3D11CreateDevice = (void *)GetProcAddress(d3d11_mod, "D3D11CreateDevice"); + if (SUCCEEDED(pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, + NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL))) + return device; + if (SUCCEEDED(pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_WARP, NULL, 0, + NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL))) + return device; + if (SUCCEEDED(pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, 0, + NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL))) + return device; + + return NULL; +} + +static void test_D3DX11CreateAsyncMemoryLoader(void) +{ + ID3DX11DataLoader *loader; + SIZE_T size; + DWORD data; + HRESULT hr; + void *ptr; + + hr = D3DX11CreateAsyncMemoryLoader(NULL, 0, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncMemoryLoader(NULL, 0, &loader); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncMemoryLoader(&data, 0, &loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + size = 100; + hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(ptr == &data, "Got data pointer %p, original %p.\n", ptr, &data); + ok(!size, "Got unexpected data size.\n"); + + /* Load() is no-op. */ + hr = ID3DX11DataLoader_Load(loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataLoader_Destroy(loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + data = 0; + hr = D3DX11CreateAsyncMemoryLoader(&data, sizeof(data), &loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + /* Load() is no-op. */ + hr = ID3DX11DataLoader_Load(loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(ptr == &data, "Got data pointer %p, original %p.\n", ptr, &data); + ok(size == sizeof(data), "Got unexpected data size.\n"); + + hr = ID3DX11DataLoader_Destroy(loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +} + +static void create_testfile(WCHAR *path, const void *data, int data_len) +{ + DWORD written; + HANDLE file; + BOOL ret; + + GetTempPathW(MAX_PATH, path); + lstrcatW(path, L"asyncloader.data"); + + file = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "Test file creation failed, at %s, error %ld.\n", + wine_dbgstr_w(path), GetLastError()); + + ret = WriteFile(file, data, data_len, &written, NULL); + ok(ret, "Write to test file failed.\n"); + + CloseHandle(file); +} + +static void test_D3DX11CreateAsyncFileLoader(void) +{ + static const char test_data1[] = "test data"; + static const char test_data2[] = "more test data"; + ID3DX11DataLoader *loader; + WCHAR path[MAX_PATH]; + SIZE_T size; + HRESULT hr; + void *ptr; + BOOL ret; + + hr = D3DX11CreateAsyncFileLoaderA(NULL, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncFileLoaderA(NULL, &loader); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncFileLoaderA("nonexistentfilename", &loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataLoader_Load(loader); + ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataLoader_Destroy(loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + /* Test file sharing using dummy empty file. */ + create_testfile(path, test_data1, sizeof(test_data1)); + + hr = D3DX11CreateAsyncFileLoaderW(path, &loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ret = DeleteFileW(path); + ok(ret, "Got unexpected ret %#x, error %ld.\n", ret, GetLastError()); + + /* File was removed before Load(). */ + hr = ID3DX11DataLoader_Load(loader); + ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + + /* Create it again. */ + create_testfile(path, test_data1, sizeof(test_data1)); + hr = ID3DX11DataLoader_Load(loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + /* Already loaded. */ + hr = ID3DX11DataLoader_Load(loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ret = DeleteFileW(path); + ok(ret, "Got unexpected ret %#x, error %ld.\n", ret, GetLastError()); + + /* Already loaded, file removed. */ + hr = ID3DX11DataLoader_Load(loader); + ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + + /* Decompress still works. */ + ptr = NULL; + hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(ptr != NULL, "Got unexpected ptr %p.\n", ptr); + ok(size == sizeof(test_data1), "Got unexpected decompressed size.\n"); + if (size == sizeof(test_data1)) + ok(!memcmp(ptr, test_data1, size), "Got unexpected file data.\n"); + + /* Create it again, with different data. */ + create_testfile(path, test_data2, sizeof(test_data2)); + + hr = ID3DX11DataLoader_Load(loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ptr = NULL; + hr = ID3DX11DataLoader_Decompress(loader, &ptr, &size); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(ptr != NULL, "Got unexpected ptr %p.\n", ptr); + ok(size == sizeof(test_data2), "Got unexpected decompressed size.\n"); + if (size == sizeof(test_data2)) + ok(!memcmp(ptr, test_data2, size), "Got unexpected file data.\n"); + + hr = ID3DX11DataLoader_Destroy(loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ret = DeleteFileW(path); + ok(ret, "Got unexpected ret %#x, error %ld.\n", ret, GetLastError()); +} + +static void test_D3DX11CreateAsyncResourceLoader(void) +{ + ID3DX11DataLoader *loader; + HRESULT hr; + + hr = D3DX11CreateAsyncResourceLoaderA(NULL, NULL, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncResourceLoaderA(NULL, NULL, &loader); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncResourceLoaderA(NULL, "noname", &loader); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncResourceLoaderW(NULL, NULL, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncResourceLoaderW(NULL, NULL, &loader); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncResourceLoaderW(NULL, L"noname", &loader); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); +} + +static void test_D3DX11CreateAsyncTextureInfoProcessor(void) +{ + ID3DX11DataProcessor *dp; + D3DX11_IMAGE_INFO info; + HRESULT hr; + int i; + + CoInitialize(NULL); + + hr = D3DX11CreateAsyncTextureInfoProcessor(NULL, NULL); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncTextureInfoProcessor(&info, NULL); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncTextureInfoProcessor(NULL, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + if (0) + { + /* Crashes on native. */ + hr = ID3DX11DataProcessor_Process(dp, (void *)test_image[0].data, test_image[0].size); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + } + + hr = ID3DX11DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncTextureInfoProcessor(&info, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataProcessor_Process(dp, (void *)test_image[0].data, 0); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataProcessor_Process(dp, NULL, test_image[0].size); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + + hr = ID3DX11DataProcessor_Process(dp, (void *)test_image[i].data, test_image[i].size); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + check_image_info(&info, test_image + i, __LINE__); + + winetest_pop_context(); + } + + hr = ID3DX11DataProcessor_CreateDeviceObject(dp, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + CoUninitialize(); +} + +static void test_D3DX11CreateAsyncTextureProcessor(void) +{ + ID3DX11DataProcessor *dp; + ID3D11Resource *resource; + ID3D11Device *device; + HRESULT hr; + int i; + + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + CoInitialize(NULL); + + hr = D3DX11CreateAsyncTextureProcessor(device, NULL, NULL); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncTextureProcessor(NULL, NULL, &dp); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncTextureProcessor(device, NULL, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataProcessor_Process(dp, (void *)test_image[0].data, 0); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataProcessor_Process(dp, NULL, test_image[0].size); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + + hr = D3DX11CreateAsyncTextureProcessor(device, NULL, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataProcessor_Process(dp, (void *)test_image[i].data, test_image[i].size); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + hr = ID3DX11DataProcessor_CreateDeviceObject(dp, (void **)&resource); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_resource_info(resource, test_image + i, __LINE__); + check_resource_data(resource, test_image + i, __LINE__); + ID3D11Resource_Release(resource); + } + + hr = ID3DX11DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + D3DX11_IMAGE_LOAD_INFO load_info = test_load_info->load_info; + + winetest_push_context("Test %u", i); + + hr = D3DX11CreateAsyncTextureProcessor(device, &load_info, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataProcessor_Process(dp, (void *)test_load_info->data, test_load_info->size); + todo_wine_if(test_load_info->todo_process_hr) + ok(hr == test_load_info->expected_process_hr, "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + resource = NULL; + hr = ID3DX11DataProcessor_CreateDeviceObject(dp, (void **)&resource); + todo_wine_if(test_load_info->todo_create_device_object_hr) + ok(hr == test_load_info->expected_create_device_object_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11Resource_Release(resource); + } + + hr = ID3DX11DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + winetest_pop_context(); + } + + CoUninitialize(); + + ok(!ID3D11Device_Release(device), "Unexpected refcount.\n"); +} + +static void test_D3DX11CreateAsyncShaderResourceViewProcessor(void) +{ + ID3D11ShaderResourceView *resource_view; + ID3DX11DataProcessor *dp; + ID3D11Device *device; + HRESULT hr; + uint32_t i; + + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + CoInitialize(NULL); + + hr = D3DX11CreateAsyncShaderResourceViewProcessor(device, NULL, NULL); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncShaderResourceViewProcessor(NULL, NULL, &dp); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11CreateAsyncShaderResourceViewProcessor(device, NULL, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataProcessor_Process(dp, (void *)test_image[0].data, 0); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataProcessor_Process(dp, NULL, test_image[0].size); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + + hr = D3DX11CreateAsyncShaderResourceViewProcessor(device, NULL, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataProcessor_Process(dp, (void *)test_image[i].data, test_image[i].size); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + hr = ID3DX11DataProcessor_CreateDeviceObject(dp, (void **)&resource_view); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + check_shader_resource_view_info(resource_view, test_image + i, __LINE__); + ID3D11ShaderResourceView_Release(resource_view); + } + + hr = ID3DX11DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + D3DX11_IMAGE_LOAD_INFO load_info = test_load_info->load_info; + + winetest_push_context("Test %u", i); + + hr = D3DX11CreateAsyncShaderResourceViewProcessor(device, &load_info, &dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3DX11DataProcessor_Process(dp, (void *)test_load_info->data, test_load_info->size); + todo_wine_if(test_load_info->todo_process_hr) + ok(hr == test_load_info->expected_process_hr, "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + resource_view = NULL; + hr = ID3DX11DataProcessor_CreateDeviceObject(dp, (void **)&resource_view); + todo_wine_if(test_load_info->todo_create_device_object_hr) + ok(hr == test_load_info->expected_create_device_object_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11ShaderResourceView_Release(resource_view); + } + + hr = ID3DX11DataProcessor_Destroy(dp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + winetest_pop_context(); + } + + CoUninitialize(); + + ok(!ID3D11Device_Release(device), "Unexpected refcount.\n"); +} + +static HRESULT WINAPI test_d3dinclude_open(ID3DInclude *iface, D3D_INCLUDE_TYPE include_type, + const char *filename, const void *parent_data, const void **data, UINT *bytes) +{ + static const char include1[] = + "#define LIGHT float4(0.0f, 0.2f, 0.5f, 1.0f)\n"; + static const char include2[] = + "#include \"include1.h\"\n" + "float4 light_color = LIGHT;\n"; + char *buffer; + + trace("filename %s.\n", filename); + trace("parent_data %p: %s.\n", parent_data, parent_data ? (char *)parent_data : "(null)"); + + if (!strcmp(filename, "include1.h")) + { + buffer = malloc(strlen(include1)); + memcpy(buffer, include1, strlen(include1)); + *bytes = strlen(include1); + ok(include_type == D3D_INCLUDE_LOCAL, "Unexpected include type %d.\n", include_type); + ok(!strncmp(include2, parent_data, strlen(include2)), + "Unexpected parent_data value.\n"); + } + else if (!strcmp(filename, "include\\include2.h")) + { + buffer = malloc(strlen(include2)); + memcpy(buffer, include2, strlen(include2)); + *bytes = strlen(include2); + ok(!parent_data, "Unexpected parent_data value.\n"); + ok(include_type == D3D_INCLUDE_LOCAL, "Unexpected include type %d.\n", include_type); + } + else + { + ok(0, "Unexpected #include for file %s.\n", filename); + return E_INVALIDARG; + } + + *data = buffer; + return S_OK; +} + +static HRESULT WINAPI test_d3dinclude_close(ID3DInclude *iface, const void *data) +{ + free((void *)data); + return S_OK; +} + +static const struct ID3DIncludeVtbl test_d3dinclude_vtbl = +{ + test_d3dinclude_open, + test_d3dinclude_close +}; + +struct test_d3dinclude +{ + ID3DInclude ID3DInclude_iface; +}; + +static void test_D3DX11CompileFromFile(void) +{ + struct test_d3dinclude include = {{&test_d3dinclude_vtbl}}; + WCHAR filename[MAX_PATH], directory[MAX_PATH]; ID3D10Blob *blob = NULL, *errors = NULL; CHAR filename_a[MAX_PATH]; HRESULT hr, result; @@ -567,430 +2897,4661 @@ static void test_D3DX11CompileFromFile(void) "#include \"include1.h\"\n" "float4 light_color = LIGHT;\n"; - create_file(L"source.ps", ps_code, strlen(ps_code), filename); - create_directory(L"include"); - create_file(L"include\\include1.h", include1_wrong, strlen(include1_wrong), NULL); - create_file(L"include1.h", include1, strlen(include1), NULL); - create_file(L"include\\include2.h", include2, strlen(include2), NULL); + create_file(L"source.ps", ps_code, strlen(ps_code), filename); + create_directory(L"include"); + create_file(L"include\\include1.h", include1_wrong, strlen(include1_wrong), NULL); + create_file(L"include1.h", include1, strlen(include1), NULL); + create_file(L"include\\include2.h", include2, strlen(include2), NULL); + + hr = D3DX11CompileFromFileW(filename, NULL, &include.ID3DInclude_iface, + "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); + ok(hr == S_OK && hr == result, "Got unexpected hr %#lx, result %#lx.\n", hr, result); + ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + ID3D10Blob_Release(blob); + blob = NULL; + + /* Windows always seems to resolve includes from the initial file location + * instead of using the immediate parent, as it would be the case for + * standard C preprocessor includes. */ + hr = D3DX11CompileFromFileW(filename, NULL, NULL, "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); + ok(hr == S_OK && hr == result, "Got unexpected hr %#lx, result %#lx.\n", hr, result); + ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + ID3D10Blob_Release(blob); + blob = NULL; + + len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, len, NULL, NULL); + hr = D3DX11CompileFromFileA(filename_a, NULL, NULL, "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); + ok(hr == S_OK && hr == result, "Got unexpected hr %#lx, result %#lx.\n", hr, result); + ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + ID3D10Blob_Release(blob); + blob = NULL; + + GetCurrentDirectoryW(MAX_PATH, directory); + SetCurrentDirectoryW(temp_dir); + + hr = D3DX11CompileFromFileW(L"source.ps", NULL, NULL, "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); + ok(hr == S_OK && hr == result, "Got unexpected hr %#lx, result %#lx.\n", hr, result); + ok(!!blob, "Got unexpected blob.\n"); + ok(!errors, "Got unexpected errors.\n"); + ID3D10Blob_Release(blob); + blob = NULL; + + SetCurrentDirectoryW(directory); + + delete_file(L"source.ps"); + delete_file(L"include\\include1.h"); + delete_file(L"include1.h"); + delete_file(L"include\\include2.h"); + delete_directory(L"include"); +} + +static DWORD main_tid; +static DWORD io_tid; + +struct data_object +{ + ID3DX11DataLoader ID3DX11DataLoader_iface; + ID3DX11DataProcessor ID3DX11DataProcessor_iface; + + HANDLE load_started; + HANDLE load_done; + HANDLE decompress_done; + HRESULT load_ret; + + DWORD process_tid; +}; + +static struct data_object *data_object_from_ID3DX11DataLoader(ID3DX11DataLoader *iface) +{ + return CONTAINING_RECORD(iface, struct data_object, ID3DX11DataLoader_iface); +} + +static LONG data_loader_load_count; +static WINAPI HRESULT data_loader_Load(ID3DX11DataLoader *iface) +{ + struct data_object *data_object = data_object_from_ID3DX11DataLoader(iface); + DWORD ret; + + ok(InterlockedDecrement(&data_loader_load_count) >= 0, "Got unexpected call.\n"); + + if (!io_tid) + io_tid = GetCurrentThreadId(); + ok(io_tid != main_tid, "Load called in main thread.\n"); + ok(io_tid == GetCurrentThreadId(), "Load called in wrong thread.\n"); + + SetEvent(data_object->load_started); + ret = WaitForSingleObject(data_object->load_done, INFINITE); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx.\n", ret); + return data_object->load_ret; +} + +static LONG data_loader_decompress_count; +static WINAPI HRESULT data_loader_Decompress(ID3DX11DataLoader *iface, void **data, SIZE_T *bytes) +{ + struct data_object *data_object = data_object_from_ID3DX11DataLoader(iface); + DWORD ret; + + ok(InterlockedDecrement(&data_loader_decompress_count) >= 0, "Got unexpected call.\n"); + ok(!!data, "Got unexpected data %p.\n", data); + ok(!!bytes, "Got unexpected bytes %p.\n", bytes); + + data_object->process_tid = GetCurrentThreadId(); + ok(data_object->process_tid != main_tid, "Decompress called in main thread.\n"); + ok(data_object->process_tid != io_tid, "Decompress called in IO thread.\n"); + + *data = (void *)0xdeadbeef; + *bytes = 0xdead; + ret = WaitForSingleObject(data_object->decompress_done, INFINITE); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx.\n", ret); + return S_OK; +} + +static LONG data_loader_destroy_count; +static WINAPI HRESULT data_loader_Destroy(ID3DX11DataLoader *iface) +{ + ok(InterlockedDecrement(&data_loader_destroy_count) >= 0, "Got unexpected call.\n"); + return S_OK; +} + +static ID3DX11DataLoaderVtbl D3DX11DataLoaderVtbl = +{ + data_loader_Load, + data_loader_Decompress, + data_loader_Destroy +}; + +static struct data_object* data_object_from_ID3DX11DataProcessor(ID3DX11DataProcessor *iface) +{ + return CONTAINING_RECORD(iface, struct data_object, ID3DX11DataProcessor_iface); +} + +static LONG data_processor_process_count; +static HRESULT WINAPI data_processor_Process(ID3DX11DataProcessor *iface, void *data, SIZE_T bytes) +{ + struct data_object *data_object = data_object_from_ID3DX11DataProcessor(iface); + + ok(InterlockedDecrement(&data_processor_process_count) >= 0, "Got unexpected call.\n"); + ok(data_object->process_tid == GetCurrentThreadId(), "Process called in unexpected thread.\n"); + + ok(data == (void *)0xdeadbeef, "Got unexpected data %p.\n", data); + ok(bytes == 0xdead, "Got unexpected bytes %Iu.\n", bytes); + return S_OK; +} + +static LONG data_processor_create_count; +static HRESULT WINAPI data_processor_CreateDeviceObject(ID3DX11DataProcessor *iface, void **object) +{ + ok(InterlockedDecrement(&data_processor_create_count) >= 0, "Got unexpected call.\n"); + ok(main_tid == GetCurrentThreadId(), "CreateDeviceObject not called in main thread.\n"); + + *object = (void *)0xdeadf00d; + return S_OK; +} + +static LONG data_processor_destroy_count; +static HRESULT WINAPI data_processor_Destroy(ID3DX11DataProcessor *iface) +{ + struct data_object *data_object = data_object_from_ID3DX11DataProcessor(iface); + + ok(InterlockedDecrement(&data_processor_destroy_count) >= 0, "Got unexpected call.\n"); + + CloseHandle(data_object->load_started); + CloseHandle(data_object->load_done); + CloseHandle(data_object->decompress_done); + free(data_object); + return S_OK; +} + +static ID3DX11DataProcessorVtbl D3DX11DataProcessorVtbl = +{ + data_processor_Process, + data_processor_CreateDeviceObject, + data_processor_Destroy +}; + +static struct data_object *create_data_object(HRESULT load_ret) +{ + struct data_object *data_object = malloc(sizeof(*data_object)); + + data_object->ID3DX11DataLoader_iface.lpVtbl = &D3DX11DataLoaderVtbl; + data_object->ID3DX11DataProcessor_iface.lpVtbl = &D3DX11DataProcessorVtbl; + + data_object->load_started = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!data_object->load_started, "CreateEvent failed, error %lu.\n", GetLastError()); + data_object->load_done = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!data_object->load_done, "CreateEvent failed, error %lu.\n", GetLastError()); + data_object->decompress_done = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!data_object->decompress_done, "CreateEvent failed, error %lu.\n", GetLastError()); + data_object->load_ret = load_ret; + + return data_object; +} + +static void test_D3DX11CreateThreadPump(void) +{ + UINT io_count, process_count, device_count, count; + struct data_object *data_object[2]; + ID3DX11DataProcessor *processor; + D3DX11_IMAGE_INFO image_info; + ID3DX11DataLoader *loader; + HRESULT hr, work_item_hr; + ID3D11Resource *resource; + ID3DX11ThreadPump *pump; + ID3D11Device *device; + SYSTEM_INFO info; + void *object; + DWORD ret; + int i; + + main_tid = GetCurrentThreadId(); + + hr = D3DX11CreateThreadPump(1024, 0, &pump); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = D3DX11CreateThreadPump(0, 1024, &pump); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + GetSystemInfo(&info); + if (info.dwNumberOfProcessors > 1) + hr = D3DX11CreateThreadPump(0, 0, &pump); + else + hr = D3DX11CreateThreadPump(0, 2, &pump); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + count = ID3DX11ThreadPump_GetWorkItemCount(pump); + ok(!count, "GetWorkItemCount returned %u.\n", count); + hr = ID3DX11ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!io_count, "Got unexpected io_count %u.\n", io_count); + ok(!process_count, "Got unexpected process_count %u.\n", process_count); + ok(!device_count, "Got unexpected device_count %u.\n", device_count); + + data_object[0] = create_data_object(E_NOTIMPL); + data_object[1] = create_data_object(S_OK); + + data_loader_load_count = 1; + hr = ID3DX11ThreadPump_AddWorkItem(pump, &data_object[0]->ID3DX11DataLoader_iface, + &data_object[0]->ID3DX11DataProcessor_iface, &work_item_hr, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ret = WaitForSingleObject(data_object[0]->load_started, INFINITE); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx.\n", ret); + ok(!data_loader_load_count, "Got unexpected data_loader_load_count %ld.\n", + data_loader_load_count); + count = ID3DX11ThreadPump_GetWorkItemCount(pump); + ok(count == 1, "GetWorkItemCount returned %u.\n", count); + hr = ID3DX11ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!io_count, "Got unexpected io_count %u.\n", io_count); + ok(!process_count, "Got unexpected process_count %u.\n", process_count); + ok(!device_count, "Got unexpected device_count %u.\n", device_count); + + hr = ID3DX11ThreadPump_AddWorkItem(pump, &data_object[1]->ID3DX11DataLoader_iface, + &data_object[1]->ID3DX11DataProcessor_iface, NULL, &object); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ret = WaitForSingleObject(data_object[0]->load_started, 50); + ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %#lx.\n", ret); + count = ID3DX11ThreadPump_GetWorkItemCount(pump); + ok(count == 2, "GetWorkItemCount returned %u.\n", count); + hr = ID3DX11ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(io_count == 1, "Got unexpected io_count %u.\n", io_count); + ok(!process_count, "Got unexpected process_count %u.\n", process_count); + ok(!device_count, "Got unexpected device_count %u.\n", device_count); + + data_loader_load_count = 1; + data_loader_destroy_count = 1; + data_processor_destroy_count = 1; + SetEvent(data_object[0]->load_done); + ret = WaitForSingleObject(data_object[1]->load_started, INFINITE); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx.\n", ret); + ok(work_item_hr == E_NOTIMPL, "Got unexpected work_item_hr %#lx.\n", work_item_hr); + ok(!data_loader_destroy_count, "Got unexpected data_loader_destroy_count %ld.\n", + data_loader_destroy_count); + ok(!data_processor_destroy_count, "Got unexpected data_processor_destroy_count %ld.\n", + data_processor_destroy_count); + ok(!data_loader_load_count, "Got unexpected data_loader_load_count %ld.\n", + data_loader_load_count); + + data_loader_decompress_count = 1; + data_processor_process_count = 1; + SetEvent(data_object[1]->load_done); + SetEvent(data_object[1]->decompress_done); + + data_processor_create_count = 1; + data_loader_destroy_count = 1; + data_processor_destroy_count = 1; + hr = ID3DX11ThreadPump_WaitForAllItems(pump); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(object == (void *)0xdeadf00d, "Got unexpected object %p.\n", object); + ok(!data_loader_decompress_count, "Got unexpected data_loader_decompress_count %ld.\n", + data_loader_decompress_count); + ok(!data_processor_process_count, "Got unexpected data_processor_process_count %ld.\n", + data_processor_process_count); + ok(!data_processor_create_count, "Got unexpected data_processor_create_count %ld.\n", + data_processor_create_count); + ok(!data_loader_destroy_count, "Got unexpected data_loader_destroy_count %ld.\n", + data_loader_destroy_count); + ok(!data_processor_destroy_count, "Got unexpected data_processor_destroy_count %ld.\n", + data_processor_destroy_count); + + data_object[0] = create_data_object(S_OK); + data_object[1] = create_data_object(S_OK); + SetEvent(data_object[0]->load_done); + SetEvent(data_object[1]->load_done); + SetEvent(data_object[1]->decompress_done); + + data_loader_load_count = 2; + data_loader_decompress_count = 2; + data_processor_process_count = 1; + hr = ID3DX11ThreadPump_AddWorkItem(pump, &data_object[0]->ID3DX11DataLoader_iface, + &data_object[0]->ID3DX11DataProcessor_iface, NULL, &object); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11ThreadPump_AddWorkItem(pump, &data_object[1]->ID3DX11DataLoader_iface, + &data_object[1]->ID3DX11DataProcessor_iface, NULL, &object); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + for (;;) + { + hr = ID3DX11ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + if (hr != S_OK || device_count) + break; + Sleep(1); + } + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!io_count, "Got unexpected io_count %u.\n", io_count); + ok(!process_count, "Got unexpected process_count %u.\n", process_count); + ok(device_count == 1, "Got unexpected device_count %u.\n", device_count); + ok(!data_loader_load_count, "Got unexpected data_loader_load_count %ld.\n", + data_loader_load_count); + ok(!data_loader_decompress_count, "Got unexpected data_loader_decompress_count %ld.\n", + data_loader_decompress_count); + ok(!data_processor_process_count, "Got unexpected data_processor_process_count %ld.\n", + data_processor_process_count); + + hr = ID3DX11ThreadPump_ProcessDeviceWorkItems(pump, 0); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!io_count, "Got unexpected io_count %u.\n", io_count); + ok(!process_count, "Got unexpected process_count %u.\n", process_count); + ok(device_count == 1, "Got unexpected device_count %u.\n", device_count); + + data_processor_create_count = 1; + data_loader_destroy_count = 1; + data_processor_destroy_count = 1; + hr = ID3DX11ThreadPump_ProcessDeviceWorkItems(pump, 1); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!io_count, "Got unexpected io_count %u.\n", io_count); + ok(!process_count, "Got unexpected process_count %u.\n", process_count); + ok(!device_count, "Got unexpected device_count %u.\n", device_count); + ok(!data_processor_create_count, "Got unexpected data_processor_create_count %ld.\n", + data_processor_create_count); + ok(!data_loader_destroy_count, "Got unexpected data_loader_destroy_count %ld.\n", + data_loader_destroy_count); + ok(!data_processor_destroy_count, "Got unexpected data_processor_destroy_count %ld.\n", + data_processor_destroy_count); + + data_processor_process_count = 1; + data_loader_destroy_count = 1; + data_processor_destroy_count = 1; + SetEvent(data_object[0]->decompress_done); + hr = ID3DX11ThreadPump_PurgeAllItems(pump); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + data_processor_process_count = 0; + ok(!data_loader_destroy_count, "Got unexpected data_loader_destroy_count %ld.\n", + data_loader_destroy_count); + ok(!data_processor_destroy_count, "Got unexpected data_processor_destroy_count %ld.\n", + data_processor_destroy_count); + + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + ID3DX11ThreadPump_Release(pump); + return; + } + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + + hr = D3DX11CreateAsyncMemoryLoader(test_image[i].data, test_image[i].size, &loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = D3DX11CreateAsyncTextureInfoProcessor(&image_info, &processor); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, &work_item_hr, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11ThreadPump_WaitForAllItems(pump); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(work_item_hr == S_OK || (work_item_hr == E_FAIL + && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", work_item_hr); + if (work_item_hr == S_OK) + check_image_info(&image_info, test_image + i, __LINE__); + + hr = D3DX11CreateAsyncMemoryLoader(test_image[i].data, test_image[i].size, &loader); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = D3DX11CreateAsyncTextureProcessor(device, NULL, &processor); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, &work_item_hr, (void **)&resource); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3DX11ThreadPump_WaitForAllItems(pump); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(work_item_hr == S_OK || (work_item_hr == E_FAIL + && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", work_item_hr); + if (work_item_hr == S_OK) + { + check_resource_info(resource, test_image + i, __LINE__); + check_resource_data(resource, test_image + i, __LINE__); + ID3D11Resource_Release(resource); + } + + winetest_pop_context(); + } + + ok(!ID3D11Device_Release(device), "Got unexpected refcount.\n"); + + ret = ID3DX11ThreadPump_Release(pump); + ok(!ret, "Got unexpected refcount %lu.\n", ret); +} + +/* dds_header.flags */ +#define DDS_CAPS 0x00000001 +#define DDS_HEIGHT 0x00000002 +#define DDS_WIDTH 0x00000004 +#define DDS_PITCH 0x00000008 +#define DDS_PIXELFORMAT 0x00001000 +#define DDS_MIPMAPCOUNT 0x00020000 +#define DDS_LINEARSIZE 0x00080000 +#define DDS_DEPTH 0x00800000 + +/* dds_header.caps */ +#define DDSCAPS_ALPHA 0x00000002 +#define DDS_CAPS_COMPLEX 0x00000008 +#define DDS_CAPS_TEXTURE 0x00001000 +#define DDSCAPS_MIPMAP 0x00400000 + +/* dds_header.caps2 */ +#define DDS_CAPS2_VOLUME 0x00200000 +#define DDS_CAPS2_CUBEMAP 0x00000200 +#define DDS_CAPS2_CUBEMAP_POSITIVEX 0x00000400 +#define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x00000800 +#define DDS_CAPS2_CUBEMAP_POSITIVEY 0x00001000 +#define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x00002000 +#define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x00004000 +#define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x00008000 +#define DDS_CAPS2_CUBEMAP_ALL_FACES ( DDS_CAPS2_CUBEMAP_POSITIVEX | DDS_CAPS2_CUBEMAP_NEGATIVEX \ + | DDS_CAPS2_CUBEMAP_POSITIVEY | DDS_CAPS2_CUBEMAP_NEGATIVEY \ + | DDS_CAPS2_CUBEMAP_POSITIVEZ | DDS_CAPS2_CUBEMAP_NEGATIVEZ ) + +/* dds_pixel_format.flags */ +#define DDS_PF_ALPHA 0x00000001 +#define DDS_PF_ALPHA_ONLY 0x00000002 +#define DDS_PF_FOURCC 0x00000004 +#define DDS_PF_INDEXED 0x00000020 +#define DDS_PF_RGB 0x00000040 +#define DDS_PF_LUMINANCE 0x00020000 +#define DDS_PF_BUMPLUMINANCE 0x00040000 +#define DDS_PF_BUMPDUDV 0x00080000 + +struct dds_pixel_format +{ + DWORD size; + DWORD flags; + DWORD fourcc; + DWORD bpp; + DWORD rmask; + DWORD gmask; + DWORD bmask; + DWORD amask; +}; + +struct dds_header +{ + DWORD size; + DWORD flags; + DWORD height; + DWORD width; + DWORD pitch_or_linear_size; + DWORD depth; + DWORD miplevels; + DWORD reserved[11]; + struct dds_pixel_format pixel_format; + DWORD caps; + DWORD caps2; + DWORD caps3; + DWORD caps4; + DWORD reserved2; +}; + +struct dds_header_dxt10 +{ + DWORD dxgi_format; + DWORD resource_dimension; + DWORD misc_flag; + DWORD array_size; + DWORD misc_flags2; +}; + +/* fills dds_header with reasonable default values */ +static void fill_dds_header(struct dds_header *header) +{ + memset(header, 0, sizeof(*header)); + + header->size = sizeof(*header); + header->flags = DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT; + header->height = 4; + header->width = 4; + header->pixel_format.size = sizeof(header->pixel_format); + /* X8R8G8B8 */ + header->pixel_format.flags = DDS_PF_RGB; + header->pixel_format.fourcc = 0; + header->pixel_format.bpp = 32; + header->pixel_format.rmask = 0xff0000; + header->pixel_format.gmask = 0x00ff00; + header->pixel_format.bmask = 0x0000ff; + header->pixel_format.amask = 0; + header->caps = DDS_CAPS_TEXTURE; +} + +static void set_dxt10_dds_header(struct dds_header *header, uint32_t append_flags, uint32_t width, uint32_t height, + uint32_t depth, uint32_t mip_levels, uint32_t pitch, uint32_t caps, uint32_t caps2) +{ + memset(header, 0, sizeof(*header)); + + header->size = sizeof(*header); + header->flags = DDS_CAPS | DDS_PIXELFORMAT | append_flags; + header->height = height; + header->width = width; + header->depth = depth; + header->miplevels = mip_levels; + header->pitch_or_linear_size = pitch; + header->pixel_format.size = sizeof(header->pixel_format); + header->pixel_format.flags = DDS_PF_FOURCC; + header->pixel_format.fourcc = MAKEFOURCC('D','X','1','0'); + header->caps = caps; + header->caps2 = caps2; +} + +static void set_dds_header_dxt10(struct dds_header_dxt10 *dxt10, DXGI_FORMAT format, uint32_t resource_dimension, + uint32_t misc_flag, uint32_t array_size, uint32_t misc_flags2) +{ + dxt10->dxgi_format = format; + dxt10->resource_dimension = resource_dimension; + dxt10->misc_flag = misc_flag; + dxt10->array_size = array_size; + dxt10->misc_flags2 = misc_flags2; +} + +#define check_dds_pixel_format(flags, fourcc, bpp, rmask, gmask, bmask, amask, format) \ + check_dds_pixel_format_(__LINE__, flags, fourcc, bpp, rmask, gmask, bmask, amask, format) +static void check_dds_pixel_format_(unsigned int line, DWORD flags, DWORD fourcc, DWORD bpp, + DWORD rmask, DWORD gmask, DWORD bmask, DWORD amask, DXGI_FORMAT expected_format) +{ + D3DX11_IMAGE_INFO info; + HRESULT hr; + struct + { + DWORD magic; + struct dds_header header; + PALETTEENTRY palette[256]; + BYTE data[256]; + } dds; + + dds.magic = MAKEFOURCC('D','D','S',' '); + fill_dds_header(&dds.header); + dds.header.pixel_format.flags = flags; + dds.header.pixel_format.fourcc = fourcc; + dds.header.pixel_format.bpp = bpp; + dds.header.pixel_format.rmask = rmask; + dds.header.pixel_format.gmask = gmask; + dds.header.pixel_format.bmask = bmask; + dds.header.pixel_format.amask = amask; + memset(dds.data, 0, sizeof(dds.data)); + + hr = D3DX11GetImageInfoFromMemory(&dds, sizeof(dds), NULL, &info, NULL); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx for pixel format %#x.\n", hr, expected_format); + if (SUCCEEDED(hr)) + { + ok_(__FILE__, line)(info.Format == expected_format, "Unexpected format %#x, expected %#x\n", + info.Format, expected_format); + } +} + +#define check_dds_pixel_format_unsupported(flags, fourcc, bpp, rmask, gmask, bmask, amask, expected_hr) \ + check_dds_pixel_format_unsupported_(__LINE__, flags, fourcc, bpp, rmask, gmask, bmask, amask, expected_hr) +static void check_dds_pixel_format_unsupported_(unsigned int line, DWORD flags, DWORD fourcc, DWORD bpp, + DWORD rmask, DWORD gmask, DWORD bmask, DWORD amask, HRESULT expected_hr) +{ + D3DX11_IMAGE_INFO info; + HRESULT hr; + struct + { + DWORD magic; + struct dds_header header; + PALETTEENTRY palette[256]; + BYTE data[256]; + } dds; + + dds.magic = MAKEFOURCC('D','D','S',' '); + fill_dds_header(&dds.header); + dds.header.pixel_format.flags = flags; + dds.header.pixel_format.fourcc = fourcc; + dds.header.pixel_format.bpp = bpp; + dds.header.pixel_format.rmask = rmask; + dds.header.pixel_format.gmask = gmask; + dds.header.pixel_format.bmask = bmask; + dds.header.pixel_format.amask = amask; + memset(dds.data, 0, sizeof(dds.data)); + + hr = D3DX11GetImageInfoFromMemory(&dds, sizeof(dds), NULL, &info, NULL); + ok_(__FILE__, line)(hr == expected_hr, "Got unexpected hr %#lx, expected %#lx.\n", hr, expected_hr); +} + +#define check_dds_dx10_format(format, expected_format, wine_todo) \ + check_dds_dx10_format_(__LINE__, format, expected_format, wine_todo) +static void check_dds_dx10_format_(uint32_t line, DXGI_FORMAT format, DXGI_FORMAT expected_format, BOOL wine_todo) +{ + const uint32_t stride = (4 * get_bpp_from_format(format) + 7) / 8; + D3DX11_IMAGE_INFO info; + HRESULT hr; + struct + { + DWORD magic; + struct dds_header header; + struct dds_header_dxt10 dxt10; + BYTE data[256]; + } dds; + + dds.magic = MAKEFOURCC('D','D','S',' '); + set_dxt10_dds_header(&dds.header, 0, 4, 4, 1, 1, stride, 0, 0); + set_dds_header_dxt10(&dds.dxt10, format, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0); + + hr = D3DX11GetImageInfoFromMemory(&dds, sizeof(dds), NULL, &info, NULL); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx for DXGI format %#x.\n", hr, format); + if (SUCCEEDED(hr)) + { + todo_wine_if(wine_todo) ok_(__FILE__, line)(info.Format == expected_format, "Unexpected format %#x, expected %#x.\n", + info.Format, expected_format); + } +} + +#define check_dds_dx10_format_unsupported(format, expected_hr) \ + check_dds_dx10_format_unsupported_(__LINE__, format, expected_hr) +static void check_dds_dx10_format_unsupported_(uint32_t line, DXGI_FORMAT format, HRESULT expected_hr) +{ + const uint32_t stride = (4 * get_bpp_from_format(format) + 7) / 8; + D3DX11_IMAGE_INFO info; + HRESULT hr; + struct + { + DWORD magic; + struct dds_header header; + struct dds_header_dxt10 dxt10; + BYTE data[256]; + } dds; + + dds.magic = MAKEFOURCC('D','D','S',' '); + set_dxt10_dds_header(&dds.header, 0, 4, 4, 1, 1, stride, 0, 0); + set_dds_header_dxt10(&dds.dxt10, format, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0); + + hr = D3DX11GetImageInfoFromMemory(&dds, sizeof(dds), NULL, &info, NULL); + ok_(__FILE__, line)(hr == expected_hr, "Got unexpected hr %#lx for DXGI format %#x.\n", hr, format); +} + +static void test_dds_header_image_info(void) +{ + struct expected + { + HRESULT hr; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t array_size; + uint32_t mip_levels; + uint32_t misc_flags; + DXGI_FORMAT format; + D3D11_RESOURCE_DIMENSION resource_dimension; + }; + static const struct + { + uint32_t flags; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t row_pitch; + uint32_t mip_levels; + uint32_t caps; + uint32_t caps2; + struct expected expected; + uint32_t pixel_data_size; + BOOL todo_hr; + BOOL todo_info; + } tests[] = { + /* File size validation isn't done on d3dx10. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT), 4, 4, 1, (4 * 4), 3, 0, 0, + { S_OK, 4, 4, 1, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, }, 0, }, + /* Depth value set to 4, but no caps bits are set. Depth is ignored. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT), 4, 4, 4, (4 * 4), 3, 0, 0, + { S_OK, 4, 4, 1, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, }, 292 }, + /* The volume texture caps2 field is ignored. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT), 4, 4, 4, (4 * 4), 3, + (DDS_CAPS_TEXTURE | DDS_CAPS_COMPLEX), DDS_CAPS2_VOLUME, + { S_OK, 4, 4, 1, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, }, 292 }, + /* + * The DDS_DEPTH flag is the only thing checked to determine if a DDS + * file represents a 3D texture. + */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT | DDS_DEPTH), 4, 4, 4, (4 * 4), 3, + 0, 0, + { S_OK, 4, 4, 4, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, }, 292 }, + /* Even if the depth field is set to 0, it's still a 3D texture. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT | DDS_DEPTH), 4, 4, 0, (4 * 4), 3, + 0, 0, + { S_OK, 4, 4, 1, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, }, 292 }, + /* The DDS_DEPTH flag overrides cubemap caps. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT | DDS_DEPTH), 4, 4, 4, (4 * 4), 3, + (DDS_CAPS_TEXTURE | DDS_CAPS_COMPLEX), (DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES), + { S_OK, 4, 4, 4, 1, 3, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, }, 292 }, + /* Cubemap where width field does not equal height. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT), 4, 5, 1, (4 * 4), 1, + (DDS_CAPS_TEXTURE | DDS_CAPS_COMPLEX), (DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES), + { S_OK, 4, 5, 1, 6, 1, D3D11_RESOURCE_MISC_TEXTURECUBE, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, }, (80 * 6) }, + /* Partial cubemaps are not supported. */ + { (DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT), 4, 4, 1, (4 * 4), 1, + (DDS_CAPS_TEXTURE | DDS_CAPS_COMPLEX), (DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_POSITIVEX), + { E_FAIL, }, (64 * 6), }, + }; + static const struct + { + uint32_t append_flags; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t row_pitch; + uint32_t mip_levels; + uint32_t caps; + uint32_t caps2; + struct dds_header_dxt10 dxt10; + struct expected expected; + uint32_t pixel_data_size; + BOOL todo_hr; + BOOL todo_info; + } dxt10_tests[] = { + /* File size validation isn't done on d3dx10. */ + { 0, 4, 4, 0, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0, }, + { S_OK, 4, 4, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, }, 0, }, + /* + * Setting the misc_flags2 field to anything other than 0 results in + * E_FAIL. + */ + { 0, 4, 4, 0, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 1, }, + { E_FAIL }, (4 * 4 * 4), }, + /* + * The misc_flags field isn't passed through directly, only the + * cube texture flag is (if it's set). + */ + { 0, 4, 4, 0, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0xfffffffb, 1, 0, }, + { S_OK, 4, 4, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, }, (4 * 4 * 4) }, + /* Resource dimension field of the header isn't validated. */ + { 0, 4, 4, 0, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, 500, 0, 1, 0, }, + { S_OK, 4, 4, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, 500, }, (4 * 4 * 4), .todo_hr = TRUE }, + /* Depth value of 2, but D3D11_RESOURCE_DIMENSION_TEXTURE2D. */ + { DDS_DEPTH, 4, 4, 2, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0, }, + { S_OK, 4, 4, 2, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, }, (4 * 4 * 4 * 2) }, + /* Depth field value is ignored if DDS_DEPTH isn't set. */ + { 0, 4, 4, 2, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0, }, + { S_OK, 4, 4, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, }, (4 * 4 * 4 * 2), }, + /* + * 3D texture with an array size larger than 1. Technically there's no + * such thing as a 3D texture array, but it succeeds. + */ + { DDS_DEPTH, 4, 4, 2, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 2, 0, }, + { S_OK, 4, 4, 2, 2, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, }, (4 * 4 * 4 * 2 * 2) }, + /* Cubemap caps are ignored for DXT10 files. */ + { 0, 4, 4, 1, (4 * 4), 1, 0, DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0, }, + { S_OK, 4, 4, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D }, (4 * 4 * 4 * 6) }, + /* Array size value is multiplied by 6 for cubemap files. */ + { 0, 4, 4, 1, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 2, 0, }, + { S_OK, 4, 4, 1, 12, 1, D3D11_RESOURCE_MISC_TEXTURECUBE, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D }, (4 * 4 * 4 * 12) }, + /* Resource dimension is validated for cube textures. */ + { 0, 4, 4, 1, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, DDS_RESOURCE_MISC_TEXTURECUBE, 2, 0, }, + { E_FAIL }, (4 * 4 * 4 * 12), }, + /* 1D Texture cube, invalid. */ + { 0, 4, 4, 1, (4 * 4), 1, 0, 0, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, DDS_RESOURCE_MISC_TEXTURECUBE, 2, 0, }, + { E_FAIL }, (4 * 4 * 4 * 12), }, + }; + D3DX11_IMAGE_INFO info; + uint32_t i, file_size; + struct + { + DWORD magic; + struct dds_header header; + struct dds_header_dxt10 dxt10; + } dds; + HRESULT hr; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("Test %u", i); + file_size = sizeof(dds.magic) + sizeof(dds.header) + tests[i].pixel_data_size; + + dds.magic = MAKEFOURCC('D','D','S',' '); + fill_dds_header(&dds.header); + dds.header.flags = tests[i].flags; + dds.header.width = tests[i].width; + dds.header.height = tests[i].height; + dds.header.depth = tests[i].depth; + dds.header.pitch_or_linear_size = tests[i].row_pitch; + dds.header.miplevels = tests[i].mip_levels; + dds.header.caps = tests[i].caps; + dds.header.caps2 = tests[i].caps2; + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(&dds, file_size, NULL, &info, NULL); + todo_wine_if(tests[i].todo_hr) ok(hr == tests[i].expected.hr, "Got unexpected hr %#lx, expected %#lx.\n", + hr, tests[i].expected.hr); + if (SUCCEEDED(hr) && SUCCEEDED(tests[i].expected.hr)) + check_image_info_values(&info, tests[i].expected.width, tests[i].expected.height, + tests[i].expected.depth, tests[i].expected.array_size, tests[i].expected.mip_levels, + tests[i].expected.misc_flags, tests[i].expected.format, + tests[i].expected.resource_dimension, D3DX11_IFF_DDS, tests[i].todo_info); + + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(dxt10_tests); ++i) + { + winetest_push_context("Test %u", i); + file_size = sizeof(dds) + dxt10_tests[i].pixel_data_size; + + dds.magic = MAKEFOURCC('D','D','S',' '); + set_dxt10_dds_header(&dds.header, dxt10_tests[i].append_flags, dxt10_tests[i].width, dxt10_tests[i].height, + dxt10_tests[i].depth, dxt10_tests[i].mip_levels, dxt10_tests[i].row_pitch, dxt10_tests[i].caps, dxt10_tests[i].caps2); + dds.dxt10 = dxt10_tests[i].dxt10; + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(&dds, file_size, NULL, &info, NULL); + todo_wine_if(dxt10_tests[i].todo_hr) ok(hr == dxt10_tests[i].expected.hr, "Got unexpected hr %#lx, expected %#lx.\n", + hr, dxt10_tests[i].expected.hr); + if (SUCCEEDED(hr) && SUCCEEDED(dxt10_tests[i].expected.hr)) + check_image_info_values(&info, dxt10_tests[i].expected.width, dxt10_tests[i].expected.height, + dxt10_tests[i].expected.depth, dxt10_tests[i].expected.array_size, dxt10_tests[i].expected.mip_levels, + dxt10_tests[i].expected.misc_flags, dxt10_tests[i].expected.format, + dxt10_tests[i].expected.resource_dimension, D3DX11_IFF_DDS, dxt10_tests[i].todo_info); + + winetest_pop_context(); + } + + /* + * Image size (e.g, the size of the pixels) isn't validated, but header + * size is. + */ + dds.magic = MAKEFOURCC('D','D','S',' '); + set_dxt10_dds_header(&dds.header, dxt10_tests[0].append_flags, dxt10_tests[0].width, dxt10_tests[0].height, + dxt10_tests[0].depth, dxt10_tests[0].mip_levels, dxt10_tests[0].row_pitch, dxt10_tests[0].caps, dxt10_tests[0].caps2); + dds.dxt10 = dxt10_tests[0].dxt10; + + hr = D3DX11GetImageInfoFromMemory(&dds, sizeof(dds) - 1, NULL, &info, NULL); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(&dds, sizeof(dds), NULL, &info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Non DXT10 header. */ + dds.magic = MAKEFOURCC('D','D','S',' '); + fill_dds_header(&dds.header); + + hr = D3DX11GetImageInfoFromMemory(&dds, sizeof(dds) - sizeof(dds.dxt10) - 1, NULL, &info, NULL); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(&dds, sizeof(dds) - sizeof(dds.dxt10), NULL, &info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +} + +static void test_get_image_info(void) +{ + static const WCHAR test_resource_name[] = L"resource.data"; + static const WCHAR test_filename[] = L"image.data"; + HMODULE resource_module; + D3DX11_IMAGE_INFO info; + WCHAR path[MAX_PATH]; + HRESULT hr, hr2; + uint32_t i; + + CoInitialize(NULL); + + hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, sizeof(bmp_1bpp), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, sizeof(bmp_1bpp) + 5, NULL, &info, NULL); /* too large size */ + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(noimage, sizeof(noimage), NULL, NULL, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(noimage, sizeof(noimage), NULL, &info, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, sizeof(bmp_1bpp) - 1, NULL, &info, NULL); + todo_wine ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(bmp_1bpp + 1, sizeof(bmp_1bpp) - 1, NULL, &info, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, 0, NULL, &info, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, 0, NULL, NULL, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(noimage, 0, NULL, &info, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(noimage, 0, NULL, NULL, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(noimage, 0, NULL, &info, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(NULL, 4, NULL, NULL, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(NULL, 4, NULL, &info, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromMemory(NULL, 0, NULL, NULL, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + /* test BMP support */ + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, sizeof(bmp_1bpp), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_BMP, FALSE); + + hr = D3DX11GetImageInfoFromMemory(bmp_2bpp, sizeof(bmp_2bpp), NULL, &info, NULL); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(bmp_4bpp, sizeof(bmp_4bpp), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_BMP, FALSE); + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(bmp_8bpp, sizeof(bmp_8bpp), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_BMP, FALSE); + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(bmp_32bpp_xrgb, sizeof(bmp_32bpp_xrgb), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 2, 2, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_BMP, FALSE); + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(bmp_32bpp_argb, sizeof(bmp_32bpp_argb), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 2, 2, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_BMP, FALSE); + + /* Grayscale PNG */ + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(png_grayscale, sizeof(png_grayscale), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 1, 1, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_PNG, FALSE); + + /* test DDS support */ + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(dds_24bit, sizeof(dds_24bit), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 2, 2, 1, 1, 2, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(dds_24bit, sizeof(dds_24bit) - 1, NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 2, 2, 1, 1, 2, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(dds_16bit, sizeof(dds_16bit), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 2, 2, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(dds_16bit, sizeof(dds_16bit) - 1, NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 2, 2, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(dds_8bit, sizeof(dds_8bit), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 16, 4, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(dds_cube_map, sizeof(dds_cube_map), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 4, 4, 1, 6, 1, D3D11_RESOURCE_MISC_TEXTURECUBE, DXGI_FORMAT_BC3_UNORM, + D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS, FALSE); + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(dds_cube_map, sizeof(dds_cube_map) - 1, NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 4, 4, 1, 6, 1, D3D11_RESOURCE_MISC_TEXTURECUBE, DXGI_FORMAT_BC3_UNORM, + D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS, FALSE); + + memset(&info, 0, sizeof(info)); + hr = D3DX11GetImageInfoFromMemory(dds_volume_map, sizeof(dds_volume_map), NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 4, 4, 2, 1, 3, 0, DXGI_FORMAT_BC2_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, + D3DX11_IFF_DDS, FALSE); + + hr = D3DX11GetImageInfoFromMemory(dds_volume_map, sizeof(dds_volume_map) - 1, NULL, &info, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&info, 4, 4, 2, 1, 3, 0, DXGI_FORMAT_BC2_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, + D3DX11_IFF_DDS, FALSE); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromMemory(test_image[i].data, test_image[i].size, NULL, &info, &hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + if (hr == S_OK) + check_image_info(&info, test_image + i, __LINE__); + + winetest_pop_context(); + } + + hr2 = 0xdeadbeef; + add_work_item_count = 0; + hr = D3DX11GetImageInfoFromMemory(test_image[0].data, test_image[0].size, &thread_pump, &info, &hr2); + ok(add_work_item_count == 1, "Got unexpected add_work_item_count %u.\n", add_work_item_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + check_image_info(&info, test_image, __LINE__); + + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromFileW(NULL, NULL, &info, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromFileW(L"deadbeaf", NULL, &info, &hr2); + ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromFileA(NULL, NULL, &info, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromFileA("deadbeaf", NULL, &info, &hr2); + ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + create_file(test_filename, test_image[i].data, test_image[i].size, path); + + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromFileW(path, NULL, &info, &hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + if (hr == S_OK) + check_image_info(&info, test_image + i, __LINE__); + + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromFileA(get_str_a(path), NULL, &info, &hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + if (hr == S_OK) + check_image_info(&info, test_image + i, __LINE__); + + delete_file(test_filename); + winetest_pop_context(); + } + + /* D3DX11GetImageInfoFromResource tests */ + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromResourceW(NULL, NULL, NULL, &info, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromResourceW(NULL, L"deadbeaf", NULL, &info, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromResourceA(NULL, NULL, NULL, &info, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromResourceA(NULL, "deadbeaf", NULL, &info, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + resource_module = create_resource_module(test_resource_name, test_image[i].data, test_image[i].size); + + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromResourceW(resource_module, L"deadbeef", NULL, &info, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromResourceW(resource_module, test_resource_name, NULL, &info, &hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP) + || broken(hr == D3DX11_ERR_INVALID_DATA) /* Vista */, + "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + if (hr == S_OK) + check_image_info(&info, test_image + i, __LINE__); + + hr2 = 0xdeadbeef; + hr = D3DX11GetImageInfoFromResourceA(resource_module, get_str_a(test_resource_name), NULL, &info, &hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP) + || broken(hr == D3DX11_ERR_INVALID_DATA) /* Vista */, + "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + if (hr == S_OK) + check_image_info(&info, test_image + i, __LINE__); + + delete_resource_module(test_resource_name, resource_module); + winetest_pop_context(); + } + + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC1_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC2_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC2_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC3_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC3_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0, DXGI_FORMAT_R8G8_B8G8_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0, DXGI_FORMAT_G8R8_G8B8_UNORM); + check_dds_pixel_format(DDS_PF_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff, DXGI_FORMAT_A8_UNORM); + check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_RGB, 0, 16, 0xf00, 0x0f0, 0x00f, 0, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000, DXGI_FORMAT_R10G10B10A2_UNORM); + check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000, DXGI_FORMAT_R10G10B10A2_UNORM); + check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_RGB, 0, 32, 0xff0000, 0x00ff00, 0x0000ff, 0, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_RGB, 0, 32, 0x0000ff, 0x00ff00, 0xff0000, 0, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0, 0, DXGI_FORMAT_R16G16_UNORM); + check_dds_pixel_format(DDS_PF_LUMINANCE, 0, 8, 0xff, 0, 0, 0, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_LUMINANCE, 0, 16, 0xffff, 0, 0, 0, DXGI_FORMAT_R16G16B16A16_UNORM); + check_dds_pixel_format(DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 16, 0x00ff, 0, 0, 0xff00, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x0f, 0, 0, 0xf0, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_INDEXED, 0, 8, 0, 0, 0, 0, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_INDEXED | DDS_PF_ALPHA, 0, 16, 0, 0, 0, 0xff00, DXGI_FORMAT_R8G8B8A8_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, 0x24, 0, 0, 0, 0, 0, DXGI_FORMAT_R16G16B16A16_UNORM); /* D3DFMT_A16B16G16R16 */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x6e, 0, 0, 0, 0, 0, DXGI_FORMAT_R16G16B16A16_SNORM); /* D3DFMT_Q16W16V16U16 */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x6f, 0, 0, 0, 0, 0, DXGI_FORMAT_R16_FLOAT); /* D3DFMT_R16F */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x70, 0, 0, 0, 0, 0, DXGI_FORMAT_R16G16_FLOAT); /* D3DFMT_G16R16F */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x71, 0, 0, 0, 0, 0, DXGI_FORMAT_R16G16B16A16_FLOAT); /* D3DFMT_A16B16G16R16F */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x72, 0, 0, 0, 0, 0, DXGI_FORMAT_R32_FLOAT); /* D3DFMT_R32F */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x73, 0, 0, 0, 0, 0, DXGI_FORMAT_R32G32_FLOAT); /* D3DFMT_G32R32F */ + check_dds_pixel_format(DDS_PF_FOURCC, 0x74, 0, 0, 0, 0, 0, DXGI_FORMAT_R32G32B32A32_FLOAT); /* D3DFMT_A32B32G32R32F */ + + /* Test for DDS pixel formats that are valid on d3dx9, but not d3dx10. */ + check_dds_pixel_format_unsupported(DDS_PF_FOURCC, MAKEFOURCC('U','Y','V','Y'), 0, 0, 0, 0, 0, E_FAIL); + check_dds_pixel_format_unsupported(DDS_PF_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0, E_FAIL); + /* Bumpmap formats aren't supported. */ + check_dds_pixel_format_unsupported(DDS_PF_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0, 0, E_FAIL); + check_dds_pixel_format_unsupported(DDS_PF_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0, 0, E_FAIL); + check_dds_pixel_format_unsupported(DDS_PF_BUMPDUDV, 0, 32, 0xff, 0xff00, 0x00ff0000, 0xff000000, E_FAIL); + check_dds_pixel_format_unsupported(DDS_PF_BUMPLUMINANCE, 0, 32, 0x0000ff, 0x00ff00, 0xff0000, 0, E_FAIL); + + /* Newer fourCC formats. */ + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC4_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC5_UNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC4_SNORM); + check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC5_SNORM); + + check_dds_dx10_format_unsupported(DXGI_FORMAT_B5G6R5_UNORM, E_FAIL); + check_dds_dx10_format_unsupported(DXGI_FORMAT_B5G5R5A1_UNORM, E_FAIL); + check_dds_dx10_format_unsupported(DXGI_FORMAT_B4G4R4A4_UNORM, E_FAIL); + + /* + * These formats should map 1:1 from the DXT10 header, unlike legacy DDS + * file equivalents. + */ + check_dds_dx10_format(DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, FALSE); + check_dds_dx10_format(DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM, FALSE); + check_dds_dx10_format(DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, FALSE); + check_dds_dx10_format(DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_B8G8R8X8_UNORM, FALSE); + check_dds_dx10_format(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, FALSE); + check_dds_dx10_format(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, FALSE); + /* Formats unsupported on d3dx10, but now supported on d3dx11. */ + todo_wine check_dds_dx10_format(DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_BC6H_UF16, FALSE); + todo_wine check_dds_dx10_format(DXGI_FORMAT_BC6H_SF16, DXGI_FORMAT_BC6H_SF16, FALSE); + todo_wine check_dds_dx10_format(DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM, FALSE); + + test_dds_header_image_info(); + + CoUninitialize(); +} + +static void test_create_texture(void) +{ + static const uint32_t dds_24bit_8_8_mip_level_expected[] = { 0xff0000ff, 0xff00ff00, 0xffff0000, 0xff000000 }; + static const WCHAR test_resource_name[] = L"resource.data"; + static const WCHAR test_filename[] = L"image.data"; + D3D11_TEXTURE2D_DESC tex_2d_desc; + D3DX11_IMAGE_LOAD_INFO load_info; + D3DX11_IMAGE_INFO img_info; + ID3D11Resource *resource; + ID3D11Texture2D *tex_2d; + HMODULE resource_module; + ID3D11Device *device; + uint32_t i, mip_level; + WCHAR path[MAX_PATH]; + HRESULT hr, hr2; + + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + CoInitialize(NULL); + + /* D3DX11CreateTextureFromMemory tests */ + resource = (ID3D11Resource *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromMemory(NULL, test_bmp_1bpp, sizeof(test_bmp_1bpp), NULL, NULL, &resource, &hr2); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + ok(resource == (ID3D11Resource *)0xdeadbeef, "Got unexpected resource %p.\n", resource); + + resource = (ID3D11Resource *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromMemory(device, NULL, 0, NULL, NULL, &resource, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + ok(resource == (ID3D11Resource *)0xdeadbeef, "Got unexpected resource %p.\n", resource); + + resource = (ID3D11Resource *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromMemory(device, NULL, sizeof(test_bmp_1bpp), NULL, NULL, &resource, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + ok(resource == (ID3D11Resource *)0xdeadbeef, "Got unexpected resource %p.\n", resource); + + resource = (ID3D11Resource *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromMemory(device, test_bmp_1bpp, 0, NULL, NULL, &resource, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(resource == (ID3D11Resource *)0xdeadbeef, "Got unexpected resource %p.\n", resource); + + resource = (ID3D11Resource *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromMemory(device, test_bmp_1bpp, sizeof(test_bmp_1bpp) - 1, NULL, NULL, &resource, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(resource == (ID3D11Resource *)0xdeadbeef, "Got unexpected resource %p.\n", resource); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromMemory(device, test_image[i].data, test_image[i].size, NULL, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + check_resource_info(resource, test_image + i, __LINE__); + check_resource_data(resource, test_image + i, __LINE__); + ID3D11Resource_Release(resource); + } + + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + + winetest_push_context("Test %u", i); + + hr2 = 0xdeadbeef; + load_info = test_load_info->load_info; + hr = D3DX11CreateTextureFromMemory(device, test_load_info->data, test_load_info->size, &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11Resource_Release(resource); + + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(test_image_load_info); ++i) + { + const struct test_image_load_info *test_load_info = &test_image_load_info[i]; + + winetest_push_context("Test %u", i); + + load_info = test_load_info->load_info; + load_info.pSrcInfo = &img_info; + + resource = NULL; + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromMemory(device, test_load_info->data, test_load_info->size, &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + check_test_image_load_info_resource(resource, test_load_info); + ID3D11Resource_Release(resource); + } + + winetest_pop_context(); + } + + /* Check behavior of the FirstMipLevel argument. */ + for (i = 0; i < 2; ++i) + { + winetest_push_context("FirstMipLevel %u", i); + memset(&img_info, 0, sizeof(img_info)); + set_d3dx11_image_load_info(&load_info, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, i, D3DX11_FROM_FILE, + D3D11_USAGE_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, + D3DX11_DEFAULT, &img_info); + + resource = NULL; + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromMemory(device, dds_24bit_8_8, sizeof(dds_24bit_8_8), &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + + hr = ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture2D, (void **)&tex_2d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ID3D11Texture2D_GetDesc(tex_2d, &tex_2d_desc); + check_texture2d_desc_values(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, FALSE); + for (mip_level = 0; mip_level < 4; ++mip_level) + { + winetest_push_context("MipLevel %u", mip_level); + check_texture_sub_resource_color(tex_2d, mip_level, NULL, + dds_24bit_8_8_mip_level_expected[min(3, mip_level + i)], 0); + winetest_pop_context(); + } + + ID3D11Texture2D_Release(tex_2d); + ID3D11Resource_Release(resource); + winetest_pop_context(); + } + + /* + * If FirstMipLevel is set to a value that is larger than the total number + * of mip levels in the image, it falls back to 0. + */ + memset(&img_info, 0, sizeof(img_info)); + set_d3dx11_image_load_info(&load_info, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, 5, D3DX11_FROM_FILE, + D3D11_USAGE_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, + D3DX11_DEFAULT, &img_info); + + resource = NULL; + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromMemory(device, dds_24bit_8_8, sizeof(dds_24bit_8_8), &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + + hr = ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture2D, (void **)&tex_2d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID3D11Texture2D_GetDesc(tex_2d, &tex_2d_desc); + check_texture2d_desc_values(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, FALSE); + for (mip_level = 0; mip_level < 4; ++mip_level) + { + winetest_push_context("MipLevel %u", mip_level); + check_texture_sub_resource_color(tex_2d, mip_level, NULL, dds_24bit_8_8_mip_level_expected[mip_level], 0); + winetest_pop_context(); + } - hr = D3DX11CompileFromFileW(filename, NULL, &include.ID3DInclude_iface, - "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); - ok(hr == S_OK && hr == result, "Got unexpected hr %#lx, result %#lx.\n", hr, result); - ok(!!blob, "Got unexpected blob.\n"); - ok(!errors, "Got unexpected errors.\n"); - ID3D10Blob_Release(blob); - blob = NULL; + ID3D11Texture2D_Release(tex_2d); + ID3D11Resource_Release(resource); - /* Windows always seems to resolve includes from the initial file location - * instead of using the immediate parent, as it would be the case for - * standard C preprocessor includes. */ - hr = D3DX11CompileFromFileW(filename, NULL, NULL, "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); - ok(hr == S_OK && hr == result, "Got unexpected hr %#lx, result %#lx.\n", hr, result); - ok(!!blob, "Got unexpected blob.\n"); - ok(!errors, "Got unexpected errors.\n"); - ID3D10Blob_Release(blob); - blob = NULL; + hr2 = 0xdeadbeef; + add_work_item_count = 0; + hr = D3DX11CreateTextureFromMemory(device, test_image[0].data, test_image[0].size, + NULL, &thread_pump, &resource, &hr2); + ok(add_work_item_count == 1, "Got unexpected add_work_item_count %u.\n", add_work_item_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + check_resource_info(resource, test_image, __LINE__); + check_resource_data(resource, test_image, __LINE__); + ID3D11Resource_Release(resource); + + /* D3DX11CreateTextureFromFile tests */ + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromFileW(device, NULL, NULL, NULL, &resource, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromFileW(device, L"deadbeef", NULL, NULL, &resource, &hr2); + ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromFileA(device, NULL, NULL, NULL, &resource, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromFileA(device, "deadbeef", NULL, NULL, &resource, &hr2); + ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - len = WideCharToMultiByte(CP_ACP, 0, filename, -1, NULL, 0, NULL, NULL); - WideCharToMultiByte(CP_ACP, 0, filename, -1, filename_a, len, NULL, NULL); - hr = D3DX11CompileFromFileA(filename_a, NULL, NULL, "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); - ok(hr == S_OK && hr == result, "Got unexpected hr %#lx, result %#lx.\n", hr, result); - ok(!!blob, "Got unexpected blob.\n"); - ok(!errors, "Got unexpected errors.\n"); - ID3D10Blob_Release(blob); - blob = NULL; + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + create_file(test_filename, test_image[i].data, test_image[i].size, path); + + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromFileW(device, path, NULL, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + check_resource_info(resource, test_image + i, __LINE__); + check_resource_data(resource, test_image + i, __LINE__); + ID3D11Resource_Release(resource); + } + + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromFileA(device, get_str_a(path), NULL, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + check_resource_info(resource, test_image + i, __LINE__); + check_resource_data(resource, test_image + i, __LINE__); + ID3D11Resource_Release(resource); + } + + delete_file(test_filename); + winetest_pop_context(); + } - GetCurrentDirectoryW(MAX_PATH, directory); - SetCurrentDirectoryW(temp_dir); + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + + winetest_push_context("Test %u", i); + create_file(test_filename, test_image[i].data, test_image[i].size, path); + load_info = test_load_info->load_info; + + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromFileW(device, path, &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11Resource_Release(resource); + + hr = D3DX11CreateTextureFromFileA(device, get_str_a(path), &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11Resource_Release(resource); + + delete_file(test_filename); + winetest_pop_context(); + } - hr = D3DX11CompileFromFileW(L"source.ps", NULL, NULL, "main", "ps_2_0", 0, 0, NULL, &blob, &errors, &result); - ok(hr == S_OK && hr == result, "Got unexpected hr %#lx, result %#lx.\n", hr, result); - ok(!!blob, "Got unexpected blob.\n"); - ok(!errors, "Got unexpected errors.\n"); - ID3D10Blob_Release(blob); - blob = NULL; + /* D3DX11CreateTextureFromResource tests */ + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromResourceW(device, NULL, NULL, NULL, NULL, &resource, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromResourceW(device, NULL, L"deadbeef", NULL, NULL, &resource, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromResourceA(device, NULL, NULL, NULL, NULL, &resource, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromResourceA(device, NULL, "deadbeef", NULL, NULL, &resource, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); - SetCurrentDirectoryW(directory); + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + resource_module = create_resource_module(test_resource_name, test_image[i].data, test_image[i].size); + + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromResourceW(device, resource_module, L"deadbeef", NULL, NULL, &resource, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromResourceW(device, resource_module, + test_resource_name, NULL, NULL, &resource, &hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + if (hr == S_OK) + { + check_resource_info(resource, test_image + i, __LINE__); + check_resource_data(resource, test_image + i, __LINE__); + ID3D11Resource_Release(resource); + } + + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromResourceA(device, resource_module, + get_str_a(test_resource_name), NULL, NULL, &resource, &hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + if (hr == S_OK) + { + check_resource_info(resource, test_image + i, __LINE__); + check_resource_data(resource, test_image + i, __LINE__); + ID3D11Resource_Release(resource); + } + + delete_resource_module(test_resource_name, resource_module); + winetest_pop_context(); + } - delete_file(L"source.ps"); - delete_file(L"include\\include1.h"); - delete_file(L"include1.h"); - delete_file(L"include\\include2.h"); - delete_directory(L"include"); + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + + winetest_push_context("Test %u", i); + resource_module = create_resource_module(test_resource_name, test_load_info->data, test_load_info->size); + load_info = test_load_info->load_info; + + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromResourceW(device, resource_module, + test_resource_name, &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11Resource_Release(resource); + + hr2 = 0xdeadbeef; + hr = D3DX11CreateTextureFromResourceA(device, resource_module, + get_str_a(test_resource_name), &load_info, NULL, &resource, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11Resource_Release(resource); + + delete_resource_module(test_resource_name, resource_module); + winetest_pop_context(); + } + + CoUninitialize(); + + ok(!ID3D11Device_Release(device), "Unexpected refcount.\n"); } -/* dds_header.flags */ -#define DDS_CAPS 0x00000001 -#define DDS_HEIGHT 0x00000002 -#define DDS_WIDTH 0x00000004 -#define DDS_PITCH 0x00000008 -#define DDS_PIXELFORMAT 0x00001000 -#define DDS_MIPMAPCOUNT 0x00020000 -#define DDS_LINEARSIZE 0x00080000 +static void test_create_shader_resource_view(void) +{ + static const uint32_t dds_24bit_8_8_mip_level_expected[] = { 0xff0000ff, 0xff00ff00, 0xffff0000, 0xff000000 }; + static const WCHAR test_resource_name[] = L"resource.data"; + static const WCHAR test_filename[] = L"image.data"; + D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc; + D3D11_TEXTURE2D_DESC tex_2d_desc; + D3DX11_IMAGE_LOAD_INFO load_info; + ID3D11ShaderResourceView *srv; + D3DX11_IMAGE_INFO img_info; + ID3D11Resource *resource; + ID3D11Texture2D *tex_2d; + HMODULE resource_module; + ID3D11Device *device; + WCHAR path[MAX_PATH]; + uint32_t i, mip_level; + HRESULT hr, hr2; + + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + CoInitialize(NULL); + + /* D3DX11CreateShaderResourceViewFromMemory tests. */ + srv = (ID3D11ShaderResourceView *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromMemory(NULL, test_bmp_1bpp, sizeof(test_bmp_1bpp), NULL, NULL, &srv, &hr2); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + ok(srv == (ID3D11ShaderResourceView *)0xdeadbeef, "Got unexpected srv %p.\n", srv); + + srv = (ID3D11ShaderResourceView *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromMemory(device, NULL, 0, NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + ok(srv == (ID3D11ShaderResourceView *)0xdeadbeef, "Got unexpected srv %p.\n", srv); + + srv = (ID3D11ShaderResourceView *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromMemory(device, NULL, sizeof(test_bmp_1bpp), NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + ok(srv == (ID3D11ShaderResourceView *)0xdeadbeef, "Got unexpected srv %p.\n", srv); + + srv = (ID3D11ShaderResourceView *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromMemory(device, test_bmp_1bpp, 0, NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(srv == (ID3D11ShaderResourceView *)0xdeadbeef, "Got unexpected srv %p.\n", srv); + + srv = (ID3D11ShaderResourceView *)0xdeadbeef; + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromMemory(device, test_bmp_1bpp, sizeof(test_bmp_1bpp) - 1, NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(srv == (ID3D11ShaderResourceView *)0xdeadbeef, "Got unexpected srv %p.\n", srv); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromMemory(device, test_image[i].data, test_image[i].size, NULL, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + check_shader_resource_view_info(srv, test_image + i, __LINE__); + ID3D11ShaderResourceView_Release(srv); + } + + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + + winetest_push_context("Test %u", i); + + hr2 = 0xdeadbeef; + load_info = test_load_info->load_info; + hr = D3DX11CreateShaderResourceViewFromMemory(device, test_load_info->data, test_load_info->size, &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11ShaderResourceView_Release(srv); + + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(test_image_load_info); ++i) + { + const struct test_image_load_info *test_load_info = &test_image_load_info[i]; + + winetest_push_context("Test %u", i); + + load_info = test_load_info->load_info; + load_info.pSrcInfo = &img_info; + + srv = NULL; + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromMemory(device, test_load_info->data, test_load_info->size, &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + check_test_image_load_info_srv(srv, test_load_info); + ID3D11ShaderResourceView_Release(srv); + } + + winetest_pop_context(); + } + + /* Check behavior of the FirstMipLevel argument. */ + for (i = 0; i < 2; ++i) + { + winetest_push_context("FirstMipLevel %u", i); + memset(&img_info, 0, sizeof(img_info)); + set_d3dx11_image_load_info(&load_info, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, i, D3DX11_FROM_FILE, + D3D11_USAGE_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, + D3DX11_DEFAULT, &img_info); + + srv = NULL; + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromMemory(device, dds_24bit_8_8, sizeof(dds_24bit_8_8), &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + + ID3D11ShaderResourceView_GetDesc(srv, &srv_desc); + ok(srv_desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2D, "Got unexpected ViewDimension %u.\n", srv_desc.ViewDimension); + ok(srv_desc.Format == img_info.Format, "Got unexpected Format %#x.\n", srv_desc.Format); + ok(!srv_desc.Texture2D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", srv_desc.Texture2D.MostDetailedMip); + ok(srv_desc.Texture2D.MipLevels == img_info.MipLevels, "Unexpected MipLevels %u.\n", srv_desc.Texture2D.MipLevels); + + ID3D11ShaderResourceView_GetResource(srv, &resource); + hr = ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture2D, (void **)&tex_2d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ID3D11Texture2D_GetDesc(tex_2d, &tex_2d_desc); + check_texture2d_desc_values(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, FALSE); + for (mip_level = 0; mip_level < 4; ++mip_level) + { + winetest_push_context("MipLevel %u", mip_level); + check_texture_sub_resource_color(tex_2d, mip_level, NULL, + dds_24bit_8_8_mip_level_expected[min(3, mip_level + i)], 0); + winetest_pop_context(); + } + + ID3D11Texture2D_Release(tex_2d); + ID3D11Resource_Release(resource); + ID3D11ShaderResourceView_Release(srv); + winetest_pop_context(); + } + + /* + * If FirstMipLevel is set to a value that is larger than the total number + * of mip levels in the image, it falls back to 0. + */ + memset(&img_info, 0, sizeof(img_info)); + set_d3dx11_image_load_info(&load_info, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, 5, D3DX11_FROM_FILE, + D3D11_USAGE_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, + D3DX11_DEFAULT, &img_info); + + resource = NULL; + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromMemory(device, dds_24bit_8_8, sizeof(dds_24bit_8_8), &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + + ID3D11ShaderResourceView_GetDesc(srv, &srv_desc); + ok(srv_desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2D, "Got unexpected ViewDimension %u.\n", srv_desc.ViewDimension); + ok(srv_desc.Format == img_info.Format, "Got unexpected Format %#x.\n", srv_desc.Format); + ok(!srv_desc.Texture2D.MostDetailedMip, "Unexpected MostDetailedMip %u.\n", srv_desc.Texture2D.MostDetailedMip); + ok(srv_desc.Texture2D.MipLevels == img_info.MipLevels, "Unexpected MipLevels %u.\n", srv_desc.Texture2D.MipLevels); + + ID3D11ShaderResourceView_GetResource(srv, &resource); + hr = ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture2D, (void **)&tex_2d); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID3D11Texture2D_GetDesc(tex_2d, &tex_2d_desc); + check_texture2d_desc_values(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, FALSE); + for (mip_level = 0; mip_level < 4; ++mip_level) + { + winetest_push_context("MipLevel %u", mip_level); + check_texture_sub_resource_color(tex_2d, mip_level, NULL, dds_24bit_8_8_mip_level_expected[mip_level], 0); + winetest_pop_context(); + } + + ID3D11Texture2D_Release(tex_2d); + ID3D11Resource_Release(resource); + ID3D11ShaderResourceView_Release(srv); + + hr2 = 0xdeadbeef; + add_work_item_count = 0; + hr = D3DX11CreateShaderResourceViewFromMemory(device, test_image[0].data, test_image[0].size, + NULL, &thread_pump, &srv, &hr2); + ok(add_work_item_count == 1, "Got unexpected add_work_item_count %u.\n", add_work_item_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + check_shader_resource_view_info(srv, test_image, __LINE__); + ID3D11ShaderResourceView_Release(srv); + + /* D3DX11CreateShaderResourceViewFromFile tests */ + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromFileW(device, NULL, NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromFileW(device, L"deadbeef", NULL, NULL, &srv, &hr2); + ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromFileA(device, NULL, NULL, NULL, &srv, &hr2); + ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromFileA(device, "deadbeef", NULL, NULL, &srv, &hr2); + ok(hr == D3D11_ERROR_FILE_NOT_FOUND, "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + create_file(test_filename, test_image[i].data, test_image[i].size, path); + + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromFileW(device, path, NULL, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + check_shader_resource_view_info(srv, test_image + i, __LINE__); + ID3D11ShaderResourceView_Release(srv); + } + + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromFileA(device, get_str_a(path), NULL, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + check_shader_resource_view_info(srv, test_image + i, __LINE__); + ID3D11ShaderResourceView_Release(srv); + } + + delete_file(test_filename); + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + + winetest_push_context("Test %u", i); + create_file(test_filename, test_image[i].data, test_image[i].size, path); + load_info = test_load_info->load_info; + + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromFileW(device, path, &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11ShaderResourceView_Release(srv); + + hr = D3DX11CreateShaderResourceViewFromFileA(device, get_str_a(path), &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11ShaderResourceView_Release(srv); + + delete_file(test_filename); + winetest_pop_context(); + } + + /* D3DX11CreateShaderResourceViewFromResource tests */ + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromResourceW(device, NULL, NULL, NULL, NULL, &srv, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromResourceW(device, NULL, L"deadbeef", NULL, NULL, &srv, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromResourceA(device, NULL, NULL, NULL, NULL, &srv, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromResourceA(device, NULL, "deadbeef", NULL, NULL, &srv, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + resource_module = create_resource_module(test_resource_name, test_image[i].data, test_image[i].size); + + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromResourceW(device, resource_module, L"deadbeef", NULL, NULL, &srv, &hr2); + ok(hr == D3DX11_ERR_INVALID_DATA, "Got unexpected hr %#lx.\n", hr); + ok(hr2 == 0xdeadbeef, "Got unexpected hr2 %#lx.\n", hr2); + + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromResourceW(device, resource_module, + test_resource_name, NULL, NULL, &srv, &hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + if (hr == S_OK) + { + check_shader_resource_view_info(srv, test_image + i, __LINE__); + ID3D11ShaderResourceView_Release(srv); + } + + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromResourceA(device, resource_module, + get_str_a(test_resource_name), NULL, NULL, &srv, &hr2); + ok(hr == S_OK || broken(hr == E_FAIL && test_image[i].expected_info.ImageFileFormat == D3DX11_IFF_WMP), + "Got unexpected hr %#lx.\n", hr); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + if (hr == S_OK) + { + check_shader_resource_view_info(srv, test_image + i, __LINE__); + ID3D11ShaderResourceView_Release(srv); + } + + delete_resource_module(test_resource_name, resource_module); + winetest_pop_context(); + } + + for (i = 0; i < ARRAY_SIZE(test_invalid_image_load_info); ++i) + { + const struct test_invalid_image_load_info *test_load_info = &test_invalid_image_load_info[i]; + + winetest_push_context("Test %u", i); + resource_module = create_resource_module(test_resource_name, test_load_info->data, test_load_info->size); + load_info = test_load_info->load_info; + + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromResourceW(device, resource_module, + test_resource_name, &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11ShaderResourceView_Release(srv); + + hr2 = 0xdeadbeef; + hr = D3DX11CreateShaderResourceViewFromResourceA(device, resource_module, + get_str_a(test_resource_name), &load_info, NULL, &srv, &hr2); + ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); + todo_wine_if(test_load_info->todo_hr) ok(hr == test_load_info->expected_hr, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ID3D11ShaderResourceView_Release(srv); + + delete_resource_module(test_resource_name, resource_module); + winetest_pop_context(); + } + + CoUninitialize(); + + ok(!ID3D11Device_Release(device), "Unexpected refcount.\n"); +} + +/* + * 4x4 RGBA cubemap with faces in the following order: blue, green, red, + * green/blue, red/blue, red/green. + */ +static const uint8_t rgba_4_4_cubemap[] = +{ + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff, + 0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff, + 0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff, + 0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff, + 0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff, + 0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff, + 0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff, + 0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff, + 0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, + 0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, + 0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, + 0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, +}; + +/* + * 8x8 (BC1-BC3) image data, four 4x4 blocks: + * +-----+-----+ + * |Blue |Green| + * | | | + * +-----+-----+ + * |Red |Black| + * | | | + * +-----+-----+ + */ +static const uint8_t bc1_8_8[] = +{ + 0x1f,0x00,0x1f,0x00,0xaa,0xaa,0xaa,0xaa,0xe0,0x07,0xe0,0x07,0xaa,0xaa,0xaa,0xaa, + 0x00,0xf8,0x00,0xf8,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, +}; + +static const uint8_t bc2_8_8[] = +{ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x1f,0x00,0xaa,0xaa,0xaa,0xaa, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x07,0xe0,0x07,0xaa,0xaa,0xaa,0xaa, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0x00,0xf8,0xaa,0xaa,0xaa,0xaa, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, +}; + +static const uint8_t bc3_8_8[] = +{ + 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00, + 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x07,0xe0,0x07,0x00,0x00,0x00,0x00, + 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0x00, + 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t bc1_to_bc3_8_8_decompressed[] = +{ + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff, + 0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff, +}; + +static const uint8_t bc4_unorm_8_8[] = +{ + 0xff,0xff,0x49,0x92,0x24,0x49,0x92,0x24,0x80,0x80,0x49,0x92,0x24,0x49,0x92,0x24, + 0x00,0x00,0x49,0x92,0x24,0x49,0x92,0x24,0x40,0x40,0x49,0x92,0x24,0x49,0x92,0x24, +}; + +static const uint8_t r8_unorm_8_8_decompressed[] = +{ + 0xff,0xff,0xff,0xff,0x80,0x80,0x80,0x80,0xff,0xff,0xff,0xff,0x80,0x80,0x80,0x80, + 0xff,0xff,0xff,0xff,0x80,0x80,0x80,0x80,0xff,0xff,0xff,0xff,0x80,0x80,0x80,0x80, + 0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40, + 0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40, +}; + +static const uint8_t bc5_unorm_8_8[] = +{ + 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xdf,0xdf,0x00,0x00,0x00,0x00,0x00,0x00, + 0xbf,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x9f,0x9f,0x00,0x00,0x00,0x00,0x00,0x00, + 0x7f,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x5f,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3f,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x1f,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t r8g8_unorm_8_8_decompressed[] = +{ + 0xff,0xdf,0xff,0xdf,0xff,0xdf,0xff,0xdf,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f, + 0xff,0xdf,0xff,0xdf,0xff,0xdf,0xff,0xdf,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f, + 0xff,0xdf,0xff,0xdf,0xff,0xdf,0xff,0xdf,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f, + 0xff,0xdf,0xff,0xdf,0xff,0xdf,0xff,0xdf,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f,0xbf,0x9f, + 0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, + 0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, + 0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, + 0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x7f,0x5f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f,0x3f,0x1f, +}; + +/* + * DXGI_FORMAT_BC{4,5}_SNORM compression/decompression is bugged in + * native D3DX10/D3DX11. When decompressing, it seems to read the decompressed + * 8-bit channel values as signed normalized integers, but then clamps them to the + * unsigned normalized integer range. That means 0x00-0x7f present unique values, + * but anything from 0x80-0xff just gives the equivalent of 0x00. When this gets + * converted to an SNORM format such as DXGI_FORMAT_R8_SNORM, it gets mapped + * to the SNORM range, where 0x00 is -1.0f, and 0x7f is 1.0f. So effectively, + * it ends up with half of the range. + */ +static const uint8_t bc4_snorm_8_8[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00, + 0x7f,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x5f,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t r8_snorm_8_8_decompressed[] = +{ + 0x81,0x81,0x81,0x81,0xc1,0xc1,0xc1,0xc1,0x81,0x81,0x81,0x81,0xc1,0xc1,0xc1,0xc1, + 0x81,0x81,0x81,0x81,0xc1,0xc1,0xc1,0xc1,0x81,0x81,0x81,0x81,0xc1,0xc1,0xc1,0xc1, + 0x7F,0x7F,0x7F,0x7F,0x3F,0x3F,0x3F,0x3F,0x7F,0x7F,0x7F,0x7F,0x3F,0x3F,0x3F,0x3F, + 0x7F,0x7F,0x7F,0x7F,0x3F,0x3F,0x3F,0x3F,0x7F,0x7F,0x7F,0x7F,0x3F,0x3F,0x3F,0x3F, +}; + +static const uint8_t bc5_snorm_8_8[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x1f,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x2f,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3e,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x4e,0x4e,0x00,0x00,0x00,0x00,0x00,0x00, + 0x5d,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0x6d,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t r8g8_snorm_8_8_decompressed[] = +{ + 0x81,0xa1,0x81,0xa1,0x81,0xa1,0x81,0xa1,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf, + 0x81,0xa1,0x81,0xa1,0x81,0xa1,0x81,0xa1,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf, + 0x81,0xa1,0x81,0xa1,0x81,0xa1,0x81,0xa1,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf, + 0x81,0xa1,0x81,0xa1,0x81,0xa1,0x81,0xa1,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf,0xbf,0xdf, + 0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b, + 0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b, + 0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b, + 0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0xfd,0x1d,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b,0x3b,0x5b, +}; + +static const uint8_t rgba_unorm_4_4[] = +{ + 0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0xff, + 0x14,0x24,0x34,0x44,0x54,0x64,0x74,0x84,0x94,0xa4,0xb4,0xc4,0xd4,0xe4,0xf4,0xff, + 0x18,0x28,0x38,0x48,0x58,0x68,0x78,0x88,0x98,0xa8,0xb8,0xc8,0xd8,0xe8,0xf8,0xff, + 0x1c,0x2c,0x3c,0x4c,0x5c,0x6c,0x7c,0x8c,0x9c,0xac,0xbc,0xcc,0xdc,0xec,0xfc,0xff, +}; + +static const uint8_t rgba_snorm_4_4[] = +{ + 0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1,0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x7f, + 0x95,0xa5,0xb5,0xc5,0xd5,0xe5,0xf5,0x04,0x14,0x24,0x34,0x44,0x54,0x64,0x74,0x7f, + 0x99,0xa9,0xb9,0xc9,0xd9,0xe9,0xf9,0x08,0x18,0x28,0x38,0x48,0x58,0x68,0x78,0x7f, + 0x9d,0xad,0xbd,0xcd,0xdd,0xed,0xfd,0x0c,0x1c,0x2c,0x3c,0x4c,0x5c,0x6c,0x7c,0x7f, +}; + +/* Conversion to/from uint/sint. */ +static const uint8_t rgba_uint_4_4[] = +{ + 0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c,0x20,0x24,0x28,0x2c,0x30,0x34,0x38,0x3c, + 0x40,0x44,0x48,0x4c,0x50,0x54,0x58,0x5c,0x60,0x64,0x68,0x6c,0x70,0x74,0x78,0x7c, + 0x80,0x84,0x88,0x8c,0x90,0x94,0x98,0x9c,0xa0,0xa4,0xa8,0xac,0xb0,0xb4,0xb8,0xbc, + 0xc0,0xc4,0xc8,0xcc,0xd0,0xd4,0xd8,0xdc,0xe0,0xe4,0xe8,0xec,0xf0,0xf4,0xf8,0xfc, +}; + +static const uint8_t rgba_uint_to_sint_4_4[] = +{ + 0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c,0x20,0x24,0x28,0x2c,0x30,0x34,0x38,0x3c, + 0x40,0x44,0x48,0x4c,0x50,0x54,0x58,0x5c,0x60,0x64,0x68,0x6c,0x70,0x74,0x78,0x7c, + 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, + 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, +}; + +static const uint8_t rgba_sint_4_4[] = +{ + 0x80,0x84,0x88,0x8c,0x90,0x94,0x98,0x9c,0xa0,0xa4,0xa8,0xac,0xb0,0xb4,0xb8,0xbc, + 0xc0,0xc4,0xc8,0xcc,0xd0,0xd4,0xd8,0xdc,0xe0,0xe4,0xe8,0xec,0xf0,0xf4,0xf8,0xfc, + 0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c,0x20,0x24,0x28,0x2c,0x30,0x34,0x38,0x3c, + 0x40,0x44,0x48,0x4c,0x50,0x54,0x58,0x5c,0x60,0x64,0x68,0x6c,0x70,0x74,0x78,0x7c, +}; + +static const uint8_t rgba_sint_to_uint_4_4[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c,0x20,0x24,0x28,0x2c,0x30,0x34,0x38,0x3c, + 0x40,0x44,0x48,0x4c,0x50,0x54,0x58,0x5c,0x60,0x64,0x68,0x6c,0x70,0x74,0x78,0x7c, +}; + +/* Conversion to/from SRGB. */ +static const uint8_t rgba_unorm_srgb_4_4[] = +{ + 0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0xff, + 0x14,0x24,0x34,0x44,0x54,0x64,0x74,0x84,0x94,0xa4,0xb4,0xc4,0xd4,0xe4,0xf4,0xff, + 0x18,0x28,0x38,0x48,0x58,0x68,0x78,0x88,0x98,0xa8,0xb8,0xc8,0xd8,0xe8,0xf8,0xff, + 0x1c,0x2c,0x3c,0x4c,0x5c,0x6c,0x7c,0x8c,0x9c,0xac,0xbc,0xcc,0xdc,0xec,0xfc,0xff, +}; + +static const uint8_t rgba_unorm_srgb_to_unorm_non_srgb_4_4[] = +{ + 0x01,0x03,0x06,0x40,0x14,0x1e,0x2a,0x80,0x49,0x5b,0x71,0xc0,0xa3,0xc0,0xdf,0xff, + 0x01,0x03,0x08,0x44,0x16,0x21,0x2d,0x84,0x4d,0x61,0x77,0xc4,0xaa,0xc7,0xe7,0xff, + 0x01,0x04,0x09,0x48,0x19,0x23,0x31,0x88,0x52,0x66,0x7c,0xc8,0xb1,0xcf,0xf0,0xff, + 0x02,0x05,0x0b,0x4c,0x1b,0x27,0x34,0x8c,0x57,0x6b,0x82,0xcc,0xb8,0xd7,0xf8,0xff, +}; + +static const uint8_t rgba_unorm_non_srgb_4_4[] = +{ + 0x00,0x20,0x50,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0,0xff, + 0x00,0x24,0x54,0x44,0x54,0x64,0x74,0x84,0x94,0xa4,0xb4,0xc4,0xd4,0xe4,0xf4,0xff, + 0x00,0x28,0x58,0x48,0x58,0x68,0x78,0x88,0x98,0xa8,0xb8,0xc8,0xd8,0xe8,0xf8,0xff, + 0x00,0x2c,0x5c,0x4c,0x5c,0x6c,0x7c,0x8c,0x9c,0xac,0xbc,0xcc,0xdc,0xec,0xfc,0xff, +}; + +static const uint8_t rgba_unorm_non_srgb_to_unorm_srgb_4_4[] = +{ + 0x00,0x63,0x97,0x40,0x97,0xa4,0xaf,0x80,0xc5,0xce,0xd7,0xc0,0xe8,0xf0,0xf8,0xff, + 0x00,0x69,0x9a,0x44,0x9a,0xa7,0xb2,0x84,0xc7,0xd1,0xda,0xc4,0xea,0xf2,0xfa,0xff, + 0x00,0x6e,0x9d,0x48,0x9d,0xaa,0xb5,0x88,0xca,0xd3,0xdc,0xc8,0xec,0xf4,0xfc,0xff, + 0x00,0x73,0xa0,0x4c,0xa0,0xad,0xb8,0x8c,0xcc,0xd5,0xde,0xcc,0xee,0xf6,0xfe,0xff, +}; + +static const struct test_texture_format_conversion +{ + D3D11_TEXTURE2D_DESC src_desc; + const uint8_t *src_data; + + DXGI_FORMAT dst_format; + const uint8_t *expected_dst_data; + + uint8_t max_diff; + BOOL todo_hr; + BOOL todo_data; +} +test_texture_format_conversion[] = +{ + { + { 8, 8, 1, 1, DXGI_FORMAT_BC1_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + bc1_8_8, DXGI_FORMAT_R8G8B8A8_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC2_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + bc2_8_8, DXGI_FORMAT_R8G8B8A8_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC3_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + bc3_8_8, DXGI_FORMAT_R8G8B8A8_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC4_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + bc4_unorm_8_8, DXGI_FORMAT_R8_UNORM, r8_unorm_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC4_SNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + bc4_snorm_8_8, DXGI_FORMAT_R8_SNORM, r8_snorm_8_8_decompressed, .todo_data = TRUE + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC5_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + bc5_unorm_8_8, DXGI_FORMAT_R8G8_UNORM, r8g8_unorm_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_BC5_SNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + bc5_snorm_8_8, DXGI_FORMAT_R8G8_SNORM, r8g8_snorm_8_8_decompressed, .todo_data = TRUE + }, + { + { 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + /* + * Wine's UNORM->SNORM conversion doesn't always match Window's, + * worst case is a difference of +/- 1. + */ + rgba_unorm_4_4, DXGI_FORMAT_R8G8B8A8_SNORM, rgba_snorm_4_4, .max_diff = 1 + }, + { + { 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_UINT, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + rgba_uint_4_4, DXGI_FORMAT_R8G8B8A8_SINT, rgba_uint_to_sint_4_4, .todo_hr = TRUE + }, + { + { 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_SINT, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + rgba_sint_4_4, DXGI_FORMAT_R8G8B8A8_UINT, rgba_sint_to_uint_4_4, .todo_hr = TRUE + }, + { + { 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + rgba_unorm_srgb_4_4, DXGI_FORMAT_R8G8B8A8_UNORM, rgba_unorm_srgb_to_unorm_non_srgb_4_4, .max_diff = 3 + }, + { + { 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + rgba_unorm_non_srgb_4_4, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, rgba_unorm_non_srgb_to_unorm_srgb_4_4, .max_diff = 2 + }, +}; + +static const struct test_texture_compression +{ + D3D11_TEXTURE2D_DESC src_desc; + DXGI_FORMAT compressed_format; + const BYTE *src_data; +} +test_texture_compression[] = +{ + { + { 8, 8, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + DXGI_FORMAT_BC1_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + DXGI_FORMAT_BC2_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + DXGI_FORMAT_BC3_UNORM, bc1_to_bc3_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_R8_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + DXGI_FORMAT_BC4_UNORM, r8_unorm_8_8_decompressed + }, + { + { 8, 8, 1, 1, DXGI_FORMAT_R8G8_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 }, + DXGI_FORMAT_BC5_UNORM, r8g8_unorm_8_8_decompressed + }, +}; + +#define check_texture_data_level(tex_pixels, tex_row_pitch, tex_slice_pitch, width, height, depth, format, exp_pixels, max_diff, wine_todo) \ + check_texture_data_level_(tex_pixels, tex_row_pitch, tex_slice_pitch, width, height, depth, format, exp_pixels, max_diff, wine_todo, __LINE__) +static void check_texture_data_level_(const uint8_t *tex_pixels, uint32_t tex_row_pitch, uint32_t tex_slice_pitch, uint32_t width, + uint32_t height, uint32_t depth, DXGI_FORMAT format, const uint8_t *exp_pixels, uint8_t max_diff, BOOL wine_todo, uint32_t line) +{ + uint32_t line_height, exp_row_pitch, exp_slice_pitch, i, j, k; + BOOL line_match = FALSE; + + line_height = 1; + exp_row_pitch = (width * get_bpp_from_format(format) + 7) / 8; + exp_slice_pitch = exp_row_pitch * height; + if (is_block_compressed(format)) + { + exp_row_pitch *= 4; + line_height = 4; + } + + for (i = 0; i < depth; ++i) + { + const uint8_t *exp_slice = exp_pixels + (i * (exp_slice_pitch)); + const uint8_t *pixel_slice = tex_pixels + (i * tex_slice_pitch); + + for (j = 0; j < height; j += line_height) + { + if (dxgi_format_is_8bpp_rgba(format)) + { + for (k = 0; k < width; ++k) + { + const uint32_t exp_pixel = ((const uint32_t *)(exp_slice + j * exp_row_pitch))[k]; + const uint32_t tex_pixel = ((const uint32_t *)(pixel_slice + j * tex_row_pitch))[k]; + const BOOL pixel_match = compare_color(tex_pixel, exp_pixel, max_diff); + + todo_wine_if(wine_todo) ok_(__FILE__, line)(pixel_match, "Data mismatch for pixel (%ux%ux%u).\n", k, j, i); + line_match = pixel_match; + if (!pixel_match) + break; + } + } + else + { + line_match = !memcmp(exp_slice + exp_row_pitch * (j / line_height), + pixel_slice + tex_row_pitch * (j / line_height), exp_row_pitch); + todo_wine_if(wine_todo) ok_(__FILE__, line)(line_match, "Data mismatch for line %u, slice %u.\n", j, i); + } + if (!line_match) + break; + } + } +} -/* dds_header.caps */ -#define DDSCAPS_ALPHA 0x00000002 -#define DDS_CAPS_TEXTURE 0x00001000 +static void set_d3dx11_texture_load_info(D3DX11_TEXTURE_LOAD_INFO *load_info, D3D11_BOX *src_box, D3D11_BOX *dst_box, + uint32_t src_first_mip, uint32_t dst_first_mip, uint32_t num_mips, uint32_t src_first_element, + uint32_t dst_first_element, uint32_t num_elems, uint32_t filter, uint32_t mip_filter) +{ + load_info->pSrcBox = src_box; + load_info->pDstBox = dst_box; + load_info->SrcFirstMip = src_first_mip; + load_info->DstFirstMip = dst_first_mip; + load_info->NumMips = num_mips; + load_info->SrcFirstElement = src_first_element; + load_info->DstFirstElement = dst_first_element; + load_info->NumElements = num_elems; + load_info->Filter = filter; + load_info->MipFilter = mip_filter; +} -/* dds_pixel_format.flags */ -#define DDS_PF_ALPHA 0x00000001 -#define DDS_PF_ALPHA_ONLY 0x00000002 -#define DDS_PF_FOURCC 0x00000004 -#define DDS_PF_RGB 0x00000040 -#define DDS_PF_LUMINANCE 0x00020000 -#define DDS_PF_BUMPLUMINANCE 0x00040000 -#define DDS_PF_BUMPDUDV 0x00080000 +static void set_d3d11_2d_texture_desc(D3D11_TEXTURE2D_DESC *desc, uint32_t width, uint32_t height, uint32_t mip_levels, + uint32_t array_size, DXGI_FORMAT format, uint32_t sample_count, uint32_t sample_quality, uint32_t usage, + uint32_t bind_flags, uint32_t cpu_access_flags, uint32_t misc_flags) +{ + desc->Width = width; + desc->Height = height; + desc->MipLevels = mip_levels; + desc->ArraySize = array_size; + desc->Format = format; + desc->SampleDesc.Count = sample_count; + desc->SampleDesc.Quality = sample_quality; + desc->Usage = usage; + desc->BindFlags = bind_flags; + desc->CPUAccessFlags = cpu_access_flags; + desc->MiscFlags = misc_flags; +} -struct dds_pixel_format +static void init_subresource_data(D3D11_SUBRESOURCE_DATA *subresources, const void *data, uint32_t width, uint32_t height, + uint32_t depth, uint32_t mip_levels, uint32_t array_size, DXGI_FORMAT format) { - DWORD size; - DWORD flags; - DWORD fourcc; - DWORD bpp; - DWORD rmask; - DWORD gmask; - DWORD bmask; - DWORD amask; -}; + const uint8_t *pixel_ptr = data; + uint32_t i, j; -struct dds_header + for (i = 0; i < array_size; ++i) + { + uint32_t tmp_width, tmp_height, tmp_depth; + + tmp_width = width; + tmp_height = height; + tmp_depth = depth; + for (j = 0; j < mip_levels; ++j) + { + D3D11_SUBRESOURCE_DATA *subresource = &subresources[(i * mip_levels) + j]; + + subresource->pSysMem = pixel_ptr; + subresource->SysMemPitch = (tmp_width * get_bpp_from_format(format) + 7) / 8; + subresource->SysMemSlicePitch = subresource->SysMemPitch * tmp_height; + if (is_block_compressed(format)) + subresource->SysMemPitch *= 4; + pixel_ptr += (subresource->SysMemSlicePitch * tmp_depth); + + tmp_width = max(tmp_width / 2, 1); + tmp_height = max(tmp_height / 2, 1); + tmp_depth = max(tmp_depth / 2, 1); + } + } +} + +static uint8_t *init_buffer_color(uint8_t *buf, uint32_t color, uint32_t width, uint32_t height, uint32_t depth) { - DWORD size; - DWORD flags; - DWORD height; - DWORD width; - DWORD pitch_or_linear_size; - DWORD depth; - DWORD miplevels; - DWORD reserved[11]; - struct dds_pixel_format pixel_format; - DWORD caps; - DWORD caps2; - DWORD caps3; - DWORD caps4; - DWORD reserved2; -}; + uint32_t i, total_pixels = width * height * depth; + uint32_t *color_buf = (uint32_t *)buf; -/* fills dds_header with reasonable default values */ -static void fill_dds_header(struct dds_header *header) + for (i = 0; i < total_pixels; ++i) + color_buf[i] = color; + return buf + (total_pixels * 4); +} + +static void set_texture_sub_resource_color(ID3D11DeviceContext *context, ID3D11Resource *rsrc, uint32_t idx, uint32_t color, + uint32_t width, uint32_t height, uint32_t depth) { - memset(header, 0, sizeof(*header)); + uint8_t tmp_buf[1024]; - header->size = sizeof(*header); - header->flags = DDS_CAPS | DDS_WIDTH | DDS_HEIGHT | DDS_PIXELFORMAT; - header->height = 4; - header->width = 4; - header->pixel_format.size = sizeof(header->pixel_format); - /* X8R8G8B8 */ - header->pixel_format.flags = DDS_PF_RGB; - header->pixel_format.fourcc = 0; - header->pixel_format.bpp = 32; - header->pixel_format.rmask = 0xff0000; - header->pixel_format.gmask = 0x00ff00; - header->pixel_format.bmask = 0x0000ff; - header->pixel_format.amask = 0; - header->caps = DDS_CAPS_TEXTURE; + init_buffer_color(tmp_buf, color, width, height, depth); + ID3D11DeviceContext_UpdateSubresource(context, rsrc, idx, NULL, (const void *)tmp_buf, width * sizeof(color), + width * height * sizeof(color)); } -#define check_dds_pixel_format(flags, fourcc, bpp, rmask, gmask, bmask, amask, format) \ - check_dds_pixel_format_(__LINE__, flags, fourcc, bpp, rmask, gmask, bmask, amask, format) -static void check_dds_pixel_format_(unsigned int line, DWORD flags, DWORD fourcc, DWORD bpp, - DWORD rmask, DWORD gmask, DWORD bmask, DWORD amask, DXGI_FORMAT expected_format) +static void test_D3DX11LoadTextureFromTexture(void) { - D3DX11_IMAGE_INFO info; + static const uint32_t test_cubemap_face_colors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffffff00, 0xffff00ff, 0xff00ffff }; + static const uint32_t test_tex_2d_array_colors[] = { 0xff0000ff, 0xff00ff00, 0xffff0000, 0xff000000 }; + D3D11_SUBRESOURCE_DATA sub_resource_data[6] = { 0 }; + D3DX11_TEXTURE_LOAD_INFO load_info; + ID3D11Texture2D *tex_2d, *tex2_2d; + D3D11_TEXTURE2D_DESC tex_2d_desc; + uint8_t tmp_buf[1024], *tmp_ptr; + ID3D11DeviceContext *context; + ID3D11Device *device; + RECT tmp_rect; + uint32_t i; HRESULT hr; - struct + + device = create_device(); + if (!device) { - DWORD magic; - struct dds_header header; - BYTE data[256]; - } dds; + skip("Failed to create device, skipping tests.\n"); + return; + } - dds.magic = MAKEFOURCC('D','D','S',' '); - fill_dds_header(&dds.header); - dds.header.pixel_format.flags = flags; - dds.header.pixel_format.fourcc = fourcc; - dds.header.pixel_format.bpp = bpp; - dds.header.pixel_format.rmask = rmask; - dds.header.pixel_format.gmask = gmask; - dds.header.pixel_format.bmask = bmask; - dds.header.pixel_format.amask = amask; - memset(dds.data, 0, sizeof(dds.data)); + CoInitialize(NULL); + ID3D11Device_GetImmediateContext(device, &context); + + /* + * Tests that still need to be written: + * -pSrcBox/pDstBox, how they behave WRT mip levels, too large, too small. + * -3D texture test. + */ + + /* 8x8 2D texture array with 2 elements and 2 mip levels. */ + tmp_ptr = tmp_buf; + for (i = 0; i < ARRAY_SIZE(test_tex_2d_array_colors); ++i) + tmp_ptr = init_buffer_color(tmp_ptr, test_tex_2d_array_colors[i], !(i & 0x1) ? 8 : 4, !(i & 0x1) ? 8 : 4, 1); + + set_d3d11_2d_texture_desc(&tex_2d_desc, 8, 8, 2, 2, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); + hr = ID3D11Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < ARRAY_SIZE(test_tex_2d_array_colors); ++i) + check_texture_sub_resource_color(tex_2d, i, NULL, test_tex_2d_array_colors[i], 0); + + /* 8x8 2D texture with 4 mip levels. */ + memset(tmp_buf, 0xff, sizeof(tmp_buf)); + set_d3d11_2d_texture_desc(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); + hr = ID3D11Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 4; ++i) + check_texture_sub_resource_color(tex2_2d, i, NULL, 0xffffffff, 0); + + /* + * If a NULL load info argument is supplied, the default D3DX11_TEXTURE_LOAD_INFO + * values are used. The first 2 mip levels from tex_2d are loaded, and + * the last 2 mip levels of tex2_2d are generated from mip level 1. + */ + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, NULL, (ID3D11Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 4; ++i) + check_texture_sub_resource_color(tex2_2d, i, NULL, test_tex_2d_array_colors[min(i, 1)], 0); + + /* NULL device context. */ + hr = D3DX11LoadTextureFromTexture(NULL, (ID3D11Resource *)tex_2d, NULL, (ID3D11Resource *)tex2_2d); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + + /* Invalid Filter argument. */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, 0, 0, 0, 9, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + + /* Filter argument of 0 is invalid. */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + + /* Invalid MipFilter argument. */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, 0, 0, 0, D3DX11_DEFAULT, 9); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + + /* MipFilter argument is only validated if mip levels are generated. */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 2, 0, 0, 0, D3DX11_DEFAULT, 9); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* + * Cannot use the same source/destination texture with matching first mip + * level and array element. + */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, 0, 0, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex_2d); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + + /* Same first mip level, different first element. */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, 0, 1, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 2; ++i) + check_texture_sub_resource_color(tex_2d, 2 + i, NULL, test_tex_2d_array_colors[i], 0); + + /* Restore values. */ + for (i = 0; i < ARRAY_SIZE(test_tex_2d_array_colors); ++i) + { + set_texture_sub_resource_color(context, (ID3D11Resource *)tex_2d, i, test_tex_2d_array_colors[i], !(i & 0x1) ? 8 : 4, + !(i & 0x1) ? 8 : 4, 1); + check_texture_sub_resource_color(tex_2d, i, NULL, test_tex_2d_array_colors[i], 0); + } - hr = D3DX11GetImageInfoFromMemory(&dds, sizeof(dds), NULL, &info, NULL); - ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx for pixel format %#x.\n", hr, expected_format); - if (SUCCEEDED(hr)) + /* Same first array element, but different FirstMips. */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 1, 0, 0, 0, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 4; ++i) + check_texture_sub_resource_color(tex_2d, i, NULL, test_tex_2d_array_colors[(i < 2) ? 0 : 2], 0); + + for (i = 0; i < ARRAY_SIZE(test_tex_2d_array_colors); ++i) { - ok_(__FILE__, line)(info.Format == expected_format, "Unexpected format %#x, expected %#x\n", - info.Format, expected_format); + set_texture_sub_resource_color(context, (ID3D11Resource *)tex_2d, i, test_tex_2d_array_colors[i], !(i & 0x1) ? 8 : 4, + !(i & 0x1) ? 8 : 4, 1); + check_texture_sub_resource_color(tex_2d, i, NULL, test_tex_2d_array_colors[i], 0); + } + + /* + * If SrcFirstElement/DstFirstElement are greater than the total number of + * elements, element 0 is used. + */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 2, 2, 0, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 2; ++i) + check_texture_sub_resource_color(tex2_2d, i, NULL, test_tex_2d_array_colors[i], 0); + + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 2, 1, 0, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 2; ++i) + check_texture_sub_resource_color(tex2_2d, i, NULL, test_tex_2d_array_colors[2 + i], 0); + + for (i = 0; i < 4; ++i) + { + set_texture_sub_resource_color(context, (ID3D11Resource *)tex2_2d, i, 0xff000000 | (0xff << (8 * i)), 8 >> i, 8 >> i, 1); + check_texture_sub_resource_color(tex2_2d, i, NULL, 0xff000000 | (0xff << (8 * i)), 0); + } + + /* DstFirstElement value tests. */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 2, 0, 2, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex2_2d, &load_info, (ID3D11Resource *)tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 2; ++i) + check_texture_sub_resource_color(tex_2d, i, NULL, 0xff000000 | (0xff << (8 * i)), 0); + for (i = 0; i < 2; ++i) + check_texture_sub_resource_color(tex_2d, 2 + i, NULL, test_tex_2d_array_colors[2 + i], 0); + + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 2, 0, 1, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex2_2d, &load_info, (ID3D11Resource *)tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 4; ++i) + check_texture_sub_resource_color(tex_2d, i, NULL, !(i & 0x01) ? 0xff0000ff : 0xff00ff00, 0); + + for (i = 0; i < 4; ++i) + { + set_texture_sub_resource_color(context, (ID3D11Resource *)tex_2d, i, test_tex_2d_array_colors[i], !(i & 0x1) ? 8 : 4, + !(i & 0x1) ? 8 : 4, 1); + check_texture_sub_resource_color(tex_2d, i, NULL, test_tex_2d_array_colors[i], 0); + + set_texture_sub_resource_color(context, (ID3D11Resource *)tex2_2d, i, 0xff000000 | (0xff << (8 * i)), 8 >> i, 8 >> i, 1); + check_texture_sub_resource_color(tex2_2d, i, NULL, 0xff000000 | (0xff << (8 * i)), 0); + } + + /* + * If SrcFirstMip is greater than the total number of mip levels, the + * final mip level is used, E.g, if SrcFirstMip is set to 3, but the + * texture only has 2 mip levels, mip level 2 is used. + */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 2, 0, 1, 0, 0, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex2_2d, 0, NULL, test_tex_2d_array_colors[1], 0); + + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 1, 0, 0, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex2_2d, 0, NULL, test_tex_2d_array_colors[0], 0); + + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 1, 0, 1, 0, 0, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex2_2d, 0, NULL, test_tex_2d_array_colors[1], 0); + + /* + * If DstFirstMip is greater than the total number of mips, nothing is + * loaded. + */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 5, 1, 0, 0, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex2_2d, 0, NULL, test_tex_2d_array_colors[1], 0); + check_texture_sub_resource_color(tex2_2d, 3, NULL, 0xff000000, 0); + + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 3, 1, 0, 0, 0, D3DX11_DEFAULT, D3DX11_DEFAULT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex2_2d, 3, NULL, test_tex_2d_array_colors[0], 0); + + ID3D11Texture2D_Release(tex2_2d); + ID3D11Texture2D_Release(tex_2d); + + for (i = 0; i < ARRAY_SIZE(test_texture_format_conversion); ++i) + { + const struct test_texture_format_conversion *test = &test_texture_format_conversion[i]; + const D3D11_TEXTURE2D_DESC *src_desc = &test->src_desc; + D3D11_TEXTURE2D_DESC tmp_desc = test->src_desc; + ID3D11Texture2D *src_texture, *dst_texture; + D3D11_MAPPED_SUBRESOURCE map = { 0 }; + + winetest_push_context("Texture format conversion test %u", i); + src_texture = dst_texture = NULL; + + init_subresource_data(sub_resource_data, test->src_data, src_desc->Width, src_desc->Height, 1, + src_desc->MipLevels, src_desc->ArraySize, src_desc->Format); + hr = ID3D11Device_CreateTexture2D(device, src_desc, sub_resource_data, &src_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_texture; + + tmp_desc.Format = test->dst_format; + tmp_desc.Usage = D3D11_USAGE_STAGING; + tmp_desc.BindFlags = 0; + tmp_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + hr = ID3D11Device_CreateTexture2D(device, &tmp_desc, NULL, &dst_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_texture; + + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)src_texture, NULL, (ID3D11Resource *)dst_texture); + todo_wine_if(test->todo_hr) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_texture; + + hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)dst_texture, 0, D3D11_MAP_READ, 0, &map); + ok(hr == S_OK, "Failed to map destination texture, hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_texture; + + check_texture_data_level(map.pData, map.RowPitch, 0, tmp_desc.Width, tmp_desc.Height, 1, test->dst_format, + test->expected_dst_data, test->max_diff, test->todo_data); +cleanup_next_texture: + if (src_texture) + ID3D11Texture2D_Release(src_texture); + if (map.pData) + ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)dst_texture, 0); + if (dst_texture) + ID3D11Texture2D_Release(dst_texture); + winetest_pop_context(); + } + + /* + * Texture compression tests. Rather than checking against compressed values + * (which we're unlikely to match due to differences in compression + * algorithms), we'll: + * Load our uncompressed source texture into a compressed destination texture. + * Load our compressed destination texture into a new decompressed destination texture. + * Check that the data in the new decompressed texture matches the + * original data. + */ + for (i = 0; i < ARRAY_SIZE(test_texture_compression); ++i) + { + const struct test_texture_compression *test = &test_texture_compression[i]; + const D3D11_TEXTURE2D_DESC *src_desc = &test->src_desc; + ID3D11Texture2D *src_texture, *dst_texture; + D3D11_TEXTURE2D_DESC tmp_desc = *src_desc; + D3D11_MAPPED_SUBRESOURCE map = { 0 }; + + winetest_push_context("Texture compression test %u", i); + src_texture = dst_texture = NULL; + + /* Create the uncompressed source texture. */ + init_subresource_data(sub_resource_data, (const void *)test->src_data, src_desc->Width, src_desc->Height, 1, + src_desc->MipLevels, src_desc->ArraySize, src_desc->Format); + hr = ID3D11Device_CreateTexture2D(device, src_desc, sub_resource_data, &src_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; + + /* Create the compressed destination texture. */ + tmp_desc.Format = test->compressed_format; + hr = ID3D11Device_CreateTexture2D(device, &tmp_desc, NULL, &dst_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; + + /* Load the uncompressed source into the compressed destination. */ + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)src_texture, NULL, (ID3D11Resource *)dst_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; + + ID3D11Texture2D_Release(src_texture); + src_texture = dst_texture; + + /* Now create the uncompressed destination texture to decompress into. */ + tmp_desc = *src_desc; + tmp_desc.Usage = D3D11_USAGE_STAGING; + tmp_desc.BindFlags = 0; + tmp_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + memset(tmp_buf, 0, sizeof(tmp_buf)); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, src_desc->Width, src_desc->Height, 1, + src_desc->MipLevels, src_desc->ArraySize, src_desc->Format); + hr = ID3D11Device_CreateTexture2D(device, &tmp_desc, sub_resource_data, &dst_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; + + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)src_texture, NULL, (ID3D11Resource *)dst_texture); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; + + hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)dst_texture, 0, D3D11_MAP_READ, 0, &map); + ok(hr == S_OK, "Failed to map destination texture, hr %#lx.\n", hr); + if (FAILED(hr)) + goto cleanup_next_compressed_texture; + + check_texture_data_level(map.pData, map.RowPitch, 0, tmp_desc.Width, tmp_desc.Height, 1, tmp_desc.Format, + test->src_data, 0, FALSE); +cleanup_next_compressed_texture: + if (src_texture) + ID3D11Texture2D_Release(src_texture); + if (map.pData) + ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)dst_texture, 0); + if (dst_texture) + ID3D11Texture2D_Release(dst_texture); + winetest_pop_context(); + } + + /* + * Use D3DX11LoadTextureFromTexture to generate mip levels. Some games + * (Total War: Shogun 2) do this instead of using D3DX11FilterTexture. + */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 1, 2, 0, 0, 1, D3DX11_FILTER_POINT, D3DX11_FILTER_NONE); + set_d3d11_2d_texture_desc(&tex_2d_desc, 8, 8, 3, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0); + + memset(tmp_buf, 0, sizeof(tmp_buf)); + memcpy(tmp_buf, bc1_to_bc3_8_8_decompressed, sizeof(bc1_to_bc3_8_8_decompressed)); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); + + hr = ID3D11Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex_2d, 1, NULL, 0x00000000, 0); + check_texture_sub_resource_color(tex_2d, 2, NULL, 0x00000000, 0); + + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + SetRect(&tmp_rect, 0, 0, 2, 2); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xffff0000, 0); + SetRect(&tmp_rect, 2, 0, 4, 2); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff00ff00, 0); + SetRect(&tmp_rect, 0, 2, 2, 4); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff0000ff, 0); + SetRect(&tmp_rect, 2, 2, 4, 4); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff000000, 0); + + SetRect(&tmp_rect, 0, 0, 1, 1); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xffff0000, 0); + SetRect(&tmp_rect, 1, 0, 2, 1); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff00ff00, 0); + SetRect(&tmp_rect, 0, 1, 1, 2); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff0000ff, 0); + SetRect(&tmp_rect, 1, 1, 2, 2); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff000000, 0); + + ID3D11Texture2D_Release(tex_2d); + + /* Cubemap. */ + set_d3d11_2d_texture_desc(&tex_2d_desc, 4, 4, 1, 6, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, D3D11_RESOURCE_MISC_TEXTURECUBE); + init_subresource_data(sub_resource_data, (const void *)rgba_4_4_cubemap, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); + + hr = ID3D11Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < 6; ++i) + check_texture_sub_resource_color(tex_2d, i, NULL, test_cubemap_face_colors[i], 0); + + /* Load individual faces of a cubemap texture into a non-cubemap texture. */ + set_d3d11_2d_texture_desc(&tex_2d_desc, 4, 4, 3, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0); + hr = ID3D11Device_CreateTexture2D(device, &tex_2d_desc, NULL, &tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + for (i = 0; i < 6; ++i) + { + /* On top of loading individual faces, we'll also generate mips. */ + set_d3dx11_texture_load_info(&load_info, NULL, NULL, 0, 0, 0, i, 0, 1, D3DX11_FILTER_POINT, D3DX11_FILTER_POINT); + hr = D3DX11LoadTextureFromTexture(context, (ID3D11Resource *)tex_2d, &load_info, (ID3D11Resource *)tex2_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + check_texture_sub_resource_color(tex2_2d, 0, NULL, test_cubemap_face_colors[i], 0); + check_texture_sub_resource_color(tex2_2d, 1, NULL, test_cubemap_face_colors[i], 0); + check_texture_sub_resource_color(tex2_2d, 2, NULL, test_cubemap_face_colors[i], 0); } + + ID3D11Texture2D_Release(tex2_2d); + ID3D11Texture2D_Release(tex_2d); + + CoUninitialize(); + + ID3D11DeviceContext_Release(context); + ok(!ID3D11Device_Release(device), "Unexpected refcount.\n"); } -static void test_D3DX11GetImageInfoFromMemory(void) +static void test_D3DX11FilterTexture(void) { - D3DX11_IMAGE_INFO info; + D3D11_SUBRESOURCE_DATA sub_resource_data[4] = { 0 }; + D3D11_TEXTURE2D_DESC tex_2d_desc; + ID3D11DeviceContext *context; + ID3D11Texture2D *tex_2d; + uint8_t tmp_buf[1024]; + ID3D11Device *device; + RECT tmp_rect; HRESULT hr; - if (!strcmp(winetest_platform, "wine")) + device = create_device(); + if (!device) { - skip("Skipping D3DX11GetImageInfoFromMemory() tests.\n"); + skip("Failed to create device, skipping tests.\n"); return; } - hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, sizeof(bmp_1bpp), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + CoInitialize(NULL); + + ID3D11Device_GetImmediateContext(device, &context); + set_d3d11_2d_texture_desc(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0); + memset(tmp_buf, 0, sizeof(tmp_buf)); + memcpy(tmp_buf, bc1_to_bc3_8_8_decompressed, sizeof(bc1_to_bc3_8_8_decompressed)); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); + + hr = ID3D11Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_texture_sub_resource_color(tex_2d, 1, NULL, 0x00000000, 0); + check_texture_sub_resource_color(tex_2d, 2, NULL, 0x00000000, 0); + check_texture_sub_resource_color(tex_2d, 3, NULL, 0x00000000, 0); + + /* Invalid filter arguments. */ + hr = D3DX11FilterTexture(context, (ID3D11Resource *)tex_2d, 0, 0); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + + hr = D3DX11FilterTexture(context, (ID3D11Resource *)tex_2d, 0, 9); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + + /* + * Filter argument isn't validated if src_level argument is greater than + * total mip levels. + */ + hr = D3DX11FilterTexture(context, (ID3D11Resource *)tex_2d, 5, 9); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* NULL device context. */ + hr = D3DX11FilterTexture(NULL, (ID3D11Resource *)tex_2d, 5, 9); + ok(hr == D3DERR_INVALIDCALL, "Unexpected hr %#lx.\n", hr); + + hr = D3DX11FilterTexture(context, (ID3D11Resource *)tex_2d, 0, D3DX11_FILTER_POINT); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + SetRect(&tmp_rect, 0, 0, 2, 2); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xffff0000, 0); + SetRect(&tmp_rect, 2, 0, 4, 2); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff00ff00, 0); + SetRect(&tmp_rect, 0, 2, 2, 4); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff0000ff, 0); + SetRect(&tmp_rect, 2, 2, 4, 4); + check_texture_sub_resource_color(tex_2d, 1, &tmp_rect, 0xff000000, 0); + + SetRect(&tmp_rect, 0, 0, 1, 1); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xffff0000, 0); + SetRect(&tmp_rect, 1, 0, 2, 1); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff00ff00, 0); + SetRect(&tmp_rect, 0, 1, 1, 2); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff0000ff, 0); + SetRect(&tmp_rect, 1, 1, 2, 2); + check_texture_sub_resource_color(tex_2d, 2, &tmp_rect, 0xff000000, 0); + + check_texture_sub_resource_color(tex_2d, 3, NULL, 0xffff0000, 0); + + ID3D11Texture2D_Release(tex_2d); + + CoUninitialize(); + + ID3D11DeviceContext_Release(context); + ok(!ID3D11Device_Release(device), "Unexpected refcount.\n"); +} - hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, sizeof(bmp_1bpp) + 5, NULL, &info, NULL); /* too large size */ - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); +static HRESULT d3d11_create_texture_1d(ID3D11Device *device, uint32_t width, uint32_t mip_levels, uint32_t array_size, + DXGI_FORMAT format, D3D11_USAGE usage, uint32_t bind_flags, uint32_t cpu_access_flags, uint32_t misc_flags, + ID3D11Texture1D **tex) +{ + const D3D11_TEXTURE1D_DESC desc = { width, mip_levels, array_size, format, usage, bind_flags, cpu_access_flags, + misc_flags }; - hr = D3DX11GetImageInfoFromMemory(noimage, sizeof(noimage), NULL, NULL, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + return ID3D11Device_CreateTexture1D(device, &desc, NULL, tex); +} - hr = D3DX11GetImageInfoFromMemory(noimage, sizeof(noimage), NULL, &info, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); +static HRESULT d3d11_create_texture_2d(ID3D11Device *device, uint32_t width, uint32_t height, uint32_t mip_levels, + uint32_t array_size, DXGI_FORMAT format, uint32_t sample_count, uint32_t sample_quality, D3D11_USAGE usage, + uint32_t bind_flags, uint32_t cpu_access_flags, uint32_t misc_flags, ID3D11Texture2D **tex) +{ + const D3D11_TEXTURE2D_DESC desc = { width, height, mip_levels, array_size, format, { sample_count, sample_quality }, + usage, bind_flags, cpu_access_flags, misc_flags }; - hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, sizeof(bmp_1bpp) - 1, NULL, &info, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + return ID3D11Device_CreateTexture2D(device, &desc, NULL, tex); +} - hr = D3DX11GetImageInfoFromMemory(bmp_1bpp + 1, sizeof(bmp_1bpp) - 1, NULL, &info, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); +static HRESULT d3d11_create_texture_3d(ID3D11Device *device, uint32_t width, uint32_t height, uint32_t depth, + uint32_t mip_levels, DXGI_FORMAT format, D3D11_USAGE usage, uint32_t bind_flags, uint32_t cpu_access_flags, + uint32_t misc_flags, ID3D11Texture3D **tex) +{ + const D3D11_TEXTURE3D_DESC desc = { width, height, depth, mip_levels, format, usage, bind_flags, cpu_access_flags, + misc_flags }; - hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, 0, NULL, &info, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + return ID3D11Device_CreateTexture3D(device, &desc, NULL, tex); +} - hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, 0, NULL, NULL, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); +enum texture_type +{ + TEXTURE_2D, + TEXTURE_2D_ARRAY, + TEXTURE_3D, + TEXTURE_CUBE, + TEXTURE_1D, + TEXTURE_1D_ARRAY, + TEXTURE_TYPE_COUNT, +}; - hr = D3DX11GetImageInfoFromMemory(noimage, 0, NULL, &info, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); +static void test_save_texture_to_dds(ID3D11Device *device) +{ + struct dds_expected + { + struct dds_header header; + struct dds_header_dxt10 dxt10; + BOOL todo; + }; + static const struct + { + DXGI_FORMAT format; + struct dds_expected dds_expected[TEXTURE_TYPE_COUNT]; + } save_tests[] = + { + { DXGI_FORMAT_R8G8B8A8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0xff, 0xff00, 0xff0000, 0xff000000 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0xff, 0xff00, 0xff0000, 0xff000000 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0xff, 0xff00, 0xff0000, 0xff000000 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R10G10B10A2_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0xffc00, 0x3ff, 0xc0000000 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R10G10B10A2_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0xffc00, 0x3ff, 0xc0000000 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0xffc00, 0x3ff, 0xc0000000 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R10G10B10A2_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R10G10B10A2_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16G16B16A16_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x24, 64, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 64, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x24, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x24, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16G16_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB, 0, 32, 0xffff, 0xffff0000, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_RGB, 0, 32, 0xffff, 0xffff0000, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_RGB, 0, 32, 0xffff, 0xffff0000, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_A8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 8, 8, 4, { 0 }, + { 32, DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + /* 5. */ + { DXGI_FORMAT_R16_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6f, 16, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6f, 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6f, 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16G16_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x70, 32, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x70, 32, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x70, 32, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x71, 64, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 64, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x71, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x71, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R32_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x72, 32, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x72, 32, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x72, 32, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R32G32_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x73, 64, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 64, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x73, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x73, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + /* 10. */ + { DXGI_FORMAT_R32G32B32A32_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 128, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x74, 128, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 128, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32A32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 128, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x74, 128, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 128, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x74, 128, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 128, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32A32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 128, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32A32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_G8R8_G8B8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B'), 16, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_G8R8_G8B8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B'), 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B'), 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_G8R8_G8B8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_G8R8_G8B8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R8G8_B8G8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G'), 16, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_B8G8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G'), 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G'), 16, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_B8G8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_B8G8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_BC1_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1'), 4, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC1_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1'), 4, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1'), 4, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + { DXGI_FORMAT_BC2_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3'), 4, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC2_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3'), 4, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3'), 4, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + /* 15. */ + { DXGI_FORMAT_BC3_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5'), 8, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC3_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + { DXGI_FORMAT_BC4_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','U'), 8, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC4_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','U'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','U'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + { DXGI_FORMAT_BC4_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC4_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + { DXGI_FORMAT_BC5_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('A','T','I','2'), 8, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC5_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('A','T','I','2'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('A','T','I','2'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + { DXGI_FORMAT_BC5_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','5','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC5_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','5','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','5','S'), 8, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + } + }, + /* 20. */ + { DXGI_FORMAT_R16G16B16A16_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6e, 64, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 64, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6e, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 64, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, 0x6e, 64, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 64, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16B16A16_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 8, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R8_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 8, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 8, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 8, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + /* 25. */ + { DXGI_FORMAT_R8G8_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8G8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8G8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16_UNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R32G32B32_FLOAT, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 96, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 96, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 96, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 96, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 96, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 96, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R32G32B32_FLOAT, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_BC1_UNORM_SRGB, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC1_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC1_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_BC1_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_BC1_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + } + }, + { DXGI_FORMAT_BC2_UNORM_SRGB, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC2_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC2_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_BC2_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_BC2_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + } + }, + /* 30. */ + { DXGI_FORMAT_BC3_UNORM_SRGB, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC3_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_BC3_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_BC3_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_BC3_UNORM_SRGB, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + } + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R8G8_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 16, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R8G8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 16, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R8G8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 16, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R8G8_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + { DXGI_FORMAT_R16G16_SNORM, + { { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, 0, 2, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH, 8, 8, 32, 8, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_VOLUME, 0, 0 + }, + { DXGI_FORMAT_R16G16_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE3D, 0, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 8, 8, 32, 0, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES, 0, 0 + }, + { DXGI_FORMAT_R16G16_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, DDS_RESOURCE_MISC_TEXTURECUBE, 1, 0 }, + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 1, 0 }, + .todo = TRUE + }, + { { 124, DDS_HEIGHT | DDS_WIDTH, 1, 8, 32, 1, 4, { 0 }, + { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }, + DDS_CAPS_TEXTURE | DDSCAPS_MIPMAP, + }, + { DXGI_FORMAT_R16G16_SNORM, D3D11_RESOURCE_DIMENSION_TEXTURE1D, 0, 2, 0 }, + .todo = TRUE + }, + } + }, + }; + ID3D11DeviceContext *context; + D3DX11_IMAGE_INFO img_info; + ID3D11Resource *tex; + ID3D10Blob *buffer; + unsigned int i, j; + HRESULT hr; + struct + { + DWORD magic; + struct dds_header header; + struct dds_header_dxt10 dxt10; + } *dds; - hr = D3DX11GetImageInfoFromMemory(noimage, 0, NULL, NULL, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + ID3D11Device_GetImmediateContext(device, &context); + for (i = 0; i < ARRAY_SIZE(save_tests); ++i) + { + if (!strcmp(winetest_platform, "wine") && (save_tests[i].format == DXGI_FORMAT_G8R8_G8B8_UNORM + || save_tests[i].format == DXGI_FORMAT_R8G8_B8G8_UNORM)) + { + skip("Skipping unsupported texture format on Wine.\n"); + continue; + } + + winetest_push_context("Test %u", i); + for (j = 0; j < TEXTURE_TYPE_COUNT; ++j) + { + const struct dds_expected *dds_expected = &save_tests[i].dds_expected[j]; + + /* Cannot create a block compressed 1D texture. */ + if (is_block_compressed(save_tests[i].format) && (j >= TEXTURE_1D)) + continue; + + switch (j) + { + case TEXTURE_1D: + hr = d3d11_create_texture_1d(device, 8, 4, 1, save_tests[i].format, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, (ID3D11Texture1D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case TEXTURE_1D_ARRAY: + hr = d3d11_create_texture_1d(device, 8, 4, 2, save_tests[i].format, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, (ID3D11Texture1D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case TEXTURE_2D: + hr = d3d11_create_texture_2d(device, 8, 8, 4, 1, save_tests[i].format, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, (ID3D11Texture2D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case TEXTURE_2D_ARRAY: + hr = d3d11_create_texture_2d(device, 8, 8, 4, 2, save_tests[i].format, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, (ID3D11Texture2D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case TEXTURE_3D: + hr = d3d11_create_texture_3d(device, 8, 8, 8, 4, save_tests[i].format, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, (ID3D11Texture3D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case TEXTURE_CUBE: + hr = d3d11_create_texture_2d(device, 8, 8, 4, 6, save_tests[i].format, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, D3D11_RESOURCE_MISC_TEXTURECUBE, (ID3D11Texture2D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + } + + if (FAILED(hr)) + continue; + + winetest_push_context("Texture type %u", j); + hr = D3DX11SaveTextureToMemory(context, tex, D3DX11_IFF_DDS, &buffer, 0); + todo_wine_if(dds_expected->todo) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + dds = ID3D10Blob_GetBufferPointer(buffer); + + hr = D3DX11GetImageInfoFromMemory(ID3D10Blob_GetBufferPointer(buffer), ID3D10Blob_GetBufferSize(buffer), NULL, + &img_info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!memcmp(&dds_expected->header, &dds->header, sizeof(dds->header)), "Header mismatch.\n"); + if (dds->header.pixel_format.fourcc == MAKEFOURCC('D','X','1','0')) + ok(!memcmp(&dds_expected->dxt10, &dds->dxt10, sizeof(dds->dxt10)), "DXT10 header mismatch.\n"); + switch (j) + { + case TEXTURE_1D: + check_image_info_values(&img_info, 8, 1, 1, 1, 4, 0, save_tests[i].format, + D3D11_RESOURCE_DIMENSION_TEXTURE1D, D3DX11_IFF_DDS, FALSE); + break; + + case TEXTURE_1D_ARRAY: + check_image_info_values(&img_info, 8, 1, 1, 2, 4, 0, save_tests[i].format, + D3D11_RESOURCE_DIMENSION_TEXTURE1D, D3DX11_IFF_DDS, FALSE); + break; + + case TEXTURE_2D: + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, save_tests[i].format, + D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS, FALSE); + break; + + case TEXTURE_2D_ARRAY: + check_image_info_values(&img_info, 8, 8, 1, 2, 4, 0, save_tests[i].format, + D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS, FALSE); + break; + + case TEXTURE_3D: + check_image_info_values(&img_info, 8, 8, 8, 1, 4, 0, save_tests[i].format, + D3D11_RESOURCE_DIMENSION_TEXTURE3D, D3DX11_IFF_DDS, FALSE); + break; + + case TEXTURE_CUBE: + check_image_info_values(&img_info, 8, 8, 1, 6, 4, D3D11_RESOURCE_MISC_TEXTURECUBE, + save_tests[i].format, D3D11_RESOURCE_DIMENSION_TEXTURE2D, D3DX11_IFF_DDS, FALSE); + break; + } + + ID3D10Blob_Release(buffer); + } + ID3D11Resource_Release(tex); + winetest_pop_context(); + } + winetest_pop_context(); + } + ID3D11DeviceContext_Release(context); +} - hr = D3DX11GetImageInfoFromMemory(noimage, 0, NULL, &info, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); +static void check_image_wic_pixel_format(IWICImagingFactory *factory, const void *data, unsigned int size, + const GUID *expected_fmt, BOOL todo) +{ + IWICBitmapFrameDecode *frame = NULL; + IWICBitmapDecoder *decoder = NULL; + IWICStream *stream = NULL; + HRESULT hr; + GUID fmt; - hr = D3DX11GetImageInfoFromMemory(NULL, 4, NULL, NULL, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = IWICImagingFactory_CreateStream(factory, &stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = D3DX11GetImageInfoFromMemory(NULL, 4, NULL, &info, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = IWICStream_InitializeFromMemory(stream, (BYTE *)data, size); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = D3DX11GetImageInfoFromMemory(NULL, 0, NULL, NULL, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream *)stream, NULL, 0, &decoder); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - /* test BMP support */ - hr = D3DX11GetImageInfoFromMemory(bmp_1bpp, sizeof(bmp_1bpp), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 1, "Unexpected width %u.\n", info.Width); - ok(info.Height == 1, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 1, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.MiscFlags == 0, "Unexpected misc flags %#x\n", info.MiscFlags); - ok(info.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_BMP, "Unexpected image file format %#x.\n", info.ImageFileFormat); + hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = D3DX11GetImageInfoFromMemory(bmp_2bpp, sizeof(bmp_2bpp), NULL, &info, NULL); - ok(hr == E_FAIL, "Got unexpected hr %#lx.\n", hr); + hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &fmt); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(todo) ok(IsEqualGUID(expected_fmt, &fmt), "Unexpected WIC format %s.\n", debugstr_guid(&fmt)); - hr = D3DX11GetImageInfoFromMemory(bmp_4bpp, sizeof(bmp_4bpp), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 1, "Unexpected width %u.\n", info.Width); - ok(info.Height == 1, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 1, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.MiscFlags == 0, "Unexpected misc flags %#x\n", info.MiscFlags); - ok(info.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_BMP, "Unexpected image file format %#x.\n", info.ImageFileFormat); + IWICBitmapFrameDecode_Release(frame); + IWICBitmapDecoder_Release(decoder); + IWICStream_Release(stream); +} - hr = D3DX11GetImageInfoFromMemory(bmp_8bpp, sizeof(bmp_8bpp), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 1, "Unexpected width %u.\n", info.Width); - ok(info.Height == 1, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 1, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.MiscFlags == 0, "Unexpected misc flags %#x\n", info.MiscFlags); - ok(info.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_BMP, "Unexpected image file format %#x.\n", info.ImageFileFormat); +static void test_save_texture_to_iffs(ID3D11Device *device) +{ + static const enum D3DX11_IMAGE_FILE_FORMAT test_iffs[] = { D3DX11_IFF_BMP, D3DX11_IFF_JPG, D3DX11_IFF_PNG, + D3DX11_IFF_TIFF, D3DX11_IFF_GIF, D3DX11_IFF_WMP }; + static const char *test_iff_str[] = { "D3DX11_IFF_BMP", "D3DX11_IFF_JPG", "D3DX11_IFF_PNG", + "D3DX11_IFF_TIFF", "D3DX11_IFF_GIF", "D3DX11_IFF_WMP" }; + struct wic_expected + { + const GUID *fmt; + BOOL todo; + }; + static const struct + { + DXGI_FORMAT format; + BOOL supported; + struct wic_expected wic_expected[ARRAY_SIZE(test_iffs)]; + } save_tests[] = + { + { DXGI_FORMAT_R8G8B8A8_UNORM, TRUE, + { { &GUID_WICPixelFormat32bppBGR, FALSE }, + { &GUID_WICPixelFormat24bppBGR, FALSE }, + { &GUID_WICPixelFormat32bppBGRA, FALSE }, + { &GUID_WICPixelFormat32bppBGRA, FALSE }, + { NULL }, + { &GUID_WICPixelFormat32bppBGRA, FALSE }, + }, + }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, TRUE, + { { &GUID_WICPixelFormat64bppRGBAFixedPoint, TRUE }, + { &GUID_WICPixelFormat24bppBGR, FALSE }, + { &GUID_WICPixelFormat64bppRGBA, FALSE }, + { &GUID_WICPixelFormat64bppRGBA, FALSE }, + { NULL }, + { &GUID_WICPixelFormat64bppRGBAHalf, FALSE }, + }, + }, + { DXGI_FORMAT_R32G32B32A32_FLOAT, TRUE, + { { &GUID_WICPixelFormat64bppRGBAFixedPoint, TRUE }, + { &GUID_WICPixelFormat24bppBGR, FALSE }, + { &GUID_WICPixelFormat64bppRGBA, FALSE }, + { &GUID_WICPixelFormat64bppRGBA, FALSE }, + { NULL }, + { &GUID_WICPixelFormat128bppRGBAFloat, FALSE }, + }, + }, + { DXGI_FORMAT_R16_UNORM, TRUE, + { { &GUID_WICPixelFormat64bppRGBAFixedPoint, TRUE }, + { &GUID_WICPixelFormat8bppGray, FALSE }, + { &GUID_WICPixelFormat16bppGray, FALSE }, + { &GUID_WICPixelFormat16bppGray, FALSE }, + { NULL }, + { &GUID_WICPixelFormat16bppGrayFixedPoint, FALSE }, + }, + }, + { DXGI_FORMAT_R10G10B10A2_UNORM, FALSE }, + /* 5. */ + { DXGI_FORMAT_R16G16B16A16_UNORM, FALSE }, + { DXGI_FORMAT_R16G16_UNORM, FALSE }, + { DXGI_FORMAT_A8_UNORM, FALSE }, + { DXGI_FORMAT_R16_FLOAT, FALSE }, + { DXGI_FORMAT_R16G16_FLOAT, FALSE }, + /* 10. */ + { DXGI_FORMAT_R32_FLOAT, FALSE }, + { DXGI_FORMAT_R32G32_FLOAT, FALSE }, + { DXGI_FORMAT_G8R8_G8B8_UNORM, FALSE }, + { DXGI_FORMAT_R8G8_B8G8_UNORM, FALSE }, + { DXGI_FORMAT_BC1_UNORM, FALSE }, + /* 15. */ + { DXGI_FORMAT_BC2_UNORM, FALSE }, + { DXGI_FORMAT_BC3_UNORM, FALSE }, + { DXGI_FORMAT_BC4_UNORM, FALSE }, + { DXGI_FORMAT_BC4_SNORM, FALSE }, + { DXGI_FORMAT_BC5_UNORM, FALSE }, + /* 20. */ + { DXGI_FORMAT_BC5_SNORM, FALSE }, + { DXGI_FORMAT_R16G16B16A16_SNORM, FALSE }, + /* Supported on d3dx11, but not d3dx10. */ + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, TRUE, + { { &GUID_WICPixelFormat32bppBGR, FALSE }, + { &GUID_WICPixelFormat24bppBGR, FALSE }, + { &GUID_WICPixelFormat32bppBGRA, FALSE }, + { &GUID_WICPixelFormat32bppBGRA, FALSE }, + { NULL }, + { &GUID_WICPixelFormat32bppBGRA, FALSE }, + }, + }, + { DXGI_FORMAT_R8_UNORM, FALSE }, + { DXGI_FORMAT_R8_SNORM, FALSE }, + /* 25. */ + { DXGI_FORMAT_R8G8_UNORM, FALSE }, + { DXGI_FORMAT_R32G32B32_FLOAT, FALSE }, + { DXGI_FORMAT_BC1_UNORM_SRGB, FALSE }, + { DXGI_FORMAT_BC2_UNORM_SRGB, FALSE }, + { DXGI_FORMAT_BC3_UNORM_SRGB, FALSE }, + /* 30. */ + { DXGI_FORMAT_R8G8B8A8_SNORM, FALSE }, + { DXGI_FORMAT_R8G8_SNORM, FALSE }, + { DXGI_FORMAT_R16G16_SNORM, FALSE }, + }; + IWICImagingFactory *factory = NULL; + ID3D11DeviceContext *context; + D3DX11_IMAGE_INFO img_info; + ID3D11Resource *tex; + ID3D10Blob *buffer; + unsigned int i, j; + HRESULT hr; - hr = D3DX11GetImageInfoFromMemory(bmp_32bpp_xrgb, sizeof(bmp_32bpp_xrgb), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 2, "Unexpected width %u.\n", info.Width); - ok(info.Height == 2, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 1, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.MiscFlags == 0, "Unexpected misc flags %#x\n", info.MiscFlags); - ok(info.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_BMP, "Unexpected image file format %#x.\n", info.ImageFileFormat); + hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICImagingFactory, (void **)&factory); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = D3DX11GetImageInfoFromMemory(bmp_32bpp_argb, sizeof(bmp_32bpp_argb), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 2, "Unexpected width %u.\n", info.Width); - ok(info.Height == 2, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 1, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.MiscFlags == 0, "Unexpected misc flags %#x\n", info.MiscFlags); - ok(info.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_BMP, "Unexpected image file format %#x.\n", info.ImageFileFormat); + ID3D11Device_GetImmediateContext(device, &context); + for (i = 0; i < ARRAY_SIZE(save_tests); ++i) + { + if (!strcmp(winetest_platform, "wine") && (save_tests[i].format == DXGI_FORMAT_G8R8_G8B8_UNORM + || save_tests[i].format == DXGI_FORMAT_R8G8_B8G8_UNORM)) + { + skip("Skipping unsupported format on Wine.\n"); + continue; + } + + hr = d3d11_create_texture_2d(device, 8, 8, 4, 1, save_tests[i].format, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, (ID3D11Texture2D **)&tex); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + continue; + + winetest_push_context("Test %u", i); + for (j = 0; j < ARRAY_SIZE(test_iffs); ++j) + { + const HRESULT expected_hr = save_tests[i].supported ? S_OK : E_FAIL; + + winetest_push_context("Image format %s", test_iff_str[j]); + hr = D3DX11SaveTextureToMemory(context, tex, test_iffs[j], &buffer, 0); + + /* GIF saving is never supported, regardless of texture format. */ + if (test_iffs[j] == D3DX11_IFF_GIF) + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + else + todo_wine_if(test_iffs[j] == D3DX11_IFF_WMP) ok(hr == expected_hr, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + check_image_wic_pixel_format(factory, ID3D10Blob_GetBufferPointer(buffer), ID3D10Blob_GetBufferSize(buffer), + save_tests[i].wic_expected[j].fmt, save_tests[i].wic_expected[j].todo); + + hr = D3DX11GetImageInfoFromMemory(ID3D10Blob_GetBufferPointer(buffer), ID3D10Blob_GetBufferSize(buffer), NULL, + &img_info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + check_image_info_values(&img_info, 8, 8, 1, 1, 1, 0, DXGI_FORMAT_R8G8B8A8_UNORM, + D3D11_RESOURCE_DIMENSION_TEXTURE2D, test_iffs[j], FALSE); + ID3D10Blob_Release(buffer); + } + winetest_pop_context(); + } + + ID3D11Resource_Release(tex); + winetest_pop_context(); + } + IWICImagingFactory_Release(factory); + ID3D11DeviceContext_Release(context); +} - /* Grayscale PNG */ - hr = D3DX11GetImageInfoFromMemory(png_grayscale, sizeof(png_grayscale), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 1, "Unexpected width %u.\n", info.Width); - ok(info.Height == 1, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 1, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.MiscFlags == 0, "Unexpected misc flags %#x\n", info.MiscFlags); - ok(info.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_PNG, "Unexpected image file format %#x.\n", info.ImageFileFormat); +static void test_save_texture(void) +{ + D3D11_SUBRESOURCE_DATA sub_resource_data[4] = { 0 }; + D3D11_TEXTURE2D_DESC tex_2d_desc; + ID3D11DeviceContext *context; + D3DX11_IMAGE_INFO img_info; + ID3D11Texture2D *tex_2d; + uint8_t tmp_buf[1024]; + ID3D11Device *device; + ID3D10Blob *buffer; + HRESULT hr; - /* test DDS support */ - hr = D3DX11GetImageInfoFromMemory(dds_24bit, sizeof(dds_24bit), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 2, "Unexpected width %u.\n", info.Width); - ok(info.Height == 2, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 2, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_DDS, "Unexpected image file format %#x.\n", info.ImageFileFormat); + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + return; + } - hr = D3DX11GetImageInfoFromMemory(dds_24bit, sizeof(dds_24bit) - 1, NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 2, "Unexpected width %u.\n", info.Width); - ok(info.Height == 2, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 2, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_DDS, "Unexpected image file format %#x.\n", info.ImageFileFormat); + CoInitialize(NULL); - hr = D3DX11GetImageInfoFromMemory(dds_16bit, sizeof(dds_16bit), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 2, "Unexpected width %u.\n", info.Width); - ok(info.Height == 2, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 1, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_DDS, "Unexpected image file format %#x.\n", info.ImageFileFormat); + test_save_texture_to_dds(device); + test_save_texture_to_iffs(device); - memset(&info, 0, sizeof(info)); - hr = D3DX11GetImageInfoFromMemory(dds_16bit, sizeof(dds_16bit) - 1, NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 2, "Unexpected width %u.\n", info.Width); - ok(info.Height == 2, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 1, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_DDS, "Unexpected image file format %#x.\n", info.ImageFileFormat); + set_d3d11_2d_texture_desc(&tex_2d_desc, 8, 8, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0); + memset(tmp_buf, 0, sizeof(tmp_buf)); + memcpy(tmp_buf, bc1_to_bc3_8_8_decompressed, sizeof(bc1_to_bc3_8_8_decompressed)); + init_subresource_data(sub_resource_data, (const void *)tmp_buf, tex_2d_desc.Width, tex_2d_desc.Height, 1, + tex_2d_desc.MipLevels, tex_2d_desc.ArraySize, tex_2d_desc.Format); - memset(&info, 0, sizeof(info)); - hr = D3DX11GetImageInfoFromMemory(dds_8bit, sizeof(dds_8bit), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 16, "Unexpected width %u.\n", info.Width); - ok(info.Height == 4, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 1, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.Format == DXGI_FORMAT_R8G8B8A8_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_DDS, "Unexpected image file format %#x.\n", info.ImageFileFormat); + hr = ID3D11Device_CreateTexture2D(device, &tex_2d_desc, sub_resource_data, &tex_2d); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = D3DX11GetImageInfoFromMemory(dds_cube_map, sizeof(dds_cube_map), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 4, "Unexpected width %u.\n", info.Width); - ok(info.Height == 4, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 6, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 1, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.Format == DXGI_FORMAT_BC3_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_DDS, "Unexpected image file format %#x.\n", info.ImageFileFormat); + ID3D11Device_GetImmediateContext(device, &context); + hr = D3DX11SaveTextureToMemory(context, (ID3D11Resource *)tex_2d, D3DX11_IFF_DDS, &buffer, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = D3DX11GetImageInfoFromMemory(dds_cube_map, sizeof(dds_cube_map) - 1, NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 4, "Unexpected width %u.\n", info.Width); - ok(info.Height == 4, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 1, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 6, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 1, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.Format == DXGI_FORMAT_BC3_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE2D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_DDS, "Unexpected image file format %#x.\n", info.ImageFileFormat); + hr = D3DX11GetImageInfoFromMemory(ID3D10Blob_GetBufferPointer(buffer), ID3D10Blob_GetBufferSize(buffer), NULL, + &img_info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + ID3D10Blob_Release(buffer); - hr = D3DX11GetImageInfoFromMemory(dds_volume_map, sizeof(dds_volume_map), NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 4, "Unexpected width %u.\n", info.Width); - ok(info.Height == 4, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 2, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 3, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.Format == DXGI_FORMAT_BC2_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE3D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_DDS, "Unexpected image file format %#x.\n", info.ImageFileFormat); + hr = D3DX11SaveTextureToFileA(context, (ID3D11Resource *)tex_2d, D3DX11_IFF_DDS, "test_a.dds"); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = D3DX11GetImageInfoFromMemory(dds_volume_map, sizeof(dds_volume_map) - 1, NULL, &info, NULL); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(info.Width == 4, "Unexpected width %u.\n", info.Width); - ok(info.Height == 4, "Unexpected height %u.\n", info.Height); - ok(info.Depth == 2, "Unexpected depth %u.\n", info.Depth); - ok(info.ArraySize == 1, "Unexpected array size %u.\n", info.ArraySize); - ok(info.MipLevels == 3, "Unexpected miplevels %u\n", info.MipLevels); - ok(info.Format == DXGI_FORMAT_BC2_UNORM, "Unexpected format %#x.\n", info.Format); - ok(info.ResourceDimension == D3D11_RESOURCE_DIMENSION_TEXTURE3D, "Unexpected resource type %#x.\n", info.ResourceDimension); - ok(info.ImageFileFormat == D3DX11_IFF_DDS, "Unexpected image file format %#x.\n", info.ImageFileFormat); + hr = D3DX11GetImageInfoFromFileA("test_a.dds", NULL, &img_info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + DeleteFileA("test_a.dds"); - check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC1_UNORM); - check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC2_UNORM); - check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC2_UNORM); - check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC3_UNORM); - check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0, DXGI_FORMAT_BC3_UNORM); - check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0, DXGI_FORMAT_R8G8_B8G8_UNORM); - check_dds_pixel_format(DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0, DXGI_FORMAT_G8R8_G8B8_UNORM); - check_dds_pixel_format(DDS_PF_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff, DXGI_FORMAT_A8_UNORM); - check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_RGB, 0, 16, 0xf00, 0x0f0, 0x00f, 0, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000, DXGI_FORMAT_R10G10B10A2_UNORM); - check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000, DXGI_FORMAT_R10G10B10A2_UNORM); - check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_RGB, 0, 32, 0xff0000, 0x00ff00, 0x0000ff, 0, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_RGB, 0, 32, 0x0000ff, 0x00ff00, 0xff0000, 0, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0, 0, DXGI_FORMAT_R16G16_UNORM); - check_dds_pixel_format(DDS_PF_LUMINANCE, 0, 8, 0xff, 0, 0, 0, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_LUMINANCE, 0, 16, 0xffff, 0, 0, 0, DXGI_FORMAT_R16G16B16A16_UNORM); - check_dds_pixel_format(DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 16, 0x00ff, 0, 0, 0xff00, DXGI_FORMAT_R8G8B8A8_UNORM); - check_dds_pixel_format(DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x0f, 0, 0, 0xf0, DXGI_FORMAT_R8G8B8A8_UNORM); + hr = D3DX11SaveTextureToFileW(context, (ID3D11Resource *)tex_2d, D3DX11_IFF_DDS, L"test_w.dds"); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DX11GetImageInfoFromFileW(L"test_w.dds", NULL, &img_info, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_image_info_values(&img_info, 8, 8, 1, 1, 4, 0, DXGI_FORMAT_R8G8B8A8_UNORM, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + D3DX11_IFF_DDS, FALSE); + DeleteFileW(L"test_w.dds"); + + ID3D11Texture2D_Release(tex_2d); + + CoUninitialize(); + + ID3D11DeviceContext_Release(context); + ok(!ID3D11Device_Release(device), "Unexpected refcount.\n"); } START_TEST(d3dx11) { + HMODULE wined3d; + + if ((wined3d = GetModuleHandleA("wined3d.dll"))) + { + enum wined3d_renderer (CDECL *p_wined3d_get_renderer)(void); + + if ((p_wined3d_get_renderer = (void *)GetProcAddress(wined3d, "wined3d_get_renderer")) + && p_wined3d_get_renderer() == WINED3D_RENDERER_OPENGL) + wined3d_opengl = true; + } + test_D3DX11CreateAsyncMemoryLoader(); test_D3DX11CreateAsyncFileLoader(); test_D3DX11CreateAsyncResourceLoader(); + test_D3DX11CreateAsyncTextureInfoProcessor(); + test_D3DX11CreateAsyncTextureProcessor(); + test_D3DX11CreateAsyncShaderResourceViewProcessor(); test_D3DX11CompileFromFile(); - test_D3DX11GetImageInfoFromMemory(); + test_D3DX11LoadTextureFromTexture(); + test_D3DX11FilterTexture(); + test_D3DX11CreateThreadPump(); + test_get_image_info(); + test_create_texture(); + test_create_shader_resource_view(); + test_save_texture(); } diff --git a/dlls/d3dx11_43/texture.c b/dlls/d3dx11_43/texture.c index fe7ab8549d05..ad8984483524 100644 --- a/dlls/d3dx11_43/texture.c +++ b/dlls/d3dx11_43/texture.c @@ -16,85 +16,1690 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define COBJMACROS + +#include "initguid.h" +#include "d3d11.h" #include "d3dx11.h" #include "d3dcompiler.h" +#include "dxhelpers.h" #include "wine/debug.h" +#include "assert.h" WINE_DEFAULT_DEBUG_CHANNEL(d3dx); -HRESULT WINAPI D3DX11CreateShaderResourceViewFromMemory(ID3D11Device *device, const void *data, - SIZE_T data_size, D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, - ID3D11ShaderResourceView **view, HRESULT *hresult) +HRESULT WINAPI D3DX11SaveTextureToFileW(ID3D11DeviceContext *context, ID3D11Resource *texture, + D3DX11_IMAGE_FILE_FORMAT format, const WCHAR *filename) +{ + ID3D10Blob *buffer; + HRESULT hr; + + TRACE("context %p, texture %p, format %u, filename %s.\n", context, texture, format, debugstr_w(filename)); + + if (!filename) + return E_FAIL; + + hr = D3DX11SaveTextureToMemory(context, texture, format, &buffer, 0); + if (SUCCEEDED(hr)) + { + hr = write_buffer_to_file(filename, buffer); + ID3D10Blob_Release(buffer); + } + + return hr; +} + +HRESULT WINAPI D3DX11SaveTextureToFileA(ID3D11DeviceContext *context, ID3D11Resource *texture, + D3DX11_IMAGE_FILE_FORMAT format, const char *filename) +{ + WCHAR *buffer; + int str_len; + HRESULT hr; + + TRACE("context %p, texture %p, format %u, filename %s.\n", context, texture, format, debugstr_a(filename)); + + if (!filename) + return E_FAIL; + + str_len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0); + if (!str_len) + return HRESULT_FROM_WIN32(GetLastError()); + + buffer = malloc(str_len * sizeof(*buffer)); + if (!buffer) + return E_OUTOFMEMORY; + + MultiByteToWideChar(CP_ACP, 0, filename, -1, buffer, str_len); + hr = D3DX11SaveTextureToFileW(context, texture, format, buffer); + free(buffer); + return hr; +} + +HRESULT WINAPI D3DX11GetImageInfoFromFileA(const char *src_file, ID3DX11ThreadPump *pump, D3DX11_IMAGE_INFO *info, + HRESULT *result) +{ + WCHAR *buffer; + int str_len; + HRESULT hr; + + TRACE("src_file %s, pump %p, info %p, result %p.\n", debugstr_a(src_file), pump, info, result); + + if (!src_file) + return E_FAIL; + + str_len = MultiByteToWideChar(CP_ACP, 0, src_file, -1, NULL, 0); + if (!str_len) + return HRESULT_FROM_WIN32(GetLastError()); + + buffer = malloc(str_len * sizeof(*buffer)); + if (!buffer) + return E_OUTOFMEMORY; + + MultiByteToWideChar(CP_ACP, 0, src_file, -1, buffer, str_len); + hr = D3DX11GetImageInfoFromFileW(buffer, pump, info, result); + + free(buffer); + + return hr; +} + +HRESULT WINAPI D3DX11GetImageInfoFromFileW(const WCHAR *src_file, ID3DX11ThreadPump *pump, D3DX11_IMAGE_INFO *info, + HRESULT *result) +{ + void *buffer = NULL; + DWORD size = 0; + HRESULT hr; + + TRACE("src_file %s, pump %p, info %p, result %p.\n", debugstr_w(src_file), pump, info, result); + + if (!src_file) + return E_FAIL; + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; + + if (FAILED((hr = D3DX11CreateAsyncFileLoaderW(src_file, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncTextureInfoProcessor(info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, result, NULL); + if (FAILED(hr)) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } + + if (SUCCEEDED((hr = load_file(src_file, &buffer, &size)))) + { + hr = get_image_info(buffer, size, info); + free(buffer); + } + if (result) + *result = hr; + return hr; +} + +HRESULT WINAPI D3DX11GetImageInfoFromResourceA(HMODULE module, const char *resource, ID3DX11ThreadPump *pump, + D3DX11_IMAGE_INFO *info, HRESULT *result) +{ + void *buffer; + HRESULT hr; + DWORD size; + + TRACE("module %p, resource %s, pump %p, info %p, result %p.\n", + module, debugstr_a(resource), pump, info, result); + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; + + if (FAILED((hr = D3DX11CreateAsyncResourceLoaderA(module, resource, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncTextureInfoProcessor(info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, result, NULL)))) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } + + if (FAILED((hr = load_resourceA(module, resource, &buffer, &size)))) + return hr; + hr = get_image_info(buffer, size, info); + if (result) + *result = hr; + return hr; +} + +HRESULT WINAPI D3DX11GetImageInfoFromResourceW(HMODULE module, const WCHAR *resource, ID3DX11ThreadPump *pump, + D3DX11_IMAGE_INFO *info, HRESULT *result) +{ + void *buffer; + HRESULT hr; + DWORD size; + + TRACE("module %p, resource %s, pump %p, info %p, result %p.\n", + module, debugstr_w(resource), pump, info, result); + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; + + if (FAILED((hr = D3DX11CreateAsyncResourceLoaderW(module, resource, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncTextureInfoProcessor(info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, result, NULL)))) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } + + if (FAILED((hr = load_resourceW(module, resource, &buffer, &size)))) + return hr; + hr = get_image_info(buffer, size, info); + if (result) + *result = hr; + return hr; +} + +static HRESULT d3dx11_image_info_from_d3dx_image(D3DX11_IMAGE_INFO *info, struct d3dx_image *image) +{ + DXGI_FORMAT format; + HRESULT hr = S_OK; + + memset(info, 0, sizeof(*info)); + if (image->image_file_format == D3DX_IMAGE_FILE_FORMAT_DDS_DXT10) + { + format = dxgi_format_from_dxt10_dds_d3dx_pixel_format_id(image->format); + info->ImageFileFormat = D3DX11_IFF_DDS; + } + else + { + if (image->image_file_format == D3DX_IMAGE_FILE_FORMAT_DDS) + format = dxgi_format_from_legacy_dds_d3dx_pixel_format_id(image->format); + else + format = DXGI_FORMAT_R8G8B8A8_UNORM; + info->ImageFileFormat = (D3DX11_IMAGE_FILE_FORMAT)image->image_file_format; + } + + if (format == DXGI_FORMAT_UNKNOWN) + { + WARN("Tried to load DDS file with unsupported format %#x.\n", image->format); + return E_FAIL; + } + + if (info->ImageFileFormat == D3DX11_IFF_FORCE_DWORD) + { + ERR("Unsupported d3dx image file.\n"); + return E_FAIL; + } + + info->Width = image->size.width; + info->Height = image->size.height; + info->Depth = image->size.depth; + info->ArraySize = image->layer_count; + info->MipLevels = image->mip_levels; + info->Format = format; + switch (image->resource_type) + { + case D3DX_RESOURCE_TYPE_TEXTURE_1D: + info->ResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE1D; + break; + + case D3DX_RESOURCE_TYPE_TEXTURE_2D: + info->ResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE2D; + break; + + case D3DX_RESOURCE_TYPE_CUBE_TEXTURE: + info->ResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE2D; + info->MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; + break; + + case D3DX_RESOURCE_TYPE_TEXTURE_3D: + info->ResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE3D; + break; + + default: + ERR("Unhandled resource type %d.\n", image->resource_type); + hr = E_FAIL; + break; + } + + return hr; +} + +HRESULT get_image_info(const void *data, SIZE_T size, D3DX11_IMAGE_INFO *img_info) { - FIXME("device %p, data %p, data_size %Iu, load_info %p, pump %p, view %p, hresult %p stub!\n", - device, data, data_size, load_info, pump, view, hresult); + struct d3dx_image image; + HRESULT hr; + + if (!data || !size) + return E_FAIL; + + hr = d3dx_image_init(data, size, &image, 0, D3DX_IMAGE_INFO_ONLY | D3DX_IMAGE_SUPPORT_DXT10); + if (SUCCEEDED(hr)) + hr = d3dx11_image_info_from_d3dx_image(img_info, &image); - return E_NOTIMPL; + if (FAILED(hr)) + { + WARN("Invalid or unsupported image file, hr %#lx.\n", hr); + return E_FAIL; + } + + return S_OK; } -HRESULT WINAPI D3DX11CreateTextureFromFileA(ID3D11Device *device, const char *filename, +HRESULT WINAPI D3DX11GetImageInfoFromMemory(const void *src_data, SIZE_T src_data_size, ID3DX11ThreadPump *pump, + D3DX11_IMAGE_INFO *img_info, HRESULT *hresult) +{ + HRESULT hr; + + TRACE("src_data %p, src_data_size %Iu, pump %p, img_info %p, hresult %p.\n", + src_data, src_data_size, pump, img_info, hresult); + + if (!src_data) + return E_FAIL; + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; + + if (FAILED((hr = D3DX11CreateAsyncMemoryLoader(src_data, src_data_size, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncTextureInfoProcessor(img_info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, hresult, NULL)))) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } + + hr = get_image_info(src_data, src_data_size, img_info); + if (hresult) + *hresult = hr; + return hr; +} + +void init_load_info(const D3DX11_IMAGE_LOAD_INFO *load_info, D3DX11_IMAGE_LOAD_INFO *out) +{ + if (load_info) + { + *out = *load_info; + return; + } + + out->Width = D3DX11_DEFAULT; + out->Height = D3DX11_DEFAULT; + out->Depth = D3DX11_DEFAULT; + out->FirstMipLevel = D3DX11_DEFAULT; + out->MipLevels = D3DX11_DEFAULT; + out->Usage = D3DX11_DEFAULT; + out->BindFlags = D3DX11_DEFAULT; + out->CpuAccessFlags = D3DX11_DEFAULT; + out->MiscFlags = D3DX11_DEFAULT; + out->Format = D3DX11_DEFAULT; + out->Filter = D3DX11_DEFAULT; + out->MipFilter = D3DX11_DEFAULT; + out->pSrcInfo = NULL; +} + +static HRESULT d3dx_create_subresource_data_for_texture(uint32_t width, uint32_t height, uint32_t depth, + uint32_t mip_levels, uint32_t layer_count, const struct pixel_format_desc *fmt_desc, + D3D11_SUBRESOURCE_DATA **out_sub_rsrc_data, uint8_t **pixel_data) +{ + uint8_t *sub_rsrc_data = NULL, *pixels_ptr; + uint32_t i, j, pixels_size, pixels_offset; + D3D11_SUBRESOURCE_DATA *sub_rsrcs = NULL; + HRESULT hr = S_OK; + + *pixel_data = NULL; + *out_sub_rsrc_data = NULL; + + pixels_offset = (sizeof(*sub_rsrcs) * mip_levels * layer_count); + pixels_size = d3dx_calculate_layer_pixels_size(fmt_desc->format, width, height, depth, mip_levels) * layer_count; + if (!(sub_rsrc_data = malloc(pixels_size + pixels_offset))) + return E_FAIL; + + sub_rsrcs = (D3D11_SUBRESOURCE_DATA *)sub_rsrc_data; + pixels_ptr = sub_rsrc_data + pixels_offset; + for (i = 0; i < layer_count; ++i) + { + struct volume size = { width, height, depth }; + + for (j = 0; j < mip_levels; ++j) + { + uint32_t row_pitch, slice_pitch; + + hr = d3dx_calculate_pixels_size(fmt_desc->format, size.width, size.height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + break; + + sub_rsrcs[i * mip_levels + j].pSysMem = pixels_ptr; + sub_rsrcs[i * mip_levels + j].SysMemPitch = row_pitch; + sub_rsrcs[i * mip_levels + j].SysMemSlicePitch = slice_pitch; + + pixels_ptr += slice_pitch * size.depth; + d3dx_get_next_mip_level_size(&size); + } + } + + if (SUCCEEDED(hr)) + { + *pixel_data = sub_rsrc_data + pixels_offset; + *out_sub_rsrc_data = sub_rsrcs; + sub_rsrc_data = NULL; + } + + free(sub_rsrc_data); + return hr; +} + +HRESULT load_texture_data(const void *data, SIZE_T size, D3DX11_IMAGE_LOAD_INFO *load_info, + D3D11_SUBRESOURCE_DATA **resource_data) +{ + const struct pixel_format_desc *fmt_desc, *src_desc; + uint32_t i, j, loaded_mip_levels, max_mip_levels; + D3D11_SUBRESOURCE_DATA *sub_rsrcs = NULL; + D3DX11_IMAGE_INFO img_info; + struct d3dx_image image; + uint8_t *pixels_ptr; + HRESULT hr; + + if (!data || !size) + return E_FAIL; + + if (FAILED(hr = d3dx_handle_filter(&load_info->Filter))) + { + ERR("Invalid filter argument %#x.\n", load_info->Filter); + return hr; + } + + hr = d3dx_image_init(data, size, &image, 0, D3DX_IMAGE_SUPPORT_DXT10); + if (FAILED(hr)) + return E_FAIL; + + hr = d3dx11_image_info_from_d3dx_image(&img_info, &image); + if (FAILED(hr)) + { + WARN("Invalid or unsupported image file, hr %#lx.\n", hr); + hr = E_FAIL; + goto end; + } + + if ((!(img_info.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) || img_info.ArraySize != 6) + && img_info.ArraySize != 1) + { + FIXME("img_info.ArraySize = %u not supported.\n", img_info.ArraySize); + hr = E_NOTIMPL; + goto end; + } + + if (load_info->FirstMipLevel == D3DX11_DEFAULT || (load_info->FirstMipLevel >= img_info.MipLevels)) + load_info->FirstMipLevel = 0; + if (load_info->Format == D3DX11_DEFAULT || load_info->Format == DXGI_FORMAT_FROM_FILE) + load_info->Format = img_info.Format; + fmt_desc = get_d3dx_pixel_format_info(d3dx_pixel_format_id_from_dxgi_format(load_info->Format)); + if (fmt_desc->format == D3DX_PIXEL_FORMAT_COUNT) + { + FIXME("Unknown DXGI format supplied, %#x.\n", load_info->Format); + hr = E_NOTIMPL; + goto end; + } + + /* Potentially round up width/height to align with block size. */ + if (!load_info->Width || load_info->Width == D3DX11_FROM_FILE || load_info->Width == D3DX11_DEFAULT) + load_info->Width = (img_info.Width + fmt_desc->block_width - 1) & ~(fmt_desc->block_width - 1); + if (!load_info->Height || load_info->Height == D3DX11_FROM_FILE || load_info->Height == D3DX11_DEFAULT) + load_info->Height = (img_info.Height + fmt_desc->block_height - 1) & ~(fmt_desc->block_height - 1); + + if (!load_info->Depth || load_info->Depth == D3DX11_FROM_FILE || load_info->Depth == D3DX11_DEFAULT) + load_info->Depth = img_info.Depth; + if ((load_info->Depth > 1) && (img_info.ResourceDimension != D3D11_RESOURCE_DIMENSION_TEXTURE3D)) + { + hr = E_FAIL; + goto end; + } + + max_mip_levels = d3dx_get_max_mip_levels_for_size(load_info->Width, load_info->Height, load_info->Depth); + if (!load_info->MipLevels || load_info->MipLevels == D3DX11_DEFAULT || load_info->MipLevels == D3DX11_FROM_FILE) + load_info->MipLevels = (load_info->MipLevels == D3DX11_FROM_FILE) ? img_info.MipLevels : max_mip_levels; + load_info->MipLevels = min(max_mip_levels, load_info->MipLevels); + + hr = d3dx_create_subresource_data_for_texture(load_info->Width, load_info->Height, load_info->Depth, + load_info->MipLevels, img_info.ArraySize, fmt_desc, &sub_rsrcs, &pixels_ptr); + if (FAILED(hr)) + goto end; + + src_desc = get_d3dx_pixel_format_info(image.format); + loaded_mip_levels = min((img_info.MipLevels - load_info->FirstMipLevel), load_info->MipLevels); + for (i = 0; i < img_info.ArraySize; ++i) + { + struct volume dst_size = { load_info->Width, load_info->Height, load_info->Depth }; + + for (j = 0; j < loaded_mip_levels; ++j) + { + D3D11_SUBRESOURCE_DATA *sub_rsrc = &sub_rsrcs[i * load_info->MipLevels + j]; + const RECT unaligned_rect = { 0, 0, dst_size.width, dst_size.height }; + struct d3dx_pixels src_pixels, dst_pixels; + + hr = d3dx_image_get_pixels(&image, i, j + load_info->FirstMipLevel, &src_pixels); + if (FAILED(hr)) + goto end; + + set_d3dx_pixels(&dst_pixels, sub_rsrc->pSysMem, sub_rsrc->SysMemPitch, sub_rsrc->SysMemSlicePitch, NULL, + dst_size.width, dst_size.height, dst_size.depth, &unaligned_rect); + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, src_desc, load_info->Filter, 0); + if (FAILED(hr)) + goto end; + + d3dx_get_next_mip_level_size(&dst_size); + } + } + + if (loaded_mip_levels < load_info->MipLevels) + { + struct volume base_level_size = { load_info->Width, load_info->Height, load_info->Depth }; + + if (FAILED(hr = d3dx_handle_filter(&load_info->MipFilter))) + { + ERR("Invalid mip filter argument %#x.\n", load_info->MipFilter); + goto end; + } + + d3dx_get_mip_level_size(&base_level_size, loaded_mip_levels - 1); + for (i = 0; i < img_info.ArraySize; ++i) + { + struct volume src_size, dst_size; + + src_size = dst_size = base_level_size; + for (j = (loaded_mip_levels - 1); j < (load_info->MipLevels - 1); ++j) + { + D3D11_SUBRESOURCE_DATA *dst_data = &sub_rsrcs[i * load_info->MipLevels + j + 1]; + D3D11_SUBRESOURCE_DATA *src_data = &sub_rsrcs[i * load_info->MipLevels + j]; + const RECT src_unaligned_rect = { 0, 0, src_size.width, src_size.height }; + struct d3dx_pixels src_pixels, dst_pixels; + RECT dst_unaligned_rect; + + d3dx_get_next_mip_level_size(&dst_size); + SetRect(&dst_unaligned_rect, 0, 0, dst_size.width, dst_size.height); + set_d3dx_pixels(&dst_pixels, dst_data->pSysMem, dst_data->SysMemPitch, dst_data->SysMemSlicePitch, NULL, + dst_size.width, dst_size.height, dst_size.depth, &dst_unaligned_rect); + set_d3dx_pixels(&src_pixels, src_data->pSysMem, src_data->SysMemPitch, src_data->SysMemSlicePitch, NULL, + src_size.width, src_size.height, src_size.depth, &src_unaligned_rect); + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, fmt_desc, load_info->MipFilter, 0); + if (FAILED(hr)) + goto end; + + src_size = dst_size; + } + } + } + + if (load_info->pSrcInfo) + *load_info->pSrcInfo = img_info; + load_info->Usage = (load_info->Usage == D3DX11_DEFAULT) ? D3D11_USAGE_DEFAULT : load_info->Usage; + load_info->BindFlags = (load_info->BindFlags == D3DX11_DEFAULT) ? D3D11_BIND_SHADER_RESOURCE : load_info->BindFlags; + load_info->CpuAccessFlags = (load_info->CpuAccessFlags == D3DX11_DEFAULT) ? 0 : load_info->CpuAccessFlags; + load_info->MiscFlags = (load_info->MiscFlags == D3DX11_DEFAULT) ? 0 : load_info->MiscFlags; + load_info->MiscFlags |= img_info.MiscFlags; + *resource_data = sub_rsrcs; + sub_rsrcs = NULL; + +end: + d3dx_image_cleanup(&image); + free(sub_rsrcs); + return hr; +} + +HRESULT create_d3d_texture(ID3D11Device *device, D3DX11_IMAGE_LOAD_INFO *load_info, + D3D11_SUBRESOURCE_DATA *resource_data, ID3D11Resource **texture) +{ + HRESULT hr; + + *texture = NULL; + switch (load_info->pSrcInfo->ResourceDimension) + { + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: + { + D3D11_TEXTURE2D_DESC texture_2d_desc = { 0 }; + ID3D11Texture2D *texture_2d; + + texture_2d_desc.Width = load_info->Width; + texture_2d_desc.Height = load_info->Height; + texture_2d_desc.MipLevels = load_info->MipLevels; + texture_2d_desc.ArraySize = load_info->pSrcInfo->ArraySize; + texture_2d_desc.Format = load_info->Format; + texture_2d_desc.SampleDesc.Count = 1; + texture_2d_desc.Usage = load_info->Usage; + texture_2d_desc.BindFlags = load_info->BindFlags; + texture_2d_desc.CPUAccessFlags = load_info->CpuAccessFlags; + texture_2d_desc.MiscFlags = load_info->MiscFlags; + + if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_2d_desc, resource_data, &texture_2d))) + return hr; + *texture = (ID3D11Resource *)texture_2d; + break; + } + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: + { + D3D11_TEXTURE3D_DESC texture_3d_desc = { 0 }; + ID3D11Texture3D *texture_3d; + + texture_3d_desc.Width = load_info->Width; + texture_3d_desc.Height = load_info->Height; + texture_3d_desc.Depth = load_info->Depth; + texture_3d_desc.MipLevels = load_info->MipLevels; + texture_3d_desc.Format = load_info->Format; + texture_3d_desc.Usage = load_info->Usage; + texture_3d_desc.BindFlags = load_info->BindFlags; + texture_3d_desc.CPUAccessFlags = load_info->CpuAccessFlags; + texture_3d_desc.MiscFlags = load_info->MiscFlags; + + if (FAILED(hr = ID3D11Device_CreateTexture3D(device, &texture_3d_desc, resource_data, &texture_3d))) + return hr; + *texture = (ID3D11Resource *)texture_3d; + break; + } + + default: + FIXME("Unhandled resource dimension %d.\n", load_info->pSrcInfo->ResourceDimension); + return E_NOTIMPL; + } + + return S_OK; +} + +static HRESULT create_texture(ID3D11Device *device, const void *data, SIZE_T size, + D3DX11_IMAGE_LOAD_INFO *load_info, ID3D11Resource **texture) +{ + D3D11_SUBRESOURCE_DATA *resource_data; + D3DX11_IMAGE_LOAD_INFO load_info_copy; + D3DX11_IMAGE_INFO img_info; + HRESULT hr; + + init_load_info(load_info, &load_info_copy); + if (load_info_copy.pSrcInfo == NULL) + load_info_copy.pSrcInfo = &img_info; + + if (FAILED((hr = load_texture_data(data, size, &load_info_copy, &resource_data)))) + return hr; + hr = create_d3d_texture(device, &load_info_copy, resource_data, texture); + free(resource_data); + return hr; +} + +HRESULT WINAPI D3DX11CreateTextureFromMemory(ID3D11Device *device, const void *src_data, SIZE_T src_data_size, + D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, ID3D11Resource **texture, HRESULT *hresult) +{ + HRESULT hr; + + TRACE("device %p, src_data %p, src_data_size %Iu, load_info %p, pump %p, texture %p, hresult %p.\n", + device, src_data, src_data_size, load_info, pump, texture, hresult); + + if (!device) + return E_INVALIDARG; + if (!src_data) + return E_FAIL; + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; + + if (FAILED((hr = D3DX11CreateAsyncMemoryLoader(src_data, src_data_size, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncTextureProcessor(device, load_info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)texture)))) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } + + hr = create_texture(device, src_data, src_data_size, load_info, texture); + if (hresult) + *hresult = hr; + return hr; +} + +HRESULT WINAPI D3DX11CreateTextureFromFileA(ID3D11Device *device, const char *src_file, D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, ID3D11Resource **texture, HRESULT *hresult) { - FIXME("device %p, filename %s, load_info %p, pump %p, texture %p, hresult %p stub.\n", - device, debugstr_a(filename), load_info, pump, texture, hresult); + int32_t str_len; + WCHAR *buffer; + HRESULT hr; + + TRACE("device %p, src_file %s, load_info %p, pump %p, texture %p, hresult %p.\n", + device, debugstr_a(src_file), load_info, pump, texture, hresult); + + if (!device) + return E_INVALIDARG; + if (!src_file) + return E_FAIL; + + if (!(str_len = MultiByteToWideChar(CP_ACP, 0, src_file, -1, NULL, 0))) + return HRESULT_FROM_WIN32(GetLastError()); + + if (!(buffer = malloc(str_len * sizeof(*buffer)))) + return E_OUTOFMEMORY; - return E_NOTIMPL; + MultiByteToWideChar(CP_ACP, 0, src_file, -1, buffer, str_len); + hr = D3DX11CreateTextureFromFileW(device, buffer, load_info, pump, texture, hresult); + + free(buffer); + + return hr; } -HRESULT WINAPI D3DX11CreateTextureFromFileW(ID3D11Device *device, const WCHAR *filename, +HRESULT WINAPI D3DX11CreateTextureFromFileW(ID3D11Device *device, const WCHAR *src_file, D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, ID3D11Resource **texture, HRESULT *hresult) { - FIXME("device %p, filename %s, load_info %p, pump %p, texture %p, hresult %p stub.\n", - device, debugstr_w(filename), load_info, pump, texture, hresult); + void *buffer = NULL; + DWORD size = 0; + HRESULT hr; + + TRACE("device %p, src_file %s, load_info %p, pump %p, texture %p, hresult %p.\n", + device, debugstr_w(src_file), load_info, pump, texture, hresult); + + if (!device) + return E_INVALIDARG; + if (!src_file) + return E_FAIL; + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; - return E_NOTIMPL; + if (FAILED((hr = D3DX11CreateAsyncFileLoaderW(src_file, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncTextureProcessor(device, load_info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)texture)))) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } + + if (SUCCEEDED((hr = load_file(src_file, &buffer, &size)))) + { + hr = create_texture(device, buffer, size, load_info, texture); + free(buffer); + } + if (hresult) + *hresult = hr; + return hr; } -HRESULT WINAPI D3DX11CreateTextureFromMemory(ID3D11Device *device, const void *data, - SIZE_T data_size, D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, - ID3D11Resource **texture, HRESULT *hresult) +HRESULT WINAPI D3DX11CreateTextureFromResourceA(ID3D11Device *device, HMODULE module, const char *resource, + D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, ID3D11Resource **texture, HRESULT *hresult) { - FIXME("device %p, data %p, data_size %Iu, load_info %p, pump %p, texture %p, hresult %p stub.\n", - device, data, data_size, load_info, pump, texture, hresult); + void *buffer; + DWORD size; + HRESULT hr; + + TRACE("device %p, module %p, resource %s, load_info %p, pump %p, texture %p, hresult %p.\n", + device, module, debugstr_a(resource), load_info, pump, texture, hresult); + + if (!device) + return E_INVALIDARG; + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; + + if (FAILED((hr = D3DX11CreateAsyncResourceLoaderA(module, resource, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncTextureProcessor(device, load_info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)texture)))) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } - return E_NOTIMPL; + if (FAILED((hr = load_resourceA(module, resource, &buffer, &size)))) + return hr; + hr = create_texture(device, buffer, size, load_info, texture); + if (hresult) + *hresult = hr; + return hr; } -HRESULT WINAPI D3DX11SaveTextureToFileW(ID3D11DeviceContext *context, ID3D11Resource *texture, - D3DX11_IMAGE_FILE_FORMAT format, const WCHAR *filename) +HRESULT WINAPI D3DX11CreateTextureFromResourceW(ID3D11Device *device, HMODULE module, const WCHAR *resource, + D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, ID3D11Resource **texture, HRESULT *hresult) { - FIXME("context %p, texture %p, format %u, filename %s stub!\n", - context, texture, format, debugstr_w(filename)); + void *buffer; + DWORD size; + HRESULT hr; + + TRACE("device %p, module %p, resource %s, load_info %p, pump %p, texture %p, hresult %p.\n", + device, module, debugstr_w(resource), load_info, pump, texture, hresult); + + if (!device) + return E_INVALIDARG; + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; - return E_NOTIMPL; + if (FAILED((hr = D3DX11CreateAsyncResourceLoaderW(module, resource, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncTextureProcessor(device, load_info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)texture)))) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } + + if (FAILED((hr = load_resourceW(module, resource, &buffer, &size)))) + return hr; + hr = create_texture(device, buffer, size, load_info, texture); + if (hresult) + *hresult = hr; + return hr; } -HRESULT WINAPI D3DX11SaveTextureToFileA(ID3D11DeviceContext *context, ID3D11Resource *texture, - D3DX11_IMAGE_FILE_FORMAT format, const char *filename) +/* + * D3DX11CreateShaderResourceView variants. + */ +HRESULT WINAPI D3DX11CreateShaderResourceViewFromFileA(ID3D11Device *device, const char *src_file, + D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, ID3D11ShaderResourceView **srv, HRESULT *hresult) { - FIXME("context %p, texture %p, format %u, filename %s stub!\n", - context, texture, format, debugstr_a(filename)); + WCHAR *buffer; + int str_len; + HRESULT hr; - return E_NOTIMPL; + TRACE("device %p, src_file %s, load_info %p, pump %p, srv %p, hresult %p.\n", + device, debugstr_a(src_file), load_info, pump, srv, hresult); + + if (!device) + return E_INVALIDARG; + if (!src_file) + return E_FAIL; + + if (!(str_len = MultiByteToWideChar(CP_ACP, 0, src_file, -1, NULL, 0))) + return HRESULT_FROM_WIN32(GetLastError()); + + if (!(buffer = malloc(str_len * sizeof(*buffer)))) + return E_OUTOFMEMORY; + + MultiByteToWideChar(CP_ACP, 0, src_file, -1, buffer, str_len); + hr = D3DX11CreateShaderResourceViewFromFileW(device, buffer, load_info, pump, srv, hresult); + + free(buffer); + + return hr; } -HRESULT WINAPI D3DX11SaveTextureToMemory(ID3D11DeviceContext *context, ID3D11Resource *texture, - D3DX11_IMAGE_FILE_FORMAT format, ID3D10Blob **buffer, UINT flags) +HRESULT WINAPI D3DX11CreateShaderResourceViewFromFileW(ID3D11Device *device, const WCHAR *src_file, + D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, ID3D11ShaderResourceView **srv, HRESULT *hresult) +{ + ID3D11Resource *texture; + void *buffer = NULL; + DWORD size = 0; + HRESULT hr; + + TRACE("device %p, src_file %s, load_info %p, pump %p, srv %p, hresult %p.\n", + device, debugstr_w(src_file), load_info, pump, srv, hresult); + + if (!device) + return E_INVALIDARG; + if (!src_file) + return E_FAIL; + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; + + if (FAILED((hr = D3DX11CreateAsyncFileLoaderW(src_file, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncShaderResourceViewProcessor(device, load_info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)srv)))) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } + + if (SUCCEEDED((hr = load_file(src_file, &buffer, &size)))) + { + hr = create_texture(device, buffer, size, load_info, &texture); + if (SUCCEEDED(hr)) + { + hr = ID3D11Device_CreateShaderResourceView(device, texture, NULL, srv); + ID3D11Resource_Release(texture); + } + free(buffer); + } + if (hresult) + *hresult = hr; + return hr; +} + +HRESULT WINAPI D3DX11CreateShaderResourceViewFromResourceA(ID3D11Device *device, HMODULE module, const char *resource, + D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, ID3D11ShaderResourceView **srv, HRESULT *hresult) +{ + ID3D11Resource *texture; + void *buffer; + DWORD size; + HRESULT hr; + + TRACE("device %p, module %p, resource %s, load_info %p, pump %p, srv %p, hresult %p.\n", + device, module, debugstr_a(resource), load_info, pump, srv, hresult); + + if (!device) + return E_INVALIDARG; + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; + + if (FAILED((hr = D3DX11CreateAsyncResourceLoaderA(module, resource, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncShaderResourceViewProcessor(device, load_info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)srv)))) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } + + if (FAILED((hr = load_resourceA(module, resource, &buffer, &size)))) + return hr; + hr = create_texture(device, buffer, size, load_info, &texture); + if (SUCCEEDED(hr)) + { + hr = ID3D11Device_CreateShaderResourceView(device, texture, NULL, srv); + ID3D11Resource_Release(texture); + } + if (hresult) + *hresult = hr; + return hr; +} + +HRESULT WINAPI D3DX11CreateShaderResourceViewFromResourceW(ID3D11Device *device, HMODULE module, const WCHAR *resource, + D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, ID3D11ShaderResourceView **srv, HRESULT *hresult) +{ + ID3D11Resource *texture; + void *buffer; + DWORD size; + HRESULT hr; + + TRACE("device %p, module %p, resource %s, load_info %p, pump %p, srv %p, hresult %p.\n", + device, module, debugstr_w(resource), load_info, pump, srv, hresult); + + if (!device) + return E_INVALIDARG; + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; + + if (FAILED((hr = D3DX11CreateAsyncResourceLoaderW(module, resource, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncShaderResourceViewProcessor(device, load_info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)srv)))) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } + + if (FAILED((hr = load_resourceW(module, resource, &buffer, &size)))) + return hr; + hr = create_texture(device, buffer, size, load_info, &texture); + if (SUCCEEDED(hr)) + { + hr = ID3D11Device_CreateShaderResourceView(device, texture, NULL, srv); + ID3D11Resource_Release(texture); + } + if (hresult) + *hresult = hr; + return hr; +} + +HRESULT WINAPI D3DX11CreateShaderResourceViewFromMemory(ID3D11Device *device, const void *src_data, SIZE_T src_data_size, + D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, ID3D11ShaderResourceView **srv, HRESULT *hresult) +{ + ID3D11Resource *texture; + HRESULT hr; + + TRACE("device %p, src_data %p, src_data_size %Iu, load_info %p, pump %p, srv %p, hresult %p.\n", + device, src_data, src_data_size, load_info, pump, srv, hresult); + + if (!device) + return E_INVALIDARG; + if (!src_data) + return E_FAIL; + + if (pump) + { + ID3DX11DataProcessor *processor; + ID3DX11DataLoader *loader; + + if (FAILED((hr = D3DX11CreateAsyncMemoryLoader(src_data, src_data_size, &loader)))) + return hr; + if (FAILED((hr = D3DX11CreateAsyncShaderResourceViewProcessor(device, load_info, &processor)))) + { + ID3DX11DataLoader_Destroy(loader); + return hr; + } + if (FAILED((hr = ID3DX11ThreadPump_AddWorkItem(pump, loader, processor, hresult, (void **)srv)))) + { + ID3DX11DataLoader_Destroy(loader); + ID3DX11DataProcessor_Destroy(processor); + } + return hr; + } + + hr = create_texture(device, src_data, src_data_size, load_info, &texture); + if (SUCCEEDED(hr)) + { + hr = ID3D11Device_CreateShaderResourceView(device, texture, NULL, srv); + ID3D11Resource_Release(texture); + } + if (hresult) + *hresult = hr; + return hr; +} + +/* + * D3DX11LoadTextureFromTexture implementation. + */ +struct d3d11_texture_resource { + D3D11_RESOURCE_DIMENSION texture_dimension; + union + { + ID3D11Resource *tex_rsrc; + ID3D11Texture2D *tex_2d; + ID3D11Texture3D *tex_3d; + } iface; + struct volume size; + uint32_t mip_levels; + uint32_t layer_count; +}; + +struct d3d11_texture { + ID3D11Device *device; + ID3D11DeviceContext *device_context; + struct d3d11_texture_resource texture; + struct d3d11_texture_resource staging_texture; + + const struct pixel_format_desc *fmt_desc; + D3D11_MAP map_flags; + D3D11_BOX texture_box; + BOOL is_cubemap; + + uint32_t first_layer; + uint32_t first_mip_level; +}; + +static void set_d3d11_box(D3D11_BOX *box, uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t front, + uint32_t back) +{ + box->left = left; + box->top = top; + box->right = right; + box->bottom = bottom; + box->front = front; + box->back = back; +} + +static const char *debug_d3d11_box(const struct D3D11_BOX *box) +{ + if (!box) + return "(null)"; + return wine_dbg_sprintf("(%ux%ux%u)-(%ux%ux%u)", box->left, box->top, box->front, box->right, box->bottom, box->back); +} + +static void d3d11_box_get_mip_level(D3D11_BOX *box, uint32_t level) +{ + uint32_t i; + + for (i = 0; i < level; ++i) + { + set_d3d11_box(box, (box->left ? (box->left / 2) : 0), (box->top ? (box->top / 2) : 0), + max(box->right / 2, 1), max(box->bottom / 2, 1), + (box->front ? (box->front / 2) : 0), max(box->back / 2, 1)); + } +} + +static HRESULT d3dx_d3d11_texture_init(ID3D11DeviceContext *context, ID3D11Resource *tex_rsrc, uint32_t first_layer, + uint32_t first_mip_level, D3D11_MAP map_flags, D3D11_BOX *tex_box, struct d3d11_texture *texture) +{ + struct d3d11_texture_resource *staging_tex_rsrc = &texture->staging_texture; + struct d3d11_texture_resource *src_tex_rsrc = &texture->texture; + HRESULT hr; + + ID3D11Resource_GetDevice(tex_rsrc, &texture->device); + if (!texture->device) + { + ERR("Failed to get device from texture resource.\n"); + return E_FAIL; + } + + texture->map_flags = map_flags; + ID3D11Resource_GetType(tex_rsrc, &src_tex_rsrc->texture_dimension); + switch (src_tex_rsrc->texture_dimension) + { + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: + { + D3D11_TEXTURE2D_DESC desc; + + hr = ID3D11Resource_QueryInterface(tex_rsrc, &IID_ID3D11Texture2D, (void **)&src_tex_rsrc->iface.tex_2d); + if (FAILED(hr)) + return hr; + + ID3D11Texture2D_GetDesc(src_tex_rsrc->iface.tex_2d, &desc); + if (map_flags != D3D11_MAP_READ && (first_mip_level >= desc.MipLevels)) + return S_FALSE; + + texture->fmt_desc = get_d3dx_pixel_format_info(d3dx_pixel_format_id_from_dxgi_format(desc.Format)); + if (texture->fmt_desc->format == D3DX_PIXEL_FORMAT_COUNT) + { + FIXME("Unknown DXGI format supplied, %#x.\n", desc.Format); + return E_NOTIMPL; + } + + set_volume_struct(&src_tex_rsrc->size, desc.Width, desc.Height, 1); + src_tex_rsrc->mip_levels = desc.MipLevels; + src_tex_rsrc->layer_count = desc.ArraySize; + + texture->first_mip_level = min((desc.MipLevels - 1), first_mip_level); + texture->first_layer = first_layer >= desc.ArraySize ? 0 : first_layer; + texture->is_cubemap = !!(desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE); + + staging_tex_rsrc->texture_dimension = src_tex_rsrc->texture_dimension; + staging_tex_rsrc->size = src_tex_rsrc->size; + d3dx_get_mip_level_size(&staging_tex_rsrc->size, texture->first_mip_level); + staging_tex_rsrc->mip_levels = src_tex_rsrc->mip_levels - texture->first_mip_level; + staging_tex_rsrc->layer_count = 1; + + /* Create the staging texture. */ + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = desc.MiscFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + if (map_flags != D3D11_MAP_READ) + desc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE; + desc.ArraySize = 1; + desc.MipLevels = staging_tex_rsrc->mip_levels; + desc.Width = staging_tex_rsrc->size.width; + desc.Height = staging_tex_rsrc->size.height; + + hr = ID3D11Device_CreateTexture2D(texture->device, &desc, NULL, &staging_tex_rsrc->iface.tex_2d); + if (FAILED(hr)) + return hr; + break; + } + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: + { + D3D11_TEXTURE3D_DESC desc; + + hr = ID3D11Resource_QueryInterface(tex_rsrc, &IID_ID3D11Texture3D, (void **)&src_tex_rsrc->iface.tex_3d); + if (FAILED(hr)) + return hr; + + ID3D11Texture3D_GetDesc(src_tex_rsrc->iface.tex_3d, &desc); + if (map_flags != D3D11_MAP_READ && (first_mip_level >= desc.MipLevels)) + return S_FALSE; + + texture->fmt_desc = get_d3dx_pixel_format_info(d3dx_pixel_format_id_from_dxgi_format(desc.Format)); + if (texture->fmt_desc->format == D3DX_PIXEL_FORMAT_COUNT) + { + FIXME("Unknown DXGI format supplied, %#x.\n", desc.Format); + return E_NOTIMPL; + } + + set_volume_struct(&src_tex_rsrc->size, desc.Width, desc.Height, desc.Depth); + src_tex_rsrc->mip_levels = desc.MipLevels; + src_tex_rsrc->layer_count = 1; + + texture->first_mip_level = min((desc.MipLevels - 1), first_mip_level); + if (first_layer) + WARN("Specified a non zero FirstElement argument on a 3D texture.\n"); + texture->first_layer = 0; + + staging_tex_rsrc->texture_dimension = src_tex_rsrc->texture_dimension; + staging_tex_rsrc->size = src_tex_rsrc->size; + d3dx_get_mip_level_size(&staging_tex_rsrc->size, texture->first_mip_level); + staging_tex_rsrc->mip_levels = src_tex_rsrc->mip_levels - texture->first_mip_level; + staging_tex_rsrc->layer_count = 1; + + /* Create the staging texture. */ + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = desc.MiscFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + if (map_flags != D3D11_MAP_READ) + desc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE; + desc.MipLevels = staging_tex_rsrc->mip_levels; + desc.Width = staging_tex_rsrc->size.width; + desc.Height = staging_tex_rsrc->size.height; + desc.Depth = staging_tex_rsrc->size.depth; + + hr = ID3D11Device_CreateTexture3D(texture->device, &desc, NULL, &staging_tex_rsrc->iface.tex_3d); + if (FAILED(hr)) + return hr; + break; + } + + default: + FIXME("Unhandled resource dimension %u.\n", src_tex_rsrc->texture_dimension); + return E_NOTIMPL; + } + + if (tex_box) + texture->texture_box = *tex_box; + else + set_d3d11_box(&texture->texture_box, 0, 0, staging_tex_rsrc->size.width, staging_tex_rsrc->size.height, 0, + staging_tex_rsrc->size.depth); + texture->device_context = context; + ID3D11DeviceContext_AddRef(context); + + return S_OK; +} + +static void d3dx_d3d11_texture_release(struct d3d11_texture *texture) +{ + if (texture->device) + ID3D11Device_Release(texture->device); + if (texture->device_context) + ID3D11DeviceContext_Release(texture->device_context); + if (texture->texture.iface.tex_rsrc) + ID3D11Resource_Release(texture->texture.iface.tex_rsrc); + if (texture->staging_texture.iface.tex_rsrc) + ID3D11Resource_Release(texture->staging_texture.iface.tex_rsrc); +} + +static HRESULT d3dx_d3d11_texture_map(struct d3d11_texture *texture, uint32_t layer, uint32_t mip_level, + struct d3dx_pixels *pixels) { - FIXME("context %p, texture %p, format %u, buffer %p, flags %#x stub!\n", - context, texture, format, buffer, flags); + struct d3d11_texture_resource *staging_tex_rsrc = &texture->staging_texture; + struct d3d11_texture_resource *src_tex_rsrc = &texture->texture; + D3D11_BOX tmp_box = texture->texture_box; + D3D11_MAPPED_SUBRESOURCE map = { 0 }; + uint32_t sub_rsrc_idx; + HRESULT hr; + + d3d11_box_get_mip_level(&tmp_box, mip_level); + sub_rsrc_idx = (src_tex_rsrc->mip_levels * (texture->first_layer + layer)) + (mip_level + texture->first_mip_level); + ID3D11DeviceContext_CopySubresourceRegion(texture->device_context, staging_tex_rsrc->iface.tex_rsrc, mip_level, 0, 0, 0, + src_tex_rsrc->iface.tex_rsrc, sub_rsrc_idx, NULL); + hr = ID3D11DeviceContext_Map(texture->device_context, staging_tex_rsrc->iface.tex_rsrc, mip_level, + texture->map_flags, 0, &map); + if (FAILED(hr)) + return hr; - return E_NOTIMPL; + TRACE("Mapping layer %u, mip level %u, box %s.\n", texture->first_layer + layer, texture->first_mip_level + mip_level, + debug_d3d11_box(&tmp_box)); + return d3dx_pixels_init(map.pData, map.RowPitch, map.DepthPitch, NULL, texture->fmt_desc->format, tmp_box.left, tmp_box.top, + tmp_box.right, tmp_box.bottom, tmp_box.front, tmp_box.back, pixels); } +static void d3dx_d3d11_texture_unmap(struct d3d11_texture *texture, uint32_t layer, uint32_t mip_level) +{ + struct d3d11_texture_resource *staging_tex_rsrc = &texture->staging_texture; + struct d3d11_texture_resource *src_tex_rsrc = &texture->texture; + uint32_t sub_rsrc_idx; + + ID3D11DeviceContext_Unmap(texture->device_context, staging_tex_rsrc->iface.tex_rsrc, mip_level); + if (texture->map_flags == D3D11_MAP_READ) + return; + + sub_rsrc_idx = (src_tex_rsrc->mip_levels * (texture->first_layer + layer)) + (mip_level + texture->first_mip_level); + ID3D11DeviceContext_CopySubresourceRegion(texture->device_context, src_tex_rsrc->iface.tex_rsrc, sub_rsrc_idx, 0, 0, 0, + staging_tex_rsrc->iface.tex_rsrc, mip_level, NULL); +} + +static const D3DX11_TEXTURE_LOAD_INFO default_load_info = { NULL, NULL, 0, 0, D3DX11_DEFAULT, 0, 0, D3DX11_DEFAULT, + D3DX11_DEFAULT, D3DX11_DEFAULT }; HRESULT WINAPI D3DX11LoadTextureFromTexture(ID3D11DeviceContext *context, ID3D11Resource *src_texture, - D3DX11_TEXTURE_LOAD_INFO *info, ID3D11Resource *dst_texture) + D3DX11_TEXTURE_LOAD_INFO *load_info, ID3D11Resource *dst_texture) +{ + D3DX11_TEXTURE_LOAD_INFO info = (load_info) ? *load_info : default_load_info; + struct d3d11_texture src_tex = { 0 }; + struct d3d11_texture dst_tex = { 0 }; + uint32_t i, j, loaded_mip_levels; + HRESULT hr; + + TRACE("context %p, src_texture %p, load_info %p, dst_texture %p.\n", context, src_texture, load_info, dst_texture); + + if (!src_texture || !dst_texture) + return E_INVALIDARG; + + if (!context) + return D3DERR_INVALIDCALL; + + if (!info.Filter || FAILED(hr = d3dx_handle_filter(&info.Filter))) + { + FIXME("Invalid filter argument.\n"); + return D3DERR_INVALIDCALL; + } + + hr = d3dx_d3d11_texture_init(context, src_texture, info.SrcFirstElement, info.SrcFirstMip, D3D11_MAP_READ, info.pSrcBox, &src_tex); + if (FAILED(hr)) + goto end; + + hr = d3dx_d3d11_texture_init(context, dst_texture, info.DstFirstElement, info.DstFirstMip, D3D11_MAP_READ_WRITE, info.pDstBox, &dst_tex); + if (hr == S_FALSE || FAILED(hr)) + goto end; + + if ((src_texture == dst_texture) && ((src_tex.first_layer == dst_tex.first_layer) && + (src_tex.first_mip_level == dst_tex.first_mip_level))) + { + hr = D3DERR_INVALIDCALL; + goto end; + } + + if (!info.NumMips || info.NumMips == D3DX11_DEFAULT) + info.NumMips = dst_tex.staging_texture.mip_levels; + info.NumMips = min(info.NumMips, dst_tex.staging_texture.mip_levels); + if (!info.NumElements || info.NumElements == D3DX11_DEFAULT) + info.NumElements = min(src_tex.texture.layer_count, dst_tex.texture.layer_count); + info.NumElements = min(info.NumElements, min(src_tex.texture.layer_count, dst_tex.texture.layer_count)); + loaded_mip_levels = min(info.NumMips, src_tex.staging_texture.mip_levels); + for (i = 0; i < info.NumElements; ++i) + { + for (j = 0; j < loaded_mip_levels; ++j) + { + struct d3dx_pixels src_pixels, dst_pixels; + + hr = d3dx_d3d11_texture_map(&src_tex, i, j, &src_pixels); + if (FAILED(hr)) + goto end; + + hr = d3dx_d3d11_texture_map(&dst_tex, i, j, &dst_pixels); + if (FAILED(hr)) + { + d3dx_d3d11_texture_unmap(&src_tex, i, j); + goto end; + } + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_tex.fmt_desc, &src_pixels, src_tex.fmt_desc, info.Filter, 0); + d3dx_d3d11_texture_unmap(&src_tex, i, j); + d3dx_d3d11_texture_unmap(&dst_tex, i, j); + if (FAILED(hr)) + { + WARN("Failed with hr %#lx.\n", hr); + goto end; + } + } + } + + if (loaded_mip_levels < info.NumMips) + { + if (!info.MipFilter || FAILED(hr = d3dx_handle_filter(&info.MipFilter))) + { + FIXME("Invalid mip filter argument.\n"); + hr = D3DERR_INVALIDCALL; + goto end; + } + + for (i = 0; i < info.NumElements; ++i) + { + for (j = loaded_mip_levels; j < info.NumMips; ++j) + { + struct d3dx_pixels src_pixels, dst_pixels; + + hr = d3dx_d3d11_texture_map(&dst_tex, i, j - 1, &src_pixels); + if (FAILED(hr)) + break; + + hr = d3dx_d3d11_texture_map(&dst_tex, i, j, &dst_pixels); + if (SUCCEEDED(hr)) + { + hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_tex.fmt_desc, &src_pixels, dst_tex.fmt_desc, info.MipFilter, 0); + d3dx_d3d11_texture_unmap(&dst_tex, i, j); + } + d3dx_d3d11_texture_unmap(&dst_tex, i, j - 1); + if (FAILED(hr)) + goto end; + } + } + } + +end: + d3dx_d3d11_texture_release(&src_tex); + d3dx_d3d11_texture_release(&dst_tex); + return SUCCEEDED(hr) ? S_OK : hr; +} + +static uint32_t d3d11_get_resource_mip_levels(ID3D11Resource *rsrc) { - FIXME("context %p, src_texture %p, info %p, dst_texture %p stub!\n", - context, src_texture, info, dst_texture); + D3D11_RESOURCE_DIMENSION rsrc_dim; + uint32_t mip_levels = 0; + HRESULT hr; + + ID3D11Resource_GetType(rsrc, &rsrc_dim); + switch (rsrc_dim) + { + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: + { + D3D11_TEXTURE2D_DESC desc; + ID3D11Texture2D *tex_2d; + + hr = ID3D11Resource_QueryInterface(rsrc, &IID_ID3D11Texture2D, (void **)&tex_2d); + if (FAILED(hr)) + break; + + ID3D11Texture2D_GetDesc(tex_2d, &desc); + ID3D11Texture2D_Release(tex_2d); + mip_levels = desc.MipLevels; + break; + } + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: + { + D3D11_TEXTURE3D_DESC desc; + ID3D11Texture3D *tex_3d; + + hr = ID3D11Resource_QueryInterface(rsrc, &IID_ID3D11Texture3D, (void **)&tex_3d); + if (FAILED(hr)) + break; + + ID3D11Texture3D_GetDesc(tex_3d, &desc); + ID3D11Texture3D_Release(tex_3d); + mip_levels = desc.MipLevels; + break; + } + + default: + break; + } + + return mip_levels; +} + +HRESULT WINAPI D3DX11FilterTexture(ID3D11DeviceContext *context, ID3D11Resource *texture, UINT src_level, UINT filter) +{ + D3DX11_TEXTURE_LOAD_INFO load_info = { NULL, NULL, src_level, src_level + 1, 0, 0, 0, 0, filter, filter }; + + TRACE("context %p, texture %p, src_level %u, filter %#x.\n", context, texture, src_level, filter); + + if (!context) + return D3DERR_INVALIDCALL; + + if (d3d11_get_resource_mip_levels(texture) <= src_level) + return S_OK; + + return D3DX11LoadTextureFromTexture(context, texture, &load_info, texture); +} + +static HRESULT d3dx11_get_save_format_for_file_format(D3DX11_IMAGE_FILE_FORMAT iff, enum d3dx_pixel_format_id src_fmt, + enum d3dx_pixel_format_id *save_fmt) +{ + *save_fmt = D3DX_PIXEL_FORMAT_COUNT; + switch (iff) + { + case D3DX11_IFF_JPG: + switch (src_fmt) + { + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM: + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM_SRGB: + case D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT: + case D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT: + *save_fmt = D3DX_PIXEL_FORMAT_B8G8R8_UNORM; + break; + + case D3DX_PIXEL_FORMAT_R16_UNORM: + *save_fmt = D3DX_PIXEL_FORMAT_L8_UNORM; + break; + + default: + return E_FAIL; + } + break; + + case D3DX11_IFF_PNG: + case D3DX11_IFF_TIFF: + switch (src_fmt) + { + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM: + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM_SRGB: + *save_fmt = D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; + break; + + case D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT: + case D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT: + *save_fmt = D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM; + break; + + case D3DX_PIXEL_FORMAT_R16_UNORM: + *save_fmt = D3DX_PIXEL_FORMAT_L16_UNORM; + break; + + default: + return E_FAIL; + } + break; + + case D3DX11_IFF_BMP: + switch (src_fmt) + { + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM: + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM_SRGB: + *save_fmt = D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM; + break; + + case D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT: + case D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT: + case D3DX_PIXEL_FORMAT_R16_UNORM: + FIXME("Encoding of BMP files to WICPixelFormat64bppRGBAFixedPoint unimplemented, using default instead.\n"); + *save_fmt = D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM; + break; + + default: + return E_FAIL; + } + break; + + case D3DX11_IFF_WMP: + FIXME("Saving to WMP is currently unimplemented.\n"); + return E_NOTIMPL; + + default: + assert(0); + break; + } + + return S_OK; +} + +HRESULT WINAPI D3DX11SaveTextureToMemory(ID3D11DeviceContext *context, ID3D11Resource *texture, + D3DX11_IMAGE_FILE_FORMAT format, ID3D10Blob **buffer, UINT flags) +{ + const struct pixel_format_desc *fmt_desc = NULL; + struct d3d11_texture src_tex = { 0 }; + enum d3dx_resource_type d3dx_rtype; + D3D11_RESOURCE_DIMENSION rsrc_dim; + struct d3dx_image image = { 0 }; + ID3D10Blob *out_buffer; + unsigned int i, j; + HRESULT hr; + + TRACE("texture %p, format %u, buffer %p, flags %#x.\n", texture, format, buffer, flags); + + if (!texture || !buffer || format == D3DX11_IFF_GIF) + return E_INVALIDARG; + + if (!context) + return D3DERR_INVALIDCALL; + + out_buffer = *buffer = NULL; + if (format == D3DX11_IFF_WMP) + { + FIXME("Saving to file format %u is currently unimplemented.\n", format); + return E_NOTIMPL; + } + + ID3D11Resource_GetType(texture, &rsrc_dim); + switch (rsrc_dim) + { + case D3D11_RESOURCE_DIMENSION_TEXTURE2D: + d3dx_rtype = D3DX_RESOURCE_TYPE_TEXTURE_2D; + break; + + case D3D11_RESOURCE_DIMENSION_TEXTURE3D: + d3dx_rtype = D3DX_RESOURCE_TYPE_TEXTURE_3D; + break; + + default: + FIXME("Currently only 2D and 3D texture saving is supported.\n"); + return E_NOTIMPL; + } + + if (format != D3DX11_IFF_DDS && rsrc_dim != D3D11_RESOURCE_DIMENSION_TEXTURE2D) + return E_INVALIDARG; + + hr = d3dx_d3d11_texture_init(context, texture, 0, 0, D3D11_MAP_READ, NULL, &src_tex); + if (FAILED(hr)) + return hr; + + if (format != D3DX11_IFF_DDS) + { + enum d3dx_pixel_format_id dst_format; + struct d3dx_pixels src_pixels; + + hr = d3dx11_get_save_format_for_file_format(format, src_tex.fmt_desc->format, &dst_format); + if (FAILED(hr)) + goto exit; + + hr = d3dx_d3d11_texture_map(&src_tex, 0, 0, &src_pixels); + if (FAILED(hr)) + goto exit; + + hr = d3dx_save_pixels_to_memory(&src_pixels, src_tex.fmt_desc, (enum d3dx_image_file_format)format, dst_format, + &out_buffer); + d3dx_d3d11_texture_unmap(&src_tex, 0, 0); + if (SUCCEEDED(hr)) + *buffer = out_buffer; + else + WARN("Failed with hr %#lx.\n", hr); + + goto exit; + } + + if (src_tex.is_cubemap) + d3dx_rtype = D3DX_RESOURCE_TYPE_CUBE_TEXTURE; + + hr = d3dx_create_dds_file_blob(src_tex.fmt_desc->format, NULL, d3dx_rtype, &src_tex.texture.size, + src_tex.texture.mip_levels, src_tex.texture.layer_count, TRUE, &out_buffer); + if (FAILED(hr)) + { + FIXME("Failed to create dds file with hr %#lx.\n", hr); + goto exit; + } + + hr = d3dx_image_init(ID3D10Blob_GetBufferPointer(out_buffer), ID3D10Blob_GetBufferSize(out_buffer), &image, 0, + D3DX_IMAGE_SUPPORT_DXT10); + if (FAILED(hr)) + goto exit; + + fmt_desc = get_d3dx_pixel_format_info(image.format); + for (i = 0; i < image.layer_count; ++i) + { + for (j = 0; j < image.mip_levels; ++j) + { + struct d3dx_pixels src_pixels, dst_pixels; + + hr = d3dx_image_get_pixels(&image, i, j, &dst_pixels); + if (FAILED(hr)) + goto exit; + + hr = d3dx_d3d11_texture_map(&src_tex, i, j, &src_pixels); + if (FAILED(hr)) + goto exit; + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, src_tex.fmt_desc, D3DX_FILTER_NONE, 0); + d3dx_d3d11_texture_unmap(&src_tex, i, j); + if (FAILED(hr)) + { + WARN("Failed with hr %#lx.\n", hr); + goto exit; + } + } + } + + if (SUCCEEDED(hr)) + *buffer = out_buffer; - return E_NOTIMPL; +exit: + if (out_buffer && *buffer != out_buffer) + ID3D10Blob_Release(out_buffer); + d3dx_d3d11_texture_release(&src_tex); + return SUCCEEDED(hr) ? S_OK : hr; } diff --git a/dlls/d3dx9_24/Makefile.in b/dlls/d3dx9_24/Makefile.in index d0fef3bebd08..e31a7b5d9062 100644 --- a/dlls/d3dx9_24/Makefile.in +++ b/dlls/d3dx9_24/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=24 +EXTRADEFS = -DD3DX_SDK_VERSION=24 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_24.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_24/d3dx9_24.spec b/dlls/d3dx9_24/d3dx9_24.spec index ead018c7ae07..1e622efcc66f 100644 --- a/dlls/d3dx9_24/d3dx9_24.spec +++ b/dlls/d3dx9_24/d3dx9_24.spec @@ -20,7 +20,7 @@ @ stdcall D3DXComputeBoundingSphere(ptr long long ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -274,9 +274,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_25/Makefile.in b/dlls/d3dx9_25/Makefile.in index 869c11629047..9f44734e01d4 100644 --- a/dlls/d3dx9_25/Makefile.in +++ b/dlls/d3dx9_25/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=25 +EXTRADEFS = -DD3DX_SDK_VERSION=25 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_25.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_25/d3dx9_25.spec b/dlls/d3dx9_25/d3dx9_25.spec index d1087a2d4cc5..5d26995fb8cb 100644 --- a/dlls/d3dx9_25/d3dx9_25.spec +++ b/dlls/d3dx9_25/d3dx9_25.spec @@ -20,7 +20,7 @@ @ stdcall D3DXComputeBoundingSphere(ptr long long ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -274,9 +274,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_26/Makefile.in b/dlls/d3dx9_26/Makefile.in index ae3f2e189537..f2c40f300c0f 100644 --- a/dlls/d3dx9_26/Makefile.in +++ b/dlls/d3dx9_26/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=26 +EXTRADEFS = -DD3DX_SDK_VERSION=26 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_26.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_26/d3dx9_26.spec b/dlls/d3dx9_26/d3dx9_26.spec index 0769e250958d..82611296e18e 100644 --- a/dlls/d3dx9_26/d3dx9_26.spec +++ b/dlls/d3dx9_26/d3dx9_26.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -278,9 +278,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_27/Makefile.in b/dlls/d3dx9_27/Makefile.in index 4f2993638f36..d81e5d72fd98 100644 --- a/dlls/d3dx9_27/Makefile.in +++ b/dlls/d3dx9_27/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=27 +EXTRADEFS = -DD3DX_SDK_VERSION=27 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_27.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_27/d3dx9_27.spec b/dlls/d3dx9_27/d3dx9_27.spec index 0769e250958d..82611296e18e 100644 --- a/dlls/d3dx9_27/d3dx9_27.spec +++ b/dlls/d3dx9_27/d3dx9_27.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -278,9 +278,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_28/Makefile.in b/dlls/d3dx9_28/Makefile.in index 3c7ddb93c2e1..76cba4e34991 100644 --- a/dlls/d3dx9_28/Makefile.in +++ b/dlls/d3dx9_28/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=28 +EXTRADEFS = -DD3DX_SDK_VERSION=28 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_28.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_28/d3dx9_28.spec b/dlls/d3dx9_28/d3dx9_28.spec index 19871f33abcb..6ccc6cffb8cb 100644 --- a/dlls/d3dx9_28/d3dx9_28.spec +++ b/dlls/d3dx9_28/d3dx9_28.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -283,9 +283,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_29/Makefile.in b/dlls/d3dx9_29/Makefile.in index 75eb3e732430..6640a0a362b0 100644 --- a/dlls/d3dx9_29/Makefile.in +++ b/dlls/d3dx9_29/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=29 +EXTRADEFS = -DD3DX_SDK_VERSION=29 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_29.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_29/d3dx9_29.spec b/dlls/d3dx9_29/d3dx9_29.spec index 19871f33abcb..6ccc6cffb8cb 100644 --- a/dlls/d3dx9_29/d3dx9_29.spec +++ b/dlls/d3dx9_29/d3dx9_29.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -283,9 +283,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_30/Makefile.in b/dlls/d3dx9_30/Makefile.in index 9b8eb133611e..b7f660826b94 100644 --- a/dlls/d3dx9_30/Makefile.in +++ b/dlls/d3dx9_30/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=30 +EXTRADEFS = -DD3DX_SDK_VERSION=30 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_30.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_30/d3dx9_30.spec b/dlls/d3dx9_30/d3dx9_30.spec index 19871f33abcb..6ccc6cffb8cb 100644 --- a/dlls/d3dx9_30/d3dx9_30.spec +++ b/dlls/d3dx9_30/d3dx9_30.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -283,9 +283,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_31/Makefile.in b/dlls/d3dx9_31/Makefile.in index 52d3a3d0986e..0330f434f210 100644 --- a/dlls/d3dx9_31/Makefile.in +++ b/dlls/d3dx9_31/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=31 +EXTRADEFS = -DD3DX_SDK_VERSION=31 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_31.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_31/d3dx9_31.spec b/dlls/d3dx9_31/d3dx9_31.spec index 38714f68127a..a33330edf605 100644 --- a/dlls/d3dx9_31/d3dx9_31.spec +++ b/dlls/d3dx9_31/d3dx9_31.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -280,9 +280,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_32/Makefile.in b/dlls/d3dx9_32/Makefile.in index 70a1696de97e..eac9ef320e62 100644 --- a/dlls/d3dx9_32/Makefile.in +++ b/dlls/d3dx9_32/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=32 +EXTRADEFS = -DD3DX_SDK_VERSION=32 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_32.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_32/d3dx9_32.spec b/dlls/d3dx9_32/d3dx9_32.spec index ed8efad9c6ce..d01b94a3bf7e 100644 --- a/dlls/d3dx9_32/d3dx9_32.spec +++ b/dlls/d3dx9_32/d3dx9_32.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -285,9 +285,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_33/Makefile.in b/dlls/d3dx9_33/Makefile.in index 2c01e9da3d96..192edee7153c 100644 --- a/dlls/d3dx9_33/Makefile.in +++ b/dlls/d3dx9_33/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=33 +EXTRADEFS = -DD3DX_SDK_VERSION=33 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_33.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_33/d3dx9_33.spec b/dlls/d3dx9_33/d3dx9_33.spec index ed8efad9c6ce..d01b94a3bf7e 100644 --- a/dlls/d3dx9_33/d3dx9_33.spec +++ b/dlls/d3dx9_33/d3dx9_33.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -285,9 +285,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_34/Makefile.in b/dlls/d3dx9_34/Makefile.in index 1e317f37226d..fa562330ddf2 100644 --- a/dlls/d3dx9_34/Makefile.in +++ b/dlls/d3dx9_34/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=34 +EXTRADEFS = -DD3DX_SDK_VERSION=34 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_34.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_34/d3dx9_34.spec b/dlls/d3dx9_34/d3dx9_34.spec index ed8efad9c6ce..d01b94a3bf7e 100644 --- a/dlls/d3dx9_34/d3dx9_34.spec +++ b/dlls/d3dx9_34/d3dx9_34.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -285,9 +285,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_35/Makefile.in b/dlls/d3dx9_35/Makefile.in index 859cef9b1ce1..84e025f662d8 100644 --- a/dlls/d3dx9_35/Makefile.in +++ b/dlls/d3dx9_35/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=35 +EXTRADEFS = -DD3DX_SDK_VERSION=35 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_35.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_35/d3dx9_35.spec b/dlls/d3dx9_35/d3dx9_35.spec index ed8efad9c6ce..d01b94a3bf7e 100644 --- a/dlls/d3dx9_35/d3dx9_35.spec +++ b/dlls/d3dx9_35/d3dx9_35.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -285,9 +285,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_36/Makefile.in b/dlls/d3dx9_36/Makefile.in index 5370b3e7e7ac..c9450144edf3 100644 --- a/dlls/d3dx9_36/Makefile.in +++ b/dlls/d3dx9_36/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=36 +EXTRADEFS = -DD3DX_SDK_VERSION=36 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_36.dll IMPORTLIB = d3dx9 IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_36/bcdec.h b/dlls/d3dx9_36/bcdec.h new file mode 100644 index 000000000000..55f996620545 --- /dev/null +++ b/dlls/d3dx9_36/bcdec.h @@ -0,0 +1,1328 @@ +/* bcdec.h - v0.96 + provides functions to decompress blocks of BC compressed images + written by Sergii "iOrange" Kudlai in 2022 + + This library does not allocate memory and is trying to use as less stack as possible + + The library was never optimized specifically for speed but for the overall size + it has zero external dependencies and is not using any runtime functions + + Supported BC formats: + BC1 (also known as DXT1) + it's "binary alpha" variant BC1A (DXT1A) + BC2 (also known as DXT3) + BC3 (also known as DXT5) + BC4 (also known as ATI1N) + BC5 (also known as ATI2N) + BC6H (HDR format) + BC7 + + BC1/BC2/BC3/BC7 are expected to decompress into 4*4 RGBA blocks 8bit per component (32bit pixel) + BC4/BC5 are expected to decompress into 4*4 R/RG blocks 8bit per component (8bit and 16bit pixel) + BC6H is expected to decompress into 4*4 RGB blocks of either 32bit float or 16bit "half" per + component (96bit or 48bit pixel) + + For more info, issues and suggestions please visit https://github.com/iOrange/bcdec + + CREDITS: + Aras Pranckevicius (@aras-p) - BC1/BC3 decoders optimizations (up to 3x the speed) + - BC6H/BC7 bits pulling routines optimizations + - optimized BC6H by moving unquantize out of the loop + - Split BC6H decompression function into 'half' and + 'float' variants + + bugfixes: + @linkmauve + + LICENSE: See end of file for license information. +*/ + +#ifndef BCDEC_HEADER_INCLUDED +#define BCDEC_HEADER_INCLUDED + +/* if BCDEC_STATIC causes problems, try defining BCDECDEF to 'inline' or 'static inline' */ +#ifndef BCDECDEF +#ifdef BCDEC_STATIC +#define BCDECDEF static +#else +#ifdef __cplusplus +#define BCDECDEF extern "C" +#else +#define BCDECDEF extern +#endif +#endif +#endif + +/* Used information sources: + https://docs.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-block-compression + https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc6h-format + https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc7-format + https://docs.microsoft.com/en-us/windows/win32/direct3d11/bc7-format-mode-reference + + ! WARNING ! Khronos's BPTC partitions tables contain mistakes, do not use them! + https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.html#BPTC + + ! Use tables from here instead ! + https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt + + Leaving it here as it's a nice read + https://fgiesen.wordpress.com/2021/10/04/gpu-bcn-decoding/ + + Fast half to float function from here + https://gist.github.com/rygorous/2144712 +*/ + +#define BCDEC_BC1_BLOCK_SIZE 8 +#define BCDEC_BC2_BLOCK_SIZE 16 +#define BCDEC_BC3_BLOCK_SIZE 16 +#define BCDEC_BC4_BLOCK_SIZE 8 +#define BCDEC_BC5_BLOCK_SIZE 16 +#define BCDEC_BC6H_BLOCK_SIZE 16 +#define BCDEC_BC7_BLOCK_SIZE 16 + +#define BCDEC_BC1_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC1_BLOCK_SIZE) +#define BCDEC_BC2_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC2_BLOCK_SIZE) +#define BCDEC_BC3_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC3_BLOCK_SIZE) +#define BCDEC_BC4_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC4_BLOCK_SIZE) +#define BCDEC_BC5_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC5_BLOCK_SIZE) +#define BCDEC_BC6H_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC6H_BLOCK_SIZE) +#define BCDEC_BC7_COMPRESSED_SIZE(w, h) ((((w)>>2)*((h)>>2))*BCDEC_BC7_BLOCK_SIZE) + +BCDECDEF void bcdec_bc1(const void* compressedBlock, void* decompressedBlock, int destinationPitch); +BCDECDEF void bcdec_bc2(const void* compressedBlock, void* decompressedBlock, int destinationPitch); +BCDECDEF void bcdec_bc3(const void* compressedBlock, void* decompressedBlock, int destinationPitch); +BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch); +BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch); +BCDECDEF void bcdec_bc6h_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned); +BCDECDEF void bcdec_bc6h_half(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned); +BCDECDEF void bcdec_bc7(const void* compressedBlock, void* decompressedBlock, int destinationPitch); + +#endif /* BCDEC_HEADER_INCLUDED */ + +#ifdef BCDEC_IMPLEMENTATION + +static void bcdec__color_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int onlyOpaqueMode) { + unsigned short c0, c1; + unsigned int refColors[4]; /* 0xAABBGGRR */ + unsigned char* dstColors; + unsigned int colorIndices; + int i, j, idx; + unsigned int r0, g0, b0, r1, g1, b1, r, g, b; + + c0 = ((unsigned short*)compressedBlock)[0]; + c1 = ((unsigned short*)compressedBlock)[1]; + + /* Expand 565 ref colors to 888 */ + r0 = (((c0 >> 11) & 0x1F) * 527 + 23) >> 6; + g0 = (((c0 >> 5) & 0x3F) * 259 + 33) >> 6; + b0 = ((c0 & 0x1F) * 527 + 23) >> 6; + refColors[0] = 0xFF000000 | (b0 << 16) | (g0 << 8) | r0; + + r1 = (((c1 >> 11) & 0x1F) * 527 + 23) >> 6; + g1 = (((c1 >> 5) & 0x3F) * 259 + 33) >> 6; + b1 = ((c1 & 0x1F) * 527 + 23) >> 6; + refColors[1] = 0xFF000000 | (b1 << 16) | (g1 << 8) | r1; + + if (c0 > c1 || onlyOpaqueMode) { /* Standard BC1 mode (also BC3 color block uses ONLY this mode) */ + /* color_2 = 2/3*color_0 + 1/3*color_1 + color_3 = 1/3*color_0 + 2/3*color_1 */ + r = (2 * r0 + r1 + 1) / 3; + g = (2 * g0 + g1 + 1) / 3; + b = (2 * b0 + b1 + 1) / 3; + refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r; + + r = (r0 + 2 * r1 + 1) / 3; + g = (g0 + 2 * g1 + 1) / 3; + b = (b0 + 2 * b1 + 1) / 3; + refColors[3] = 0xFF000000 | (b << 16) | (g << 8) | r; + } else { /* Quite rare BC1A mode */ + /* color_2 = 1/2*color_0 + 1/2*color_1; + color_3 = 0; */ + r = (r0 + r1 + 1) >> 1; + g = (g0 + g1 + 1) >> 1; + b = (b0 + b1 + 1) >> 1; + refColors[2] = 0xFF000000 | (b << 16) | (g << 8) | r; + + refColors[3] = 0x00000000; + } + + colorIndices = ((unsigned int*)compressedBlock)[1]; + + /* Fill out the decompressed color block */ + dstColors = (unsigned char*)decompressedBlock; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + idx = colorIndices & 0x03; + ((unsigned int*)dstColors)[j] = refColors[idx]; + colorIndices >>= 2; + } + + dstColors += destinationPitch; + } +} + +static void bcdec__sharp_alpha_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + unsigned short* alpha; + unsigned char* decompressed; + int i, j; + + alpha = (unsigned short*)compressedBlock; + decompressed = (unsigned char*)decompressedBlock; + + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + decompressed[j * 4] = ((alpha[i] >> (4 * j)) & 0x0F) * 17; + } + + decompressed += destinationPitch; + } +} + +static void bcdec__smooth_alpha_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int pixelSize) { + unsigned char* decompressed; + unsigned char alpha[8]; + int i, j; + unsigned long long block, indices; + + block = *(unsigned long long*)compressedBlock; + decompressed = (unsigned char*)decompressedBlock; + + alpha[0] = block & 0xFF; + alpha[1] = (block >> 8) & 0xFF; + + if (alpha[0] > alpha[1]) { + /* 6 interpolated alpha values. */ + alpha[2] = (6 * alpha[0] + alpha[1] + 1) / 7; /* 6/7*alpha_0 + 1/7*alpha_1 */ + alpha[3] = (5 * alpha[0] + 2 * alpha[1] + 1) / 7; /* 5/7*alpha_0 + 2/7*alpha_1 */ + alpha[4] = (4 * alpha[0] + 3 * alpha[1] + 1) / 7; /* 4/7*alpha_0 + 3/7*alpha_1 */ + alpha[5] = (3 * alpha[0] + 4 * alpha[1] + 1) / 7; /* 3/7*alpha_0 + 4/7*alpha_1 */ + alpha[6] = (2 * alpha[0] + 5 * alpha[1] + 1) / 7; /* 2/7*alpha_0 + 5/7*alpha_1 */ + alpha[7] = ( alpha[0] + 6 * alpha[1] + 1) / 7; /* 1/7*alpha_0 + 6/7*alpha_1 */ + } + else { + /* 4 interpolated alpha values. */ + alpha[2] = (4 * alpha[0] + alpha[1] + 1) / 5; /* 4/5*alpha_0 + 1/5*alpha_1 */ + alpha[3] = (3 * alpha[0] + 2 * alpha[1] + 1) / 5; /* 3/5*alpha_0 + 2/5*alpha_1 */ + alpha[4] = (2 * alpha[0] + 3 * alpha[1] + 1) / 5; /* 2/5*alpha_0 + 3/5*alpha_1 */ + alpha[5] = ( alpha[0] + 4 * alpha[1] + 1) / 5; /* 1/5*alpha_0 + 4/5*alpha_1 */ + alpha[6] = 0x00; + alpha[7] = 0xFF; + } + + indices = block >> 16; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + decompressed[j * pixelSize] = alpha[indices & 0x07]; + indices >>= 3; + } + + decompressed += destinationPitch; + } +} + +typedef struct bcdec__bitstream { + unsigned long long low; + unsigned long long high; +} bcdec__bitstream_t; + +static int bcdec__bitstream_read_bits(bcdec__bitstream_t* bstream, int numBits) { + unsigned int mask = (1 << numBits) - 1; + /* Read the low N bits */ + unsigned int bits = (bstream->low & mask); + + bstream->low >>= numBits; + /* Put the low N bits of "high" into the high 64-N bits of "low". */ + bstream->low |= (bstream->high & mask) << (sizeof(bstream->high) * 8 - numBits); + bstream->high >>= numBits; + + return bits; +} + +static int bcdec__bitstream_read_bit(bcdec__bitstream_t* bstream) { + return bcdec__bitstream_read_bits(bstream, 1); +} + +/* reversed bits pulling, used in BC6H decoding + why ?? just why ??? */ +static int bcdec__bitstream_read_bits_r(bcdec__bitstream_t* bstream, int numBits) { + int bits = bcdec__bitstream_read_bits(bstream, numBits); + /* Reverse the bits. */ + int result = 0; + while (numBits--) { + result <<= 1; + result |= (bits & 1); + bits >>= 1; + } + return result; +} + + + +BCDECDEF void bcdec_bc1(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + bcdec__color_block(compressedBlock, decompressedBlock, destinationPitch, 0); +} + +BCDECDEF void bcdec_bc2(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + bcdec__color_block(((char*)compressedBlock) + 8, decompressedBlock, destinationPitch, 1); + bcdec__sharp_alpha_block(compressedBlock, ((char*)decompressedBlock) + 3, destinationPitch); +} + +BCDECDEF void bcdec_bc3(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + bcdec__color_block(((char*)compressedBlock) + 8, decompressedBlock, destinationPitch, 1); + bcdec__smooth_alpha_block(compressedBlock, ((char*)decompressedBlock) + 3, destinationPitch, 4); +} + +BCDECDEF void bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + bcdec__smooth_alpha_block(compressedBlock, decompressedBlock, destinationPitch, 1); +} + +BCDECDEF void bcdec_bc5(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + bcdec__smooth_alpha_block(compressedBlock, decompressedBlock, destinationPitch, 2); + bcdec__smooth_alpha_block(((char*)compressedBlock) + 8, ((char*)decompressedBlock) + 1, destinationPitch, 2); +} + +/* http://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend */ +static int bcdec__extend_sign(int val, int bits) { + return (val << (32 - bits)) >> (32 - bits); +} + +static int bcdec__transform_inverse(int val, int a0, int bits, int isSigned) { + /* If the precision of A0 is "p" bits, then the transform algorithm is: + B0 = (B0 + A0) & ((1 << p) - 1) */ + val = (val + a0) & ((1 << bits) - 1); + if (isSigned) { + val = bcdec__extend_sign(val, bits); + } + return val; +} + +/* pretty much copy-paste from documentation */ +static int bcdec__unquantize(int val, int bits, int isSigned) { + int unq, s = 0; + + if (!isSigned) { + if (bits >= 15) { + unq = val; + } else if (!val) { + unq = 0; + } else if (val == ((1 << bits) - 1)) { + unq = 0xFFFF; + } else { + unq = ((val << 16) + 0x8000) >> bits; + } + } else { + if (bits >= 16) { + unq = val; + } else { + if (val < 0) { + s = 1; + val = -val; + } + + if (val == 0) { + unq = 0; + } else if (val >= ((1 << (bits - 1)) - 1)) { + unq = 0x7FFF; + } else { + unq = ((val << 15) + 0x4000) >> (bits - 1); + } + + if (s) { + unq = -unq; + } + } + } + return unq; +} + +static int bcdec__interpolate(int a, int b, int* weights, int index) { + return (a * (64 - weights[index]) + b * weights[index] + 32) >> 6; +} + +static unsigned short bcdec__finish_unquantize(int val, int isSigned) { + int s; + + if (!isSigned) { + return (unsigned short)((val * 31) >> 6); /* scale the magnitude by 31 / 64 */ + } else { + val = (val < 0) ? -(((-val) * 31) >> 5) : (val * 31) >> 5; /* scale the magnitude by 31 / 32 */ + s = 0; + if (val < 0) { + s = 0x8000; + val = -val; + } + return (unsigned short)(s | val); + } +} + +/* modified half_to_float_fast4 from https://gist.github.com/rygorous/2144712 */ +static float bcdec__half_to_float_quick(unsigned short half) { + typedef union { + unsigned int u; + float f; + } FP32; + + static const FP32 magic = { 113 << 23 }; + static const unsigned int shifted_exp = 0x7c00 << 13; /* exponent mask after shift */ + FP32 o; + unsigned int exp; + + o.u = (half & 0x7fff) << 13; /* exponent/mantissa bits */ + exp = shifted_exp & o.u; /* just the exponent */ + o.u += (127 - 15) << 23; /* exponent adjust */ + + /* handle exponent special cases */ + if (exp == shifted_exp) { /* Inf/NaN? */ + o.u += (128 - 16) << 23; /* extra exp adjust */ + } else if (exp == 0) { /* Zero/Denormal? */ + o.u += 1 << 23; /* extra exp adjust */ + o.f -= magic.f; /* renormalize */ + } + + o.u |= (half & 0x8000) << 16; /* sign bit */ + return o.f; +} + +BCDECDEF void bcdec_bc6h_half(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) { + static char actual_bits_count[4][14] = { + { 10, 7, 11, 11, 11, 9, 8, 8, 8, 6, 10, 11, 12, 16 }, /* W */ + { 5, 6, 5, 4, 4, 5, 6, 5, 5, 6, 10, 9, 8, 4 }, /* dR */ + { 5, 6, 4, 5, 4, 5, 5, 6, 5, 6, 10, 9, 8, 4 }, /* dG */ + { 5, 6, 4, 4, 5, 5, 5, 5, 6, 6, 10, 9, 8, 4 } /* dB */ + }; + + /* There are 32 possible partition sets for a two-region tile. + Each 4x4 block represents a single shape. + Here also every fix-up index has MSB bit set. */ + static unsigned char partition_sets[32][4][4] = { + { {128, 0, 1, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 0, 1, 129} }, /* 0 */ + { {128, 0, 0, 1}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 0, 129} }, /* 1 */ + { {128, 1, 1, 1}, {0, 1, 1, 1}, { 0, 1, 1, 1}, {0, 1, 1, 129} }, /* 2 */ + { {128, 0, 0, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 1, 1, 129} }, /* 3 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 1, 129} }, /* 4 */ + { {128, 0, 1, 1}, {0, 1, 1, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 5 */ + { {128, 0, 0, 1}, {0, 0, 1, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 6 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 0, 1, 1}, {0, 1, 1, 129} }, /* 7 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 1}, {0, 0, 1, 129} }, /* 8 */ + { {128, 0, 1, 1}, {0, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 9 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 10 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 1}, {0, 1, 1, 129} }, /* 11 */ + { {128, 0, 0, 1}, {0, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 12 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 13 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 14 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 0}, {1, 1, 1, 129} }, /* 15 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, { 1, 1, 1, 0}, {1, 1, 1, 129} }, /* 16 */ + { {128, 1, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 0}, {0, 0, 0, 0} }, /* 17 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 1, 0} }, /* 18 */ + { {128, 1, 129, 1}, {0, 0, 1, 1}, { 0, 0, 0, 1}, {0, 0, 0, 0} }, /* 19 */ + { {128, 0, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 0}, {0, 0, 0, 0} }, /* 20 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, {129, 1, 0, 0}, {1, 1, 1, 0} }, /* 21 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 0, 0} }, /* 22 */ + { {128, 1, 1, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 0, 0, 129} }, /* 23 */ + { {128, 0, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 0, 0} }, /* 24 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 0, 0} }, /* 25 */ + { {128, 1, 129, 0}, {0, 1, 1, 0}, { 0, 1, 1, 0}, {0, 1, 1, 0} }, /* 26 */ + { {128, 0, 129, 1}, {0, 1, 1, 0}, { 0, 1, 1, 0}, {1, 1, 0, 0} }, /* 27 */ + { {128, 0, 0, 1}, {0, 1, 1, 1}, {129, 1, 1, 0}, {1, 0, 0, 0} }, /* 28 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, {129, 1, 1, 1}, {0, 0, 0, 0} }, /* 29 */ + { {128, 1, 129, 1}, {0, 0, 0, 1}, { 1, 0, 0, 0}, {1, 1, 1, 0} }, /* 30 */ + { {128, 0, 129, 1}, {1, 0, 0, 1}, { 1, 0, 0, 1}, {1, 1, 0, 0} } /* 31 */ + }; + + static int aWeight3[8] = { 0, 9, 18, 27, 37, 46, 55, 64 }; + static int aWeight4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 }; + + bcdec__bitstream_t bstream; + int mode, partition, numPartitions, i, j, partitionSet, indexBits, index, ep_i, actualBits0Mode; + int r[4], g[4], b[4]; /* wxyz */ + unsigned short* decompressed; + int* weights; + + decompressed = (unsigned short*)decompressedBlock; + + bstream.low = ((unsigned long long*)compressedBlock)[0]; + bstream.high = ((unsigned long long*)compressedBlock)[1]; + + r[0] = r[1] = r[2] = r[3] = 0; + g[0] = g[1] = g[2] = g[3] = 0; + b[0] = b[1] = b[2] = b[3] = 0; + + mode = bcdec__bitstream_read_bits(&bstream, 2); + if (mode > 1) { + mode |= (bcdec__bitstream_read_bits(&bstream, 3) << 2); + } + + /* modes >= 11 (10 in my code) are using 0 one, others will read it from the bitstream */ + partition = 0; + + switch (mode) { + /* mode 1 */ + case 0b00: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 75 bits (10.555, 10.555, 10.555) */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* rx[4:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* gx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 5); /* ry[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 5); /* rz[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 0; + } break; + + /* mode 2 */ + case 0b01: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 75 bits (7666, 7666, 7666) */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gy[5] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gz[5] */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 7); /* rw[6:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 7); /* gw[6:0] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* by[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 7); /* bw[6:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* bz[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* rx[5:0] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* gx[5:0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* bx[5:0] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 6); /* ry[5:0] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 6); /* rz[5:0] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 1; + } break; + + /* mode 3 */ + case 0b00010: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (11.555, 11.444, 11.444) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* rx[4:0] */ + r[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* rw[10] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* gx[3:0] */ + g[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* gw[10] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* bx[3:0] */ + b[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* bw[10] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 5); /* ry[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 5); /* rz[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 2; + } break; + + /* mode 4 */ + case 0b00110: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (11.444, 11.555, 11.444) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* rx[3:0] */ + r[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* rw[10] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* gx[4:0] */ + g[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* gw[10] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* bx[3:0] */ + b[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* bw[10] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* ry[3:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* rz[3:0] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 3; + } break; + + /* mode 5 */ + case 0b01010: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (11.444, 11.444, 11.555) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* rx[3:0] */ + r[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* rw[10] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* gx[3:0] */ + g[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* gw[10] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bx[4:0] */ + b[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* bw[10] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* ry[3:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* rz[3:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 4; + } break; + + /* mode 6 */ + case 0b01110: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (9555, 9555, 9555) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 9); /* rw[8:0] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 9); /* gw[8:0] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 9); /* bw[8:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* rx[4:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* gx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gx[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 5); /* ry[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 5); /* rz[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 5; + } break; + + /* mode 7 */ + case 0b10010: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (8666, 8555, 8555) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* rw[7:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* gw[7:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* bw[7:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* rx[5:0] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* gx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 6); /* ry[5:0] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 6); /* rz[5:0] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 6; + } break; + + /* mode 8 */ + case 0b10110: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (8555, 8666, 8555) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* rw[7:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* gw[7:0] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gy[5] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* bw[7:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gz[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* rx[4:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* gx[5:0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* zx[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 5); /* ry[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 5); /* rz[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 7; + } break; + + /* mode 9 */ + case 0b11010: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (8555, 8555, 8666) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* rw[7:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* gw[7:0] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* by[5] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 8); /* bw[7:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* bz[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* bw[4:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 5); /* gx[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* bx[5:0] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 5); /* ry[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 5); /* rz[4:0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 8; + } break; + + /* mode 10 */ + case 0b11110: { + /* Partitition indices: 46 bits + Partition: 5 bits + Color Endpoints: 72 bits (6666, 6666, 6666) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 6); /* rw[5:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gz[4] */ + b[3] |= bcdec__bitstream_read_bit(&bstream); /* bz[0] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 1; /* bz[1] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* by[4] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 6); /* gw[5:0] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gy[5] */ + b[2] |= bcdec__bitstream_read_bit(&bstream) << 5; /* by[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 2; /* bz[2] */ + g[2] |= bcdec__bitstream_read_bit(&bstream) << 4; /* gy[4] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 6); /* bw[5:0] */ + g[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* gz[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 3; /* bz[3] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 5; /* bz[5] */ + b[3] |= bcdec__bitstream_read_bit(&bstream) << 4; /* bz[4] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* rx[5:0] */ + g[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* gy[3:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* gx[5:0] */ + g[3] |= bcdec__bitstream_read_bits(&bstream, 4); /* gz[3:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 6); /* bx[5:0] */ + b[2] |= bcdec__bitstream_read_bits(&bstream, 4); /* by[3:0] */ + r[2] |= bcdec__bitstream_read_bits(&bstream, 6); /* ry[5:0] */ + r[3] |= bcdec__bitstream_read_bits(&bstream, 6); /* rz[5:0] */ + partition = bcdec__bitstream_read_bits(&bstream, 5); /* d[4:0] */ + mode = 9; + } break; + + /* mode 11 */ + case 0b00011: { + /* Partitition indices: 63 bits + Partition: 0 bits + Color Endpoints: 60 bits (10.10, 10.10, 10.10) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 10); /* rx[9:0] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 10); /* gx[9:0] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 10); /* bx[9:0] */ + mode = 10; + } break; + + /* mode 12 */ + case 0b00111: { + /* Partitition indices: 63 bits + Partition: 0 bits + Color Endpoints: 60 bits (11.9, 11.9, 11.9) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 9); /* rx[8:0] */ + r[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* rw[10] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 9); /* gx[8:0] */ + g[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* gw[10] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 9); /* bx[8:0] */ + b[0] |= bcdec__bitstream_read_bit(&bstream) << 10; /* bw[10] */ + mode = 11; + } break; + + /* mode 13 */ + case 0b01011: { + /* Partitition indices: 63 bits + Partition: 0 bits + Color Endpoints: 60 bits (12.8, 12.8, 12.8) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 8); /* rx[7:0] */ + r[0] |= bcdec__bitstream_read_bits_r(&bstream, 2) << 10;/* rx[10:11] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 8); /* gx[7:0] */ + g[0] |= bcdec__bitstream_read_bits_r(&bstream, 2) << 10;/* gx[10:11] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 8); /* bx[7:0] */ + b[0] |= bcdec__bitstream_read_bits_r(&bstream, 2) << 10;/* bx[10:11] */ + mode = 12; + } break; + + /* mode 14 */ + case 0b01111: { + /* Partitition indices: 63 bits + Partition: 0 bits + Color Endpoints: 60 bits (16.4, 16.4, 16.4) */ + r[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* rw[9:0] */ + g[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* gw[9:0] */ + b[0] |= bcdec__bitstream_read_bits(&bstream, 10); /* bw[9:0] */ + r[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* rx[3:0] */ + r[0] |= bcdec__bitstream_read_bits_r(&bstream, 6) << 10;/* rw[10:15] */ + g[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* gx[3:0] */ + g[0] |= bcdec__bitstream_read_bits_r(&bstream, 6) << 10;/* gw[10:15] */ + b[1] |= bcdec__bitstream_read_bits(&bstream, 4); /* bx[3:0] */ + b[0] |= bcdec__bitstream_read_bits_r(&bstream, 6) << 10;/* bw[10:15] */ + mode = 13; + } break; + + default: { + /* Modes 10011, 10111, 11011, and 11111 (not shown) are reserved. + Do not use these in your encoder. If the hardware is passed blocks + with one of these modes specified, the resulting decompressed block + must contain all zeroes in all channels except for the alpha channel. */ + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + decompressed[j * 3 + 0] = 0; + decompressed[j * 3 + 1] = 0; + decompressed[j * 3 + 2] = 0; + } + decompressed += destinationPitch; + } + + return; + } + } + + numPartitions = (mode >= 10) ? 0 : 1; + + actualBits0Mode = actual_bits_count[0][mode]; + if (isSigned) { + r[0] = bcdec__extend_sign(r[0], actualBits0Mode); + g[0] = bcdec__extend_sign(g[0], actualBits0Mode); + b[0] = bcdec__extend_sign(b[0], actualBits0Mode); + } + + /* Mode 11 (like Mode 10) does not use delta compression, + and instead stores both color endpoints explicitly. */ + if ((mode != 9 && mode != 10) || isSigned) { + for (i = 1; i < (numPartitions + 1) * 2; ++i) { + r[i] = bcdec__extend_sign(r[i], actual_bits_count[1][mode]); + g[i] = bcdec__extend_sign(g[i], actual_bits_count[2][mode]); + b[i] = bcdec__extend_sign(b[i], actual_bits_count[3][mode]); + } + } + + if (mode != 9 && mode != 10) { + for (i = 1; i < (numPartitions + 1) * 2; ++i) { + r[i] = bcdec__transform_inverse(r[i], r[0], actualBits0Mode, isSigned); + g[i] = bcdec__transform_inverse(g[i], g[0], actualBits0Mode, isSigned); + b[i] = bcdec__transform_inverse(b[i], b[0], actualBits0Mode, isSigned); + } + } + + for (i = 0; i < (numPartitions + 1) * 2; ++i) { + r[i] = bcdec__unquantize(r[i], actualBits0Mode, isSigned); + g[i] = bcdec__unquantize(g[i], actualBits0Mode, isSigned); + b[i] = bcdec__unquantize(b[i], actualBits0Mode, isSigned); + } + + weights = (mode >= 10) ? aWeight4 : aWeight3; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + partitionSet = (mode >= 10) ? ((i|j) ? 0 : 128) : partition_sets[partition][i][j]; + + indexBits = (mode >= 10) ? 4 : 3; + /* fix-up index is specified with one less bit */ + /* The fix-up index for subset 0 is always index 0 */ + if (partitionSet & 0x80) { + indexBits--; + } + partitionSet &= 0x01; + + index = bcdec__bitstream_read_bits(&bstream, indexBits); + + ep_i = partitionSet * 2; + decompressed[j * 3 + 0] = bcdec__finish_unquantize( + bcdec__interpolate(r[ep_i], r[ep_i+1], weights, index), isSigned); + decompressed[j * 3 + 1] = bcdec__finish_unquantize( + bcdec__interpolate(g[ep_i], g[ep_i+1], weights, index), isSigned); + decompressed[j * 3 + 2] = bcdec__finish_unquantize( + bcdec__interpolate(b[ep_i], b[ep_i+1], weights, index), isSigned); + } + + decompressed += destinationPitch; + } +} + +BCDECDEF void bcdec_bc6h_float(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int isSigned) { + unsigned short block[16*3]; + float* decompressed; + const unsigned short* b; + int i, j; + + bcdec_bc6h_half(compressedBlock, block, 4*3, isSigned); + b = block; + decompressed = (float*)decompressedBlock; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + decompressed[j * 3 + 0] = bcdec__half_to_float_quick(*b++); + decompressed[j * 3 + 1] = bcdec__half_to_float_quick(*b++); + decompressed[j * 3 + 2] = bcdec__half_to_float_quick(*b++); + } + decompressed += destinationPitch; + } +} + +static void bcdec__swap_values(int* a, int* b) { + a[0] ^= b[0], b[0] ^= a[0], a[0] ^= b[0]; +} + +BCDECDEF void bcdec_bc7(const void* compressedBlock, void* decompressedBlock, int destinationPitch) { + static char actual_bits_count[2][8] = { + { 4, 6, 5, 7, 5, 7, 7, 5 }, /* RGBA */ + { 0, 0, 0, 0, 6, 8, 7, 5 }, /* Alpha */ + }; + + /* There are 64 possible partition sets for a two-region tile. + Each 4x4 block represents a single shape. + Here also every fix-up index has MSB bit set. */ + static unsigned char partition_sets[2][64][4][4] = { + { /* Partition table for 2-subset BPTC */ + { {128, 0, 1, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 0, 1, 129} }, /* 0 */ + { {128, 0, 0, 1}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 0, 129} }, /* 1 */ + { {128, 1, 1, 1}, {0, 1, 1, 1}, { 0, 1, 1, 1}, {0, 1, 1, 129} }, /* 2 */ + { {128, 0, 0, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 1, 1, 129} }, /* 3 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 1, 129} }, /* 4 */ + { {128, 0, 1, 1}, {0, 1, 1, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 5 */ + { {128, 0, 0, 1}, {0, 0, 1, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 6 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 0, 1, 1}, {0, 1, 1, 129} }, /* 7 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 1}, {0, 0, 1, 129} }, /* 8 */ + { {128, 0, 1, 1}, {0, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 9 */ + { {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} }, /* 10 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 1}, {0, 1, 1, 129} }, /* 11 */ + { {128, 0, 0, 1}, {0, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 12 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 13 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} }, /* 14 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 0}, {1, 1, 1, 129} }, /* 15 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, { 1, 1, 1, 0}, {1, 1, 1, 129} }, /* 16 */ + { {128, 1, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 0}, {0, 0, 0, 0} }, /* 17 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 1, 0} }, /* 18 */ + { {128, 1, 129, 1}, {0, 0, 1, 1}, { 0, 0, 0, 1}, {0, 0, 0, 0} }, /* 19 */ + { {128, 0, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 0}, {0, 0, 0, 0} }, /* 20 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, {129, 1, 0, 0}, {1, 1, 1, 0} }, /* 21 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 0, 0} }, /* 22 */ + { {128, 1, 1, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 0, 0, 129} }, /* 23 */ + { {128, 0, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 0, 0} }, /* 24 */ + { {128, 0, 0, 0}, {1, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 0, 0} }, /* 25 */ + { {128, 1, 129, 0}, {0, 1, 1, 0}, { 0, 1, 1, 0}, {0, 1, 1, 0} }, /* 26 */ + { {128, 0, 129, 1}, {0, 1, 1, 0}, { 0, 1, 1, 0}, {1, 1, 0, 0} }, /* 27 */ + { {128, 0, 0, 1}, {0, 1, 1, 1}, {129, 1, 1, 0}, {1, 0, 0, 0} }, /* 28 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, {129, 1, 1, 1}, {0, 0, 0, 0} }, /* 29 */ + { {128, 1, 129, 1}, {0, 0, 0, 1}, { 1, 0, 0, 0}, {1, 1, 1, 0} }, /* 30 */ + { {128, 0, 129, 1}, {1, 0, 0, 1}, { 1, 0, 0, 1}, {1, 1, 0, 0} }, /* 31 */ + { {128, 1, 0, 1}, {0, 1, 0, 1}, { 0, 1, 0, 1}, {0, 1, 0, 129} }, /* 32 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, { 0, 0, 0, 0}, {1, 1, 1, 129} }, /* 33 */ + { {128, 1, 0, 1}, {1, 0, 129, 0}, { 0, 1, 0, 1}, {1, 0, 1, 0} }, /* 34 */ + { {128, 0, 1, 1}, {0, 0, 1, 1}, {129, 1, 0, 0}, {1, 1, 0, 0} }, /* 35 */ + { {128, 0, 129, 1}, {1, 1, 0, 0}, { 0, 0, 1, 1}, {1, 1, 0, 0} }, /* 36 */ + { {128, 1, 0, 1}, {0, 1, 0, 1}, {129, 0, 1, 0}, {1, 0, 1, 0} }, /* 37 */ + { {128, 1, 1, 0}, {1, 0, 0, 1}, { 0, 1, 1, 0}, {1, 0, 0, 129} }, /* 38 */ + { {128, 1, 0, 1}, {1, 0, 1, 0}, { 1, 0, 1, 0}, {0, 1, 0, 129} }, /* 39 */ + { {128, 1, 129, 1}, {0, 0, 1, 1}, { 1, 1, 0, 0}, {1, 1, 1, 0} }, /* 40 */ + { {128, 0, 0, 1}, {0, 0, 1, 1}, {129, 1, 0, 0}, {1, 0, 0, 0} }, /* 41 */ + { {128, 0, 129, 1}, {0, 0, 1, 0}, { 0, 1, 0, 0}, {1, 1, 0, 0} }, /* 42 */ + { {128, 0, 129, 1}, {1, 0, 1, 1}, { 1, 1, 0, 1}, {1, 1, 0, 0} }, /* 43 */ + { {128, 1, 129, 0}, {1, 0, 0, 1}, { 1, 0, 0, 1}, {0, 1, 1, 0} }, /* 44 */ + { {128, 0, 1, 1}, {1, 1, 0, 0}, { 1, 1, 0, 0}, {0, 0, 1, 129} }, /* 45 */ + { {128, 1, 1, 0}, {0, 1, 1, 0}, { 1, 0, 0, 1}, {1, 0, 0, 129} }, /* 46 */ + { {128, 0, 0, 0}, {0, 1, 129, 0}, { 0, 1, 1, 0}, {0, 0, 0, 0} }, /* 47 */ + { {128, 1, 0, 0}, {1, 1, 129, 0}, { 0, 1, 0, 0}, {0, 0, 0, 0} }, /* 48 */ + { {128, 0, 129, 0}, {0, 1, 1, 1}, { 0, 0, 1, 0}, {0, 0, 0, 0} }, /* 49 */ + { {128, 0, 0, 0}, {0, 0, 129, 0}, { 0, 1, 1, 1}, {0, 0, 1, 0} }, /* 50 */ + { {128, 0, 0, 0}, {0, 1, 0, 0}, {129, 1, 1, 0}, {0, 1, 0, 0} }, /* 51 */ + { {128, 1, 1, 0}, {1, 1, 0, 0}, { 1, 0, 0, 1}, {0, 0, 1, 129} }, /* 52 */ + { {128, 0, 1, 1}, {0, 1, 1, 0}, { 1, 1, 0, 0}, {1, 0, 0, 129} }, /* 53 */ + { {128, 1, 129, 0}, {0, 0, 1, 1}, { 1, 0, 0, 1}, {1, 1, 0, 0} }, /* 54 */ + { {128, 0, 129, 1}, {1, 0, 0, 1}, { 1, 1, 0, 0}, {0, 1, 1, 0} }, /* 55 */ + { {128, 1, 1, 0}, {1, 1, 0, 0}, { 1, 1, 0, 0}, {1, 0, 0, 129} }, /* 56 */ + { {128, 1, 1, 0}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {1, 0, 0, 129} }, /* 57 */ + { {128, 1, 1, 1}, {1, 1, 1, 0}, { 1, 0, 0, 0}, {0, 0, 0, 129} }, /* 58 */ + { {128, 0, 0, 1}, {1, 0, 0, 0}, { 1, 1, 1, 0}, {0, 1, 1, 129} }, /* 59 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, { 0, 0, 1, 1}, {0, 0, 1, 129} }, /* 60 */ + { {128, 0, 129, 1}, {0, 0, 1, 1}, { 1, 1, 1, 1}, {0, 0, 0, 0} }, /* 61 */ + { {128, 0, 129, 0}, {0, 0, 1, 0}, { 1, 1, 1, 0}, {1, 1, 1, 0} }, /* 62 */ + { {128, 1, 0, 0}, {0, 1, 0, 0}, { 0, 1, 1, 1}, {0, 1, 1, 129} } /* 63 */ + }, + { /* Partition table for 3-subset BPTC */ + { {128, 0, 1, 129}, {0, 0, 1, 1}, { 0, 2, 2, 1}, { 2, 2, 2, 130} }, /* 0 */ + { {128, 0, 0, 129}, {0, 0, 1, 1}, {130, 2, 1, 1}, { 2, 2, 2, 1} }, /* 1 */ + { {128, 0, 0, 0}, {2, 0, 0, 1}, {130, 2, 1, 1}, { 2, 2, 1, 129} }, /* 2 */ + { {128, 2, 2, 130}, {0, 0, 2, 2}, { 0, 0, 1, 1}, { 0, 1, 1, 129} }, /* 3 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 1, 2, 2}, { 1, 1, 2, 130} }, /* 4 */ + { {128, 0, 1, 129}, {0, 0, 1, 1}, { 0, 0, 2, 2}, { 0, 0, 2, 130} }, /* 5 */ + { {128, 0, 2, 130}, {0, 0, 2, 2}, { 1, 1, 1, 1}, { 1, 1, 1, 129} }, /* 6 */ + { {128, 0, 1, 1}, {0, 0, 1, 1}, {130, 2, 1, 1}, { 2, 2, 1, 129} }, /* 7 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 1, 1, 1}, { 2, 2, 2, 130} }, /* 8 */ + { {128, 0, 0, 0}, {1, 1, 1, 1}, {129, 1, 1, 1}, { 2, 2, 2, 130} }, /* 9 */ + { {128, 0, 0, 0}, {1, 1, 129, 1}, { 2, 2, 2, 2}, { 2, 2, 2, 130} }, /* 10 */ + { {128, 0, 1, 2}, {0, 0, 129, 2}, { 0, 0, 1, 2}, { 0, 0, 1, 130} }, /* 11 */ + { {128, 1, 1, 2}, {0, 1, 129, 2}, { 0, 1, 1, 2}, { 0, 1, 1, 130} }, /* 12 */ + { {128, 1, 2, 2}, {0, 129, 2, 2}, { 0, 1, 2, 2}, { 0, 1, 2, 130} }, /* 13 */ + { {128, 0, 1, 129}, {0, 1, 1, 2}, { 1, 1, 2, 2}, { 1, 2, 2, 130} }, /* 14 */ + { {128, 0, 1, 129}, {2, 0, 0, 1}, {130, 2, 0, 0}, { 2, 2, 2, 0} }, /* 15 */ + { {128, 0, 0, 129}, {0, 0, 1, 1}, { 0, 1, 1, 2}, { 1, 1, 2, 130} }, /* 16 */ + { {128, 1, 1, 129}, {0, 0, 1, 1}, {130, 0, 0, 1}, { 2, 2, 0, 0} }, /* 17 */ + { {128, 0, 0, 0}, {1, 1, 2, 2}, {129, 1, 2, 2}, { 1, 1, 2, 130} }, /* 18 */ + { {128, 0, 2, 130}, {0, 0, 2, 2}, { 0, 0, 2, 2}, { 1, 1, 1, 129} }, /* 19 */ + { {128, 1, 1, 129}, {0, 1, 1, 1}, { 0, 2, 2, 2}, { 0, 2, 2, 130} }, /* 20 */ + { {128, 0, 0, 129}, {0, 0, 0, 1}, {130, 2, 2, 1}, { 2, 2, 2, 1} }, /* 21 */ + { {128, 0, 0, 0}, {0, 0, 129, 1}, { 0, 1, 2, 2}, { 0, 1, 2, 130} }, /* 22 */ + { {128, 0, 0, 0}, {1, 1, 0, 0}, {130, 2, 129, 0}, { 2, 2, 1, 0} }, /* 23 */ + { {128, 1, 2, 130}, {0, 129, 2, 2}, { 0, 0, 1, 1}, { 0, 0, 0, 0} }, /* 24 */ + { {128, 0, 1, 2}, {0, 0, 1, 2}, {129, 1, 2, 2}, { 2, 2, 2, 130} }, /* 25 */ + { {128, 1, 1, 0}, {1, 2, 130, 1}, {129, 2, 2, 1}, { 0, 1, 1, 0} }, /* 26 */ + { {128, 0, 0, 0}, {0, 1, 129, 0}, { 1, 2, 130, 1}, { 1, 2, 2, 1} }, /* 27 */ + { {128, 0, 2, 2}, {1, 1, 0, 2}, {129, 1, 0, 2}, { 0, 0, 2, 130} }, /* 28 */ + { {128, 1, 1, 0}, {0, 129, 1, 0}, { 2, 0, 0, 2}, { 2, 2, 2, 130} }, /* 29 */ + { {128, 0, 1, 1}, {0, 1, 2, 2}, { 0, 1, 130, 2}, { 0, 0, 1, 129} }, /* 30 */ + { {128, 0, 0, 0}, {2, 0, 0, 0}, {130, 2, 1, 1}, { 2, 2, 2, 129} }, /* 31 */ + { {128, 0, 0, 0}, {0, 0, 0, 2}, {129, 1, 2, 2}, { 1, 2, 2, 130} }, /* 32 */ + { {128, 2, 2, 130}, {0, 0, 2, 2}, { 0, 0, 1, 2}, { 0, 0, 1, 129} }, /* 33 */ + { {128, 0, 1, 129}, {0, 0, 1, 2}, { 0, 0, 2, 2}, { 0, 2, 2, 130} }, /* 34 */ + { {128, 1, 2, 0}, {0, 129, 2, 0}, { 0, 1, 130, 0}, { 0, 1, 2, 0} }, /* 35 */ + { {128, 0, 0, 0}, {1, 1, 129, 1}, { 2, 2, 130, 2}, { 0, 0, 0, 0} }, /* 36 */ + { {128, 1, 2, 0}, {1, 2, 0, 1}, {130, 0, 129, 2}, { 0, 1, 2, 0} }, /* 37 */ + { {128, 1, 2, 0}, {2, 0, 1, 2}, {129, 130, 0, 1}, { 0, 1, 2, 0} }, /* 38 */ + { {128, 0, 1, 1}, {2, 2, 0, 0}, { 1, 1, 130, 2}, { 0, 0, 1, 129} }, /* 39 */ + { {128, 0, 1, 1}, {1, 1, 130, 2}, { 2, 2, 0, 0}, { 0, 0, 1, 129} }, /* 40 */ + { {128, 1, 0, 129}, {0, 1, 0, 1}, { 2, 2, 2, 2}, { 2, 2, 2, 130} }, /* 41 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, {130, 1, 2, 1}, { 2, 1, 2, 129} }, /* 42 */ + { {128, 0, 2, 2}, {1, 129, 2, 2}, { 0, 0, 2, 2}, { 1, 1, 2, 130} }, /* 43 */ + { {128, 0, 2, 130}, {0, 0, 1, 1}, { 0, 0, 2, 2}, { 0, 0, 1, 129} }, /* 44 */ + { {128, 2, 2, 0}, {1, 2, 130, 1}, { 0, 2, 2, 0}, { 1, 2, 2, 129} }, /* 45 */ + { {128, 1, 0, 1}, {2, 2, 130, 2}, { 2, 2, 2, 2}, { 0, 1, 0, 129} }, /* 46 */ + { {128, 0, 0, 0}, {2, 1, 2, 1}, {130, 1, 2, 1}, { 2, 1, 2, 129} }, /* 47 */ + { {128, 1, 0, 129}, {0, 1, 0, 1}, { 0, 1, 0, 1}, { 2, 2, 2, 130} }, /* 48 */ + { {128, 2, 2, 130}, {0, 1, 1, 1}, { 0, 2, 2, 2}, { 0, 1, 1, 129} }, /* 49 */ + { {128, 0, 0, 2}, {1, 129, 1, 2}, { 0, 0, 0, 2}, { 1, 1, 1, 130} }, /* 50 */ + { {128, 0, 0, 0}, {2, 129, 1, 2}, { 2, 1, 1, 2}, { 2, 1, 1, 130} }, /* 51 */ + { {128, 2, 2, 2}, {0, 129, 1, 1}, { 0, 1, 1, 1}, { 0, 2, 2, 130} }, /* 52 */ + { {128, 0, 0, 2}, {1, 1, 1, 2}, {129, 1, 1, 2}, { 0, 0, 0, 130} }, /* 53 */ + { {128, 1, 1, 0}, {0, 129, 1, 0}, { 0, 1, 1, 0}, { 2, 2, 2, 130} }, /* 54 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 2, 1, 129, 2}, { 2, 1, 1, 130} }, /* 55 */ + { {128, 1, 1, 0}, {0, 129, 1, 0}, { 2, 2, 2, 2}, { 2, 2, 2, 130} }, /* 56 */ + { {128, 0, 2, 2}, {0, 0, 1, 1}, { 0, 0, 129, 1}, { 0, 0, 2, 130} }, /* 57 */ + { {128, 0, 2, 2}, {1, 1, 2, 2}, {129, 1, 2, 2}, { 0, 0, 2, 130} }, /* 58 */ + { {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 0}, { 2, 129, 1, 130} }, /* 59 */ + { {128, 0, 0, 130}, {0, 0, 0, 1}, { 0, 0, 0, 2}, { 0, 0, 0, 129} }, /* 60 */ + { {128, 2, 2, 2}, {1, 2, 2, 2}, { 0, 2, 2, 2}, {129, 2, 2, 130} }, /* 61 */ + { {128, 1, 0, 129}, {2, 2, 2, 2}, { 2, 2, 2, 2}, { 2, 2, 2, 130} }, /* 62 */ + { {128, 1, 1, 129}, {2, 0, 1, 1}, {130, 2, 0, 1}, { 2, 2, 2, 0} } /* 63 */ + } + }; + + static int aWeight2[] = { 0, 21, 43, 64 }; + static int aWeight3[] = { 0, 9, 18, 27, 37, 46, 55, 64 }; + static int aWeight4[] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 }; + + static unsigned char sModeHasPBits = 0b11001011; + + bcdec__bitstream_t bstream; + int mode, partition, numPartitions, numEndpoints, i, j, k, rotation, partitionSet; + int indexSelectionBit, indexBits, indexBits2, index, index2; + int endpoints[6][4]; + char indices[4][4]; + int r, g, b, a; + int* weights, * weights2; + unsigned char* decompressed; + + decompressed = (unsigned char*)decompressedBlock; + + bstream.low = ((unsigned long long*)compressedBlock)[0]; + bstream.high = ((unsigned long long*)compressedBlock)[1]; + + for (mode = 0; mode < 8 && (0 == bcdec__bitstream_read_bit(&bstream)); ++mode); + + /* unexpected mode, clear the block (transparent black) */ + if (mode >= 8) { + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + decompressed[j * 4 + 0] = 0; + decompressed[j * 4 + 1] = 0; + decompressed[j * 4 + 2] = 0; + decompressed[j * 4 + 3] = 0; + } + decompressed += destinationPitch; + } + + return; + } + + partition = 0; + numPartitions = 1; + rotation = 0; + indexSelectionBit = 0; + + if (mode == 0 || mode == 1 || mode == 2 || mode == 3 || mode == 7) { + numPartitions = (mode == 0 || mode == 2) ? 3 : 2; + partition = bcdec__bitstream_read_bits(&bstream, (mode == 0) ? 4 : 6); + } + + numEndpoints = numPartitions * 2; + + if (mode == 4 || mode == 5) { + rotation = bcdec__bitstream_read_bits(&bstream, 2); + + if (mode == 4) { + indexSelectionBit = bcdec__bitstream_read_bit(&bstream); + } + } + + /* Extract endpoints */ + /* RGB */ + for (i = 0; i < 3; ++i) { + for (j = 0; j < numEndpoints; ++j) { + endpoints[j][i] = bcdec__bitstream_read_bits(&bstream, actual_bits_count[0][mode]); + } + } + /* Alpha (if any) */ + if (actual_bits_count[1][mode] > 0) { + for (j = 0; j < numEndpoints; ++j) { + endpoints[j][3] = bcdec__bitstream_read_bits(&bstream, actual_bits_count[1][mode]); + } + } + + /* Fully decode endpoints */ + /* First handle modes that have P-bits */ + if (mode == 0 || mode == 1 || mode == 3 || mode == 6 || mode == 7) { + for (i = 0; i < numEndpoints; ++i) { + /* component-wise left-shift */ + for (j = 0; j < 4; ++j) { + endpoints[i][j] <<= 1; + } + } + + /* if P-bit is shared */ + if (mode == 1) { + i = bcdec__bitstream_read_bit(&bstream); + j = bcdec__bitstream_read_bit(&bstream); + + /* rgb component-wise insert pbits */ + for (k = 0; k < 3; ++k) { + endpoints[0][k] |= i; + endpoints[1][k] |= i; + endpoints[2][k] |= j; + endpoints[3][k] |= j; + } + } else if (sModeHasPBits & (1 << mode)) { + /* unique P-bit per endpoint */ + for (i = 0; i < numEndpoints; ++i) { + j = bcdec__bitstream_read_bit(&bstream); + for (k = 0; k < 4; ++k) { + endpoints[i][k] |= j; + } + } + } + } + + for (i = 0; i < numEndpoints; ++i) { + /* get color components precision including pbit */ + j = actual_bits_count[0][mode] + ((sModeHasPBits >> mode) & 1); + + for (k = 0; k < 3; ++k) { + /* left shift endpoint components so that their MSB lies in bit 7 */ + endpoints[i][k] = endpoints[i][k] << (8 - j); + /* Replicate each component's MSB into the LSBs revealed by the left-shift operation above */ + endpoints[i][k] = endpoints[i][k] | (endpoints[i][k] >> j); + } + + /* get alpha component precision including pbit */ + j = actual_bits_count[1][mode] + ((sModeHasPBits >> mode) & 1); + + /* left shift endpoint components so that their MSB lies in bit 7 */ + endpoints[i][3] = endpoints[i][3] << (8 - j); + /* Replicate each component's MSB into the LSBs revealed by the left-shift operation above */ + endpoints[i][3] = endpoints[i][3] | (endpoints[i][3] >> j); + } + + /* If this mode does not explicitly define the alpha component */ + /* set alpha equal to 1.0 */ + if (!actual_bits_count[1][mode]) { + for (j = 0; j < numEndpoints; ++j) { + endpoints[j][3] = 0xFF; + } + } + + /* Determine weights tables */ + indexBits = (mode == 0 || mode == 1) ? 3 : ((mode == 6) ? 4 : 2); + indexBits2 = (mode == 4) ? 3 : ((mode == 5) ? 2 : 0); + weights = (indexBits == 2) ? aWeight2 : ((indexBits == 3) ? aWeight3 : aWeight4); + weights2 = (indexBits2 == 2) ? aWeight2 : aWeight3; + + /* Quite inconvenient that indices aren't interleaved so we have to make 2 passes here */ + /* Pass #1: collecting color indices */ + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + partitionSet = (numPartitions == 1) ? ((i | j) ? 0 : 128) : partition_sets[numPartitions - 2][partition][i][j]; + + indexBits = (mode == 0 || mode == 1) ? 3 : ((mode == 6) ? 4 : 2); + /* fix-up index is specified with one less bit */ + /* The fix-up index for subset 0 is always index 0 */ + if (partitionSet & 0x80) { + indexBits--; + } + + indices[i][j] = bcdec__bitstream_read_bits(&bstream, indexBits); + } + } + + /* Pass #2: reading alpha indices (if any) and interpolating & rotating */ + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + partitionSet = (numPartitions == 1) ? ((i|j) ? 0 : 128) : partition_sets[numPartitions - 2][partition][i][j]; + partitionSet &= 0x03; + + index = indices[i][j]; + + if (!indexBits2) { + r = bcdec__interpolate(endpoints[partitionSet * 2][0], endpoints[partitionSet * 2 + 1][0], weights, index); + g = bcdec__interpolate(endpoints[partitionSet * 2][1], endpoints[partitionSet * 2 + 1][1], weights, index); + b = bcdec__interpolate(endpoints[partitionSet * 2][2], endpoints[partitionSet * 2 + 1][2], weights, index); + a = bcdec__interpolate(endpoints[partitionSet * 2][3], endpoints[partitionSet * 2 + 1][3], weights, index); + } else { + index2 = bcdec__bitstream_read_bits(&bstream, (i|j) ? indexBits2 : (indexBits2 - 1)); + /* The index value for interpolating color comes from the secondary index bits for the texel + if the mode has an index selection bit and its value is one, and from the primary index bits otherwise. + The alpha index comes from the secondary index bits if the block has a secondary index and + the block either doesn’t have an index selection bit or that bit is zero, and from the primary index bits otherwise. */ + if (!indexSelectionBit) { + r = bcdec__interpolate(endpoints[partitionSet * 2][0], endpoints[partitionSet * 2 + 1][0], weights, index); + g = bcdec__interpolate(endpoints[partitionSet * 2][1], endpoints[partitionSet * 2 + 1][1], weights, index); + b = bcdec__interpolate(endpoints[partitionSet * 2][2], endpoints[partitionSet * 2 + 1][2], weights, index); + a = bcdec__interpolate(endpoints[partitionSet * 2][3], endpoints[partitionSet * 2 + 1][3], weights2, index2); + } else { + r = bcdec__interpolate(endpoints[partitionSet * 2][0], endpoints[partitionSet * 2 + 1][0], weights2, index2); + g = bcdec__interpolate(endpoints[partitionSet * 2][1], endpoints[partitionSet * 2 + 1][1], weights2, index2); + b = bcdec__interpolate(endpoints[partitionSet * 2][2], endpoints[partitionSet * 2 + 1][2], weights2, index2); + a = bcdec__interpolate(endpoints[partitionSet * 2][3], endpoints[partitionSet * 2 + 1][3], weights, index); + } + } + + switch (rotation) { + case 1: { /* 01 – Block format is Scalar(R) Vector(AGB) - swap A and R */ + bcdec__swap_values(&a, &r); + } break; + case 2: { /* 10 – Block format is Scalar(G) Vector(RAB) - swap A and G */ + bcdec__swap_values(&a, &g); + } break; + case 3: { /* 11 - Block format is Scalar(B) Vector(RGA) - swap A and B */ + bcdec__swap_values(&a, &b); + } break; + } + + decompressed[j * 4 + 0] = r; + decompressed[j * 4 + 1] = g; + decompressed[j * 4 + 2] = b; + decompressed[j * 4 + 3] = a; + } + + decompressed += destinationPitch; + } +} + +#endif /* BCDEC_IMPLEMENTATION */ + +/* LICENSE: + +This software is available under 2 licenses -- choose whichever you prefer. + +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License + +Copyright (c) 2022 Sergii Kudlai + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------ +ALTERNATIVE B - The Unlicense + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +*/ diff --git a/dlls/d3dx9_36/d3dx9_36.spec b/dlls/d3dx9_36/d3dx9_36.spec index 13405ad8909d..d5e39385847a 100644 --- a/dlls/d3dx9_36/d3dx9_36.spec +++ b/dlls/d3dx9_36/d3dx9_36.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -287,9 +287,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 6a9b3e12b7ba..6fae64aff717 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -25,209 +25,20 @@ #include #include "wine/debug.h" #include "wine/rbtree.h" - -#define COBJMACROS -#include "d3dx9.h" +#include "d3dx_helpers.h" #define ULONG64_MAX (~(ULONG64)0) #define FOURCC_TX_1 0x54580100 -#define D3DX9_FILTER_INVALID_BITS 0xff80fff8 -static inline HRESULT d3dx9_validate_filter(uint32_t filter) -{ - if ((filter & D3DX9_FILTER_INVALID_BITS) || !(filter & 0x7) || ((filter & 0x7) > D3DX_FILTER_BOX)) - return D3DERR_INVALIDCALL; - - return D3D_OK; -} - static inline HRESULT d3dx9_handle_load_filter(DWORD *filter) { if (*filter == D3DX_DEFAULT) *filter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER; - return d3dx9_validate_filter(*filter); -} - -struct vec4 -{ - float x, y, z, w; -}; - -enum range { - RANGE_FULL = 0, - RANGE_UNORM = 1, - RANGE_SNORM = 2, -}; - -struct d3dx_color -{ - struct vec4 value; - enum range rgb_range; - enum range a_range; -}; - -static inline void set_d3dx_color(struct d3dx_color *color, const struct vec4 *value, enum range rgb_range, - enum range a_range) -{ - color->value = *value; - color->rgb_range = rgb_range; - color->a_range = a_range; -} - -struct volume -{ - UINT width; - UINT height; - UINT depth; -}; - -static inline void set_volume_struct(struct volume *volume, uint32_t width, uint32_t height, uint32_t depth) -{ - volume->width = width; - volume->height = height; - volume->depth = depth; -} - -/* These values act as indexes into the pixel_format_desc table. */ -enum d3dx_pixel_format_id -{ - D3DX_PIXEL_FORMAT_B8G8R8_UNORM, - D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, - D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM, - D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM, - D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM, - D3DX_PIXEL_FORMAT_B5G6R5_UNORM, - D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM, - D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM, - D3DX_PIXEL_FORMAT_B2G3R3_UNORM, - D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM, - D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM, - D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM, - D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM, - D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM, - D3DX_PIXEL_FORMAT_R16G16B16_UNORM, - D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM, - D3DX_PIXEL_FORMAT_R16G16_UNORM, - D3DX_PIXEL_FORMAT_A8_UNORM, - D3DX_PIXEL_FORMAT_L8A8_UNORM, - D3DX_PIXEL_FORMAT_L4A4_UNORM, - D3DX_PIXEL_FORMAT_L8_UNORM, - D3DX_PIXEL_FORMAT_L16_UNORM, - D3DX_PIXEL_FORMAT_DXT1_UNORM, - D3DX_PIXEL_FORMAT_DXT2_UNORM, - D3DX_PIXEL_FORMAT_DXT3_UNORM, - D3DX_PIXEL_FORMAT_DXT4_UNORM, - D3DX_PIXEL_FORMAT_DXT5_UNORM, - D3DX_PIXEL_FORMAT_R16_FLOAT, - D3DX_PIXEL_FORMAT_R16G16_FLOAT, - D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT, - D3DX_PIXEL_FORMAT_R32_FLOAT, - D3DX_PIXEL_FORMAT_R32G32_FLOAT, - D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT, - D3DX_PIXEL_FORMAT_P8_UINT, - D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM, - D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM, - D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM, - D3DX_PIXEL_FORMAT_U8V8_SNORM, - D3DX_PIXEL_FORMAT_U16V16_SNORM, - D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM, - D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM, - D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM, - D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM, - D3DX_PIXEL_FORMAT_UYVY, - D3DX_PIXEL_FORMAT_YUY2, - D3DX_PIXEL_FORMAT_COUNT, -}; - -/* for internal use */ -enum component_type -{ - CTYPE_EMPTY, - CTYPE_UNORM, - CTYPE_SNORM, - CTYPE_FLOAT, - CTYPE_LUMA, - CTYPE_INDEX, -}; - -enum format_flag -{ - FMT_FLAG_DXT = 0x01, - FMT_FLAG_PACKED = 0x02, - /* Internal only format, has no exact D3DFORMAT equivalent. */ - FMT_FLAG_INTERNAL = 0x04, -}; - -struct pixel_format_desc { - enum d3dx_pixel_format_id format; - BYTE bits[4]; - BYTE shift[4]; - UINT bytes_per_pixel; - UINT block_width; - UINT block_height; - UINT block_byte_count; - enum component_type a_type; - enum component_type rgb_type; - uint32_t flags; -}; - -struct d3dx_pixels -{ - const void *data; - uint32_t row_pitch; - uint32_t slice_pitch; - const PALETTEENTRY *palette; - - struct volume size; - RECT unaligned_rect; -}; - -static inline void set_d3dx_pixels(struct d3dx_pixels *pixels, const void *data, uint32_t row_pitch, - uint32_t slice_pitch, const PALETTEENTRY *palette, uint32_t width, uint32_t height, uint32_t depth, - const RECT *unaligned_rect) -{ - pixels->data = data; - pixels->row_pitch = row_pitch; - pixels->slice_pitch = slice_pitch; - pixels->palette = palette; - set_volume_struct(&pixels->size, width, height, depth); - pixels->unaligned_rect = *unaligned_rect; + return d3dx_validate_filter(*filter); } -#define D3DX_IMAGE_INFO_ONLY 1 -struct d3dx_image -{ - D3DRESOURCETYPE resource_type; - enum d3dx_pixel_format_id format; - - struct volume size; - uint32_t mip_levels; - uint32_t layer_count; - - BYTE *pixels; - PALETTEENTRY *palette; - uint32_t layer_pitch; - - /* - * image_buf and image_palette are pointers to allocated memory used to store - * image data. If they are non-NULL, they need to be freed when no longer - * in use. - */ - void *image_buf; - PALETTEENTRY *image_palette; - - D3DXIMAGE_FILEFORMAT image_file_format; -}; - -HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, - uint32_t starting_mip_level, uint32_t flags); -void d3dx_image_cleanup(struct d3dx_image *image); -HRESULT d3dx_image_get_pixels(struct d3dx_image *image, uint32_t layer, uint32_t mip_level, - struct d3dx_pixels *pixels); -void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image); - struct d3dx_include_from_file { ID3DXInclude ID3DXInclude_iface; @@ -236,97 +47,22 @@ struct d3dx_include_from_file extern CRITICAL_SECTION from_file_mutex; extern const struct ID3DXIncludeVtbl d3dx_include_from_file_vtbl; -static inline BOOL is_unknown_format(const struct pixel_format_desc *format) -{ - return (format->format == D3DX_PIXEL_FORMAT_COUNT); -} - -static inline BOOL is_index_format(const struct pixel_format_desc *format) -{ - return (format->a_type == CTYPE_INDEX || format->rgb_type == CTYPE_INDEX); -} - -static inline BOOL is_compressed_format(const struct pixel_format_desc *format) -{ - return !!(format->flags & FMT_FLAG_DXT); -} - -static inline BOOL is_packed_format(const struct pixel_format_desc *format) -{ - return !!(format->flags & FMT_FLAG_PACKED); -} - -static inline BOOL format_types_match(const struct pixel_format_desc *src, const struct pixel_format_desc *dst) -{ - if ((src->a_type && dst->a_type) && (src->a_type != dst->a_type)) - return FALSE; - - if ((src->rgb_type && dst->rgb_type) && (src->rgb_type != dst->rgb_type)) - return FALSE; - - if (src->flags != dst->flags) - return FALSE; - - return (src->rgb_type == dst->rgb_type || src->a_type == dst->a_type); -} - -static inline BOOL is_internal_format(const struct pixel_format_desc *format) -{ - return !!(format->flags & FMT_FLAG_INTERNAL); -} - -static inline BOOL is_conversion_from_supported(const struct pixel_format_desc *format) -{ - return !is_packed_format(format) && !is_unknown_format(format); -} - -static inline BOOL is_conversion_to_supported(const struct pixel_format_desc *format) -{ - return !is_index_format(format) && !is_packed_format(format) && !is_unknown_format(format); -} - HRESULT map_view_of_file(const WCHAR *filename, void **buffer, DWORD *length); HRESULT load_resource_into_memory(HMODULE module, HRSRC resinfo, void **buffer, DWORD *length); -HRESULT write_buffer_to_file(const WCHAR *filename, ID3DXBuffer *buffer); - D3DFORMAT d3dformat_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id format); enum d3dx_pixel_format_id d3dx_pixel_format_id_from_d3dformat(D3DFORMAT format); -const struct pixel_format_desc *get_d3dx_pixel_format_info(enum d3dx_pixel_format_id format); +enum d3dx_resource_type d3dx_resource_type_from_d3dresourcetype(D3DRESOURCETYPE type); const struct pixel_format_desc *get_format_info(D3DFORMAT format); const struct pixel_format_desc *get_format_info_idx(int idx); -void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *src, const PALETTEENTRY *palette, - struct d3dx_color *dst); -void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst); - -void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, - BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *size, - const struct pixel_format_desc *format); -void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, - const struct volume *src_size, const struct pixel_format_desc *src_format, - BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *dst_size, - const struct pixel_format_desc *dst_format, D3DCOLOR color_key, const PALETTEENTRY *palette); -void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, - const struct volume *src_size, const struct pixel_format_desc *src_format, - BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *dst_size, - const struct pixel_format_desc *dst_format, D3DCOLOR color_key, const PALETTEENTRY *palette); - HRESULT lock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, D3DLOCKED_RECT *lock, IDirect3DSurface9 **temp_surface, BOOL write); HRESULT unlock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, IDirect3DSurface9 *temp_surface, BOOL update); -HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, - const PALETTEENTRY *palette, enum d3dx_pixel_format_id format, uint32_t left, uint32_t top, uint32_t right, - uint32_t bottom, uint32_t front, uint32_t back, struct d3dx_pixels *pixels); -HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, - const struct pixel_format_desc *dst_desc, struct d3dx_pixels *src_pixels, - const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key); -void get_aligned_rect(uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t width, uint32_t height, - const struct pixel_format_desc *fmt_desc, RECT *aligned_rect); - -unsigned short float_32_to_16(const float in); -float float_16_to_32(const unsigned short in); +HRESULT d3dx_get_save_pixel_format_from_image_file_format(const struct pixel_format_desc *src_fmt_desc, + D3DXIMAGE_FILEFORMAT file_format, enum d3dx_pixel_format_id *save_fmt); +void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image); /* debug helpers */ const char *debug_d3dxparameter_class(D3DXPARAMETER_CLASS c); diff --git a/dlls/d3dx9_36/d3dx_helpers.c b/dlls/d3dx9_36/d3dx_helpers.c new file mode 100644 index 000000000000..8db599541a20 --- /dev/null +++ b/dlls/d3dx9_36/d3dx_helpers.c @@ -0,0 +1,3439 @@ +/* + * Copyright 2024 Connor McAdams for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "wine/debug.h" +#include "d3dx_helpers.h" + +#include "initguid.h" +#include "ole2.h" +#include "wincodec.h" + +#define BCDEC_IMPLEMENTATION +#include "bcdec.h" +#define STB_DXT_IMPLEMENTATION +#include "stb_dxt.h" +#include + +WINE_DEFAULT_DEBUG_CHANNEL(d3dx); + +HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**); + +#define FMT_FLAGS_BCN_SRGB (FMT_FLAG_DXT | FMT_FLAG_DXGI | FMT_FLAG_SRGB) +/************************************************************ + * pixel format table providing info about number of bytes per pixel, + * number of bits per channel and format type. + * + * Call get_format_info to request information about a specific format. + */ +static const struct pixel_format_desc formats[] = +{ + /* format bpc shifts bpp blocks alpha type rgb type flags */ + {D3DX_PIXEL_FORMAT_B8G8R8_UNORM, { 0, 8, 8, 8}, { 0, 16, 8, 0}, 3, 1, 1, 3, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, { 8, 8, 8, 8}, {24, 16, 8, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM_SRGB, { 8, 8, 8, 8}, {24, 16, 8, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXGI | FMT_FLAG_SRGB}, + {D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM, { 0, 8, 8, 8}, { 0, 16, 8, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM, { 8, 8, 8, 8}, {24, 0, 8, 16}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM_SRGB, { 8, 8, 8, 8}, {24, 0, 8, 16}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXGI | FMT_FLAG_SRGB}, + {D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM, { 0, 8, 8, 8}, { 0, 0, 8, 16}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B5G6R5_UNORM, { 0, 5, 6, 5}, { 0, 11, 5, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM, { 0, 5, 5, 5}, { 0, 10, 5, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM, { 1, 5, 5, 5}, {15, 10, 5, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B2G3R3_UNORM, { 0, 3, 3, 2}, { 0, 5, 2, 0}, 1, 1, 1, 1, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM, { 8, 3, 3, 2}, { 8, 5, 2, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM, { 4, 4, 4, 4}, {12, 8, 4, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM, { 0, 4, 4, 4}, { 0, 8, 4, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM, { 2, 10, 10, 10}, {30, 20, 10, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM, { 2, 10, 10, 10}, {30, 0, 10, 20}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_R16G16B16_UNORM, { 0, 16, 16, 16}, { 0, 0, 16, 32}, 6, 1, 1, 6, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_INTERNAL}, + {D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_R8_UNORM, { 0, 8, 0, 0}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_DXGI}, + {D3DX_PIXEL_FORMAT_R8_SNORM, { 0, 8, 0, 0}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_EMPTY, CTYPE_SNORM, FMT_FLAG_DXGI}, + {D3DX_PIXEL_FORMAT_R8G8_UNORM, { 0, 8, 8, 0}, { 0, 0, 8, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_DXGI}, + {D3DX_PIXEL_FORMAT_R16_UNORM, { 0, 16, 0, 0}, { 0, 0, 0, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_DXGI}, + {D3DX_PIXEL_FORMAT_R16G16_UNORM, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_A8_UNORM, { 8, 0, 0, 0}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_UNORM, CTYPE_EMPTY, 0 }, + {D3DX_PIXEL_FORMAT_L8A8_UNORM, { 8, 8, 0, 0}, { 8, 0, 0, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_LUMA, 0 }, + {D3DX_PIXEL_FORMAT_L4A4_UNORM, { 4, 4, 0, 0}, { 4, 0, 0, 0}, 1, 1, 1, 1, CTYPE_UNORM, CTYPE_LUMA, 0 }, + {D3DX_PIXEL_FORMAT_L8_UNORM, { 0, 8, 0, 0}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_EMPTY, CTYPE_LUMA, 0 }, + {D3DX_PIXEL_FORMAT_L16_UNORM, { 0, 16, 0, 0}, { 0, 0, 0, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_LUMA, 0 }, + {D3DX_PIXEL_FORMAT_DXT1_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 8, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, + {D3DX_PIXEL_FORMAT_BC1_UNORM_SRGB, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 8, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAGS_BCN_SRGB}, + {D3DX_PIXEL_FORMAT_DXT2_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT | FMT_FLAG_PM_ALPHA}, + {D3DX_PIXEL_FORMAT_DXT3_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, + {D3DX_PIXEL_FORMAT_BC2_UNORM_SRGB, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAGS_BCN_SRGB}, + {D3DX_PIXEL_FORMAT_DXT4_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT | FMT_FLAG_PM_ALPHA}, + {D3DX_PIXEL_FORMAT_DXT5_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, + {D3DX_PIXEL_FORMAT_BC3_UNORM_SRGB, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAGS_BCN_SRGB}, + {D3DX_PIXEL_FORMAT_BC4_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 8, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_DXT | FMT_FLAG_DXGI}, + {D3DX_PIXEL_FORMAT_BC4_SNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 8, CTYPE_EMPTY, CTYPE_SNORM, FMT_FLAG_DXT | FMT_FLAG_DXGI}, + {D3DX_PIXEL_FORMAT_BC5_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_DXT | FMT_FLAG_DXGI}, + {D3DX_PIXEL_FORMAT_BC5_SNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_EMPTY, CTYPE_SNORM, FMT_FLAG_DXT | FMT_FLAG_DXGI}, + {D3DX_PIXEL_FORMAT_R16_FLOAT, { 0, 16, 0, 0}, { 0, 0, 0, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_R16G16_FLOAT, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_FLOAT, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_R32_FLOAT, { 0, 32, 0, 0}, { 0, 0, 0, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_R32G32_FLOAT, { 0, 32, 32, 0}, { 0, 0, 32, 0}, 8, 1, 1, 8, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_R11G11B10_FLOAT, { 0, 11, 11, 10}, { 0, 0, 11, 22}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_FLOAT, FMT_FLAG_DXGI}, + {D3DX_PIXEL_FORMAT_R32G32B32_FLOAT, { 0, 32, 32, 32}, { 0, 0, 32, 64}, 12, 1, 1, 12, CTYPE_EMPTY, CTYPE_FLOAT, FMT_FLAG_DXGI}, + {D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT, {32, 32, 32, 32}, {96, 0, 32, 64}, 16, 1, 1, 16, CTYPE_FLOAT, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_P8_UINT, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_INDEX, CTYPE_INDEX, 0 }, + {D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM, { 8, 8, 8, 8}, { 8, 0, 0, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_INDEX, 0 }, + {D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM, { 8, 8, 8, 8}, {24, 0, 8, 16}, 4, 1, 1, 4, CTYPE_SNORM, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_SNORM, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_U8V8_SNORM, { 0, 8, 8, 0}, { 0, 0, 8, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_U16V16_SNORM, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM, { 8, 8, 8, 0}, {16, 0, 8, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM, { 2, 10, 10, 10}, {30, 0, 10, 20}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, + {D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, + {D3DX_PIXEL_FORMAT_UYVY, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, + {D3DX_PIXEL_FORMAT_YUY2, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, + /* marks last element */ + {D3DX_PIXEL_FORMAT_COUNT, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 0, 1, 1, 0, CTYPE_EMPTY, CTYPE_EMPTY, 0 }, +}; + +const struct pixel_format_desc *get_d3dx_pixel_format_info(enum d3dx_pixel_format_id format) +{ + return &formats[min(format, D3DX_PIXEL_FORMAT_COUNT)]; +} + +static const struct +{ + const GUID *wic_guid; + enum d3dx_pixel_format_id d3dx_pixel_format; +} wic_pixel_formats[] = +{ + { &GUID_WICPixelFormat8bppIndexed, D3DX_PIXEL_FORMAT_P8_UINT }, + { &GUID_WICPixelFormat1bppIndexed, D3DX_PIXEL_FORMAT_P8_UINT }, + { &GUID_WICPixelFormat4bppIndexed, D3DX_PIXEL_FORMAT_P8_UINT }, + { &GUID_WICPixelFormat8bppGray, D3DX_PIXEL_FORMAT_L8_UNORM }, + { &GUID_WICPixelFormat16bppGray, D3DX_PIXEL_FORMAT_L16_UNORM }, + { &GUID_WICPixelFormat16bppBGR555, D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM }, + { &GUID_WICPixelFormat16bppBGR565, D3DX_PIXEL_FORMAT_B5G6R5_UNORM }, + { &GUID_WICPixelFormat24bppBGR, D3DX_PIXEL_FORMAT_B8G8R8_UNORM }, + { &GUID_WICPixelFormat32bppBGR, D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM }, + { &GUID_WICPixelFormat32bppBGRA, D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM }, + { &GUID_WICPixelFormat48bppRGB, D3DX_PIXEL_FORMAT_R16G16B16_UNORM }, + { &GUID_WICPixelFormat64bppRGBA, D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM }, +}; + +static enum d3dx_pixel_format_id d3dx_pixel_format_id_from_wic_pixel_format(const GUID *guid) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); i++) + { + if (IsEqualGUID(wic_pixel_formats[i].wic_guid, guid)) + return wic_pixel_formats[i].d3dx_pixel_format; + } + + return D3DX_PIXEL_FORMAT_COUNT; + +} + +static const GUID *wic_guid_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id d3dx_pixel_format) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); i++) + { + if (wic_pixel_formats[i].d3dx_pixel_format == d3dx_pixel_format) + return wic_pixel_formats[i].wic_guid; + } + + return NULL; +} + +#define IMAGETYPE_COLORMAPPED 1 +#define IMAGETYPE_TRUECOLOR 2 +#define IMAGETYPE_GRAYSCALE 3 +#define IMAGETYPE_MASK 0x07 +#define IMAGETYPE_RLE 8 + +#define IMAGE_RIGHTTOLEFT 0x10 +#define IMAGE_TOPTOBOTTOM 0x20 + +#include "pshpack1.h" +struct tga_header +{ + uint8_t id_length; + uint8_t color_map_type; + uint8_t image_type; + uint16_t color_map_firstentry; + uint16_t color_map_length; + uint8_t color_map_entrysize; + uint16_t xorigin; + uint16_t yorigin; + uint16_t width; + uint16_t height; + uint8_t depth; + uint8_t image_descriptor; +}; +#include "poppack.h" + +static const struct +{ + struct dds_pixel_format dds_pixel_format; + enum d3dx_pixel_format_id d3dx_pixel_format; +} dds_pixel_formats[] = +{ + /* DDS_PF_FOURCC. */ + { { 32, DDS_PF_FOURCC, MAKEFOURCC('U','Y','V','Y') }, D3DX_PIXEL_FORMAT_UYVY }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('Y','U','Y','2') }, D3DX_PIXEL_FORMAT_YUY2 }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G'), 16 }, D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B'), 16 }, D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1'), 4 }, D3DX_PIXEL_FORMAT_DXT1_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','2') }, D3DX_PIXEL_FORMAT_DXT2_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3'), 4 }, D3DX_PIXEL_FORMAT_DXT3_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','4') }, D3DX_PIXEL_FORMAT_DXT4_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5'), 8 }, D3DX_PIXEL_FORMAT_DXT5_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','U'), 8 }, D3DX_PIXEL_FORMAT_BC4_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','4','S'), 8 }, D3DX_PIXEL_FORMAT_BC4_SNORM }, + /* ATI2 is treated identically to BC5U in d3dx10+. */ + { { 32, DDS_PF_FOURCC, MAKEFOURCC('A','T','I','2'), 8 }, D3DX_PIXEL_FORMAT_BC5_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','5','U'), 8 }, D3DX_PIXEL_FORMAT_BC5_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('B','C','5','S'), 8 }, D3DX_PIXEL_FORMAT_BC5_SNORM }, + /* These aren't actually fourcc values, they're just D3DFMT values. */ + { { 32, DDS_PF_FOURCC, 0x24, 64 }, D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM }, + { { 32, DDS_PF_FOURCC, 0x6e, 64 }, D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM }, + { { 32, DDS_PF_FOURCC, 0x6f, 16 }, D3DX_PIXEL_FORMAT_R16_FLOAT }, + { { 32, DDS_PF_FOURCC, 0x70, 32 }, D3DX_PIXEL_FORMAT_R16G16_FLOAT }, + { { 32, DDS_PF_FOURCC, 0x71, 64 }, D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT }, + { { 32, DDS_PF_FOURCC, 0x72, 32 }, D3DX_PIXEL_FORMAT_R32_FLOAT }, + { { 32, DDS_PF_FOURCC, 0x73, 64 }, D3DX_PIXEL_FORMAT_R32G32_FLOAT }, + { { 32, DDS_PF_FOURCC, 0x74, 128 }, D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT }, + /* DDS_PF_RGB. */ + { { 32, DDS_PF_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0x00 }, D3DX_PIXEL_FORMAT_B2G3R3_UNORM }, + { { 32, DDS_PF_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0x0000 }, D3DX_PIXEL_FORMAT_B5G6R5_UNORM }, + { { 32, DDS_PF_RGB, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x0000 }, D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM }, + { { 32, DDS_PF_RGB, 0, 16, 0x0f00, 0x00f0, 0x000f, 0x0000 }, D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM }, + { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, D3DX_PIXEL_FORMAT_B8G8R8_UNORM }, + { { 32, DDS_PF_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 }, D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM }, + { { 32, DDS_PF_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_R16G16_UNORM }, + { { 32, DDS_PF_RGB, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 }, D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00 }, D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000 }, D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000 }, D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }, D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }, D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 }, D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM }, + /* DDS_PF_INDEXED. */ + { { 32, DDS_PF_INDEXED, 0, 8 }, D3DX_PIXEL_FORMAT_P8_UINT }, + { { 32, DDS_PF_INDEXED | DDS_PF_ALPHA, 0, 16, 0, 0, 0, 0xff00, }, D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM }, + /* DDS_PF_LUMINANCE. */ + { { 32, DDS_PF_LUMINANCE, 0, 8, 0x00ff }, D3DX_PIXEL_FORMAT_L8_UNORM }, + { { 32, DDS_PF_LUMINANCE, 0, 16, 0xffff }, D3DX_PIXEL_FORMAT_L16_UNORM }, + { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x000f, 0, 0, 0x00f0 }, D3DX_PIXEL_FORMAT_L4A4_UNORM }, + { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 16, 0x00ff, 0, 0, 0xff00 }, D3DX_PIXEL_FORMAT_L8A8_UNORM }, + /* Exceptional case, A8L8 can also have 8bpp. */ + { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x00ff, 0, 0, 0xff00 }, D3DX_PIXEL_FORMAT_L8A8_UNORM }, + /* DDS_PF_ALPHA_ONLY. */ + { { 32, DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff }, D3DX_PIXEL_FORMAT_A8_UNORM }, + /* DDS_PF_BUMPDUDV. */ + { { 32, DDS_PF_BUMPDUDV, 0, 16, 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_U8V8_SNORM }, + { { 32, DDS_PF_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_U16V16_SNORM }, + { { 32, DDS_PF_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }, D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM }, + { { 32, DDS_PF_BUMPDUDV | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }, D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM }, + /* DDS_PF_BUMPLUMINANCE. */ + { { 32, DDS_PF_BUMPLUMINANCE, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 }, D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM }, +}; + +static BOOL dds_pixel_format_compare(const struct dds_pixel_format *pf_a, const struct dds_pixel_format *pf_b, + BOOL check_rmask, BOOL check_gmask, BOOL check_bmask, BOOL check_amask) +{ + return pf_a->bpp == pf_b->bpp && !((check_rmask && pf_a->rmask != pf_b->rmask) + || (check_gmask && pf_a->gmask != pf_b->gmask) || (check_bmask && pf_a->bmask != pf_b->bmask) + || (check_amask && pf_a->amask != pf_b->amask)); +} + +static enum d3dx_pixel_format_id d3dx_pixel_format_id_from_dds_pixel_format(const struct dds_pixel_format *pixel_format) +{ + uint32_t i; + + TRACE("pixel_format: size %lu, flags %#lx, fourcc %#lx, bpp %lu.\n", pixel_format->size, + pixel_format->flags, pixel_format->fourcc, pixel_format->bpp); + TRACE("rmask %#lx, gmask %#lx, bmask %#lx, amask %#lx.\n", pixel_format->rmask, pixel_format->gmask, + pixel_format->bmask, pixel_format->amask); + + for (i = 0; i < ARRAY_SIZE(dds_pixel_formats); ++i) + { + const struct dds_pixel_format *dds_pf = &dds_pixel_formats[i].dds_pixel_format; + + if (pixel_format->flags != dds_pf->flags + /* Alpha flag might also be set alongside fourCC. */ + && ((pixel_format->flags & DDS_PF_FOURCC) != dds_pf->flags)) + continue; + + switch (pixel_format->flags & ~DDS_PF_ALPHA) + { + case DDS_PF_ALPHA_ONLY: + if (dds_pixel_format_compare(pixel_format, dds_pf, FALSE, FALSE, FALSE, TRUE)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_FOURCC: + if (pixel_format->fourcc == dds_pf->fourcc) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_INDEXED: + if (dds_pixel_format_compare(pixel_format, dds_pf, FALSE, FALSE, FALSE, pixel_format->flags & DDS_PF_ALPHA)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_RGB: + if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, pixel_format->flags & DDS_PF_ALPHA)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_LUMINANCE: + if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, FALSE, FALSE, pixel_format->flags & DDS_PF_ALPHA)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_BUMPLUMINANCE: + if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, FALSE)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_BUMPDUDV: + if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, TRUE)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + default: + assert(0); /* Should not happen. */ + break; + } + } + + WARN("Unknown pixel format (flags %#lx, fourcc %#lx, bpp %lu, r %#lx, g %#lx, b %#lx, a %#lx).\n", + pixel_format->flags, pixel_format->fourcc, pixel_format->bpp, + pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask); + return D3DX_PIXEL_FORMAT_COUNT; +} + +HRESULT dds_pixel_format_from_d3dx_pixel_format_id(struct dds_pixel_format *pixel_format, + enum d3dx_pixel_format_id d3dx_pixel_format) +{ + const struct dds_pixel_format *pf = NULL; + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(dds_pixel_formats); ++i) + { + if (dds_pixel_formats[i].d3dx_pixel_format == d3dx_pixel_format) + { + pf = &dds_pixel_formats[i].dds_pixel_format; + break; + } + } + + if (!pf) + { + WARN("Unhandled format %#x.\n", d3dx_pixel_format); + return E_NOTIMPL; + } + + if (pixel_format) + *pixel_format = *pf; + + return S_OK; +} + +enum d3dx_pixel_format_id d3dx_pixel_format_id_from_dxgi_format(DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: return D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM; + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM_SRGB; + case DXGI_FORMAT_B8G8R8A8_UNORM: return D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM_SRGB; + case DXGI_FORMAT_B8G8R8X8_UNORM: return D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM; + case DXGI_FORMAT_B5G6R5_UNORM: return D3DX_PIXEL_FORMAT_B5G6R5_UNORM; + case DXGI_FORMAT_B5G5R5A1_UNORM: return D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM; + case DXGI_FORMAT_B4G4R4A4_UNORM: return D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM; + case DXGI_FORMAT_R10G10B10A2_UNORM: return D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM; + case DXGI_FORMAT_R16G16B16A16_UNORM: return D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM; + case DXGI_FORMAT_R8_UNORM: return D3DX_PIXEL_FORMAT_R8_UNORM; + case DXGI_FORMAT_R8_SNORM: return D3DX_PIXEL_FORMAT_R8_SNORM; + case DXGI_FORMAT_R8G8_UNORM: return D3DX_PIXEL_FORMAT_R8G8_UNORM; + case DXGI_FORMAT_R16_UNORM: return D3DX_PIXEL_FORMAT_R16_UNORM; + case DXGI_FORMAT_R16G16_UNORM: return D3DX_PIXEL_FORMAT_R16G16_UNORM; + case DXGI_FORMAT_A8_UNORM: return D3DX_PIXEL_FORMAT_A8_UNORM; + case DXGI_FORMAT_R16_FLOAT: return D3DX_PIXEL_FORMAT_R16_FLOAT; + case DXGI_FORMAT_R16G16_FLOAT: return D3DX_PIXEL_FORMAT_R16G16_FLOAT; + case DXGI_FORMAT_R16G16B16A16_FLOAT: return D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT; + case DXGI_FORMAT_R32_FLOAT: return D3DX_PIXEL_FORMAT_R32_FLOAT; + case DXGI_FORMAT_R32G32_FLOAT: return D3DX_PIXEL_FORMAT_R32G32_FLOAT; + case DXGI_FORMAT_R32G32B32_FLOAT: return D3DX_PIXEL_FORMAT_R32G32B32_FLOAT; + case DXGI_FORMAT_R11G11B10_FLOAT: return D3DX_PIXEL_FORMAT_R11G11B10_FLOAT; + case DXGI_FORMAT_R32G32B32A32_FLOAT: return D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT; + case DXGI_FORMAT_G8R8_G8B8_UNORM: return D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM; + case DXGI_FORMAT_R8G8_B8G8_UNORM: return D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM; + case DXGI_FORMAT_BC1_UNORM: return D3DX_PIXEL_FORMAT_BC1_UNORM; + case DXGI_FORMAT_BC1_UNORM_SRGB: return D3DX_PIXEL_FORMAT_BC1_UNORM_SRGB; + case DXGI_FORMAT_BC2_UNORM: return D3DX_PIXEL_FORMAT_BC2_UNORM; + case DXGI_FORMAT_BC2_UNORM_SRGB: return D3DX_PIXEL_FORMAT_BC2_UNORM_SRGB; + case DXGI_FORMAT_BC3_UNORM: return D3DX_PIXEL_FORMAT_BC3_UNORM; + case DXGI_FORMAT_BC3_UNORM_SRGB: return D3DX_PIXEL_FORMAT_BC3_UNORM_SRGB; + case DXGI_FORMAT_BC4_UNORM: return D3DX_PIXEL_FORMAT_BC4_UNORM; + case DXGI_FORMAT_BC4_SNORM: return D3DX_PIXEL_FORMAT_BC4_SNORM; + case DXGI_FORMAT_BC5_UNORM: return D3DX_PIXEL_FORMAT_BC5_UNORM; + case DXGI_FORMAT_BC5_SNORM: return D3DX_PIXEL_FORMAT_BC5_SNORM; + case DXGI_FORMAT_R8G8B8A8_SNORM: return D3DX_PIXEL_FORMAT_R8G8B8A8_SNORM; + case DXGI_FORMAT_R8G8_SNORM: return D3DX_PIXEL_FORMAT_R8G8_SNORM; + case DXGI_FORMAT_R16G16_SNORM: return D3DX_PIXEL_FORMAT_R16G16_SNORM; + case DXGI_FORMAT_R16G16B16A16_SNORM: return D3DX_PIXEL_FORMAT_R16G16B16A16_SNORM; + + default: + FIXME("Unhandled DXGI format %#x.\n", format); + return D3DX_PIXEL_FORMAT_COUNT; + } +} + +static DXGI_FORMAT dxgi_format_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id format) +{ + switch (format) + { + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM_SRGB: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + case D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM; + case D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + case D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM: return DXGI_FORMAT_B8G8R8X8_UNORM; + case D3DX_PIXEL_FORMAT_B5G6R5_UNORM: return DXGI_FORMAT_B5G6R5_UNORM; + case D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM: return DXGI_FORMAT_B5G5R5A1_UNORM; + case D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM: return DXGI_FORMAT_B4G4R4A4_UNORM; + case D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM: return DXGI_FORMAT_R10G10B10A2_UNORM; + case D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM: return DXGI_FORMAT_R16G16B16A16_UNORM; + case D3DX_PIXEL_FORMAT_R8_UNORM: return DXGI_FORMAT_R8_UNORM; + case D3DX_PIXEL_FORMAT_R8_SNORM: return DXGI_FORMAT_R8_SNORM; + case D3DX_PIXEL_FORMAT_R8G8_UNORM: return DXGI_FORMAT_R8G8_UNORM; + case D3DX_PIXEL_FORMAT_R16_UNORM: return DXGI_FORMAT_R16_UNORM; + case D3DX_PIXEL_FORMAT_R16G16_UNORM: return DXGI_FORMAT_R16G16_UNORM; + case D3DX_PIXEL_FORMAT_A8_UNORM: return DXGI_FORMAT_A8_UNORM; + case D3DX_PIXEL_FORMAT_R16_FLOAT: return DXGI_FORMAT_R16_FLOAT; + case D3DX_PIXEL_FORMAT_R16G16_FLOAT: return DXGI_FORMAT_R16G16_FLOAT; + case D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; + case D3DX_PIXEL_FORMAT_R32_FLOAT: return DXGI_FORMAT_R32_FLOAT; + case D3DX_PIXEL_FORMAT_R32G32_FLOAT: return DXGI_FORMAT_R32G32_FLOAT; + case D3DX_PIXEL_FORMAT_R11G11B10_FLOAT: return DXGI_FORMAT_R11G11B10_FLOAT; + case D3DX_PIXEL_FORMAT_R32G32B32_FLOAT: return DXGI_FORMAT_R32G32B32_FLOAT; + case D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT; + case D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM: return DXGI_FORMAT_G8R8_G8B8_UNORM; + case D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM: return DXGI_FORMAT_R8G8_B8G8_UNORM; + case D3DX_PIXEL_FORMAT_BC1_UNORM: return DXGI_FORMAT_BC1_UNORM; + case D3DX_PIXEL_FORMAT_BC1_UNORM_SRGB: return DXGI_FORMAT_BC1_UNORM_SRGB; + case D3DX_PIXEL_FORMAT_BC2_UNORM: return DXGI_FORMAT_BC2_UNORM; + case D3DX_PIXEL_FORMAT_BC2_UNORM_SRGB: return DXGI_FORMAT_BC2_UNORM_SRGB; + case D3DX_PIXEL_FORMAT_BC3_UNORM: return DXGI_FORMAT_BC3_UNORM; + case D3DX_PIXEL_FORMAT_BC3_UNORM_SRGB: return DXGI_FORMAT_BC3_UNORM_SRGB; + case D3DX_PIXEL_FORMAT_BC4_UNORM: return DXGI_FORMAT_BC4_UNORM; + case D3DX_PIXEL_FORMAT_BC4_SNORM: return DXGI_FORMAT_BC4_SNORM; + case D3DX_PIXEL_FORMAT_BC5_UNORM: return DXGI_FORMAT_BC5_UNORM; + case D3DX_PIXEL_FORMAT_BC5_SNORM: return DXGI_FORMAT_BC5_SNORM; + case D3DX_PIXEL_FORMAT_R8G8B8A8_SNORM: return DXGI_FORMAT_R8G8B8A8_SNORM; + case D3DX_PIXEL_FORMAT_R8G8_SNORM: return DXGI_FORMAT_R8G8_SNORM; + case D3DX_PIXEL_FORMAT_R16G16_SNORM: return DXGI_FORMAT_R16G16_SNORM; + case D3DX_PIXEL_FORMAT_R16G16B16A16_SNORM: return DXGI_FORMAT_R16G16B16A16_SNORM; + + default: + FIXME("Unhandled format %#x.\n", format); + return DXGI_FORMAT_UNKNOWN; + } +} + +/* + * These are mappings from legacy DDS header formats to DXGI formats. Some + * don't map to a DXGI_FORMAT at all, and some only map to the default format. + */ +DXGI_FORMAT dxgi_format_from_legacy_dds_d3dx_pixel_format_id(enum d3dx_pixel_format_id format) +{ + switch (format) + { + /* + * Some of these formats do have DXGI_FORMAT equivalents, but get + * mapped to DXGI_FORMAT_R8G8B8A8_UNORM instead. + */ + case D3DX_PIXEL_FORMAT_P8_UINT: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B8G8R8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B5G6R5_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B2G3R3_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_L8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_L4A4_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_L8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + + /* B10G10R10A2 doesn't exist in DXGI, both map to R10G10B10A2. */ + case D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM: + case D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM: return DXGI_FORMAT_R10G10B10A2_UNORM; + + case D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM: return DXGI_FORMAT_R16G16B16A16_SNORM; + case D3DX_PIXEL_FORMAT_L16_UNORM: return DXGI_FORMAT_R16G16B16A16_UNORM; + case D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM: return DXGI_FORMAT_R16G16B16A16_UNORM; + case D3DX_PIXEL_FORMAT_R16G16_UNORM: return DXGI_FORMAT_R16G16_UNORM; + case D3DX_PIXEL_FORMAT_A8_UNORM: return DXGI_FORMAT_A8_UNORM; + case D3DX_PIXEL_FORMAT_R16_FLOAT: return DXGI_FORMAT_R16_FLOAT; + case D3DX_PIXEL_FORMAT_R16G16_FLOAT: return DXGI_FORMAT_R16G16_FLOAT; + case D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; + case D3DX_PIXEL_FORMAT_R32_FLOAT: return DXGI_FORMAT_R32_FLOAT; + case D3DX_PIXEL_FORMAT_R32G32_FLOAT: return DXGI_FORMAT_R32G32_FLOAT; + case D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT; + case D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM: return DXGI_FORMAT_G8R8_G8B8_UNORM; + case D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM: return DXGI_FORMAT_R8G8_B8G8_UNORM; + + case D3DX_PIXEL_FORMAT_DXT1_UNORM: return DXGI_FORMAT_BC1_UNORM; + case D3DX_PIXEL_FORMAT_DXT2_UNORM: return DXGI_FORMAT_BC2_UNORM; + case D3DX_PIXEL_FORMAT_DXT3_UNORM: return DXGI_FORMAT_BC2_UNORM; + case D3DX_PIXEL_FORMAT_DXT4_UNORM: return DXGI_FORMAT_BC3_UNORM; + case D3DX_PIXEL_FORMAT_DXT5_UNORM: return DXGI_FORMAT_BC3_UNORM; + case D3DX_PIXEL_FORMAT_BC4_UNORM: return DXGI_FORMAT_BC4_UNORM; + case D3DX_PIXEL_FORMAT_BC4_SNORM: return DXGI_FORMAT_BC4_SNORM; + case D3DX_PIXEL_FORMAT_BC5_UNORM: return DXGI_FORMAT_BC5_UNORM; + case D3DX_PIXEL_FORMAT_BC5_SNORM: return DXGI_FORMAT_BC5_SNORM; + + /* These formats are known and explicitly unsupported on d3dx10+. */ + case D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM: + case D3DX_PIXEL_FORMAT_U8V8_SNORM: + case D3DX_PIXEL_FORMAT_U16V16_SNORM: + case D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM: + case D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM: + case D3DX_PIXEL_FORMAT_UYVY: + case D3DX_PIXEL_FORMAT_YUY2: + return DXGI_FORMAT_UNKNOWN; + + default: + FIXME("Unknown d3dx_pixel_format_id %#x.\n", format); + return DXGI_FORMAT_UNKNOWN; + } +} + +DXGI_FORMAT dxgi_format_from_dxt10_dds_d3dx_pixel_format_id(enum d3dx_pixel_format_id format) +{ + switch (format) + { + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM_SRGB: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + case D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM; + case D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + case D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM: return DXGI_FORMAT_B8G8R8X8_UNORM; + case D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM: return DXGI_FORMAT_R10G10B10A2_UNORM; + case D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM: return DXGI_FORMAT_R16G16B16A16_UNORM; + case D3DX_PIXEL_FORMAT_R8_UNORM: return DXGI_FORMAT_R8_UNORM; + case D3DX_PIXEL_FORMAT_R8_SNORM: return DXGI_FORMAT_R8_SNORM; + case D3DX_PIXEL_FORMAT_R8G8_UNORM: return DXGI_FORMAT_R8G8_UNORM; + case D3DX_PIXEL_FORMAT_R16_UNORM: return DXGI_FORMAT_R16_UNORM; + case D3DX_PIXEL_FORMAT_R16G16_UNORM: return DXGI_FORMAT_R16G16_UNORM; + case D3DX_PIXEL_FORMAT_A8_UNORM: return DXGI_FORMAT_A8_UNORM; + case D3DX_PIXEL_FORMAT_R16_FLOAT: return DXGI_FORMAT_R16_FLOAT; + case D3DX_PIXEL_FORMAT_R16G16_FLOAT: return DXGI_FORMAT_R16G16_FLOAT; + case D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; + case D3DX_PIXEL_FORMAT_R32_FLOAT: return DXGI_FORMAT_R32_FLOAT; + case D3DX_PIXEL_FORMAT_R32G32_FLOAT: return DXGI_FORMAT_R32G32_FLOAT; + case D3DX_PIXEL_FORMAT_R11G11B10_FLOAT: return DXGI_FORMAT_R11G11B10_FLOAT; + case D3DX_PIXEL_FORMAT_R32G32B32_FLOAT: return DXGI_FORMAT_R32G32B32_FLOAT; + case D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT; + case D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM: return DXGI_FORMAT_G8R8_G8B8_UNORM; + case D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM: return DXGI_FORMAT_R8G8_B8G8_UNORM; + case D3DX_PIXEL_FORMAT_BC1_UNORM: return DXGI_FORMAT_BC1_UNORM; + case D3DX_PIXEL_FORMAT_BC1_UNORM_SRGB: return DXGI_FORMAT_BC1_UNORM_SRGB; + case D3DX_PIXEL_FORMAT_BC2_UNORM: return DXGI_FORMAT_BC2_UNORM; + case D3DX_PIXEL_FORMAT_BC2_UNORM_SRGB: return DXGI_FORMAT_BC2_UNORM_SRGB; + case D3DX_PIXEL_FORMAT_BC3_UNORM: return DXGI_FORMAT_BC3_UNORM; + case D3DX_PIXEL_FORMAT_BC3_UNORM_SRGB: return DXGI_FORMAT_BC3_UNORM_SRGB; + case D3DX_PIXEL_FORMAT_BC4_UNORM: return DXGI_FORMAT_BC4_UNORM; + case D3DX_PIXEL_FORMAT_BC4_SNORM: return DXGI_FORMAT_BC4_SNORM; + case D3DX_PIXEL_FORMAT_BC5_UNORM: return DXGI_FORMAT_BC5_UNORM; + case D3DX_PIXEL_FORMAT_BC5_SNORM: return DXGI_FORMAT_BC5_SNORM; + case D3DX_PIXEL_FORMAT_R16G16B16A16_SNORM: return DXGI_FORMAT_R16G16B16A16_SNORM; + case D3DX_PIXEL_FORMAT_R8G8B8A8_SNORM: return DXGI_FORMAT_R8G8B8A8_SNORM; + case D3DX_PIXEL_FORMAT_R8G8_SNORM: return DXGI_FORMAT_R8G8_SNORM; + case D3DX_PIXEL_FORMAT_R16G16_SNORM: return DXGI_FORMAT_R16G16_SNORM; + + /* + * These have DXGI_FORMAT equivalents, but are explicitly unsupported on + * d3dx10/d3dx11. + */ + case D3DX_PIXEL_FORMAT_B5G6R5_UNORM: + case D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM: + case D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM: + return DXGI_FORMAT_UNKNOWN; + + default: + FIXME("Unhandled d3dx_pixel_format_id %#x.\n", format); + return DXGI_FORMAT_UNKNOWN; + } +} + +void d3dx_get_next_mip_level_size(struct volume *size) +{ + size->width = max(size->width / 2, 1); + size->height = max(size->height / 2, 1); + size->depth = max(size->depth / 2, 1); +} + +void d3dx_get_mip_level_size(struct volume *size, uint32_t level) +{ + uint32_t i; + + for (i = 0; i < level; ++i) + d3dx_get_next_mip_level_size(size); +} + +uint32_t d3dx_get_max_mip_levels_for_size(uint32_t width, uint32_t height, uint32_t depth) +{ + struct volume tmp = { width, height, depth }; + uint32_t mip_levels = 1; + + while (!(tmp.width == 1 && tmp.height == 1 && tmp.depth == 1)) + { + d3dx_get_next_mip_level_size(&tmp); + mip_levels++; + } + + return mip_levels; +} + +static const char *debug_volume(const struct volume *volume) +{ + if (!volume) + return "(null)"; + return wine_dbg_sprintf("(%ux%ux%u)", volume->width, volume->height, volume->depth); +} + +HRESULT d3dx_calculate_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, + uint32_t *pitch, uint32_t *size) +{ + const struct pixel_format_desc *format_desc = get_d3dx_pixel_format_info(format); + + if (is_unknown_format(format_desc)) + return E_NOTIMPL; + + if (format_desc->block_width != 1 || format_desc->block_height != 1) + { + *pitch = format_desc->block_byte_count + * max(1, (width + format_desc->block_width - 1) / format_desc->block_width); + *size = *pitch + * max(1, (height + format_desc->block_height - 1) / format_desc->block_height); + } + else + { + *pitch = width * format_desc->bytes_per_pixel; + *size = *pitch * height; + } + + return S_OK; +} + +uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, uint32_t depth, + uint32_t mip_levels) +{ + uint32_t layer_size, row_pitch, slice_pitch, i; + struct volume dims = { width, height, depth }; + + layer_size = 0; + for (i = 0; i < mip_levels; ++i) + { + if (FAILED(d3dx_calculate_pixels_size(format, dims.width, dims.height, &row_pitch, &slice_pitch))) + return 0; + layer_size += slice_pitch * dims.depth; + d3dx_get_next_mip_level_size(&dims); + } + + return layer_size; +} + +/* These defines match D3D10/D3D11 values. */ +#define DDS_RESOURCE_MISC_TEXTURECUBE 0x04 +#define DDS_RESOURCE_DIMENSION_UNKNOWN 0 +#define DDS_RESOURCE_DIMENSION_TEXTURE1D 2 +#define DDS_RESOURCE_DIMENSION_TEXTURE2D 3 +#define DDS_RESOURCE_DIMENSION_TEXTURE3D 4 +struct dds_header_dxt10 +{ + uint32_t dxgi_format; + uint32_t resource_dimension; + uint32_t misc_flags; + uint32_t array_size; + uint32_t misc_flags2; +}; + +static void set_dds_header_dxt10(struct dds_header_dxt10 *dxt10, uint32_t dxgi_format, uint32_t resource_dimension, + uint32_t misc_flags, uint32_t array_size, uint32_t misc_flags2) +{ + dxt10->dxgi_format = dxgi_format; + dxt10->resource_dimension = resource_dimension; + dxt10->misc_flags = misc_flags; + dxt10->array_size = array_size; + dxt10->misc_flags2 = misc_flags2; +} + +static uint32_t dxt10_resource_dimension_from_d3dx_resource_type(enum d3dx_resource_type resource_type) +{ + switch (resource_type) + { + case D3DX_RESOURCE_TYPE_TEXTURE_1D: return DDS_RESOURCE_DIMENSION_TEXTURE1D; + case D3DX_RESOURCE_TYPE_TEXTURE_2D: return DDS_RESOURCE_DIMENSION_TEXTURE2D; + case D3DX_RESOURCE_TYPE_TEXTURE_3D: return DDS_RESOURCE_DIMENSION_TEXTURE3D; + case D3DX_RESOURCE_TYPE_CUBE_TEXTURE: return DDS_RESOURCE_DIMENSION_TEXTURE2D; + + default: + break; + } + + FIXME("Unhandled d3dx resource type %u.\n", resource_type); + return DDS_RESOURCE_DIMENSION_UNKNOWN; +} + +static BOOL has_extended_header(const struct dds_header *header) +{ + return (header->pixel_format.flags & DDS_PF_FOURCC) && + (header->pixel_format.fourcc == MAKEFOURCC('D', 'X', '1', '0')); +} + +static const struct dds_pixel_format dxt10_pf = { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','1','0') }; +static HRESULT d3dx_init_dds_header(struct dds_header *header, enum d3dx_resource_type resource_type, + enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels, uint32_t layer_count, + BOOL support_dxt10) +{ + HRESULT hr; + + memset(header, 0, sizeof(*header)); + header->signature = MAKEFOURCC('D','D','S',' '); + /* The signature is not really part of the DDS header. */ + header->size = sizeof(*header) - FIELD_OFFSET(struct dds_header, size); + header->flags = DDS_HEIGHT | DDS_WIDTH; + header->height = size->height; + header->width = size->width; + header->depth = (size->depth > 1) ? size->depth : 0; + header->miplevels = (mip_levels > 1) ? mip_levels : 0; + header->caps = DDS_CAPS_TEXTURE; + + if (size->depth > 1) + { + header->flags |= DDS_DEPTH; + header->caps2 |= DDS_CAPS2_VOLUME; + } + + if (mip_levels > 1) + header->caps |= DDS_CAPS_MIPMAP; + + if (resource_type == D3DX_RESOURCE_TYPE_CUBE_TEXTURE) + { + header->caps |= DDS_CAPS_COMPLEX; + header->caps2 |= (DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES); + } + + if (support_dxt10) + { + uint32_t row_pitch, slice_pitch; + struct dds_pixel_format pf; + + hr = dds_pixel_format_from_d3dx_pixel_format_id(&pf, format); + if (FAILED(hr) || pf.flags == DDS_PF_BUMPDUDV || pf.flags == DDS_PF_BUMPLUMINANCE + || (resource_type != D3DX_RESOURCE_TYPE_CUBE_TEXTURE && layer_count > 1) + || (resource_type == D3DX_RESOURCE_TYPE_CUBE_TEXTURE && layer_count > 6)) + { + if (dxgi_format_from_d3dx_pixel_format_id(format) == DXGI_FORMAT_UNKNOWN) + return E_NOTIMPL; + + pf = dxt10_pf; + } + + header->pixel_format = pf; + hr = d3dx_calculate_pixels_size(format, size->width, size->height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + return hr; + + /* Always sets mip levels and row pitch in header. */ + header->pitch_or_linear_size = row_pitch; + header->miplevels = mip_levels; + if (header->caps2) + header->caps |= DDS_CAPS_COMPLEX; + } + else + { + hr = dds_pixel_format_from_d3dx_pixel_format_id(&header->pixel_format, format); + if (FAILED(hr)) + return hr; + + /* d3dx10+ sets the bpp field for fourCC pixel formats, d3dx9 does not. */ + if (header->pixel_format.flags == DDS_PF_FOURCC) + header->pixel_format.bpp = 0; + + header->flags |= DDS_CAPS | DDS_PIXELFORMAT; + if (header->pixel_format.flags & DDS_PF_ALPHA || header->pixel_format.flags & DDS_PF_ALPHA_ONLY) + header->caps |= DDSCAPS_ALPHA; + if (header->pixel_format.flags & DDS_PF_INDEXED) + header->caps |= DDSCAPS_PALETTE; + if (mip_levels > 1) + { + header->flags |= DDS_MIPMAPCOUNT; + header->caps |= DDS_CAPS_COMPLEX; + } + } + + return S_OK; +} + +HRESULT d3dx_create_dds_file_blob(enum d3dx_pixel_format_id format, const PALETTEENTRY *palette, + enum d3dx_resource_type resource_type, const struct volume *size, uint32_t mip_levels, uint32_t layers, + BOOL support_dxt10, ID3DXBlob **out_blob) +{ + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(format); + uint32_t header_size, pixels_size; + struct dds_header_dxt10 dxt10; + struct dds_header header; + uint8_t *buf_ptr; + ID3DXBlob *blob; + HRESULT hr; + + *out_blob = blob = NULL; + hr = d3dx_init_dds_header(&header, resource_type, format, size, mip_levels, layers, support_dxt10); + if (FAILED(hr)) + return hr; + + pixels_size = d3dx_calculate_layer_pixels_size(format, size->width, size->height, size->depth, mip_levels) * layers; + header_size = sizeof(header); + if (is_index_format(fmt_desc)) + header_size += DDS_PALETTE_SIZE; + if (has_extended_header(&header)) + { + const BOOL is_cubemap = resource_type == D3DX_RESOURCE_TYPE_CUBE_TEXTURE; + + set_dds_header_dxt10(&dxt10, dxgi_format_from_d3dx_pixel_format_id(format), + dxt10_resource_dimension_from_d3dx_resource_type(resource_type), + is_cubemap ? DDS_RESOURCE_MISC_TEXTURECUBE : 0, + is_cubemap ? layers / 6 : layers, 0); + header_size += sizeof(dxt10); + } + + hr = d3dx_create_blob(header_size + pixels_size, &blob); + if (FAILED(hr)) + return hr; + + buf_ptr = d3dx_blob_get_buffer_pointer(blob); + memcpy(buf_ptr, &header, sizeof(header)); + if (is_index_format(fmt_desc)) + memcpy(buf_ptr + sizeof(header), palette, DDS_PALETTE_SIZE); + else if (has_extended_header(&header)) + memcpy(buf_ptr + sizeof(header), &dxt10, sizeof(dxt10)); + + *out_blob = blob; + + return hr; +} + +static const GUID *wic_container_guid_from_d3dx_file_format(enum d3dx_image_file_format iff) +{ + switch (iff) + { + case D3DX_IMAGE_FILE_FORMAT_DIB: + case D3DX_IMAGE_FILE_FORMAT_BMP: return &GUID_ContainerFormatBmp; + case D3DX_IMAGE_FILE_FORMAT_JPG: return &GUID_ContainerFormatJpeg; + case D3DX_IMAGE_FILE_FORMAT_PNG: return &GUID_ContainerFormatPng; + case D3DX_IMAGE_FILE_FORMAT_TIFF: return &GUID_ContainerFormatTiff; + case D3DX_IMAGE_FILE_FORMAT_GIF: return &GUID_ContainerFormatGif; + case D3DX_IMAGE_FILE_FORMAT_WMP: return &GUID_ContainerFormatWmp; + default: + assert(0 && "Unexpected file format."); + return NULL; + } +} + +static HRESULT d3dx_pixels_save_wic(struct d3dx_pixels *pixels, const struct pixel_format_desc *fmt_desc, + enum d3dx_image_file_format image_file_format, IStream **wic_file, uint32_t *wic_file_size) +{ + const GUID *container_format = wic_container_guid_from_d3dx_file_format(image_file_format); + const GUID *pixel_format_guid = wic_guid_from_d3dx_pixel_format_id(fmt_desc->format); + IWICBitmapFrameEncode *wic_frame = NULL; + IPropertyBag2 *encoder_options = NULL; + IWICBitmapEncoder *wic_encoder = NULL; + WICPixelFormatGUID wic_pixel_format; + const LARGE_INTEGER seek = { 0 }; + IWICImagingFactory *wic_factory; + IWICPalette *wic_palette = NULL; + IStream *stream = NULL; + STATSTG stream_stats; + HRESULT hr; + + assert(container_format && pixel_format_guid); + hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &wic_factory); + if (FAILED(hr)) + return D3DERR_INVALIDCALL; + + hr = IWICImagingFactory_CreateEncoder(wic_factory, container_format, NULL, &wic_encoder); + if (FAILED(hr)) + { + hr = D3DERR_INVALIDCALL; + goto exit; + } + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapEncoder_Initialize(wic_encoder, stream, WICBitmapEncoderNoCache); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapEncoder_CreateNewFrame(wic_encoder, &wic_frame, &encoder_options); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameEncode_Initialize(wic_frame, encoder_options); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameEncode_SetSize(wic_frame, pixels->size.width, pixels->size.height); + if (FAILED(hr)) + goto exit; + + if (pixels->palette) + { + WICColor tmp_palette[256]; + unsigned int i; + + hr = IWICImagingFactory_CreatePalette(wic_factory, &wic_palette); + if (FAILED(hr)) + goto exit; + + for (i = 0; i < ARRAY_SIZE(tmp_palette); ++i) + { + const PALETTEENTRY *pe = &pixels->palette[i]; + + tmp_palette[i] = (pe->peFlags << 24) | (pe->peRed << 16) | (pe->peGreen << 8) | (pe->peBlue); + } + + hr = IWICPalette_InitializeCustom(wic_palette, tmp_palette, ARRAY_SIZE(tmp_palette)); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameEncode_SetPalette(wic_frame, wic_palette); + if (FAILED(hr)) + goto exit; + } + + /* + * Encode 32bpp BGRA format surfaces as 32bpp BGRX for BMP. + * This matches the behavior of native. + */ + if (IsEqualGUID(&GUID_ContainerFormatBmp, container_format) && (fmt_desc->format == D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM)) + pixel_format_guid = wic_guid_from_d3dx_pixel_format_id(D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM); + + memcpy(&wic_pixel_format, pixel_format_guid, sizeof(*pixel_format_guid)); + hr = IWICBitmapFrameEncode_SetPixelFormat(wic_frame, &wic_pixel_format); + if (FAILED(hr)) + goto exit; + + if (!IsEqualGUID(pixel_format_guid, &wic_pixel_format)) + { + ERR("SetPixelFormat returned a different pixel format.\n"); + hr = E_FAIL; + goto exit; + } + + hr = IWICBitmapFrameEncode_WritePixels(wic_frame, pixels->size.height, pixels->row_pitch, pixels->slice_pitch, + (BYTE *)pixels->data); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameEncode_Commit(wic_frame); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapEncoder_Commit(wic_encoder); + if (FAILED(hr)) + goto exit; + + hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); + if (FAILED(hr)) + goto exit; + + hr = IStream_Stat(stream, &stream_stats, STATFLAG_NONAME); + if (FAILED(hr)) + goto exit; + + if (!stream_stats.cbSize.u.HighPart) + { + *wic_file = stream; + *wic_file_size = stream_stats.cbSize.u.LowPart; + } + else + { + hr = D3DX_ERROR_INVALID_DATA; + } + +exit: + if (wic_factory) + IWICImagingFactory_Release(wic_factory); + if (stream && (*wic_file != stream)) + IStream_Release(stream); + if (wic_frame) + IWICBitmapFrameEncode_Release(wic_frame); + if (wic_palette) + IWICPalette_Release(wic_palette); + if (encoder_options) + IPropertyBag2_Release(encoder_options); + if (wic_encoder) + IWICBitmapEncoder_Release(wic_encoder); + + return hr; +} + +HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, + enum d3dx_image_file_format file_format, enum d3dx_pixel_format_id dst_format, ID3DXBlob **dst_blob) +{ + const struct pixel_format_desc *dst_fmt_desc = get_d3dx_pixel_format_info(dst_format); + uint32_t dst_row_pitch, dst_slice_pitch; + struct d3dx_pixels dst_pixels; + uint8_t *pixels, *tmp_buf; + ID3DXBlob *blob; + HRESULT hr; + + *dst_blob = blob = NULL; + pixels = tmp_buf = NULL; + hr = d3dx_calculate_pixels_size(dst_format, src_pixels->size.width, src_pixels->size.height, &dst_row_pitch, + &dst_slice_pitch); + if (FAILED(hr)) + return hr; + + src_pixels->size.depth = (file_format == D3DX_IMAGE_FILE_FORMAT_DDS) ? src_pixels->size.depth : 1; + switch (file_format) + { + case D3DX_IMAGE_FILE_FORMAT_DDS: + { + struct dds_header *header; + uint32_t header_size; + + header_size = is_index_format(dst_fmt_desc) ? sizeof(*header) + DDS_PALETTE_SIZE : sizeof(*header); + hr = d3dx_create_blob((dst_slice_pitch * src_pixels->size.depth) + header_size, &blob); + if (FAILED(hr)) + return hr; + + header = d3dx_blob_get_buffer_pointer(blob); + pixels = (uint8_t *)d3dx_blob_get_buffer_pointer(blob) + header_size; + hr = d3dx_init_dds_header(header, D3DX_RESOURCE_TYPE_TEXTURE_2D, dst_format, &src_pixels->size, 1, 1, FALSE); + if (FAILED(hr)) + goto exit; + if (is_index_format(dst_fmt_desc)) + memcpy((uint8_t *)d3dx_blob_get_buffer_pointer(blob) + sizeof(*header), src_pixels->palette, + DDS_PALETTE_SIZE); + break; + } + + case D3DX_IMAGE_FILE_FORMAT_TGA: + { + struct tga_header *header; + + hr = d3dx_create_blob(dst_slice_pitch + sizeof(*header), &blob); + if (FAILED(hr)) + return hr; + + header = d3dx_blob_get_buffer_pointer(blob); + pixels = (uint8_t *)d3dx_blob_get_buffer_pointer(blob) + sizeof(*header); + + memset(header, 0, sizeof(*header)); + header->image_type = IMAGETYPE_TRUECOLOR; + header->width = src_pixels->size.width; + header->height = src_pixels->size.height; + header->image_descriptor = IMAGE_TOPTOBOTTOM; + header->depth = dst_fmt_desc->bytes_per_pixel * 8; + if (dst_fmt_desc->format == D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) + header->image_descriptor |= 0x08; + break; + } + + case D3DX_IMAGE_FILE_FORMAT_TIFF: + case D3DX_IMAGE_FILE_FORMAT_DIB: + case D3DX_IMAGE_FILE_FORMAT_BMP: + case D3DX_IMAGE_FILE_FORMAT_PNG: + case D3DX_IMAGE_FILE_FORMAT_JPG: + if (src_fmt_desc == dst_fmt_desc) + dst_pixels = *src_pixels; + else + pixels = tmp_buf = malloc(dst_slice_pitch); + break; + + default: + break; + } + + if (src_pixels->size.width != 0 && src_pixels->size.height != 0) + { + const RECT dst_rect = { 0, 0, src_pixels->size.width, src_pixels->size.height }; + + if (pixels) + { + set_d3dx_pixels(&dst_pixels, pixels, dst_row_pitch, dst_slice_pitch, src_pixels->palette, src_pixels->size.width, + src_pixels->size.height, src_pixels->size.depth, &dst_rect); + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_fmt_desc, src_pixels, src_fmt_desc, D3DX_FILTER_NONE, 0); + if (FAILED(hr)) + goto exit; + } + + /* WIC path, encode the image. */ + if (!blob) + { + IStream *wic_file = NULL; + uint32_t buf_size = 0; + + hr = d3dx_pixels_save_wic(&dst_pixels, dst_fmt_desc, file_format, &wic_file, &buf_size); + if (FAILED(hr)) + goto exit; + + hr = d3dx_create_blob(buf_size, &blob); + if (FAILED(hr)) + { + IStream_Release(wic_file); + goto exit; + } + + hr = IStream_Read(wic_file, d3dx_blob_get_buffer_pointer(blob), buf_size, NULL); + IStream_Release(wic_file); + if (FAILED(hr)) + goto exit; + } + } + /* Return an empty buffer for size 0 images via WIC. */ + else if (!blob) + { + hr = d3dx_create_blob(64, &blob); + if (FAILED(hr)) + goto exit; + } + + *dst_blob = blob; +exit: + free(tmp_buf); + if (*dst_blob != blob) + d3dx_blob_release(blob); + return hr; +} + +static const uint8_t bmp_file_signature[] = { 'B', 'M' }; +static const uint8_t jpg_file_signature[] = { 0xff, 0xd8 }; +static const uint8_t png_file_signature[] = { 0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a }; +static const uint8_t dds_file_signature[] = { 'D', 'D', 'S', ' ' }; +static const uint8_t ppm_plain_file_signature[] = { 'P', '3' }; +static const uint8_t ppm_raw_file_signature[] = { 'P', '6' }; +static const uint8_t hdr_file_signature[] = { '#', '?', 'R', 'A', 'D', 'I', 'A', 'N', 'C', 'E', '\n' }; +static const uint8_t pfm_color_file_signature[] = { 'P', 'F' }; +static const uint8_t pfm_gray_file_signature[] = { 'P', 'f' }; +static const uint8_t tiff_le_file_signature[] = { 'I', 'I', 0x2a, 0x00 }; +static const uint8_t tiff_be_file_signature[] = { 'M', 'M', 0x00, 0x2a }; +static const uint8_t gif_87a_file_signature[] = { 'G', 'I', 'F', '8', '7', 'a' }; +static const uint8_t gif_89a_file_signature[] = { 'G', 'I', 'F', '8', '9', 'a' }; +static const uint8_t wmp_v0_file_signature[] = { 'I', 'I', 0xbc, 0x00 }; +static const uint8_t wmp_v1_file_signature[] = { 'I', 'I', 0xbc, 0x01 }; + +/* + * If none of these match, the file is either DIB, TGA, or something we don't + * support. + */ +struct d3dx_file_format_signature +{ + const uint8_t *file_signature; + uint32_t file_signature_len; + enum d3dx_image_file_format image_file_format; +}; + +static const struct d3dx_file_format_signature file_format_signatures[] = +{ + { bmp_file_signature, sizeof(bmp_file_signature), D3DX_IMAGE_FILE_FORMAT_BMP }, + { jpg_file_signature, sizeof(jpg_file_signature), D3DX_IMAGE_FILE_FORMAT_JPG }, + { png_file_signature, sizeof(png_file_signature), D3DX_IMAGE_FILE_FORMAT_PNG }, + { dds_file_signature, sizeof(dds_file_signature), D3DX_IMAGE_FILE_FORMAT_DDS }, + { ppm_plain_file_signature, sizeof(ppm_plain_file_signature), D3DX_IMAGE_FILE_FORMAT_PPM }, + { ppm_raw_file_signature, sizeof(ppm_raw_file_signature), D3DX_IMAGE_FILE_FORMAT_PPM }, + { hdr_file_signature, sizeof(hdr_file_signature), D3DX_IMAGE_FILE_FORMAT_HDR }, + { pfm_color_file_signature, sizeof(pfm_color_file_signature), D3DX_IMAGE_FILE_FORMAT_PFM }, + { pfm_gray_file_signature, sizeof(pfm_gray_file_signature), D3DX_IMAGE_FILE_FORMAT_PFM }, + { tiff_le_file_signature, sizeof(tiff_le_file_signature), D3DX_IMAGE_FILE_FORMAT_TIFF }, + { tiff_be_file_signature, sizeof(tiff_be_file_signature), D3DX_IMAGE_FILE_FORMAT_TIFF }, + { gif_87a_file_signature, sizeof(gif_87a_file_signature), D3DX_IMAGE_FILE_FORMAT_GIF }, + { gif_89a_file_signature, sizeof(gif_89a_file_signature), D3DX_IMAGE_FILE_FORMAT_GIF }, + { wmp_v0_file_signature, sizeof(wmp_v0_file_signature), D3DX_IMAGE_FILE_FORMAT_WMP }, + { wmp_v1_file_signature, sizeof(wmp_v1_file_signature), D3DX_IMAGE_FILE_FORMAT_WMP }, +}; + +static BOOL d3dx_get_image_file_format_from_file_signature(const void *src_data, uint32_t src_data_size, + enum d3dx_image_file_format *out_iff) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(file_format_signatures); ++i) + { + const struct d3dx_file_format_signature *signature = &file_format_signatures[i]; + + if ((src_data_size >= signature->file_signature_len) + && !memcmp(src_data, signature->file_signature, signature->file_signature_len)) + { + *out_iff = signature->image_file_format; + return TRUE; + } + } + + return FALSE; +} + +static enum d3dx_resource_type dxt10_resource_dimension_to_d3dx_resource_type(uint32_t resource_dimension) +{ + switch (resource_dimension) + { + case DDS_RESOURCE_DIMENSION_TEXTURE1D: return D3DX_RESOURCE_TYPE_TEXTURE_1D; + case DDS_RESOURCE_DIMENSION_TEXTURE2D: return D3DX_RESOURCE_TYPE_TEXTURE_2D; + case DDS_RESOURCE_DIMENSION_TEXTURE3D: return D3DX_RESOURCE_TYPE_TEXTURE_3D; + + default: + break; + } + + FIXME("Unhandled DXT10 resource dimension value %u.\n", resource_dimension); + return D3DX_RESOURCE_TYPE_UNKNOWN; +} + +static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src_data_size, + struct d3dx_image *image, uint32_t starting_mip_level, uint32_t flags) +{ + uint32_t expected_src_data_size, header_size; + const struct dds_header *header = src_data; + BOOL is_indexed_fmt; + HRESULT hr; + + if (src_data_size < sizeof(*header) || header->pixel_format.size != sizeof(header->pixel_format)) + return D3DX_ERROR_INVALID_DATA; + + is_indexed_fmt = !!(header->pixel_format.flags & DDS_PF_INDEXED); + header_size = is_indexed_fmt ? sizeof(*header) + DDS_PALETTE_SIZE : sizeof(*header); + + set_volume_struct(&image->size, header->width, header->height, 1); + image->mip_levels = header->miplevels ? header->miplevels : 1; + if (has_extended_header(header) && (flags & D3DX_IMAGE_SUPPORT_DXT10)) + { + const struct dds_header_dxt10 *dxt10 = (const struct dds_header_dxt10 *)((uint8_t *)src_data + header_size); + + header_size += sizeof(*dxt10); + if (src_data_size < header_size) + return D3DX_ERROR_INVALID_DATA; + + TRACE("File type is DXT10 DDS.\n"); + if ((image->format = d3dx_pixel_format_id_from_dxgi_format(dxt10->dxgi_format)) == D3DX_PIXEL_FORMAT_COUNT) + return D3DX_ERROR_INVALID_DATA; + + if (dxt10->misc_flags2) + { + ERR("Invalid misc_flags2 field %#x.\n", dxt10->misc_flags2); + return D3DX_ERROR_INVALID_DATA; + } + + image->image_file_format = D3DX_IMAGE_FILE_FORMAT_DDS_DXT10; + image->size.depth = (header->flags & DDS_DEPTH) ? max(header->depth, 1) : 1; + image->layer_count = max(1, dxt10->array_size); + image->resource_type = dxt10_resource_dimension_to_d3dx_resource_type(dxt10->resource_dimension); + if (dxt10->misc_flags & DDS_RESOURCE_MISC_TEXTURECUBE) + { + if (image->resource_type != D3DX_RESOURCE_TYPE_TEXTURE_2D) + return D3DX_ERROR_INVALID_DATA; + image->resource_type = D3DX_RESOURCE_TYPE_CUBE_TEXTURE; + image->layer_count *= 6; + } + } + else + { + TRACE("File type is DDS.\n"); + + if ((image->format = d3dx_pixel_format_id_from_dds_pixel_format(&header->pixel_format)) == D3DX_PIXEL_FORMAT_COUNT) + return D3DX_ERROR_INVALID_DATA; + + image->image_file_format = D3DX_IMAGE_FILE_FORMAT_DDS; + image->layer_count = 1; + if (header->flags & DDS_DEPTH) + { + image->size.depth = max(header->depth, 1); + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_3D; + } + else if (header->caps2 & DDS_CAPS2_CUBEMAP) + { + if ((header->caps2 & DDS_CAPS2_CUBEMAP_ALL_FACES) != DDS_CAPS2_CUBEMAP_ALL_FACES) + { + WARN("Tried to load a partial cubemap DDS file.\n"); + return D3DX_ERROR_INVALID_DATA; + } + + image->layer_count = 6; + image->resource_type = D3DX_RESOURCE_TYPE_CUBE_TEXTURE; + } + else + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; + } + + TRACE("Pixel format is %#x.\n", image->format); + image->layer_pitch = d3dx_calculate_layer_pixels_size(image->format, image->size.width, image->size.height, + image->size.depth, image->mip_levels); + if (!image->layer_pitch) + return D3DX_ERROR_INVALID_DATA; + expected_src_data_size = (image->layer_pitch * image->layer_count) + header_size; + if (src_data_size < expected_src_data_size) + { + WARN("File is too short %u, expected at least %u bytes.\n", src_data_size, expected_src_data_size); + /* d3dx10/d3dx11 do not validate the size of the pixels. */ + if (!(flags & D3DX_IMAGE_SUPPORT_DXT10)) + return D3DX_ERROR_INVALID_DATA; + } + + image->palette = (is_indexed_fmt) ? (PALETTEENTRY *)(((uint8_t *)src_data) + sizeof(*header)) : NULL; + image->pixels = ((BYTE *)src_data) + header_size; + if (starting_mip_level && (image->mip_levels > 1)) + { + uint32_t i, row_pitch, slice_pitch, initial_mip_levels; + const struct volume initial_size = image->size; + + initial_mip_levels = image->mip_levels; + for (i = 0; i < starting_mip_level; i++) + { + hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + return hr; + + image->pixels += slice_pitch * image->size.depth; + d3dx_get_next_mip_level_size(&image->size); + if (--image->mip_levels == 1) + break; + } + + TRACE("Requested starting mip level %u, actual starting mip level is %u (of %u total in image).\n", + starting_mip_level, (initial_mip_levels - image->mip_levels), initial_mip_levels); + TRACE("Original dimensions %s, new dimensions %s.\n", debug_volume(&initial_size), debug_volume(&image->size)); + } + + return S_OK; +} + +static BOOL convert_dib_to_bmp(const void **data, unsigned int *size) +{ + ULONG header_size; + ULONG count = 0; + ULONG offset; + BITMAPFILEHEADER *header; + BYTE *new_data; + UINT new_size; + + if ((*size < 4) || (*size < (header_size = *(ULONG*)*data))) + return FALSE; + + if ((header_size == sizeof(BITMAPINFOHEADER)) || + (header_size == sizeof(BITMAPV4HEADER)) || + (header_size == sizeof(BITMAPV5HEADER)) || + (header_size == 64 /* sizeof(BITMAPCOREHEADER2) */)) + { + /* All structures begin with the same memory layout as BITMAPINFOHEADER */ + BITMAPINFOHEADER *info_header = (BITMAPINFOHEADER*)*data; + count = info_header->biClrUsed; + + if (!count && info_header->biBitCount <= 8) + count = 1 << info_header->biBitCount; + + offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBQUAD) * count; + + /* For BITMAPINFOHEADER with BI_BITFIELDS compression, there are 3 additional color masks after header */ + if ((info_header->biSize == sizeof(BITMAPINFOHEADER)) && (info_header->biCompression == BI_BITFIELDS)) + offset += 3 * sizeof(DWORD); + } + else if (header_size == sizeof(BITMAPCOREHEADER)) + { + BITMAPCOREHEADER *core_header = (BITMAPCOREHEADER*)*data; + + if (core_header->bcBitCount <= 8) + count = 1 << core_header->bcBitCount; + + offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBTRIPLE) * count; + } + else + { + return FALSE; + } + + TRACE("Converting DIB file to BMP\n"); + + new_size = *size + sizeof(BITMAPFILEHEADER); + new_data = malloc(new_size); + CopyMemory(new_data + sizeof(BITMAPFILEHEADER), *data, *size); + + /* Add BMP header */ + header = (BITMAPFILEHEADER*)new_data; + header->bfType = 0x4d42; /* BM */ + header->bfSize = new_size; + header->bfReserved1 = 0; + header->bfReserved2 = 0; + header->bfOffBits = offset; + + /* Update input data */ + *data = new_data; + *size = new_size; + + return TRUE; +} + +/* windowscodecs always returns xRGB, but we should return ARGB if and only if + * at least one pixel has a non-zero alpha component. */ +static BOOL image_is_argb(IWICBitmapFrameDecode *frame, struct d3dx_image *image) +{ + unsigned int size, i; + BYTE *buffer; + HRESULT hr; + + if (image->format != D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM || image->image_file_format != D3DX_IMAGE_FILE_FORMAT_BMP) + return FALSE; + + size = image->size.width * image->size.height * 4; + if (!(buffer = malloc(size))) + return FALSE; + + if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, image->size.width * 4, size, buffer))) + { + ERR("Failed to copy pixels, hr %#lx.\n", hr); + free(buffer); + return FALSE; + } + + for (i = 0; i < image->size.width * image->size.height; ++i) + { + if (buffer[i * 4 + 3]) + { + free(buffer); + return TRUE; + } + } + + free(buffer); + return FALSE; +} + +const char *debug_d3dx_image_file_format(enum d3dx_image_file_format format) +{ + switch (format) + { +#define FMT_TO_STR(format) case format: return #format + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_BMP); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_JPG); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_TGA); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PNG); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_DDS); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PPM); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_DIB); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_HDR); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PFM); +#undef FMT_TO_STR + default: + return "unrecognized"; + } +} + +static HRESULT d3dx_image_wic_frame_decode(struct d3dx_image *image, + IWICImagingFactory *wic_factory, IWICBitmapFrameDecode *bitmap_frame) +{ + const struct pixel_format_desc *fmt_desc; + uint32_t row_pitch, slice_pitch; + IWICPalette *wic_palette = NULL; + PALETTEENTRY *palette = NULL; + WICColor *colors = NULL; + BYTE *buffer = NULL; + HRESULT hr; + + fmt_desc = get_d3dx_pixel_format_info(image->format); + hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + return hr; + + /* Allocate a buffer for our image. */ + if (!(buffer = malloc(slice_pitch))) + return E_OUTOFMEMORY; + + hr = IWICBitmapFrameDecode_CopyPixels(bitmap_frame, NULL, row_pitch, slice_pitch, buffer); + if (FAILED(hr)) + { + free(buffer); + return hr; + } + + if (is_index_format(fmt_desc)) + { + uint32_t nb_colors, i; + + hr = IWICImagingFactory_CreatePalette(wic_factory, &wic_palette); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameDecode_CopyPalette(bitmap_frame, wic_palette); + if (FAILED(hr)) + goto exit; + + hr = IWICPalette_GetColorCount(wic_palette, &nb_colors); + if (FAILED(hr)) + goto exit; + + colors = malloc(nb_colors * sizeof(colors[0])); + palette = malloc(nb_colors * sizeof(palette[0])); + if (!colors || !palette) + { + hr = E_OUTOFMEMORY; + goto exit; + } + + hr = IWICPalette_GetColors(wic_palette, nb_colors, colors, &nb_colors); + if (FAILED(hr)) + goto exit; + + /* Convert colors from WICColor (ARGB) to PALETTEENTRY (ABGR) */ + for (i = 0; i < nb_colors; i++) + { + palette[i].peRed = (colors[i] >> 16) & 0xff; + palette[i].peGreen = (colors[i] >> 8) & 0xff; + palette[i].peBlue = colors[i] & 0xff; + palette[i].peFlags = (colors[i] >> 24) & 0xff; /* peFlags is the alpha component in DX8 and higher */ + } + } + + image->image_buf = image->pixels = buffer; + image->image_palette = image->palette = palette; + +exit: + free(colors); + if (image->image_buf != buffer) + free(buffer); + if (image->image_palette != palette) + free(palette); + if (wic_palette) + IWICPalette_Release(wic_palette); + + return hr; +} + +static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src_data_size, + struct d3dx_image *image, enum d3dx_image_file_format d3dx_file_format, uint32_t flags) +{ + const GUID *container_format_guid = wic_container_guid_from_d3dx_file_format(d3dx_file_format); + IWICBitmapFrameDecode *bitmap_frame = NULL; + IWICBitmapDecoder *bitmap_decoder = NULL; + IWICImagingFactory *wic_factory; + WICPixelFormatGUID pixel_format; + IWICStream *wic_stream = NULL; + uint32_t frame_count = 0; + HRESULT hr; + + hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &wic_factory); + if (FAILED(hr)) + return hr; + + hr = IWICImagingFactory_CreateDecoder(wic_factory, container_format_guid, NULL, &bitmap_decoder); + if (FAILED(hr)) + goto exit; + + hr = IWICImagingFactory_CreateStream(wic_factory, &wic_stream); + if (FAILED(hr)) + goto exit; + + hr = IWICStream_InitializeFromMemory(wic_stream, (BYTE *)src_data, src_data_size); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapDecoder_Initialize(bitmap_decoder, (IStream *)wic_stream, 0); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapDecoder_GetFrameCount(bitmap_decoder, &frame_count); + if (FAILED(hr) || (SUCCEEDED(hr) && !frame_count)) + { + hr = D3DX_ERROR_INVALID_DATA; + goto exit; + } + + image->image_file_format = d3dx_file_format; + hr = IWICBitmapDecoder_GetFrame(bitmap_decoder, 0, &bitmap_frame); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameDecode_GetSize(bitmap_frame, &image->size.width, &image->size.height); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameDecode_GetPixelFormat(bitmap_frame, &pixel_format); + if (FAILED(hr)) + goto exit; + + image->format = d3dx_pixel_format_id_from_wic_pixel_format(&pixel_format); + if (image->format == D3DX_PIXEL_FORMAT_COUNT) + { + WARN("Unsupported pixel format %s.\n", debugstr_guid(&pixel_format)); + hr = D3DX_ERROR_INVALID_DATA; + goto exit; + } + + /* D3DX10/D3DX11 ignore alpha channels in bitmaps. */ + if (!(flags & D3DX_IMAGE_SUPPORT_DXT10) && image_is_argb(bitmap_frame, image)) + image->format = D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; + + if (!(flags & D3DX_IMAGE_INFO_ONLY)) + { + hr = d3dx_image_wic_frame_decode(image, wic_factory, bitmap_frame); + if (FAILED(hr)) + goto exit; + } + + image->size.depth = 1; + image->mip_levels = 1; + image->layer_count = 1; + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; + +exit: + if (bitmap_frame) + IWICBitmapFrameDecode_Release(bitmap_frame); + if (bitmap_decoder) + IWICBitmapDecoder_Release(bitmap_decoder); + if (wic_stream) + IWICStream_Release(wic_stream); + IWICImagingFactory_Release(wic_factory); + + return hr; +} + +static enum d3dx_pixel_format_id d3dx_get_tga_format_for_bpp(uint8_t bpp) +{ + switch (bpp) + { + case 15: return D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM; + case 16: return D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM; + case 24: return D3DX_PIXEL_FORMAT_B8G8R8_UNORM; + case 32: return D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; + default: + WARN("Unhandled bpp %u for targa.\n", bpp); + return D3DX_PIXEL_FORMAT_COUNT; + } +} + +static HRESULT d3dx_image_tga_rle_decode_row(const uint8_t **src, uint32_t src_bytes_left, uint32_t row_width, + uint32_t bytes_per_pixel, uint8_t *dst_row) +{ + const uint8_t *src_ptr = *src; + uint32_t pixel_count = 0; + + while (pixel_count != row_width) + { + uint32_t rle_count = (src_ptr[0] & 0x7f) + 1; + uint32_t rle_packet_size = 1; + + rle_packet_size += (src_ptr[0] & 0x80) ? bytes_per_pixel : (bytes_per_pixel * rle_count); + if ((rle_packet_size > src_bytes_left) || (pixel_count + rle_count) > row_width) + return D3DX_ERROR_INVALID_DATA; + + if (src_ptr[0] & 0x80) + { + uint32_t i; + + for (i = 0; i < rle_count; ++i) + memcpy(&dst_row[(pixel_count + i) * bytes_per_pixel], src_ptr + 1, bytes_per_pixel); + } + else + { + memcpy(&dst_row[pixel_count * bytes_per_pixel], src_ptr + 1, rle_packet_size - 1); + } + + src_ptr += rle_packet_size; + src_bytes_left -= rle_packet_size; + pixel_count += rle_count; + if (!src_bytes_left && pixel_count != row_width) + return D3DX_ERROR_INVALID_DATA; + } + + *src = src_ptr; + return S_OK; +} + +static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, + const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, + const struct volume *dst_size, const struct pixel_format_desc *dst_format, DWORD color_key, + const PALETTEENTRY *palette, uint32_t filter_flags); +static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_size, uint32_t src_header_size, + struct d3dx_image *image) +{ + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(image->format); + const struct tga_header *header = (const struct tga_header *)src_data; + const BOOL right_to_left = !!(header->image_descriptor & IMAGE_RIGHTTOLEFT); + const BOOL bottom_to_top = !(header->image_descriptor & IMAGE_TOPTOBOTTOM); + const BOOL is_rle = !!(header->image_type & IMAGETYPE_RLE); + uint8_t *img_buf = NULL, *src_row = NULL; + uint32_t row_pitch, slice_pitch, i; + PALETTEENTRY *palette = NULL; + const uint8_t *src_pos; + HRESULT hr; + + hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + return hr; + + /* File is too small. */ + if (!is_rle && (src_header_size + slice_pitch) > src_data_size) + return D3DX_ERROR_INVALID_DATA; + + if (image->format == D3DX_PIXEL_FORMAT_P8_UINT) + { + const uint8_t *src_palette = ((const uint8_t *)src_data) + sizeof(*header) + header->id_length; + const struct volume image_map_size = { header->color_map_length, 1, 1 }; + uint32_t src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch; + const struct pixel_format_desc *src_desc, *dst_desc; + + if (!(palette = malloc(sizeof(*palette) * 256))) + return E_OUTOFMEMORY; + + /* + * Convert from a TGA colormap to PALETTEENTRY. TGA is BGRA, + * PALETTEENTRY is RGBA. + */ + src_desc = get_d3dx_pixel_format_info(d3dx_get_tga_format_for_bpp(header->color_map_entrysize)); + hr = d3dx_calculate_pixels_size(src_desc->format, header->color_map_length, 1, &src_row_pitch, &src_slice_pitch); + if (FAILED(hr)) + goto exit; + + dst_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + d3dx_calculate_pixels_size(dst_desc->format, 256, 1, &dst_row_pitch, &dst_slice_pitch); + convert_argb_pixels(src_palette, src_row_pitch, src_slice_pitch, &image_map_size, src_desc, (BYTE *)palette, + dst_row_pitch, dst_slice_pitch, &image_map_size, dst_desc, 0, NULL, D3DX_FILTER_NONE); + + /* Initialize unused palette entries to 0xff. */ + if (header->color_map_length < 256) + memset(&palette[header->color_map_length], 0xff, sizeof(*palette) * (256 - header->color_map_length)); + } + + if (!is_rle && !bottom_to_top && !right_to_left) + { + image->pixels = (uint8_t *)src_data + src_header_size; + image->image_palette = image->palette = palette; + return S_OK; + } + + if (!(img_buf = malloc(slice_pitch))) + { + hr = E_OUTOFMEMORY; + goto exit; + } + + /* Allocate an extra row to use as a temporary buffer. */ + if (is_rle) + { + if (!(src_row = malloc(row_pitch))) + { + hr = E_OUTOFMEMORY; + goto exit; + } + } + + src_pos = (const uint8_t *)src_data + src_header_size; + for (i = 0; i < image->size.height; ++i) + { + const uint32_t dst_row_idx = bottom_to_top ? (image->size.height - i - 1) : i; + uint8_t *dst_row = img_buf + (dst_row_idx * row_pitch); + + if (is_rle) + { + hr = d3dx_image_tga_rle_decode_row(&src_pos, src_data_size - (src_pos - (const uint8_t *)src_data), + image->size.width, fmt_desc->bytes_per_pixel, src_row); + if (FAILED(hr)) + goto exit; + } + else + { + src_row = (uint8_t *)src_pos; + src_pos += row_pitch; + } + + if (right_to_left) + { + const uint8_t *src_pixel = &src_row[((image->size.width - 1)) * fmt_desc->bytes_per_pixel]; + uint8_t *dst_pixel = dst_row; + uint32_t j; + + for (j = 0; j < image->size.width; ++j) + { + memcpy(dst_pixel, src_pixel, fmt_desc->bytes_per_pixel); + src_pixel -= fmt_desc->bytes_per_pixel; + dst_pixel += fmt_desc->bytes_per_pixel; + } + } + else + { + memcpy(dst_row, src_row, row_pitch); + } + } + + image->image_buf = image->pixels = img_buf; + image->image_palette = image->palette = palette; + +exit: + if (is_rle) + free(src_row); + if (img_buf && (image->image_buf != img_buf)) + free(img_buf); + if (palette && (image->image_palette != palette)) + free(palette); + + return hr; +} + +static HRESULT d3dx_initialize_image_from_tga(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, + uint32_t flags) +{ + const struct tga_header *header = (const struct tga_header *)src_data; + uint32_t expected_header_size = sizeof(*header); + + if (src_data_size < sizeof(*header)) + return D3DX_ERROR_INVALID_DATA; + + expected_header_size += header->id_length; + expected_header_size += header->color_map_length * ((header->color_map_entrysize + 7) / CHAR_BIT); + if (src_data_size < expected_header_size) + return D3DX_ERROR_INVALID_DATA; + + if (header->color_map_type && ((header->color_map_type > 1) || (!header->color_map_length) + || (d3dx_get_tga_format_for_bpp(header->color_map_entrysize) == D3DX_PIXEL_FORMAT_COUNT))) + return D3DX_ERROR_INVALID_DATA; + + switch (header->image_type & IMAGETYPE_MASK) + { + case IMAGETYPE_COLORMAPPED: + if (header->depth != 8 || !header->color_map_type) + return D3DX_ERROR_INVALID_DATA; + image->format = D3DX_PIXEL_FORMAT_P8_UINT; + break; + + case IMAGETYPE_TRUECOLOR: + if ((image->format = d3dx_get_tga_format_for_bpp(header->depth)) == D3DX_PIXEL_FORMAT_COUNT) + return D3DX_ERROR_INVALID_DATA; + break; + + case IMAGETYPE_GRAYSCALE: + if (header->depth != 8) + return D3DX_ERROR_INVALID_DATA; + image->format = D3DX_PIXEL_FORMAT_L8_UNORM; + break; + + default: + return D3DX_ERROR_INVALID_DATA; + } + + set_volume_struct(&image->size, header->width, header->height, 1); + image->mip_levels = 1; + image->layer_count = 1; + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; + image->image_file_format = D3DX_IMAGE_FILE_FORMAT_TGA; + + if (!(flags & D3DX_IMAGE_INFO_ONLY)) + return d3dx_image_tga_decode(src_data, src_data_size, expected_header_size, image); + + return S_OK; +} + +HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, + uint32_t starting_mip_level, uint32_t flags) +{ + enum d3dx_image_file_format iff = D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD; + const BOOL is_d3dx9 = !(flags & D3DX_IMAGE_SUPPORT_DXT10); + HRESULT hr; + + if (!src_data || !src_data_size || !image) + return D3DERR_INVALIDCALL; + + memset(image, 0, sizeof(*image)); + if (!d3dx_get_image_file_format_from_file_signature(src_data, src_data_size, &iff)) + { + uint32_t src_image_size = src_data_size; + const void *src_image = src_data; + + /* + * All file formats supported by d3dx10/d3dx11 are detectable by + * file signature. + */ + if (!is_d3dx9) + return E_FAIL; + + if (convert_dib_to_bmp(&src_image, &src_image_size)) + { + hr = d3dx_image_init(src_image, src_image_size, image, starting_mip_level, flags); + free((void *)src_image); + if (SUCCEEDED(hr)) + image->image_file_format = D3DX_IMAGE_FILE_FORMAT_DIB; + return hr; + } + + /* Last resort, try TGA. */ + return d3dx_initialize_image_from_tga(src_data, src_data_size, image, flags); + } + + switch (iff) + { + case D3DX_IMAGE_FILE_FORMAT_BMP: + case D3DX_IMAGE_FILE_FORMAT_JPG: + case D3DX_IMAGE_FILE_FORMAT_PNG: + hr = d3dx_initialize_image_from_wic(src_data, src_data_size, image, iff, flags); + break; + + case D3DX_IMAGE_FILE_FORMAT_TIFF: + case D3DX_IMAGE_FILE_FORMAT_GIF: + case D3DX_IMAGE_FILE_FORMAT_WMP: + if (is_d3dx9) + { + WARN("Tried to load file format %s on d3dx9.\n", debug_d3dx_image_file_format(iff)); + hr = D3DX_ERROR_INVALID_DATA; + } + else + { + hr = d3dx_initialize_image_from_wic(src_data, src_data_size, image, iff, flags); + } + break; + + case D3DX_IMAGE_FILE_FORMAT_DDS: + hr = d3dx_initialize_image_from_dds(src_data, src_data_size, image, starting_mip_level, flags); + break; + + case D3DX_IMAGE_FILE_FORMAT_PPM: + case D3DX_IMAGE_FILE_FORMAT_HDR: + case D3DX_IMAGE_FILE_FORMAT_PFM: + if (is_d3dx9) + { + FIXME("Support for file format %s is currently unimplemented.\n", debug_d3dx_image_file_format(iff)); + hr = E_NOTIMPL; + } + else + { + WARN("Tried to load file format %s on d3dx%d.\n", debug_d3dx_image_file_format(iff), D3DX_D3D_VERSION); + hr = E_FAIL; + } + break; + + case D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD: + ERR("Unrecognized file format.\n"); + hr = D3DX_ERROR_INVALID_DATA; + break; + + default: + assert(0); + return E_FAIL; + } + + return hr; +} + +void d3dx_image_cleanup(struct d3dx_image *image) +{ + free(image->image_buf); + free(image->image_palette); +} + +HRESULT d3dx_image_get_pixels(struct d3dx_image *image, uint32_t layer, uint32_t mip_level, + struct d3dx_pixels *pixels) +{ + struct volume mip_level_size = image->size; + const BYTE *pixels_ptr = image->pixels; + uint32_t row_pitch, slice_pitch, i; + RECT unaligned_rect; + HRESULT hr = S_OK; + + if (mip_level >= image->mip_levels) + { + ERR("Tried to retrieve mip level %u, but image only has %u mip levels.\n", mip_level, image->mip_levels); + return E_FAIL; + } + + if (layer >= image->layer_count) + { + ERR("Tried to retrieve layer %u, but image only has %u layers.\n", layer, image->layer_count); + return E_FAIL; + } + + slice_pitch = row_pitch = 0; + for (i = 0; i < image->mip_levels; i++) + { + hr = d3dx_calculate_pixels_size(image->format, mip_level_size.width, mip_level_size.height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + return hr; + + if (i == mip_level) + break; + + pixels_ptr += slice_pitch * mip_level_size.depth; + d3dx_get_next_mip_level_size(&mip_level_size); + } + + pixels_ptr += (layer * image->layer_pitch); + SetRect(&unaligned_rect, 0, 0, mip_level_size.width, mip_level_size.height); + set_d3dx_pixels(pixels, pixels_ptr, row_pitch, slice_pitch, image->palette, mip_level_size.width, + mip_level_size.height, mip_level_size.depth, &unaligned_rect); + + return S_OK; +} + +unsigned short float_32_to_16(const float in) +{ + int exp = 0, origexp; + float tmp = fabsf(in); + int sign = (copysignf(1, in) < 0); + unsigned int mantissa; + unsigned short ret; + + /* Deal with special numbers */ + if (isinf(in)) return (sign ? 0xffff : 0x7fff); + if (isnan(in)) return (sign ? 0xffff : 0x7fff); + if (in == 0.0f) return (sign ? 0x8000 : 0x0000); + + if (tmp < (float)(1u << 10)) + { + do + { + tmp *= 2.0f; + exp--; + } while (tmp < (float)(1u << 10)); + } + else if (tmp >= (float)(1u << 11)) + { + do + { + tmp /= 2.0f; + exp++; + } while (tmp >= (float)(1u << 11)); + } + + exp += 10; /* Normalize the mantissa */ + exp += 15; /* Exponent is encoded with excess 15 */ + + origexp = exp; + + mantissa = (unsigned int) tmp; + if ((tmp - mantissa == 0.5f && mantissa % 2 == 1) || /* round half to even */ + (tmp - mantissa > 0.5f)) + { + mantissa++; /* round to nearest, away from zero */ + } + if (mantissa == 2048) + { + mantissa = 1024; + exp++; + } + + if (exp > 31) + { + /* too big */ + ret = 0x7fff; /* INF */ + } + else if (exp <= 0) + { + unsigned int rounding = 0; + + /* Denormalized half float */ + + /* return 0x0000 (=0.0) for numbers too small to represent in half floats */ + if (exp < -11) + return (sign ? 0x8000 : 0x0000); + + exp = origexp; + + /* the 13 extra bits from single precision are used for rounding */ + mantissa = (unsigned int)(tmp * (1u << 13)); + mantissa >>= 1 - exp; /* denormalize */ + + mantissa -= ~(mantissa >> 13) & 1; /* round half to even */ + /* remove 13 least significant bits to get half float precision */ + mantissa >>= 12; + rounding = mantissa & 1; + mantissa >>= 1; + + ret = mantissa + rounding; + } + else + { + ret = (exp << 10) | (mantissa & 0x3ff); + } + + ret |= ((sign ? 1 : 0) << 15); /* Add the sign */ + return ret; +} + +/* Native d3dx9's D3DXFloat16to32Array lacks support for NaN and Inf. Specifically, e = 16 is treated as a + * regular number - e.g., 0x7fff is converted to 131008.0 and 0xffff to -131008.0. */ +float float_16_to_32(const unsigned short in) +{ + const unsigned short s = (in & 0x8000); + const unsigned short e = (in & 0x7C00) >> 10; + const unsigned short m = in & 0x3FF; + const float sgn = (s ? -1.0f : 1.0f); + + if (e == 0) + { + if (m == 0) return sgn * 0.0f; /* +0.0 or -0.0 */ + else return sgn * powf(2, -14.0f) * (m / 1024.0f); + } + else + { + return sgn * powf(2, e - 15.0f) * (1.0f + (m / 1024.0f)); + } +} + +static float partial_float_to_32(const uint16_t in, const uint8_t bits) +{ + static const uint16_t exponent_mask[2] = { 0x03e0, 0x07c0 }; + static const uint16_t mantissa_mask[2] = { 0x1f, 0x3f }; + static const uint8_t exponent_shift[2] = { 5, 6 }; + const uint8_t const_idx = (bits == 10) ? 0 : 1; + const uint16_t e = (in & exponent_mask[const_idx]) >> exponent_shift[const_idx]; + const uint16_t m = in & mantissa_mask[const_idx]; + uint32_t exponent, mantissa; + uint32_t float_bits = 0; + + if (!e && !m) + return 0.0f; + + if (e == 0x1f) + return m ? NAN : INFINITY; + + mantissa = m; + exponent = e; + + /* The value is denormalized. */ + if (!exponent) + { + /* Normalize the value in the resulting float. */ + exponent = 1; + while (!(mantissa & exponent_mask[const_idx])) + { + exponent--; + mantissa <<= 1; + } + + mantissa &= mantissa_mask[const_idx]; + } + + float_bits = ((exponent + 112) << 23) | (mantissa << (23 - exponent_shift[const_idx])); + return *((float *)&float_bits); +} + +static uint16_t float_32_to_partial_float(const float in, const uint8_t bits) +{ + const uint32_t in_exponent = ((*((const uint32_t *)&in)) & 0x7f800000) >> 23; + const uint32_t in_mantissa = ((*((const uint32_t *)&in)) & 0x007fffff); + static const float largest_float[2] = { 64512.0f, 65024.0f }; + static const uint16_t partial_max_val[2] = { 0x3df, 0x7bf }; + static const uint16_t partial_inf[2] = { 0x3e0, 0x7c0 }; + static const uint16_t partial_nan[2] = { 0x3ff, 0x7ff }; + static const uint8_t mantissa_shift[2] = { 18, 17 }; + static const uint8_t exp_shift[2] = { 5, 6 }; + const uint8_t const_idx = (bits == 11); + const BOOL sign = signbit(in); + uint8_t out_exponent = 0; + uint8_t out_mantissa = 0; + uint16_t res = 0; + + if (isnan(in)) + return partial_nan[const_idx]; + else if (!sign && isinf(in)) + return partial_inf[const_idx]; + else if (sign) + return 0x000; + else if (in >= largest_float[const_idx]) + return partial_max_val[const_idx]; + + /* + * Exponent of 0x71 is 2^-14, which is the smallest exponent for float10/11. + * If the exponent of our float is smaller than this, we need to + * denormalize the float. + */ + if (in_exponent < 0x71) + { + /* The number is too small to represent, just return 0. */ + if (((0x71 - in_exponent) + mantissa_shift[const_idx]) >= 24) + return 0x000; + + out_mantissa = (((0x800000 | in_mantissa) >> (0x71 - in_exponent)) >> mantissa_shift[const_idx]); + out_exponent = 0x00; + } + else + { + out_exponent = in_exponent - 0x70; + out_mantissa = in_mantissa >> mantissa_shift[const_idx]; + } + + res = (out_exponent << exp_shift[const_idx]) | out_mantissa; + return res; +} + +struct argb_conversion_info +{ + const struct pixel_format_desc *srcformat; + const struct pixel_format_desc *destformat; + DWORD srcshift[4], destshift[4]; + DWORD srcmask[4], destmask[4]; + BOOL process_channel[4]; + DWORD channelmask; +}; + +static void init_argb_conversion_info(const struct pixel_format_desc *srcformat, const struct pixel_format_desc *destformat, struct argb_conversion_info *info) +{ + UINT i; + ZeroMemory(info->process_channel, 4 * sizeof(BOOL)); + info->channelmask = 0; + + info->srcformat = srcformat; + info->destformat = destformat; + + for(i = 0;i < 4;i++) { + /* srcshift is used to extract the _relevant_ components */ + info->srcshift[i] = srcformat->shift[i] + max( srcformat->bits[i] - destformat->bits[i], 0); + + /* destshift is used to move the components to the correct position */ + info->destshift[i] = destformat->shift[i] + max(destformat->bits[i] - srcformat->bits[i], 0); + + info->srcmask[i] = ((1 << srcformat->bits[i]) - 1) << srcformat->shift[i]; + info->destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i]; + + /* channelmask specifies bits which aren't used in the source format but in the destination one */ + if(destformat->bits[i]) { + if(srcformat->bits[i]) info->process_channel[i] = TRUE; + else info->channelmask |= info->destmask[i]; + } + } +} + +/************************************************************ + * get_relevant_argb_components + * + * Extracts the relevant components from the source color and + * drops the less significant bits if they aren't used by the destination format. + */ +static void get_relevant_argb_components(const struct argb_conversion_info *info, const BYTE *col, DWORD *out) +{ + unsigned int i, j; + unsigned int component, mask; + + for (i = 0; i < 4; ++i) + { + if (!info->process_channel[i]) + continue; + + component = 0; + mask = info->srcmask[i]; + for (j = 0; j < 4 && mask; ++j) + { + if (info->srcshift[i] < j * 8) + component |= (col[j] & mask) << (j * 8 - info->srcshift[i]); + else + component |= (col[j] & mask) >> (info->srcshift[i] - j * 8); + mask >>= 8; + } + out[i] = component; + } +} + +static float d3dx_clamp(float value, float min_value, float max_value) +{ + if (isnan(value)) + return max_value; + return value < min_value ? min_value : value > max_value ? max_value : value; +} + +/************************************************************ + * make_argb_color + * + * Recombines the output of get_relevant_argb_components and converts + * it to the destination format. + */ +static DWORD make_argb_color(const struct argb_conversion_info *info, const DWORD *in) +{ + UINT i; + DWORD val = 0; + + for(i = 0;i < 4;i++) { + if(info->process_channel[i]) { + /* necessary to make sure that e.g. an X4R4G4B4 white maps to an R8G8B8 white instead of 0xf0f0f0 */ + signed int shift; + for(shift = info->destshift[i]; shift > info->destformat->shift[i]; shift -= info->srcformat->bits[i]) val |= in[i] << shift; + val |= (in[i] >> (info->destformat->shift[i] - shift)) << info->destformat->shift[i]; + } + } + val |= info->channelmask; /* new channels are set to their maximal value */ + return val; +} + +static enum range get_range_for_component_type(enum component_type type) +{ + switch (type) + { + case CTYPE_SNORM: + return RANGE_SNORM; + + case CTYPE_LUMA: + case CTYPE_INDEX: + case CTYPE_UNORM: + return RANGE_UNORM; + + case CTYPE_EMPTY: + case CTYPE_FLOAT: + return RANGE_FULL; + + default: + assert(0); + return RANGE_FULL; + } +} + +static void premultiply_alpha(struct vec4 *vec) +{ + vec->x *= vec->w; + vec->y *= vec->w; + vec->z *= vec->w; +} + +static void undo_premultiplied_alpha(struct vec4 *vec) +{ + vec->x = (vec->w == 0.0f) ? 0.0f : vec->x / vec->w; + vec->y = (vec->w == 0.0f) ? 0.0f : vec->y / vec->w; + vec->z = (vec->w == 0.0f) ? 0.0f : vec->z / vec->w; +} + +static void vec4_to_sRGB(struct vec4 *vec) +{ + vec->x = (vec->x <= 0.0031308f) ? (12.92f * vec->x) : (1.055f * powf(vec->x, 1.0f / 2.4f) - 0.055f); + vec->y = (vec->y <= 0.0031308f) ? (12.92f * vec->y) : (1.055f * powf(vec->y, 1.0f / 2.4f) - 0.055f); + vec->z = (vec->z <= 0.0031308f) ? (12.92f * vec->z) : (1.055f * powf(vec->z, 1.0f / 2.4f) - 0.055f); +} + +static void vec4_from_sRGB(struct vec4 *vec) +{ + vec->x = (vec->x <= 0.04045f) ? vec->x / 12.92f : powf((vec->x + 0.055f) / 1.055f, 2.4f); + vec->y = (vec->y <= 0.04045f) ? vec->y / 12.92f : powf((vec->y + 0.055f) / 1.055f, 2.4f); + vec->z = (vec->z <= 0.04045f) ? vec->z / 12.92f : powf((vec->z + 0.055f) / 1.055f, 2.4f); +} + +/* It doesn't work for components bigger than 32 bits (or somewhat smaller but unaligned). */ +void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *src, const PALETTEENTRY *palette, + struct d3dx_color *dst) +{ + DWORD mask, tmp; + unsigned int c; + + dst->rgb_range = get_range_for_component_type(format->rgb_type); + dst->a_range = get_range_for_component_type(format->a_type); + for (c = 0; c < 4; ++c) + { + const enum component_type dst_ctype = !c ? format->a_type : format->rgb_type; + static const unsigned int component_offsets[4] = {3, 0, 1, 2}; + float *dst_component = &dst->value.x + component_offsets[c]; + + if (format->bits[c]) + { + mask = ~0u >> (32 - format->bits[c]); + + memcpy(&tmp, src + format->shift[c] / 8, + min(sizeof(DWORD), (format->shift[c] % 8 + format->bits[c] + 7) / 8)); + tmp = (tmp >> (format->shift[c] % 8)) & mask; + + switch (dst_ctype) + { + case CTYPE_FLOAT: + if (format->bits[c] == 10 || format->bits[c] == 11) + *dst_component = partial_float_to_32(((tmp >> format->shift[c] % 8) & mask), format->bits[c]); + else if (format->bits[c] == 16) + *dst_component = float_16_to_32(tmp); + else + *dst_component = *(float *)&tmp; + break; + + case CTYPE_INDEX: + *dst_component = (&palette[tmp].peRed)[component_offsets[c]] / 255.0f; + break; + + case CTYPE_LUMA: + case CTYPE_UNORM: + *dst_component = (float)tmp / mask; + break; + + case CTYPE_SNORM: + { + const uint32_t sign_bit = (1u << (format->bits[c] - 1)); + uint32_t tmp_extended = (tmp & sign_bit) ? (tmp | ~(sign_bit - 1)) : tmp; + + /* + * In order to clamp to an even range, we need to ignore + * the maximum negative value. + */ + if (tmp == sign_bit) + tmp_extended |= 1; + + *dst_component = (float)(((int32_t)tmp_extended)) / (sign_bit - 1); + break; + } + + default: + break; + } + } + else if (dst_ctype == CTYPE_LUMA) + { + assert(format->bits[1]); + *dst_component = dst->value.x; + } + else + { + *dst_component = 1.0f; + } + } +} + +/* It doesn't work for components bigger than 32 bits. */ +void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst) +{ + DWORD v, mask32; + unsigned int c, i; + + memset(dst, 0, format->bytes_per_pixel); + + for (c = 0; c < 4; ++c) + { + const enum component_type dst_ctype = !c ? format->a_type : format->rgb_type; + static const unsigned int component_offsets[4] = {3, 0, 1, 2}; + const float src_component = *(&src->value.x + component_offsets[c]); + const enum range src_range = !c ? src->a_range : src->rgb_range; + + if (!format->bits[c]) + continue; + + mask32 = ~0u >> (32 - format->bits[c]); + + switch (dst_ctype) + { + case CTYPE_FLOAT: + if (format->bits[c] == 10 || format->bits[c] == 11) + v = float_32_to_partial_float(src_component, format->bits[c]); + else if (format->bits[c] == 16) + v = float_32_to_16(src_component); + else + v = *(DWORD *)&src_component; + break; + + case CTYPE_LUMA: + { + float val = src->value.x * 0.2125f + src->value.y * 0.7154f + src->value.z * 0.0721f; + + if (src_range == RANGE_SNORM) + val = (val + 1.0f) / 2.0f; + + v = d3dx_clamp(val, 0.0f, 1.0f) * ((1u << format->bits[c]) - 1) + 0.5f; + break; + } + + case CTYPE_UNORM: + { + float val = src_component; + + if (src_range == RANGE_SNORM) + val = (val + 1.0f) / 2.0f; + + v = d3dx_clamp(val, 0.0f, 1.0f) * ((1u << format->bits[c]) - 1) + 0.5f; + break; + } + + case CTYPE_SNORM: + { + const uint32_t max_value = (1u << (format->bits[c] - 1)) - 1; + float val = src_component; + + if (src_range == RANGE_UNORM) + val = (val * 2.0f) - 1.0f; + + v = d3dx_clamp(val, -1.0f, 1.0f) * max_value + 0.5f; + break; + } + + /* We shouldn't be trying to output to CTYPE_INDEX. */ + case CTYPE_INDEX: + assert(0); + break; + + default: + v = 0; + break; + } + + for (i = format->shift[c] / 8 * 8; i < format->shift[c] + format->bits[c]; i += 8) + { + BYTE mask, byte; + + if (format->shift[c] > i) + { + mask = mask32 << (format->shift[c] - i); + byte = (v << (format->shift[c] - i)) & mask; + } + else + { + mask = mask32 >> (i - format->shift[c]); + byte = (v >> (i - format->shift[c])) & mask; + } + dst[i / 8] |= byte; + } + } +} + +/************************************************************ + * copy_pixels + * + * Copies the source buffer to the destination buffer. + * Works for any pixel format. + * The source and the destination must be block-aligned. + */ +static void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, + BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *size, + const struct pixel_format_desc *format) +{ + UINT row, slice; + BYTE *dst_addr; + const BYTE *src_addr; + UINT row_block_count = (size->width + format->block_width - 1) / format->block_width; + UINT row_count = (size->height + format->block_height - 1) / format->block_height; + + for (slice = 0; slice < size->depth; slice++) + { + src_addr = src + slice * src_slice_pitch; + dst_addr = dst + slice * dst_slice_pitch; + + for (row = 0; row < row_count; row++) + { + memcpy(dst_addr, src_addr, row_block_count * format->block_byte_count); + src_addr += src_row_pitch; + dst_addr += dst_row_pitch; + } + } +} + +/************************************************************ + * convert_argb_pixels + * + * Copies the source buffer to the destination buffer, performing + * any necessary format conversion and color keying. + * Pixels outsize the source rect are blacked out. + */ +static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, + const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, + const struct volume *dst_size, const struct pixel_format_desc *dst_format, DWORD color_key, + const PALETTEENTRY *palette, uint32_t filter_flags) +{ + struct argb_conversion_info conv_info, ck_conv_info; + const struct pixel_format_desc *ck_format; + BOOL src_pma, dst_pma, src_srgb, dst_srgb; + DWORD channels[4]; + UINT min_width, min_height, min_depth; + UINT x, y, z; + + TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, " + "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key 0x%08lx, palette %p.\n", + src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, + dst_format, color_key, palette); + + ZeroMemory(channels, sizeof(channels)); + init_argb_conversion_info(src_format, dst_format, &conv_info); + + src_pma = !!(filter_flags & D3DX_FILTER_PMA_IN); + dst_pma = !!(filter_flags & D3DX_FILTER_PMA_OUT); + src_srgb = !!(filter_flags & D3DX_FILTER_SRGB_IN); + dst_srgb = !!(filter_flags & D3DX_FILTER_SRGB_OUT); + min_width = min(src_size->width, dst_size->width); + min_height = min(src_size->height, dst_size->height); + min_depth = min(src_size->depth, dst_size->depth); + + if (color_key) + { + /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ + ck_format = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM); + init_argb_conversion_info(src_format, ck_format, &ck_conv_info); + } + + for (z = 0; z < min_depth; z++) { + const BYTE *src_slice_ptr = src + z * src_slice_pitch; + BYTE *dst_slice_ptr = dst + z * dst_slice_pitch; + + for (y = 0; y < min_height; y++) { + const BYTE *src_ptr = src_slice_ptr + y * src_row_pitch; + BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch; + + for (x = 0; x < min_width; x++) { + if (filter_flags_match(filter_flags) && format_types_match(src_format, dst_format) + && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4) + { + DWORD val; + + get_relevant_argb_components(&conv_info, src_ptr, channels); + val = make_argb_color(&conv_info, channels); + + if (color_key) + { + DWORD ck_pixel; + + get_relevant_argb_components(&ck_conv_info, src_ptr, channels); + ck_pixel = make_argb_color(&ck_conv_info, channels); + if (ck_pixel == color_key) + val &= ~conv_info.destmask[0]; + } + memcpy(dst_ptr, &val, dst_format->bytes_per_pixel); + } + else + { + struct d3dx_color color, tmp; + + format_to_d3dx_color(src_format, src_ptr, palette, &color); + if (src_pma && src_pma != dst_pma) + undo_premultiplied_alpha(&color.value); + if (src_srgb && src_srgb != dst_srgb) + vec4_from_sRGB(&color.value); + tmp = color; + + if (color_key) + { + DWORD ck_pixel; + + format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); + if (ck_pixel == color_key) + tmp.value.w = 0.0f; + } + + color = tmp; + if (dst_srgb && src_srgb != dst_srgb) + vec4_to_sRGB(&color.value); + if (dst_pma && src_pma != dst_pma) + premultiply_alpha(&color.value); + format_from_d3dx_color(dst_format, &color, dst_ptr); + } + + src_ptr += src_format->bytes_per_pixel; + dst_ptr += dst_format->bytes_per_pixel; + } + + if (src_size->width < dst_size->width) /* black out remaining pixels */ + memset(dst_ptr, 0, dst_format->bytes_per_pixel * (dst_size->width - src_size->width)); + } + + if (src_size->height < dst_size->height) /* black out remaining pixels */ + memset(dst + src_size->height * dst_row_pitch, 0, dst_row_pitch * (dst_size->height - src_size->height)); + } + if (src_size->depth < dst_size->depth) /* black out remaining pixels */ + memset(dst + src_size->depth * dst_slice_pitch, 0, dst_slice_pitch * (dst_size->depth - src_size->depth)); +} + +/************************************************************ + * point_filter_argb_pixels + * + * Copies the source buffer to the destination buffer, performing + * any necessary format conversion, color keying and stretching + * using a point filter. + */ +static void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, + const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, + const struct volume *dst_size, const struct pixel_format_desc *dst_format, DWORD color_key, + const PALETTEENTRY *palette, uint32_t filter_flags) +{ + struct argb_conversion_info conv_info, ck_conv_info; + const struct pixel_format_desc *ck_format; + BOOL src_pma, dst_pma, src_srgb, dst_srgb; + DWORD channels[4]; + UINT x, y, z; + + TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, " + "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key 0x%08lx, palette %p.\n", + src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, + dst_format, color_key, palette); + + src_srgb = !!(filter_flags & D3DX_FILTER_SRGB_IN); + dst_srgb = !!(filter_flags & D3DX_FILTER_SRGB_OUT); + src_pma = !!(filter_flags & D3DX_FILTER_PMA_IN); + dst_pma = !!(filter_flags & D3DX_FILTER_PMA_OUT); + ZeroMemory(channels, sizeof(channels)); + init_argb_conversion_info(src_format, dst_format, &conv_info); + + if (color_key) + { + /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ + ck_format = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM); + init_argb_conversion_info(src_format, ck_format, &ck_conv_info); + } + + for (z = 0; z < dst_size->depth; z++) + { + BYTE *dst_slice_ptr = dst + z * dst_slice_pitch; + const BYTE *src_slice_ptr = src + src_slice_pitch * (z * src_size->depth / dst_size->depth); + + for (y = 0; y < dst_size->height; y++) + { + BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch; + const BYTE *src_row_ptr = src_slice_ptr + src_row_pitch * (y * src_size->height / dst_size->height); + + for (x = 0; x < dst_size->width; x++) + { + const BYTE *src_ptr = src_row_ptr + (x * src_size->width / dst_size->width) * src_format->bytes_per_pixel; + + if (filter_flags_match(filter_flags) && format_types_match(src_format, dst_format) + && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4) + { + DWORD val; + + get_relevant_argb_components(&conv_info, src_ptr, channels); + val = make_argb_color(&conv_info, channels); + + if (color_key) + { + DWORD ck_pixel; + + get_relevant_argb_components(&ck_conv_info, src_ptr, channels); + ck_pixel = make_argb_color(&ck_conv_info, channels); + if (ck_pixel == color_key) + val &= ~conv_info.destmask[0]; + } + memcpy(dst_ptr, &val, dst_format->bytes_per_pixel); + } + else + { + struct d3dx_color color, tmp; + + format_to_d3dx_color(src_format, src_ptr, palette, &color); + if (src_pma && src_pma != dst_pma) + undo_premultiplied_alpha(&color.value); + if (src_srgb && src_srgb != dst_srgb) + vec4_from_sRGB(&color.value); + tmp = color; + + if (color_key) + { + DWORD ck_pixel; + + format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); + if (ck_pixel == color_key) + tmp.value.w = 0.0f; + } + + color = tmp; + if (dst_srgb && src_srgb != dst_srgb) + vec4_to_sRGB(&color.value); + if (dst_pma && src_pma != dst_pma) + premultiply_alpha(&color.value); + format_from_d3dx_color(dst_format, &color, dst_ptr); + } + + dst_ptr += dst_format->bytes_per_pixel; + } + } + } +} + +struct d3dx_bcn_decompression_context +{ + void (*decompress_bcn_block)(const void *, void *, int); + const struct pixel_format_desc *compressed_format_desc; + struct d3dx_pixels *compressed_pixels; + + const struct pixel_format_desc *decompressed_format_desc; + uint8_t cur_block_decompressed[192]; + uint32_t cur_block_row_pitch; + int32_t cur_block_x; + int32_t cur_block_y; + int32_t cur_block_z; +}; + +static void d3dx_init_bcn_decompression_context(struct d3dx_bcn_decompression_context *context, + struct d3dx_pixels *pixels, const struct pixel_format_desc *desc, const struct pixel_format_desc *dst_desc) +{ + memset(context, 0, sizeof(*context)); + switch (desc->format) + { + case D3DX_PIXEL_FORMAT_DXT1_UNORM: + case D3DX_PIXEL_FORMAT_BC1_UNORM_SRGB: + context->decompress_bcn_block = bcdec_bc1; + break; + + case D3DX_PIXEL_FORMAT_DXT2_UNORM: + case D3DX_PIXEL_FORMAT_DXT3_UNORM: + case D3DX_PIXEL_FORMAT_BC2_UNORM_SRGB: + context->decompress_bcn_block = bcdec_bc2; + break; + + case D3DX_PIXEL_FORMAT_DXT4_UNORM: + case D3DX_PIXEL_FORMAT_DXT5_UNORM: + case D3DX_PIXEL_FORMAT_BC3_UNORM_SRGB: + context->decompress_bcn_block = bcdec_bc3; + break; + + case D3DX_PIXEL_FORMAT_BC4_UNORM: + case D3DX_PIXEL_FORMAT_BC4_SNORM: + context->decompress_bcn_block = bcdec_bc4; + break; + + case D3DX_PIXEL_FORMAT_BC5_UNORM: + case D3DX_PIXEL_FORMAT_BC5_SNORM: + context->decompress_bcn_block = bcdec_bc5; + break; + + default: + assert(0); + break; + } + + context->compressed_format_desc = desc; + context->compressed_pixels = pixels; + + context->decompressed_format_desc = dst_desc; + context->cur_block_row_pitch = dst_desc->bytes_per_pixel * desc->block_width; + context->cur_block_x = context->cur_block_y = context->cur_block_z = -1; +} + +static void d3dx_fetch_bcn_texel(struct d3dx_bcn_decompression_context *context, int32_t x, int32_t y, int32_t z, void *texel) +{ + const struct pixel_format_desc *decomp_fmt_desc = context->decompressed_format_desc; + const struct pixel_format_desc *comp_fmt_desc = context->compressed_format_desc; + const int32_t y_aligned = (y & ~(comp_fmt_desc->block_height - 1)); + const int32_t x_aligned = (x & ~(comp_fmt_desc->block_width - 1)); + uint32_t pixel_offset; + + if (z != context->cur_block_z || (x_aligned != context->cur_block_x) || (y_aligned != context->cur_block_y)) + { + const BYTE *block_ptr = context->compressed_pixels->data; + + block_ptr += z * context->compressed_pixels->slice_pitch; + block_ptr += (y / comp_fmt_desc->block_height) * context->compressed_pixels->row_pitch; + block_ptr += (x / comp_fmt_desc->block_width) * comp_fmt_desc->block_byte_count; + context->decompress_bcn_block(block_ptr, context->cur_block_decompressed, context->cur_block_row_pitch); + context->cur_block_x = (x & (comp_fmt_desc->block_width)); + context->cur_block_y = (y & (comp_fmt_desc->block_height)); + context->cur_block_z = z; + } + + pixel_offset = (y & (comp_fmt_desc->block_height - 1)) * context->cur_block_row_pitch; + pixel_offset += (x & (comp_fmt_desc->block_width - 1)) * decomp_fmt_desc->bytes_per_pixel; + memcpy(texel, context->cur_block_decompressed + pixel_offset, decomp_fmt_desc->bytes_per_pixel); +} + +static HRESULT d3dx_pixels_decompress(struct d3dx_pixels *pixels, const struct pixel_format_desc *desc, + BOOL is_dst, void **out_memory, uint32_t *out_row_pitch, uint32_t *out_slice_pitch, + const struct pixel_format_desc **out_desc) +{ + uint32_t x, y, z, uncompressed_slice_pitch, uncompressed_row_pitch; + const struct pixel_format_desc *uncompressed_desc = NULL; + struct d3dx_bcn_decompression_context context; + const struct volume *size = &pixels->size; + BYTE *uncompressed_mem; + + switch (desc->format) + { + case D3DX_PIXEL_FORMAT_DXT1_UNORM: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + break; + + case D3DX_PIXEL_FORMAT_BC1_UNORM_SRGB: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM_SRGB); + break; + + case D3DX_PIXEL_FORMAT_DXT2_UNORM: + case D3DX_PIXEL_FORMAT_DXT3_UNORM: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + break; + + case D3DX_PIXEL_FORMAT_BC2_UNORM_SRGB: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM_SRGB); + break; + + case D3DX_PIXEL_FORMAT_DXT4_UNORM: + case D3DX_PIXEL_FORMAT_DXT5_UNORM: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + break; + + case D3DX_PIXEL_FORMAT_BC3_UNORM_SRGB: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM_SRGB); + break; + + case D3DX_PIXEL_FORMAT_BC4_UNORM: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8_UNORM); + break; + + case D3DX_PIXEL_FORMAT_BC4_SNORM: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8_SNORM); + break; + + case D3DX_PIXEL_FORMAT_BC5_UNORM: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8_UNORM); + break; + + case D3DX_PIXEL_FORMAT_BC5_SNORM: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8_SNORM); + break; + + default: + FIXME("Unexpected compressed texture format %u.\n", desc->format); + return E_NOTIMPL; + } + + uncompressed_row_pitch = size->width * uncompressed_desc->bytes_per_pixel; + uncompressed_slice_pitch = uncompressed_row_pitch * size->height; + if (!(uncompressed_mem = malloc(size->depth * uncompressed_slice_pitch))) + return E_OUTOFMEMORY; + + /* + * For compressed destination pixels, width/height will represent + * the entire set of compressed blocks our destination rectangle touches. + * If we're only updating a sub-area of any blocks, we need to decompress + * the pixels outside of the sub-area. + */ + if (is_dst) + { + const RECT aligned_rect = { 0, 0, size->width, size->height }; + + /* + * If our destination covers the entire set of blocks, no + * decompression needs to be done, just return the allocated memory. + */ + if (EqualRect(&aligned_rect, &pixels->unaligned_rect)) + goto exit; + } + + TRACE("Decompressing pixels.\n"); + d3dx_init_bcn_decompression_context(&context, pixels, desc, uncompressed_desc); + for (z = 0; z < size->depth; ++z) + { + for (y = 0; y < size->height; ++y) + { + BYTE *ptr = &uncompressed_mem[(z * uncompressed_slice_pitch) + (y * uncompressed_row_pitch)]; + for (x = 0; x < size->width; ++x) + { + const POINT pt = { x, y }; + + if (!is_dst) + d3dx_fetch_bcn_texel(&context, x + pixels->unaligned_rect.left, y + pixels->unaligned_rect.top, z, ptr); + else if (!PtInRect(&pixels->unaligned_rect, pt)) + d3dx_fetch_bcn_texel(&context, x, y, z, ptr); + ptr += uncompressed_desc->bytes_per_pixel; + } + } + } + +exit: + *out_memory = uncompressed_mem; + *out_row_pitch = uncompressed_row_pitch; + *out_slice_pitch = uncompressed_slice_pitch; + *out_desc = uncompressed_desc; + + return S_OK; +} + +static void d3dx_init_bcn_block_buffer(const void *src_data, uint32_t src_row_pitch, uint8_t src_width, uint8_t src_height, + const struct pixel_format_desc *src_desc, uint8_t *block_buf) +{ + uint8_t x, y; + + for (y = 0; y < 4; ++y) + { + const uint8_t *src_row = ((const uint8_t *)src_data) + ((y % src_height) * src_row_pitch); + + for (x = 0; x < 4; ++x) + { + uint8_t *dst_pixel = &block_buf[(y * 4 * src_desc->bytes_per_pixel) + (x * src_desc->bytes_per_pixel)]; + const uint8_t *src_pixel = src_row + (((x % src_width)) * src_desc->bytes_per_pixel); + + memcpy(dst_pixel, src_pixel, src_desc->bytes_per_pixel); + } + } +} + +static void d3dx_compress_bc1_block(const void *src_data, uint32_t src_row_pitch, uint8_t src_width, uint8_t src_height, + void *dst_data) +{ + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + uint8_t tmp_buf[4 * 4 * 4]; + + d3dx_init_bcn_block_buffer(src_data, src_row_pitch, src_width, src_height, fmt_desc, tmp_buf); + + stb_compress_dxt_block(dst_data, (const uint8_t *)tmp_buf, FALSE, 0); +} + +static void d3dx_compress_bc2_block(const void *src_data, uint32_t src_row_pitch, uint8_t src_width, uint8_t src_height, + void *dst_data) +{ + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + uint8_t *dst_data_offset = dst_data; + uint8_t tmp_buf[4 * 4 * 4], y; + + d3dx_init_bcn_block_buffer(src_data, src_row_pitch, src_width, src_height, fmt_desc, tmp_buf); + for (y = 0; y < 4; ++y) + { + uint8_t *tmp_row = &tmp_buf[y * 4 * fmt_desc->bytes_per_pixel]; + + dst_data_offset[0] = (tmp_row[7] & 0xf0); + dst_data_offset[0] |= (tmp_row[3] >> 4); + dst_data_offset[1] = (tmp_row[15] & 0xf0); + dst_data_offset[1] |= (tmp_row[11] >> 4); + + /* + * Set all alpha values to 0xff so they aren't considered during + * compression. + */ + tmp_row[3] = tmp_row[7] = tmp_row[11] = tmp_row[15] = 0xff; + dst_data_offset += 2; + } + + stb_compress_dxt_block(dst_data_offset, (const unsigned char *)tmp_buf, FALSE, 0); +} + +static void d3dx_compress_bc3_block(const void *src_data, uint32_t src_row_pitch, uint8_t src_width, uint8_t src_height, + void *dst_data) +{ + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + uint8_t tmp_buf[4 * 4 * 4]; + + d3dx_init_bcn_block_buffer(src_data, src_row_pitch, src_width, src_height, fmt_desc, tmp_buf); + + stb_compress_dxt_block(dst_data, (const uint8_t *)tmp_buf, TRUE, 0); +} + +static void d3dx_compress_bc4_block(const void *src_data, uint32_t src_row_pitch, uint8_t src_width, uint8_t src_height, + void *dst_data) +{ + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8_UNORM); + uint8_t tmp_buf[4 * 4]; + + d3dx_init_bcn_block_buffer(src_data, src_row_pitch, src_width, src_height, fmt_desc, tmp_buf); + + stb_compress_bc4_block(dst_data, (const unsigned char *)tmp_buf); +} + +static void d3dx_compress_bc5_block(const void *src_data, uint32_t src_row_pitch, uint8_t src_width, uint8_t src_height, + void *dst_data) +{ + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8_UNORM); + uint8_t tmp_buf[4 * 4 * 2]; + + d3dx_init_bcn_block_buffer(src_data, src_row_pitch, src_width, src_height, fmt_desc, tmp_buf); + + stb_compress_bc5_block(dst_data, (const unsigned char *)tmp_buf); +} + +static HRESULT d3dx_pixels_compress(struct d3dx_pixels *src_pixels, + const struct pixel_format_desc *src_desc, struct d3dx_pixels *dst_pixels, + const struct pixel_format_desc *dst_desc) +{ + void (*compress_bcn_block)(const void *, uint32_t, uint8_t, uint8_t, void *) = NULL; + uint32_t x, y, z; + + /* Pick a compression function. */ + switch (dst_desc->format) + { + case D3DX_PIXEL_FORMAT_DXT1_UNORM: + case D3DX_PIXEL_FORMAT_BC1_UNORM_SRGB: + compress_bcn_block = d3dx_compress_bc1_block; + break; + + case D3DX_PIXEL_FORMAT_DXT2_UNORM: + case D3DX_PIXEL_FORMAT_DXT3_UNORM: + case D3DX_PIXEL_FORMAT_BC2_UNORM_SRGB: + compress_bcn_block = d3dx_compress_bc2_block; + break; + + case D3DX_PIXEL_FORMAT_DXT4_UNORM: + case D3DX_PIXEL_FORMAT_DXT5_UNORM: + case D3DX_PIXEL_FORMAT_BC3_UNORM_SRGB: + compress_bcn_block = d3dx_compress_bc3_block; + break; + + case D3DX_PIXEL_FORMAT_BC4_UNORM: + case D3DX_PIXEL_FORMAT_BC4_SNORM: + compress_bcn_block = d3dx_compress_bc4_block; + break; + + case D3DX_PIXEL_FORMAT_BC5_UNORM: + case D3DX_PIXEL_FORMAT_BC5_SNORM: + compress_bcn_block = d3dx_compress_bc5_block; + break; + + default: + FIXME("Unexpected compressed texture format %u.\n", dst_desc->format); + return E_NOTIMPL; + } + + assert(compress_bcn_block); + + TRACE("Compressing pixels.\n"); + for (z = 0; z < src_pixels->size.depth; ++z) + { + const BYTE *src_slice = ((const BYTE *)src_pixels->data) + (z * src_pixels->slice_pitch); + BYTE *dst_slice = ((BYTE *)dst_pixels->data) + (z * dst_pixels->slice_pitch); + + for (y = 0; y < src_pixels->size.height; y += dst_desc->block_height) + { + BYTE *dst_ptr = &dst_slice[(y / dst_desc->block_height) * dst_pixels->row_pitch]; + uint8_t tmp_src_height = min(dst_desc->block_height, src_pixels->size.height - y); + const BYTE *src_ptr = &src_slice[y * src_pixels->row_pitch]; + + for (x = 0; x < src_pixels->size.width; x += dst_desc->block_width) + { + uint8_t tmp_src_width = min(dst_desc->block_width, src_pixels->size.width - x); + + compress_bcn_block(src_ptr, src_pixels->row_pitch, tmp_src_width, tmp_src_height, dst_ptr); + src_ptr += (src_desc->bytes_per_pixel * dst_desc->block_width); + dst_ptr += dst_desc->block_byte_count; + } + } + } + + return S_OK; +} + +HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, + const PALETTEENTRY *palette, enum d3dx_pixel_format_id format, uint32_t left, uint32_t top, uint32_t right, + uint32_t bottom, uint32_t front, uint32_t back, struct d3dx_pixels *pixels) +{ + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(format); + const BYTE *ptr = data; + RECT unaligned_rect; + + memset(pixels, 0, sizeof(*pixels)); + if (is_unknown_format(fmt_desc)) + { + FIXME("Unsupported format %#x.\n", format); + return E_NOTIMPL; + } + + ptr += front * slice_pitch; + ptr += (top / fmt_desc->block_height) * row_pitch; + ptr += (left / fmt_desc->block_width) * fmt_desc->block_byte_count; + + if (is_compressed_format(fmt_desc)) + { + uint32_t left_aligned, top_aligned; + + top_aligned = top & ~(fmt_desc->block_height - 1); + left_aligned = left & ~(fmt_desc->block_width - 1); + SetRect(&unaligned_rect, left, top, right, bottom); + OffsetRect(&unaligned_rect, -left_aligned, -top_aligned); + } + else + { + SetRect(&unaligned_rect, 0, 0, (right - left), (bottom - top)); + } + + if (!slice_pitch) + slice_pitch = row_pitch * (bottom - top); + set_d3dx_pixels(pixels, ptr, row_pitch, slice_pitch, palette, (right - left), (bottom - top), (back - front), + &unaligned_rect); + + return S_OK; +} + +static const char *debug_d3dx_pixels(struct d3dx_pixels *pixels) +{ + if (!pixels) + return "(null)"; + return wine_dbg_sprintf("(data %p, row_pitch %d, slice_pitch %d, palette %p, width %d, height %d, depth %d, " + "unaligned_rect %s)", pixels->data, pixels->row_pitch, pixels->slice_pitch, pixels->palette, + pixels->size.width, pixels->size.height, pixels->size.depth, wine_dbgstr_rect(&pixels->unaligned_rect)); +} + +HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, + const struct pixel_format_desc *dst_desc, struct d3dx_pixels *src_pixels, + const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key) +{ + struct volume src_size, dst_size, dst_size_aligned; + BOOL src_pma, dst_pma, src_srgb, dst_srgb; + HRESULT hr = S_OK; + + TRACE("dst_pixels %s, dst_desc %p, src_pixels %s, src_desc %p, filter_flags %#x, color_key %#x.\n", + debug_d3dx_pixels(dst_pixels), dst_desc, debug_d3dx_pixels(src_pixels), src_desc, + filter_flags, color_key); + + if (src_desc->flags & FMT_FLAG_SRGB) + filter_flags |= D3DX_FILTER_SRGB_IN; + if (src_desc->flags & FMT_FLAG_PM_ALPHA) + filter_flags |= D3DX_FILTER_PMA_IN; + + if (dst_desc->flags & FMT_FLAG_SRGB) + filter_flags |= D3DX_FILTER_SRGB_OUT; + if (dst_desc->flags & FMT_FLAG_PM_ALPHA) + filter_flags |= D3DX_FILTER_PMA_OUT; + + src_srgb = !!(filter_flags & D3DX_FILTER_SRGB_IN); + dst_srgb = !!(filter_flags & D3DX_FILTER_SRGB_OUT); + src_pma = !!(filter_flags & D3DX_FILTER_PMA_IN); + dst_pma = !!(filter_flags & D3DX_FILTER_PMA_OUT); + + if (is_compressed_format(src_desc)) + set_volume_struct(&src_size, (src_pixels->unaligned_rect.right - src_pixels->unaligned_rect.left), + (src_pixels->unaligned_rect.bottom - src_pixels->unaligned_rect.top), src_pixels->size.depth); + else + src_size = src_pixels->size; + + dst_size_aligned = dst_pixels->size; + if (is_compressed_format(dst_desc)) + set_volume_struct(&dst_size, (dst_pixels->unaligned_rect.right - dst_pixels->unaligned_rect.left), + (dst_pixels->unaligned_rect.bottom - dst_pixels->unaligned_rect.top), dst_pixels->size.depth); + else + dst_size = dst_size_aligned; + + /* Everything matches, simply copy the pixels. */ + if (src_desc->format == dst_desc->format + && (dst_size.width == src_size.width && !(dst_size.width % dst_desc->block_width)) + && (dst_size.height == src_size.height && !(dst_size.height % dst_desc->block_height)) + && (dst_size.depth == src_size.depth) + && (src_pma == dst_pma) + && (src_srgb == dst_srgb) + && color_key == 0 + && !(src_pixels->unaligned_rect.left & (src_desc->block_width - 1)) + && !(src_pixels->unaligned_rect.top & (src_desc->block_height - 1)) + && !(dst_pixels->unaligned_rect.left & (dst_desc->block_width - 1)) + && !(dst_pixels->unaligned_rect.top & (dst_desc->block_height - 1))) + { + TRACE("Simple copy.\n"); + copy_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, (void *)dst_pixels->data, + dst_pixels->row_pitch, dst_pixels->slice_pitch, &src_size, src_desc); + return S_OK; + } + + /* Stretching or format conversion. */ + if (!is_conversion_from_supported(src_desc) + || !is_conversion_to_supported(dst_desc)) + { + FIXME("Unsupported format conversion %#x -> %#x.\n", src_desc->format, dst_desc->format); + return E_NOTIMPL; + } + + /* + * If the source is a compressed image, we need to decompress it first + * before doing any modifications. + */ + if (is_compressed_format(src_desc)) + { + uint32_t uncompressed_row_pitch, uncompressed_slice_pitch; + const struct pixel_format_desc *uncompressed_desc; + void *uncompressed_mem = NULL; + + hr = d3dx_pixels_decompress(src_pixels, src_desc, FALSE, &uncompressed_mem, &uncompressed_row_pitch, + &uncompressed_slice_pitch, &uncompressed_desc); + if (SUCCEEDED(hr)) + { + struct d3dx_pixels uncompressed_pixels; + + d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, + uncompressed_desc->format, 0, 0, src_pixels->size.width, src_pixels->size.height, + 0, src_pixels->size.depth, &uncompressed_pixels); + + hr = d3dx_load_pixels_from_pixels(dst_pixels, dst_desc, &uncompressed_pixels, uncompressed_desc, + filter_flags, color_key); + } + free(uncompressed_mem); + goto exit; + } + + /* Same as the above, need to decompress the destination prior to modifying. */ + if (is_compressed_format(dst_desc)) + { + uint32_t uncompressed_row_pitch, uncompressed_slice_pitch; + const struct pixel_format_desc *uncompressed_desc; + struct d3dx_pixels uncompressed_pixels; + void *uncompressed_mem = NULL; + + hr = d3dx_pixels_decompress(dst_pixels, dst_desc, TRUE, &uncompressed_mem, &uncompressed_row_pitch, + &uncompressed_slice_pitch, &uncompressed_desc); + if (FAILED(hr)) + goto exit; + + d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, + uncompressed_desc->format, dst_pixels->unaligned_rect.left, dst_pixels->unaligned_rect.top, + dst_pixels->unaligned_rect.right, dst_pixels->unaligned_rect.bottom, 0, dst_pixels->size.depth, + &uncompressed_pixels); + + hr = d3dx_load_pixels_from_pixels(&uncompressed_pixels, uncompressed_desc, src_pixels, src_desc, filter_flags, + color_key); + if (SUCCEEDED(hr)) + { + d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, + uncompressed_desc->format, 0, 0, dst_size_aligned.width, dst_size_aligned.height, 0, + dst_pixels->size.depth, &uncompressed_pixels); + + hr = d3dx_pixels_compress(&uncompressed_pixels, uncompressed_desc, dst_pixels, dst_desc); + if (FAILED(hr)) + WARN("Failed to compress pixels, hr %#lx.\n", hr); + } + free(uncompressed_mem); + goto exit; + } + + if ((filter_flags & 0xf) == D3DX_FILTER_NONE) + { + convert_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, src_desc, + (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, dst_desc, + color_key, src_pixels->palette, filter_flags); + } + else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ + { + if ((filter_flags & 0xf) != D3DX_FILTER_POINT) + FIXME("Unhandled filter %#x.\n", filter_flags); + + /* Always apply a point filter until D3DX_FILTER_LINEAR, + * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ + point_filter_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, + src_desc, (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, + dst_desc, color_key, src_pixels->palette, filter_flags); + } + +exit: + if (FAILED(hr)) + WARN("Failed to load pixels, hr %#lx.\n", hr); + return hr; +} + +void get_aligned_rect(uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t width, uint32_t height, + const struct pixel_format_desc *fmt_desc, RECT *aligned_rect) +{ + SetRect(aligned_rect, left, top, right, bottom); + if (aligned_rect->left & (fmt_desc->block_width - 1)) + aligned_rect->left = aligned_rect->left & ~(fmt_desc->block_width - 1); + if (aligned_rect->top & (fmt_desc->block_height - 1)) + aligned_rect->top = aligned_rect->top & ~(fmt_desc->block_height - 1); + if (aligned_rect->right & (fmt_desc->block_width - 1) && aligned_rect->right != width) + aligned_rect->right = min((aligned_rect->right + fmt_desc->block_width - 1) + & ~(fmt_desc->block_width - 1), width); + if (aligned_rect->bottom & (fmt_desc->block_height - 1) && aligned_rect->bottom != height) + aligned_rect->bottom = min((aligned_rect->bottom + fmt_desc->block_height - 1) + & ~(fmt_desc->block_height - 1), height); +} + +HRESULT write_buffer_to_file(const WCHAR *dst_filename, ID3DXBlob *buffer) +{ + HRESULT hr = S_OK; + void *buffer_pointer; + DWORD buffer_size; + DWORD bytes_written; + HANDLE file = CreateFileW(dst_filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) + return HRESULT_FROM_WIN32(GetLastError()); + + buffer_pointer = d3dx_blob_get_buffer_pointer(buffer); + buffer_size = d3dx_blob_get_buffer_size(buffer); + + if (!WriteFile(file, buffer_pointer, buffer_size, &bytes_written, NULL)) + hr = HRESULT_FROM_WIN32(GetLastError()); + + CloseHandle(file); + return hr; +} + +/* File/resource loading functions shared amongst d3dx10/d3dx11. */ +HRESULT load_file(const WCHAR *path, void **data, DWORD *size) +{ + DWORD read_len; + HANDLE file; + BOOL ret; + + file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file == INVALID_HANDLE_VALUE) + return D3DX_HELPER_ERR_FILE_NOT_FOUND; + + *size = GetFileSize(file, NULL); + *data = malloc(*size); + if (!*data) + { + CloseHandle(file); + return E_OUTOFMEMORY; + } + + ret = ReadFile(file, *data, *size, &read_len, NULL); + CloseHandle(file); + if (!ret || read_len != *size) + { + WARN("Failed to read file contents.\n"); + free(*data); + return E_FAIL; + } + return S_OK; +} + +HRESULT load_resource_initA(HMODULE module, const char *resource, HRSRC *rsrc) +{ + if (!(*rsrc = FindResourceA(module, resource, (const char *)RT_RCDATA))) + *rsrc = FindResourceA(module, resource, (const char *)RT_BITMAP); + if (!*rsrc) + { + WARN("Failed to find resource.\n"); + return D3DX_ERROR_INVALID_DATA; + } + return S_OK; +} + +HRESULT load_resource_initW(HMODULE module, const WCHAR *resource, HRSRC *rsrc) +{ + if (!(*rsrc = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA))) + *rsrc = FindResourceW(module, resource, (const WCHAR *)RT_BITMAP); + if (!*rsrc) + { + WARN("Failed to find resource.\n"); + return D3DX_ERROR_INVALID_DATA; + } + return S_OK; +} + +HRESULT load_resource(HMODULE module, HRSRC rsrc, void **data, DWORD *size) +{ + HGLOBAL hglobal; + + if (!(*size = SizeofResource(module, rsrc))) + return D3DX_ERROR_INVALID_DATA; + if (!(hglobal = LoadResource(module, rsrc))) + return D3DX_ERROR_INVALID_DATA; + if (!(*data = LockResource(hglobal))) + return D3DX_ERROR_INVALID_DATA; + return S_OK; +} + +HRESULT load_resourceA(HMODULE module, const char *resource, void **data, DWORD *size) +{ + HRESULT hr; + HRSRC rsrc; + + if (FAILED((hr = load_resource_initA(module, resource, &rsrc)))) + return hr; + return load_resource(module, rsrc, data, size); +} + +HRESULT load_resourceW(HMODULE module, const WCHAR *resource, void **data, DWORD *size) +{ + HRESULT hr; + HRSRC rsrc; + + if ((FAILED(hr = load_resource_initW(module, resource, &rsrc)))) + return hr; + return load_resource(module, rsrc, data, size); +} diff --git a/dlls/d3dx9_36/d3dx_helpers.h b/dlls/d3dx9_36/d3dx_helpers.h new file mode 100644 index 000000000000..1f64c8d3c561 --- /dev/null +++ b/dlls/d3dx9_36/d3dx_helpers.h @@ -0,0 +1,563 @@ +/* + * Copyright 2024 Connor McAdams for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#ifndef __WINE_D3DX_HELPERS_H +#define __WINE_D3DX_HELPERS_H + +#include +#include "windef.h" /* For RECT. */ +#include "wingdi.h" /* For PALETTEENTRY. */ + +#if D3DX_D3D_VERSION == 9 +#define COBJMACROS +#include "d3dx9.h" + +#define D3DX_ERROR_INVALID_DATA D3DXERR_INVALIDDATA; +#define D3DX_HELPER_ERR_FILE_NOT_FOUND ERROR_FILE_NOT_FOUND + +#define ID3DXBlob ID3DXBuffer +#define d3dx_create_blob(size, blob) D3DXCreateBuffer(size, blob) +#define d3dx_blob_get_buffer_pointer(blob) ID3DXBuffer_GetBufferPointer(blob) +#define d3dx_blob_get_buffer_size(blob) ID3DXBuffer_GetBufferSize(blob) +#define d3dx_blob_release(blob) ID3DXBuffer_Release(blob) +#endif /* D3DX_D3D_VERSION == 9 */ + +#if D3DX_D3D_VERSION == 10 +#define COBJMACROS +#include "d3dx10.h" + +#define D3DERR_INVALIDCALL 0x8876086c +#define D3DX_ERROR_INVALID_DATA D3DX10_ERR_INVALID_DATA + +#define D3DX_HELPER_ERR_FILE_NOT_FOUND D3D10_ERROR_FILE_NOT_FOUND + +#define D3DX_DEFAULT D3DX10_DEFAULT + +#define D3DX_FILTER_NONE D3DX10_FILTER_NONE +#define D3DX_FILTER_POINT D3DX10_FILTER_POINT +#define D3DX_FILTER_LINEAR D3DX10_FILTER_LINEAR +#define D3DX_FILTER_TRIANGLE D3DX10_FILTER_TRIANGLE +#define D3DX_FILTER_BOX D3DX10_FILTER_BOX +#define D3DX_FILTER_MIRROR_U D3DX10_FILTER_MIRROR_U +#define D3DX_FILTER_MIRROR_V D3DX10_FILTER_MIRROR_V +#define D3DX_FILTER_MIRROR_W D3DX10_FILTER_MIRROR_W +#define D3DX_FILTER_MIRROR D3DX10_FILTER_MIRROR +#define D3DX_FILTER_DITHER D3DX10_FILTER_DITHER +#define D3DX_FILTER_DITHER_DIFFUSION D3DX10_FILTER_DITHER_DIFFUSION +#define D3DX_FILTER_SRGB_IN D3DX10_FILTER_SRGB_IN +#define D3DX_FILTER_SRGB_OUT D3DX10_FILTER_SRGB_OUT +#define D3DX_FILTER_SRGB D3DX10_FILTER_SRGB + +#define ID3DXBlob ID3D10Blob +#define d3dx_create_blob(size, blob) D3D10CreateBlob(size, blob) +#define d3dx_blob_get_buffer_pointer(blob) ID3D10Blob_GetBufferPointer(blob) +#define d3dx_blob_get_buffer_size(blob) ID3D10Blob_GetBufferSize(blob) +#define d3dx_blob_release(blob) ID3D10Blob_Release(blob) + +enum d3dx_pixel_format_id d3dx_pixel_format_id_from_dxgi_format(DXGI_FORMAT format); +DXGI_FORMAT dxgi_format_from_legacy_dds_d3dx_pixel_format_id(enum d3dx_pixel_format_id format); +DXGI_FORMAT dxgi_format_from_dxt10_dds_d3dx_pixel_format_id(enum d3dx_pixel_format_id format); +#endif /* D3DX_D3D_VERSION == 10 */ + +#if D3DX_D3D_VERSION == 11 +#define COBJMACROS +#include "d3dx11.h" +#include "d3dcompiler.h" + +#define D3DERR_INVALIDCALL 0x8876086c +#define D3DX_ERROR_INVALID_DATA D3DX11_ERR_INVALID_DATA + +#define D3DX_HELPER_ERR_FILE_NOT_FOUND D3D11_ERROR_FILE_NOT_FOUND + +#define D3DX_DEFAULT D3DX11_DEFAULT + +#define D3DX_FILTER_NONE D3DX11_FILTER_NONE +#define D3DX_FILTER_POINT D3DX11_FILTER_POINT +#define D3DX_FILTER_LINEAR D3DX11_FILTER_LINEAR +#define D3DX_FILTER_TRIANGLE D3DX11_FILTER_TRIANGLE +#define D3DX_FILTER_BOX D3DX11_FILTER_BOX +#define D3DX_FILTER_MIRROR_U D3DX11_FILTER_MIRROR_U +#define D3DX_FILTER_MIRROR_V D3DX11_FILTER_MIRROR_V +#define D3DX_FILTER_MIRROR_W D3DX11_FILTER_MIRROR_W +#define D3DX_FILTER_MIRROR D3DX11_FILTER_MIRROR +#define D3DX_FILTER_DITHER D3DX11_FILTER_DITHER +#define D3DX_FILTER_DITHER_DIFFUSION D3DX11_FILTER_DITHER_DIFFUSION +#define D3DX_FILTER_SRGB_IN D3DX11_FILTER_SRGB_IN +#define D3DX_FILTER_SRGB_OUT D3DX11_FILTER_SRGB_OUT +#define D3DX_FILTER_SRGB D3DX11_FILTER_SRGB + +#define ID3DXBlob ID3D10Blob +#define d3dx_create_blob(size, blob) D3DCreateBlob(size, blob) +#define d3dx_blob_get_buffer_pointer(blob) ID3D10Blob_GetBufferPointer(blob) +#define d3dx_blob_get_buffer_size(blob) ID3D10Blob_GetBufferSize(blob) +#define d3dx_blob_release(blob) ID3D10Blob_Release(blob) + +enum d3dx_pixel_format_id d3dx_pixel_format_id_from_dxgi_format(DXGI_FORMAT format); +DXGI_FORMAT dxgi_format_from_legacy_dds_d3dx_pixel_format_id(enum d3dx_pixel_format_id format); +DXGI_FORMAT dxgi_format_from_dxt10_dds_d3dx_pixel_format_id(enum d3dx_pixel_format_id format); +#endif /* D3DX_D3D_VERSION == 11 */ + +#define D3DX_FILTER_INVALID_BITS 0xff80fff8 +static inline HRESULT d3dx_validate_filter(uint32_t filter) +{ + if ((filter & D3DX_FILTER_INVALID_BITS) || !(filter & 0x7) || ((filter & 0x7) > D3DX_FILTER_BOX)) + return D3DERR_INVALIDCALL; + + return S_OK; +} + +static inline HRESULT d3dx_handle_filter(UINT *filter) +{ + if (*filter == D3DX_DEFAULT) + *filter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER; + + return d3dx_validate_filter(*filter); +} + +#ifndef MAKEFOURCC +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ + ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 )) +#endif + +#define DDS_PALETTE_SIZE (sizeof(PALETTEENTRY) * 256) + +/* dds_header.flags */ +#define DDS_CAPS 0x1 +#define DDS_HEIGHT 0x2 +#define DDS_WIDTH 0x4 +#define DDS_PITCH 0x8 +#define DDS_PIXELFORMAT 0x1000 +#define DDS_MIPMAPCOUNT 0x20000 +#define DDS_LINEARSIZE 0x80000 +#define DDS_DEPTH 0x800000 + +/* dds_header.caps */ +#define DDSCAPS_ALPHA 0x2 +#define DDS_CAPS_COMPLEX 0x8 +#define DDSCAPS_PALETTE 0x100 +#define DDS_CAPS_TEXTURE 0x1000 +#define DDS_CAPS_MIPMAP 0x400000 + +/* dds_header.caps2 */ +#define DDS_CAPS2_CUBEMAP 0x200 +#define DDS_CAPS2_CUBEMAP_POSITIVEX 0x400 +#define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x800 +#define DDS_CAPS2_CUBEMAP_POSITIVEY 0x1000 +#define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x2000 +#define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x4000 +#define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x8000 +#define DDS_CAPS2_CUBEMAP_ALL_FACES ( DDS_CAPS2_CUBEMAP_POSITIVEX | DDS_CAPS2_CUBEMAP_NEGATIVEX \ + | DDS_CAPS2_CUBEMAP_POSITIVEY | DDS_CAPS2_CUBEMAP_NEGATIVEY \ + | DDS_CAPS2_CUBEMAP_POSITIVEZ | DDS_CAPS2_CUBEMAP_NEGATIVEZ ) +#define DDS_CAPS2_VOLUME 0x200000 + +/* dds_pixel_format.flags */ +#define DDS_PF_ALPHA 0x1 +#define DDS_PF_ALPHA_ONLY 0x2 +#define DDS_PF_FOURCC 0x4 +#define DDS_PF_INDEXED 0x20 +#define DDS_PF_RGB 0x40 +#define DDS_PF_YUV 0x200 +#define DDS_PF_LUMINANCE 0x20000 +#define DDS_PF_BUMPLUMINANCE 0x40000 +#define DDS_PF_BUMPDUDV 0x80000 + +struct dds_pixel_format +{ + DWORD size; + DWORD flags; + DWORD fourcc; + DWORD bpp; + DWORD rmask; + DWORD gmask; + DWORD bmask; + DWORD amask; +}; + +struct dds_header +{ + DWORD signature; + DWORD size; + DWORD flags; + DWORD height; + DWORD width; + DWORD pitch_or_linear_size; + DWORD depth; + DWORD miplevels; + DWORD reserved[11]; + struct dds_pixel_format pixel_format; + DWORD caps; + DWORD caps2; + DWORD caps3; + DWORD caps4; + DWORD reserved2; +}; + +/* These are custom Wine only filter flags. */ +#define D3DX_FILTER_PMA_IN 0x00800000 +#define D3DX_FILTER_PMA_OUT 0x01000000 +#define D3DX_FILTER_PMA 0x01800000 + +struct vec4 +{ + float x, y, z, w; +}; + +enum range { + RANGE_FULL = 0, + RANGE_UNORM = 1, + RANGE_SNORM = 2, +}; + +struct d3dx_color +{ + struct vec4 value; + enum range rgb_range; + enum range a_range; +}; + +static inline void set_d3dx_color(struct d3dx_color *color, const struct vec4 *value, enum range rgb_range, + enum range a_range) +{ + color->value = *value; + color->rgb_range = rgb_range; + color->a_range = a_range; +} + +struct volume +{ + UINT width; + UINT height; + UINT depth; +}; + +static inline void set_volume_struct(struct volume *volume, uint32_t width, uint32_t height, uint32_t depth) +{ + volume->width = width; + volume->height = height; + volume->depth = depth; +} + +enum d3dx_image_file_format +{ + D3DX_IMAGE_FILE_FORMAT_BMP = 0, + D3DX_IMAGE_FILE_FORMAT_JPG = 1, + D3DX_IMAGE_FILE_FORMAT_TGA = 2, + D3DX_IMAGE_FILE_FORMAT_PNG = 3, + D3DX_IMAGE_FILE_FORMAT_DDS = 4, + D3DX_IMAGE_FILE_FORMAT_PPM = 5, + D3DX_IMAGE_FILE_FORMAT_DIB = 6, + D3DX_IMAGE_FILE_FORMAT_HDR = 7, + D3DX_IMAGE_FILE_FORMAT_PFM = 8, + /* TIFF/GIF/WMP are only available on d3dx10/d3dx11. */ + D3DX_IMAGE_FILE_FORMAT_TIFF = 10, + D3DX_IMAGE_FILE_FORMAT_GIF = 11, + D3DX_IMAGE_FILE_FORMAT_WMP = 12, + /* This is a Wine only file format value. */ + D3DX_IMAGE_FILE_FORMAT_DDS_DXT10 = 100, + D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD = 0x7fffffff +}; + +enum d3dx_resource_type +{ + D3DX_RESOURCE_TYPE_UNKNOWN, + D3DX_RESOURCE_TYPE_TEXTURE_1D, + D3DX_RESOURCE_TYPE_TEXTURE_2D, + D3DX_RESOURCE_TYPE_TEXTURE_3D, + D3DX_RESOURCE_TYPE_CUBE_TEXTURE, + D3DX_RESOURCE_TYPE_COUNT, +}; + +/* These values act as indexes into the pixel_format_desc table. */ +enum d3dx_pixel_format_id +{ + D3DX_PIXEL_FORMAT_B8G8R8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM_SRGB, + D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM, + D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM, + D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM_SRGB, + D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM, + D3DX_PIXEL_FORMAT_B5G6R5_UNORM, + D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM, + D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM, + D3DX_PIXEL_FORMAT_B2G3R3_UNORM, + D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM, + D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM, + D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM, + D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM, + D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM, + D3DX_PIXEL_FORMAT_R16G16B16_UNORM, + D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM, + D3DX_PIXEL_FORMAT_R8_UNORM, + D3DX_PIXEL_FORMAT_R8_SNORM, + D3DX_PIXEL_FORMAT_R8G8_UNORM, + D3DX_PIXEL_FORMAT_R16_UNORM, + D3DX_PIXEL_FORMAT_R16G16_UNORM, + D3DX_PIXEL_FORMAT_A8_UNORM, + D3DX_PIXEL_FORMAT_L8A8_UNORM, + D3DX_PIXEL_FORMAT_L4A4_UNORM, + D3DX_PIXEL_FORMAT_L8_UNORM, + D3DX_PIXEL_FORMAT_L16_UNORM, + D3DX_PIXEL_FORMAT_DXT1_UNORM, + D3DX_PIXEL_FORMAT_BC1_UNORM_SRGB, + D3DX_PIXEL_FORMAT_DXT2_UNORM, + D3DX_PIXEL_FORMAT_DXT3_UNORM, + D3DX_PIXEL_FORMAT_BC2_UNORM_SRGB, + D3DX_PIXEL_FORMAT_DXT4_UNORM, + D3DX_PIXEL_FORMAT_DXT5_UNORM, + D3DX_PIXEL_FORMAT_BC3_UNORM_SRGB, + D3DX_PIXEL_FORMAT_BC4_UNORM, + D3DX_PIXEL_FORMAT_BC4_SNORM, + D3DX_PIXEL_FORMAT_BC5_UNORM, + D3DX_PIXEL_FORMAT_BC5_SNORM, + D3DX_PIXEL_FORMAT_R16_FLOAT, + D3DX_PIXEL_FORMAT_R16G16_FLOAT, + D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT, + D3DX_PIXEL_FORMAT_R32_FLOAT, + D3DX_PIXEL_FORMAT_R32G32_FLOAT, + D3DX_PIXEL_FORMAT_R11G11B10_FLOAT, + D3DX_PIXEL_FORMAT_R32G32B32_FLOAT, + D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT, + D3DX_PIXEL_FORMAT_P8_UINT, + D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM, + D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM, + D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM, + D3DX_PIXEL_FORMAT_U8V8_SNORM, + D3DX_PIXEL_FORMAT_U16V16_SNORM, + D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM, + D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM, + D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM, + D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM, + D3DX_PIXEL_FORMAT_UYVY, + D3DX_PIXEL_FORMAT_YUY2, + D3DX_PIXEL_FORMAT_COUNT, +}; + +/* These are aliases. */ +#define D3DX_PIXEL_FORMAT_R16G16B16A16_SNORM D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM +#define D3DX_PIXEL_FORMAT_R16G16_SNORM D3DX_PIXEL_FORMAT_U16V16_SNORM +#define D3DX_PIXEL_FORMAT_R8G8B8A8_SNORM D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM +#define D3DX_PIXEL_FORMAT_R8G8_SNORM D3DX_PIXEL_FORMAT_U8V8_SNORM +#define D3DX_PIXEL_FORMAT_BC1_UNORM D3DX_PIXEL_FORMAT_DXT1_UNORM +#define D3DX_PIXEL_FORMAT_BC2_UNORM D3DX_PIXEL_FORMAT_DXT3_UNORM +#define D3DX_PIXEL_FORMAT_BC3_UNORM D3DX_PIXEL_FORMAT_DXT5_UNORM + + +/* for internal use */ +enum component_type +{ + CTYPE_EMPTY, + CTYPE_UNORM, + CTYPE_SNORM, + CTYPE_FLOAT, + CTYPE_LUMA, + CTYPE_INDEX, +}; + +enum format_flag +{ + FMT_FLAG_DXT = 0x01, + FMT_FLAG_PACKED = 0x02, + /* Internal only format, has no exact D3DFORMAT equivalent. */ + FMT_FLAG_INTERNAL = 0x04, + FMT_FLAG_PM_ALPHA = 0x08, + /* + * For formats that only have a DXGI_FORMAT mapping, no D3DFORMAT + * equivalent. + */ + FMT_FLAG_DXGI = 0x10, + FMT_FLAG_SRGB = 0x20, +}; + +struct pixel_format_desc { + enum d3dx_pixel_format_id format; + BYTE bits[4]; + BYTE shift[4]; + UINT bytes_per_pixel; + UINT block_width; + UINT block_height; + UINT block_byte_count; + enum component_type a_type; + enum component_type rgb_type; + uint32_t flags; +}; + +struct d3dx_pixels +{ + const void *data; + uint32_t row_pitch; + uint32_t slice_pitch; + const PALETTEENTRY *palette; + + struct volume size; + RECT unaligned_rect; +}; + +static inline void set_d3dx_pixels(struct d3dx_pixels *pixels, const void *data, uint32_t row_pitch, + uint32_t slice_pitch, const PALETTEENTRY *palette, uint32_t width, uint32_t height, uint32_t depth, + const RECT *unaligned_rect) +{ + pixels->data = data; + pixels->row_pitch = row_pitch; + pixels->slice_pitch = slice_pitch; + pixels->palette = palette; + set_volume_struct(&pixels->size, width, height, depth); + pixels->unaligned_rect = *unaligned_rect; +} + +#define D3DX_IMAGE_INFO_ONLY 1 +#define D3DX_IMAGE_SUPPORT_DXT10 2 +struct d3dx_image +{ + enum d3dx_resource_type resource_type; + enum d3dx_pixel_format_id format; + + struct volume size; + uint32_t mip_levels; + uint32_t layer_count; + + BYTE *pixels; + PALETTEENTRY *palette; + uint32_t layer_pitch; + + /* + * image_buf and image_palette are pointers to allocated memory used to store + * image data. If they are non-NULL, they need to be freed when no longer + * in use. + */ + void *image_buf; + PALETTEENTRY *image_palette; + + enum d3dx_image_file_format image_file_format; +}; + +HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, + uint32_t starting_mip_level, uint32_t flags); +void d3dx_image_cleanup(struct d3dx_image *image); +HRESULT d3dx_image_get_pixels(struct d3dx_image *image, uint32_t layer, uint32_t mip_level, + struct d3dx_pixels *pixels); + +static inline BOOL is_unknown_format(const struct pixel_format_desc *format) +{ + return (format->format == D3DX_PIXEL_FORMAT_COUNT); +} + +static inline BOOL is_index_format(const struct pixel_format_desc *format) +{ + return (format->a_type == CTYPE_INDEX || format->rgb_type == CTYPE_INDEX); +} + +static inline BOOL is_compressed_format(const struct pixel_format_desc *format) +{ + return !!(format->flags & FMT_FLAG_DXT); +} + +static inline BOOL is_packed_format(const struct pixel_format_desc *format) +{ + return !!(format->flags & FMT_FLAG_PACKED); +} + +static inline BOOL format_types_match(const struct pixel_format_desc *src, const struct pixel_format_desc *dst) +{ + if ((src->a_type && dst->a_type) && (src->a_type != dst->a_type)) + return FALSE; + + if ((src->rgb_type && dst->rgb_type) && (src->rgb_type != dst->rgb_type)) + return FALSE; + + if (src->flags != dst->flags) + return FALSE; + + return (src->rgb_type == dst->rgb_type || src->a_type == dst->a_type); +} + +static inline BOOL is_internal_format(const struct pixel_format_desc *format) +{ + return !!(format->flags & FMT_FLAG_INTERNAL); +} + +static inline BOOL is_dxgi_format(const struct pixel_format_desc *format) +{ + return !!(format->flags & FMT_FLAG_DXGI); +} + +static inline BOOL filter_flags_match(uint32_t filter_flags) +{ + if (!!(filter_flags & D3DX_FILTER_PMA_IN) != !!((filter_flags & D3DX_FILTER_PMA_OUT))) + return FALSE; + if (!!(filter_flags & D3DX_FILTER_SRGB_IN) != !!((filter_flags & D3DX_FILTER_SRGB_OUT))) + return FALSE; + + return TRUE; +} + +static inline BOOL is_conversion_from_supported(const struct pixel_format_desc *format) +{ + return !is_packed_format(format) && !is_unknown_format(format); +} + +static inline BOOL is_conversion_to_supported(const struct pixel_format_desc *format) +{ + return !is_index_format(format) && !is_packed_format(format) && !is_unknown_format(format); +} + +const struct pixel_format_desc *get_d3dx_pixel_format_info(enum d3dx_pixel_format_id format); +HRESULT dds_pixel_format_from_d3dx_pixel_format_id(struct dds_pixel_format *pixel_format, + enum d3dx_pixel_format_id d3dx_pixel_format); + +void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *src, const PALETTEENTRY *palette, + struct d3dx_color *dst); +void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst); + +void d3dx_get_next_mip_level_size(struct volume *size); +void d3dx_get_mip_level_size(struct volume *size, uint32_t level); +uint32_t d3dx_get_max_mip_levels_for_size(uint32_t width, uint32_t height, uint32_t depth); +HRESULT d3dx_calculate_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, + uint32_t *pitch, uint32_t *size); +uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, uint32_t depth, + uint32_t mip_levels); +HRESULT d3dx_create_dds_file_blob(enum d3dx_pixel_format_id format, const PALETTEENTRY *palette, + enum d3dx_resource_type resource_type, const struct volume *size, uint32_t mip_levels, uint32_t layers, + BOOL support_dxt10, ID3DXBlob **out_blob); +HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, + enum d3dx_image_file_format file_format, enum d3dx_pixel_format_id dst_format, ID3DXBlob **dst_blob); +HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, + const PALETTEENTRY *palette, enum d3dx_pixel_format_id format, uint32_t left, uint32_t top, uint32_t right, + uint32_t bottom, uint32_t front, uint32_t back, struct d3dx_pixels *pixels); +HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, + const struct pixel_format_desc *dst_desc, struct d3dx_pixels *src_pixels, + const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key); +void get_aligned_rect(uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t width, uint32_t height, + const struct pixel_format_desc *fmt_desc, RECT *aligned_rect); + +unsigned short float_32_to_16(const float in); +float float_16_to_32(const unsigned short in); +/* debug helpers */ +const char *debug_d3dx_image_file_format(enum d3dx_image_file_format format); + +HRESULT write_buffer_to_file(const WCHAR *filename, ID3DXBlob *buffer); +HRESULT load_file(const WCHAR *path, void **data, DWORD *size); +HRESULT load_resource(HMODULE module, HRSRC rsrc, void **data, DWORD *size); +HRESULT load_resourceW(HMODULE module, const WCHAR *resource, void **data, DWORD *size); +HRESULT load_resourceA(HMODULE module, const char *resource, void **data, DWORD *size); +HRESULT load_resource_initA(HMODULE module, const char *resource, HRSRC *rsrc); +HRESULT load_resource_initW(HMODULE module, const WCHAR *resource, HRSRC *rsrc); +#endif /* __WINE_D3DX_HELPERS_H */ diff --git a/dlls/d3dx9_36/effect.c b/dlls/d3dx9_36/effect.c index 628d8ebc3eb9..a89dc679a77a 100644 --- a/dlls/d3dx9_36/effect.c +++ b/dlls/d3dx9_36/effect.c @@ -1943,6 +1943,7 @@ static void d3dx_pool_release_shared_parameter(struct d3dx_top_level_parameter * else { free(param->shared_data->parameters); + param->shared_data->parameters = NULL; /* Zeroing table size is required as the entry in pool parameters table can be reused. */ param->shared_data->size = 0; param->shared_data = NULL; diff --git a/dlls/d3dx9_36/math.c b/dlls/d3dx9_36/math.c index 92eb8f68f142..ac384213e294 100644 --- a/dlls/d3dx9_36/math.c +++ b/dlls/d3dx9_36/math.c @@ -2099,91 +2099,6 @@ D3DXVECTOR4* WINAPI D3DXVec4TransformArray(D3DXVECTOR4* out, UINT outstride, con return out; } -unsigned short float_32_to_16(const float in) -{ - int exp = 0, origexp; - float tmp = fabsf(in); - int sign = (copysignf(1, in) < 0); - unsigned int mantissa; - unsigned short ret; - - /* Deal with special numbers */ - if (isinf(in)) return (sign ? 0xffff : 0x7fff); - if (isnan(in)) return (sign ? 0xffff : 0x7fff); - if (in == 0.0f) return (sign ? 0x8000 : 0x0000); - - if (tmp < (float)(1u << 10)) - { - do - { - tmp *= 2.0f; - exp--; - } while (tmp < (float)(1u << 10)); - } - else if (tmp >= (float)(1u << 11)) - { - do - { - tmp /= 2.0f; - exp++; - } while (tmp >= (float)(1u << 11)); - } - - exp += 10; /* Normalize the mantissa */ - exp += 15; /* Exponent is encoded with excess 15 */ - - origexp = exp; - - mantissa = (unsigned int) tmp; - if ((tmp - mantissa == 0.5f && mantissa % 2 == 1) || /* round half to even */ - (tmp - mantissa > 0.5f)) - { - mantissa++; /* round to nearest, away from zero */ - } - if (mantissa == 2048) - { - mantissa = 1024; - exp++; - } - - if (exp > 31) - { - /* too big */ - ret = 0x7fff; /* INF */ - } - else if (exp <= 0) - { - unsigned int rounding = 0; - - /* Denormalized half float */ - - /* return 0x0000 (=0.0) for numbers too small to represent in half floats */ - if (exp < -11) - return (sign ? 0x8000 : 0x0000); - - exp = origexp; - - /* the 13 extra bits from single precision are used for rounding */ - mantissa = (unsigned int)(tmp * (1u << 13)); - mantissa >>= 1 - exp; /* denormalize */ - - mantissa -= ~(mantissa >> 13) & 1; /* round half to even */ - /* remove 13 least significant bits to get half float precision */ - mantissa >>= 12; - rounding = mantissa & 1; - mantissa >>= 1; - - ret = mantissa + rounding; - } - else - { - ret = (exp << 10) | (mantissa & 0x3ff); - } - - ret |= ((sign ? 1 : 0) << 15); /* Add the sign */ - return ret; -} - D3DXFLOAT16 *WINAPI D3DXFloat32To16Array(D3DXFLOAT16 *pout, const FLOAT *pin, UINT n) { unsigned int i; @@ -2198,26 +2113,6 @@ D3DXFLOAT16 *WINAPI D3DXFloat32To16Array(D3DXFLOAT16 *pout, const FLOAT *pin, UI return pout; } -/* Native d3dx9's D3DXFloat16to32Array lacks support for NaN and Inf. Specifically, e = 16 is treated as a - * regular number - e.g., 0x7fff is converted to 131008.0 and 0xffff to -131008.0. */ -float float_16_to_32(const unsigned short in) -{ - const unsigned short s = (in & 0x8000); - const unsigned short e = (in & 0x7C00) >> 10; - const unsigned short m = in & 0x3FF; - const float sgn = (s ? -1.0f : 1.0f); - - if (e == 0) - { - if (m == 0) return sgn * 0.0f; /* +0.0 or -0.0 */ - else return sgn * powf(2, -14.0f) * (m / 1024.0f); - } - else - { - return sgn * powf(2, e - 15.0f) * (1.0f + (m / 1024.0f)); - } -} - FLOAT *WINAPI D3DXFloat16To32Array(FLOAT *pout, const D3DXFLOAT16 *pin, UINT n) { unsigned int i; diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index 23ab7b597080..578bc5f51028 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -7631,6 +7631,24 @@ HRESULT WINAPI D3DXComputeTangentFrameEx(ID3DXMesh *mesh, DWORD texture_in_seman return hr; } +/************************************************************************* + * D3DXComputeTangent (D3DX9_36.@) + */ +HRESULT WINAPI D3DXComputeTangent(ID3DXMesh *mesh, DWORD stage_idx, DWORD tangent_idx, + DWORD binorm_idx, DWORD wrap, const DWORD *adjacency) +{ + TRACE("mesh %p, stage_idx %ld, tangent_idx %ld, binorm_idx %ld, wrap %ld, adjacency %p.\n", + mesh, stage_idx, tangent_idx, binorm_idx, wrap, adjacency); + + return D3DXComputeTangentFrameEx( mesh, D3DDECLUSAGE_TEXCOORD, stage_idx, + ( binorm_idx == D3DX_DEFAULT ) ? D3DX_DEFAULT : D3DDECLUSAGE_BINORMAL, + binorm_idx, + ( tangent_idx == D3DX_DEFAULT ) ? D3DX_DEFAULT : D3DDECLUSAGE_TANGENT, + tangent_idx, D3DX_DEFAULT, 0, + ( wrap ? D3DXTANGENT_WRAP_UV : 0 ) | D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_ORTHOGONALIZE_FROM_U, + adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL); +} + /************************************************************************* * D3DXComputeNormals (D3DX9_36.@) */ diff --git a/dlls/d3dx9_36/stb_dxt.h b/dlls/d3dx9_36/stb_dxt.h new file mode 100644 index 000000000000..c80a5e1bb5f5 --- /dev/null +++ b/dlls/d3dx9_36/stb_dxt.h @@ -0,0 +1,729 @@ +// stb_dxt.h - v1.12 - DXT1/DXT5 compressor - public domain +// original by fabian "ryg" giesen - ported to C by stb +// use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation +// +// USAGE: +// call stb_compress_dxt_block() for every block (you must pad) +// source should be a 4x4 block of RGBA data in row-major order; +// Alpha channel is not stored if you specify alpha=0 (but you +// must supply some constant alpha in the alpha channel). +// You can turn on dithering and "high quality" using mode. +// +// version history: +// v1.12 - (ryg) fix bug in single-color table generator +// v1.11 - (ryg) avoid racy global init, better single-color tables, remove dither +// v1.10 - (i.c) various small quality improvements +// v1.09 - (stb) update documentation re: surprising alpha channel requirement +// v1.08 - (stb) fix bug in dxt-with-alpha block +// v1.07 - (stb) bc4; allow not using libc; add STB_DXT_STATIC +// v1.06 - (stb) fix to known-broken 1.05 +// v1.05 - (stb) support bc5/3dc (Arvids Kokins), use extern "C" in C++ (Pavel Krajcevski) +// v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec); +// single color match fix (allow for inexact color interpolation); +// optimal DXT5 index finder; "high quality" mode that runs multiple refinement steps. +// v1.03 - (stb) endianness support +// v1.02 - (stb) fix alpha encoding bug +// v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom +// v1.00 - (stb) first release +// +// contributors: +// Rich Geldreich (more accurate index selection) +// Kevin Schmidt (#defines for "freestanding" compilation) +// github:ppiastucki (BC4 support) +// Ignacio Castano - improve DXT endpoint quantization +// Alan Hickman - static table initialization +// +// LICENSE +// +// See end of file for license information. + +#ifndef STB_INCLUDE_STB_DXT_H +#define STB_INCLUDE_STB_DXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STB_DXT_STATIC +#define STBDDEF static +#else +#define STBDDEF extern +#endif + +// compression mode (bitflags) +#define STB_DXT_NORMAL 0 +#define STB_DXT_DITHER 1 // use dithering. was always dubious, now deprecated. does nothing! +#define STB_DXT_HIGHQUAL 2 // high quality mode, does two refinement steps instead of 1. ~30-40% slower. + +STBDDEF void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode); +STBDDEF void stb_compress_bc4_block(unsigned char *dest, const unsigned char *src_r_one_byte_per_pixel); +STBDDEF void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel); + +#define STB_COMPRESS_DXT_BLOCK + +#ifdef __cplusplus +} +#endif +#endif // STB_INCLUDE_STB_DXT_H + +#ifdef STB_DXT_IMPLEMENTATION + +// configuration options for DXT encoder. set them in the project/makefile or just define +// them at the top. + +// STB_DXT_USE_ROUNDING_BIAS +// use a rounding bias during color interpolation. this is closer to what "ideal" +// interpolation would do but doesn't match the S3TC/DX10 spec. old versions (pre-1.03) +// implicitly had this turned on. +// +// in case you're targeting a specific type of hardware (e.g. console programmers): +// NVidia and Intel GPUs (as of 2010) as well as DX9 ref use DXT decoders that are closer +// to STB_DXT_USE_ROUNDING_BIAS. AMD/ATI, S3 and DX10 ref are closer to rounding with no bias. +// you also see "(a*5 + b*3) / 8" on some old GPU designs. +// #define STB_DXT_USE_ROUNDING_BIAS + +#include + +#if !defined(STBD_FABS) +#include +#endif + +#ifndef STBD_FABS +#define STBD_FABS(x) fabs(x) +#endif + +static const unsigned char stb__OMatch5[256][2] = { + { 0, 0 }, { 0, 0 }, { 0, 1 }, { 0, 1 }, { 1, 0 }, { 1, 0 }, { 1, 0 }, { 1, 1 }, + { 1, 1 }, { 1, 1 }, { 1, 2 }, { 0, 4 }, { 2, 1 }, { 2, 1 }, { 2, 1 }, { 2, 2 }, + { 2, 2 }, { 2, 2 }, { 2, 3 }, { 1, 5 }, { 3, 2 }, { 3, 2 }, { 4, 0 }, { 3, 3 }, + { 3, 3 }, { 3, 3 }, { 3, 4 }, { 3, 4 }, { 3, 4 }, { 3, 5 }, { 4, 3 }, { 4, 3 }, + { 5, 2 }, { 4, 4 }, { 4, 4 }, { 4, 5 }, { 4, 5 }, { 5, 4 }, { 5, 4 }, { 5, 4 }, + { 6, 3 }, { 5, 5 }, { 5, 5 }, { 5, 6 }, { 4, 8 }, { 6, 5 }, { 6, 5 }, { 6, 5 }, + { 6, 6 }, { 6, 6 }, { 6, 6 }, { 6, 7 }, { 5, 9 }, { 7, 6 }, { 7, 6 }, { 8, 4 }, + { 7, 7 }, { 7, 7 }, { 7, 7 }, { 7, 8 }, { 7, 8 }, { 7, 8 }, { 7, 9 }, { 8, 7 }, + { 8, 7 }, { 9, 6 }, { 8, 8 }, { 8, 8 }, { 8, 9 }, { 8, 9 }, { 9, 8 }, { 9, 8 }, + { 9, 8 }, { 10, 7 }, { 9, 9 }, { 9, 9 }, { 9, 10 }, { 8, 12 }, { 10, 9 }, { 10, 9 }, + { 10, 9 }, { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 11 }, { 9, 13 }, { 11, 10 }, { 11, 10 }, + { 12, 8 }, { 11, 11 }, { 11, 11 }, { 11, 11 }, { 11, 12 }, { 11, 12 }, { 11, 12 }, { 11, 13 }, + { 12, 11 }, { 12, 11 }, { 13, 10 }, { 12, 12 }, { 12, 12 }, { 12, 13 }, { 12, 13 }, { 13, 12 }, + { 13, 12 }, { 13, 12 }, { 14, 11 }, { 13, 13 }, { 13, 13 }, { 13, 14 }, { 12, 16 }, { 14, 13 }, + { 14, 13 }, { 14, 13 }, { 14, 14 }, { 14, 14 }, { 14, 14 }, { 14, 15 }, { 13, 17 }, { 15, 14 }, + { 15, 14 }, { 16, 12 }, { 15, 15 }, { 15, 15 }, { 15, 15 }, { 15, 16 }, { 15, 16 }, { 15, 16 }, + { 15, 17 }, { 16, 15 }, { 16, 15 }, { 17, 14 }, { 16, 16 }, { 16, 16 }, { 16, 17 }, { 16, 17 }, + { 17, 16 }, { 17, 16 }, { 17, 16 }, { 18, 15 }, { 17, 17 }, { 17, 17 }, { 17, 18 }, { 16, 20 }, + { 18, 17 }, { 18, 17 }, { 18, 17 }, { 18, 18 }, { 18, 18 }, { 18, 18 }, { 18, 19 }, { 17, 21 }, + { 19, 18 }, { 19, 18 }, { 20, 16 }, { 19, 19 }, { 19, 19 }, { 19, 19 }, { 19, 20 }, { 19, 20 }, + { 19, 20 }, { 19, 21 }, { 20, 19 }, { 20, 19 }, { 21, 18 }, { 20, 20 }, { 20, 20 }, { 20, 21 }, + { 20, 21 }, { 21, 20 }, { 21, 20 }, { 21, 20 }, { 22, 19 }, { 21, 21 }, { 21, 21 }, { 21, 22 }, + { 20, 24 }, { 22, 21 }, { 22, 21 }, { 22, 21 }, { 22, 22 }, { 22, 22 }, { 22, 22 }, { 22, 23 }, + { 21, 25 }, { 23, 22 }, { 23, 22 }, { 24, 20 }, { 23, 23 }, { 23, 23 }, { 23, 23 }, { 23, 24 }, + { 23, 24 }, { 23, 24 }, { 23, 25 }, { 24, 23 }, { 24, 23 }, { 25, 22 }, { 24, 24 }, { 24, 24 }, + { 24, 25 }, { 24, 25 }, { 25, 24 }, { 25, 24 }, { 25, 24 }, { 26, 23 }, { 25, 25 }, { 25, 25 }, + { 25, 26 }, { 24, 28 }, { 26, 25 }, { 26, 25 }, { 26, 25 }, { 26, 26 }, { 26, 26 }, { 26, 26 }, + { 26, 27 }, { 25, 29 }, { 27, 26 }, { 27, 26 }, { 28, 24 }, { 27, 27 }, { 27, 27 }, { 27, 27 }, + { 27, 28 }, { 27, 28 }, { 27, 28 }, { 27, 29 }, { 28, 27 }, { 28, 27 }, { 29, 26 }, { 28, 28 }, + { 28, 28 }, { 28, 29 }, { 28, 29 }, { 29, 28 }, { 29, 28 }, { 29, 28 }, { 30, 27 }, { 29, 29 }, + { 29, 29 }, { 29, 30 }, { 29, 30 }, { 30, 29 }, { 30, 29 }, { 30, 29 }, { 30, 30 }, { 30, 30 }, + { 30, 30 }, { 30, 31 }, { 30, 31 }, { 31, 30 }, { 31, 30 }, { 31, 30 }, { 31, 31 }, { 31, 31 }, +}; +static const unsigned char stb__OMatch6[256][2] = { + { 0, 0 }, { 0, 1 }, { 1, 0 }, { 1, 1 }, { 1, 1 }, { 1, 2 }, { 2, 1 }, { 2, 2 }, + { 2, 2 }, { 2, 3 }, { 3, 2 }, { 3, 3 }, { 3, 3 }, { 3, 4 }, { 4, 3 }, { 4, 4 }, + { 4, 4 }, { 4, 5 }, { 5, 4 }, { 5, 5 }, { 5, 5 }, { 5, 6 }, { 6, 5 }, { 6, 6 }, + { 6, 6 }, { 6, 7 }, { 7, 6 }, { 7, 7 }, { 7, 7 }, { 7, 8 }, { 8, 7 }, { 8, 8 }, + { 8, 8 }, { 8, 9 }, { 9, 8 }, { 9, 9 }, { 9, 9 }, { 9, 10 }, { 10, 9 }, { 10, 10 }, + { 10, 10 }, { 10, 11 }, { 11, 10 }, { 8, 16 }, { 11, 11 }, { 11, 12 }, { 12, 11 }, { 9, 17 }, + { 12, 12 }, { 12, 13 }, { 13, 12 }, { 11, 16 }, { 13, 13 }, { 13, 14 }, { 14, 13 }, { 12, 17 }, + { 14, 14 }, { 14, 15 }, { 15, 14 }, { 14, 16 }, { 15, 15 }, { 15, 16 }, { 16, 14 }, { 16, 15 }, + { 17, 14 }, { 16, 16 }, { 16, 17 }, { 17, 16 }, { 18, 15 }, { 17, 17 }, { 17, 18 }, { 18, 17 }, + { 20, 14 }, { 18, 18 }, { 18, 19 }, { 19, 18 }, { 21, 15 }, { 19, 19 }, { 19, 20 }, { 20, 19 }, + { 20, 20 }, { 20, 20 }, { 20, 21 }, { 21, 20 }, { 21, 21 }, { 21, 21 }, { 21, 22 }, { 22, 21 }, + { 22, 22 }, { 22, 22 }, { 22, 23 }, { 23, 22 }, { 23, 23 }, { 23, 23 }, { 23, 24 }, { 24, 23 }, + { 24, 24 }, { 24, 24 }, { 24, 25 }, { 25, 24 }, { 25, 25 }, { 25, 25 }, { 25, 26 }, { 26, 25 }, + { 26, 26 }, { 26, 26 }, { 26, 27 }, { 27, 26 }, { 24, 32 }, { 27, 27 }, { 27, 28 }, { 28, 27 }, + { 25, 33 }, { 28, 28 }, { 28, 29 }, { 29, 28 }, { 27, 32 }, { 29, 29 }, { 29, 30 }, { 30, 29 }, + { 28, 33 }, { 30, 30 }, { 30, 31 }, { 31, 30 }, { 30, 32 }, { 31, 31 }, { 31, 32 }, { 32, 30 }, + { 32, 31 }, { 33, 30 }, { 32, 32 }, { 32, 33 }, { 33, 32 }, { 34, 31 }, { 33, 33 }, { 33, 34 }, + { 34, 33 }, { 36, 30 }, { 34, 34 }, { 34, 35 }, { 35, 34 }, { 37, 31 }, { 35, 35 }, { 35, 36 }, + { 36, 35 }, { 36, 36 }, { 36, 36 }, { 36, 37 }, { 37, 36 }, { 37, 37 }, { 37, 37 }, { 37, 38 }, + { 38, 37 }, { 38, 38 }, { 38, 38 }, { 38, 39 }, { 39, 38 }, { 39, 39 }, { 39, 39 }, { 39, 40 }, + { 40, 39 }, { 40, 40 }, { 40, 40 }, { 40, 41 }, { 41, 40 }, { 41, 41 }, { 41, 41 }, { 41, 42 }, + { 42, 41 }, { 42, 42 }, { 42, 42 }, { 42, 43 }, { 43, 42 }, { 40, 48 }, { 43, 43 }, { 43, 44 }, + { 44, 43 }, { 41, 49 }, { 44, 44 }, { 44, 45 }, { 45, 44 }, { 43, 48 }, { 45, 45 }, { 45, 46 }, + { 46, 45 }, { 44, 49 }, { 46, 46 }, { 46, 47 }, { 47, 46 }, { 46, 48 }, { 47, 47 }, { 47, 48 }, + { 48, 46 }, { 48, 47 }, { 49, 46 }, { 48, 48 }, { 48, 49 }, { 49, 48 }, { 50, 47 }, { 49, 49 }, + { 49, 50 }, { 50, 49 }, { 52, 46 }, { 50, 50 }, { 50, 51 }, { 51, 50 }, { 53, 47 }, { 51, 51 }, + { 51, 52 }, { 52, 51 }, { 52, 52 }, { 52, 52 }, { 52, 53 }, { 53, 52 }, { 53, 53 }, { 53, 53 }, + { 53, 54 }, { 54, 53 }, { 54, 54 }, { 54, 54 }, { 54, 55 }, { 55, 54 }, { 55, 55 }, { 55, 55 }, + { 55, 56 }, { 56, 55 }, { 56, 56 }, { 56, 56 }, { 56, 57 }, { 57, 56 }, { 57, 57 }, { 57, 57 }, + { 57, 58 }, { 58, 57 }, { 58, 58 }, { 58, 58 }, { 58, 59 }, { 59, 58 }, { 59, 59 }, { 59, 59 }, + { 59, 60 }, { 60, 59 }, { 60, 60 }, { 60, 60 }, { 60, 61 }, { 61, 60 }, { 61, 61 }, { 61, 61 }, + { 61, 62 }, { 62, 61 }, { 62, 62 }, { 62, 62 }, { 62, 63 }, { 63, 62 }, { 63, 63 }, { 63, 63 }, +}; + +static int stb__Mul8Bit(int a, int b) +{ + int t = a*b + 128; + return (t + (t >> 8)) >> 8; +} + +static void stb__From16Bit(unsigned char *out, unsigned short v) +{ + int rv = (v & 0xf800) >> 11; + int gv = (v & 0x07e0) >> 5; + int bv = (v & 0x001f) >> 0; + + // expand to 8 bits via bit replication + out[0] = (rv * 33) >> 2; + out[1] = (gv * 65) >> 4; + out[2] = (bv * 33) >> 2; + out[3] = 0; +} + +static unsigned short stb__As16Bit(int r, int g, int b) +{ + return (unsigned short)((stb__Mul8Bit(r,31) << 11) + (stb__Mul8Bit(g,63) << 5) + stb__Mul8Bit(b,31)); +} + +// linear interpolation at 1/3 point between a and b, using desired rounding type +static int stb__Lerp13(int a, int b) +{ +#ifdef STB_DXT_USE_ROUNDING_BIAS + // with rounding bias + return a + stb__Mul8Bit(b-a, 0x55); +#else + // without rounding bias + // replace "/ 3" by "* 0xaaab) >> 17" if your compiler sucks or you really need every ounce of speed. + return (2*a + b) / 3; +#endif +} + +// lerp RGB color +static void stb__Lerp13RGB(unsigned char *out, unsigned char *p1, unsigned char *p2) +{ + out[0] = (unsigned char)stb__Lerp13(p1[0], p2[0]); + out[1] = (unsigned char)stb__Lerp13(p1[1], p2[1]); + out[2] = (unsigned char)stb__Lerp13(p1[2], p2[2]); +} + +/****************************************************************************/ + +static void stb__EvalColors(unsigned char *color,unsigned short c0,unsigned short c1) +{ + stb__From16Bit(color+ 0, c0); + stb__From16Bit(color+ 4, c1); + stb__Lerp13RGB(color+ 8, color+0, color+4); + stb__Lerp13RGB(color+12, color+4, color+0); +} + +// The color matching function +static unsigned int stb__MatchColorsBlock(unsigned char *block, unsigned char *color) +{ + unsigned int mask = 0; + int dirr = color[0*4+0] - color[1*4+0]; + int dirg = color[0*4+1] - color[1*4+1]; + int dirb = color[0*4+2] - color[1*4+2]; + int dots[16]; + int stops[4]; + int i; + int c0Point, halfPoint, c3Point; + + for(i=0;i<16;i++) + dots[i] = block[i*4+0]*dirr + block[i*4+1]*dirg + block[i*4+2]*dirb; + + for(i=0;i<4;i++) + stops[i] = color[i*4+0]*dirr + color[i*4+1]*dirg + color[i*4+2]*dirb; + + // think of the colors as arranged on a line; project point onto that line, then choose + // next color out of available ones. we compute the crossover points for "best color in top + // half"/"best in bottom half" and then the same inside that subinterval. + // + // relying on this 1d approximation isn't always optimal in terms of euclidean distance, + // but it's very close and a lot faster. + // http://cbloomrants.blogspot.com/2008/12/12-08-08-dxtc-summary.html + + c0Point = (stops[1] + stops[3]); + halfPoint = (stops[3] + stops[2]); + c3Point = (stops[2] + stops[0]); + + for (i=15;i>=0;i--) { + int dot = dots[i]*2; + mask <<= 2; + + if(dot < halfPoint) + mask |= (dot < c0Point) ? 1 : 3; + else + mask |= (dot < c3Point) ? 2 : 0; + } + + return mask; +} + +// The color optimization function. (Clever code, part 1) +static void stb__OptimizeColorsBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16) +{ + int mind,maxd; + unsigned char *minp, *maxp; + double magn; + int v_r,v_g,v_b; + static const int nIterPower = 4; + float covf[6],vfr,vfg,vfb; + + // determine color distribution + int cov[6]; + int mu[3],min[3],max[3]; + int ch,i,iter; + + for(ch=0;ch<3;ch++) + { + const unsigned char *bp = ((const unsigned char *) block) + ch; + int muv,minv,maxv; + + muv = minv = maxv = bp[0]; + for(i=4;i<64;i+=4) + { + muv += bp[i]; + if (bp[i] < minv) minv = bp[i]; + else if (bp[i] > maxv) maxv = bp[i]; + } + + mu[ch] = (muv + 8) >> 4; + min[ch] = minv; + max[ch] = maxv; + } + + // determine covariance matrix + for (i=0;i<6;i++) + cov[i] = 0; + + for (i=0;i<16;i++) + { + int r = block[i*4+0] - mu[0]; + int g = block[i*4+1] - mu[1]; + int b = block[i*4+2] - mu[2]; + + cov[0] += r*r; + cov[1] += r*g; + cov[2] += r*b; + cov[3] += g*g; + cov[4] += g*b; + cov[5] += b*b; + } + + // convert covariance matrix to float, find principal axis via power iter + for(i=0;i<6;i++) + covf[i] = cov[i] / 255.0f; + + vfr = (float) (max[0] - min[0]); + vfg = (float) (max[1] - min[1]); + vfb = (float) (max[2] - min[2]); + + for(iter=0;iter magn) magn = STBD_FABS(vfg); + if (STBD_FABS(vfb) > magn) magn = STBD_FABS(vfb); + + if(magn < 4.0f) { // too small, default to luminance + v_r = 299; // JPEG YCbCr luma coefs, scaled by 1000. + v_g = 587; + v_b = 114; + } else { + magn = 512.0 / magn; + v_r = (int) (vfr * magn); + v_g = (int) (vfg * magn); + v_b = (int) (vfb * magn); + } + + minp = maxp = block; + mind = maxd = block[0]*v_r + block[1]*v_g + block[2]*v_b; + // Pick colors at extreme points + for(i=1;i<16;i++) + { + int dot = block[i*4+0]*v_r + block[i*4+1]*v_g + block[i*4+2]*v_b; + + if (dot < mind) { + mind = dot; + minp = block+i*4; + } + + if (dot > maxd) { + maxd = dot; + maxp = block+i*4; + } + } + + *pmax16 = stb__As16Bit(maxp[0],maxp[1],maxp[2]); + *pmin16 = stb__As16Bit(minp[0],minp[1],minp[2]); +} + +static const float stb__midpoints5[32] = { + 0.015686f, 0.047059f, 0.078431f, 0.111765f, 0.145098f, 0.176471f, 0.207843f, 0.241176f, 0.274510f, 0.305882f, 0.337255f, 0.370588f, 0.403922f, 0.435294f, 0.466667f, 0.5f, + 0.533333f, 0.564706f, 0.596078f, 0.629412f, 0.662745f, 0.694118f, 0.725490f, 0.758824f, 0.792157f, 0.823529f, 0.854902f, 0.888235f, 0.921569f, 0.952941f, 0.984314f, 1.0f +}; + +static const float stb__midpoints6[64] = { + 0.007843f, 0.023529f, 0.039216f, 0.054902f, 0.070588f, 0.086275f, 0.101961f, 0.117647f, 0.133333f, 0.149020f, 0.164706f, 0.180392f, 0.196078f, 0.211765f, 0.227451f, 0.245098f, + 0.262745f, 0.278431f, 0.294118f, 0.309804f, 0.325490f, 0.341176f, 0.356863f, 0.372549f, 0.388235f, 0.403922f, 0.419608f, 0.435294f, 0.450980f, 0.466667f, 0.482353f, 0.500000f, + 0.517647f, 0.533333f, 0.549020f, 0.564706f, 0.580392f, 0.596078f, 0.611765f, 0.627451f, 0.643137f, 0.658824f, 0.674510f, 0.690196f, 0.705882f, 0.721569f, 0.737255f, 0.754902f, + 0.772549f, 0.788235f, 0.803922f, 0.819608f, 0.835294f, 0.850980f, 0.866667f, 0.882353f, 0.898039f, 0.913725f, 0.929412f, 0.945098f, 0.960784f, 0.976471f, 0.992157f, 1.0f +}; + +static unsigned short stb__Quantize5(float x) +{ + unsigned short q; + x = x < 0 ? 0 : x > 1 ? 1 : x; // saturate + q = (unsigned short)(x * 31); + q += (x > stb__midpoints5[q]); + return q; +} + +static unsigned short stb__Quantize6(float x) +{ + unsigned short q; + x = x < 0 ? 0 : x > 1 ? 1 : x; // saturate + q = (unsigned short)(x * 63); + q += (x > stb__midpoints6[q]); + return q; +} + +// The refinement function. (Clever code, part 2) +// Tries to optimize colors to suit block contents better. +// (By solving a least squares system via normal equations+Cramer's rule) +static int stb__RefineBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16, unsigned int mask) +{ + static const int w1Tab[4] = { 3,0,2,1 }; + static const int prods[4] = { 0x090000,0x000900,0x040102,0x010402 }; + // ^some magic to save a lot of multiplies in the accumulating loop... + // (precomputed products of weights for least squares system, accumulated inside one 32-bit register) + + float f; + unsigned short oldMin, oldMax, min16, max16; + int i, akku = 0, xx,xy,yy; + int At1_r,At1_g,At1_b; + int At2_r,At2_g,At2_b; + unsigned int cm = mask; + + oldMin = *pmin16; + oldMax = *pmax16; + + if((mask ^ (mask<<2)) < 4) // all pixels have the same index? + { + // yes, linear system would be singular; solve using optimal + // single-color match on average color + int r = 8, g = 8, b = 8; + for (i=0;i<16;++i) { + r += block[i*4+0]; + g += block[i*4+1]; + b += block[i*4+2]; + } + + r >>= 4; g >>= 4; b >>= 4; + + max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0]; + min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1]; + } else { + At1_r = At1_g = At1_b = 0; + At2_r = At2_g = At2_b = 0; + for (i=0;i<16;++i,cm>>=2) { + int step = cm&3; + int w1 = w1Tab[step]; + int r = block[i*4+0]; + int g = block[i*4+1]; + int b = block[i*4+2]; + + akku += prods[step]; + At1_r += w1*r; + At1_g += w1*g; + At1_b += w1*b; + At2_r += r; + At2_g += g; + At2_b += b; + } + + At2_r = 3*At2_r - At1_r; + At2_g = 3*At2_g - At1_g; + At2_b = 3*At2_b - At1_b; + + // extract solutions and decide solvability + xx = akku >> 16; + yy = (akku >> 8) & 0xff; + xy = (akku >> 0) & 0xff; + + f = 3.0f / 255.0f / (xx*yy - xy*xy); + + max16 = stb__Quantize5((At1_r*yy - At2_r * xy) * f) << 11; + max16 |= stb__Quantize6((At1_g*yy - At2_g * xy) * f) << 5; + max16 |= stb__Quantize5((At1_b*yy - At2_b * xy) * f) << 0; + + min16 = stb__Quantize5((At2_r*xx - At1_r * xy) * f) << 11; + min16 |= stb__Quantize6((At2_g*xx - At1_g * xy) * f) << 5; + min16 |= stb__Quantize5((At2_b*xx - At1_b * xy) * f) << 0; + } + + *pmin16 = min16; + *pmax16 = max16; + return oldMin != min16 || oldMax != max16; +} + +// Color block compression +static void stb__CompressColorBlock(unsigned char *dest, unsigned char *block, int mode) +{ + unsigned int mask; + int i; + int refinecount; + unsigned short max16, min16; + unsigned char color[4*4]; + + refinecount = (mode & STB_DXT_HIGHQUAL) ? 2 : 1; + + // check if block is constant + for (i=1;i<16;i++) + if (((unsigned int *) block)[i] != ((unsigned int *) block)[0]) + break; + + if(i == 16) { // constant color + int r = block[0], g = block[1], b = block[2]; + mask = 0xaaaaaaaa; + max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0]; + min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1]; + } else { + // first step: PCA+map along principal axis + stb__OptimizeColorsBlock(block,&max16,&min16); + if (max16 != min16) { + stb__EvalColors(color,max16,min16); + mask = stb__MatchColorsBlock(block,color); + } else + mask = 0; + + // third step: refine (multiple times if requested) + for (i=0;i> 8); + dest[2] = (unsigned char) (min16); + dest[3] = (unsigned char) (min16 >> 8); + dest[4] = (unsigned char) (mask); + dest[5] = (unsigned char) (mask >> 8); + dest[6] = (unsigned char) (mask >> 16); + dest[7] = (unsigned char) (mask >> 24); +} + +// Alpha block compression (this is easy for a change) +static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src, int stride) +{ + int i,dist,bias,dist4,dist2,bits,mask; + + // find min/max color + int mn,mx; + mn = mx = src[0]; + + for (i=1;i<16;i++) + { + if (src[i*stride] < mn) mn = src[i*stride]; + else if (src[i*stride] > mx) mx = src[i*stride]; + } + + // encode them + dest[0] = (unsigned char)mx; + dest[1] = (unsigned char)mn; + dest += 2; + + /* + * Wine specific optimization to more closely match Windows behavior: If + * max is equal to minimum, just set all bits to 0 (which means the value + * is the value of max in this case). + */ + if (mx == mn) { + memset(dest, 0, 6); + return; + } + + // determine bias and emit color indices + // given the choice of mx/mn, these indices are optimal: + // http://fgiesen.wordpress.com/2009/12/15/dxt5-alpha-block-index-determination/ + dist = mx-mn; + dist4 = dist*4; + dist2 = dist*2; + bias = (dist < 8) ? (dist - 1) : (dist/2 + 2); + bias -= mn * 7; + bits = 0,mask=0; + + for (i=0;i<16;i++) { + int a = src[i*stride]*7 + bias; + int ind,t; + + // select index. this is a "linear scale" lerp factor between 0 (val=min) and 7 (val=max). + t = (a >= dist4) ? -1 : 0; ind = t & 4; a -= dist4 & t; + t = (a >= dist2) ? -1 : 0; ind += t & 2; a -= dist2 & t; + ind += (a >= dist); + + // turn linear scale into DXT index (0/1 are extremal pts) + ind = -ind & 7; + ind ^= (2 > ind); + + // write index + mask |= ind << bits; + if((bits += 3) >= 8) { + *dest++ = (unsigned char)mask; + mask >>= 8; + bits -= 8; + } + } +} + +void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode) +{ + unsigned char data[16][4]; + if (alpha) { + int i; + stb__CompressAlphaBlock(dest,(unsigned char*) src+3, 4); + dest += 8; + // make a new copy of the data in which alpha is opaque, + // because code uses a fast test for color constancy + memcpy(data, src, 4*16); + for (i=0; i < 16; ++i) + data[i][3] = 255; + src = &data[0][0]; + } + + stb__CompressColorBlock(dest,(unsigned char*) src,mode); +} + +void stb_compress_bc4_block(unsigned char *dest, const unsigned char *src) +{ + stb__CompressAlphaBlock(dest,(unsigned char*) src, 1); +} + +void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src) +{ + stb__CompressAlphaBlock(dest,(unsigned char*) src,2); + stb__CompressAlphaBlock(dest + 8,(unsigned char*) src+1,2); +} +#endif // STB_DXT_IMPLEMENTATION + +// Compile with STB_DXT_IMPLEMENTATION and STB_DXT_GENERATE_TABLES +// defined to generate the tables above. +#ifdef STB_DXT_GENERATE_TABLES +#include + +int main() +{ + int i, j; + const char *omatch_names[] = { "stb__OMatch5", "stb__OMatch6" }; + int dequant_mults[2] = { 33*4, 65 }; // .4 fixed-point dequant multipliers + + // optimal endpoint tables + for (i = 0; i < 2; ++i) { + int dequant = dequant_mults[i]; + int size = i ? 64 : 32; + printf("static const unsigned char %s[256][2] = {\n", omatch_names[i]); + for (int j = 0; j < 256; ++j) { + int mn, mx; + int best_mn = 0, best_mx = 0; + int best_err = 256 * 100; + for (mn=0;mn> 4; + int maxe = (mx * dequant) >> 4; + int err = abs(stb__Lerp13(maxe, mine) - j) * 100; + + // DX10 spec says that interpolation must be within 3% of "correct" result, + // add this as error term. Normally we'd expect a random distribution of + // +-1.5% error, but nowhere in the spec does it say that the error has to be + // unbiased - better safe than sorry. + err += abs(maxe - mine) * 3; + + if(err < best_err) { + best_mn = mn; + best_mx = mx; + best_err = err; + } + } + } + if ((j % 8) == 0) printf(" "); // 2 spaces, third is done below + printf(" { %2d, %2d },", best_mx, best_mn); + if ((j % 8) == 7) printf("\n"); + } + printf("};\n"); + } + + return 0; +} +#endif + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 9d2dc96a9791..7e0116411bd9 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -18,141 +18,11 @@ * */ - #include "d3dx9_private.h" - -#include "initguid.h" -#include "ole2.h" -#include "wincodec.h" - -#include "txc_dxtn.h" #include WINE_DEFAULT_DEBUG_CHANNEL(d3dx); -HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**); - -static const struct -{ - const GUID *wic_guid; - enum d3dx_pixel_format_id d3dx_pixel_format; -} wic_pixel_formats[] = -{ - { &GUID_WICPixelFormat8bppIndexed, D3DX_PIXEL_FORMAT_P8_UINT }, - { &GUID_WICPixelFormat1bppIndexed, D3DX_PIXEL_FORMAT_P8_UINT }, - { &GUID_WICPixelFormat4bppIndexed, D3DX_PIXEL_FORMAT_P8_UINT }, - { &GUID_WICPixelFormat8bppGray, D3DX_PIXEL_FORMAT_L8_UNORM }, - { &GUID_WICPixelFormat16bppBGR555, D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM }, - { &GUID_WICPixelFormat16bppBGR565, D3DX_PIXEL_FORMAT_B5G6R5_UNORM }, - { &GUID_WICPixelFormat24bppBGR, D3DX_PIXEL_FORMAT_B8G8R8_UNORM }, - { &GUID_WICPixelFormat32bppBGR, D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM }, - { &GUID_WICPixelFormat32bppBGRA, D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM }, - { &GUID_WICPixelFormat48bppRGB, D3DX_PIXEL_FORMAT_R16G16B16_UNORM }, - { &GUID_WICPixelFormat64bppRGBA, D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM }, -}; - -static enum d3dx_pixel_format_id d3dx_pixel_format_id_from_wic_pixel_format(const GUID *guid) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); i++) - { - if (IsEqualGUID(wic_pixel_formats[i].wic_guid, guid)) - return wic_pixel_formats[i].d3dx_pixel_format; - } - - return D3DX_PIXEL_FORMAT_COUNT; - -} - -static const GUID *wic_guid_from_d3dformat(D3DFORMAT format) -{ - enum d3dx_pixel_format_id d3dx_pixel_format = d3dx_pixel_format_id_from_d3dformat(format); - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); i++) - { - if (wic_pixel_formats[i].d3dx_pixel_format == d3dx_pixel_format) - return wic_pixel_formats[i].wic_guid; - } - - return NULL; -} - -#define DDS_PALETTE_SIZE (sizeof(PALETTEENTRY) * 256) - -/* dds_header.flags */ -#define DDS_CAPS 0x1 -#define DDS_HEIGHT 0x2 -#define DDS_WIDTH 0x4 -#define DDS_PITCH 0x8 -#define DDS_PIXELFORMAT 0x1000 -#define DDS_MIPMAPCOUNT 0x20000 -#define DDS_LINEARSIZE 0x80000 -#define DDS_DEPTH 0x800000 - -/* dds_header.caps */ -#define DDSCAPS_ALPHA 0x2 -#define DDS_CAPS_COMPLEX 0x8 -#define DDSCAPS_PALETTE 0x100 -#define DDS_CAPS_TEXTURE 0x1000 -#define DDS_CAPS_MIPMAP 0x400000 - -/* dds_header.caps2 */ -#define DDS_CAPS2_CUBEMAP 0x200 -#define DDS_CAPS2_CUBEMAP_POSITIVEX 0x400 -#define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x800 -#define DDS_CAPS2_CUBEMAP_POSITIVEY 0x1000 -#define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x2000 -#define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x4000 -#define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x8000 -#define DDS_CAPS2_CUBEMAP_ALL_FACES ( DDS_CAPS2_CUBEMAP_POSITIVEX | DDS_CAPS2_CUBEMAP_NEGATIVEX \ - | DDS_CAPS2_CUBEMAP_POSITIVEY | DDS_CAPS2_CUBEMAP_NEGATIVEY \ - | DDS_CAPS2_CUBEMAP_POSITIVEZ | DDS_CAPS2_CUBEMAP_NEGATIVEZ ) -#define DDS_CAPS2_VOLUME 0x200000 - -/* dds_pixel_format.flags */ -#define DDS_PF_ALPHA 0x1 -#define DDS_PF_ALPHA_ONLY 0x2 -#define DDS_PF_FOURCC 0x4 -#define DDS_PF_INDEXED 0x20 -#define DDS_PF_RGB 0x40 -#define DDS_PF_YUV 0x200 -#define DDS_PF_LUMINANCE 0x20000 -#define DDS_PF_BUMPLUMINANCE 0x40000 -#define DDS_PF_BUMPDUDV 0x80000 - -struct dds_pixel_format -{ - DWORD size; - DWORD flags; - DWORD fourcc; - DWORD bpp; - DWORD rmask; - DWORD gmask; - DWORD bmask; - DWORD amask; -}; - -struct dds_header -{ - DWORD signature; - DWORD size; - DWORD flags; - DWORD height; - DWORD width; - DWORD pitch_or_linear_size; - DWORD depth; - DWORD miplevels; - DWORD reserved[11]; - struct dds_pixel_format pixel_format; - DWORD caps; - DWORD caps2; - DWORD caps3; - DWORD caps4; - DWORD reserved2; -}; - HRESULT lock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, D3DLOCKED_RECT *lock, IDirect3DSurface9 **temp_surface, BOOL write) { @@ -247,2424 +117,632 @@ HRESULT unlock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, return hr; } -static const struct -{ - struct dds_pixel_format dds_pixel_format; - enum d3dx_pixel_format_id d3dx_pixel_format; -} dds_pixel_formats[] = +static const enum d3dx_pixel_format_id tga_save_pixel_formats[] = { - /* DDS_PF_FOURCC. */ - { { 32, DDS_PF_FOURCC, MAKEFOURCC('U','Y','V','Y') }, D3DX_PIXEL_FORMAT_UYVY }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('Y','U','Y','2') }, D3DX_PIXEL_FORMAT_YUY2 }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G') }, D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B') }, D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1') }, D3DX_PIXEL_FORMAT_DXT1_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','2') }, D3DX_PIXEL_FORMAT_DXT2_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3') }, D3DX_PIXEL_FORMAT_DXT3_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','4') }, D3DX_PIXEL_FORMAT_DXT4_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5') }, D3DX_PIXEL_FORMAT_DXT5_UNORM }, - /* These aren't actually fourcc values, they're just D3DFMT values. */ - { { 32, DDS_PF_FOURCC, 0x24 }, D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM }, - { { 32, DDS_PF_FOURCC, 0x6e }, D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM }, - { { 32, DDS_PF_FOURCC, 0x6f }, D3DX_PIXEL_FORMAT_R16_FLOAT }, - { { 32, DDS_PF_FOURCC, 0x70 }, D3DX_PIXEL_FORMAT_R16G16_FLOAT }, - { { 32, DDS_PF_FOURCC, 0x71 }, D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT }, - { { 32, DDS_PF_FOURCC, 0x72 }, D3DX_PIXEL_FORMAT_R32_FLOAT }, - { { 32, DDS_PF_FOURCC, 0x73 }, D3DX_PIXEL_FORMAT_R32G32_FLOAT }, - { { 32, DDS_PF_FOURCC, 0x74 }, D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT }, - /* DDS_PF_RGB. */ - { { 32, DDS_PF_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0x00 }, D3DX_PIXEL_FORMAT_B2G3R3_UNORM }, - { { 32, DDS_PF_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0x0000 }, D3DX_PIXEL_FORMAT_B5G6R5_UNORM }, - { { 32, DDS_PF_RGB, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x0000 }, D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM }, - { { 32, DDS_PF_RGB, 0, 16, 0x0f00, 0x00f0, 0x000f, 0x0000 }, D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM }, - { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, D3DX_PIXEL_FORMAT_B8G8R8_UNORM }, - { { 32, DDS_PF_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 }, D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM }, - { { 32, DDS_PF_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_R16G16_UNORM }, - { { 32, DDS_PF_RGB, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 }, D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00 }, D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000 }, D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000 }, D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }, D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }, D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 }, D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM }, - /* DDS_PF_INDEXED. */ - { { 32, DDS_PF_INDEXED, 0, 8 }, D3DX_PIXEL_FORMAT_P8_UINT }, - { { 32, DDS_PF_INDEXED | DDS_PF_ALPHA, 0, 16, 0, 0, 0, 0xff00, }, D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM }, - /* DDS_PF_LUMINANCE. */ - { { 32, DDS_PF_LUMINANCE, 0, 8, 0x00ff }, D3DX_PIXEL_FORMAT_L8_UNORM }, - { { 32, DDS_PF_LUMINANCE, 0, 16, 0xffff }, D3DX_PIXEL_FORMAT_L16_UNORM }, - { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x000f, 0, 0, 0x00f0 }, D3DX_PIXEL_FORMAT_L4A4_UNORM }, - { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 16, 0x00ff, 0, 0, 0xff00 }, D3DX_PIXEL_FORMAT_L8A8_UNORM }, - /* Exceptional case, A8L8 can also have 8bpp. */ - { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x00ff, 0, 0, 0xff00 }, D3DX_PIXEL_FORMAT_L8A8_UNORM }, - /* DDS_PF_ALPHA_ONLY. */ - { { 32, DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff }, D3DX_PIXEL_FORMAT_A8_UNORM }, - /* DDS_PF_BUMPDUDV. */ - { { 32, DDS_PF_BUMPDUDV, 0, 16, 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_U8V8_SNORM }, - { { 32, DDS_PF_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_U16V16_SNORM }, - { { 32, DDS_PF_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }, D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM }, - { { 32, DDS_PF_BUMPDUDV | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }, D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM }, - /* DDS_PF_BUMPLUMINANCE. */ - { { 32, DDS_PF_BUMPLUMINANCE, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 }, D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM }, + D3DX_PIXEL_FORMAT_B8G8R8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM }; -static BOOL dds_pixel_format_compare(const struct dds_pixel_format *pf_a, const struct dds_pixel_format *pf_b, - BOOL check_rmask, BOOL check_gmask, BOOL check_bmask, BOOL check_amask) +static const enum d3dx_pixel_format_id png_save_pixel_formats[] = { - return pf_a->bpp == pf_b->bpp && !((check_rmask && pf_a->rmask != pf_b->rmask) - || (check_gmask && pf_a->gmask != pf_b->gmask) || (check_bmask && pf_a->bmask != pf_b->bmask) - || (check_amask && pf_a->amask != pf_b->amask)); -} + D3DX_PIXEL_FORMAT_B8G8R8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, + D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM +}; -static enum d3dx_pixel_format_id d3dx_pixel_format_id_from_dds_pixel_format(const struct dds_pixel_format *pixel_format) +static const enum d3dx_pixel_format_id jpg_save_pixel_formats[] = { - uint32_t i; + D3DX_PIXEL_FORMAT_B8G8R8_UNORM, +}; - TRACE("pixel_format: size %lu, flags %#lx, fourcc %#lx, bpp %lu.\n", pixel_format->size, - pixel_format->flags, pixel_format->fourcc, pixel_format->bpp); - TRACE("rmask %#lx, gmask %#lx, bmask %#lx, amask %#lx.\n", pixel_format->rmask, pixel_format->gmask, - pixel_format->bmask, pixel_format->amask); +static const enum d3dx_pixel_format_id bmp_save_pixel_formats[] = +{ + D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM, + D3DX_PIXEL_FORMAT_B5G6R5_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, + D3DX_PIXEL_FORMAT_P8_UINT +}; - for (i = 0; i < ARRAY_SIZE(dds_pixel_formats); ++i) - { - const struct dds_pixel_format *dds_pf = &dds_pixel_formats[i].dds_pixel_format; +static const enum d3dx_pixel_format_id unimplemented_bmp_save_pixel_formats[] = +{ + D3DX_PIXEL_FORMAT_A8_UNORM, + D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM, + D3DX_PIXEL_FORMAT_L8A8_UNORM, + D3DX_PIXEL_FORMAT_L16_UNORM, + D3DX_PIXEL_FORMAT_B2G3R3_UNORM, + D3DX_PIXEL_FORMAT_R16_FLOAT, + D3DX_PIXEL_FORMAT_R16G16_FLOAT, + D3DX_PIXEL_FORMAT_R16G16_UNORM, + D3DX_PIXEL_FORMAT_R32_FLOAT, + D3DX_PIXEL_FORMAT_R32G32_FLOAT, + D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM, + D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM, + D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM, + D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM, + D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM, + D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM, + D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM, + D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM, +}; - if (pixel_format->flags != dds_pf->flags) - continue; +static BOOL d3dx_pixel_format_id_array_contains(const enum d3dx_pixel_format_id *format_ids, uint32_t format_ids_size, + enum d3dx_pixel_format_id format) +{ + unsigned int i; - switch (pixel_format->flags & ~DDS_PF_ALPHA) - { - case DDS_PF_ALPHA_ONLY: - if (dds_pixel_format_compare(pixel_format, dds_pf, FALSE, FALSE, FALSE, TRUE)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_FOURCC: - if (pixel_format->fourcc == dds_pf->fourcc) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_INDEXED: - if (dds_pixel_format_compare(pixel_format, dds_pf, FALSE, FALSE, FALSE, pixel_format->flags & DDS_PF_ALPHA)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_RGB: - if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, pixel_format->flags & DDS_PF_ALPHA)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_LUMINANCE: - if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, FALSE, FALSE, pixel_format->flags & DDS_PF_ALPHA)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_BUMPLUMINANCE: - if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, FALSE)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_BUMPDUDV: - if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, TRUE)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - default: - assert(0); /* Should not happen. */ - break; - } + for (i = 0; i < format_ids_size; ++i) + { + if (format_ids[i] == format) + return TRUE; } - WARN("Unknown pixel format (flags %#lx, fourcc %#lx, bpp %lu, r %#lx, g %#lx, b %#lx, a %#lx).\n", - pixel_format->flags, pixel_format->fourcc, pixel_format->bpp, - pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask); - return D3DX_PIXEL_FORMAT_COUNT; + return FALSE; } -static HRESULT dds_pixel_format_from_d3dx_pixel_format_id(struct dds_pixel_format *pixel_format, - enum d3dx_pixel_format_id d3dx_pixel_format) +static enum d3dx_pixel_format_id get_replacement_d3dx_pixel_format_id(enum d3dx_pixel_format_id format) { - const struct dds_pixel_format *pf = NULL; - uint32_t i; - - for (i = 0; i < ARRAY_SIZE(dds_pixel_formats); ++i) + switch (format) { - if (dds_pixel_formats[i].d3dx_pixel_format == d3dx_pixel_format) - { - pf = &dds_pixel_formats[i].dds_pixel_format; - break; - } - } + case D3DX_PIXEL_FORMAT_P8_UINT: + case D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM: + case D3DX_PIXEL_FORMAT_DXT1_UNORM: + case D3DX_PIXEL_FORMAT_DXT2_UNORM: + case D3DX_PIXEL_FORMAT_DXT3_UNORM: + case D3DX_PIXEL_FORMAT_DXT4_UNORM: + case D3DX_PIXEL_FORMAT_DXT5_UNORM: + return D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; - if (!pf) - { - WARN("Unhandled format %#x.\n", d3dx_pixel_format); - return E_NOTIMPL; + default: + break; } - if (pixel_format) - *pixel_format = *pf; - - return D3D_OK; -} - -static void d3dx_get_next_mip_level_size(struct volume *size) -{ - size->width = max(size->width / 2, 1); - size->height = max(size->height / 2, 1); - size->depth = max(size->depth / 2, 1); + return format; } -static const char *debug_volume(const struct volume *volume) +static enum d3dx_pixel_format_id d3dx_get_closest_d3dx_pixel_format_id(const enum d3dx_pixel_format_id *format_ids, + uint32_t format_ids_size, enum d3dx_pixel_format_id format_id) { - if (!volume) - return "(null)"; - return wine_dbg_sprintf("(%ux%ux%u)", volume->width, volume->height, volume->depth); -} + const struct pixel_format_desc *fmt, *curfmt, *bestfmt = NULL; + int32_t bestscore = INT_MIN, i = 0, j; + int32_t rgb_channels, a_channel; + BOOL alpha_only, rgb_only; -static HRESULT d3dx_calculate_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, - uint32_t *pitch, uint32_t *size) -{ - const struct pixel_format_desc *format_desc = get_d3dx_pixel_format_info(format); + TRACE("Requested format is not directly supported, looking for the best alternative.\n"); - if (is_unknown_format(format_desc)) - return E_NOTIMPL; + fmt = get_d3dx_pixel_format_info(get_replacement_d3dx_pixel_format_id(format_id)); + alpha_only = rgb_only = FALSE; + if (fmt->a_type != CTYPE_EMPTY && fmt->rgb_type == CTYPE_EMPTY) + alpha_only = TRUE; + else if (fmt->a_type == CTYPE_EMPTY && fmt->rgb_type != CTYPE_EMPTY) + rgb_only = TRUE; - if (format_desc->block_width != 1 || format_desc->block_height != 1) - { - *pitch = format_desc->block_byte_count - * max(1, (width + format_desc->block_width - 1) / format_desc->block_width); - *size = *pitch - * max(1, (height + format_desc->block_height - 1) / format_desc->block_height); - } + if (fmt->rgb_type == CTYPE_LUMA) + rgb_channels = 3; else + rgb_channels = !!fmt->bits[1] + !!fmt->bits[2] + !!fmt->bits[3]; + a_channel = !!fmt->bits[0]; + for (i = 0; i < format_ids_size; ++i) { - *pitch = width * format_desc->bytes_per_pixel; - *size = *pitch * height; - } + int32_t cur_rgb_channels, cur_a_channel; + int32_t score; - return D3D_OK; -} + curfmt = get_d3dx_pixel_format_info(format_ids[i]); + if (!is_conversion_to_supported(curfmt)) + continue; + if (alpha_only && curfmt->a_type == CTYPE_EMPTY) + continue; + if (rgb_only && curfmt->rgb_type == CTYPE_EMPTY) + continue; + if (fmt->rgb_type == CTYPE_SNORM && curfmt->rgb_type != CTYPE_SNORM) + continue; -static uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, uint32_t depth, - uint32_t mip_levels) -{ - uint32_t layer_size, row_pitch, slice_pitch, i; - struct volume dims = { width, height, depth }; + cur_rgb_channels = !!curfmt->bits[1] + !!curfmt->bits[2] + !!curfmt->bits[3]; + cur_a_channel = !!curfmt->bits[0]; + /* This format can be used, let's evaluate it. + Weights chosen quite arbitrarily... */ + score = 512 * (format_types_match(curfmt, fmt)); + score -= 32 * abs(cur_a_channel - a_channel); + score -= 32 * abs(cur_rgb_channels - rgb_channels); + for (j = 0; j < 4; j++) + { + int diff = curfmt->bits[j] - fmt->bits[j]; + score -= (diff < 0 ? -diff * 8 : diff) * (j == 0 ? 1 : 2); + } - layer_size = 0; - for (i = 0; i < mip_levels; ++i) - { - if (FAILED(d3dx_calculate_pixels_size(format, dims.width, dims.height, &row_pitch, &slice_pitch))) - return 0; - layer_size += slice_pitch * dims.depth; - d3dx_get_next_mip_level_size(&dims); + if (score > bestscore) + { + bestscore = score; + bestfmt = curfmt; + } } - return layer_size; -} - -static HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE resource_type, - enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels) -{ - HRESULT hr; - - memset(header, 0, sizeof(*header)); - header->signature = MAKEFOURCC('D','D','S',' '); - /* The signature is not really part of the DDS header. */ - header->size = sizeof(*header) - FIELD_OFFSET(struct dds_header, size); - hr = dds_pixel_format_from_d3dx_pixel_format_id(&header->pixel_format, format); - if (FAILED(hr)) - return hr; - - header->flags = DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_PIXELFORMAT; - header->height = size->height; - header->width = size->width; - header->caps = DDS_CAPS_TEXTURE; - if (header->pixel_format.flags & DDS_PF_ALPHA || header->pixel_format.flags & DDS_PF_ALPHA_ONLY) - header->caps |= DDSCAPS_ALPHA; - if (header->pixel_format.flags & DDS_PF_INDEXED) - header->caps |= DDSCAPS_PALETTE; - - return D3D_OK; + return (bestfmt) ? bestfmt->format : D3DX_PIXEL_FORMAT_COUNT; } -static HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, - D3DXIMAGE_FILEFORMAT file_format, ID3DXBuffer **dst_buffer) +HRESULT d3dx_get_save_pixel_format_from_image_file_format(const struct pixel_format_desc *src_fmt_desc, + D3DXIMAGE_FILEFORMAT file_format, enum d3dx_pixel_format_id *save_fmt) { - enum d3dx_pixel_format_id dst_format = src_fmt_desc->format; - const struct pixel_format_desc *dst_fmt_desc; - uint32_t dst_row_pitch, dst_slice_pitch; - struct d3dx_pixels dst_pixels; - ID3DXBuffer *buffer; - uint8_t *pixels; + const enum d3dx_pixel_format_id *save_fmts; + unsigned int save_fmts_count; HRESULT hr; - *dst_buffer = NULL; switch (file_format) { case D3DXIFF_DDS: - { - struct dds_header *header; - uint32_t header_size; - - hr = dds_pixel_format_from_d3dx_pixel_format_id(NULL, dst_format); + hr = dds_pixel_format_from_d3dx_pixel_format_id(NULL, src_fmt_desc->format); if (FAILED(hr)) return hr; + *save_fmt = src_fmt_desc->format; + return D3D_OK; - dst_fmt_desc = get_d3dx_pixel_format_info(dst_format); - hr = d3dx_calculate_pixels_size(dst_format, src_pixels->size.width, src_pixels->size.height, &dst_row_pitch, - &dst_slice_pitch); - if (FAILED(hr)) - return hr; + case D3DXIFF_TGA: + save_fmts = tga_save_pixel_formats; + save_fmts_count = ARRAY_SIZE(tga_save_pixel_formats); + break; - header_size = is_index_format(dst_fmt_desc) ? sizeof(*header) + DDS_PALETTE_SIZE : sizeof(*header); - hr = D3DXCreateBuffer(dst_slice_pitch + header_size, &buffer); - if (FAILED(hr)) - return hr; + case D3DXIFF_PNG: + save_fmts = png_save_pixel_formats; + save_fmts_count = ARRAY_SIZE(png_save_pixel_formats); + break; - header = ID3DXBuffer_GetBufferPointer(buffer); - pixels = (uint8_t *)ID3DXBuffer_GetBufferPointer(buffer) + header_size; - hr = d3dx_init_dds_header(header, D3DRTYPE_TEXTURE, dst_format, &src_pixels->size, 1); - if (FAILED(hr)) - goto exit; - if (is_index_format(dst_fmt_desc)) - memcpy((uint8_t *)ID3DXBuffer_GetBufferPointer(buffer) + sizeof(*header), src_pixels->palette, - DDS_PALETTE_SIZE); + case D3DXIFF_JPG: + save_fmts = jpg_save_pixel_formats; + save_fmts_count = ARRAY_SIZE(jpg_save_pixel_formats); + break; + + case D3DXIFF_BMP: + case D3DXIFF_DIB: + if (d3dx_pixel_format_id_array_contains(unimplemented_bmp_save_pixel_formats, + ARRAY_SIZE(unimplemented_bmp_save_pixel_formats), src_fmt_desc->format)) + { + FIXME("Saving d3dformat %#x currently unimplemented for file type %s.\n", src_fmt_desc->format, + debug_d3dx_image_file_format((enum d3dx_image_file_format)file_format)); + return E_NOTIMPL; + } + save_fmts = bmp_save_pixel_formats; + save_fmts_count = ARRAY_SIZE(bmp_save_pixel_formats); break; - } default: assert(0 && "Unexpected file format."); return E_FAIL; } - if (src_pixels->size.width != 0 && src_pixels->size.height != 0) + if (d3dx_pixel_format_id_array_contains(save_fmts, save_fmts_count, src_fmt_desc->format)) { - const RECT dst_rect = { 0, 0, src_pixels->size.width, src_pixels->size.height }; - - set_d3dx_pixels(&dst_pixels, pixels, dst_row_pitch, dst_slice_pitch, src_pixels->palette, src_pixels->size.width, - src_pixels->size.height, src_pixels->size.depth, &dst_rect); - - hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_fmt_desc, src_pixels, src_fmt_desc, D3DX_FILTER_NONE, 0); - if (FAILED(hr)) - goto exit; + *save_fmt = src_fmt_desc->format; + return D3D_OK; } - *dst_buffer = buffer; -exit: - if (*dst_buffer != buffer) - ID3DXBuffer_Release(buffer); - return hr; -} - -static HRESULT save_dds_surface_to_memory(ID3DXBuffer **dst_buffer, IDirect3DSurface9 *src_surface, - const PALETTEENTRY *src_palette, const RECT *src_rect) -{ - const struct pixel_format_desc *src_fmt_desc; - D3DSURFACE_DESC src_surface_desc; - IDirect3DSurface9 *temp_surface; - struct d3dx_pixels src_pixels; - D3DLOCKED_RECT locked_rect; - ID3DXBuffer *buffer; - RECT src_rect_temp; - HRESULT hr; - - IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc); - src_fmt_desc = get_format_info(src_surface_desc.Format); - if (is_unknown_format(src_fmt_desc)) - return E_NOTIMPL; - - if (!src_palette && is_index_format(src_fmt_desc)) + if (!is_conversion_from_supported(src_fmt_desc)) { - FIXME("Default palette unimplemented.\n"); + FIXME("Cannot convert d3dx pixel format %d, can't save.\n", src_fmt_desc->format); return E_NOTIMPL; } - if (src_rect) - { - if (src_rect->left > src_rect->right || src_rect->right > src_surface_desc.Width - || src_rect->top > src_rect->bottom || src_rect->bottom > src_surface_desc.Height - || src_rect->left < 0 || src_rect->top < 0) - { - WARN("Invalid src_rect specified.\n"); - return D3DERR_INVALIDCALL; - } - } - else - { - SetRect(&src_rect_temp, 0, 0, src_surface_desc.Width, src_surface_desc.Height); - src_rect = &src_rect_temp; - } + *save_fmt = d3dx_get_closest_d3dx_pixel_format_id(save_fmts, save_fmts_count, src_fmt_desc->format); - hr = lock_surface(src_surface, NULL, &locked_rect, &temp_surface, FALSE); - if (FAILED(hr)) - return hr; + return (*save_fmt == D3DX_PIXEL_FORMAT_COUNT) ? D3DERR_INVALIDCALL : D3D_OK; +} - hr = d3dx_pixels_init(locked_rect.pBits, locked_rect.Pitch, 0, src_palette, src_fmt_desc->format, - src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1, &src_pixels); - if (FAILED(hr)) +void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image) +{ + info->ImageFileFormat = (D3DXIMAGE_FILEFORMAT)image->image_file_format; + info->Width = image->size.width; + info->Height = image->size.height; + info->Depth = image->size.depth; + info->MipLevels = image->mip_levels; + switch (image->format) { - unlock_surface(src_surface, NULL, temp_surface, FALSE); - return hr; - } + case D3DX_PIXEL_FORMAT_R16G16B16_UNORM: + info->Format = D3DFMT_A16B16G16R16; + break; - hr = d3dx_save_pixels_to_memory(&src_pixels, src_fmt_desc, D3DXIFF_DDS, &buffer); - if (FAILED(hr)) - { - unlock_surface(src_surface, NULL, temp_surface, FALSE); - return hr; - } + case D3DX_PIXEL_FORMAT_B8G8R8_UNORM: + if (info->ImageFileFormat == D3DXIFF_PNG || info->ImageFileFormat == D3DXIFF_JPG) + info->Format = D3DFMT_X8R8G8B8; + else + info->Format = d3dformat_from_d3dx_pixel_format_id(image->format); + break; - hr = unlock_surface(src_surface, NULL, temp_surface, FALSE); - if (FAILED(hr)) - { - ID3DXBuffer_Release(buffer); - return hr; + default: + info->Format = d3dformat_from_d3dx_pixel_format_id(image->format); + break; } - - *dst_buffer = buffer; - return D3D_OK; + if (image->resource_type == D3DX_RESOURCE_TYPE_TEXTURE_3D) + info->ResourceType = D3DRTYPE_VOLUMETEXTURE; + else if (image->resource_type == D3DX_RESOURCE_TYPE_CUBE_TEXTURE) + info->ResourceType = D3DRTYPE_CUBETEXTURE; + else + info->ResourceType = D3DRTYPE_TEXTURE; } -static const uint8_t bmp_file_signature[] = { 'B', 'M' }; -static const uint8_t jpg_file_signature[] = { 0xff, 0xd8 }; -static const uint8_t png_file_signature[] = { 0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a }; -static const uint8_t dds_file_signature[] = { 'D', 'D', 'S', ' ' }; -static const uint8_t ppm_plain_file_signature[] = { 'P', '3' }; -static const uint8_t ppm_raw_file_signature[] = { 'P', '6' }; -static const uint8_t hdr_file_signature[] = { '#', '?', 'R', 'A', 'D', 'I', 'A', 'N', 'C', 'E', '\n' }; -static const uint8_t pfm_color_file_signature[] = { 'P', 'F' }; -static const uint8_t pfm_gray_file_signature[] = { 'P', 'f' }; - -/* - * If none of these match, the file is either DIB, TGA, or something we don't - * support. +/************************************************************ + * D3DXGetImageInfoFromFileInMemory + * + * Fills a D3DXIMAGE_INFO structure with info about an image + * + * PARAMS + * data [I] pointer to the image file data + * datasize [I] size of the passed data + * info [O] pointer to the destination structure + * + * RETURNS + * Success: D3D_OK, if info is not NULL and data and datasize make up a valid image file or + * if info is NULL and data and datasize are not NULL + * Failure: D3DXERR_INVALIDDATA, if data is no valid image file and datasize and info are not NULL + * D3DERR_INVALIDCALL, if data is NULL or + * if datasize is 0 + * + * NOTES + * datasize may be bigger than the actual file size + * */ -struct d3dx_file_format_signature +HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, D3DXIMAGE_INFO *info) { - const uint8_t *file_signature; - uint32_t file_signature_len; - D3DXIMAGE_FILEFORMAT image_file_format; -}; + struct d3dx_image image; + HRESULT hr; -static const struct d3dx_file_format_signature file_format_signatures[] = -{ - { bmp_file_signature, sizeof(bmp_file_signature), D3DXIFF_BMP }, - { jpg_file_signature, sizeof(jpg_file_signature), D3DXIFF_JPG }, - { png_file_signature, sizeof(png_file_signature), D3DXIFF_PNG }, - { dds_file_signature, sizeof(dds_file_signature), D3DXIFF_DDS }, - { ppm_plain_file_signature, sizeof(ppm_plain_file_signature), D3DXIFF_PPM }, - { ppm_raw_file_signature, sizeof(ppm_raw_file_signature), D3DXIFF_PPM }, - { hdr_file_signature, sizeof(hdr_file_signature), D3DXIFF_HDR }, - { pfm_color_file_signature, sizeof(pfm_color_file_signature), D3DXIFF_PFM }, - { pfm_gray_file_signature, sizeof(pfm_gray_file_signature), D3DXIFF_PFM }, -}; + TRACE("(%p, %d, %p)\n", data, datasize, info); -static BOOL d3dx_get_image_file_format_from_file_signature(const void *src_data, uint32_t src_data_size, - D3DXIMAGE_FILEFORMAT *out_iff) -{ - unsigned int i; + if (!data || !datasize) + return D3DERR_INVALIDCALL; - for (i = 0; i < ARRAY_SIZE(file_format_signatures); ++i) - { - const struct d3dx_file_format_signature *signature = &file_format_signatures[i]; + if (!info) + return D3D_OK; - if ((src_data_size >= signature->file_signature_len) - && !memcmp(src_data, signature->file_signature, signature->file_signature_len)) - { - *out_iff = signature->image_file_format; - return TRUE; - } + hr = d3dx_image_init(data, datasize, &image, 0, D3DX_IMAGE_INFO_ONLY); + if (FAILED(hr)) { + TRACE("Invalid or unsupported image file\n"); + return D3DXERR_INVALIDDATA; } - return FALSE; -} - -static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src_data_size, - struct d3dx_image *image, uint32_t starting_mip_level) -{ - uint32_t expected_src_data_size, header_size; - const struct dds_header *header = src_data; - BOOL is_indexed_fmt; - HRESULT hr; - - if (src_data_size < sizeof(*header) || header->pixel_format.size != sizeof(header->pixel_format)) - return D3DXERR_INVALIDDATA; - - TRACE("File type is DDS.\n"); - is_indexed_fmt = !!(header->pixel_format.flags & DDS_PF_INDEXED); - header_size = is_indexed_fmt ? sizeof(*header) + DDS_PALETTE_SIZE : sizeof(*header); - - set_volume_struct(&image->size, header->width, header->height, 1); - image->mip_levels = header->miplevels ? header->miplevels : 1; - image->format = d3dx_pixel_format_id_from_dds_pixel_format(&header->pixel_format); - image->layer_count = 1; - - if (image->format == D3DX_PIXEL_FORMAT_COUNT) - return D3DXERR_INVALIDDATA; - - TRACE("Pixel format is %#x.\n", image->format); - if (header->flags & DDS_DEPTH) - { - image->size.depth = max(header->depth, 1); - image->resource_type = D3DRTYPE_VOLUMETEXTURE; - } - else if (header->caps2 & DDS_CAPS2_CUBEMAP) - { - if ((header->caps2 & DDS_CAPS2_CUBEMAP_ALL_FACES) != DDS_CAPS2_CUBEMAP_ALL_FACES) - { - WARN("Tried to load a partial cubemap DDS file.\n"); - return D3DXERR_INVALIDDATA; - } - - image->layer_count = 6; - image->resource_type = D3DRTYPE_CUBETEXTURE; - } - else - image->resource_type = D3DRTYPE_TEXTURE; - - image->layer_pitch = d3dx_calculate_layer_pixels_size(image->format, image->size.width, image->size.height, - image->size.depth, image->mip_levels); - if (!image->layer_pitch) - return D3DXERR_INVALIDDATA; - expected_src_data_size = (image->layer_pitch * image->layer_count) + header_size; - if (src_data_size < expected_src_data_size) - { - WARN("File is too short %u, expected at least %u bytes.\n", src_data_size, expected_src_data_size); - return D3DXERR_INVALIDDATA; - } - - image->palette = (is_indexed_fmt) ? (PALETTEENTRY *)(((uint8_t *)src_data) + sizeof(*header)) : NULL; - image->pixels = ((BYTE *)src_data) + header_size; - image->image_file_format = D3DXIFF_DDS; - if (starting_mip_level && (image->mip_levels > 1)) - { - uint32_t i, row_pitch, slice_pitch, initial_mip_levels; - const struct volume initial_size = image->size; - - initial_mip_levels = image->mip_levels; - for (i = 0; i < starting_mip_level; i++) - { - hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); - if (FAILED(hr)) - return hr; - - image->pixels += slice_pitch * image->size.depth; - d3dx_get_next_mip_level_size(&image->size); - if (--image->mip_levels == 1) - break; - } - - TRACE("Requested starting mip level %u, actual starting mip level is %u (of %u total in image).\n", - starting_mip_level, (initial_mip_levels - image->mip_levels), initial_mip_levels); - TRACE("Original dimensions %s, new dimensions %s.\n", debug_volume(&initial_size), debug_volume(&image->size)); - } - - return D3D_OK; -} - -static BOOL convert_dib_to_bmp(const void **data, unsigned int *size) -{ - ULONG header_size; - ULONG count = 0; - ULONG offset; - BITMAPFILEHEADER *header; - BYTE *new_data; - UINT new_size; - - if ((*size < 4) || (*size < (header_size = *(ULONG*)*data))) - return FALSE; - - if ((header_size == sizeof(BITMAPINFOHEADER)) || - (header_size == sizeof(BITMAPV4HEADER)) || - (header_size == sizeof(BITMAPV5HEADER)) || - (header_size == 64 /* sizeof(BITMAPCOREHEADER2) */)) - { - /* All structures begin with the same memory layout as BITMAPINFOHEADER */ - BITMAPINFOHEADER *info_header = (BITMAPINFOHEADER*)*data; - count = info_header->biClrUsed; - - if (!count && info_header->biBitCount <= 8) - count = 1 << info_header->biBitCount; - - offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBQUAD) * count; - - /* For BITMAPINFOHEADER with BI_BITFIELDS compression, there are 3 additional color masks after header */ - if ((info_header->biSize == sizeof(BITMAPINFOHEADER)) && (info_header->biCompression == BI_BITFIELDS)) - offset += 3 * sizeof(DWORD); - } - else if (header_size == sizeof(BITMAPCOREHEADER)) - { - BITMAPCOREHEADER *core_header = (BITMAPCOREHEADER*)*data; - - if (core_header->bcBitCount <= 8) - count = 1 << core_header->bcBitCount; - - offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBTRIPLE) * count; - } - else - { - return FALSE; - } - - TRACE("Converting DIB file to BMP\n"); - - new_size = *size + sizeof(BITMAPFILEHEADER); - new_data = malloc(new_size); - CopyMemory(new_data + sizeof(BITMAPFILEHEADER), *data, *size); - - /* Add BMP header */ - header = (BITMAPFILEHEADER*)new_data; - header->bfType = 0x4d42; /* BM */ - header->bfSize = new_size; - header->bfReserved1 = 0; - header->bfReserved2 = 0; - header->bfOffBits = offset; - - /* Update input data */ - *data = new_data; - *size = new_size; - - return TRUE; -} - -/* windowscodecs always returns xRGB, but we should return ARGB if and only if - * at least one pixel has a non-zero alpha component. */ -static BOOL image_is_argb(IWICBitmapFrameDecode *frame, struct d3dx_image *image) -{ - unsigned int size, i; - BYTE *buffer; - HRESULT hr; - - if (image->format != D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM || image->image_file_format != D3DXIFF_BMP) - return FALSE; - - size = image->size.width * image->size.height * 4; - if (!(buffer = malloc(size))) - return FALSE; - - if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, image->size.width * 4, size, buffer))) - { - ERR("Failed to copy pixels, hr %#lx.\n", hr); - free(buffer); - return FALSE; - } - - for (i = 0; i < image->size.width * image->size.height; ++i) - { - if (buffer[i * 4 + 3]) - { - free(buffer); - return TRUE; - } - } - - free(buffer); - return FALSE; -} - -struct d3dx_wic_file_format -{ - const GUID *wic_container_guid; - D3DXIMAGE_FILEFORMAT d3dx_file_format; -}; - -static const GUID *d3dx_file_format_to_wic_container_guid(D3DXIMAGE_FILEFORMAT iff) -{ - switch (iff) - { - case D3DXIFF_BMP: return &GUID_ContainerFormatBmp; - case D3DXIFF_JPG: return &GUID_ContainerFormatJpeg; - case D3DXIFF_PNG: return &GUID_ContainerFormatPng; - default: - assert(0); /* Shouldn't happen. */ - return NULL; - } -} - -static const char *debug_d3dx_image_file_format(D3DXIMAGE_FILEFORMAT format) -{ - switch (format) - { -#define FMT_TO_STR(format) case format: return #format - FMT_TO_STR(D3DXIFF_BMP); - FMT_TO_STR(D3DXIFF_JPG); - FMT_TO_STR(D3DXIFF_TGA); - FMT_TO_STR(D3DXIFF_PNG); - FMT_TO_STR(D3DXIFF_DDS); - FMT_TO_STR(D3DXIFF_PPM); - FMT_TO_STR(D3DXIFF_DIB); - FMT_TO_STR(D3DXIFF_HDR); - FMT_TO_STR(D3DXIFF_PFM); -#undef FMT_TO_STR - default: - return "unrecognized"; - } -} - -static HRESULT d3dx_image_wic_frame_decode(struct d3dx_image *image, - IWICImagingFactory *wic_factory, IWICBitmapFrameDecode *bitmap_frame) -{ - const struct pixel_format_desc *fmt_desc; - uint32_t row_pitch, slice_pitch; - IWICPalette *wic_palette = NULL; - PALETTEENTRY *palette = NULL; - WICColor *colors = NULL; - BYTE *buffer = NULL; - HRESULT hr; - - fmt_desc = get_d3dx_pixel_format_info(image->format); - hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); - if (FAILED(hr)) - return hr; - - /* Allocate a buffer for our image. */ - if (!(buffer = malloc(slice_pitch))) - return E_OUTOFMEMORY; - - hr = IWICBitmapFrameDecode_CopyPixels(bitmap_frame, NULL, row_pitch, slice_pitch, buffer); - if (FAILED(hr)) - { - free(buffer); - return hr; - } - - if (is_index_format(fmt_desc)) - { - uint32_t nb_colors, i; - - hr = IWICImagingFactory_CreatePalette(wic_factory, &wic_palette); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapFrameDecode_CopyPalette(bitmap_frame, wic_palette); - if (FAILED(hr)) - goto exit; - - hr = IWICPalette_GetColorCount(wic_palette, &nb_colors); - if (FAILED(hr)) - goto exit; - - colors = malloc(nb_colors * sizeof(colors[0])); - palette = malloc(nb_colors * sizeof(palette[0])); - if (!colors || !palette) - { - hr = E_OUTOFMEMORY; - goto exit; - } - - hr = IWICPalette_GetColors(wic_palette, nb_colors, colors, &nb_colors); - if (FAILED(hr)) - goto exit; - - /* Convert colors from WICColor (ARGB) to PALETTEENTRY (ABGR) */ - for (i = 0; i < nb_colors; i++) - { - palette[i].peRed = (colors[i] >> 16) & 0xff; - palette[i].peGreen = (colors[i] >> 8) & 0xff; - palette[i].peBlue = colors[i] & 0xff; - palette[i].peFlags = (colors[i] >> 24) & 0xff; /* peFlags is the alpha component in DX8 and higher */ - } - } - - image->image_buf = image->pixels = buffer; - image->image_palette = image->palette = palette; - -exit: - free(colors); - if (image->image_buf != buffer) - free(buffer); - if (image->image_palette != palette) - free(palette); - if (wic_palette) - IWICPalette_Release(wic_palette); - - return hr; -} - -static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src_data_size, - struct d3dx_image *image, D3DXIMAGE_FILEFORMAT d3dx_file_format, uint32_t flags) -{ - const GUID *container_format_guid = d3dx_file_format_to_wic_container_guid(d3dx_file_format); - IWICBitmapFrameDecode *bitmap_frame = NULL; - IWICBitmapDecoder *bitmap_decoder = NULL; - IWICImagingFactory *wic_factory; - WICPixelFormatGUID pixel_format; - IWICStream *wic_stream = NULL; - uint32_t frame_count = 0; - HRESULT hr; - - hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &wic_factory); - if (FAILED(hr)) - return hr; - - hr = IWICImagingFactory_CreateDecoder(wic_factory, container_format_guid, NULL, &bitmap_decoder); - if (FAILED(hr)) - goto exit; - - hr = IWICImagingFactory_CreateStream(wic_factory, &wic_stream); - if (FAILED(hr)) - goto exit; - - hr = IWICStream_InitializeFromMemory(wic_stream, (BYTE *)src_data, src_data_size); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapDecoder_Initialize(bitmap_decoder, (IStream *)wic_stream, 0); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapDecoder_GetFrameCount(bitmap_decoder, &frame_count); - if (FAILED(hr) || (SUCCEEDED(hr) && !frame_count)) - { - hr = D3DXERR_INVALIDDATA; - goto exit; - } - - image->image_file_format = d3dx_file_format; - hr = IWICBitmapDecoder_GetFrame(bitmap_decoder, 0, &bitmap_frame); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapFrameDecode_GetSize(bitmap_frame, &image->size.width, &image->size.height); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapFrameDecode_GetPixelFormat(bitmap_frame, &pixel_format); - if (FAILED(hr)) - goto exit; - - image->format = d3dx_pixel_format_id_from_wic_pixel_format(&pixel_format); - if (image->format == D3DX_PIXEL_FORMAT_COUNT) - { - WARN("Unsupported pixel format %s.\n", debugstr_guid(&pixel_format)); - hr = D3DXERR_INVALIDDATA; - goto exit; - } - - if (image_is_argb(bitmap_frame, image)) - image->format = D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; - - if (!(flags & D3DX_IMAGE_INFO_ONLY)) - { - hr = d3dx_image_wic_frame_decode(image, wic_factory, bitmap_frame); - if (FAILED(hr)) - goto exit; - } - - image->size.depth = 1; - image->mip_levels = 1; - image->layer_count = 1; - image->resource_type = D3DRTYPE_TEXTURE; - -exit: - if (bitmap_frame) - IWICBitmapFrameDecode_Release(bitmap_frame); - if (bitmap_decoder) - IWICBitmapDecoder_Release(bitmap_decoder); - if (wic_stream) - IWICStream_Release(wic_stream); - IWICImagingFactory_Release(wic_factory); - - return hr; -} - -static enum d3dx_pixel_format_id d3dx_get_tga_format_for_bpp(uint8_t bpp) -{ - switch (bpp) - { - case 15: return D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM; - case 16: return D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM; - case 24: return D3DX_PIXEL_FORMAT_B8G8R8_UNORM; - case 32: return D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; - default: - WARN("Unhandled bpp %u for targa.\n", bpp); - return D3DX_PIXEL_FORMAT_COUNT; - } -} - -#define IMAGETYPE_COLORMAPPED 1 -#define IMAGETYPE_TRUECOLOR 2 -#define IMAGETYPE_GRAYSCALE 3 -#define IMAGETYPE_MASK 0x07 -#define IMAGETYPE_RLE 8 - -#define IMAGE_RIGHTTOLEFT 0x10 -#define IMAGE_TOPTOBOTTOM 0x20 - -#include "pshpack1.h" -struct tga_header -{ - uint8_t id_length; - uint8_t color_map_type; - uint8_t image_type; - uint16_t color_map_firstentry; - uint16_t color_map_length; - uint8_t color_map_entrysize; - uint16_t xorigin; - uint16_t yorigin; - uint16_t width; - uint16_t height; - uint8_t depth; - uint8_t image_descriptor; -}; -#include "poppack.h" - -static HRESULT d3dx_image_tga_rle_decode_row(const uint8_t **src, uint32_t src_bytes_left, uint32_t row_width, - uint32_t bytes_per_pixel, uint8_t *dst_row) -{ - const uint8_t *src_ptr = *src; - uint32_t pixel_count = 0; - - while (pixel_count != row_width) - { - uint32_t rle_count = (src_ptr[0] & 0x7f) + 1; - uint32_t rle_packet_size = 1; - - rle_packet_size += (src_ptr[0] & 0x80) ? bytes_per_pixel : (bytes_per_pixel * rle_count); - if ((rle_packet_size > src_bytes_left) || (pixel_count + rle_count) > row_width) - return D3DXERR_INVALIDDATA; - - if (src_ptr[0] & 0x80) - { - uint32_t i; - - for (i = 0; i < rle_count; ++i) - memcpy(&dst_row[(pixel_count + i) * bytes_per_pixel], src_ptr + 1, bytes_per_pixel); - } - else - { - memcpy(&dst_row[pixel_count * bytes_per_pixel], src_ptr + 1, rle_packet_size - 1); - } - - src_ptr += rle_packet_size; - src_bytes_left -= rle_packet_size; - pixel_count += rle_count; - if (!src_bytes_left && pixel_count != row_width) - return D3DXERR_INVALIDDATA; - } - - *src = src_ptr; - return D3D_OK; -} - -static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_size, uint32_t src_header_size, - struct d3dx_image *image) -{ - const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(image->format); - const struct tga_header *header = (const struct tga_header *)src_data; - const BOOL right_to_left = !!(header->image_descriptor & IMAGE_RIGHTTOLEFT); - const BOOL bottom_to_top = !(header->image_descriptor & IMAGE_TOPTOBOTTOM); - const BOOL is_rle = !!(header->image_type & IMAGETYPE_RLE); - uint8_t *img_buf = NULL, *src_row = NULL; - uint32_t row_pitch, slice_pitch, i; - PALETTEENTRY *palette = NULL; - const uint8_t *src_pos; - HRESULT hr; - - hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); - if (FAILED(hr)) - return hr; - - /* File is too small. */ - if (!is_rle && (src_header_size + slice_pitch) > src_data_size) - return D3DXERR_INVALIDDATA; - - if (image->format == D3DX_PIXEL_FORMAT_P8_UINT) - { - const uint8_t *src_palette = ((const uint8_t *)src_data) + sizeof(*header) + header->id_length; - const struct volume image_map_size = { header->color_map_length, 1, 1 }; - uint32_t src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch; - const struct pixel_format_desc *src_desc, *dst_desc; - - if (!(palette = malloc(sizeof(*palette) * 256))) - return E_OUTOFMEMORY; - - /* - * Convert from a TGA colormap to PALETTEENTRY. TGA is BGRA, - * PALETTEENTRY is RGBA. - */ - src_desc = get_d3dx_pixel_format_info(d3dx_get_tga_format_for_bpp(header->color_map_entrysize)); - hr = d3dx_calculate_pixels_size(src_desc->format, header->color_map_length, 1, &src_row_pitch, &src_slice_pitch); - if (FAILED(hr)) - goto exit; - - dst_desc = get_format_info(D3DFMT_A8B8G8R8); - d3dx_calculate_pixels_size(dst_desc->format, 256, 1, &dst_row_pitch, &dst_slice_pitch); - convert_argb_pixels(src_palette, src_row_pitch, src_slice_pitch, &image_map_size, src_desc, (BYTE *)palette, - dst_row_pitch, dst_slice_pitch, &image_map_size, dst_desc, 0, NULL); - - /* Initialize unused palette entries to 0xff. */ - if (header->color_map_length < 256) - memset(&palette[header->color_map_length], 0xff, sizeof(*palette) * (256 - header->color_map_length)); - } - - if (!is_rle && !bottom_to_top && !right_to_left) - { - image->pixels = (uint8_t *)src_data + src_header_size; - image->image_palette = image->palette = palette; - return D3D_OK; - } - - if (!(img_buf = malloc(slice_pitch))) - { - hr = E_OUTOFMEMORY; - goto exit; - } - - /* Allocate an extra row to use as a temporary buffer. */ - if (is_rle) - { - if (!(src_row = malloc(row_pitch))) - { - hr = E_OUTOFMEMORY; - goto exit; - } - } - - src_pos = (const uint8_t *)src_data + src_header_size; - for (i = 0; i < image->size.height; ++i) - { - const uint32_t dst_row_idx = bottom_to_top ? (image->size.height - i - 1) : i; - uint8_t *dst_row = img_buf + (dst_row_idx * row_pitch); - - if (is_rle) - { - hr = d3dx_image_tga_rle_decode_row(&src_pos, src_data_size - (src_pos - (const uint8_t *)src_data), - image->size.width, fmt_desc->bytes_per_pixel, src_row); - if (FAILED(hr)) - goto exit; - } - else - { - src_row = (uint8_t *)src_pos; - src_pos += row_pitch; - } - - if (right_to_left) - { - const uint8_t *src_pixel = &src_row[((image->size.width - 1)) * fmt_desc->bytes_per_pixel]; - uint8_t *dst_pixel = dst_row; - uint32_t j; - - for (j = 0; j < image->size.width; ++j) - { - memcpy(dst_pixel, src_pixel, fmt_desc->bytes_per_pixel); - src_pixel -= fmt_desc->bytes_per_pixel; - dst_pixel += fmt_desc->bytes_per_pixel; - } - } - else - { - memcpy(dst_row, src_row, row_pitch); - } - } - - image->image_buf = image->pixels = img_buf; - image->image_palette = image->palette = palette; - -exit: - if (is_rle) - free(src_row); - if (img_buf && (image->image_buf != img_buf)) - free(img_buf); - if (palette && (image->image_palette != palette)) - free(palette); - - return hr; -} - -static HRESULT d3dx_initialize_image_from_tga(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, - uint32_t flags) -{ - const struct tga_header *header = (const struct tga_header *)src_data; - uint32_t expected_header_size = sizeof(*header); - - if (src_data_size < sizeof(*header)) - return D3DXERR_INVALIDDATA; - - expected_header_size += header->id_length; - expected_header_size += header->color_map_length * ((header->color_map_entrysize + 7) / CHAR_BIT); - if (src_data_size < expected_header_size) - return D3DXERR_INVALIDDATA; - - if (header->color_map_type && ((header->color_map_type > 1) || (!header->color_map_length) - || (d3dx_get_tga_format_for_bpp(header->color_map_entrysize) == D3DX_PIXEL_FORMAT_COUNT))) - return D3DXERR_INVALIDDATA; - - switch (header->image_type & IMAGETYPE_MASK) - { - case IMAGETYPE_COLORMAPPED: - if (header->depth != 8 || !header->color_map_type) - return D3DXERR_INVALIDDATA; - image->format = D3DX_PIXEL_FORMAT_P8_UINT; - break; - - case IMAGETYPE_TRUECOLOR: - if ((image->format = d3dx_get_tga_format_for_bpp(header->depth)) == D3DX_PIXEL_FORMAT_COUNT) - return D3DXERR_INVALIDDATA; - break; - - case IMAGETYPE_GRAYSCALE: - if (header->depth != 8) - return D3DXERR_INVALIDDATA; - image->format = D3DX_PIXEL_FORMAT_L8_UNORM; - break; - - default: - return D3DXERR_INVALIDDATA; - } - - set_volume_struct(&image->size, header->width, header->height, 1); - image->mip_levels = 1; - image->layer_count = 1; - image->resource_type = D3DRTYPE_TEXTURE; - image->image_file_format = D3DXIFF_TGA; - - if (!(flags & D3DX_IMAGE_INFO_ONLY)) - return d3dx_image_tga_decode(src_data, src_data_size, expected_header_size, image); - - return D3D_OK; -} - -HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, - uint32_t starting_mip_level, uint32_t flags) -{ - D3DXIMAGE_FILEFORMAT iff = D3DXIFF_FORCE_DWORD; - HRESULT hr; - - if (!src_data || !src_data_size || !image) - return D3DERR_INVALIDCALL; - - memset(image, 0, sizeof(*image)); - if (!d3dx_get_image_file_format_from_file_signature(src_data, src_data_size, &iff)) - { - uint32_t src_image_size = src_data_size; - const void *src_image = src_data; - - if (convert_dib_to_bmp(&src_image, &src_image_size)) - { - hr = d3dx_image_init(src_image, src_image_size, image, starting_mip_level, flags); - free((void *)src_image); - if (SUCCEEDED(hr)) - image->image_file_format = D3DXIFF_DIB; - return hr; - } - - /* Last resort, try TGA. */ - return d3dx_initialize_image_from_tga(src_data, src_data_size, image, flags); - } - - switch (iff) - { - case D3DXIFF_BMP: - case D3DXIFF_JPG: - case D3DXIFF_PNG: - hr = d3dx_initialize_image_from_wic(src_data, src_data_size, image, iff, flags); - break; - - case D3DXIFF_DDS: - hr = d3dx_initialize_image_from_dds(src_data, src_data_size, image, starting_mip_level); - break; - - case D3DXIFF_PPM: - case D3DXIFF_HDR: - case D3DXIFF_PFM: - WARN("Unsupported file format %s.\n", debug_d3dx_image_file_format(iff)); - hr = E_NOTIMPL; - break; - - case D3DXIFF_FORCE_DWORD: - ERR("Unrecognized file format.\n"); - hr = D3DXERR_INVALIDDATA; - break; - - default: - assert(0); - return E_FAIL; - } - - return hr; -} - -void d3dx_image_cleanup(struct d3dx_image *image) -{ - free(image->image_buf); - free(image->image_palette); -} - -HRESULT d3dx_image_get_pixels(struct d3dx_image *image, uint32_t layer, uint32_t mip_level, - struct d3dx_pixels *pixels) -{ - struct volume mip_level_size = image->size; - const BYTE *pixels_ptr = image->pixels; - uint32_t row_pitch, slice_pitch, i; - RECT unaligned_rect; - HRESULT hr = S_OK; - - if (mip_level >= image->mip_levels) - { - ERR("Tried to retrieve mip level %u, but image only has %u mip levels.\n", mip_level, image->mip_levels); - return E_FAIL; - } - - if (layer >= image->layer_count) - { - ERR("Tried to retrieve layer %u, but image only has %u layers.\n", layer, image->layer_count); - return E_FAIL; - } - - slice_pitch = row_pitch = 0; - for (i = 0; i < image->mip_levels; i++) - { - hr = d3dx_calculate_pixels_size(image->format, mip_level_size.width, mip_level_size.height, &row_pitch, &slice_pitch); - if (FAILED(hr)) - return hr; - - if (i == mip_level) - break; - - pixels_ptr += slice_pitch * mip_level_size.depth; - d3dx_get_next_mip_level_size(&mip_level_size); - } - - pixels_ptr += (layer * image->layer_pitch); - SetRect(&unaligned_rect, 0, 0, mip_level_size.width, mip_level_size.height); - set_d3dx_pixels(pixels, pixels_ptr, row_pitch, slice_pitch, image->palette, mip_level_size.width, - mip_level_size.height, mip_level_size.depth, &unaligned_rect); - - return D3D_OK; -} - -void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image) -{ - info->ImageFileFormat = image->image_file_format; - info->Width = image->size.width; - info->Height = image->size.height; - info->Depth = image->size.depth; - info->MipLevels = image->mip_levels; - switch (image->format) - { - case D3DX_PIXEL_FORMAT_R16G16B16_UNORM: - info->Format = D3DFMT_A16B16G16R16; - break; - - case D3DX_PIXEL_FORMAT_B8G8R8_UNORM: - if (info->ImageFileFormat == D3DXIFF_PNG || info->ImageFileFormat == D3DXIFF_JPG) - info->Format = D3DFMT_X8R8G8B8; - else - info->Format = d3dformat_from_d3dx_pixel_format_id(image->format); - break; - - default: - info->Format = d3dformat_from_d3dx_pixel_format_id(image->format); - break; - } - info->ResourceType = image->resource_type; -} - -/************************************************************ - * D3DXGetImageInfoFromFileInMemory - * - * Fills a D3DXIMAGE_INFO structure with info about an image - * - * PARAMS - * data [I] pointer to the image file data - * datasize [I] size of the passed data - * info [O] pointer to the destination structure - * - * RETURNS - * Success: D3D_OK, if info is not NULL and data and datasize make up a valid image file or - * if info is NULL and data and datasize are not NULL - * Failure: D3DXERR_INVALIDDATA, if data is no valid image file and datasize and info are not NULL - * D3DERR_INVALIDCALL, if data is NULL or - * if datasize is 0 - * - * NOTES - * datasize may be bigger than the actual file size - * - */ -HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, D3DXIMAGE_INFO *info) -{ - struct d3dx_image image; - HRESULT hr; - - TRACE("(%p, %d, %p)\n", data, datasize, info); - - if (!data || !datasize) - return D3DERR_INVALIDCALL; - - if (!info) - return D3D_OK; - - hr = d3dx_image_init(data, datasize, &image, 0, D3DX_IMAGE_INFO_ONLY); - if (FAILED(hr)) { - TRACE("Invalid or unsupported image file\n"); - return D3DXERR_INVALIDDATA; - } - - d3dximage_info_from_d3dx_image(info, &image); - return D3D_OK; -} - -/************************************************************ - * D3DXGetImageInfoFromFile - * - * RETURNS - * Success: D3D_OK, if we successfully load a valid image file or - * if we successfully load a file which is no valid image and info is NULL - * Failure: D3DXERR_INVALIDDATA, if we fail to load file or - * if file is not a valid image file and info is not NULL - * D3DERR_INVALIDCALL, if file is NULL - * - */ -HRESULT WINAPI D3DXGetImageInfoFromFileA(const char *file, D3DXIMAGE_INFO *info) -{ - WCHAR *widename; - HRESULT hr; - int strlength; - - TRACE("file %s, info %p.\n", debugstr_a(file), info); - - if( !file ) return D3DERR_INVALIDCALL; - - strlength = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0); - widename = malloc(strlength * sizeof(*widename)); - MultiByteToWideChar(CP_ACP, 0, file, -1, widename, strlength); - - hr = D3DXGetImageInfoFromFileW(widename, info); - free(widename); - - return hr; -} - -HRESULT WINAPI D3DXGetImageInfoFromFileW(const WCHAR *file, D3DXIMAGE_INFO *info) -{ - void *buffer; - HRESULT hr; - DWORD size; - - TRACE("file %s, info %p.\n", debugstr_w(file), info); - - if (!file) - return D3DERR_INVALIDCALL; - - if (FAILED(map_view_of_file(file, &buffer, &size))) - return D3DXERR_INVALIDDATA; - - hr = D3DXGetImageInfoFromFileInMemory(buffer, size, info); - UnmapViewOfFile(buffer); - - return hr; -} - -/************************************************************ - * D3DXGetImageInfoFromResource - * - * RETURNS - * Success: D3D_OK, if resource is a valid image file - * Failure: D3DXERR_INVALIDDATA, if resource is no valid image file or NULL or - * if we fail to load resource - * - */ -HRESULT WINAPI D3DXGetImageInfoFromResourceA(HMODULE module, const char *resource, D3DXIMAGE_INFO *info) -{ - HRSRC resinfo; - void *buffer; - DWORD size; - - TRACE("module %p, resource %s, info %p.\n", module, debugstr_a(resource), info); - - if (!(resinfo = FindResourceA(module, resource, (const char *)RT_RCDATA)) - /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ - && !(resinfo = FindResourceA(module, resource, (const char *)RT_BITMAP))) - return D3DXERR_INVALIDDATA; - - if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size))) - return D3DXERR_INVALIDDATA; - - return D3DXGetImageInfoFromFileInMemory(buffer, size, info); -} - -HRESULT WINAPI D3DXGetImageInfoFromResourceW(HMODULE module, const WCHAR *resource, D3DXIMAGE_INFO *info) -{ - HRSRC resinfo; - void *buffer; - DWORD size; - - TRACE("module %p, resource %s, info %p.\n", module, debugstr_w(resource), info); - - if (!(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)) - /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ - && !(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_BITMAP))) - return D3DXERR_INVALIDDATA; - - if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size))) - return D3DXERR_INVALIDDATA; - - return D3DXGetImageInfoFromFileInMemory(buffer, size, info); -} - -static HRESULT d3dx_load_surface_from_memory(IDirect3DSurface9 *dst_surface, - const PALETTEENTRY *dst_palette, const RECT *dst_rect, const void *src_memory, - enum d3dx_pixel_format_id src_format, uint32_t src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect, - DWORD filter, D3DCOLOR color_key) -{ - const struct pixel_format_desc *src_desc, *dst_desc; - struct d3dx_pixels src_pixels, dst_pixels; - RECT dst_rect_tmp, dst_rect_aligned; - IDirect3DSurface9 *surface; - D3DLOCKED_RECT lock_rect; - D3DSURFACE_DESC desc; - HRESULT hr; - - IDirect3DSurface9_GetDesc(dst_surface, &desc); - if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) - { - TRACE("Multisampled destination surface, doing nothing.\n"); - return D3D_OK; - } - - dst_desc = get_format_info(desc.Format); - if (!dst_rect) - { - SetRect(&dst_rect_tmp, 0, 0, desc.Width, desc.Height); - dst_rect = &dst_rect_tmp; - } - else - { - if (dst_rect->left > dst_rect->right || dst_rect->right > desc.Width - || dst_rect->top > dst_rect->bottom || dst_rect->bottom > desc.Height - || dst_rect->left < 0 || dst_rect->top < 0) - { - WARN("Invalid dst_rect specified.\n"); - return D3DERR_INVALIDCALL; - } - if (dst_rect->left == dst_rect->right || dst_rect->top == dst_rect->bottom) - { - WARN("Empty dst_rect specified.\n"); - return D3D_OK; - } - } - - src_desc = get_d3dx_pixel_format_info(src_format); - hr = d3dx_pixels_init(src_memory, src_pitch, 0, src_palette, src_desc->format, - src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1, &src_pixels); - if (FAILED(hr)) - return hr; - - get_aligned_rect(dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, desc.Width, desc.Height, - dst_desc, &dst_rect_aligned); - if (FAILED(hr = lock_surface(dst_surface, &dst_rect_aligned, &lock_rect, &surface, TRUE))) - return hr; - - set_d3dx_pixels(&dst_pixels, lock_rect.pBits, lock_rect.Pitch, 0, dst_palette, - (dst_rect_aligned.right - dst_rect_aligned.left), (dst_rect_aligned.bottom - dst_rect_aligned.top), 1, - dst_rect); - OffsetRect(&dst_pixels.unaligned_rect, -dst_rect_aligned.left, -dst_rect_aligned.top); - - if (FAILED(hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_desc, &src_pixels, src_desc, filter, color_key))) - { - unlock_surface(dst_surface, &dst_rect_aligned, surface, FALSE); - return hr; - } - - return unlock_surface(dst_surface, &dst_rect_aligned, surface, TRUE); + d3dximage_info_from_d3dx_image(info, &image); + return D3D_OK; } /************************************************************ - * D3DXLoadSurfaceFromFileInMemory - * - * Loads data from a given buffer into a surface and fills a given - * D3DXIMAGE_INFO structure with info about the source data. - * - * PARAMS - * pDestSurface [I] pointer to the surface - * pDestPalette [I] palette to use - * pDestRect [I] to be filled area of the surface - * pSrcData [I] pointer to the source data - * SrcDataSize [I] size of the source data in bytes - * pSrcRect [I] area of the source data to load - * dwFilter [I] filter to apply on stretching - * Colorkey [I] colorkey - * pSrcInfo [O] pointer to a D3DXIMAGE_INFO structure + * D3DXGetImageInfoFromFile * * RETURNS - * Success: D3D_OK - * Failure: D3DERR_INVALIDCALL, if pDestSurface, pSrcData or SrcDataSize is NULL - * D3DXERR_INVALIDDATA, if pSrcData is no valid image file + * Success: D3D_OK, if we successfully load a valid image file or + * if we successfully load a file which is no valid image and info is NULL + * Failure: D3DXERR_INVALIDDATA, if we fail to load file or + * if file is not a valid image file and info is not NULL + * D3DERR_INVALIDCALL, if file is NULL * */ -HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(IDirect3DSurface9 *pDestSurface, - const PALETTEENTRY *pDestPalette, const RECT *pDestRect, const void *pSrcData, UINT SrcDataSize, - const RECT *pSrcRect, DWORD dwFilter, D3DCOLOR Colorkey, D3DXIMAGE_INFO *pSrcInfo) -{ - struct d3dx_pixels pixels = { 0 }; - struct d3dx_image image; - D3DXIMAGE_INFO img_info; - RECT src_rect; - HRESULT hr; - - TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_data %p, src_data_size %u, " - "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", - pDestSurface, pDestPalette, wine_dbgstr_rect(pDestRect), pSrcData, SrcDataSize, - wine_dbgstr_rect(pSrcRect), dwFilter, Colorkey, pSrcInfo); - - if (!pDestSurface || !pSrcData || !SrcDataSize) - return D3DERR_INVALIDCALL; - - if (FAILED(hr = d3dx9_handle_load_filter(&dwFilter))) - return hr; - - hr = d3dx_image_init(pSrcData, SrcDataSize, &image, 0, 0); - if (FAILED(hr)) - return D3DXERR_INVALIDDATA; - - d3dximage_info_from_d3dx_image(&img_info, &image); - if (pSrcRect) - src_rect = *pSrcRect; - else - SetRect(&src_rect, 0, 0, img_info.Width, img_info.Height); - - hr = d3dx_image_get_pixels(&image, 0, 0, &pixels); - if (FAILED(hr)) - goto exit; - - hr = d3dx_load_surface_from_memory(pDestSurface, pDestPalette, pDestRect, pixels.data, image.format, pixels.row_pitch, - pixels.palette, &src_rect, dwFilter, Colorkey); - if (SUCCEEDED(hr) && pSrcInfo) - *pSrcInfo = img_info; - -exit: - d3dx_image_cleanup(&image); - return FAILED(hr) ? D3DXERR_INVALIDDATA : D3D_OK; -} - -HRESULT WINAPI D3DXLoadSurfaceFromFileA(IDirect3DSurface9 *dst_surface, - const PALETTEENTRY *dst_palette, const RECT *dst_rect, const char *src_file, - const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) -{ - WCHAR *src_file_w; - HRESULT hr; - int strlength; - - TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, " - "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", - dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_a(src_file), - wine_dbgstr_rect(src_rect), filter, color_key, src_info); - - if (!src_file || !dst_surface) - return D3DERR_INVALIDCALL; - - strlength = MultiByteToWideChar(CP_ACP, 0, src_file, -1, NULL, 0); - src_file_w = malloc(strlength * sizeof(*src_file_w)); - MultiByteToWideChar(CP_ACP, 0, src_file, -1, src_file_w, strlength); - - hr = D3DXLoadSurfaceFromFileW(dst_surface, dst_palette, dst_rect, - src_file_w, src_rect, filter, color_key, src_info); - free(src_file_w); - - return hr; -} - -HRESULT WINAPI D3DXLoadSurfaceFromFileW(IDirect3DSurface9 *dst_surface, - const PALETTEENTRY *dst_palette, const RECT *dst_rect, const WCHAR *src_file, - const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) +HRESULT WINAPI D3DXGetImageInfoFromFileA(const char *file, D3DXIMAGE_INFO *info) { - DWORD data_size; - void *data; + WCHAR *widename; HRESULT hr; + int strlength; - TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, " - "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", - dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_w(src_file), - wine_dbgstr_rect(src_rect), filter, color_key, src_info); - - if (!src_file || !dst_surface) - return D3DERR_INVALIDCALL; - - if (FAILED(map_view_of_file(src_file, &data, &data_size))) - return D3DXERR_INVALIDDATA; - - hr = D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, - data, data_size, src_rect, filter, color_key, src_info); - UnmapViewOfFile(data); - - return hr; -} - -HRESULT WINAPI D3DXLoadSurfaceFromResourceA(IDirect3DSurface9 *dst_surface, - const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const char *resource, - const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) -{ - DWORD data_size; - HRSRC resinfo; - void *data; - - TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, " - "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", - dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_a(resource), - wine_dbgstr_rect(src_rect), filter, color_key, src_info); - - if (!dst_surface) - return D3DERR_INVALIDCALL; - - if (!(resinfo = FindResourceA(src_module, resource, (const char *)RT_RCDATA)) - /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ - && !(resinfo = FindResourceA(src_module, resource, (const char *)RT_BITMAP))) - return D3DXERR_INVALIDDATA; - - if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size))) - return D3DXERR_INVALIDDATA; - - return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, - data, data_size, src_rect, filter, color_key, src_info); -} - -HRESULT WINAPI D3DXLoadSurfaceFromResourceW(IDirect3DSurface9 *dst_surface, - const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const WCHAR *resource, - const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) -{ - DWORD data_size; - HRSRC resinfo; - void *data; - - TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, " - "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", - dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_w(resource), - wine_dbgstr_rect(src_rect), filter, color_key, src_info); - - if (!dst_surface) - return D3DERR_INVALIDCALL; - - if (!(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_RCDATA)) - /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ - && !(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_BITMAP))) - return D3DXERR_INVALIDDATA; - - if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size))) - return D3DXERR_INVALIDDATA; - - return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, - data, data_size, src_rect, filter, color_key, src_info); -} - - -/************************************************************ - * helper functions for D3DXLoadSurfaceFromMemory - */ -struct argb_conversion_info -{ - const struct pixel_format_desc *srcformat; - const struct pixel_format_desc *destformat; - DWORD srcshift[4], destshift[4]; - DWORD srcmask[4], destmask[4]; - BOOL process_channel[4]; - DWORD channelmask; -}; - -static void init_argb_conversion_info(const struct pixel_format_desc *srcformat, const struct pixel_format_desc *destformat, struct argb_conversion_info *info) -{ - UINT i; - ZeroMemory(info->process_channel, 4 * sizeof(BOOL)); - info->channelmask = 0; - - info->srcformat = srcformat; - info->destformat = destformat; + TRACE("file %s, info %p.\n", debugstr_a(file), info); - for(i = 0;i < 4;i++) { - /* srcshift is used to extract the _relevant_ components */ - info->srcshift[i] = srcformat->shift[i] + max( srcformat->bits[i] - destformat->bits[i], 0); + if( !file ) return D3DERR_INVALIDCALL; - /* destshift is used to move the components to the correct position */ - info->destshift[i] = destformat->shift[i] + max(destformat->bits[i] - srcformat->bits[i], 0); + strlength = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0); + widename = malloc(strlength * sizeof(*widename)); + MultiByteToWideChar(CP_ACP, 0, file, -1, widename, strlength); - info->srcmask[i] = ((1 << srcformat->bits[i]) - 1) << srcformat->shift[i]; - info->destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i]; + hr = D3DXGetImageInfoFromFileW(widename, info); + free(widename); - /* channelmask specifies bits which aren't used in the source format but in the destination one */ - if(destformat->bits[i]) { - if(srcformat->bits[i]) info->process_channel[i] = TRUE; - else info->channelmask |= info->destmask[i]; - } - } + return hr; } -/************************************************************ - * get_relevant_argb_components - * - * Extracts the relevant components from the source color and - * drops the less significant bits if they aren't used by the destination format. - */ -static void get_relevant_argb_components(const struct argb_conversion_info *info, const BYTE *col, DWORD *out) +HRESULT WINAPI D3DXGetImageInfoFromFileW(const WCHAR *file, D3DXIMAGE_INFO *info) { - unsigned int i, j; - unsigned int component, mask; + void *buffer; + HRESULT hr; + DWORD size; - for (i = 0; i < 4; ++i) - { - if (!info->process_channel[i]) - continue; + TRACE("file %s, info %p.\n", debugstr_w(file), info); - component = 0; - mask = info->srcmask[i]; - for (j = 0; j < 4 && mask; ++j) - { - if (info->srcshift[i] < j * 8) - component |= (col[j] & mask) << (j * 8 - info->srcshift[i]); - else - component |= (col[j] & mask) >> (info->srcshift[i] - j * 8); - mask >>= 8; - } - out[i] = component; - } -} + if (!file) + return D3DERR_INVALIDCALL; -static float d3dx_clamp(float value, float min_value, float max_value) -{ - if (isnan(value)) - return max_value; - return value < min_value ? min_value : value > max_value ? max_value : value; + if (FAILED(map_view_of_file(file, &buffer, &size))) + return D3DXERR_INVALIDDATA; + + hr = D3DXGetImageInfoFromFileInMemory(buffer, size, info); + UnmapViewOfFile(buffer); + + return hr; } /************************************************************ - * make_argb_color + * D3DXGetImageInfoFromResource + * + * RETURNS + * Success: D3D_OK, if resource is a valid image file + * Failure: D3DXERR_INVALIDDATA, if resource is no valid image file or NULL or + * if we fail to load resource * - * Recombines the output of get_relevant_argb_components and converts - * it to the destination format. */ -static DWORD make_argb_color(const struct argb_conversion_info *info, const DWORD *in) +HRESULT WINAPI D3DXGetImageInfoFromResourceA(HMODULE module, const char *resource, D3DXIMAGE_INFO *info) { - UINT i; - DWORD val = 0; - - for(i = 0;i < 4;i++) { - if(info->process_channel[i]) { - /* necessary to make sure that e.g. an X4R4G4B4 white maps to an R8G8B8 white instead of 0xf0f0f0 */ - signed int shift; - for(shift = info->destshift[i]; shift > info->destformat->shift[i]; shift -= info->srcformat->bits[i]) val |= in[i] << shift; - val |= (in[i] >> (info->destformat->shift[i] - shift)) << info->destformat->shift[i]; - } - } - val |= info->channelmask; /* new channels are set to their maximal value */ - return val; -} + HRSRC resinfo; + void *buffer; + DWORD size; -static enum range get_range_for_component_type(enum component_type type) -{ - switch (type) - { - case CTYPE_SNORM: - return RANGE_SNORM; + TRACE("module %p, resource %s, info %p.\n", module, debugstr_a(resource), info); - case CTYPE_LUMA: - case CTYPE_INDEX: - case CTYPE_UNORM: - return RANGE_UNORM; + if (!(resinfo = FindResourceA(module, resource, (const char *)RT_RCDATA)) + /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ + && !(resinfo = FindResourceA(module, resource, (const char *)RT_BITMAP))) + return D3DXERR_INVALIDDATA; - case CTYPE_EMPTY: - case CTYPE_FLOAT: - return RANGE_FULL; + if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size))) + return D3DXERR_INVALIDDATA; - default: - assert(0); - return RANGE_FULL; - } + return D3DXGetImageInfoFromFileInMemory(buffer, size, info); } -/* It doesn't work for components bigger than 32 bits (or somewhat smaller but unaligned). */ -void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *src, const PALETTEENTRY *palette, - struct d3dx_color *dst) +HRESULT WINAPI D3DXGetImageInfoFromResourceW(HMODULE module, const WCHAR *resource, D3DXIMAGE_INFO *info) { - DWORD mask, tmp; - unsigned int c; - - dst->rgb_range = get_range_for_component_type(format->rgb_type); - dst->a_range = get_range_for_component_type(format->a_type); - for (c = 0; c < 4; ++c) - { - const enum component_type dst_ctype = !c ? format->a_type : format->rgb_type; - static const unsigned int component_offsets[4] = {3, 0, 1, 2}; - float *dst_component = &dst->value.x + component_offsets[c]; + HRSRC resinfo; + void *buffer; + DWORD size; - if (format->bits[c]) - { - mask = ~0u >> (32 - format->bits[c]); + TRACE("module %p, resource %s, info %p.\n", module, debugstr_w(resource), info); - memcpy(&tmp, src + format->shift[c] / 8, - min(sizeof(DWORD), (format->shift[c] % 8 + format->bits[c] + 7) / 8)); - tmp = (tmp >> (format->shift[c] % 8)) & mask; + if (!(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)) + /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ + && !(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_BITMAP))) + return D3DXERR_INVALIDDATA; - switch (dst_ctype) - { - case CTYPE_FLOAT: - if (format->bits[c] == 16) - *dst_component = float_16_to_32(tmp); - else - *dst_component = *(float *)&tmp; - break; - - case CTYPE_INDEX: - *dst_component = (&palette[tmp].peRed)[component_offsets[c]] / 255.0f; - break; - - case CTYPE_LUMA: - case CTYPE_UNORM: - *dst_component = (float)tmp / mask; - break; - - case CTYPE_SNORM: - { - const uint32_t sign_bit = (1u << (format->bits[c] - 1)); - uint32_t tmp_extended = (tmp & sign_bit) ? (tmp | ~(sign_bit - 1)) : tmp; - - /* - * In order to clamp to an even range, we need to ignore - * the maximum negative value. - */ - if (tmp == sign_bit) - tmp_extended |= 1; - - *dst_component = (float)(((int32_t)tmp_extended)) / (sign_bit - 1); - break; - } + if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size))) + return D3DXERR_INVALIDDATA; - default: - break; - } - } - else if (dst_ctype == CTYPE_LUMA) - { - assert(format->bits[1]); - *dst_component = dst->value.x; - } - else - { - *dst_component = 1.0f; - } - } + return D3DXGetImageInfoFromFileInMemory(buffer, size, info); } -/* It doesn't work for components bigger than 32 bits. */ -void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst) +static HRESULT d3dx_load_surface_from_memory(IDirect3DSurface9 *dst_surface, + const PALETTEENTRY *dst_palette, const RECT *dst_rect, const void *src_memory, + enum d3dx_pixel_format_id src_format, uint32_t src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect, + DWORD filter, D3DCOLOR color_key) { - DWORD v, mask32; - unsigned int c, i; - - memset(dst, 0, format->bytes_per_pixel); + const struct pixel_format_desc *src_desc, *dst_desc; + struct d3dx_pixels src_pixels, dst_pixels; + RECT dst_rect_tmp, dst_rect_aligned; + IDirect3DSurface9 *surface; + D3DLOCKED_RECT lock_rect; + D3DSURFACE_DESC desc; + HRESULT hr; - for (c = 0; c < 4; ++c) + IDirect3DSurface9_GetDesc(dst_surface, &desc); + if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) { - const enum component_type dst_ctype = !c ? format->a_type : format->rgb_type; - static const unsigned int component_offsets[4] = {3, 0, 1, 2}; - const float src_component = *(&src->value.x + component_offsets[c]); - const enum range src_range = !c ? src->a_range : src->rgb_range; - - if (!format->bits[c]) - continue; - - mask32 = ~0u >> (32 - format->bits[c]); - - switch (dst_ctype) - { - case CTYPE_FLOAT: - if (format->bits[c] == 16) - v = float_32_to_16(src_component); - else - v = *(DWORD *)&src_component; - break; - - case CTYPE_LUMA: - { - float val = src->value.x * 0.2125f + src->value.y * 0.7154f + src->value.z * 0.0721f; - - if (src_range == RANGE_SNORM) - val = (val + 1.0f) / 2.0f; - - v = d3dx_clamp(val, 0.0f, 1.0f) * ((1u << format->bits[c]) - 1) + 0.5f; - break; - } - - case CTYPE_UNORM: - { - float val = src_component; - - if (src_range == RANGE_SNORM) - val = (val + 1.0f) / 2.0f; - - v = d3dx_clamp(val, 0.0f, 1.0f) * ((1u << format->bits[c]) - 1) + 0.5f; - break; - } - - case CTYPE_SNORM: - { - const uint32_t max_value = (1u << (format->bits[c] - 1)) - 1; - float val = src_component; - - if (src_range == RANGE_UNORM) - val = (val * 2.0f) - 1.0f; - - v = d3dx_clamp(val, -1.0f, 1.0f) * max_value + 0.5f; - break; - } - - /* We shouldn't be trying to output to CTYPE_INDEX. */ - case CTYPE_INDEX: - assert(0); - break; - - default: - v = 0; - break; - } - - for (i = format->shift[c] / 8 * 8; i < format->shift[c] + format->bits[c]; i += 8) - { - BYTE mask, byte; - - if (format->shift[c] > i) - { - mask = mask32 << (format->shift[c] - i); - byte = (v << (format->shift[c] - i)) & mask; - } - else - { - mask = mask32 >> (i - format->shift[c]); - byte = (v >> (i - format->shift[c])) & mask; - } - dst[i / 8] |= byte; - } + TRACE("Multisampled destination surface, doing nothing.\n"); + return D3D_OK; } -} -/************************************************************ - * copy_pixels - * - * Copies the source buffer to the destination buffer. - * Works for any pixel format. - * The source and the destination must be block-aligned. - */ -void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, - BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *size, - const struct pixel_format_desc *format) -{ - UINT row, slice; - BYTE *dst_addr; - const BYTE *src_addr; - UINT row_block_count = (size->width + format->block_width - 1) / format->block_width; - UINT row_count = (size->height + format->block_height - 1) / format->block_height; - - for (slice = 0; slice < size->depth; slice++) + dst_desc = get_format_info(desc.Format); + if (!dst_rect) { - src_addr = src + slice * src_slice_pitch; - dst_addr = dst + slice * dst_slice_pitch; - - for (row = 0; row < row_count; row++) + SetRect(&dst_rect_tmp, 0, 0, desc.Width, desc.Height); + dst_rect = &dst_rect_tmp; + } + else + { + if (dst_rect->left > dst_rect->right || dst_rect->right > desc.Width + || dst_rect->top > dst_rect->bottom || dst_rect->bottom > desc.Height + || dst_rect->left < 0 || dst_rect->top < 0) { - memcpy(dst_addr, src_addr, row_block_count * format->block_byte_count); - src_addr += src_row_pitch; - dst_addr += dst_row_pitch; + WARN("Invalid dst_rect specified.\n"); + return D3DERR_INVALIDCALL; + } + if (dst_rect->left == dst_rect->right || dst_rect->top == dst_rect->bottom) + { + WARN("Empty dst_rect specified.\n"); + return D3D_OK; } } -} -/************************************************************ - * convert_argb_pixels - * - * Copies the source buffer to the destination buffer, performing - * any necessary format conversion and color keying. - * Pixels outsize the source rect are blacked out. - */ -void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, - const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, - const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key, - const PALETTEENTRY *palette) -{ - struct argb_conversion_info conv_info, ck_conv_info; - const struct pixel_format_desc *ck_format; - DWORD channels[4]; - UINT min_width, min_height, min_depth; - UINT x, y, z; - - TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, " - "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key 0x%08lx, palette %p.\n", - src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, - dst_format, color_key, palette); + src_desc = get_d3dx_pixel_format_info(src_format); + hr = d3dx_pixels_init(src_memory, src_pitch, 0, src_palette, src_desc->format, + src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1, &src_pixels); + if (FAILED(hr)) + return hr; - ZeroMemory(channels, sizeof(channels)); - init_argb_conversion_info(src_format, dst_format, &conv_info); + get_aligned_rect(dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, desc.Width, desc.Height, + dst_desc, &dst_rect_aligned); + if (FAILED(hr = lock_surface(dst_surface, &dst_rect_aligned, &lock_rect, &surface, TRUE))) + return hr; - min_width = min(src_size->width, dst_size->width); - min_height = min(src_size->height, dst_size->height); - min_depth = min(src_size->depth, dst_size->depth); + set_d3dx_pixels(&dst_pixels, lock_rect.pBits, lock_rect.Pitch, 0, dst_palette, + (dst_rect_aligned.right - dst_rect_aligned.left), (dst_rect_aligned.bottom - dst_rect_aligned.top), 1, + dst_rect); + OffsetRect(&dst_pixels.unaligned_rect, -dst_rect_aligned.left, -dst_rect_aligned.top); - if (color_key) + if (FAILED(hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_desc, &src_pixels, src_desc, filter, color_key))) { - /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ - ck_format = get_format_info(D3DFMT_A8R8G8B8); - init_argb_conversion_info(src_format, ck_format, &ck_conv_info); + unlock_surface(dst_surface, &dst_rect_aligned, surface, FALSE); + return hr; } - for (z = 0; z < min_depth; z++) { - const BYTE *src_slice_ptr = src + z * src_slice_pitch; - BYTE *dst_slice_ptr = dst + z * dst_slice_pitch; - - for (y = 0; y < min_height; y++) { - const BYTE *src_ptr = src_slice_ptr + y * src_row_pitch; - BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch; - - for (x = 0; x < min_width; x++) { - if (format_types_match(src_format, dst_format) - && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4) - { - DWORD val; - - get_relevant_argb_components(&conv_info, src_ptr, channels); - val = make_argb_color(&conv_info, channels); - - if (color_key) - { - DWORD ck_pixel; - - get_relevant_argb_components(&ck_conv_info, src_ptr, channels); - ck_pixel = make_argb_color(&ck_conv_info, channels); - if (ck_pixel == color_key) - val &= ~conv_info.destmask[0]; - } - memcpy(dst_ptr, &val, dst_format->bytes_per_pixel); - } - else - { - struct d3dx_color color, tmp; - - format_to_d3dx_color(src_format, src_ptr, palette, &color); - tmp = color; - - if (color_key) - { - DWORD ck_pixel; - - format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); - if (ck_pixel == color_key) - tmp.value.w = 0.0f; - } - - color = tmp; - format_from_d3dx_color(dst_format, &color, dst_ptr); - } - - src_ptr += src_format->bytes_per_pixel; - dst_ptr += dst_format->bytes_per_pixel; - } - - if (src_size->width < dst_size->width) /* black out remaining pixels */ - memset(dst_ptr, 0, dst_format->bytes_per_pixel * (dst_size->width - src_size->width)); - } - - if (src_size->height < dst_size->height) /* black out remaining pixels */ - memset(dst + src_size->height * dst_row_pitch, 0, dst_row_pitch * (dst_size->height - src_size->height)); - } - if (src_size->depth < dst_size->depth) /* black out remaining pixels */ - memset(dst + src_size->depth * dst_slice_pitch, 0, dst_slice_pitch * (dst_size->depth - src_size->depth)); + return unlock_surface(dst_surface, &dst_rect_aligned, surface, TRUE); } /************************************************************ - * point_filter_argb_pixels + * D3DXLoadSurfaceFromFileInMemory + * + * Loads data from a given buffer into a surface and fills a given + * D3DXIMAGE_INFO structure with info about the source data. + * + * PARAMS + * pDestSurface [I] pointer to the surface + * pDestPalette [I] palette to use + * pDestRect [I] to be filled area of the surface + * pSrcData [I] pointer to the source data + * SrcDataSize [I] size of the source data in bytes + * pSrcRect [I] area of the source data to load + * dwFilter [I] filter to apply on stretching + * Colorkey [I] colorkey + * pSrcInfo [O] pointer to a D3DXIMAGE_INFO structure + * + * RETURNS + * Success: D3D_OK + * Failure: D3DERR_INVALIDCALL, if pDestSurface, pSrcData or SrcDataSize is NULL + * D3DXERR_INVALIDDATA, if pSrcData is no valid image file * - * Copies the source buffer to the destination buffer, performing - * any necessary format conversion, color keying and stretching - * using a point filter. */ -void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, - const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, - const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key, - const PALETTEENTRY *palette) -{ - struct argb_conversion_info conv_info, ck_conv_info; - const struct pixel_format_desc *ck_format; - DWORD channels[4]; - UINT x, y, z; - - TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, " - "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key 0x%08lx, palette %p.\n", - src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, - dst_format, color_key, palette); - - ZeroMemory(channels, sizeof(channels)); - init_argb_conversion_info(src_format, dst_format, &conv_info); - - if (color_key) - { - /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ - ck_format = get_format_info(D3DFMT_A8R8G8B8); - init_argb_conversion_info(src_format, ck_format, &ck_conv_info); - } - - for (z = 0; z < dst_size->depth; z++) - { - BYTE *dst_slice_ptr = dst + z * dst_slice_pitch; - const BYTE *src_slice_ptr = src + src_slice_pitch * (z * src_size->depth / dst_size->depth); - - for (y = 0; y < dst_size->height; y++) - { - BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch; - const BYTE *src_row_ptr = src_slice_ptr + src_row_pitch * (y * src_size->height / dst_size->height); - - for (x = 0; x < dst_size->width; x++) - { - const BYTE *src_ptr = src_row_ptr + (x * src_size->width / dst_size->width) * src_format->bytes_per_pixel; - - if (format_types_match(src_format, dst_format) - && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4) - { - DWORD val; - - get_relevant_argb_components(&conv_info, src_ptr, channels); - val = make_argb_color(&conv_info, channels); - - if (color_key) - { - DWORD ck_pixel; - - get_relevant_argb_components(&ck_conv_info, src_ptr, channels); - ck_pixel = make_argb_color(&ck_conv_info, channels); - if (ck_pixel == color_key) - val &= ~conv_info.destmask[0]; - } - memcpy(dst_ptr, &val, dst_format->bytes_per_pixel); - } - else - { - struct d3dx_color color, tmp; - - format_to_d3dx_color(src_format, src_ptr, palette, &color); - tmp = color; - - if (color_key) - { - DWORD ck_pixel; - - format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); - if (ck_pixel == color_key) - tmp.value.w = 0.0f; - } - - color = tmp; - format_from_d3dx_color(dst_format, &color, dst_ptr); - } - - dst_ptr += dst_format->bytes_per_pixel; - } - } - } -} - -static HRESULT d3dx_pixels_decompress(struct d3dx_pixels *pixels, const struct pixel_format_desc *desc, - BOOL is_dst, void **out_memory, uint32_t *out_row_pitch, uint32_t *out_slice_pitch, - const struct pixel_format_desc **out_desc) +HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(IDirect3DSurface9 *pDestSurface, + const PALETTEENTRY *pDestPalette, const RECT *pDestRect, const void *pSrcData, UINT SrcDataSize, + const RECT *pSrcRect, DWORD dwFilter, D3DCOLOR Colorkey, D3DXIMAGE_INFO *pSrcInfo) { - void (*fetch_dxt_texel)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); - uint32_t x, y, z, tmp_pitch, uncompressed_slice_pitch, uncompressed_row_pitch; - const struct pixel_format_desc *uncompressed_desc = NULL; - const struct volume *size = &pixels->size; - BYTE *uncompressed_mem; + struct d3dx_pixels pixels = { 0 }; + struct d3dx_image image; + D3DXIMAGE_INFO img_info; + RECT src_rect; + HRESULT hr; - switch (desc->format) - { - case D3DX_PIXEL_FORMAT_DXT1_UNORM: - uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); - fetch_dxt_texel = fetch_2d_texel_rgba_dxt1; - break; - case D3DX_PIXEL_FORMAT_DXT2_UNORM: - case D3DX_PIXEL_FORMAT_DXT3_UNORM: - uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); - fetch_dxt_texel = fetch_2d_texel_rgba_dxt3; - break; - case D3DX_PIXEL_FORMAT_DXT4_UNORM: - case D3DX_PIXEL_FORMAT_DXT5_UNORM: - uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); - fetch_dxt_texel = fetch_2d_texel_rgba_dxt5; - break; - default: - FIXME("Unexpected compressed texture format %u.\n", desc->format); - return E_NOTIMPL; - } + TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_data %p, src_data_size %u, " + "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", + pDestSurface, pDestPalette, wine_dbgstr_rect(pDestRect), pSrcData, SrcDataSize, + wine_dbgstr_rect(pSrcRect), dwFilter, Colorkey, pSrcInfo); - uncompressed_row_pitch = size->width * uncompressed_desc->bytes_per_pixel; - uncompressed_slice_pitch = uncompressed_row_pitch * size->height; - if (!(uncompressed_mem = malloc(size->depth * uncompressed_slice_pitch))) - return E_OUTOFMEMORY; - - /* - * For compressed destination pixels, width/height will represent - * the entire set of compressed blocks our destination rectangle touches. - * If we're only updating a sub-area of any blocks, we need to decompress - * the pixels outside of the sub-area. - */ - if (is_dst) - { - const RECT aligned_rect = { 0, 0, size->width, size->height }; - - /* - * If our destination covers the entire set of blocks, no - * decompression needs to be done, just return the allocated memory. - */ - if (EqualRect(&aligned_rect, &pixels->unaligned_rect)) - goto exit; - } + if (!pDestSurface || !pSrcData || !SrcDataSize) + return D3DERR_INVALIDCALL; - TRACE("Decompressing pixels.\n"); - tmp_pitch = pixels->row_pitch * desc->block_width / desc->block_byte_count; - for (z = 0; z < size->depth; ++z) - { - const BYTE *slice_data = ((BYTE *)pixels->data) + (pixels->slice_pitch * z); + if (FAILED(hr = d3dx9_handle_load_filter(&dwFilter))) + return hr; - for (y = 0; y < size->height; ++y) - { - BYTE *ptr = &uncompressed_mem[(z * uncompressed_slice_pitch) + (y * uncompressed_row_pitch)]; - for (x = 0; x < size->width; ++x) - { - const POINT pt = { x, y }; - - if (!is_dst) - fetch_dxt_texel(tmp_pitch, slice_data, x + pixels->unaligned_rect.left, - y + pixels->unaligned_rect.top, ptr); - else if (!PtInRect(&pixels->unaligned_rect, pt)) - fetch_dxt_texel(tmp_pitch, slice_data, x, y, ptr); - ptr += uncompressed_desc->bytes_per_pixel; - } - } - } + hr = d3dx_image_init(pSrcData, SrcDataSize, &image, 0, 0); + if (FAILED(hr)) + return D3DXERR_INVALIDDATA; -exit: - *out_memory = uncompressed_mem; - *out_row_pitch = uncompressed_row_pitch; - *out_slice_pitch = uncompressed_slice_pitch; - *out_desc = uncompressed_desc; + d3dximage_info_from_d3dx_image(&img_info, &image); + if (pSrcRect) + src_rect = *pSrcRect; + else + SetRect(&src_rect, 0, 0, img_info.Width, img_info.Height); - return S_OK; -} + hr = d3dx_image_get_pixels(&image, 0, 0, &pixels); + if (FAILED(hr)) + goto exit; -HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, - const PALETTEENTRY *palette, enum d3dx_pixel_format_id format, uint32_t left, uint32_t top, uint32_t right, - uint32_t bottom, uint32_t front, uint32_t back, struct d3dx_pixels *pixels) -{ - const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(format); - const BYTE *ptr = data; - RECT unaligned_rect; + hr = d3dx_load_surface_from_memory(pDestSurface, pDestPalette, pDestRect, pixels.data, image.format, pixels.row_pitch, + pixels.palette, &src_rect, dwFilter, Colorkey); + if (SUCCEEDED(hr) && pSrcInfo) + *pSrcInfo = img_info; - memset(pixels, 0, sizeof(*pixels)); - if (is_unknown_format(fmt_desc)) - { - FIXME("Unsupported format %#x.\n", format); - return E_NOTIMPL; - } +exit: + d3dx_image_cleanup(&image); + return FAILED(hr) ? D3DXERR_INVALIDDATA : D3D_OK; +} - ptr += front * slice_pitch; - ptr += (top / fmt_desc->block_height) * row_pitch; - ptr += (left / fmt_desc->block_width) * fmt_desc->block_byte_count; +HRESULT WINAPI D3DXLoadSurfaceFromFileA(IDirect3DSurface9 *dst_surface, + const PALETTEENTRY *dst_palette, const RECT *dst_rect, const char *src_file, + const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) +{ + WCHAR *src_file_w; + HRESULT hr; + int strlength; - if (is_compressed_format(fmt_desc)) - { - uint32_t left_aligned, top_aligned; + TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, " + "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", + dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_a(src_file), + wine_dbgstr_rect(src_rect), filter, color_key, src_info); - top_aligned = top & ~(fmt_desc->block_height - 1); - left_aligned = left & ~(fmt_desc->block_width - 1); - SetRect(&unaligned_rect, left, top, right, bottom); - OffsetRect(&unaligned_rect, -left_aligned, -top_aligned); - } - else - { - SetRect(&unaligned_rect, 0, 0, (right - left), (bottom - top)); - } + if (!src_file || !dst_surface) + return D3DERR_INVALIDCALL; - set_d3dx_pixels(pixels, ptr, row_pitch, slice_pitch, palette, (right - left), (bottom - top), (back - front), - &unaligned_rect); + strlength = MultiByteToWideChar(CP_ACP, 0, src_file, -1, NULL, 0); + src_file_w = malloc(strlength * sizeof(*src_file_w)); + MultiByteToWideChar(CP_ACP, 0, src_file, -1, src_file_w, strlength); - return S_OK; -} + hr = D3DXLoadSurfaceFromFileW(dst_surface, dst_palette, dst_rect, + src_file_w, src_rect, filter, color_key, src_info); + free(src_file_w); -static const char *debug_d3dx_pixels(struct d3dx_pixels *pixels) -{ - if (!pixels) - return "(null)"; - return wine_dbg_sprintf("(data %p, row_pitch %d, slice_pitch %d, palette %p, width %d, height %d, depth %d, " - "unaligned_rect %s)", pixels->data, pixels->row_pitch, pixels->slice_pitch, pixels->palette, - pixels->size.width, pixels->size.height, pixels->size.depth, wine_dbgstr_rect(&pixels->unaligned_rect)); + return hr; } -HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, - const struct pixel_format_desc *dst_desc, struct d3dx_pixels *src_pixels, - const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key) +HRESULT WINAPI D3DXLoadSurfaceFromFileW(IDirect3DSurface9 *dst_surface, + const PALETTEENTRY *dst_palette, const RECT *dst_rect, const WCHAR *src_file, + const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) { - struct volume src_size, dst_size, dst_size_aligned; - HRESULT hr = S_OK; - - TRACE("dst_pixels %s, dst_desc %p, src_pixels %s, src_desc %p, filter_flags %#x, color_key %#x.\n", - debug_d3dx_pixels(dst_pixels), dst_desc, debug_d3dx_pixels(src_pixels), src_desc, - filter_flags, color_key); + DWORD data_size; + void *data; + HRESULT hr; - if (is_compressed_format(src_desc)) - set_volume_struct(&src_size, (src_pixels->unaligned_rect.right - src_pixels->unaligned_rect.left), - (src_pixels->unaligned_rect.bottom - src_pixels->unaligned_rect.top), src_pixels->size.depth); - else - src_size = src_pixels->size; + TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, " + "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", + dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_w(src_file), + wine_dbgstr_rect(src_rect), filter, color_key, src_info); - dst_size_aligned = dst_pixels->size; - if (is_compressed_format(dst_desc)) - set_volume_struct(&dst_size, (dst_pixels->unaligned_rect.right - dst_pixels->unaligned_rect.left), - (dst_pixels->unaligned_rect.bottom - dst_pixels->unaligned_rect.top), dst_pixels->size.depth); - else - dst_size = dst_size_aligned; - - /* Everything matches, simply copy the pixels. */ - if (src_desc->format == dst_desc->format - && (dst_size.width == src_size.width && !(dst_size.width % dst_desc->block_width)) - && (dst_size.height == src_size.height && !(dst_size.height % dst_desc->block_height)) - && (dst_size.depth == src_size.depth) - && color_key == 0 - && !(src_pixels->unaligned_rect.left & (src_desc->block_width - 1)) - && !(src_pixels->unaligned_rect.top & (src_desc->block_height - 1)) - && !(dst_pixels->unaligned_rect.left & (dst_desc->block_width - 1)) - && !(dst_pixels->unaligned_rect.top & (dst_desc->block_height - 1))) - { - TRACE("Simple copy.\n"); - copy_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, (void *)dst_pixels->data, - dst_pixels->row_pitch, dst_pixels->slice_pitch, &src_size, src_desc); - return S_OK; - } + if (!src_file || !dst_surface) + return D3DERR_INVALIDCALL; - /* Stretching or format conversion. */ - if (!is_conversion_from_supported(src_desc) - || !is_conversion_to_supported(dst_desc)) - { - FIXME("Unsupported format conversion %#x -> %#x.\n", src_desc->format, dst_desc->format); - return E_NOTIMPL; - } + if (FAILED(map_view_of_file(src_file, &data, &data_size))) + return D3DXERR_INVALIDDATA; - /* - * If the source is a compressed image, we need to decompress it first - * before doing any modifications. - */ - if (is_compressed_format(src_desc)) - { - uint32_t uncompressed_row_pitch, uncompressed_slice_pitch; - const struct pixel_format_desc *uncompressed_desc; - void *uncompressed_mem = NULL; + hr = D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, + data, data_size, src_rect, filter, color_key, src_info); + UnmapViewOfFile(data); - hr = d3dx_pixels_decompress(src_pixels, src_desc, FALSE, &uncompressed_mem, &uncompressed_row_pitch, - &uncompressed_slice_pitch, &uncompressed_desc); - if (SUCCEEDED(hr)) - { - struct d3dx_pixels uncompressed_pixels; + return hr; +} - d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, - uncompressed_desc->format, 0, 0, src_pixels->size.width, src_pixels->size.height, - 0, src_pixels->size.depth, &uncompressed_pixels); +HRESULT WINAPI D3DXLoadSurfaceFromResourceA(IDirect3DSurface9 *dst_surface, + const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const char *resource, + const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) +{ + DWORD data_size; + HRSRC resinfo; + void *data; - hr = d3dx_load_pixels_from_pixels(dst_pixels, dst_desc, &uncompressed_pixels, uncompressed_desc, - filter_flags, color_key); - } - free(uncompressed_mem); - goto exit; - } + TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, " + "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", + dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_a(resource), + wine_dbgstr_rect(src_rect), filter, color_key, src_info); - /* Same as the above, need to decompress the destination prior to modifying. */ - if (is_compressed_format(dst_desc)) - { - uint32_t uncompressed_row_pitch, uncompressed_slice_pitch; - const struct pixel_format_desc *uncompressed_desc; - struct d3dx_pixels uncompressed_pixels; - void *uncompressed_mem = NULL; + if (!dst_surface) + return D3DERR_INVALIDCALL; - hr = d3dx_pixels_decompress(dst_pixels, dst_desc, TRUE, &uncompressed_mem, &uncompressed_row_pitch, - &uncompressed_slice_pitch, &uncompressed_desc); - if (FAILED(hr)) - goto exit; + if (!(resinfo = FindResourceA(src_module, resource, (const char *)RT_RCDATA)) + /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ + && !(resinfo = FindResourceA(src_module, resource, (const char *)RT_BITMAP))) + return D3DXERR_INVALIDDATA; - d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, - uncompressed_desc->format, dst_pixels->unaligned_rect.left, dst_pixels->unaligned_rect.top, - dst_pixels->unaligned_rect.right, dst_pixels->unaligned_rect.bottom, 0, dst_pixels->size.depth, - &uncompressed_pixels); + if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size))) + return D3DXERR_INVALIDDATA; - hr = d3dx_load_pixels_from_pixels(&uncompressed_pixels, uncompressed_desc, src_pixels, src_desc, filter_flags, - color_key); - if (SUCCEEDED(hr)) - { - GLenum gl_format = 0; - uint32_t i; + return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, + data, data_size, src_rect, filter, color_key, src_info); +} - TRACE("Compressing DXTn surface.\n"); - switch (dst_desc->format) - { - case D3DX_PIXEL_FORMAT_DXT1_UNORM: - gl_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - break; - case D3DX_PIXEL_FORMAT_DXT2_UNORM: - case D3DX_PIXEL_FORMAT_DXT3_UNORM: - gl_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - break; - case D3DX_PIXEL_FORMAT_DXT4_UNORM: - case D3DX_PIXEL_FORMAT_DXT5_UNORM: - gl_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - break; - default: - ERR("Unexpected destination compressed format %u.\n", dst_desc->format); - } +HRESULT WINAPI D3DXLoadSurfaceFromResourceW(IDirect3DSurface9 *dst_surface, + const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const WCHAR *resource, + const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) +{ + DWORD data_size; + HRSRC resinfo; + void *data; - for (i = 0; i < dst_size_aligned.depth; ++i) - { - BYTE *uncompressed_mem_slice = (BYTE *)uncompressed_mem + (i * uncompressed_slice_pitch); - BYTE *dst_memory_slice = ((BYTE *)dst_pixels->data) + (i * dst_pixels->slice_pitch); + TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, " + "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", + dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_w(resource), + wine_dbgstr_rect(src_rect), filter, color_key, src_info); - tx_compress_dxtn(4, dst_size_aligned.width, dst_size_aligned.height, uncompressed_mem_slice, gl_format, - dst_memory_slice, dst_pixels->row_pitch); - } - } - free(uncompressed_mem); - goto exit; - } + if (!dst_surface) + return D3DERR_INVALIDCALL; - if ((filter_flags & 0xf) == D3DX_FILTER_NONE) - { - convert_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, src_desc, - (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, dst_desc, - color_key, src_pixels->palette); - } - else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ - { - if ((filter_flags & 0xf) != D3DX_FILTER_POINT) - FIXME("Unhandled filter %#x.\n", filter_flags); - - /* Always apply a point filter until D3DX_FILTER_LINEAR, - * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ - point_filter_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, - src_desc, (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, - dst_desc, color_key, src_pixels->palette); - } + if (!(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_RCDATA)) + /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ + && !(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_BITMAP))) + return D3DXERR_INVALIDDATA; -exit: - if (FAILED(hr)) - WARN("Failed to load pixels, hr %#lx.\n", hr); - return hr; -} + if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size))) + return D3DXERR_INVALIDDATA; -void get_aligned_rect(uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t width, uint32_t height, - const struct pixel_format_desc *fmt_desc, RECT *aligned_rect) -{ - SetRect(aligned_rect, left, top, right, bottom); - if (aligned_rect->left & (fmt_desc->block_width - 1)) - aligned_rect->left = aligned_rect->left & ~(fmt_desc->block_width - 1); - if (aligned_rect->top & (fmt_desc->block_height - 1)) - aligned_rect->top = aligned_rect->top & ~(fmt_desc->block_height - 1); - if (aligned_rect->right & (fmt_desc->block_width - 1) && aligned_rect->right != width) - aligned_rect->right = min((aligned_rect->right + fmt_desc->block_width - 1) - & ~(fmt_desc->block_width - 1), width); - if (aligned_rect->bottom & (fmt_desc->block_height - 1) && aligned_rect->bottom != height) - aligned_rect->bottom = min((aligned_rect->bottom + fmt_desc->block_height - 1) - & ~(fmt_desc->block_height - 1), height); + return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, + data, data_size, src_rect, filter, color_key, src_info); } /************************************************************ @@ -2949,218 +1027,92 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF HRESULT WINAPI D3DXSaveSurfaceToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format, IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect) { - IWICBitmapEncoder *encoder = NULL; - IWICBitmapFrameEncode *frame = NULL; - IPropertyBag2 *encoder_options = NULL; - IStream *stream = NULL; - HRESULT hr; - const GUID *container_format; - const GUID *pixel_format_guid; - WICPixelFormatGUID wic_pixel_format; - IWICImagingFactory *factory; - D3DFORMAT d3d_pixel_format; + const struct pixel_format_desc *src_fmt_desc; + enum d3dx_pixel_format_id dst_fmt; D3DSURFACE_DESC src_surface_desc; IDirect3DSurface9 *temp_surface; + struct d3dx_pixels src_pixels; D3DLOCKED_RECT locked_rect; - int width, height; - STATSTG stream_stats; - HGLOBAL stream_hglobal; ID3DXBuffer *buffer; - DWORD size; + RECT src_rect_temp; + HRESULT hr; TRACE("dst_buffer %p, file_format %#x, src_surface %p, src_palette %p, src_rect %s.\n", dst_buffer, file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); - if (!dst_buffer || !src_surface) return D3DERR_INVALIDCALL; - - IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc); - if (file_format != D3DXIFF_DDS && (src_palette || is_index_format(get_format_info(src_surface_desc.Format)))) - { - FIXME("Saving surfaces with palettized pixel formats to non-DDS files is not implemented yet.\n"); + if (!dst_buffer || !src_surface || file_format > D3DXIFF_PFM) return D3DERR_INVALIDCALL; - } switch (file_format) { - case D3DXIFF_BMP: - case D3DXIFF_DIB: - container_format = &GUID_ContainerFormatBmp; - break; - case D3DXIFF_PNG: - container_format = &GUID_ContainerFormatPng; - break; - case D3DXIFF_JPG: - container_format = &GUID_ContainerFormatJpeg; - break; - case D3DXIFF_DDS: - return save_dds_surface_to_memory(dst_buffer, src_surface, src_palette, src_rect); case D3DXIFF_HDR: case D3DXIFF_PFM: - case D3DXIFF_TGA: case D3DXIFF_PPM: - FIXME("File format %#x is not supported yet\n", file_format); + FIXME("File format %s is not supported yet.\n", + debug_d3dx_image_file_format((enum d3dx_image_file_format)file_format)); return E_NOTIMPL; + default: - return D3DERR_INVALIDCALL; + break; + } + + IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc); + src_fmt_desc = get_format_info(src_surface_desc.Format); + if (is_unknown_format(src_fmt_desc)) + return E_NOTIMPL; + + if (!src_palette && is_index_format(src_fmt_desc)) + { + FIXME("Default palette unimplemented.\n"); + return E_NOTIMPL; } if (src_rect) { - if (src_rect->left == src_rect->right || src_rect->top == src_rect->bottom) + if (src_rect->left > src_rect->right || src_rect->right > src_surface_desc.Width + || src_rect->top > src_rect->bottom || src_rect->bottom > src_surface_desc.Height + || src_rect->left < 0 || src_rect->top < 0) { - WARN("Invalid rectangle with 0 area\n"); - return D3DXCreateBuffer(64, dst_buffer); - } - if (src_rect->left < 0 || src_rect->top < 0) - return D3DERR_INVALIDCALL; - if (src_rect->left > src_rect->right || src_rect->top > src_rect->bottom) - return D3DERR_INVALIDCALL; - if (src_rect->right > src_surface_desc.Width || src_rect->bottom > src_surface_desc.Height) + WARN("Invalid src_rect specified.\n"); return D3DERR_INVALIDCALL; - - width = src_rect->right - src_rect->left; - height = src_rect->bottom - src_rect->top; + } } else { - width = src_surface_desc.Width; - height = src_surface_desc.Height; + SetRect(&src_rect_temp, 0, 0, src_surface_desc.Width, src_surface_desc.Height); + src_rect = &src_rect_temp; } - hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory); - if (FAILED(hr)) goto cleanup_err; - - hr = IWICImagingFactory_CreateEncoder(factory, container_format, NULL, &encoder); - IWICImagingFactory_Release(factory); - if (FAILED(hr)) goto cleanup_err; - - hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); - if (FAILED(hr)) goto cleanup_err; - - hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache); - if (FAILED(hr)) goto cleanup_err; - - hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frame, &encoder_options); - if (FAILED(hr)) goto cleanup_err; - - hr = IWICBitmapFrameEncode_Initialize(frame, encoder_options); - if (FAILED(hr)) goto cleanup_err; - - hr = IWICBitmapFrameEncode_SetSize(frame, width, height); - if (FAILED(hr)) goto cleanup_err; + hr = d3dx_get_save_pixel_format_from_image_file_format(src_fmt_desc, file_format, &dst_fmt); + if (FAILED(hr)) + return hr; - pixel_format_guid = wic_guid_from_d3dformat(src_surface_desc.Format); - if (!pixel_format_guid) - { - FIXME("Pixel format %#x is not supported yet\n", src_surface_desc.Format); - hr = E_NOTIMPL; - goto cleanup; - } + hr = lock_surface(src_surface, NULL, &locked_rect, &temp_surface, FALSE); + if (FAILED(hr)) + return hr; - memcpy(&wic_pixel_format, pixel_format_guid, sizeof(GUID)); - hr = IWICBitmapFrameEncode_SetPixelFormat(frame, &wic_pixel_format); - d3d_pixel_format = d3dformat_from_d3dx_pixel_format_id(d3dx_pixel_format_id_from_wic_pixel_format(&wic_pixel_format)); - if (SUCCEEDED(hr) && d3d_pixel_format != D3DFMT_UNKNOWN) + hr = d3dx_pixels_init(locked_rect.pBits, locked_rect.Pitch, 0, src_palette, src_fmt_desc->format, + src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1, &src_pixels); + if (FAILED(hr)) { - TRACE("Using pixel format %s %#x\n", debugstr_guid(&wic_pixel_format), d3d_pixel_format); - if (src_surface_desc.Format == d3d_pixel_format) /* Simple copy */ - { - if (FAILED(hr = lock_surface(src_surface, src_rect, &locked_rect, &temp_surface, FALSE))) - goto cleanup; - - IWICBitmapFrameEncode_WritePixels(frame, height, - locked_rect.Pitch, height * locked_rect.Pitch, locked_rect.pBits); - unlock_surface(src_surface, src_rect, temp_surface, FALSE); - } - else /* Pixel format conversion */ - { - const struct pixel_format_desc *src_format_desc, *dst_format_desc; - struct volume size; - DWORD dst_pitch; - void *dst_data; - - src_format_desc = get_format_info(src_surface_desc.Format); - dst_format_desc = get_format_info(d3d_pixel_format); - if (!is_conversion_from_supported(src_format_desc) - || !is_conversion_to_supported(dst_format_desc)) - { - FIXME("Unsupported format conversion %#x -> %#x.\n", - src_surface_desc.Format, d3d_pixel_format); - hr = E_NOTIMPL; - goto cleanup; - } - - size.width = width; - size.height = height; - size.depth = 1; - dst_pitch = width * dst_format_desc->bytes_per_pixel; - dst_data = malloc(dst_pitch * height); - if (!dst_data) - { - hr = E_OUTOFMEMORY; - goto cleanup; - } - if (FAILED(hr = lock_surface(src_surface, src_rect, &locked_rect, &temp_surface, FALSE))) - { - free(dst_data); - goto cleanup; - } - convert_argb_pixels(locked_rect.pBits, locked_rect.Pitch, 0, &size, src_format_desc, - dst_data, dst_pitch, 0, &size, dst_format_desc, 0, NULL); - unlock_surface(src_surface, src_rect, temp_surface, FALSE); - - IWICBitmapFrameEncode_WritePixels(frame, height, dst_pitch, dst_pitch * height, dst_data); - free(dst_data); - } - - hr = IWICBitmapFrameEncode_Commit(frame); - if (SUCCEEDED(hr)) hr = IWICBitmapEncoder_Commit(encoder); + unlock_surface(src_surface, NULL, temp_surface, FALSE); + return hr; } - else WARN("Unsupported pixel format %#x\n", src_surface_desc.Format); - /* copy data from stream to ID3DXBuffer */ - hr = IStream_Stat(stream, &stream_stats, STATFLAG_NONAME); - if (FAILED(hr)) goto cleanup_err; - - if (stream_stats.cbSize.u.HighPart != 0) + hr = d3dx_save_pixels_to_memory(&src_pixels, src_fmt_desc, (enum d3dx_image_file_format)file_format, dst_fmt, &buffer); + if (FAILED(hr)) { - hr = D3DXERR_INVALIDDATA; - goto cleanup; + unlock_surface(src_surface, NULL, temp_surface, FALSE); + return hr; } - size = stream_stats.cbSize.u.LowPart; - - /* Remove BMP header for DIB */ - if (file_format == D3DXIFF_DIB) - size -= sizeof(BITMAPFILEHEADER); - - hr = D3DXCreateBuffer(size, &buffer); - if (FAILED(hr)) goto cleanup; - hr = GetHGlobalFromStream(stream, &stream_hglobal); - if (SUCCEEDED(hr)) + hr = unlock_surface(src_surface, NULL, temp_surface, FALSE); + if (FAILED(hr)) { - void *buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); - void *stream_data = GlobalLock(stream_hglobal); - /* Remove BMP header for DIB */ - if (file_format == D3DXIFF_DIB) - stream_data = (void*)((BYTE*)stream_data + sizeof(BITMAPFILEHEADER)); - memcpy(buffer_pointer, stream_data, size); - GlobalUnlock(stream_hglobal); - *dst_buffer = buffer; + ID3DXBuffer_Release(buffer); + return hr; } - else ID3DXBuffer_Release(buffer); - -cleanup_err: - if (FAILED(hr) && hr != E_OUTOFMEMORY) - hr = D3DERR_INVALIDCALL; - -cleanup: - if (stream) IStream_Release(stream); - - if (frame) IWICBitmapFrameEncode_Release(frame); - if (encoder_options) IPropertyBag2_Release(encoder_options); - if (encoder) IWICBitmapEncoder_Release(encoder); - - return hr; + *dst_buffer = buffer; + return D3D_OK; } diff --git a/dlls/d3dx9_36/tests/d3dx9_test_images.h b/dlls/d3dx9_36/tests/d3dx9_test_images.h index 68d4152d5429..3ed5373c705d 100644 --- a/dlls/d3dx9_36/tests/d3dx9_test_images.h +++ b/dlls/d3dx9_36/tests/d3dx9_test_images.h @@ -23,6 +23,58 @@ #define COBJMACROS #include "d3dx9tex.h" +/* + * MAKE_DDHRESULT is first defined in d3dx9.h, with the same definition as the + * one in ddraw.h. + */ +#ifdef MAKE_DDHRESULT +#undef MAKE_DDHRESULT +#endif +#include "ddraw.h" + +/* dds_pixel_format.flags */ +#define DDS_PF_ALPHA 0x00000001 +#define DDS_PF_ALPHA_ONLY 0x00000002 +#define DDS_PF_FOURCC 0x00000004 +#define DDS_PF_INDEXED 0x00000020 +#define DDS_PF_RGB 0x00000040 +#define DDS_PF_LUMINANCE 0x00020000 +#define DDS_PF_BUMPLUMINANCE 0x00040000 +#define DDS_PF_BUMPDUDV 0x00080000 + +struct dds_pixel_format +{ + DWORD size; + DWORD flags; + DWORD fourcc; + DWORD bpp; + DWORD rmask; + DWORD gmask; + DWORD bmask; + DWORD amask; +}; + +struct dds_header +{ + DWORD size; + DWORD flags; + DWORD height; + DWORD width; + DWORD pitch_or_linear_size; + DWORD depth; + DWORD miplevels; + DWORD reserved[11]; + struct dds_pixel_format pixel_format; + DWORD caps; + DWORD caps2; + DWORD caps3; + DWORD caps4; + DWORD reserved2; +}; + +#define DDS_FILE_HEADER_SIZE (sizeof(uint32_t) + sizeof(struct dds_header)) +#define PALETTED_DDS_FILE_HEADER_SIZE (DDS_FILE_HEADER_SIZE + (sizeof(PALETTEENTRY) * 256)) + static const struct { uint32_t filter; @@ -42,6 +94,89 @@ test_filter_values[] = { 0xff800001, D3DERR_INVALIDCALL }, }; +static const PALETTEENTRY test_palette[256] = +{ + {0x00,0x00,0x00,0x00}, {0x00,0x00,0x80,0x01}, {0x00,0x80,0x00,0x02}, {0x00,0x80,0x80,0x03}, + {0x80,0x00,0x00,0x04}, {0x80,0x00,0x80,0x05}, {0x80,0x80,0x00,0x06}, {0xc0,0xc0,0xc0,0x07}, + {0xc0,0xdc,0xc0,0x08}, {0xf0,0xca,0xa6,0x09}, {0x00,0x20,0x40,0x0a}, {0x00,0x20,0x60,0x0b}, + {0x00,0x20,0x80,0x0c}, {0x00,0x20,0xa0,0x0d}, {0x00,0x20,0xc0,0x0e}, {0x00,0x20,0xe0,0x0f}, + + {0x00,0x40,0x00,0x10}, {0x00,0x40,0x20,0x11}, {0x00,0x40,0x40,0x12}, {0x00,0x40,0x60,0x13}, + {0x00,0x40,0x80,0x14}, {0x00,0x40,0xa0,0x15}, {0x00,0x40,0xc0,0x16}, {0x00,0x40,0xe0,0x17}, + {0x00,0x60,0x00,0x18}, {0x00,0x60,0x20,0x19}, {0x00,0x60,0x40,0x1a}, {0x00,0x60,0x60,0x1b}, + {0x00,0x60,0x80,0x1c}, {0x00,0x60,0xa0,0x1d}, {0x00,0x60,0xc0,0x1e}, {0x00,0x60,0xe0,0x1f}, + + {0x00,0x80,0x00,0x20}, {0x00,0x80,0x20,0x21}, {0x00,0x80,0x40,0x22}, {0x00,0x80,0x60,0x23}, + {0x00,0x80,0x80,0x24}, {0x00,0x80,0xa0,0x25}, {0x00,0x80,0xc0,0x26}, {0x00,0x80,0xe0,0x27}, + {0x00,0xa0,0x00,0x28}, {0x00,0xa0,0x20,0x29}, {0x00,0xa0,0x40,0x2a}, {0x00,0xa0,0x60,0x2b}, + {0x00,0xa0,0x80,0x2c}, {0x00,0xa0,0xa0,0x2d}, {0x00,0xa0,0xc0,0x2e}, {0x00,0xa0,0xe0,0x2f}, + + {0x00,0xc0,0x00,0x30}, {0x00,0xc0,0x20,0x31}, {0x00,0xc0,0x40,0x32}, {0x00,0xc0,0x60,0x33}, + {0x00,0xc0,0x80,0x34}, {0x00,0xc0,0xa0,0x35}, {0x00,0xc0,0xc0,0x36}, {0x00,0xc0,0xe0,0x37}, + {0x00,0xe0,0x00,0x38}, {0x00,0xe0,0x20,0x39}, {0x00,0xe0,0x40,0x3a}, {0x00,0xe0,0x60,0x3b}, + {0x00,0xe0,0x80,0x3c}, {0x00,0xe0,0xa0,0x3d}, {0x00,0xe0,0xc0,0x3e}, {0x00,0xe0,0xe0,0x3f}, + + {0x40,0x00,0x00,0x40}, {0x40,0x00,0x20,0x41}, {0x40,0x00,0x40,0x42}, {0x40,0x00,0x60,0x43}, + {0x40,0x00,0x80,0x44}, {0x40,0x00,0xa0,0x45}, {0x40,0x00,0xc0,0x46}, {0x40,0x00,0xe0,0x47}, + {0x40,0x20,0x00,0x48}, {0x40,0x20,0x20,0x49}, {0x40,0x20,0x40,0x4a}, {0x40,0x20,0x60,0x4b}, + {0x40,0x20,0x80,0x4c}, {0x40,0x20,0xa0,0x4d}, {0x40,0x20,0xc0,0x4e}, {0x40,0x20,0xe0,0x4f}, + + {0x40,0x40,0x00,0x50}, {0x40,0x40,0x20,0x51}, {0x40,0x40,0x40,0x52}, {0x40,0x40,0x60,0x53}, + {0x40,0x40,0x80,0x54}, {0x40,0x40,0xa0,0x55}, {0x40,0x40,0xc0,0x56}, {0x40,0x40,0xe0,0x57}, + {0x40,0x60,0x00,0x58}, {0x40,0x60,0x20,0x59}, {0x40,0x60,0x40,0x5a}, {0x40,0x60,0x60,0x5b}, + {0x40,0x60,0x80,0x5c}, {0x40,0x60,0xa0,0x5d}, {0x40,0x60,0xc0,0x5e}, {0x40,0x60,0xe0,0x5f}, + + {0x40,0x80,0x00,0x60}, {0x40,0x80,0x20,0x61}, {0x40,0x80,0x40,0x62}, {0x40,0x80,0x60,0x63}, + {0x40,0x80,0x80,0x64}, {0x40,0x80,0xa0,0x65}, {0x40,0x80,0xc0,0x66}, {0x40,0x80,0xe0,0x67}, + {0x40,0xa0,0x00,0x68}, {0x40,0xa0,0x20,0x69}, {0x40,0xa0,0x40,0x6a}, {0x40,0xa0,0x60,0x6b}, + {0x40,0xa0,0x80,0x6c}, {0x40,0xa0,0xa0,0x6d}, {0x40,0xa0,0xc0,0x6e}, {0x40,0xa0,0xe0,0x6f}, + + {0x40,0xc0,0x00,0x70}, {0x40,0xc0,0x20,0x71}, {0x40,0xc0,0x40,0x72}, {0x40,0xc0,0x60,0x73}, + {0x40,0xc0,0x80,0x74}, {0x40,0xc0,0xa0,0x75}, {0x40,0xc0,0xc0,0x76}, {0x40,0xc0,0xe0,0x77}, + {0x40,0xe0,0x00,0x78}, {0x40,0xe0,0x20,0x79}, {0x40,0xe0,0x40,0x7a}, {0x40,0xe0,0x60,0x7b}, + {0x40,0xe0,0x80,0x7c}, {0x40,0xe0,0xa0,0x7d}, {0x40,0xe0,0xc0,0x7e}, {0x40,0xe0,0xe0,0x7f}, + + {0x80,0x00,0x00,0x80}, {0x80,0x00,0x20,0x81}, {0x80,0x00,0x40,0x82}, {0x80,0x00,0x60,0x83}, + {0x80,0x00,0x80,0x84}, {0x80,0x00,0xa0,0x85}, {0x80,0x00,0xc0,0x86}, {0x80,0x00,0xe0,0x87}, + {0x80,0x20,0x00,0x88}, {0x80,0x20,0x20,0x89}, {0x80,0x20,0x40,0x8a}, {0x80,0x20,0x60,0x8b}, + {0x80,0x20,0x80,0x8c}, {0x80,0x20,0xa0,0x8d}, {0x80,0x20,0xc0,0x8e}, {0x80,0x20,0xe0,0x8f}, + + {0x80,0x40,0x00,0x90}, {0x80,0x40,0x20,0x91}, {0x80,0x40,0x40,0x92}, {0x80,0x40,0x60,0x93}, + {0x80,0x40,0x80,0x94}, {0x80,0x40,0xa0,0x95}, {0x80,0x40,0xc0,0x96}, {0x80,0x40,0xe0,0x97}, + {0x80,0x60,0x00,0x98}, {0x80,0x60,0x20,0x99}, {0x80,0x60,0x40,0x9a}, {0x80,0x60,0x60,0x9b}, + {0x80,0x60,0x80,0x9c}, {0x80,0x60,0xa0,0x9d}, {0x80,0x60,0xc0,0x9e}, {0x80,0x60,0xe0,0x9f}, + + {0x80,0x80,0x00,0xa0}, {0x80,0x80,0x20,0xa1}, {0x80,0x80,0x40,0xa2}, {0x80,0x80,0x60,0xa3}, + {0x80,0x80,0x80,0xa4}, {0x80,0x80,0xa0,0xa5}, {0x80,0x80,0xc0,0xa6}, {0x80,0x80,0xe0,0xa7}, + {0x80,0xa0,0x00,0xa8}, {0x80,0xa0,0x20,0xa9}, {0x80,0xa0,0x40,0xaa}, {0x80,0xa0,0x60,0xab}, + {0x80,0xa0,0x80,0xac}, {0x80,0xa0,0xa0,0xad}, {0x80,0xa0,0xc0,0xae}, {0x80,0xa0,0xe0,0xaf}, + + {0x80,0xc0,0x00,0xb0}, {0x80,0xc0,0x20,0xb1}, {0x80,0xc0,0x40,0xb2}, {0x80,0xc0,0x60,0xb3}, + {0x80,0xc0,0x80,0xb4}, {0x80,0xc0,0xa0,0xb5}, {0x80,0xc0,0xc0,0xb6}, {0x80,0xc0,0xe0,0xb7}, + {0x80,0xe0,0x00,0xb8}, {0x80,0xe0,0x20,0xb9}, {0x80,0xe0,0x40,0xba}, {0x80,0xe0,0x60,0xbb}, + {0x80,0xe0,0x80,0xbc}, {0x80,0xe0,0xa0,0xbd}, {0x80,0xe0,0xc0,0xbe}, {0x80,0xe0,0xe0,0xbf}, + + {0xc0,0x00,0x00,0xc0}, {0xc0,0x00,0x20,0xc1}, {0xc0,0x00,0x40,0xc2}, {0xc0,0x00,0x60,0xc3}, + {0xc0,0x00,0x80,0xc4}, {0xc0,0x00,0xa0,0xc5}, {0xc0,0x00,0xc0,0xc6}, {0xc0,0x00,0xe0,0xc7}, + {0xc0,0x20,0x00,0xc8}, {0xc0,0x20,0x20,0xc9}, {0xc0,0x20,0x40,0xca}, {0xc0,0x20,0x60,0xcb}, + {0xc0,0x20,0x80,0xcc}, {0xc0,0x20,0xa0,0xcd}, {0xc0,0x20,0xc0,0xce}, {0xc0,0x20,0xe0,0xcf}, + + {0xc0,0x40,0x00,0xd0}, {0xc0,0x40,0x20,0xd1}, {0xc0,0x40,0x40,0xd2}, {0xc0,0x40,0x60,0xd3}, + {0xc0,0x40,0x80,0xd4}, {0xc0,0x40,0xa0,0xd5}, {0xc0,0x40,0xc0,0xd6}, {0xc0,0x40,0xe0,0xd7}, + {0xc0,0x60,0x00,0xd8}, {0xc0,0x60,0x20,0xd9}, {0xc0,0x60,0x40,0xda}, {0xc0,0x60,0x60,0xdb}, + {0xc0,0x60,0x80,0xdc}, {0xc0,0x60,0xa0,0xdd}, {0xc0,0x60,0xc0,0xde}, {0xc0,0x60,0xe0,0xdf}, + + {0xc0,0x80,0x00,0xe0}, {0xc0,0x80,0x20,0xe1}, {0xc0,0x80,0x40,0xe2}, {0xc0,0x80,0x60,0xe3}, + {0xc0,0x80,0x80,0xe4}, {0xc0,0x80,0xa0,0xe5}, {0xc0,0x80,0xc0,0xe6}, {0xc0,0x80,0xe0,0xe7}, + {0xc0,0xa0,0x00,0xe8}, {0xc0,0xa0,0x20,0xe9}, {0xc0,0xa0,0x40,0xea}, {0xc0,0xa0,0x60,0xeb}, + {0xc0,0xa0,0x80,0xec}, {0xc0,0xa0,0xa0,0xed}, {0xc0,0xa0,0xc0,0xee}, {0xc0,0xa0,0xe0,0xef}, + + {0xc0,0xc0,0x00,0xf0}, {0xc0,0xc0,0x20,0xf1}, {0xc0,0xc0,0x40,0xf2}, {0xc0,0xc0,0x60,0xf3}, + {0xc0,0xc0,0x80,0xf4}, {0xc0,0xc0,0xa0,0xf5}, {0xf0,0xfb,0xff,0xf6}, {0xa4,0xa0,0xa0,0xf7}, + {0x80,0x80,0x80,0xf8}, {0x00,0x00,0xff,0xf9}, {0x00,0xff,0x00,0xfa}, {0x00,0xff,0xff,0xfb}, + {0xff,0x00,0x00,0xfc}, {0xff,0x00,0xff,0xfd}, {0xff,0xff,0x00,0xfe}, {0xff,0xff,0xff,0xff}, +}; + /* 1x1 bmp (1 bpp) */ static const uint8_t bmp_1bpp[] = { @@ -806,6 +941,82 @@ static inline void check_image_info_(const char *file, uint32_t line, const D3DX image_file_format, info->ImageFileFormat); } +#define check_dds_pixel_format_struct(pixel_format, expected_pixel_format, wine_todo) \ + check_dds_pixel_format_struct_(__FILE__, __LINE__, pixel_format, expected_pixel_format, wine_todo) +static inline void check_dds_pixel_format_struct_(const char *file, uint32_t line, const struct dds_pixel_format *pixel_format, + const struct dds_pixel_format *expected_pixel_format, BOOL wine_todo) +{ + BOOL matched; + + matched = !memcmp(expected_pixel_format, pixel_format, sizeof(*pixel_format)); + todo_wine_if(wine_todo) ok_(file, line)(matched, "Got unexpected dds pixel format values.\n"); + if (matched) + return; + + todo_wine_if(wine_todo && pixel_format->flags != expected_pixel_format->flags) + ok_(file, line)(pixel_format->flags == expected_pixel_format->flags, "Unexpected DDS pixel format flags %#lx.\n", + pixel_format->flags); + todo_wine_if(wine_todo && pixel_format->fourcc != expected_pixel_format->fourcc) + ok_(file, line)(pixel_format->fourcc == expected_pixel_format->fourcc, "Unexpected DDS pixel format fourcc %#lx.\n", + pixel_format->fourcc); + todo_wine_if(wine_todo && pixel_format->bpp != expected_pixel_format->bpp) + ok_(file, line)(pixel_format->bpp == expected_pixel_format->bpp, "Unexpected DDS pixel format bpp %#lx.\n", + pixel_format->bpp); + todo_wine_if(wine_todo && pixel_format->rmask != expected_pixel_format->rmask) + ok_(file, line)(pixel_format->rmask == expected_pixel_format->rmask, "Unexpected DDS pixel format rmask %#lx.\n", + pixel_format->rmask); + todo_wine_if(wine_todo && pixel_format->gmask != expected_pixel_format->gmask) + ok_(file, line)(pixel_format->gmask == expected_pixel_format->gmask, "Unexpected DDS pixel format gmask %#lx.\n", + pixel_format->gmask); + todo_wine_if(wine_todo && pixel_format->bmask != expected_pixel_format->bmask) + ok_(file, line)(pixel_format->bmask == expected_pixel_format->bmask, "Unexpected DDS pixel format bmask %#lx.\n", + pixel_format->bmask); + todo_wine_if(wine_todo && pixel_format->amask != expected_pixel_format->amask) + ok_(file, line)(pixel_format->amask == expected_pixel_format->amask, "Unexpected DDS pixel format amask %#lx.\n", + pixel_format->amask); +} + +#define check_dds_header(header, flags, height, width, pitch, depth, mip_levels, pixel_format, caps, caps2, wine_todo) \ + check_dds_header_(__FILE__, __LINE__, header, flags, height, width, pitch, depth, mip_levels, pixel_format, \ + caps, caps2, wine_todo) +static inline void check_dds_header_(const char *file, uint32_t line, const struct dds_header *header, uint32_t flags, + uint32_t height, uint32_t width, uint32_t pitch, uint32_t depth, uint32_t mip_levels, + const struct dds_pixel_format *pixel_format, uint32_t caps, uint32_t caps2, BOOL wine_todo) +{ + const struct dds_header expected_header = { sizeof(*header), flags, height, width, pitch, depth, mip_levels, { 0 }, + *pixel_format, caps, caps2, 0, 0, 0 }; + BOOL matched; + + matched = !memcmp(&expected_header, header, sizeof(*header)); + todo_wine_if(wine_todo) ok_(file, line)(matched, "Got unexpected dds header values.\n"); + if (matched) + return; + + todo_wine_if(wine_todo && header->flags != flags) + ok_(file, line)(header->flags == flags, "Unexpected DDS header flags %#lx.\n", header->flags); + todo_wine_if(wine_todo && header->width != width) + ok_(file, line)(header->width == width, "Unexpected DDS header width %#lx.\n", header->width); + todo_wine_if(wine_todo && header->height != height) + ok_(file, line)(header->height == height, "Unexpected DDS header height %#lx.\n", header->height); + todo_wine_if(wine_todo && header->pitch_or_linear_size != pitch) + ok_(file, line)(header->pitch_or_linear_size == pitch, "Unexpected DDS header pitch %#lx.\n", + header->pitch_or_linear_size); + todo_wine_if(wine_todo && header->depth != depth) + ok_(file, line)(header->depth == depth, "Unexpected DDS header depth %#lx.\n", header->depth); + todo_wine_if(wine_todo && header->miplevels != mip_levels) + ok_(file, line)(header->miplevels == mip_levels, "Unexpected DDS header mip levels %#lx.\n", header->miplevels); + ok_(file, line)(!memcmp(header->reserved, expected_header.reserved, sizeof(header->reserved)), + "Unexpected values in DDS header reserved field."); + check_dds_pixel_format_struct(&header->pixel_format, pixel_format, FALSE); + todo_wine_if(wine_todo && header->caps != caps) + ok_(file, line)(header->caps == caps, "Unexpected DDS header caps %#lx.\n", header->caps); + todo_wine_if(wine_todo && header->caps2 != caps2) + ok_(file, line)(header->caps2 == caps2, "Unexpected DDS header caps2 %#lx.\n", header->caps2); + ok_(file, line)(!header->caps3, "Unexpected DDS header caps3 %#lx.\n", header->caps3); + ok_(file, line)(!header->caps4, "Unexpected DDS header caps4 %#lx.\n", header->caps4); + ok_(file, line)(!header->reserved2, "Unexpected DDS header reserved2 %#lx.\n", header->reserved2); +} + struct volume_readback { IDirect3DVolume9 *volume; @@ -897,6 +1108,32 @@ static inline void get_texture_volume_readback_(const char *file, uint32_t line, } } +static inline BOOL compare_uint(uint32_t x, uint32_t y, uint32_t max_diff) +{ + uint32_t diff = x > y ? x - y : y - x; + + return diff <= max_diff; +} + +static inline BOOL compare_color_4bpp(uint32_t c1, uint32_t c2, uint8_t max_diff) +{ + return compare_uint(c1 & 0xff, c2 & 0xff, max_diff) + && compare_uint((c1 >> 8) & 0xff, (c2 >> 8) & 0xff, max_diff) + && compare_uint((c1 >> 16) & 0xff, (c2 >> 16) & 0xff, max_diff) + && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff); +} + +#define check_volume_readback_pixel_4bpp_diff(rb, x, y, z, color, max_diff, todo) \ + _check_volume_readback_pixel_4bpp_diff(__FILE__, __LINE__, rb, x, y, z, color, max_diff, todo) +static inline void _check_volume_readback_pixel_4bpp_diff(const char *file, uint32_t line, struct volume_readback *rb, + uint32_t x, uint32_t y, uint32_t z, uint32_t expected_color, uint32_t max_diff, BOOL todo) +{ + uint32_t color = get_volume_readback_color(rb, x, y, z); + + todo_wine_if(todo) ok_(file, line)(compare_color_4bpp(color, expected_color, max_diff), + "Got color 0x%08x, expected 0x%08x.\n", color, expected_color); +} + #define check_volume_readback_pixel_4bpp(rb, x, y, z, color, todo) \ _check_volume_readback_pixel_4bpp(__FILE__, __LINE__, rb, x, y, z, color, todo) static inline void _check_volume_readback_pixel_4bpp(const char *file, uint32_t line, struct volume_readback *rb, diff --git a/dlls/d3dx9_36/tests/shader.c b/dlls/d3dx9_36/tests/shader.c index 4ce668b92c3e..4ff54925adf8 100644 --- a/dlls/d3dx9_36/tests/shader.c +++ b/dlls/d3dx9_36/tests/shader.c @@ -6869,14 +6869,7 @@ static void test_hlsl_double(void) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); hr = D3DXCompileShader(ps_hlsl, sizeof(ps_hlsl), NULL, NULL, "main", "ps_2_0", 0, &ps_bytecode, &errors, NULL); - todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); - if (FAILED(hr)) - { - if (errors) - trace("%s", (char *)ID3DXBuffer_GetBufferPointer(errors)); - release_test_context(&context); - return; - } + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); hr = IDirect3DDevice9_CreateVertexShader(context.device, ID3DXBuffer_GetBufferPointer(vs_bytecode), &vs); ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 80343934cea7..7ce268ceeafb 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -26,22 +26,6 @@ #include #include "d3dx9_test_images.h" -/* - * MAKE_DDHRESULT is first defined in d3dx9.h, with the same definition as the - * one in ddraw.h. - */ -#ifdef MAKE_DDHRESULT -#undef MAKE_DDHRESULT -#endif -#include "ddraw.h" - -static BOOL compare_uint(uint32_t x, uint32_t y, uint32_t max_diff) -{ - uint32_t diff = x > y ? x - y : y - x; - - return diff <= max_diff; -} - static BOOL compare_float(float f, float g, uint32_t ulps) { int32_t x = *(int32_t *)&f; @@ -149,46 +133,6 @@ static HRESULT create_file(const char *filename, const unsigned char *data, cons return D3DERR_INVALIDCALL; } -/* dds_pixel_format.flags */ -#define DDS_PF_ALPHA 0x00000001 -#define DDS_PF_ALPHA_ONLY 0x00000002 -#define DDS_PF_FOURCC 0x00000004 -#define DDS_PF_INDEXED 0x00000020 -#define DDS_PF_RGB 0x00000040 -#define DDS_PF_LUMINANCE 0x00020000 -#define DDS_PF_BUMPLUMINANCE 0x00040000 -#define DDS_PF_BUMPDUDV 0x00080000 - -struct dds_pixel_format -{ - DWORD size; - DWORD flags; - DWORD fourcc; - DWORD bpp; - DWORD rmask; - DWORD gmask; - DWORD bmask; - DWORD amask; -}; - -struct dds_header -{ - DWORD size; - DWORD flags; - DWORD height; - DWORD width; - DWORD pitch_or_linear_size; - DWORD depth; - DWORD miplevels; - DWORD reserved[11]; - struct dds_pixel_format pixel_format; - DWORD caps; - DWORD caps2; - DWORD caps3; - DWORD caps4; - DWORD reserved2; -}; - /* fills dds_header with reasonable default values */ static void fill_dds_header(struct dds_header *header) { @@ -1085,6 +1029,13 @@ static inline void _check_pixel_4bpp(unsigned int line, const D3DLOCKED_RECT *lo ok_(__FILE__, line)(color == expected_color, "Got color 0x%08lx, expected 0x%08lx\n", color, expected_color); } +#define check_pixel_4bpp_diff(lockrect, x, y, color, max_diff) _check_pixel_4bpp_diff(__LINE__, lockrect, x, y, color, max_diff) +static inline void _check_pixel_4bpp_diff(unsigned int line, const D3DLOCKED_RECT *lockrect, int x, int y, DWORD expected_color, uint8_t max_diff) +{ + DWORD color = ((DWORD*)lockrect->pBits)[x + y * lockrect->Pitch / 4]; + ok_(__FILE__, line)(compare_color_4bpp(color, expected_color, max_diff), "Got color 0x%08lx, expected 0x%08lx.\n", color, expected_color); +} + #define check_pixel_8bpp(lockrect, x, y, color) _check_pixel_8bpp(__LINE__, lockrect, x, y, color) static inline void _check_pixel_8bpp(unsigned int line, const D3DLOCKED_RECT *lockrect, int x, int y, uint64_t expected_color) { @@ -1116,89 +1067,6 @@ static inline void _check_readback_pixel_4bpp(unsigned int line, struct surface_ todo_wine_if(todo) ok_(__FILE__, line)(color == expected_color, "Got color 0x%08x, expected 0x%08x.\n", color, expected_color); } -static const PALETTEENTRY test_palette[256] = -{ - {0x00,0x00,0x00,0x00}, {0x00,0x00,0x80,0x01}, {0x00,0x80,0x00,0x02}, {0x00,0x80,0x80,0x03}, - {0x80,0x00,0x00,0x04}, {0x80,0x00,0x80,0x05}, {0x80,0x80,0x00,0x06}, {0xc0,0xc0,0xc0,0x07}, - {0xc0,0xdc,0xc0,0x08}, {0xf0,0xca,0xa6,0x09}, {0x00,0x20,0x40,0x0a}, {0x00,0x20,0x60,0x0b}, - {0x00,0x20,0x80,0x0c}, {0x00,0x20,0xa0,0x0d}, {0x00,0x20,0xc0,0x0e}, {0x00,0x20,0xe0,0x0f}, - - {0x00,0x40,0x00,0x10}, {0x00,0x40,0x20,0x11}, {0x00,0x40,0x40,0x12}, {0x00,0x40,0x60,0x13}, - {0x00,0x40,0x80,0x14}, {0x00,0x40,0xa0,0x15}, {0x00,0x40,0xc0,0x16}, {0x00,0x40,0xe0,0x17}, - {0x00,0x60,0x00,0x18}, {0x00,0x60,0x20,0x19}, {0x00,0x60,0x40,0x1a}, {0x00,0x60,0x60,0x1b}, - {0x00,0x60,0x80,0x1c}, {0x00,0x60,0xa0,0x1d}, {0x00,0x60,0xc0,0x1e}, {0x00,0x60,0xe0,0x1f}, - - {0x00,0x80,0x00,0x20}, {0x00,0x80,0x20,0x21}, {0x00,0x80,0x40,0x22}, {0x00,0x80,0x60,0x23}, - {0x00,0x80,0x80,0x24}, {0x00,0x80,0xa0,0x25}, {0x00,0x80,0xc0,0x26}, {0x00,0x80,0xe0,0x27}, - {0x00,0xa0,0x00,0x28}, {0x00,0xa0,0x20,0x29}, {0x00,0xa0,0x40,0x2a}, {0x00,0xa0,0x60,0x2b}, - {0x00,0xa0,0x80,0x2c}, {0x00,0xa0,0xa0,0x2d}, {0x00,0xa0,0xc0,0x2e}, {0x00,0xa0,0xe0,0x2f}, - - {0x00,0xc0,0x00,0x30}, {0x00,0xc0,0x20,0x31}, {0x00,0xc0,0x40,0x32}, {0x00,0xc0,0x60,0x33}, - {0x00,0xc0,0x80,0x34}, {0x00,0xc0,0xa0,0x35}, {0x00,0xc0,0xc0,0x36}, {0x00,0xc0,0xe0,0x37}, - {0x00,0xe0,0x00,0x38}, {0x00,0xe0,0x20,0x39}, {0x00,0xe0,0x40,0x3a}, {0x00,0xe0,0x60,0x3b}, - {0x00,0xe0,0x80,0x3c}, {0x00,0xe0,0xa0,0x3d}, {0x00,0xe0,0xc0,0x3e}, {0x00,0xe0,0xe0,0x3f}, - - {0x40,0x00,0x00,0x40}, {0x40,0x00,0x20,0x41}, {0x40,0x00,0x40,0x42}, {0x40,0x00,0x60,0x43}, - {0x40,0x00,0x80,0x44}, {0x40,0x00,0xa0,0x45}, {0x40,0x00,0xc0,0x46}, {0x40,0x00,0xe0,0x47}, - {0x40,0x20,0x00,0x48}, {0x40,0x20,0x20,0x49}, {0x40,0x20,0x40,0x4a}, {0x40,0x20,0x60,0x4b}, - {0x40,0x20,0x80,0x4c}, {0x40,0x20,0xa0,0x4d}, {0x40,0x20,0xc0,0x4e}, {0x40,0x20,0xe0,0x4f}, - - {0x40,0x40,0x00,0x50}, {0x40,0x40,0x20,0x51}, {0x40,0x40,0x40,0x52}, {0x40,0x40,0x60,0x53}, - {0x40,0x40,0x80,0x54}, {0x40,0x40,0xa0,0x55}, {0x40,0x40,0xc0,0x56}, {0x40,0x40,0xe0,0x57}, - {0x40,0x60,0x00,0x58}, {0x40,0x60,0x20,0x59}, {0x40,0x60,0x40,0x5a}, {0x40,0x60,0x60,0x5b}, - {0x40,0x60,0x80,0x5c}, {0x40,0x60,0xa0,0x5d}, {0x40,0x60,0xc0,0x5e}, {0x40,0x60,0xe0,0x5f}, - - {0x40,0x80,0x00,0x60}, {0x40,0x80,0x20,0x61}, {0x40,0x80,0x40,0x62}, {0x40,0x80,0x60,0x63}, - {0x40,0x80,0x80,0x64}, {0x40,0x80,0xa0,0x65}, {0x40,0x80,0xc0,0x66}, {0x40,0x80,0xe0,0x67}, - {0x40,0xa0,0x00,0x68}, {0x40,0xa0,0x20,0x69}, {0x40,0xa0,0x40,0x6a}, {0x40,0xa0,0x60,0x6b}, - {0x40,0xa0,0x80,0x6c}, {0x40,0xa0,0xa0,0x6d}, {0x40,0xa0,0xc0,0x6e}, {0x40,0xa0,0xe0,0x6f}, - - {0x40,0xc0,0x00,0x70}, {0x40,0xc0,0x20,0x71}, {0x40,0xc0,0x40,0x72}, {0x40,0xc0,0x60,0x73}, - {0x40,0xc0,0x80,0x74}, {0x40,0xc0,0xa0,0x75}, {0x40,0xc0,0xc0,0x76}, {0x40,0xc0,0xe0,0x77}, - {0x40,0xe0,0x00,0x78}, {0x40,0xe0,0x20,0x79}, {0x40,0xe0,0x40,0x7a}, {0x40,0xe0,0x60,0x7b}, - {0x40,0xe0,0x80,0x7c}, {0x40,0xe0,0xa0,0x7d}, {0x40,0xe0,0xc0,0x7e}, {0x40,0xe0,0xe0,0x7f}, - - {0x80,0x00,0x00,0x80}, {0x80,0x00,0x20,0x81}, {0x80,0x00,0x40,0x82}, {0x80,0x00,0x60,0x83}, - {0x80,0x00,0x80,0x84}, {0x80,0x00,0xa0,0x85}, {0x80,0x00,0xc0,0x86}, {0x80,0x00,0xe0,0x87}, - {0x80,0x20,0x00,0x88}, {0x80,0x20,0x20,0x89}, {0x80,0x20,0x40,0x8a}, {0x80,0x20,0x60,0x8b}, - {0x80,0x20,0x80,0x8c}, {0x80,0x20,0xa0,0x8d}, {0x80,0x20,0xc0,0x8e}, {0x80,0x20,0xe0,0x8f}, - - {0x80,0x40,0x00,0x90}, {0x80,0x40,0x20,0x91}, {0x80,0x40,0x40,0x92}, {0x80,0x40,0x60,0x93}, - {0x80,0x40,0x80,0x94}, {0x80,0x40,0xa0,0x95}, {0x80,0x40,0xc0,0x96}, {0x80,0x40,0xe0,0x97}, - {0x80,0x60,0x00,0x98}, {0x80,0x60,0x20,0x99}, {0x80,0x60,0x40,0x9a}, {0x80,0x60,0x60,0x9b}, - {0x80,0x60,0x80,0x9c}, {0x80,0x60,0xa0,0x9d}, {0x80,0x60,0xc0,0x9e}, {0x80,0x60,0xe0,0x9f}, - - {0x80,0x80,0x00,0xa0}, {0x80,0x80,0x20,0xa1}, {0x80,0x80,0x40,0xa2}, {0x80,0x80,0x60,0xa3}, - {0x80,0x80,0x80,0xa4}, {0x80,0x80,0xa0,0xa5}, {0x80,0x80,0xc0,0xa6}, {0x80,0x80,0xe0,0xa7}, - {0x80,0xa0,0x00,0xa8}, {0x80,0xa0,0x20,0xa9}, {0x80,0xa0,0x40,0xaa}, {0x80,0xa0,0x60,0xab}, - {0x80,0xa0,0x80,0xac}, {0x80,0xa0,0xa0,0xad}, {0x80,0xa0,0xc0,0xae}, {0x80,0xa0,0xe0,0xaf}, - - {0x80,0xc0,0x00,0xb0}, {0x80,0xc0,0x20,0xb1}, {0x80,0xc0,0x40,0xb2}, {0x80,0xc0,0x60,0xb3}, - {0x80,0xc0,0x80,0xb4}, {0x80,0xc0,0xa0,0xb5}, {0x80,0xc0,0xc0,0xb6}, {0x80,0xc0,0xe0,0xb7}, - {0x80,0xe0,0x00,0xb8}, {0x80,0xe0,0x20,0xb9}, {0x80,0xe0,0x40,0xba}, {0x80,0xe0,0x60,0xbb}, - {0x80,0xe0,0x80,0xbc}, {0x80,0xe0,0xa0,0xbd}, {0x80,0xe0,0xc0,0xbe}, {0x80,0xe0,0xe0,0xbf}, - - {0xc0,0x00,0x00,0xc0}, {0xc0,0x00,0x20,0xc1}, {0xc0,0x00,0x40,0xc2}, {0xc0,0x00,0x60,0xc3}, - {0xc0,0x00,0x80,0xc4}, {0xc0,0x00,0xa0,0xc5}, {0xc0,0x00,0xc0,0xc6}, {0xc0,0x00,0xe0,0xc7}, - {0xc0,0x20,0x00,0xc8}, {0xc0,0x20,0x20,0xc9}, {0xc0,0x20,0x40,0xca}, {0xc0,0x20,0x60,0xcb}, - {0xc0,0x20,0x80,0xcc}, {0xc0,0x20,0xa0,0xcd}, {0xc0,0x20,0xc0,0xce}, {0xc0,0x20,0xe0,0xcf}, - - {0xc0,0x40,0x00,0xd0}, {0xc0,0x40,0x20,0xd1}, {0xc0,0x40,0x40,0xd2}, {0xc0,0x40,0x60,0xd3}, - {0xc0,0x40,0x80,0xd4}, {0xc0,0x40,0xa0,0xd5}, {0xc0,0x40,0xc0,0xd6}, {0xc0,0x40,0xe0,0xd7}, - {0xc0,0x60,0x00,0xd8}, {0xc0,0x60,0x20,0xd9}, {0xc0,0x60,0x40,0xda}, {0xc0,0x60,0x60,0xdb}, - {0xc0,0x60,0x80,0xdc}, {0xc0,0x60,0xa0,0xdd}, {0xc0,0x60,0xc0,0xde}, {0xc0,0x60,0xe0,0xdf}, - - {0xc0,0x80,0x00,0xe0}, {0xc0,0x80,0x20,0xe1}, {0xc0,0x80,0x40,0xe2}, {0xc0,0x80,0x60,0xe3}, - {0xc0,0x80,0x80,0xe4}, {0xc0,0x80,0xa0,0xe5}, {0xc0,0x80,0xc0,0xe6}, {0xc0,0x80,0xe0,0xe7}, - {0xc0,0xa0,0x00,0xe8}, {0xc0,0xa0,0x20,0xe9}, {0xc0,0xa0,0x40,0xea}, {0xc0,0xa0,0x60,0xeb}, - {0xc0,0xa0,0x80,0xec}, {0xc0,0xa0,0xa0,0xed}, {0xc0,0xa0,0xc0,0xee}, {0xc0,0xa0,0xe0,0xef}, - - {0xc0,0xc0,0x00,0xf0}, {0xc0,0xc0,0x20,0xf1}, {0xc0,0xc0,0x40,0xf2}, {0xc0,0xc0,0x60,0xf3}, - {0xc0,0xc0,0x80,0xf4}, {0xc0,0xc0,0xa0,0xf5}, {0xf0,0xfb,0xff,0xf6}, {0xa4,0xa0,0xa0,0xf7}, - {0x80,0x80,0x80,0xf8}, {0x00,0x00,0xff,0xf9}, {0x00,0xff,0x00,0xfa}, {0x00,0xff,0xff,0xfb}, - {0xff,0x00,0x00,0xfc}, {0xff,0x00,0xff,0xfd}, {0xff,0xff,0x00,0xfe}, {0xff,0xff,0xff,0xff}, -}; - static const uint16_t v16u16_2_2[] = { 0x0000, 0x3000, 0x4000, 0x7fff, 0x8000, 0x8001, 0xc000, 0xffff, @@ -1487,7 +1355,7 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) { const uint32_t expected_pixel = !(x & 0x01) ? 0xffffffff : 0x00000000; - check_readback_pixel_4bpp(&surface_rb, x, y, expected_pixel, !expected_pixel); + check_readback_pixel_4bpp(&surface_rb, x, y, expected_pixel, FALSE); } } release_surface_readback(&surface_rb); @@ -1515,9 +1383,8 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) for (x = 0; x < 4; ++x) { const uint32_t expected_pixel = dxt_pma_decompressed_expected[(y * 4) + x]; - const BOOL todo = ((expected_pixel >> 24) & 0xff) != 0xff; - todo_wine_if(todo) check_pixel_4bpp(&lock_rect, x, y, expected_pixel); + check_pixel_4bpp_diff(&lock_rect, x, y, expected_pixel, 1); } } IDirect3DSurface9_UnlockRect(decomp_surf); @@ -2688,6 +2555,50 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + /* Test SRGB filter flags. */ + SetRect(&rect, 0, 0, 2, 2); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8r8g8b8, D3DFMT_A8R8G8B8, 8, NULL, &rect, + D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + /* SRGB in, no SRGB out. */ + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_4bpp_diff(&lockrect, 0, 0, 0x00010306, 2); + check_pixel_4bpp_diff(&lockrect, 1, 0, 0x40141e2a, 2); + check_pixel_4bpp_diff(&lockrect, 0, 1, 0x80495b71, 2); + check_pixel_4bpp_diff(&lockrect, 1, 1, 0xc0a3c0ff, 2); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8r8g8b8, D3DFMT_A8R8G8B8, 8, NULL, &rect, + D3DX_FILTER_NONE | D3DX_FILTER_SRGB_OUT, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + /* No SRGB in, SRGB out. */ + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_4bpp_diff(&lockrect, 0, 0, 0x00486377, 2); + check_pixel_4bpp_diff(&lockrect, 1, 0, 0x4097a4af, 2); + check_pixel_4bpp_diff(&lockrect, 0, 1, 0x80c5ced7, 2); + check_pixel_4bpp_diff(&lockrect, 1, 1, 0xc0e8f0ff, 2); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8r8g8b8, D3DFMT_A8R8G8B8, 8, NULL, &rect, + D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN | D3DX_FILTER_SRGB_OUT, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + /* SRGB in, SRGB out, no changes. */ + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_4bpp_diff(&lockrect, 0, 0, pixdata_a8r8g8b8[0], 0); + check_pixel_4bpp_diff(&lockrect, 1, 0, pixdata_a8r8g8b8[1], 0); + check_pixel_4bpp_diff(&lockrect, 0, 1, pixdata_a8r8g8b8[2], 0); + check_pixel_4bpp_diff(&lockrect, 1, 1, pixdata_a8r8g8b8[3], 0); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + check_release((IUnknown*)surf, 0); } @@ -3425,82 +3336,6 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) if(testbitmap_ok) DeleteFileA("testbitmap.bmp"); } -#define check_dds_pixel_format_struct(pixel_format, expected_pixel_format, wine_todo) \ - check_dds_pixel_format_struct_(__FILE__, __LINE__, pixel_format, expected_pixel_format, wine_todo) -static void check_dds_pixel_format_struct_(const char *file, uint32_t line, const struct dds_pixel_format *pixel_format, - const struct dds_pixel_format *expected_pixel_format, BOOL wine_todo) -{ - BOOL matched; - - matched = !memcmp(expected_pixel_format, pixel_format, sizeof(*pixel_format)); - todo_wine_if(wine_todo) ok_(file, line)(matched, "Got unexpected dds pixel format values.\n"); - if (matched) - return; - - todo_wine_if(wine_todo && pixel_format->flags != expected_pixel_format->flags) - ok_(file, line)(pixel_format->flags == expected_pixel_format->flags, "Unexpected DDS pixel format flags %#lx.\n", - pixel_format->flags); - todo_wine_if(wine_todo && pixel_format->fourcc != expected_pixel_format->fourcc) - ok_(file, line)(pixel_format->fourcc == expected_pixel_format->fourcc, "Unexpected DDS pixel format fourcc %#lx.\n", - pixel_format->fourcc); - todo_wine_if(wine_todo && pixel_format->bpp != expected_pixel_format->bpp) - ok_(file, line)(pixel_format->bpp == expected_pixel_format->bpp, "Unexpected DDS pixel format bpp %#lx.\n", - pixel_format->bpp); - todo_wine_if(wine_todo && pixel_format->rmask != expected_pixel_format->rmask) - ok_(file, line)(pixel_format->rmask == expected_pixel_format->rmask, "Unexpected DDS pixel format rmask %#lx.\n", - pixel_format->rmask); - todo_wine_if(wine_todo && pixel_format->gmask != expected_pixel_format->gmask) - ok_(file, line)(pixel_format->gmask == expected_pixel_format->gmask, "Unexpected DDS pixel format gmask %#lx.\n", - pixel_format->gmask); - todo_wine_if(wine_todo && pixel_format->bmask != expected_pixel_format->bmask) - ok_(file, line)(pixel_format->bmask == expected_pixel_format->bmask, "Unexpected DDS pixel format bmask %#lx.\n", - pixel_format->bmask); - todo_wine_if(wine_todo && pixel_format->amask != expected_pixel_format->amask) - ok_(file, line)(pixel_format->amask == expected_pixel_format->amask, "Unexpected DDS pixel format amask %#lx.\n", - pixel_format->amask); -} - -#define check_dds_header(header, flags, height, width, pitch, depth, mip_levels, pixel_format, caps, caps2, wine_todo) \ - check_dds_header_(__FILE__, __LINE__, header, flags, height, width, pitch, depth, mip_levels, pixel_format, \ - caps, caps2, wine_todo) -static void check_dds_header_(const char *file, uint32_t line, const struct dds_header *header, uint32_t flags, - uint32_t height, uint32_t width, uint32_t pitch, uint32_t depth, uint32_t mip_levels, - const struct dds_pixel_format *pixel_format, uint32_t caps, uint32_t caps2, BOOL wine_todo) -{ - const struct dds_header expected_header = { sizeof(*header), flags, height, width, pitch, depth, mip_levels, { 0 }, - *pixel_format, caps, caps2, 0, 0, 0 }; - BOOL matched; - - matched = !memcmp(&expected_header, header, sizeof(*header)); - todo_wine_if(wine_todo) ok_(file, line)(matched, "Got unexpected dds header values.\n"); - if (matched) - return; - - todo_wine_if(wine_todo && header->flags != flags) - ok_(file, line)(header->flags == flags, "Unexpected DDS header flags %#lx.\n", header->flags); - todo_wine_if(wine_todo && header->width != width) - ok_(file, line)(header->width == width, "Unexpected DDS header width %#lx.\n", header->width); - todo_wine_if(wine_todo && header->height != height) - ok_(file, line)(header->height == height, "Unexpected DDS header height %#lx.\n", header->height); - todo_wine_if(wine_todo && header->pitch_or_linear_size != pitch) - ok_(file, line)(header->pitch_or_linear_size == pitch, "Unexpected DDS header pitch %#lx.\n", - header->pitch_or_linear_size); - todo_wine_if(wine_todo && header->depth != depth) - ok_(file, line)(header->depth == depth, "Unexpected DDS header depth %#lx.\n", header->depth); - todo_wine_if(wine_todo && header->miplevels != mip_levels) - ok_(file, line)(header->miplevels == mip_levels, "Unexpected DDS header mip levels %#lx.\n", header->miplevels); - ok_(file, line)(!memcmp(header->reserved, expected_header.reserved, sizeof(header->reserved)), - "Unexpected values in DDS header reserved field."); - check_dds_pixel_format_struct(&header->pixel_format, pixel_format, FALSE); - todo_wine_if(wine_todo && header->caps != caps) - ok_(file, line)(header->caps == caps, "Unexpected DDS header caps %#lx.\n", header->caps); - todo_wine_if(wine_todo && header->caps2 != caps2) - ok_(file, line)(header->caps2 == caps2, "Unexpected DDS header caps2 %#lx.\n", header->caps2); - ok_(file, line)(!header->caps3, "Unexpected DDS header caps3 %#lx.\n", header->caps3); - ok_(file, line)(!header->caps4, "Unexpected DDS header caps4 %#lx.\n", header->caps4); - ok_(file, line)(!header->reserved2, "Unexpected DDS header reserved2 %#lx.\n", header->reserved2); -} - #define DDS_FILE_HEADER_SIZE (sizeof(uint32_t) + sizeof(struct dds_header)) #define PALETTED_DDS_FILE_HEADER_SIZE (DDS_FILE_HEADER_SIZE + (sizeof(PALETTEENTRY) * 256)) static void test_save_surface_to_dds(IDirect3DDevice9 *device) @@ -3826,6 +3661,644 @@ static void test_save_surface_to_dds(IDirect3DDevice9 *device) } } +static BOOL is_dxt_d3dformat(D3DFORMAT fmt) +{ + return (fmt & 0x00ffffff) == MAKEFOURCC('D','X','T',0); +} + +static void test_save_surface_iffs(IDirect3DDevice9 *device) +{ + static const D3DXIMAGE_FILEFORMAT test_iff[] = { D3DXIFF_BMP, D3DXIFF_JPG, D3DXIFF_TGA, D3DXIFF_PNG, + D3DXIFF_PPM, D3DXIFF_DIB, D3DXIFF_HDR, D3DXIFF_PFM }; + static const char *test_iff_str[] = { "D3DXIFF_BMP", "D3DXIFF_JPG", "D3DXIFF_TGA", "D3DXIFF_PNG", + "D3DXIFF_PPM", "D3DXIFF_DIB", "D3DXIFF_HDR", "D3DXIFF_PFM" }; + static const struct + { + D3DFORMAT format; + const PALETTEENTRY *palette; + struct + { + HRESULT hr; + D3DFORMAT format; + BOOL todo_hr; + BOOL todo_format; + } + iff_expected[8]; + uint8_t init_pixel_value; + } iff_tests[] = { + { D3DFMT_P8, test_palette, + { { D3D_OK, D3DFMT_P8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_P8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A8P8, test_palette, + { { D3D_OK, D3DFMT_P8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_P8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_P8, NULL, + { { D3D_OK, D3DFMT_A8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A8P8, NULL, + { { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A8P8, NULL, + { { D3D_OK, D3DFMT_A8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, 0xff + }, + { D3DFMT_R8G8B8, NULL, + { { D3D_OK, D3DFMT_R8G8B8, }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_R8G8B8, }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + /* + * For BMP/DIB, these encode as D3DFMT_X8R8G8B8. If there's a single + * pixel with a non-zero alpha channel, it reports as D3DFMT_A8R8G8B8. + */ + { D3DFMT_A8R8G8B8, NULL, + { { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8, }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + /* + * Same as decoding for BMP/DIB, if the alpha channel is set to a + * non-zero value on any pixel we get a different format. + */ + { D3DFMT_A8R8G8B8, NULL, + { { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8, }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, 0xff + }, + { D3DFMT_X8R8G8B8, NULL, + { { D3D_OK, D3DFMT_X8R8G8B8, }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + /* + * Unlike D3DFMT_A8R8G8B8, even if the alpha channel is all 0, + * D3DFMT_A8B8G8R8 doesn't get replaced with D3DFMT_X8B8G8R8 + * for BMP/DIB. + */ + { D3DFMT_A8B8G8R8, NULL, + { { D3D_OK, D3DFMT_A8B8G8R8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8B8G8R8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_X8B8G8R8, NULL, + { { D3D_OK, D3DFMT_X8B8G8R8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8B8G8R8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_R5G6B5, NULL, + { { D3D_OK, D3DFMT_R5G6B5, }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_R5G6B5, }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_X1R5G5B5, NULL, + { { D3D_OK, D3DFMT_X1R5G5B5, }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X1R5G5B5, }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A1R5G5B5, NULL, + { { D3D_OK, D3DFMT_A1R5G5B5, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A1R5G5B5, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_R3G3B2, NULL, + { { D3D_OK, D3DFMT_P8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_P8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A8R3G3B2, NULL, + { { D3D_OK, D3DFMT_A8R3G3B2, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R3G3B2, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A4R4G4B4, NULL, + { { D3D_OK, D3DFMT_A4R4G4B4, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A4R4G4B4, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_X4R4G4B4, NULL, + { { D3D_OK, D3DFMT_X4R4G4B4, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X4R4G4B4, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A2R10G10B10, NULL, + { { D3D_OK, D3DFMT_A2R10G10B10, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A16B16G16R16 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A2R10G10B10, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A2B10G10R10, NULL, + { { D3D_OK, D3DFMT_A2B10G10R10, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A16B16G16R16 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A2B10G10R10, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A16B16G16R16, NULL, + { { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A16B16G16R16 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_G16R16, NULL, + { { D3D_OK, D3DFMT_G16R16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_A16B16G16R16 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_G16R16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A8, NULL, + { { D3D_OK, D3DFMT_A8R3G3B2, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R3G3B2, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A8L8, NULL, + { { D3D_OK, D3DFMT_A8L8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8L8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A4L4, NULL, + { { D3D_OK, D3DFMT_A4R4G4B4, .todo_format = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A4R4G4B4, .todo_format = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + /* + * For BMP/DIB, this ends up as a paletted bitmap file where the + * palette consists of RGB values of 0x00->0xff. Essentially, the luma + * value acts as an index into this palette. Weird that there are L16 + * and A8L8 representations, but this is done in a unique way. + */ + { D3DFMT_L8, NULL, + { { D3D_OK, D3DFMT_P8, .todo_format = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_P8, .todo_format = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_L16, NULL, + { { D3D_OK, D3DFMT_L16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_A16B16G16R16 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_L16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_DXT1, NULL, + { { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_DXT2, NULL, + { { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_DXT2, NULL, + { { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, 0xff + }, + { D3DFMT_DXT3, NULL, + { { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_DXT4, NULL, + { { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_DXT5, NULL, + { { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_R16F, NULL, + { { D3D_OK, D3DFMT_G16R16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_A16B16G16R16 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_G16R16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_G16R16F, NULL, + { { D3D_OK, D3DFMT_G16R16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_A16B16G16R16 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_G16R16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A16B16G16R16F, NULL, + { { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A16B16G16R16 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_R32F, NULL, + { { D3D_OK, D3DFMT_G16R16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_A16B16G16R16 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_G16R16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_G32R32F, NULL, + { { D3D_OK, D3DFMT_G16R16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_R8G8B8 }, + { D3D_OK, D3DFMT_A16B16G16R16 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_G16R16, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A32B32G32R32F, NULL, + { { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A8R8G8B8 }, + { D3D_OK, D3DFMT_A16B16G16R16 }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8 }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_Q8W8V8U8, NULL, + { { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + }, + }, + { D3DFMT_V8U8, NULL, + { { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + }, + }, + { D3DFMT_V16U16, NULL, + { { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + }, + }, + { D3DFMT_X8L8V8U8, NULL, + { { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + }, + }, + { D3DFMT_A2W10V10U10, NULL, + { { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + }, + }, + { D3DFMT_Q16W16V16U16, NULL, + { { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + { D3DERR_INVALIDCALL, .todo_hr = TRUE }, + }, + }, + { D3DFMT_R8G8_B8G8, NULL, + { { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_G8R8_G8B8, NULL, + { { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_UYVY, NULL, + { { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + { D3DFMT_YUY2, NULL, + { { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_X8R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_R8G8B8, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + { D3D_OK, D3DFMT_A32B32G32R32F, .todo_hr = TRUE }, + }, + }, + }; + IDirect3DSurface9 *surface; + ID3DXBuffer *buffer; + uint32_t i, j; + HRESULT hr; + + for (i = 0; i < ARRAY_SIZE(iff_tests); ++i) + { + D3DLOCKED_RECT lockrect; + + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, iff_tests[i].format, + D3DPOOL_SCRATCH, &surface, NULL); + if (FAILED(hr)) + { + skip("Couldn't create surface for format %#x.\n", iff_tests[i].format); + continue; + } + + hr = IDirect3DSurface9_LockRect(surface, &lockrect, NULL, 0); + if (SUCCEEDED(hr)) + { + const uint32_t tmp_height = is_dxt_d3dformat(iff_tests[i].format) ? 1 : 4; + + for (j = 0; j < tmp_height; ++j) + memset(((uint8_t *)lockrect.pBits) + (j * lockrect.Pitch), iff_tests[i].init_pixel_value, lockrect.Pitch); + IDirect3DSurface9_UnlockRect(surface); + } + + winetest_push_context("Test %u (%s)", i, debug_d3dformat(iff_tests[i].format)); + for (j = 0; j < ARRAY_SIZE(test_iff); ++j) + { + winetest_push_context("File format %u (%s)", j, test_iff_str[j]); + + buffer = NULL; + hr = D3DXSaveSurfaceToFileInMemory(&buffer, test_iff[j], surface, iff_tests[i].palette, NULL); + todo_wine_if(iff_tests[i].iff_expected[j].todo_hr) ok(hr == iff_tests[i].iff_expected[j].hr, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + D3DXIMAGE_INFO info = { 0 }; + + hr = D3DXGetImageInfoFromFileInMemory(ID3DXBuffer_GetBufferPointer(buffer), ID3DXBuffer_GetBufferSize(buffer), &info); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(iff_tests[i].iff_expected[j].todo_format) ok(info.Format == iff_tests[i].iff_expected[j].format, + "Unexpected image format %u (%s), expected %u (%s).\n", info.Format, debug_d3dformat(info.Format), + iff_tests[i].iff_expected[j].format, debug_d3dformat(iff_tests[i].iff_expected[j].format)); + ID3DXBuffer_Release(buffer); + } + winetest_pop_context(); + } + + IDirect3DSurface9_Release(surface); + winetest_pop_context(); + } +} + static void test_D3DXSaveSurfaceToFileInMemory(IDirect3DDevice9 *device) { static const struct dds_pixel_format d3dfmt_a8r8g8b8_pf = { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, @@ -3852,10 +4325,16 @@ static void test_D3DXSaveSurfaceToFileInMemory(IDirect3DDevice9 *device) struct dds_header header; BYTE *data; } *dds; + struct + { + struct tga_header header; + BYTE *data; + } *tga; + ID3DXBuffer *buffer, *buffer2; IDirect3DSurface9 *surface; IDirect3DTexture9 *texture; unsigned int i, x, y; - ID3DXBuffer *buffer; + D3DXIMAGE_INFO info; HRESULT hr; RECT rect; @@ -3934,6 +4413,52 @@ static void test_D3DXSaveSurfaceToFileInMemory(IDirect3DDevice9 *device) &d3dfmt_a8r8g8b8_pf, DDSCAPS_TEXTURE | DDSCAPS_ALPHA, 0, FALSE); ID3DXBuffer_Release(buffer); + /* Test saved targa file headers. */ + hr = D3DXSaveSurfaceToFileInMemory(&buffer, D3DXIFF_TGA, surface, NULL, NULL); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + tga = ID3DXBuffer_GetBufferPointer(buffer); + ok(ID3DXBuffer_GetBufferSize(buffer) == (sizeof(tga->header) + tga->header.id_length + (4 * 4 * 4)), "Unexpected buffer size %lu.\n", + ID3DXBuffer_GetBufferSize(buffer)); + ok(tga->header.image_type == IMAGETYPE_TRUECOLOR, "Got unexpected image type %u.\n", tga->header.image_type); + ok(tga->header.height == 4, "Got unexpected height %u.\n", tga->header.height); + ok(tga->header.width == 4, "Got unexpected width %u.\n", tga->header.width); + ok(tga->header.depth == 32, "Got unexpected depth %u.\n", tga->header.depth); + ok(tga->header.image_descriptor == (IMAGE_TOPTOBOTTOM | 0x8), "Got unexpected image descriptor %#x.\n", tga->header.image_descriptor); + ID3DXBuffer_Release(buffer); + + /* Size 0 rectangle. */ + SetRectEmpty(&rect); + hr = D3DXSaveSurfaceToFileInMemory(&buffer, D3DXIFF_TGA, surface, NULL, &rect); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + tga = ID3DXBuffer_GetBufferPointer(buffer); + ok(ID3DXBuffer_GetBufferSize(buffer) == (sizeof(tga->header) + tga->header.id_length), "Unexpected buffer size %lu.\n", + ID3DXBuffer_GetBufferSize(buffer)); + ok(tga->header.image_type == IMAGETYPE_TRUECOLOR, "Got unexpected image type %u.\n", tga->header.image_type); + ok(!tga->header.height, "Got unexpected height %u.\n", tga->header.height); + ok(!tga->header.width, "Got unexpected width %u.\n", tga->header.width); + ok(tga->header.depth == 32, "Got unexpected depth %u.\n", tga->header.depth); + ok(tga->header.image_descriptor == (IMAGE_TOPTOBOTTOM | 0x8), "Got unexpected image descriptor %#x.\n", tga->header.image_descriptor); + ID3DXBuffer_Release(buffer); + + /* Saving as D3DXIFF_DIB actually saves as a BMP. */ + hr = D3DXSaveSurfaceToFileInMemory(&buffer, D3DXIFF_DIB, surface, NULL, NULL); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = D3DXSaveSurfaceToFileInMemory(&buffer2, D3DXIFF_BMP, surface, NULL, NULL); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = D3DXGetImageInfoFromFileInMemory(ID3DXBuffer_GetBufferPointer(buffer), ID3DXBuffer_GetBufferSize(buffer), &info); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(info.ImageFileFormat == D3DXIFF_BMP, "Unexpected ImageFileFormat %d.\n", info.ImageFileFormat); + ok(ID3DXBuffer_GetBufferSize(buffer) == ID3DXBuffer_GetBufferSize(buffer2), "Unexpected buffer size.\n"); + ok(!memcmp(ID3DXBuffer_GetBufferPointer(buffer), ID3DXBuffer_GetBufferPointer(buffer2), ID3DXBuffer_GetBufferSize(buffer)), + "Files do not match.\n"); + + ID3DXBuffer_Release(buffer); + ID3DXBuffer_Release(buffer2); + IDirect3DSurface9_Release(surface); for (i = 0; i < ARRAY_SIZE(test_access_types); ++i) @@ -3958,6 +4483,7 @@ static void test_D3DXSaveSurfaceToFileInMemory(IDirect3DDevice9 *device) } test_save_surface_to_dds(device); + test_save_surface_iffs(device); } static void test_D3DXSaveSurfaceToFile(IDirect3DDevice9 *device) @@ -4035,10 +4561,11 @@ static void test_D3DXSaveSurfaceToFile(IDirect3DDevice9 *device) { hr = D3DXSaveSurfaceToFileA("saved_surface.ppm", D3DXIFF_PPM, surface, NULL, NULL); ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); - hr = D3DXSaveSurfaceToFileA("saved_surface.tga", D3DXIFF_TGA, surface, NULL, NULL); - ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); } + hr = D3DXSaveSurfaceToFileA("saved_surface.tga", D3DXIFF_TGA, surface, NULL, NULL); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + hr = D3DXSaveSurfaceToFileA("saved_surface.dds", D3DXIFF_DDS, surface, NULL, NULL); ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); diff --git a/dlls/d3dx9_36/tests/texture.c b/dlls/d3dx9_36/tests/texture.c index ce7f6d7056f1..d107fea0f976 100644 --- a/dlls/d3dx9_36/tests/texture.c +++ b/dlls/d3dx9_36/tests/texture.c @@ -25,6 +25,7 @@ #include "d3dx9tex.h" #include "resources.h" #include +#include #include "d3dx9_test_images.h" static int has_2d_dxt1, has_2d_dxt3, has_2d_dxt5, has_cube_dxt5, has_3d_dxt3; @@ -168,13 +169,6 @@ static inline void check_texture_mip_levels_(uint32_t line, IDirect3DBaseTexture mip_levels, expected_mip_levels); } -static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff) -{ - unsigned int diff = x > y ? x - y : y - x; - - return diff <= max_diff; -} - static BOOL compare_color(DWORD c1, DWORD c2, BYTE max_diff) { return compare_uint(c1 & 0xff, c2 & 0xff, max_diff) @@ -3096,6 +3090,165 @@ static void WINAPI fill_cube_positive_x(D3DXVECTOR4 *out, const D3DXVECTOR3 *tex out->x = 1; } +static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) +{ + static const struct + { + D3DRESOURCETYPE type; + D3DFORMAT format; + D3DPOOL pool; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t mip_levels; + const PALETTEENTRY *palette; + + HRESULT expected_hr; + struct dds_pixel_format expected_pixel_format; + uint32_t expected_flags; + uint32_t expected_width; + uint32_t expected_height; + uint32_t expected_pitch; + uint32_t expected_depth; + uint32_t expected_mip_levels; + uint32_t expected_caps; + uint32_t expected_caps2; + uint32_t expected_buffer_size; + BOOL todo_hr; + BOOL todo_expected; + } dds_tests[] = + { + /* Paletted format tests. */ + { D3DRTYPE_TEXTURE, D3DFMT_P8, D3DPOOL_SCRATCH, 4, 4, 0, 3, test_palette, D3D_OK, + { 32, DDS_PF_INDEXED, 0, 8, 0, 0, 0, 0 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, + (DDSCAPS_TEXTURE | DDSCAPS_PALETTE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX), 0, PALETTED_DDS_FILE_HEADER_SIZE + 21, + }, + { D3DRTYPE_CUBETEXTURE, D3DFMT_P8, D3DPOOL_SCRATCH, 4, 0, 0, 3, test_palette, D3D_OK, + { 32, DDS_PF_INDEXED, 0, 8, 0, 0, 0, 0 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, + (DDSCAPS_TEXTURE | DDSCAPS_PALETTE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX), (DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES), + PALETTED_DDS_FILE_HEADER_SIZE + (126) + }, + { D3DRTYPE_VOLUMETEXTURE, D3DFMT_P8, D3DPOOL_SCRATCH, 4, 4, 4, 3, test_palette, D3D_OK, + { 32, DDS_PF_INDEXED, 0, 8, 0, 0, 0, 0 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT | DDSD_DEPTH), 4, 4, 0, 4, 3, + (DDSCAPS_TEXTURE | DDSCAPS_PALETTE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX), (DDSCAPS2_VOLUME), + PALETTED_DDS_FILE_HEADER_SIZE + 73 + }, + /* D3DFMT_A8R8G8B8 textures with multiple levels. */ + { D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 4, 0, 3, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, + (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX | DDSCAPS_ALPHA), 0, DDS_FILE_HEADER_SIZE + 84, + }, + { D3DRTYPE_CUBETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 0, 0, 3, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, + (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_ALPHA | DDSCAPS_COMPLEX), (DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES), + DDS_FILE_HEADER_SIZE + (504) + }, + /* + * Volume texture with D3DPOOL default. Can't be mapped for read, + * can't be saved. + */ + { D3DRTYPE_VOLUMETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 4, 4, 3, NULL, D3DERR_INVALIDCALL }, + /* D3DPOOL_SYSTEMMEM can be saved. */ + { D3DRTYPE_VOLUMETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, 4, 4, 4, 3, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_DEPTH | DDSD_MIPMAPCOUNT), 4, 4, 0, 4, 3, + (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_ALPHA | DDSCAPS_COMPLEX ), (DDSCAPS2_VOLUME), DDS_FILE_HEADER_SIZE + 292, + }, + /* Single mip level, no mip flags. */ + { D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 4, 0, 1, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), 4, 4, 0, 0, 0, + (DDSCAPS_TEXTURE | DDSCAPS_ALPHA), 0, DDS_FILE_HEADER_SIZE + 64, + }, + /* 8. */ + { D3DRTYPE_CUBETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 0, 0, 1, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), 4, 4, 0, 0, 0, + (DDSCAPS_TEXTURE | DDSCAPS_ALPHA | DDSCAPS_COMPLEX), (DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES), + DDS_FILE_HEADER_SIZE + (384) + }, + { D3DRTYPE_VOLUMETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, 4, 4, 4, 1, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_DEPTH), 4, 4, 0, 4, 0, + (DDSCAPS_TEXTURE | DDSCAPS_ALPHA), (DDSCAPS2_VOLUME), DDS_FILE_HEADER_SIZE + 256, + }, + /* Volume texture with a depth of 1. */ + { D3DRTYPE_VOLUMETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, 4, 4, 1, 1, NULL, D3D_OK, + { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, + (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), 4, 4, 0, 0, 0, + (DDSCAPS_TEXTURE | DDSCAPS_ALPHA), 0, DDS_FILE_HEADER_SIZE + 64, + }, + }; + struct + { + DWORD magic; + struct dds_header header; + BYTE *data; + } *dds; + IDirect3DVolumeTexture9 *volume_texture; + IDirect3DCubeTexture9 *cube_texture; + IDirect3DBaseTexture9 *save_tex; + IDirect3DTexture9 *texture; + ID3DXBuffer *buffer; + unsigned int i; + HRESULT hr; + + for (i = 0; i < ARRAY_SIZE(dds_tests); ++i) + { + winetest_push_context("Test %u", i); + + switch (dds_tests[i].type) + { + case D3DRTYPE_TEXTURE: + hr = IDirect3DDevice9_CreateTexture(device, dds_tests[i].width, dds_tests[i].height, dds_tests[i].mip_levels, 0, + dds_tests[i].format, dds_tests[i].pool, &texture, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + save_tex = (IDirect3DBaseTexture9 *)texture; + break; + + case D3DRTYPE_CUBETEXTURE: + hr = IDirect3DDevice9_CreateCubeTexture(device, dds_tests[i].width, dds_tests[i].mip_levels, 0, + dds_tests[i].format, dds_tests[i].pool, &cube_texture, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + save_tex = (IDirect3DBaseTexture9 *)cube_texture; + break; + + case D3DRTYPE_VOLUMETEXTURE: + hr = IDirect3DDevice9_CreateVolumeTexture(device, dds_tests[i].width, dds_tests[i].height, dds_tests[i].depth, + dds_tests[i].mip_levels, 0, dds_tests[i].format, dds_tests[i].pool, &volume_texture, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + save_tex = (IDirect3DBaseTexture9 *)volume_texture; + break; + + default: + assert(0); + break; + } + + hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, save_tex, dds_tests[i].palette); + todo_wine_if(dds_tests[i].todo_hr) ok(hr == dds_tests[i].expected_hr, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + ok(ID3DXBuffer_GetBufferSize(buffer) == dds_tests[i].expected_buffer_size, "Unexpected buffer size %lu.\n", + ID3DXBuffer_GetBufferSize(buffer)); + + dds = ID3DXBuffer_GetBufferPointer(buffer); + check_dds_header(&dds->header, dds_tests[i].expected_flags, dds_tests[i].expected_height, dds_tests[i].expected_width, + dds_tests[i].expected_pitch, dds_tests[i].expected_depth, dds_tests[i].expected_mip_levels, + &dds_tests[i].expected_pixel_format, dds_tests[i].expected_caps, dds_tests[i].expected_caps2, dds_tests[i].todo_expected); + ID3DXBuffer_Release(buffer); + } + + IDirect3DBaseTexture9_Release(save_tex); + winetest_pop_context(); + } +} + static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) { HRESULT hr; @@ -3136,24 +3289,20 @@ static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) } } - todo_wine { hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, (IDirect3DBaseTexture9 *)texture, NULL); ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); - if (SUCCEEDED(hr)) - { - buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); - buffer_size = ID3DXBuffer_GetBufferSize(buffer); - hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); - ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); - ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); - ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); - ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); - ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE); - ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); - ID3DXBuffer_Release(buffer); - } - } + buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); + buffer_size = ID3DXBuffer_GetBufferSize(buffer); + hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); + ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); + + ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); + ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); + ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); + ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE); + ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); + ID3DXBuffer_Release(buffer); IDirect3DTexture9_Release(texture); @@ -3208,24 +3357,20 @@ static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) ID3DXBuffer_Release(buffer); } - todo_wine { hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, (IDirect3DBaseTexture9 *)cube_texture, NULL); ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); - if (SUCCEEDED(hr)) - { - buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); - buffer_size = ID3DXBuffer_GetBufferSize(buffer); - hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); - ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); - ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); - ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); - ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); - ok(info.ResourceType == D3DRTYPE_CUBETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_CUBETEXTURE); - ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); - ID3DXBuffer_Release(buffer); - } - } + buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); + buffer_size = ID3DXBuffer_GetBufferSize(buffer); + hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); + ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); + + ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); + ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); + ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); + ok(info.ResourceType == D3DRTYPE_CUBETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_CUBETEXTURE); + ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); + ID3DXBuffer_Release(buffer); IDirect3DCubeTexture9_Release(cube_texture); @@ -3237,7 +3382,6 @@ static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) return; } - todo_wine { hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_BMP, (IDirect3DBaseTexture9 *)volume_texture, NULL); ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); if (SUCCEEDED(hr)) @@ -3258,24 +3402,22 @@ static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, (IDirect3DBaseTexture9 *)volume_texture, NULL); ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); - if (SUCCEEDED(hr)) - { - buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); - buffer_size = ID3DXBuffer_GetBufferSize(buffer); - hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); - ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); - ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); - ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); - ok(info.Depth == 256, "Got depth %u, expected %u\n", info.Depth, 256); - ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); - ok(info.ResourceType == D3DRTYPE_VOLUMETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_VOLUMETEXTURE); - ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); - ID3DXBuffer_Release(buffer); - } - } + buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); + buffer_size = ID3DXBuffer_GetBufferSize(buffer); + hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); + ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); + + ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); + ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); + ok(info.Depth == 256, "Got depth %u, expected %u\n", info.Depth, 256); + ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); + ok(info.ResourceType == D3DRTYPE_VOLUMETEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_VOLUMETEXTURE); + ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); + ID3DXBuffer_Release(buffer); IDirect3DVolumeTexture9_Release(volume_texture); + test_save_texture_to_dds_file(device); } static void test_texture_shader(void) diff --git a/dlls/d3dx9_36/tests/volume.c b/dlls/d3dx9_36/tests/volume.c index d7529eb486cd..d96473f935a6 100644 --- a/dlls/d3dx9_36/tests/volume.c +++ b/dlls/d3dx9_36/tests/volume.c @@ -392,6 +392,250 @@ static void test_D3DXLoadVolumeFromFileInMemory(IDirect3DDevice9 *device) IDirect3DVolumeTexture9_Release(volume_texture); } +static void set_vec3(D3DXVECTOR3 *v, float x, float y, float z) +{ + v->x = x; + v->y = y; + v->z = z; +} + +static const D3DXVECTOR4 quadrant_color[] = { + { 1.0f, 0.0f, 0.0f, 1.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, { 1.0f, 0.0f, 0.0f, 1.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, +}; + +static void WINAPI fill_func_volume(D3DXVECTOR4 *value, const D3DXVECTOR3 *texcoord, + const D3DXVECTOR3 *texelsize, void *data) +{ + D3DXVECTOR3 vec = *texcoord; + uint32_t idx; + + if (data) + { + *value = *(D3DXVECTOR4 *)data; + return; + } + + set_vec3(&vec, (vec.x / texelsize->x) - 0.5f, (vec.y / texelsize->y) - 0.5f, (vec.z / texelsize->z) - 0.5f); + if (vec.x < 8.0f) + idx = vec.y < 8.0f ? 0 : 2; + else + idx = vec.y < 8.0f ? 1 : 3; + idx += vec.z < 1.0f ? 0 : 4; + + *value = quadrant_color[idx]; +} + +static void test_d3dx_save_volume_to_file(IDirect3DDevice9 *device) +{ + static const struct + { + D3DXIMAGE_FILEFORMAT file_format; + const char *file_name_a; + const WCHAR *file_name_w; + D3DFORMAT save_format; + } save_files[] = { + { D3DXIFF_BMP, "saved_volume_a.bmp", L"saved_volume_w.bmp", D3DFMT_A8R8G8B8 }, + { D3DXIFF_JPG, "saved_volume_a.jpg", L"saved_volume_w.jpg", D3DFMT_X8R8G8B8 }, + { D3DXIFF_TGA, "saved_volume_a.tga", L"saved_volume_w.tga", D3DFMT_A8R8G8B8 }, + { D3DXIFF_PNG, "saved_volume_a.png", L"saved_volume_w.png", D3DFMT_A8R8G8B8 }, + { D3DXIFF_DIB, "saved_volume_a.dib", L"saved_volume_w.dib", D3DFMT_A8R8G8B8 }, + { D3DXIFF_DDS, "saved_volume_a.dds", L"saved_volume_w.dds", D3DFMT_A8R8G8B8 }, + }; + static const struct dds_pixel_format d3dfmt_a8r8g8b8_pf = { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, + 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; + struct + { + DWORD magic; + struct dds_header header; + BYTE *data; + } *dds; + static const uint32_t front_expected[] = { 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffffffff }; + static const uint32_t back_expected[] = { 0xffffffff, 0xff0000ff, 0xffff0000, 0xff00ff00 }; + static const uint32_t coords[][2] = { { 0, 0 }, { 15, 0 }, { 0, 15 }, { 15, 15 } }; + const D3DXVECTOR4 clear_val = { 0.0f, 0.0f, 0.0f, 0.0f }; + IDirect3DVolumeTexture9 *volume_texture; + struct volume_readback volume_rb; + ID3DXBuffer *buffer = NULL; + IDirect3DVolume9 *volume; + D3DXIMAGE_INFO info; + uint32_t i, j, k; + D3DBOX box; + HRESULT hr; + + hr = IDirect3DDevice9_CreateVolumeTexture(device, 16, 16, 2, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, + &volume_texture, NULL); + if (FAILED(hr)) + { + skip("Failed to create volume texture.\n"); + return; + } + + hr = D3DXFillVolumeTexture(volume_texture, fill_func_volume, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, 0, &volume); + + set_box(&box, 0, 0, 16, 16, 1, 2); + hr = D3DXSaveVolumeToFileInMemory(&buffer, D3DXIFF_DDS, volume, NULL, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + dds = ID3DXBuffer_GetBufferPointer(buffer); + check_dds_header(&dds->header, DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_DEPTH | DDSD_PIXELFORMAT, 16, 16, 0, + 2, 0, &d3dfmt_a8r8g8b8_pf, DDSCAPS_TEXTURE | DDSCAPS_ALPHA, DDSCAPS2_VOLUME, FALSE); + ID3DXBuffer_Release(buffer); + + /* + * Box only has a depth of 1, saves like a regular surface. E.g no depth + * flags/fields set. + */ + set_box(&box, 0, 0, 16, 16, 1, 2); + hr = D3DXSaveVolumeToFileInMemory(&buffer, D3DXIFF_DDS, volume, NULL, &box); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + dds = ID3DXBuffer_GetBufferPointer(buffer); + check_dds_header(&dds->header, DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT, 16, 16, 0, 0, 0, + &d3dfmt_a8r8g8b8_pf, DDSCAPS_TEXTURE | DDSCAPS_ALPHA, 0, FALSE); + ID3DXBuffer_Release(buffer); + + for (i = 0; i < ARRAY_SIZE(save_files); ++i) + { + winetest_push_context("Test %u", i); + + /* ASCII string. */ + for (j = 0; j < 2; ++j) + { + const uint32_t *expected_colors = !j ? front_expected : back_expected; + + hr = D3DXFillVolumeTexture(volume_texture, fill_func_volume, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXSaveVolumeToFileA(save_files[i].file_name_a, save_files[i].file_format, volume, NULL, !j ? NULL : &box); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXFillVolumeTexture(volume_texture, fill_func_volume, (void *)&clear_val); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + memset(&info, 0, sizeof(info)); + hr = D3DXLoadVolumeFromFileA(volume, NULL, NULL, save_files[i].file_name_a, NULL, D3DX_FILTER_NONE, 0, &info); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + get_texture_volume_readback(device, volume_texture, 0, &volume_rb); + if (save_files[i].file_format == D3DXIFF_DDS) + { + check_image_info(&info, 16, 16, !j ? 2 : 1, 1, save_files[i].save_format, !j ? D3DRTYPE_VOLUMETEXTURE : D3DRTYPE_TEXTURE, + D3DXIFF_DDS, FALSE); + for (k = 0; k < ARRAY_SIZE(coords); ++k) + check_volume_readback_pixel_4bpp_diff(&volume_rb, coords[k][0], coords[k][1], 0, expected_colors[k], 4, FALSE); + for (k = 0; k < ARRAY_SIZE(coords); ++k) + check_volume_readback_pixel_4bpp_diff(&volume_rb, coords[k][0], coords[k][1], 1, !j ? back_expected[k] : 0, 4, FALSE); + } + else + { + const D3DXIMAGE_FILEFORMAT iff = save_files[i].file_format == D3DXIFF_DIB ? D3DXIFF_BMP : save_files[i].file_format; + const uint8_t max_diff = iff == D3DXIFF_JPG ? 40 : 0; + + check_image_info(&info, 16, 16, 1, 1, save_files[i].save_format, D3DRTYPE_TEXTURE, iff, FALSE); + for (k = 0; k < ARRAY_SIZE(coords); ++k) + check_volume_readback_pixel_4bpp_diff(&volume_rb, coords[k][0], coords[k][1], 0, expected_colors[k], max_diff, FALSE); + } + release_volume_readback(&volume_rb); + + DeleteFileA(save_files[i].file_name_a); + } + + /* Wide string. */ + for (j = 0; j < 2; ++j) + { + const uint32_t *expected_colors = !j ? front_expected : back_expected; + + hr = D3DXFillVolumeTexture(volume_texture, fill_func_volume, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXSaveVolumeToFileW(save_files[i].file_name_w, save_files[i].file_format, volume, NULL, !j ? NULL : &box); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXFillVolumeTexture(volume_texture, fill_func_volume, (void *)&clear_val); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + memset(&info, 0, sizeof(info)); + hr = D3DXLoadVolumeFromFileW(volume, NULL, NULL, save_files[i].file_name_w, NULL, D3DX_FILTER_NONE, 0, &info); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + get_texture_volume_readback(device, volume_texture, 0, &volume_rb); + if (save_files[i].file_format == D3DXIFF_DDS) + { + check_image_info(&info, 16, 16, !j ? 2 : 1, 1, save_files[i].save_format, !j ? D3DRTYPE_VOLUMETEXTURE : D3DRTYPE_TEXTURE, + D3DXIFF_DDS, FALSE); + for (k = 0; k < ARRAY_SIZE(coords); ++k) + check_volume_readback_pixel_4bpp_diff(&volume_rb, coords[k][0], coords[k][1], 0, expected_colors[k], 0, FALSE); + for (k = 0; k < ARRAY_SIZE(coords); ++k) + check_volume_readback_pixel_4bpp_diff(&volume_rb, coords[k][0], coords[k][1], 1, !j ? back_expected[k] : 0, 0, FALSE); + } + else + { + const D3DXIMAGE_FILEFORMAT iff = save_files[i].file_format == D3DXIFF_DIB ? D3DXIFF_BMP : save_files[i].file_format; + const uint8_t max_diff = iff == D3DXIFF_JPG ? 40 : 0; + + check_image_info(&info, 16, 16, 1, 1, save_files[i].save_format, D3DRTYPE_TEXTURE, iff, FALSE); + for (k = 0; k < ARRAY_SIZE(coords); ++k) + check_volume_readback_pixel_4bpp_diff(&volume_rb, coords[k][0], coords[k][1], 0, expected_colors[k], max_diff, FALSE); + } + release_volume_readback(&volume_rb); + + DeleteFileW(save_files[i].file_name_w); + } + + /* InMemory. */ + for (j = 0; j < 2; ++j) + { + const uint32_t *expected_colors = !j ? front_expected : back_expected; + ID3DXBuffer *buffer = NULL; + + hr = D3DXFillVolumeTexture(volume_texture, fill_func_volume, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXSaveVolumeToFileInMemory(&buffer, save_files[i].file_format, volume, NULL, !j ? NULL : &box); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXFillVolumeTexture(volume_texture, fill_func_volume, (void *)&clear_val); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + memset(&info, 0, sizeof(info)); + hr = D3DXLoadVolumeFromFileInMemory(volume, NULL, NULL, ID3DXBuffer_GetBufferPointer(buffer), + ID3DXBuffer_GetBufferSize(buffer), NULL, D3DX_FILTER_NONE, 0, &info); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + ID3DXBuffer_Release(buffer); + + get_texture_volume_readback(device, volume_texture, 0, &volume_rb); + if (save_files[i].file_format == D3DXIFF_DDS) + { + check_image_info(&info, 16, 16, !j ? 2 : 1, 1, save_files[i].save_format, !j ? D3DRTYPE_VOLUMETEXTURE : D3DRTYPE_TEXTURE, + D3DXIFF_DDS, FALSE); + for (k = 0; k < ARRAY_SIZE(coords); ++k) + check_volume_readback_pixel_4bpp_diff(&volume_rb, coords[k][0], coords[k][1], 0, expected_colors[k], 4, FALSE); + for (k = 0; k < ARRAY_SIZE(coords); ++k) + check_volume_readback_pixel_4bpp_diff(&volume_rb, coords[k][0], coords[k][1], 1, !j ? back_expected[k] : 0, 4, FALSE); + } + else + { + const D3DXIMAGE_FILEFORMAT iff = save_files[i].file_format == D3DXIFF_DIB ? D3DXIFF_BMP : save_files[i].file_format; + const uint8_t max_diff = iff == D3DXIFF_JPG ? 40 : 0; + + check_image_info(&info, 16, 16, 1, 1, save_files[i].save_format, D3DRTYPE_TEXTURE, iff, FALSE); + for (k = 0; k < ARRAY_SIZE(coords); ++k) + check_volume_readback_pixel_4bpp_diff(&volume_rb, coords[k][0], coords[k][1], 0, expected_colors[k], max_diff, FALSE); + } + release_volume_readback(&volume_rb); + } + + winetest_pop_context(); + } + + IDirect3DVolume9_Release(volume); + IDirect3DVolumeTexture9_Release(volume_texture); +} + START_TEST(volume) { HWND wnd; @@ -428,6 +672,7 @@ START_TEST(volume) test_D3DXLoadVolumeFromMemory(device); test_D3DXLoadVolumeFromFileInMemory(device); + test_d3dx_save_volume_to_file(device); IDirect3DDevice9_Release(device); IDirect3D9_Release(d3d); diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index 719a2787445b..e0ec927a779f 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -59,7 +59,7 @@ HRESULT WINAPI D3DXFilterTexture(IDirect3DBaseTexture9 *texture, if (!texture) return D3DERR_INVALIDCALL; - if (filter != D3DX_DEFAULT && FAILED(hr = d3dx9_validate_filter(filter))) + if (filter != D3DX_DEFAULT && FAILED(hr = d3dx_validate_filter(filter))) return hr; if (srclevel == D3DX_DEFAULT) @@ -567,7 +567,7 @@ static D3DFORMAT get_alpha_replacement_format(D3DFORMAT format) static uint32_t d3dx9_get_mip_filter_value(uint32_t mip_filter, uint32_t *skip_levels) { - uint32_t filter = (mip_filter == D3DX_DEFAULT) ? D3DX_FILTER_BOX : mip_filter & ~D3DX9_FILTER_INVALID_BITS; + uint32_t filter = (mip_filter == D3DX_DEFAULT) ? D3DX_FILTER_BOX : mip_filter & ~D3DX_FILTER_INVALID_BITS; *skip_levels = mip_filter != D3DX_DEFAULT ? mip_filter >> D3DX_SKIP_DDS_MIP_LEVELS_SHIFT : 0; *skip_levels &= D3DX_SKIP_DDS_MIP_LEVELS_MASK; @@ -1856,40 +1856,204 @@ HRESULT WINAPI D3DXSaveTextureToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format, IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette) { - HRESULT hr; + const struct pixel_format_desc *fmt_desc = NULL; + struct d3dx_image image = { 0 }; + ID3DXBuffer *buffer = NULL; + uint32_t mip_levels, i, j; D3DRESOURCETYPE type; - IDirect3DSurface9 *surface; + struct volume size; + HRESULT hr; TRACE("dst_buffer %p, file_format %u, src_texture %p, src_palette %p.\n", dst_buffer, file_format, src_texture, src_palette); - if (!dst_buffer || !src_texture) return D3DERR_INVALIDCALL; + if (!dst_buffer || !src_texture || file_format > D3DXIFF_PFM) + return D3DERR_INVALIDCALL; - if (file_format == D3DXIFF_DDS) + type = IDirect3DBaseTexture9_GetType(src_texture); + if (type < D3DRTYPE_TEXTURE || type > D3DRTYPE_CUBETEXTURE) + return D3DERR_INVALIDCALL; + + if (file_format != D3DXIFF_DDS) { - FIXME("DDS file format isn't supported yet\n"); - return E_NOTIMPL; + if (type == D3DRTYPE_VOLUMETEXTURE) + { + IDirect3DVolume9 *volume; + + hr = IDirect3DVolumeTexture9_GetVolumeLevel((IDirect3DVolumeTexture9 *)src_texture, 0, &volume); + if (SUCCEEDED(hr)) + { + hr = D3DXSaveVolumeToFileInMemory(dst_buffer, file_format, volume, src_palette, NULL); + IDirect3DVolume9_Release(volume); + } + } + else + { + IDirect3DSurface9 *surface; + + hr = get_surface(type, src_texture, D3DCUBEMAP_FACE_POSITIVE_X, 0, &surface); + if (SUCCEEDED(hr)) + { + hr = D3DXSaveSurfaceToFileInMemory(dst_buffer, file_format, surface, src_palette, NULL); + IDirect3DSurface9_Release(surface); + } + } + + return hr; } - type = IDirect3DBaseTexture9_GetType(src_texture); + mip_levels = IDirect3DBaseTexture9_GetLevelCount(src_texture); switch (type) { case D3DRTYPE_TEXTURE: + { + IDirect3DTexture9 *texture = (IDirect3DTexture9 *)src_texture; + D3DSURFACE_DESC desc; + + hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc); + if (FAILED(hr)) + break; + + fmt_desc = get_format_info(desc.Format); + if (is_unknown_format(fmt_desc)) + return E_NOTIMPL; + + set_volume_struct(&size, desc.Width, desc.Height, 1); + break; + } + case D3DRTYPE_CUBETEXTURE: - hr = get_surface(type, src_texture, D3DCUBEMAP_FACE_POSITIVE_X, 0, &surface); + { + IDirect3DCubeTexture9 *texture = (IDirect3DCubeTexture9 *)src_texture; + D3DSURFACE_DESC desc; + + hr = IDirect3DCubeTexture9_GetLevelDesc(texture, 0, &desc); + if (FAILED(hr)) + break; + + fmt_desc = get_format_info(desc.Format); + if (is_unknown_format(fmt_desc)) + return E_NOTIMPL; + + set_volume_struct(&size, desc.Width, desc.Height, 1); break; + } + case D3DRTYPE_VOLUMETEXTURE: - FIXME("Volume textures aren't supported yet\n"); - return E_NOTIMPL; + { + IDirect3DVolumeTexture9 *texture = (IDirect3DVolumeTexture9 *)src_texture; + D3DVOLUME_DESC desc; + + hr = IDirect3DVolumeTexture9_GetLevelDesc(texture, 0, &desc); + if (FAILED(hr)) + break; + + fmt_desc = get_format_info(desc.Format); + if (is_unknown_format(fmt_desc)) + return E_NOTIMPL; + + set_volume_struct(&size, desc.Width, desc.Height, desc.Depth); + break; + } + default: - return D3DERR_INVALIDCALL; + assert(0); /* Should not happen. */ + return E_FAIL; } - if (SUCCEEDED(hr)) + if (is_index_format(fmt_desc) && !src_palette) + return E_NOTIMPL; + + hr = d3dx_create_dds_file_blob(fmt_desc->format, src_palette, d3dx_resource_type_from_d3dresourcetype(type), + &size, mip_levels, type == D3DRTYPE_CUBETEXTURE ? 6 : 1, FALSE, &buffer); + if (FAILED(hr)) + goto exit; + + hr = d3dx_image_init(ID3DXBuffer_GetBufferPointer(buffer), ID3DXBuffer_GetBufferSize(buffer), &image, 0, 0); + if (FAILED(hr)) + goto exit; + + /* So now, things are setup to do inverse of CreateTexture. */ + if (type != D3DRTYPE_VOLUMETEXTURE) { - hr = D3DXSaveSurfaceToFileInMemory(dst_buffer, file_format, surface, src_palette, NULL); - IDirect3DSurface9_Release(surface); + for (j = 0; j < image.layer_count; ++j) + { + for (i = 0; i < mip_levels; ++i) + { + IDirect3DSurface9 *src_surface, *tmp_surface; + struct d3dx_pixels src_pixels, dst_pixels; + D3DSURFACE_DESC src_surface_desc; + D3DLOCKED_RECT src_locked_rect; + RECT src_rect; + + hr = d3dx_image_get_pixels(&image, j, i, &dst_pixels); + if (FAILED(hr)) + break; + + hr = get_surface(type, src_texture, j, i, &src_surface); + if (FAILED(hr)) + break; + + hr = lock_surface(src_surface, NULL, &src_locked_rect, &tmp_surface, FALSE); + if (FAILED(hr)) + break; + + IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc); + SetRect(&src_rect, 0, 0, src_surface_desc.Width, src_surface_desc.Height); + set_d3dx_pixels(&src_pixels, src_locked_rect.pBits, src_locked_rect.Pitch, 0, src_palette, + src_surface_desc.Width, src_surface_desc.Height, 1, &src_rect); + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, fmt_desc, D3DX_FILTER_NONE, 0); + if (FAILED(hr)) + { + unlock_surface(src_surface, NULL, tmp_surface, FALSE); + IDirect3DSurface9_Release(src_surface); + break; + } + + hr = unlock_surface(src_surface, NULL, tmp_surface, FALSE); + IDirect3DSurface9_Release(src_surface); + if (FAILED(hr)) + break; + } + } } + else + { + IDirect3DVolumeTexture9 *volume_tex = (IDirect3DVolumeTexture9 *)src_texture; + + for (i = 0; i < mip_levels; ++i) + { + struct d3dx_pixels src_pixels, dst_pixels; + D3DVOLUME_DESC src_volume_desc; + D3DLOCKED_BOX src_locked_box; + RECT src_rect; + + hr = d3dx_image_get_pixels(&image, 0, i, &dst_pixels); + if (FAILED(hr)) + break; + + hr = IDirect3DVolumeTexture9_LockBox(volume_tex, i, &src_locked_box, NULL, D3DLOCK_READONLY); + if (FAILED(hr)) + break; + + IDirect3DVolumeTexture9_GetLevelDesc(volume_tex, i, &src_volume_desc); + SetRect(&src_rect, 0, 0, src_volume_desc.Width, src_volume_desc.Height); + set_d3dx_pixels(&src_pixels, src_locked_box.pBits, src_locked_box.RowPitch, src_locked_box.SlicePitch, + src_palette, src_volume_desc.Width, src_volume_desc.Height, src_volume_desc.Depth, &src_rect); + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, fmt_desc, D3DX_FILTER_NONE, 0); + IDirect3DVolumeTexture9_UnlockBox(volume_tex, i); + if (FAILED(hr)) + break; + } + } + + *dst_buffer = buffer; + +exit: + if (buffer && (buffer != *dst_buffer)) + ID3DXBuffer_Release(buffer); return hr; } diff --git a/dlls/d3dx9_36/txc_compress_dxtn.c b/dlls/d3dx9_36/txc_compress_dxtn.c deleted file mode 100644 index 7f10de8076b1..000000000000 --- a/dlls/d3dx9_36/txc_compress_dxtn.c +++ /dev/null @@ -1,841 +0,0 @@ -/* - * libtxc_dxtn - * Version: 1.0 - * - * Copyright (C) 2004 Roland Scheidegger All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include "txc_dxtn.h" - -/* weights used for error function, basically weights (unsquared 2/4/1) according to rgb->luminance conversion - not sure if this really reflects visual perception */ -#define REDWEIGHT 4 -#define GREENWEIGHT 16 -#define BLUEWEIGHT 1 - -#define ALPHACUT 127 - -static void fancybasecolorsearch( GLubyte *blkaddr, GLubyte srccolors[4][4][4], GLubyte *bestcolor[2], - GLint numxpixels, GLint numypixels, GLint type, GLboolean haveAlpha) -{ - /* use same luminance-weighted distance metric to determine encoding as for finding the base colors */ - - /* TODO could also try to find a better encoding for the 3-color-encoding type, this really should be done - if it's rgba_dxt1 and we have alpha in the block, currently even values which will be mapped to black - due to their alpha value will influence the result */ - GLint i, j, colors, z; - GLuint pixerror, pixerrorred, pixerrorgreen, pixerrorblue, pixerrorbest; - GLint colordist, blockerrlin[2][3]; - GLubyte nrcolor[2]; - GLint pixerrorcolorbest[3]; - GLubyte enc = 0; - GLubyte cv[4][4]; - GLubyte testcolor[2][3]; - -/* fprintf(stderr, "color begin 0 r/g/b %d/%d/%d, 1 r/g/b %d/%d/%d\n", - bestcolor[0][0], bestcolor[0][1], bestcolor[0][2], bestcolor[1][0], bestcolor[1][1], bestcolor[1][2]);*/ - if (((bestcolor[0][0] & 0xf8) << 8 | (bestcolor[0][1] & 0xfc) << 3 | bestcolor[0][2] >> 3) < - ((bestcolor[1][0] & 0xf8) << 8 | (bestcolor[1][1] & 0xfc) << 3 | bestcolor[1][2] >> 3)) { - testcolor[0][0] = bestcolor[0][0]; - testcolor[0][1] = bestcolor[0][1]; - testcolor[0][2] = bestcolor[0][2]; - testcolor[1][0] = bestcolor[1][0]; - testcolor[1][1] = bestcolor[1][1]; - testcolor[1][2] = bestcolor[1][2]; - } - else { - testcolor[1][0] = bestcolor[0][0]; - testcolor[1][1] = bestcolor[0][1]; - testcolor[1][2] = bestcolor[0][2]; - testcolor[0][0] = bestcolor[1][0]; - testcolor[0][1] = bestcolor[1][1]; - testcolor[0][2] = bestcolor[1][2]; - } - - for (i = 0; i < 3; i ++) { - cv[0][i] = testcolor[0][i]; - cv[1][i] = testcolor[1][i]; - cv[2][i] = (testcolor[0][i] * 2 + testcolor[1][i]) / 3; - cv[3][i] = (testcolor[0][i] + testcolor[1][i] * 2) / 3; - } - - blockerrlin[0][0] = 0; - blockerrlin[0][1] = 0; - blockerrlin[0][2] = 0; - blockerrlin[1][0] = 0; - blockerrlin[1][1] = 0; - blockerrlin[1][2] = 0; - - nrcolor[0] = 0; - nrcolor[1] = 0; - - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - pixerrorbest = 0xffffffff; - for (colors = 0; colors < 4; colors++) { - colordist = srccolors[j][i][0] - (cv[colors][0]); - pixerror = colordist * colordist * REDWEIGHT; - pixerrorred = colordist; - colordist = srccolors[j][i][1] - (cv[colors][1]); - pixerror += colordist * colordist * GREENWEIGHT; - pixerrorgreen = colordist; - colordist = srccolors[j][i][2] - (cv[colors][2]); - pixerror += colordist * colordist * BLUEWEIGHT; - pixerrorblue = colordist; - if (pixerror < pixerrorbest) { - enc = colors; - pixerrorbest = pixerror; - pixerrorcolorbest[0] = pixerrorred; - pixerrorcolorbest[1] = pixerrorgreen; - pixerrorcolorbest[2] = pixerrorblue; - } - } - if (enc == 0) { - for (z = 0; z < 3; z++) { - blockerrlin[0][z] += 3 * pixerrorcolorbest[z]; - } - nrcolor[0] += 3; - } - else if (enc == 2) { - for (z = 0; z < 3; z++) { - blockerrlin[0][z] += 2 * pixerrorcolorbest[z]; - } - nrcolor[0] += 2; - for (z = 0; z < 3; z++) { - blockerrlin[1][z] += 1 * pixerrorcolorbest[z]; - } - nrcolor[1] += 1; - } - else if (enc == 3) { - for (z = 0; z < 3; z++) { - blockerrlin[0][z] += 1 * pixerrorcolorbest[z]; - } - nrcolor[0] += 1; - for (z = 0; z < 3; z++) { - blockerrlin[1][z] += 2 * pixerrorcolorbest[z]; - } - nrcolor[1] += 2; - } - else if (enc == 1) { - for (z = 0; z < 3; z++) { - blockerrlin[1][z] += 3 * pixerrorcolorbest[z]; - } - nrcolor[1] += 3; - } - } - } - if (nrcolor[0] == 0) nrcolor[0] = 1; - if (nrcolor[1] == 0) nrcolor[1] = 1; - for (j = 0; j < 2; j++) { - for (i = 0; i < 3; i++) { - GLint newvalue = testcolor[j][i] + blockerrlin[j][i] / nrcolor[j]; - if (newvalue <= 0) - testcolor[j][i] = 0; - else if (newvalue >= 255) - testcolor[j][i] = 255; - else testcolor[j][i] = newvalue; - } - } - - if ((abs(testcolor[0][0] - testcolor[1][0]) < 8) && - (abs(testcolor[0][1] - testcolor[1][1]) < 4) && - (abs(testcolor[0][2] - testcolor[1][2]) < 8)) { - /* both colors are so close they might get encoded as the same 16bit values */ - GLubyte coldiffred, coldiffgreen, coldiffblue, coldiffmax, factor, ind0, ind1; - - coldiffred = abs(testcolor[0][0] - testcolor[1][0]); - coldiffgreen = 2 * abs(testcolor[0][1] - testcolor[1][1]); - coldiffblue = abs(testcolor[0][2] - testcolor[1][2]); - coldiffmax = coldiffred; - if (coldiffmax < coldiffgreen) coldiffmax = coldiffgreen; - if (coldiffmax < coldiffblue) coldiffmax = coldiffblue; - if (coldiffmax > 0) { - if (coldiffmax > 4) factor = 2; - else if (coldiffmax > 2) factor = 3; - else factor = 4; - /* Won't do much if the color value is near 255... */ - /* argh so many ifs */ - if (testcolor[1][1] >= testcolor[0][1]) { - ind1 = 1; ind0 = 0; - } - else { - ind1 = 0; ind0 = 1; - } - if ((testcolor[ind1][1] + factor * coldiffgreen) <= 255) - testcolor[ind1][1] += factor * coldiffgreen; - else testcolor[ind1][1] = 255; - if ((testcolor[ind1][0] - testcolor[ind0][1]) > 0) { - if ((testcolor[ind1][0] + factor * coldiffred) <= 255) - testcolor[ind1][0] += factor * coldiffred; - else testcolor[ind1][0] = 255; - } - else { - if ((testcolor[ind0][0] + factor * coldiffred) <= 255) - testcolor[ind0][0] += factor * coldiffred; - else testcolor[ind0][0] = 255; - } - if ((testcolor[ind1][2] - testcolor[ind0][2]) > 0) { - if ((testcolor[ind1][2] + factor * coldiffblue) <= 255) - testcolor[ind1][2] += factor * coldiffblue; - else testcolor[ind1][2] = 255; - } - else { - if ((testcolor[ind0][2] + factor * coldiffblue) <= 255) - testcolor[ind0][2] += factor * coldiffblue; - else testcolor[ind0][2] = 255; - } - } - } - - if (((testcolor[0][0] & 0xf8) << 8 | (testcolor[0][1] & 0xfc) << 3 | testcolor[0][2] >> 3) < - ((testcolor[1][0] & 0xf8) << 8 | (testcolor[1][1] & 0xfc) << 3 | testcolor[1][2]) >> 3) { - for (i = 0; i < 3; i++) { - bestcolor[0][i] = testcolor[0][i]; - bestcolor[1][i] = testcolor[1][i]; - } - } - else { - for (i = 0; i < 3; i++) { - bestcolor[0][i] = testcolor[1][i]; - bestcolor[1][i] = testcolor[0][i]; - } - } - -/* fprintf(stderr, "color end 0 r/g/b %d/%d/%d, 1 r/g/b %d/%d/%d\n", - bestcolor[0][0], bestcolor[0][1], bestcolor[0][2], bestcolor[1][0], bestcolor[1][1], bestcolor[1][2]);*/ -} - - - -static void storedxtencodedblock( GLubyte *blkaddr, GLubyte srccolors[4][4][4], GLubyte *bestcolor[2], - GLint numxpixels, GLint numypixels, GLuint type, GLboolean haveAlpha) -{ - /* use same luminance-weighted distance metric to determine encoding as for finding the base colors */ - - GLint i, j, colors; - GLuint testerror, testerror2, pixerror, pixerrorbest; - GLint colordist; - GLushort color0, color1, tempcolor; - GLuint bits = 0, bits2 = 0; - GLubyte *colorptr; - GLubyte enc = 0; - GLubyte cv[4][4]; - - bestcolor[0][0] = bestcolor[0][0] & 0xf8; - bestcolor[0][1] = bestcolor[0][1] & 0xfc; - bestcolor[0][2] = bestcolor[0][2] & 0xf8; - bestcolor[1][0] = bestcolor[1][0] & 0xf8; - bestcolor[1][1] = bestcolor[1][1] & 0xfc; - bestcolor[1][2] = bestcolor[1][2] & 0xf8; - - color0 = bestcolor[0][0] << 8 | bestcolor[0][1] << 3 | bestcolor[0][2] >> 3; - color1 = bestcolor[1][0] << 8 | bestcolor[1][1] << 3 | bestcolor[1][2] >> 3; - if (color0 < color1) { - tempcolor = color0; color0 = color1; color1 = tempcolor; - colorptr = bestcolor[0]; bestcolor[0] = bestcolor[1]; bestcolor[1] = colorptr; - } - - - for (i = 0; i < 3; i++) { - cv[0][i] = bestcolor[0][i]; - cv[1][i] = bestcolor[1][i]; - cv[2][i] = (bestcolor[0][i] * 2 + bestcolor[1][i]) / 3; - cv[3][i] = (bestcolor[0][i] + bestcolor[1][i] * 2) / 3; - } - - testerror = 0; - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - pixerrorbest = 0xffffffff; - for (colors = 0; colors < 4; colors++) { - colordist = srccolors[j][i][0] - cv[colors][0]; - pixerror = colordist * colordist * REDWEIGHT; - colordist = srccolors[j][i][1] - cv[colors][1]; - pixerror += colordist * colordist * GREENWEIGHT; - colordist = srccolors[j][i][2] - cv[colors][2]; - pixerror += colordist * colordist * BLUEWEIGHT; - if (pixerror < pixerrorbest) { - pixerrorbest = pixerror; - enc = colors; - } - } - testerror += pixerrorbest; - bits |= enc << (2 * (j * 4 + i)); - } - } - /* some hw might disagree but actually decoding should always use 4-color encoding - for non-dxt1 formats */ - if (type == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || type == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) { - for (i = 0; i < 3; i++) { - cv[2][i] = (bestcolor[0][i] + bestcolor[1][i]) / 2; - /* this isn't used. Looks like the black color constant can only be used - with RGB_DXT1 if I read the spec correctly (note though that the radeon gpu disagrees, - it will decode 3 to black even with DXT3/5), and due to how the color searching works - it won't get used even then */ - cv[3][i] = 0; - } - testerror2 = 0; - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - pixerrorbest = 0xffffffff; - if ((type == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) && (srccolors[j][i][3] <= ALPHACUT)) { - enc = 3; - pixerrorbest = 0; /* don't calculate error */ - } - else { - /* we're calculating the same what we have done already for colors 0-1 above... */ - for (colors = 0; colors < 3; colors++) { - colordist = srccolors[j][i][0] - cv[colors][0]; - pixerror = colordist * colordist * REDWEIGHT; - colordist = srccolors[j][i][1] - cv[colors][1]; - pixerror += colordist * colordist * GREENWEIGHT; - colordist = srccolors[j][i][2] - cv[colors][2]; - pixerror += colordist * colordist * BLUEWEIGHT; - if (pixerror < pixerrorbest) { - pixerrorbest = pixerror; - /* need to exchange colors later */ - if (colors > 1) enc = colors; - else enc = colors ^ 1; - } - } - } - testerror2 += pixerrorbest; - bits2 |= enc << (2 * (j * 4 + i)); - } - } - } else { - testerror2 = 0xffffffff; - } - - /* finally we're finished, write back colors and bits */ - if ((testerror > testerror2) || (haveAlpha)) { - *blkaddr++ = color1 & 0xff; - *blkaddr++ = color1 >> 8; - *blkaddr++ = color0 & 0xff; - *blkaddr++ = color0 >> 8; - *blkaddr++ = bits2 & 0xff; - *blkaddr++ = ( bits2 >> 8) & 0xff; - *blkaddr++ = ( bits2 >> 16) & 0xff; - *blkaddr = bits2 >> 24; - } - else { - *blkaddr++ = color0 & 0xff; - *blkaddr++ = color0 >> 8; - *blkaddr++ = color1 & 0xff; - *blkaddr++ = color1 >> 8; - *blkaddr++ = bits & 0xff; - *blkaddr++ = ( bits >> 8) & 0xff; - *blkaddr++ = ( bits >> 16) & 0xff; - *blkaddr = bits >> 24; - } -} - -static void encodedxtcolorblockfaster( GLubyte *blkaddr, GLubyte srccolors[4][4][4], - GLint numxpixels, GLint numypixels, GLuint type ) -{ -/* simplistic approach. We need two base colors, simply use the "highest" and the "lowest" color - present in the picture as base colors */ - - /* define lowest and highest color as shortest and longest vector to 0/0/0, though the - vectors are weighted similar to their importance in rgb-luminance conversion - doesn't work too well though... - This seems to be a rather difficult problem */ - - GLubyte *bestcolor[2]; - GLubyte basecolors[2][3]; - GLubyte i, j; - GLuint lowcv, highcv, testcv; - GLboolean haveAlpha = GL_FALSE; - - lowcv = highcv = srccolors[0][0][0] * srccolors[0][0][0] * REDWEIGHT + - srccolors[0][0][1] * srccolors[0][0][1] * GREENWEIGHT + - srccolors[0][0][2] * srccolors[0][0][2] * BLUEWEIGHT; - bestcolor[0] = bestcolor[1] = srccolors[0][0]; - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* don't use this as a base color if the pixel will get black/transparent anyway */ - if ((type != GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) || (srccolors[j][i][3] > ALPHACUT)) { - testcv = srccolors[j][i][0] * srccolors[j][i][0] * REDWEIGHT + - srccolors[j][i][1] * srccolors[j][i][1] * GREENWEIGHT + - srccolors[j][i][2] * srccolors[j][i][2] * BLUEWEIGHT; - if (testcv > highcv) { - highcv = testcv; - bestcolor[1] = srccolors[j][i]; - } - else if (testcv < lowcv) { - lowcv = testcv; - bestcolor[0] = srccolors[j][i]; - } - } - else haveAlpha = GL_TRUE; - } - } - /* make sure the original color values won't get touched... */ - for (j = 0; j < 2; j++) { - for (i = 0; i < 3; i++) { - basecolors[j][i] = bestcolor[j][i]; - } - } - bestcolor[0] = basecolors[0]; - bestcolor[1] = basecolors[1]; - - /* try to find better base colors */ - fancybasecolorsearch(blkaddr, srccolors, bestcolor, numxpixels, numypixels, type, haveAlpha); - /* find the best encoding for these colors, and store the result */ - storedxtencodedblock(blkaddr, srccolors, bestcolor, numxpixels, numypixels, type, haveAlpha); -} - -static void writedxt5encodedalphablock( GLubyte *blkaddr, GLubyte alphabase1, GLubyte alphabase2, - GLubyte alphaenc[16]) -{ - *blkaddr++ = alphabase1; - *blkaddr++ = alphabase2; - *blkaddr++ = alphaenc[0] | (alphaenc[1] << 3) | ((alphaenc[2] & 3) << 6); - *blkaddr++ = (alphaenc[2] >> 2) | (alphaenc[3] << 1) | (alphaenc[4] << 4) | ((alphaenc[5] & 1) << 7); - *blkaddr++ = (alphaenc[5] >> 1) | (alphaenc[6] << 2) | (alphaenc[7] << 5); - *blkaddr++ = alphaenc[8] | (alphaenc[9] << 3) | ((alphaenc[10] & 3) << 6); - *blkaddr++ = (alphaenc[10] >> 2) | (alphaenc[11] << 1) | (alphaenc[12] << 4) | ((alphaenc[13] & 1) << 7); - *blkaddr++ = (alphaenc[13] >> 1) | (alphaenc[14] << 2) | (alphaenc[15] << 5); -} - -static void encodedxt5alpha(GLubyte *blkaddr, GLubyte srccolors[4][4][4], - GLint numxpixels, GLint numypixels) -{ - GLubyte alphabase[2], alphause[2]; - GLshort alphatest[2]; - GLuint alphablockerror1, alphablockerror2, alphablockerror3; - GLubyte i, j, aindex, acutValues[7]; - GLubyte alphaenc1[16], alphaenc2[16], alphaenc3[16]; - GLboolean alphaabsmin = GL_FALSE; - GLboolean alphaabsmax = GL_FALSE; - GLshort alphadist; - - /* find lowest and highest alpha value in block, alphabase[0] lowest, alphabase[1] highest */ - alphabase[0] = 0xff; alphabase[1] = 0x0; - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if (srccolors[j][i][3] == 0) - alphaabsmin = GL_TRUE; - else if (srccolors[j][i][3] == 255) - alphaabsmax = GL_TRUE; - else { - if (srccolors[j][i][3] > alphabase[1]) - alphabase[1] = srccolors[j][i][3]; - if (srccolors[j][i][3] < alphabase[0]) - alphabase[0] = srccolors[j][i][3]; - } - } - } - - - if ((alphabase[0] > alphabase[1]) && !(alphaabsmin && alphaabsmax)) { /* one color, either max or min */ - /* shortcut here since it is a very common case (and also avoids later problems) */ - /* || (alphabase[0] == alphabase[1] && !alphaabsmin && !alphaabsmax) */ - /* could also test for alpha0 == alpha1 (and not min/max), but probably not common, so don't bother */ - - *blkaddr++ = srccolors[0][0][3]; - blkaddr++; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; - *blkaddr++ = 0; -/* fprintf(stderr, "enc0 used\n");*/ - return; - } - - /* find best encoding for alpha0 > alpha1 */ - /* it's possible this encoding is better even if both alphaabsmin and alphaabsmax are true */ - alphablockerror1 = 0x0; - alphablockerror2 = 0xffffffff; - alphablockerror3 = 0xffffffff; - if (alphaabsmin) alphause[0] = 0; - else alphause[0] = alphabase[0]; - if (alphaabsmax) alphause[1] = 255; - else alphause[1] = alphabase[1]; - /* calculate the 7 cut values, just the middle between 2 of the computed alpha values */ - for (aindex = 0; aindex < 7; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphause[0] * (2*aindex + 1) + alphause[1] * (14 - (2*aindex + 1))) / 14; - } - - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i][3] > acutValues[0]) { - alphaenc1[4*j + i] = 0; - alphadist = srccolors[j][i][3] - alphause[1]; - } - else if (srccolors[j][i][3] > acutValues[1]) { - alphaenc1[4*j + i] = 2; - alphadist = srccolors[j][i][3] - (alphause[1] * 6 + alphause[0] * 1) / 7; - } - else if (srccolors[j][i][3] > acutValues[2]) { - alphaenc1[4*j + i] = 3; - alphadist = srccolors[j][i][3] - (alphause[1] * 5 + alphause[0] * 2) / 7; - } - else if (srccolors[j][i][3] > acutValues[3]) { - alphaenc1[4*j + i] = 4; - alphadist = srccolors[j][i][3] - (alphause[1] * 4 + alphause[0] * 3) / 7; - } - else if (srccolors[j][i][3] > acutValues[4]) { - alphaenc1[4*j + i] = 5; - alphadist = srccolors[j][i][3] - (alphause[1] * 3 + alphause[0] * 4) / 7; - } - else if (srccolors[j][i][3] > acutValues[5]) { - alphaenc1[4*j + i] = 6; - alphadist = srccolors[j][i][3] - (alphause[1] * 2 + alphause[0] * 5) / 7; - } - else if (srccolors[j][i][3] > acutValues[6]) { - alphaenc1[4*j + i] = 7; - alphadist = srccolors[j][i][3] - (alphause[1] * 1 + alphause[0] * 6) / 7; - } - else { - alphaenc1[4*j + i] = 1; - alphadist = srccolors[j][i][3] - alphause[0]; - } - alphablockerror1 += alphadist * alphadist; - } - } -/* for (i = 0; i < 16; i++) { - fprintf(stderr, "%d ", alphaenc1[i]); - } - fprintf(stderr, "cutVals "); - for (i = 0; i < 8; i++) { - fprintf(stderr, "%d ", acutValues[i]); - } - fprintf(stderr, "srcVals "); - for (j = 0; j < numypixels; j++) - for (i = 0; i < numxpixels; i++) { - fprintf(stderr, "%d ", srccolors[j][i][3]); - } - - fprintf(stderr, "\n"); - }*/ - /* it's not very likely this encoding is better if both alphaabsmin and alphaabsmax - are false but try it anyway */ - if (alphablockerror1 >= 32) { - - /* don't bother if encoding is already very good, this condition should also imply - we have valid alphabase colors which we absolutely need (alphabase[0] <= alphabase[1]) */ - alphablockerror2 = 0; - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphabase[0] * (10 - (2*aindex + 1)) + alphabase[1] * (2*aindex + 1)) / 10; - } - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i][3] == 0) { - alphaenc2[4*j + i] = 6; - alphadist = 0; - } - else if (srccolors[j][i][3] == 255) { - alphaenc2[4*j + i] = 7; - alphadist = 0; - } - else if (srccolors[j][i][3] <= acutValues[0]) { - alphaenc2[4*j + i] = 0; - alphadist = srccolors[j][i][3] - alphabase[0]; - } - else if (srccolors[j][i][3] <= acutValues[1]) { - alphaenc2[4*j + i] = 2; - alphadist = srccolors[j][i][3] - (alphabase[0] * 4 + alphabase[1] * 1) / 5; - } - else if (srccolors[j][i][3] <= acutValues[2]) { - alphaenc2[4*j + i] = 3; - alphadist = srccolors[j][i][3] - (alphabase[0] * 3 + alphabase[1] * 2) / 5; - } - else if (srccolors[j][i][3] <= acutValues[3]) { - alphaenc2[4*j + i] = 4; - alphadist = srccolors[j][i][3] - (alphabase[0] * 2 + alphabase[1] * 3) / 5; - } - else if (srccolors[j][i][3] <= acutValues[4]) { - alphaenc2[4*j + i] = 5; - alphadist = srccolors[j][i][3] - (alphabase[0] * 1 + alphabase[1] * 4) / 5; - } - else { - alphaenc2[4*j + i] = 1; - alphadist = srccolors[j][i][3] - alphabase[1]; - } - alphablockerror2 += alphadist * alphadist; - } - } - - - /* skip this if the error is already very small - this encoding is MUCH better on average than #2 though, but expensive! */ - if ((alphablockerror2 > 96) && (alphablockerror1 > 96)) { - GLshort blockerrlin1 = 0; - GLshort blockerrlin2 = 0; - GLubyte nralphainrangelow = 0; - GLubyte nralphainrangehigh = 0; - alphatest[0] = 0xff; - alphatest[1] = 0x0; - /* if we have large range it's likely there are values close to 0/255, try to map them to 0/255 */ - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if ((srccolors[j][i][3] > alphatest[1]) && (srccolors[j][i][3] < (255 -(alphabase[1] - alphabase[0]) / 28))) - alphatest[1] = srccolors[j][i][3]; - if ((srccolors[j][i][3] < alphatest[0]) && (srccolors[j][i][3] > (alphabase[1] - alphabase[0]) / 28)) - alphatest[0] = srccolors[j][i][3]; - } - } - /* shouldn't happen too often, don't really care about those degenerated cases */ - if (alphatest[1] <= alphatest[0]) { - alphatest[0] = 1; - alphatest[1] = 254; -/* fprintf(stderr, "only 1 or 0 colors for encoding!\n");*/ - } - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; - } - - /* find the "average" difference between the alpha values and the next encoded value. - This is then used to calculate new base values. - Should there be some weighting, i.e. those values closer to alphatest[x] have more weight, - since they will see more improvement, and also because the values in the middle are somewhat - likely to get no improvement at all (because the base values might move in different directions)? - OTOH it would mean the values in the middle are even less likely to get an improvement - */ - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - if (srccolors[j][i][3] <= alphatest[0] / 2) { - } - else if (srccolors[j][i][3] > ((255 + alphatest[1]) / 2)) { - } - else if (srccolors[j][i][3] <= acutValues[0]) { - blockerrlin1 += (srccolors[j][i][3] - alphatest[0]); - nralphainrangelow += 1; - } - else if (srccolors[j][i][3] <= acutValues[1]) { - blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); - blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i][3] <= acutValues[2]) { - blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); - blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i][3] <= acutValues[3]) { - blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); - blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else if (srccolors[j][i][3] <= acutValues[4]) { - blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); - blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); - nralphainrangelow += 1; - nralphainrangehigh += 1; - } - else { - blockerrlin2 += (srccolors[j][i][3] - alphatest[1]); - nralphainrangehigh += 1; - } - } - } - /* shouldn't happen often, needed to avoid div by zero */ - if (nralphainrangelow == 0) nralphainrangelow = 1; - if (nralphainrangehigh == 0) nralphainrangehigh = 1; - alphatest[0] = alphatest[0] + (blockerrlin1 / nralphainrangelow); -/* fprintf(stderr, "block err lin low %d, nr %d\n", blockerrlin1, nralphainrangelow); - fprintf(stderr, "block err lin high %d, nr %d\n", blockerrlin2, nralphainrangehigh);*/ - /* again shouldn't really happen often... */ - if (alphatest[0] < 0) { - alphatest[0] = 0; -/* fprintf(stderr, "adj alpha base val to 0\n");*/ - } - alphatest[1] = alphatest[1] + (blockerrlin2 / nralphainrangehigh); - if (alphatest[1] > 255) { - alphatest[1] = 255; -/* fprintf(stderr, "adj alpha base val to 255\n");*/ - } - - alphablockerror3 = 0; - for (aindex = 0; aindex < 5; aindex++) { - /* don't forget here is always rounded down */ - acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; - } - for (j = 0; j < numypixels; j++) { - for (i = 0; i < numxpixels; i++) { - /* maybe it's overkill to have the most complicated calculation just for the error - calculation which we only need to figure out if encoding1 or encoding2 is better... */ - if (srccolors[j][i][3] <= alphatest[0] / 2) { - alphaenc3[4*j + i] = 6; - alphadist = srccolors[j][i][3]; - } - else if (srccolors[j][i][3] > ((255 + alphatest[1]) / 2)) { - alphaenc3[4*j + i] = 7; - alphadist = 255 - srccolors[j][i][3]; - } - else if (srccolors[j][i][3] <= acutValues[0]) { - alphaenc3[4*j + i] = 0; - alphadist = srccolors[j][i][3] - alphatest[0]; - } - else if (srccolors[j][i][3] <= acutValues[1]) { - alphaenc3[4*j + i] = 2; - alphadist = srccolors[j][i][3] - (alphatest[0] * 4 + alphatest[1] * 1) / 5; - } - else if (srccolors[j][i][3] <= acutValues[2]) { - alphaenc3[4*j + i] = 3; - alphadist = srccolors[j][i][3] - (alphatest[0] * 3 + alphatest[1] * 2) / 5; - } - else if (srccolors[j][i][3] <= acutValues[3]) { - alphaenc3[4*j + i] = 4; - alphadist = srccolors[j][i][3] - (alphatest[0] * 2 + alphatest[1] * 3) / 5; - } - else if (srccolors[j][i][3] <= acutValues[4]) { - alphaenc3[4*j + i] = 5; - alphadist = srccolors[j][i][3] - (alphatest[0] * 1 + alphatest[1] * 4) / 5; - } - else { - alphaenc3[4*j + i] = 1; - alphadist = srccolors[j][i][3] - alphatest[1]; - } - alphablockerror3 += alphadist * alphadist; - } - } - } - } - /* write the alpha values and encoding back. */ - if ((alphablockerror1 <= alphablockerror2) && (alphablockerror1 <= alphablockerror3)) { -/* if (alphablockerror1 > 96) fprintf(stderr, "enc1 used, error %d\n", alphablockerror1);*/ - writedxt5encodedalphablock( blkaddr, alphause[1], alphause[0], alphaenc1 ); - } - else if (alphablockerror2 <= alphablockerror3) { -/* if (alphablockerror2 > 96) fprintf(stderr, "enc2 used, error %d\n", alphablockerror2);*/ - writedxt5encodedalphablock( blkaddr, alphabase[0], alphabase[1], alphaenc2 ); - } - else { -/* fprintf(stderr, "enc3 used, error %d\n", alphablockerror3);*/ - writedxt5encodedalphablock( blkaddr, (GLubyte)alphatest[0], (GLubyte)alphatest[1], alphaenc3 ); - } -} - -static void extractsrccolors( GLubyte srcpixels[4][4][4], const GLchan *srcaddr, - GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps) -{ - GLubyte i, j, c; - const GLchan *curaddr; - for (j = 0; j < numypixels; j++) { - curaddr = srcaddr + j * srcRowStride * comps; - for (i = 0; i < numxpixels; i++) { - for (c = 0; c < comps; c++) { - srcpixels[j][i][c] = *curaddr++ / (CHAN_MAX / 255); - } - } - } -} - - -void tx_compress_dxtn(GLint srccomps, GLint width, GLint height, const GLubyte *srcPixData, - GLenum destFormat, GLubyte *dest, GLint dstRowStride) -{ - GLubyte *blkaddr = dest; - GLubyte srcpixels[4][4][4]; - const GLchan *srcaddr = srcPixData; - GLint numxpixels, numypixels; - GLint i, j; - GLint dstRowDiff; - - switch (destFormat) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - /* hmm we used to get called without dstRowStride... */ - dstRowDiff = dstRowStride >= (width * 2) ? dstRowStride - (((width + 3) & ~3) * 2) : 0; -/* fprintf(stderr, "dxt1 tex width %d tex height %d dstRowStride %d\n", - width, height, dstRowStride); */ - for (j = 0; j < height; j += 4) { - if (height > j + 3) numypixels = 4; - else numypixels = height - j; - srcaddr = srcPixData + j * width * srccomps; - for (i = 0; i < width; i += 4) { - if (width > i + 3) numxpixels = 4; - else numxpixels = width - i; - extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps); - encodedxtcolorblockfaster(blkaddr, srcpixels, numxpixels, numypixels, destFormat); - srcaddr += srccomps * numxpixels; - blkaddr += 8; - } - blkaddr += dstRowDiff; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0; -/* fprintf(stderr, "dxt3 tex width %d tex height %d dstRowStride %d\n", - width, height, dstRowStride); */ - for (j = 0; j < height; j += 4) { - if (height > j + 3) numypixels = 4; - else numypixels = height - j; - srcaddr = srcPixData + j * width * srccomps; - for (i = 0; i < width; i += 4) { - if (width > i + 3) numxpixels = 4; - else numxpixels = width - i; - extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps); - *blkaddr++ = (srcpixels[0][0][3] >> 4) | (srcpixels[0][1][3] & 0xf0); - *blkaddr++ = (srcpixels[0][2][3] >> 4) | (srcpixels[0][3][3] & 0xf0); - *blkaddr++ = (srcpixels[1][0][3] >> 4) | (srcpixels[1][1][3] & 0xf0); - *blkaddr++ = (srcpixels[1][2][3] >> 4) | (srcpixels[1][3][3] & 0xf0); - *blkaddr++ = (srcpixels[2][0][3] >> 4) | (srcpixels[2][1][3] & 0xf0); - *blkaddr++ = (srcpixels[2][2][3] >> 4) | (srcpixels[2][3][3] & 0xf0); - *blkaddr++ = (srcpixels[3][0][3] >> 4) | (srcpixels[3][1][3] & 0xf0); - *blkaddr++ = (srcpixels[3][2][3] >> 4) | (srcpixels[3][3][3] & 0xf0); - encodedxtcolorblockfaster(blkaddr, srcpixels, numxpixels, numypixels, destFormat); - srcaddr += srccomps * numxpixels; - blkaddr += 8; - } - blkaddr += dstRowDiff; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0; -/* fprintf(stderr, "dxt5 tex width %d tex height %d dstRowStride %d\n", - width, height, dstRowStride); */ - for (j = 0; j < height; j += 4) { - if (height > j + 3) numypixels = 4; - else numypixels = height - j; - srcaddr = srcPixData + j * width * srccomps; - for (i = 0; i < width; i += 4) { - if (width > i + 3) numxpixels = 4; - else numxpixels = width - i; - extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps); - encodedxt5alpha(blkaddr, srcpixels, numxpixels, numypixels); - encodedxtcolorblockfaster(blkaddr + 8, srcpixels, numxpixels, numypixels, destFormat); - srcaddr += srccomps * numxpixels; - blkaddr += 16; - } - blkaddr += dstRowDiff; - } - break; - default: - /* fprintf(stderr, "libdxtn: Bad dstFormat %d in tx_compress_dxtn\n", destFormat); */ - return; - } -} diff --git a/dlls/d3dx9_36/txc_dxtn.h b/dlls/d3dx9_36/txc_dxtn.h deleted file mode 100644 index 3c1e3d46c289..000000000000 --- a/dlls/d3dx9_36/txc_dxtn.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * libtxc_dxtn - * Version: 1.0 - * - * Copyright (C) 2004 Roland Scheidegger All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _TXC_DXTN_H -#define _TXC_DXTN_H - -#include "winternl.h" -#include "wine/wgl.h" - -typedef GLubyte GLchan; -#define UBYTE_TO_CHAN(b) (b) -#define CHAN_MAX 255 -#define RCOMP 0 -#define GCOMP 1 -#define BCOMP 2 -#define ACOMP 3 - -void fetch_2d_texel_rgb_dxt1(GLint srcRowStride, const GLubyte *pixdata, - GLint i, GLint j, GLvoid *texel); -void fetch_2d_texel_rgba_dxt1(GLint srcRowStride, const GLubyte *pixdata, - GLint i, GLint j, GLvoid *texel); -void fetch_2d_texel_rgba_dxt3(GLint srcRowStride, const GLubyte *pixdata, - GLint i, GLint j, GLvoid *texel); -void fetch_2d_texel_rgba_dxt5(GLint srcRowStride, const GLubyte *pixdata, - GLint i, GLint j, GLvoid *texel); - -void tx_compress_dxtn(GLint srccomps, GLint width, GLint height, - const GLubyte *srcPixData, GLenum destformat, - GLubyte *dest, GLint dstRowStride); - -#endif /* _TXC_DXTN_H */ diff --git a/dlls/d3dx9_36/txc_fetch_dxtn.c b/dlls/d3dx9_36/txc_fetch_dxtn.c deleted file mode 100644 index 7f0db56a155d..000000000000 --- a/dlls/d3dx9_36/txc_fetch_dxtn.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * libtxc_dxtn - * Version: 1.0 - * - * Copyright (C) 2004 Roland Scheidegger All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include "txc_dxtn.h" - -#define EXP5TO8R(packedcol) \ - ((((packedcol) >> 8) & 0xf8) | (((packedcol) >> 13) & 0x7)) - -#define EXP6TO8G(packedcol) \ - ((((packedcol) >> 3) & 0xfc) | (((packedcol) >> 9) & 0x3)) - -#define EXP5TO8B(packedcol) \ - ((((packedcol) << 3) & 0xf8) | (((packedcol) >> 2) & 0x7)) - -#define EXP4TO8(col) \ - ((col) | ((col) << 4)) - -/* inefficient. To be efficient, it would be necessary to decode 16 pixels at once */ - -static void dxt135_decode_imageblock ( const GLubyte *img_block_src, - GLint i, GLint j, GLuint dxt_type, GLvoid *texel ) { - GLchan *rgba = (GLchan *) texel; - const GLushort color0 = img_block_src[0] | (img_block_src[1] << 8); - const GLushort color1 = img_block_src[2] | (img_block_src[3] << 8); - const GLuint bits = img_block_src[4] | (img_block_src[5] << 8) | - (img_block_src[6] << 16) | (img_block_src[7] << 24); - /* What about big/little endian? */ - GLubyte bit_pos = 2 * (j * 4 + i) ; - GLubyte code = (GLubyte) ((bits >> bit_pos) & 3); - - rgba[ACOMP] = CHAN_MAX; - switch (code) { - case 0: - rgba[RCOMP] = UBYTE_TO_CHAN( EXP5TO8R(color0) ); - rgba[GCOMP] = UBYTE_TO_CHAN( EXP6TO8G(color0) ); - rgba[BCOMP] = UBYTE_TO_CHAN( EXP5TO8B(color0) ); - break; - case 1: - rgba[RCOMP] = UBYTE_TO_CHAN( EXP5TO8R(color1) ); - rgba[GCOMP] = UBYTE_TO_CHAN( EXP6TO8G(color1) ); - rgba[BCOMP] = UBYTE_TO_CHAN( EXP5TO8B(color1) ); - break; - case 2: - if ((dxt_type > 1) || (color0 > color1)) { - rgba[RCOMP] = UBYTE_TO_CHAN( ((EXP5TO8R(color0) * 2 + EXP5TO8R(color1)) / 3) ); - rgba[GCOMP] = UBYTE_TO_CHAN( ((EXP6TO8G(color0) * 2 + EXP6TO8G(color1)) / 3) ); - rgba[BCOMP] = UBYTE_TO_CHAN( ((EXP5TO8B(color0) * 2 + EXP5TO8B(color1)) / 3) ); - } - else { - rgba[RCOMP] = UBYTE_TO_CHAN( ((EXP5TO8R(color0) + EXP5TO8R(color1)) / 2) ); - rgba[GCOMP] = UBYTE_TO_CHAN( ((EXP6TO8G(color0) + EXP6TO8G(color1)) / 2) ); - rgba[BCOMP] = UBYTE_TO_CHAN( ((EXP5TO8B(color0) + EXP5TO8B(color1)) / 2) ); - } - break; - case 3: - if ((dxt_type > 1) || (color0 > color1)) { - rgba[RCOMP] = UBYTE_TO_CHAN( ((EXP5TO8R(color0) + EXP5TO8R(color1) * 2) / 3) ); - rgba[GCOMP] = UBYTE_TO_CHAN( ((EXP6TO8G(color0) + EXP6TO8G(color1) * 2) / 3) ); - rgba[BCOMP] = UBYTE_TO_CHAN( ((EXP5TO8B(color0) + EXP5TO8B(color1) * 2) / 3) ); - } - else { - rgba[RCOMP] = 0; - rgba[GCOMP] = 0; - rgba[BCOMP] = 0; - if (dxt_type == 1) rgba[ACOMP] = UBYTE_TO_CHAN(0); - } - break; - default: - /* CANNOT happen (I hope) */ - break; - } -} - - -void fetch_2d_texel_rgb_dxt1(GLint srcRowStride, const GLubyte *pixdata, - GLint i, GLint j, GLvoid *texel) -{ - /* Extract the (i,j) pixel from pixdata and return it - * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. - */ - - const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8); - dxt135_decode_imageblock(blksrc, (i&3), (j&3), 0, texel); -} - - -void fetch_2d_texel_rgba_dxt1(GLint srcRowStride, const GLubyte *pixdata, - GLint i, GLint j, GLvoid *texel) -{ - /* Extract the (i,j) pixel from pixdata and return it - * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. - */ - - const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8); - dxt135_decode_imageblock(blksrc, (i&3), (j&3), 1, texel); -} - -void fetch_2d_texel_rgba_dxt3(GLint srcRowStride, const GLubyte *pixdata, - GLint i, GLint j, GLvoid *texel) { - - /* Extract the (i,j) pixel from pixdata and return it - * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. - */ - - GLchan *rgba = (GLchan *) texel; - const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 16); -#if 0 - /* Simple 32bit version. */ -/* that's pretty brain-dead for a single pixel, isn't it? */ - const GLubyte bit_pos = 4 * ((j&3) * 4 + (i&3)); - const GLuint alpha_low = blksrc[0] | (blksrc[1] << 8) | (blksrc[2] << 16) | (blksrc[3] << 24); - const GLuint alpha_high = blksrc[4] | (blksrc[5] << 8) | (blksrc[6] << 16) | (blksrc[7] << 24); - - dxt135_decode_imageblock(blksrc + 8, (i&3), (j&3), 2, texel); - if (bit_pos < 32) - rgba[ACOMP] = UBYTE_TO_CHAN( (GLubyte)(EXP4TO8((alpha_low >> bit_pos) & 15)) ); - else - rgba[ACOMP] = UBYTE_TO_CHAN( (GLubyte)(EXP4TO8((alpha_high >> (bit_pos - 32)) & 15)) ); -#endif -#if 1 -/* TODO test this! */ - const GLubyte anibble = (blksrc[((j&3) * 4 + (i&3)) / 2] >> (4 * (i&1))) & 0xf; - dxt135_decode_imageblock(blksrc + 8, (i&3), (j&3), 2, texel); - rgba[ACOMP] = UBYTE_TO_CHAN( (GLubyte)(EXP4TO8(anibble)) ); -#endif - -} - -void fetch_2d_texel_rgba_dxt5(GLint srcRowStride, const GLubyte *pixdata, - GLint i, GLint j, GLvoid *texel) { - - /* Extract the (i,j) pixel from pixdata and return it - * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. - */ - - GLchan *rgba = (GLchan *) texel; - const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 16); - const GLubyte alpha0 = blksrc[0]; - const GLubyte alpha1 = blksrc[1]; -#if 0 - const GLubyte bit_pos = 3 * ((j&3) * 4 + (i&3)); - /* simple 32bit version */ - const GLuint bits_low = blksrc[2] | (blksrc[3] << 8) | (blksrc[4] << 16) | (blksrc[5] << 24); - const GLuint bits_high = blksrc[6] | (blksrc[7] << 8); - GLubyte code; - - if (bit_pos < 30) - code = (GLubyte) ((bits_low >> bit_pos) & 7); - else if (bit_pos == 30) - code = (GLubyte) ((bits_low >> 30) & 3) | ((bits_high << 2) & 4); - else - code = (GLubyte) ((bits_high >> (bit_pos - 32)) & 7); -#endif -#if 1 -/* TODO test this! */ - const GLubyte bit_pos = ((j&3) * 4 + (i&3)) * 3; - const GLubyte acodelow = blksrc[2 + bit_pos / 8]; - const GLubyte acodehigh = blksrc[3 + bit_pos / 8]; - const GLubyte code = (acodelow >> (bit_pos & 0x7) | - (acodehigh << (8 - (bit_pos & 0x7)))) & 0x7; -#endif - dxt135_decode_imageblock(blksrc + 8, (i&3), (j&3), 2, texel); -#if 0 - if (alpha0 > alpha1) { - switch (code) { - case 0: - rgba[ACOMP] = UBYTE_TO_CHAN( alpha0 ); - break; - case 1: - rgba[ACOMP] = UBYTE_TO_CHAN( alpha1 ); - break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - rgba[ACOMP] = UBYTE_TO_CHAN( ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7) ); - break; - } - } - else { - switch (code) { - case 0: - rgba[ACOMP] = UBYTE_TO_CHAN( alpha0 ); - break; - case 1: - rgba[ACOMP] = UBYTE_TO_CHAN( alpha1 ); - break; - case 2: - case 3: - case 4: - case 5: - rgba[ACOMP] = UBYTE_TO_CHAN( ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5) ); - break; - case 6: - rgba[ACOMP] = 0; - break; - case 7: - rgba[ACOMP] = CHAN_MAX; - break; - } - } -#endif -/* not sure. Which version is faster? */ -#if 1 -/* TODO test this */ - if (code == 0) - rgba[ACOMP] = UBYTE_TO_CHAN( alpha0 ); - else if (code == 1) - rgba[ACOMP] = UBYTE_TO_CHAN( alpha1 ); - else if (alpha0 > alpha1) - rgba[ACOMP] = UBYTE_TO_CHAN( ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7) ); - else if (code < 6) - rgba[ACOMP] = UBYTE_TO_CHAN( ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5) ); - else if (code == 6) - rgba[ACOMP] = 0; - else - rgba[ACOMP] = CHAN_MAX; -#endif -} diff --git a/dlls/d3dx9_36/util.c b/dlls/d3dx9_36/util.c index e6a11cdc1e4b..b68421ff002b 100644 --- a/dlls/d3dx9_36/util.c +++ b/dlls/d3dx9_36/util.c @@ -22,64 +22,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3dx); -/************************************************************ - * pixel format table providing info about number of bytes per pixel, - * number of bits per channel and format type. - * - * Call get_format_info to request information about a specific format. - */ -static const struct pixel_format_desc formats[] = -{ - /* format bpc shifts bpp blocks alpha type rgb type flags */ - {D3DX_PIXEL_FORMAT_B8G8R8_UNORM, { 0, 8, 8, 8}, { 0, 16, 8, 0}, 3, 1, 1, 3, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, { 8, 8, 8, 8}, {24, 16, 8, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM, { 0, 8, 8, 8}, { 0, 16, 8, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM, { 8, 8, 8, 8}, {24, 0, 8, 16}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM, { 0, 8, 8, 8}, { 0, 0, 8, 16}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B5G6R5_UNORM, { 0, 5, 6, 5}, { 0, 11, 5, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM, { 0, 5, 5, 5}, { 0, 10, 5, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM, { 1, 5, 5, 5}, {15, 10, 5, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B2G3R3_UNORM, { 0, 3, 3, 2}, { 0, 5, 2, 0}, 1, 1, 1, 1, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM, { 8, 3, 3, 2}, { 8, 5, 2, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM, { 4, 4, 4, 4}, {12, 8, 4, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM, { 0, 4, 4, 4}, { 0, 8, 4, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM, { 2, 10, 10, 10}, {30, 20, 10, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM, { 2, 10, 10, 10}, {30, 0, 10, 20}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_R16G16B16_UNORM, { 0, 16, 16, 16}, { 0, 0, 16, 32}, 6, 1, 1, 6, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_INTERNAL}, - {D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_R16G16_UNORM, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_A8_UNORM, { 8, 0, 0, 0}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_UNORM, CTYPE_EMPTY, 0 }, - {D3DX_PIXEL_FORMAT_L8A8_UNORM, { 8, 8, 0, 0}, { 8, 0, 0, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_LUMA, 0 }, - {D3DX_PIXEL_FORMAT_L4A4_UNORM, { 4, 4, 0, 0}, { 4, 0, 0, 0}, 1, 1, 1, 1, CTYPE_UNORM, CTYPE_LUMA, 0 }, - {D3DX_PIXEL_FORMAT_L8_UNORM, { 0, 8, 0, 0}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_EMPTY, CTYPE_LUMA, 0 }, - {D3DX_PIXEL_FORMAT_L16_UNORM, { 0, 16, 0, 0}, { 0, 0, 0, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_LUMA, 0 }, - {D3DX_PIXEL_FORMAT_DXT1_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 8, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_DXT2_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_DXT3_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_DXT4_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_DXT5_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_R16_FLOAT, { 0, 16, 0, 0}, { 0, 0, 0, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_R16G16_FLOAT, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_FLOAT, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_R32_FLOAT, { 0, 32, 0, 0}, { 0, 0, 0, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_R32G32_FLOAT, { 0, 32, 32, 0}, { 0, 0, 32, 0}, 8, 1, 1, 8, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT, {32, 32, 32, 32}, {96, 0, 32, 64}, 16, 1, 1, 16, CTYPE_FLOAT, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_P8_UINT, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_INDEX, CTYPE_INDEX, 0 }, - {D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM, { 8, 8, 8, 8}, { 8, 0, 0, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_INDEX, 0 }, - {D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM, { 8, 8, 8, 8}, {24, 0, 8, 16}, 4, 1, 1, 4, CTYPE_SNORM, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_SNORM, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_U8V8_SNORM, { 0, 8, 8, 0}, { 0, 0, 8, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_U16V16_SNORM, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM, { 8, 8, 8, 0}, {16, 0, 8, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM, { 2, 10, 10, 10}, {30, 0, 10, 20}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, - {D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, - {D3DX_PIXEL_FORMAT_UYVY, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, - {D3DX_PIXEL_FORMAT_YUY2, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, - /* marks last element */ - {D3DX_PIXEL_FORMAT_COUNT, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 0, 1, 1, 0, CTYPE_EMPTY, CTYPE_EMPTY, 0 }, -}; - D3DFORMAT d3dformat_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id format) { switch (format) @@ -129,9 +71,13 @@ D3DFORMAT d3dformat_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id format) case D3DX_PIXEL_FORMAT_UYVY: return D3DFMT_UYVY; case D3DX_PIXEL_FORMAT_YUY2: return D3DFMT_YUY2; default: - if (!is_internal_format(get_d3dx_pixel_format_info(format))) + { + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(format); + + if (!is_internal_format(fmt_desc) && !is_dxgi_format(fmt_desc)) FIXME("Unknown d3dx_pixel_format_id %u.\n", format); return D3DFMT_UNKNOWN; + } } } @@ -189,6 +135,19 @@ enum d3dx_pixel_format_id d3dx_pixel_format_id_from_d3dformat(D3DFORMAT format) } } +enum d3dx_resource_type d3dx_resource_type_from_d3dresourcetype(D3DRESOURCETYPE type) +{ + switch (type) + { + case D3DRTYPE_TEXTURE: return D3DX_RESOURCE_TYPE_TEXTURE_2D; + case D3DRTYPE_VOLUMETEXTURE: return D3DX_RESOURCE_TYPE_TEXTURE_3D; + case D3DRTYPE_CUBETEXTURE: return D3DX_RESOURCE_TYPE_CUBE_TEXTURE; + default: + FIXME("No d3dx_resource_type for D3DRESOURCETYPE %d.\n", type); + return D3DX_RESOURCE_TYPE_COUNT; + } +} + /************************************************************ * map_view_of_file * @@ -274,31 +233,6 @@ HRESULT load_resource_into_memory(HMODULE module, HRSRC resinfo, void **buffer, return S_OK; } -HRESULT write_buffer_to_file(const WCHAR *dst_filename, ID3DXBuffer *buffer) -{ - HRESULT hr = S_OK; - void *buffer_pointer; - DWORD buffer_size; - DWORD bytes_written; - HANDLE file = CreateFileW(dst_filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (file == INVALID_HANDLE_VALUE) - return HRESULT_FROM_WIN32(GetLastError()); - - buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); - buffer_size = ID3DXBuffer_GetBufferSize(buffer); - - if (!WriteFile(file, buffer_pointer, buffer_size, &bytes_written, NULL)) - hr = HRESULT_FROM_WIN32(GetLastError()); - - CloseHandle(file); - return hr; -} - -const struct pixel_format_desc *get_d3dx_pixel_format_info(enum d3dx_pixel_format_id format) -{ - return &formats[min(format, D3DX_PIXEL_FORMAT_COUNT)]; -} - /************************************************************ * get_format_info * @@ -311,7 +245,7 @@ const struct pixel_format_desc *get_d3dx_pixel_format_info(enum d3dx_pixel_forma */ const struct pixel_format_desc *get_format_info(D3DFORMAT format) { - const struct pixel_format_desc *fmt_desc = &formats[d3dx_pixel_format_id_from_d3dformat(format)]; + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(d3dx_pixel_format_id_from_d3dformat(format)); if (is_unknown_format(fmt_desc)) FIXME("Unknown format %s.\n", debugstr_fourcc(format)); @@ -320,7 +254,7 @@ const struct pixel_format_desc *get_format_info(D3DFORMAT format) const struct pixel_format_desc *get_format_info_idx(int idx) { - return idx < D3DX_PIXEL_FORMAT_COUNT ? &formats[idx] : NULL; + return idx < D3DX_PIXEL_FORMAT_COUNT ? get_d3dx_pixel_format_info(idx) : NULL; } #define WINE_D3DX_TO_STR(x) case x: return #x diff --git a/dlls/d3dx9_36/volume.c b/dlls/d3dx9_36/volume.c index e3444a063c77..f5922b856abd 100644 --- a/dlls/d3dx9_36/volume.c +++ b/dlls/d3dx9_36/volume.c @@ -279,3 +279,147 @@ HRESULT WINAPI D3DXLoadVolumeFromVolume(IDirect3DVolume9 *dst_volume, const PALE IDirect3DVolume9_UnlockBox(src_volume); return hr; } + +HRESULT WINAPI D3DXSaveVolumeToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format, + IDirect3DVolume9 *src_volume, const PALETTEENTRY *src_palette, const D3DBOX *src_box) +{ + const struct pixel_format_desc *src_fmt_desc; + RECT src_rect_aligned, src_rect_unaligned; + D3DBOX src_box_aligned, src_box_tmp; + enum d3dx_pixel_format_id dst_fmt; + struct d3dx_pixels src_pixels; + D3DLOCKED_BOX locked_box; + ID3DXBuffer *buffer; + D3DVOLUME_DESC desc; + HRESULT hr; + + TRACE("dst_buffer %p, file_format %#x, src_volume %p, src_palette %p, src_box %p.\n", + dst_buffer, file_format, src_volume, src_palette, src_box); + + if (!dst_buffer || !src_volume || file_format > D3DXIFF_PFM) + return D3DERR_INVALIDCALL; + + *dst_buffer = NULL; + switch (file_format) + { + case D3DXIFF_HDR: + case D3DXIFF_PFM: + case D3DXIFF_PPM: + FIXME("File format %s is not supported yet.\n", + debug_d3dx_image_file_format((enum d3dx_image_file_format)file_format)); + return E_NOTIMPL; + + default: + break; + } + + IDirect3DVolume9_GetDesc(src_volume, &desc); + src_fmt_desc = get_format_info(desc.Format); + if (is_unknown_format(src_fmt_desc)) + return E_NOTIMPL; + + if (!src_palette && is_index_format(src_fmt_desc)) + { + FIXME("Default palette unimplemented.\n"); + return E_NOTIMPL; + } + + if (!src_box) + { + set_d3dbox(&src_box_tmp, 0, 0, desc.Width, desc.Height, 0, desc.Depth); + src_box = &src_box_tmp; + } + else + { + if (src_box->Left >= src_box->Right || src_box->Right > desc.Width + || src_box->Top >= src_box->Bottom || src_box->Bottom > desc.Height + || src_box->Front >= src_box->Back || src_box->Back > desc.Depth) + { + WARN("Invalid src_box specified.\n"); + return D3DERR_INVALIDCALL; + } + } + + hr = d3dx_get_save_pixel_format_from_image_file_format(src_fmt_desc, file_format, &dst_fmt); + if (FAILED(hr)) + return hr; + + get_aligned_rect(src_box->Left, src_box->Top, src_box->Right, src_box->Bottom, desc.Width, desc.Height, + src_fmt_desc, &src_rect_aligned); + set_d3dbox(&src_box_aligned, src_rect_aligned.left, src_rect_aligned.top, src_rect_aligned.right, + src_rect_aligned.bottom, src_box->Front, src_box->Back); + + hr = IDirect3DVolume9_LockBox(src_volume, &locked_box, &src_box_aligned, 0); + if (FAILED(hr)) + return hr; + + SetRect(&src_rect_unaligned, src_box->Left, src_box->Top, src_box->Right, src_box->Bottom); + OffsetRect(&src_rect_unaligned, -src_rect_aligned.left, -src_rect_aligned.top); + set_d3dx_pixels(&src_pixels, locked_box.pBits, locked_box.RowPitch, locked_box.SlicePitch, src_palette, + (src_box_aligned.Right - src_box_aligned.Left), (src_box_aligned.Bottom - src_box_aligned.Top), + (src_box_aligned.Back - src_box_aligned.Front), &src_rect_unaligned); + + hr = d3dx_save_pixels_to_memory(&src_pixels, src_fmt_desc, (enum d3dx_image_file_format)file_format, dst_fmt, &buffer); + if (FAILED(hr)) + { + IDirect3DVolume9_UnlockBox(src_volume); + return hr; + } + + IDirect3DVolume9_UnlockBox(src_volume); + *dst_buffer = buffer; + return D3D_OK; +} + +HRESULT WINAPI D3DXSaveVolumeToFileA(const char *dst_filename, D3DXIMAGE_FILEFORMAT file_format, + IDirect3DVolume9 *src_volume, const PALETTEENTRY *src_palette, const D3DBOX *src_box) +{ + ID3DXBuffer *buffer; + WCHAR *filename; + int32_t len; + HRESULT hr; + + TRACE("(%s, %#x, %p, %p, %p): relay\n", + wine_dbgstr_a(dst_filename), file_format, src_volume, src_palette, src_box); + + if (!dst_filename) + return D3DERR_INVALIDCALL; + + len = MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, NULL, 0); + filename = malloc(len * sizeof(WCHAR)); + if (!filename) + return E_OUTOFMEMORY; + MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, filename, len); + + hr = D3DXSaveVolumeToFileInMemory(&buffer, file_format, src_volume, src_palette, src_box); + if (SUCCEEDED(hr)) + { + hr = write_buffer_to_file(filename, buffer); + ID3DXBuffer_Release(buffer); + } + + free(filename); + return hr; +} + +HRESULT WINAPI D3DXSaveVolumeToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format, + IDirect3DVolume9 *src_volume, const PALETTEENTRY *src_palette, const D3DBOX *src_box) +{ + ID3DXBuffer *buffer; + HRESULT hr; + + TRACE("(%s, %#x, %p, %p, %p): relay\n", + wine_dbgstr_w(dst_filename), file_format, src_volume, src_palette, src_box); + + if (!dst_filename) + return D3DERR_INVALIDCALL; + + hr = D3DXSaveVolumeToFileInMemory(&buffer, file_format, src_volume, src_palette, src_box); + if (SUCCEEDED(hr)) + { + hr = write_buffer_to_file(dst_filename, buffer); + ID3DXBuffer_Release(buffer); + } + + return hr; +} diff --git a/dlls/d3dx9_37/Makefile.in b/dlls/d3dx9_37/Makefile.in index 150f1ceb215c..d4224c70b869 100644 --- a/dlls/d3dx9_37/Makefile.in +++ b/dlls/d3dx9_37/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=37 +EXTRADEFS = -DD3DX_SDK_VERSION=37 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_37.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_37/d3dx9_37.spec b/dlls/d3dx9_37/d3dx9_37.spec index 13405ad8909d..d5e39385847a 100644 --- a/dlls/d3dx9_37/d3dx9_37.spec +++ b/dlls/d3dx9_37/d3dx9_37.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -287,9 +287,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_38/Makefile.in b/dlls/d3dx9_38/Makefile.in index 5706fe9b2032..9084249990ae 100644 --- a/dlls/d3dx9_38/Makefile.in +++ b/dlls/d3dx9_38/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=38 +EXTRADEFS = -DD3DX_SDK_VERSION=38 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_38.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_38/d3dx9_38.spec b/dlls/d3dx9_38/d3dx9_38.spec index 13405ad8909d..d5e39385847a 100644 --- a/dlls/d3dx9_38/d3dx9_38.spec +++ b/dlls/d3dx9_38/d3dx9_38.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -287,9 +287,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_39/Makefile.in b/dlls/d3dx9_39/Makefile.in index 9e8f8f6199ea..894362b326bd 100644 --- a/dlls/d3dx9_39/Makefile.in +++ b/dlls/d3dx9_39/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=39 +EXTRADEFS = -DD3DX_SDK_VERSION=39 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_39.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_39/d3dx9_39.spec b/dlls/d3dx9_39/d3dx9_39.spec index 13405ad8909d..d5e39385847a 100644 --- a/dlls/d3dx9_39/d3dx9_39.spec +++ b/dlls/d3dx9_39/d3dx9_39.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -287,9 +287,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_40/Makefile.in b/dlls/d3dx9_40/Makefile.in index fe10a5d3dcb4..4629f689be10 100644 --- a/dlls/d3dx9_40/Makefile.in +++ b/dlls/d3dx9_40/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=40 +EXTRADEFS = -DD3DX_SDK_VERSION=40 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_40.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_40/d3dx9_40.spec b/dlls/d3dx9_40/d3dx9_40.spec index 13405ad8909d..d5e39385847a 100644 --- a/dlls/d3dx9_40/d3dx9_40.spec +++ b/dlls/d3dx9_40/d3dx9_40.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -287,9 +287,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_41/Makefile.in b/dlls/d3dx9_41/Makefile.in index bc02a280d339..894b584a4014 100644 --- a/dlls/d3dx9_41/Makefile.in +++ b/dlls/d3dx9_41/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=41 +EXTRADEFS = -DD3DX_SDK_VERSION=41 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_41.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_41/d3dx9_41.spec b/dlls/d3dx9_41/d3dx9_41.spec index 13405ad8909d..d5e39385847a 100644 --- a/dlls/d3dx9_41/d3dx9_41.spec +++ b/dlls/d3dx9_41/d3dx9_41.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -287,9 +287,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_42/Makefile.in b/dlls/d3dx9_42/Makefile.in index 5efa6cc00cd0..61c92735f008 100644 --- a/dlls/d3dx9_42/Makefile.in +++ b/dlls/d3dx9_42/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=42 +EXTRADEFS = -DD3DX_SDK_VERSION=42 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_42.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -22,8 +23,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_42/d3dx9_42.spec b/dlls/d3dx9_42/d3dx9_42.spec index 1f4cf67c7b24..47129bc6ed11 100644 --- a/dlls/d3dx9_42/d3dx9_42.spec +++ b/dlls/d3dx9_42/d3dx9_42.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -280,9 +280,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_43/Makefile.in b/dlls/d3dx9_43/Makefile.in index 1d6618598761..f84d3843a4d2 100644 --- a/dlls/d3dx9_43/Makefile.in +++ b/dlls/d3dx9_43/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=43 +EXTRADEFS = -DD3DX_SDK_VERSION=43 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_43.dll IMPORTLIB = d3dx9_43 IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 @@ -10,6 +10,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ @@ -23,8 +24,6 @@ SOURCES = \ sprite.c \ surface.c \ texture.c \ - txc_compress_dxtn.c \ - txc_fetch_dxtn.c \ util.c \ version.rc \ volume.c \ diff --git a/dlls/d3dx9_43/d3dx9_43.spec b/dlls/d3dx9_43/d3dx9_43.spec index 1f4cf67c7b24..47129bc6ed11 100644 --- a/dlls/d3dx9_43/d3dx9_43.spec +++ b/dlls/d3dx9_43/d3dx9_43.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) @@ -280,9 +280,9 @@ @ stdcall D3DXSaveTextureToFileA(str long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(wstr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(str long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(wstr long ptr ptr ptr) @ stub D3DXSimplifyMesh(ptr ptr ptr ptr long long ptr) @ stdcall D3DXSphereBoundProbe(ptr float ptr ptr) @ stub D3DXSplitMesh(ptr ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/dbghelp/Makefile.in b/dlls/dbghelp/Makefile.in index 152ef80611a5..dd27e159f182 100644 --- a/dlls/dbghelp/Makefile.in +++ b/dlls/dbghelp/Makefile.in @@ -19,6 +19,7 @@ SOURCES = \ module.c \ msc.c \ path.c \ + pdb.c \ pe_module.c \ source.c \ stabs.c \ diff --git a/dlls/dbghelp/coff.c b/dlls/dbghelp/coff.c index 21b4f726dd36..d4d804d935e4 100644 --- a/dlls/dbghelp/coff.c +++ b/dlls/dbghelp/coff.c @@ -114,7 +114,7 @@ static int coff_add_file(struct CoffFileSet* coff_files, struct module* module, file = coff_files->files + coff_files->nfiles; file->startaddr = 0xffffffff; file->endaddr = 0; - file->compiland = symt_new_compiland(module, source_new(module, NULL, filename)); + file->compiland = symt_new_compiland(module, filename); file->linetab_offset = -1; file->linecnt = 0; file->entries = NULL; @@ -161,7 +161,6 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) int linetab_indx; const char* nampnt; int naux; - BOOL ret = FALSE; ULONG64 addr; TRACE("Processing COFF symbols...\n"); @@ -219,8 +218,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) */ const char* fn; - fn = source_get(msc_dbg->module, - coff_files.files[curr_file_idx].compiland->source); + fn = coff_files.files[curr_file_idx].compiland->filename; TRACE("Duplicating sect from %s: %lx %x %x %d %d\n", fn, aux->Section.Length, @@ -242,7 +240,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) else { TRACE("New text sect from %s: %lx %x %x %d %d\n", - source_get(msc_dbg->module, coff_files.files[curr_file_idx].compiland->source), + coff_files.files[curr_file_idx].compiland->filename, aux->Section.Length, aux->Section.NumberOfRelocations, aux->Section.NumberOfLinenumbers, @@ -281,12 +279,12 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) /* FIXME: was adding symbol to this_file ??? */ coff_add_symbol(&coff_files.files[curr_file_idx], - &symt_new_function(msc_dbg->module, - coff_files.files[curr_file_idx].compiland, + &symt_new_function(msc_dbg->module, + coff_files.files[curr_file_idx].compiland, nampnt, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value, 0 /* FIXME */, - NULL /* FIXME */)->symt); + 0 /* FIXME */, 0)->symt); continue; } @@ -317,15 +315,15 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) if (j < coff_files.nfiles) { coff_add_symbol(&coff_files.files[j], - &symt_new_function(msc_dbg->module, compiland, nampnt, + &symt_new_function(msc_dbg->module, compiland, nampnt, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value, - 0 /* FIXME */, NULL /* FIXME */)->symt); - } - else + 0 /* FIXME */, 0 /* FIXME */, 0)->symt); + } + else { - symt_new_function(msc_dbg->module, NULL, nampnt, + symt_new_function(msc_dbg->module, NULL, nampnt, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value, - 0 /* FIXME */, NULL /* FIXME */); + 0 /* FIXME */, 0 /* FIXME */, 0); } i += naux; continue; @@ -354,7 +352,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) loc.reg = 0; loc.offset = msc_dbg->module->module.BaseOfImage + base + coff_sym->Value; symt_new_global_variable(msc_dbg->module, NULL, nampnt, TRUE /* FIXME */, - loc, 0 /* FIXME */, NULL /* FIXME */); + loc, 0 /* FIXME */, 0 /* FIXME */); i += naux; continue; } @@ -378,7 +376,8 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) i += naux; } - if (coff_files.files != NULL) + if (coff_files.files == NULL) return FALSE; + if (SymGetOptions() & SYMOPT_LOAD_LINES) { /* * OK, we now should have a list of files, and we should have a list @@ -420,7 +419,7 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) { symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1], - coff_files.files[j].compiland->source, + source_new(msc_dbg->module, NULL, coff_files.files[j].compiland->filename), linepnt->Linenumber, msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress); } @@ -436,15 +435,13 @@ BOOL coff_process_info(const struct msc_debug_info* msc_dbg) HeapFree(GetProcessHeap(), 0, coff_files.files[j].entries); } HeapFree(GetProcessHeap(), 0, coff_files.files); - msc_dbg->module->module.SymType = SymCoff; - /* FIXME: we could have a finer grain here */ - msc_dbg->module->module.LineNumbers = TRUE; - msc_dbg->module->module.GlobalSymbols = TRUE; - msc_dbg->module->module.TypeInfo = FALSE; - msc_dbg->module->module.SourceIndexed = TRUE; - msc_dbg->module->module.Publics = TRUE; - ret = TRUE; } - - return ret; + msc_dbg->module->module.SymType = SymCoff; + + msc_dbg->module->module.LineNumbers = !!(SymGetOptions() & SYMOPT_LOAD_LINES); + msc_dbg->module->module.GlobalSymbols = TRUE; + msc_dbg->module->module.TypeInfo = FALSE; + msc_dbg->module->module.SourceIndexed = TRUE; + msc_dbg->module->module.Publics = TRUE; + return TRUE; } diff --git a/dlls/dbghelp/cpu_i386.c b/dlls/dbghelp/cpu_i386.c index a322dfcdda32..42e4c8820094 100644 --- a/dlls/dbghelp/cpu_i386.c +++ b/dlls/dbghelp/cpu_i386.c @@ -95,8 +95,7 @@ static BOOL fetch_next_frame32(struct cpu_stack_walk* csw, union ctx *pcontext, DWORD_PTR curr_pc) { DWORD64 xframe; - struct pdb_cmd_pair cpair[4]; - DWORD val32; + DWORD val32; WOW64_CONTEXT *context = &pcontext->x86; if (dwarf2_virtual_unwind(csw, curr_pc, pcontext, &xframe)) @@ -104,12 +103,9 @@ static BOOL fetch_next_frame32(struct cpu_stack_walk* csw, context->Esp = xframe; return TRUE; } - cpair[0].name = "$ebp"; cpair[0].pvalue = &context->Ebp; - cpair[1].name = "$esp"; cpair[1].pvalue = &context->Esp; - cpair[2].name = "$eip"; cpair[2].pvalue = &context->Eip; - cpair[3].name = NULL; cpair[3].pvalue = NULL; - if (!pdb_virtual_unwind(csw, curr_pc, pcontext, cpair)) + if (!pdb_virtual_unwind(csw, curr_pc, pcontext) && + !old_pdb_virtual_unwind(csw, curr_pc, pcontext)) { /* do a simple unwind using ebp * we assume a "regular" prologue in the function has been used diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index 5a023152ec41..a46d052b8c78 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -717,12 +717,15 @@ BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr) BOOL WINAPI SymSetScopeFromIndex(HANDLE hProcess, ULONG64 addr, DWORD index) { struct module_pair pair; + symref_t symref; struct symt* sym; TRACE("(%p %#I64x %lu)\n", hProcess, addr, index); if (!module_init_pair(&pair, hProcess, addr)) return FALSE; - sym = symt_index2ptr(pair.effective, index); + symref = symt_index_to_symref(pair.effective, index); + if (!symt_is_symref_ptr(symref)) return FALSE; + sym = (struct symt*)symref; if (!symt_check_tag(sym, SymTagFunction)) return FALSE; pair.pcs->localscope_pc = ((struct symt_function*)sym)->ranges[0].low; /* FIXME of FuncDebugStart when it exists? */ @@ -761,6 +764,7 @@ BOOL WINAPI SymSetScopeFromInlineContext(HANDLE hProcess, ULONG64 addr, DWORD in } } +#ifndef _WIN64 /****************************************************************** * reg_cb64to32 (internal) * @@ -806,6 +810,7 @@ static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, U } return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user); } +#endif /****************************************************************** * pcs_callback (internal) @@ -874,17 +879,19 @@ static BOOL sym_register_cb(HANDLE hProcess, return TRUE; } +#ifndef _WIN64 /*********************************************************************** * SymRegisterCallback (DBGHELP.@) */ -BOOL WINAPI SymRegisterCallback(HANDLE hProcess, +BOOL WINAPI SymRegisterCallback(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK CallbackFunction, PVOID UserContext) { - TRACE("(%p, %p, %p)\n", + TRACE("(%p, %p, %p)\n", hProcess, CallbackFunction, UserContext); return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE); } +#endif /*********************************************************************** * SymRegisterCallback64 (DBGHELP.@) diff --git a/dlls/dbghelp/dbghelp.spec b/dlls/dbghelp/dbghelp.spec index a89c2c1d86b7..c9ae3bbb73c3 100644 --- a/dlls/dbghelp/dbghelp.spec +++ b/dlls/dbghelp/dbghelp.spec @@ -2,7 +2,8 @@ @ stub DbgHelpCreateUserDumpW @ stdcall EnumDirTree(long str str ptr ptr ptr) @ stdcall EnumDirTreeW(long wstr wstr ptr ptr ptr) -@ stdcall EnumerateLoadedModules(long ptr ptr) +@ stdcall -arch=win32 EnumerateLoadedModules(long ptr ptr) +@ stdcall -arch=win64 EnumerateLoadedModules(long ptr ptr) EnumerateLoadedModules64 @ stdcall EnumerateLoadedModules64(long ptr ptr) @ stdcall EnumerateLoadedModulesEx(long ptr ptr) EnumerateLoadedModules64 @ stdcall EnumerateLoadedModulesExW(long ptr ptr) EnumerateLoadedModulesW64 @@ -30,7 +31,8 @@ @ stdcall MiniDumpWriteDump(ptr long ptr long ptr ptr ptr) @ stdcall SearchTreeForFile(str str ptr) @ stdcall SearchTreeForFileW(wstr wstr ptr) -@ stdcall StackWalk(long long long ptr ptr ptr ptr ptr ptr) +@ stdcall -arch=win32 StackWalk(long long long ptr ptr ptr ptr ptr ptr) +@ stdcall -arch=win64 StackWalk(long long long ptr ptr ptr ptr ptr ptr) StackWalk64 @ stdcall StackWalk64(long long long ptr ptr ptr ptr ptr ptr) @ stdcall StackWalkEx(long long long ptr ptr ptr ptr ptr ptr long) @ stub SymAddSourceStream @@ -60,10 +62,12 @@ @ stdcall SymEnumTypesByName(ptr int64 str ptr ptr) @ stdcall SymEnumTypesByNameW(ptr int64 wstr ptr ptr) @ stdcall SymEnumTypesW(ptr int64 ptr ptr) -@ stdcall SymEnumerateModules(long ptr ptr) +@ stdcall -arch=win32 SymEnumerateModules(long ptr ptr) +@ stdcall -arch=win64 SymEnumerateModules(long ptr ptr) SymEnumerateModules64 @ stdcall SymEnumerateModules64(long ptr ptr) @ stdcall SymEnumerateModulesW64(long ptr ptr) -@ stdcall SymEnumerateSymbols(long long ptr ptr) +@ stdcall -arch=win32 SymEnumerateSymbols(long long ptr ptr) +@ stdcall -arch=win64 SymEnumerateSymbols(long int64 ptr ptr) SymEnumerateSymbols64 @ stdcall SymEnumerateSymbols64(long int64 ptr ptr) @ stub SymEnumerateSymbolsW @ stub SymEnumerateSymbolsW64 @@ -83,31 +87,40 @@ @ stdcall SymFromNameW(long wstr ptr) @ stub SymFromToken @ stub SymFromTokenW -@ stdcall SymFunctionTableAccess(long long) +@ stdcall -arch=win32 SymFunctionTableAccess(long long) +@ stdcall -arch=win64 SymFunctionTableAccess(long int64) SymFunctionTableAccess64 @ stdcall SymFunctionTableAccess64(long int64) @ stub SymGetFileLineOffsets64 @ stub SymGetHomeDirectory @ stub SymGetHomeDirectoryW @ stdcall SymGetExtendedOption(long) -@ stdcall SymGetLineFromAddr(long long ptr ptr) +@ stdcall -arch=win32 SymGetLineFromAddr(long long ptr ptr) +@ stdcall -arch=win64 SymGetLineFromAddr(long int64 ptr ptr) SymGetLineFromAddr64 @ stdcall SymGetLineFromAddr64(long int64 ptr ptr) +@ stub SymGetLineFromAddrW @ stdcall SymGetLineFromAddrW64(long int64 ptr ptr) @ stdcall SymGetLineFromInlineContext(long int64 long int64 ptr ptr) @ stdcall SymGetLineFromInlineContextW(long int64 long int64 ptr ptr) -@ stdcall SymGetLineFromName(long str str long ptr ptr) +@ stdcall -arch=win32 SymGetLineFromName(long str str long ptr ptr) +@ stdcall -arch=win64 SymGetLineFromName(long str str long ptr ptr) SymGetLineFromName64 @ stdcall SymGetLineFromName64(long str str long ptr ptr) @ stdcall SymGetLineFromNameW64(long wstr wstr long ptr ptr) -@ stdcall SymGetLineNext(long ptr) +@ stdcall -arch=win32 SymGetLineNext(long ptr) +@ stdcall -arch=win64 SymGetLineNext(long ptr) SymGetLineNext64 @ stdcall SymGetLineNext64(long ptr) @ stdcall SymGetLineNextW64(long ptr) -@ stdcall SymGetLinePrev(long ptr) +@ stdcall -arch=win32 SymGetLinePrev(long ptr) +@ stdcall -arch=win64 SymGetLinePrev(long ptr) SymGetLinePrev64 @ stdcall SymGetLinePrev64(long ptr) @ stdcall SymGetLinePrevW64(long ptr) -@ stdcall SymGetModuleBase(long long) +@ stdcall -arch=win32 SymGetModuleBase(long long) +@ stdcall -arch=win64 SymGetModuleBase(long int64) SymGetModuleBase64 @ stdcall SymGetModuleBase64(long int64) -@ stdcall SymGetModuleInfo(long long ptr) +@ stdcall -arch=win32 SymGetModuleInfo(long ptr ptr) +@ stdcall -arch=win64 SymGetModuleInfo(long int64 ptr) SymGetModuleInfo64 @ stdcall SymGetModuleInfo64(long int64 ptr) -@ stdcall SymGetModuleInfoW(long long ptr) +@ stdcall -arch=win32 SymGetModuleInfoW(long long ptr) +@ stdcall -arch=win64 SymGetModuleInfoW(long int64 ptr) SymGetModuleInfoW64 @ stdcall SymGetModuleInfoW64(long int64 ptr) @ stub SymGetOmapBlockBase @ stdcall SymGetOptions() @@ -123,13 +136,17 @@ @ stub SymGetSourceFileW @ stub SymGetSourceVarFromToken @ stub SymGetSourceVarFromTokenW -@ stdcall SymGetSymFromAddr(long long ptr ptr) +@ stdcall -arch=win32 SymGetSymFromAddr(long long ptr ptr) +@ stdcall -arch=win64 SymGetSymFromAddr(long int64 ptr ptr) SymGetSymFromAddr64 @ stdcall SymGetSymFromAddr64(long int64 ptr ptr) -@ stdcall SymGetSymFromName(long str ptr) +@ stdcall -arch=win32 SymGetSymFromName(long str ptr) +@ stdcall -arch=win64 SymGetSymFromName(long str ptr) SymGetSymFromName64 @ stdcall SymGetSymFromName64(long str ptr) -@ stdcall SymGetSymNext(long ptr) +@ stdcall -arch=win32 SymGetSymNext(long ptr) +@ stdcall -arch=win64 SymGetSymNext(long ptr) SymGetSymNext64 @ stdcall SymGetSymNext64(long ptr) -@ stdcall SymGetSymPrev(long ptr) +@ stdcall -arch=win32 SymGetSymPrev(long ptr) +@ stdcall -arch=win64 SymGetSymPrev(long ptr) SymGetSymPrev64 @ stdcall SymGetSymPrev64(long ptr) @ stub SymGetSymbolFile @ stub SymGetSymbolFileW @@ -140,7 +157,8 @@ @ stub SymGetUnwindInfo @ stdcall SymInitialize(long str long) @ stdcall SymInitializeW(long wstr long) -@ stdcall SymLoadModule(long long str str long long) +@ stdcall -arch=win32 SymLoadModule(long long str str long long) +@ stdcall -arch=win64 SymLoadModule(long long str str int64 long) SymLoadModule64 @ stdcall SymLoadModule64(long long str str int64 long) @ stdcall SymLoadModuleEx(long long str str int64 long ptr long) @ stdcall SymLoadModuleExW(long long wstr wstr int64 long ptr long) @@ -155,10 +173,12 @@ @ stub SymPrevW @ stdcall SymQueryInlineTrace(long int64 long int64 int64 ptr ptr) @ stdcall SymRefreshModuleList(long) -@ stdcall SymRegisterCallback(long ptr ptr) +@ stdcall -arch=win32 SymRegisterCallback(long ptr ptr) +@ stdcall -arch=win64 SymRegisterCallback(long ptr ptr) SymRegisterCallback64 @ stdcall SymRegisterCallback64(long ptr int64) @ stdcall SymRegisterCallbackW64(long ptr int64) -@ stdcall SymRegisterFunctionEntryCallback(ptr ptr ptr) +@ stdcall -arch=win32 SymRegisterFunctionEntryCallback(long ptr ptr) +@ stdcall -arch=win64 SymRegisterFunctionEntryCallback(long ptr ptr) SymRegisterFunctionEntryCallback64 @ stdcall SymRegisterFunctionEntryCallback64(ptr ptr int64) @ stdcall SymSearch(long int64 long long str int64 ptr ptr long) @ stdcall SymSearchW(long int64 long long wstr int64 ptr ptr long) @@ -191,9 +211,11 @@ @ stub SymSrvStoreSupplementW # @ stub SymSetSymWithAddr64 no longer present ?? @ stub SymSetSymWithAddr64 -@ stdcall SymUnDName(ptr str long) +@ stdcall -arch=win32 SymUnDName(ptr str long) +@ stdcall -arch=win64 SymUnDName(ptr str long) SymUnDName64 @ stdcall SymUnDName64(ptr str long) -@ stdcall SymUnloadModule(long long) +@ stdcall -arch=win32 SymUnloadModule(long long) +@ stdcall -arch=win64 SymUnloadModule(long int64) SymUnloadModule64 @ stdcall SymUnloadModule64(long int64) @ stdcall UnDecorateSymbolName(str ptr long long) @ stdcall UnDecorateSymbolNameW(wstr ptr long long) diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 8def6a7dae6f..d16468dc07ad 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -31,6 +31,7 @@ #include "winnls.h" #include "wine/list.h" #include "wine/rbtree.h" +#include "wine/debug.h" #include "cvconst.h" @@ -45,6 +46,7 @@ void* pool_alloc(struct pool* a, size_t len) __WINE_ALLOC_SIZE(2) __WINE_MALL void* pool_realloc(struct pool* a, void* ptr, size_t len) __WINE_ALLOC_SIZE(3); char* pool_strdup(struct pool* a, const char* str) __WINE_MALLOC; WCHAR* pool_wcsdup(struct pool* a, const WCHAR* str) __WINE_MALLOC; +void pool_free(struct pool* a, void* ptr); struct vector { @@ -181,11 +183,13 @@ static inline BOOL symt_check_tag(const struct symt* s, enum SymTagEnum tag) return s && s->tag == tag; } +typedef ULONG_PTR symref_t; + /* lexical tree */ struct symt_block { struct symt symt; - struct symt* container; /* block, or func */ + symref_t container; /* block, or func */ struct vector vchildren; /* sub-blocks & local variables */ unsigned num_ranges; struct addr_range ranges[]; @@ -201,9 +205,9 @@ struct symt_module /* in fact any of .exe, .dll... */ struct symt_compiland { struct symt symt; - struct symt_module* container; /* symt_module */ + symref_t container; /* symt_module */ ULONG_PTR address; - unsigned source; + const char *filename; struct vector vchildren; /* global variables & functions */ void* user; /* when debug info provider needs to store information */ }; @@ -213,8 +217,8 @@ struct symt_data struct symt symt; struct hash_table_elt hash_elt; /* if global symbol */ enum DataKind kind; - struct symt* container; - struct symt* type; + symref_t container; + symref_t type; union /* depends on kind */ { /* DataIs{Global, FileStatic, StaticLocal}: @@ -290,11 +294,12 @@ struct symt_function { struct symt symt; /* SymTagFunction or SymTagInlineSite */ struct hash_table_elt hash_elt; /* if global symbol, inline site */ - struct symt* container; /* compiland (for SymTagFunction) or function (for SymTagInlineSite) */ - struct symt* type; /* points to function_signature */ + symref_t container; /* compiland (for SymTagFunction) or function (for SymTagInlineSite) */ + symref_t type; /* points to function_signature */ struct vector vlines; struct vector vchildren; /* locals, params, blocks, start/end, labels, inline sites */ struct symt_function* next_inlinesite;/* linked list of inline sites in this function */ + DWORD_PTR user; /* free to use by debug info backends */ unsigned num_ranges; struct addr_range ranges[]; }; @@ -303,7 +308,7 @@ struct symt_hierarchy_point { struct symt symt; /* either SymTagFunctionDebugStart, SymTagFunctionDebugEnd, SymTagLabel */ struct hash_table_elt hash_elt; /* if label (and in compiland's hash table if global) */ - struct symt* parent; /* symt_function or symt_compiland */ + symref_t container; /* symt_function or symt_compiland */ struct location loc; }; @@ -311,8 +316,8 @@ struct symt_public { struct symt symt; struct hash_table_elt hash_elt; - struct symt* container; /* compiland */ - BOOL is_function; + symref_t container; /* compiland */ + BOOL is_function; ULONG_PTR address; ULONG_PTR size; }; @@ -321,7 +326,7 @@ struct symt_thunk { struct symt symt; struct hash_table_elt hash_elt; - struct symt* container; /* compiland */ + symref_t container; /* compiland */ ULONG_PTR address; ULONG_PTR size; THUNK_ORDINAL ordinal; /* FIXME: doesn't seem to be accessible */ @@ -385,7 +390,7 @@ struct symt_typedef { struct symt symt; struct hash_table_elt hash_elt; - struct symt* type; + symref_t type; }; struct symt_udt @@ -410,23 +415,71 @@ enum format_info DFI_MACHO, DFI_DWARF, DFI_PDB, + DFI_OLD_PDB, DFI_LAST }; -struct module_format +struct lineinfo_t { - struct module* module; - void (*remove)(struct process* pcs, struct module_format* modfmt); - void (*loc_compute)(struct process* pcs, - const struct module_format* modfmt, + BOOL unicode; + PVOID key; + DWORD line_number; + union + { + CHAR* file_nameA; + WCHAR* file_nameW; + }; + DWORD64 address; +}; + +struct module_format; +enum method_result {MR_SUCCESS, MR_FAILURE, MR_NOT_FOUND}; +struct module_format_vtable +{ + /* module handling */ + void (*remove)(struct module_format* modfmt); + + /* index management */ + enum method_result (*request_symref_t)(struct module_format *modfmt, symref_t ref, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data); + enum method_result (*lookup_by_address)(struct module_format *modfmt, DWORD_PTR address, symref_t *symref); + enum method_result (*lookup_by_name)(struct module_format *modfmt, const char *name, symref_t *symref); + enum method_result (*enumerate_symbols)(struct module_format *modfmt, const WCHAR *match, BOOL (*cb)(symref_t, const char *, void *), void *user); + + /* types management */ + enum method_result (*find_type)(struct module_format *modfmt, const char *name, symref_t *ref); + enum method_result (*enumerate_types)(struct module_format *modfmt, BOOL (*cb)(symref_t, const char *, void*), void *user); + + /* stack walk */ + void (*loc_compute)(const struct module_format* modfmt, const struct symt_function* func, struct location* loc); + /* line information */ + enum method_result (*get_line_from_address)(struct module_format *modfmt, + DWORD64 address, struct lineinfo_t *line_info); + enum method_result (*advance_line_info)(struct module_format *modfmt, + struct lineinfo_t *line_info, BOOL forward); + enum method_result (*enumerate_lines)(struct module_format *modfmt, const WCHAR* compiland_regex, + const WCHAR *source_file_regex, PSYM_ENUMLINES_CALLBACK cb, void *user); + enum method_result (*get_line_from_inlined_address)(struct module_format *modfmt, struct symt_function *inlined, + DWORD64 address, struct lineinfo_t *line_info); + + /* source files information */ + enum method_result (*enumerate_sources)(struct module_format *modfmt, const WCHAR *sourcefile_regex, + PSYM_ENUMSOURCEFILES_CALLBACKW cb, void *user); +}; + +struct module_format +{ + struct module* module; + const struct module_format_vtable* vtable; + union { struct elf_module_info* elf_info; struct dwarf2_module_info_s* dwarf2_info; struct pe_module_info* pe_info; - struct macho_module_info* macho_info; + struct macho_module_info* macho_info; + struct old_pdb_module_info* old_pdb_info; struct pdb_module_info* pdb_info; } u; }; @@ -452,6 +505,12 @@ struct module /* specific information for debug types */ struct module_format* format_info[DFI_LAST]; unsigned debug_format_bitmask; + /* Hack for fast symdef deref... + * Note: if ever we need another backend with dedicated symref_t support, + * we could always use the 3 non-zero lower bits of symref_t to match a + * debug backend. + */ + struct module_format *ops_symref_modfmt; /* memory allocation pool */ struct pool pool; @@ -469,7 +528,6 @@ struct module /* types */ struct hash_table ht_types; - struct vector vtypes; /* source files */ unsigned sources_used; @@ -478,6 +536,29 @@ struct module struct wine_rb_tree sources_offsets_tree; }; +struct module_format_vtable_iterator +{ + int dfi; + struct module_format *modfmt; +}; + +#define MODULE_FORMAT_VTABLE_INDEX(f) (offsetof(struct module_format_vtable, f) / sizeof(void*)) + +static inline BOOL module_format_vtable_iterator_next(struct module *module, struct module_format_vtable_iterator *iter, size_t method_index) +{ + for ( ; iter->dfi < DFI_LAST; iter->dfi++) + { + iter->modfmt = module->format_info[iter->dfi]; + if (iter->modfmt && ((const void**)iter->modfmt->vtable)[method_index]) + { + iter->dfi++; + return TRUE; + } + } + iter->modfmt = NULL; + return FALSE; +} + typedef BOOL (*enum_modules_cb)(const WCHAR*, ULONG_PTR addr, void* user); struct loader_ops @@ -753,14 +834,9 @@ extern BOOL pe_load_debug_directory(const struct process* pcs, const IMAGE_DEBUG_DIRECTORY* dbg, int nDbg); extern DWORD msc_get_file_indexinfo(void* image, const IMAGE_DEBUG_DIRECTORY* dbgdir, DWORD size, SYMSRV_INDEX_INFOW* info); -struct pdb_cmd_pair { - const char* name; - DWORD* pvalue; -}; -extern BOOL pdb_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, - union ctx *context, struct pdb_cmd_pair *cpair); -extern DWORD pdb_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info); -extern DWORD dbg_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info); +extern DWORD pdb_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info); +extern DWORD dbg_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info); +extern BOOL old_pdb_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, union ctx *context); /* path.c */ extern BOOL path_find_symbol_file(const struct process *pcs, const struct module *module, @@ -773,6 +849,14 @@ extern BOOL search_unix_path(const WCHAR *name, const WCHAR *path, BOOL (*match) extern const WCHAR* file_name(const WCHAR* str); extern const char* file_nameA(const char* str); +/* pdb.c */ +extern BOOL pdb_init_modfmt(const struct process *pcs, const struct msc_debug_info *msc_dbg, + const WCHAR *filename, BOOL *has_linenumber_info); +extern BOOL pdb_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, union ctx *context); +struct _PDB_FPO_DATA; +extern BOOL pdb_fpo_unwind_parse_cmd_string(struct cpu_stack_walk* csw, struct _PDB_FPO_DATA* fpoext, + const char* cmd, WOW64_CONTEXT *context); + /* pe_module.c */ extern BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth, BOOL* is_builtin); extern struct module* @@ -795,6 +879,7 @@ extern BOOL pe_has_buildid_debug(struct image_file_map *fmap, GUID *guid extern unsigned source_new(struct module* module, const char* basedir, const char* source); extern const char* source_get(const struct module* module, unsigned idx); extern int source_rb_compare(const void *key, const struct wine_rb_entry *entry); +extern char *source_build_path(const char *base, const char *name); /* stabs.c */ typedef void (*stabs_def_cb)(struct module* module, ULONG_PTR load_offset, @@ -827,6 +912,7 @@ extern BOOL symt_get_address(const struct symt* type, ULONG64* addr); extern int __cdecl symt_cmp_addr(const void* p1, const void* p2); extern void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si); extern void symbol_setname(SYMBOL_INFO* si, const char* name); +extern BOOL symt_match_stringAW(const char *string, const WCHAR *re, BOOL _case); extern struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr); extern struct symt_ht* @@ -834,47 +920,48 @@ extern struct symt_ht* extern struct symt_module* symt_new_module(struct module* module); extern struct symt_compiland* - symt_new_compiland(struct module* module, unsigned src_idx); + symt_new_compiland(struct module* module, const char *filename); extern struct symt_public* - symt_new_public(struct module* module, - struct symt_compiland* parent, + symt_new_public(struct module* module, + struct symt_compiland* parent, const char* typename, BOOL is_function, ULONG_PTR address, unsigned size); extern struct symt_data* - symt_new_global_variable(struct module* module, + symt_new_global_variable(struct module* module, struct symt_compiland* parent, const char* name, unsigned is_static, struct location loc, ULONG_PTR size, - struct symt* type); + symref_t type); extern struct symt_function* symt_new_function(struct module* module, struct symt_compiland* parent, const char* name, ULONG_PTR addr, ULONG_PTR size, - struct symt* type); + symref_t type, DWORD_PTR user); extern struct symt_function* symt_new_inlinesite(struct module* module, struct symt_function* func, struct symt* parent, const char* name, - struct symt* type, + symref_t type, + DWORD_PTR user, unsigned num_ranges); extern void symt_add_func_line(struct module* module, struct symt_function* func, unsigned source_idx, int line_num, ULONG_PTR offset); extern struct symt_data* - symt_add_func_local(struct module* module, - struct symt_function* func, + symt_add_func_local(struct module* module, + struct symt_function* func, enum DataKind dt, const struct location* loc, struct symt_block* block, - struct symt* type, const char* name); + symref_t, const char* name); extern struct symt_data* symt_add_func_constant(struct module* module, struct symt_function* func, struct symt_block* block, - struct symt* type, const char* name, VARIANT* v); + symref_t, const char* name, VARIANT* v); extern struct symt_block* symt_open_func_block(struct module* module, struct symt_function* func, @@ -898,22 +985,46 @@ extern struct symt_thunk* extern struct symt_data* symt_new_constant(struct module* module, struct symt_compiland* parent, - const char* name, struct symt* type, + const char* name, symref_t type, const VARIANT* v); extern struct symt_hierarchy_point* symt_new_label(struct module* module, struct symt_compiland* compiland, const char* name, ULONG_PTR address); -extern struct symt* symt_index2ptr(struct module* module, DWORD id); -extern DWORD symt_ptr2index(struct module* module, const struct symt* sym); +static inline BOOL symt_is_symref_ptr(symref_t ref) {return (ref & 3) == 0;} +static inline symref_t + symt_ptr_to_symref(const struct symt *symt) {return (ULONG_PTR)symt;} +static inline struct symt* + _symt_symref_to_ptr(const char *file, unsigned lineno, symref_t symref) +{ + if (!symt_is_symref_ptr(symref)) + { + MESSAGE("%s:%u can't convert symref to ptr\n", file, lineno); + return NULL; + } + return (struct symt*)symref; +} +/* this function shall be used with care as not all symref:s are actual pointers */ +#define SYMT_SYMREF_TO_PTR(s) _symt_symref_to_ptr(__FILE__, __LINE__, (s)) +extern symref_t symt_index_to_symref(struct module* module, DWORD id); +extern DWORD symt_symref_to_index(struct module* module, symref_t sym); +static inline DWORD symt_ptr_to_index(struct module *module, const struct symt *symt) {return symt_symref_to_index(module, symt_ptr_to_symref(symt));} + extern struct symt_custom* symt_new_custom(struct module* module, const char* name, DWORD64 addr, DWORD size); +extern BOOL lineinfo_set_nameA(struct process* pcs, struct lineinfo_t* intl, char* str); /* type.c */ extern void symt_init_basic(struct module* module); +extern BOOL symt_get_info_raw(struct module* module, const struct symt* type, + IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo); extern BOOL symt_get_info(struct module* module, const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo); +extern BOOL symt_get_info_from_index(struct module* module, DWORD index, + IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo); +extern BOOL symt_get_info_from_symref(struct module* module, symref_t type, + IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo); extern struct symt_basic* symt_get_basic(enum BasicType, unsigned size); extern struct symt_udt* @@ -921,17 +1032,17 @@ extern struct symt_udt* unsigned size, enum UdtKind kind); extern BOOL symt_set_udt_size(struct module* module, struct symt_udt* type, unsigned size); -extern BOOL symt_add_udt_element(struct module* module, - struct symt_udt* udt_type, +extern BOOL symt_add_udt_element(struct module* module, + struct symt_udt* udt_type, const char* name, - struct symt* elt_type, unsigned offset, + symref_t elt_type, unsigned offset, unsigned bit_offset, unsigned bit_size); extern struct symt_enum* symt_new_enum(struct module* module, const char* typename, struct symt* basetype); -extern BOOL symt_add_enum_element(struct module* module, - struct symt_enum* enum_type, - const char* name, int value); +extern BOOL symt_add_enum_element(struct module* module, + struct symt_enum* enum_type, + const char* name, const VARIANT *value); extern struct symt_array* symt_new_array(struct module* module, int min, DWORD count, struct symt* base, struct symt* index); @@ -943,11 +1054,11 @@ extern BOOL symt_add_function_signature_parameter(struct module* module, struct symt_function_signature* sig, struct symt* param); extern struct symt_pointer* - symt_new_pointer(struct module* module, + symt_new_pointer(struct module* module, struct symt* ref_type, ULONG_PTR size); extern struct symt_typedef* - symt_new_typedef(struct module* module, struct symt* ref, + symt_new_typedef(struct module* module, symref_t ref, const char* name); extern struct symt_function* symt_find_lowest_inlined(struct symt_function* func, DWORD64 addr); diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 84e861890d57..12b7f28a22bd 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -128,6 +128,7 @@ struct attribute ULONG_PTR uvalue; ULONGLONG lluvalue; LONG_PTR svalue; + LONGLONG llsvalue; const char* string; struct dwarf2_block block; } u; @@ -282,18 +283,19 @@ static DWORD64 dwarf2_parse_u8(dwarf2_traverse_context_t* ctx) return uvalue; } -static ULONG_PTR dwarf2_get_leb128_as_unsigned(const unsigned char* ptr, const unsigned char** end) +static ULONG64 dwarf2_get_leb128_as_unsigned(const unsigned char* ptr, const unsigned char** end) { - ULONG_PTR ret = 0; + ULONG64 ret = 0; unsigned char byte; unsigned shift = 0; do { byte = dwarf2_get_byte(ptr++); - ret |= (byte & 0x7f) << shift; + ret |= (ULONG64)(byte & 0x7f) << shift; shift += 7; } while (byte & 0x80); + if ((ret >> (shift - 7)) != (byte & 0x7F)) FIXME("Overflow in LEB128 encoding\n"); if (end) *end = ptr; return ret; @@ -301,47 +303,45 @@ static ULONG_PTR dwarf2_get_leb128_as_unsigned(const unsigned char* ptr, const u static ULONG_PTR dwarf2_leb128_as_unsigned(dwarf2_traverse_context_t* ctx) { - ULONG_PTR ret; + ULONG64 ret; assert(ctx); ret = dwarf2_get_leb128_as_unsigned(ctx->data, &ctx->data); - + if (ret != (ULONG_PTR)ret) WARN("Dropping bits from LEB128 value\n"); return ret; } -static LONG_PTR dwarf2_get_leb128_as_signed(const unsigned char* ptr, const unsigned char** end) +static LONG64 dwarf2_get_leb128_as_signed(const unsigned char* ptr, const unsigned char** end) { - LONG_PTR ret = 0; + ULONG64 ret = 0; unsigned char byte; unsigned shift = 0; - const unsigned size = sizeof(int) * 8; do { byte = dwarf2_get_byte(ptr++); - ret |= (byte & 0x7f) << shift; + ret |= (ULONG64)(byte & 0x7f) << shift; shift += 7; } while (byte & 0x80); - if (end) *end = ptr; - /* as spec: sign bit of byte is 2nd high order bit (80x40) - * -> 0x80 is used as flag. - */ - if ((shift < size) && (byte & 0x40)) - { - ret |= - (1 << shift); - } + if (end) *end = ptr; + if ((shift < sizeof(ULONG64) * 8) && (byte & 0x40)) + /* as spec: sign bit of byte is 2nd high order bit (80x40) + * -> 0x80 is used as flag. + */ + ret |= ~(ULONG64)0 << shift; return ret; } static LONG_PTR dwarf2_leb128_as_signed(dwarf2_traverse_context_t* ctx) { - LONG_PTR ret = 0; + LONG64 ret = 0; assert(ctx); ret = dwarf2_get_leb128_as_signed(ctx->data, &ctx->data); + if (ret != (LONG_PTR)ret) WARN("Dropping bits from LEB128 value\n"); return ret; } @@ -609,16 +609,16 @@ static BOOL dwarf2_fill_attr(const dwarf2_parse_context_t* ctx, break; case DW_FORM_sdata: - attr->u.svalue = dwarf2_get_leb128_as_signed(data, NULL); + attr->u.llsvalue = dwarf2_get_leb128_as_signed(data, NULL); break; case DW_FORM_ref_udata: - attr->u.uvalue = ctx->ref_offset + dwarf2_get_leb128_as_unsigned(data, NULL); + attr->u.lluvalue = ctx->ref_offset + dwarf2_get_leb128_as_unsigned(data, NULL); TRACE("ref_udata<0x%Ix>\n", attr->u.uvalue); break; case DW_FORM_udata: - attr->u.uvalue = dwarf2_get_leb128_as_unsigned(data, NULL); + attr->u.lluvalue = dwarf2_get_leb128_as_unsigned(data, NULL); TRACE("udata<0x%Ix>\n", attr->u.uvalue); break; @@ -712,6 +712,141 @@ static BOOL dwarf2_fill_attr(const dwarf2_parse_context_t* ctx, return TRUE; } +static struct symt *symt_get_real_type(struct symt *symt) +{ + while (symt && symt->tag == SymTagTypedef) + symt = (struct symt*)(((struct symt_typedef*)symt)->type); + return symt; +} + +static BOOL dwarf2_fill_in_variant(struct module *module, VARIANT *v, const struct attribute *attr, struct symt *type) +{ + ULONG64 uinteger; + LONG64 sinteger; + enum BasicType bt = btInt; + + type = symt_get_real_type(type); + if (symt_check_tag(type, SymTagBaseType)) + bt = ((struct symt_basic*)type)->bt; + + /* data1, data2, data4 can hold either signed or unsigned values... + * so ensure proper extension of signed types... + */ + switch (attr->form) + { + case DW_FORM_data1: + uinteger = attr->u.uvalue; + sinteger = (char)(unsigned char)attr->u.uvalue; + break; + case DW_FORM_data2: + uinteger = attr->u.uvalue; + sinteger = (short)(unsigned short)attr->u.uvalue; + break; + case DW_FORM_data4: + uinteger = attr->u.uvalue; + sinteger = (int)(unsigned int)attr->u.uvalue; + break; + + case DW_FORM_udata: + case DW_FORM_data8: + sinteger = uinteger = attr->u.lluvalue; + break; + + case DW_FORM_sdata: + uinteger = sinteger = attr->u.llsvalue; + break; + + case DW_FORM_strp: + case DW_FORM_string: + /* FIXME: native doesn't report const strings from here !! + * however, the value of the string is in the code somewhere + */ + V_VT(v) = VT_BYREF; + V_BYREF(v) = pool_strdup(&module->pool, attr->u.string); + return TRUE; + break; + + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + case DW_FORM_exprloc: + V_VT(v) = VT_I4; + switch (attr->u.block.size) + { + case 1: V_I4(v) = *(BYTE*)attr->u.block.ptr; break; + case 2: V_I4(v) = *(USHORT*)attr->u.block.ptr; break; + case 4: V_I4(v) = *(DWORD*)attr->u.block.ptr; break; + default: + V_VT(v) = VT_BYREF; + V_BYREF(v) = pool_alloc(&module->pool, attr->u.block.size); + memcpy(V_BYREF(v), attr->u.block.ptr, attr->u.block.size); + } + return TRUE; + break; + case DW_FORM_sec_offset: + case DW_FORM_addr: + FIXME("Unexpected form %Ix\n", attr->form); + default: + V_VT(v) = VT_EMPTY; + return FALSE; + } + /* native always stores in the shortest format in variant */ + if (bt == btChar || bt == btInt || bt == btLong) + { + if (sinteger == (signed char)sinteger) + { + V_VT(v) = VT_I1; + V_I1(v) = sinteger; + } + if (sinteger == (short int)sinteger) + { + V_VT(v) = VT_I2; + V_I2(v) = sinteger; + } + else if (sinteger == (int)sinteger) + { + V_VT(v) = VT_I4; + V_I4(v) = sinteger; + } + else + { + V_VT(v) = VT_I8; + V_I8(v) = sinteger; + } + } + else if (bt == btUInt || bt == btULong || bt == btWChar) + { + if (uinteger == (unsigned char)uinteger) + { + V_VT(v) = VT_UI1; + V_UI1(v) = uinteger; + } + else if (uinteger == (unsigned short int)uinteger) + { + V_VT(v) = VT_UI2; + V_UI2(v) = uinteger; + } + else if (uinteger == (unsigned int)uinteger) + { + V_VT(v) = VT_UI4; + V_UI4(v) = uinteger; + } + else + { + V_VT(v) = VT_UI8; + V_UI8(v) = uinteger; + } + } + else + { + FIXME("Unexpected base type bt=%x for form=%Ix\n", bt, attr->form); + return FALSE; + } + + return TRUE; +} + static dwarf2_debug_info_t* dwarf2_jump_to_debug_info(struct attribute* attr); static BOOL dwarf2_find_attribute(const dwarf2_debug_info_t* di, @@ -1061,12 +1196,24 @@ static BOOL dwarf2_compute_location_attr(dwarf2_parse_context_t* ctx, return TRUE; } /* fall through */ - case DW_FORM_data1: case DW_FORM_data2: - case DW_FORM_udata: case DW_FORM_sdata: + case DW_FORM_data1: + case DW_FORM_data2: + loc->kind = loc_absolute; + loc->reg = 0; + loc->offset = xloc.u.uvalue; + return TRUE; + case DW_FORM_udata: loc->kind = loc_absolute; loc->reg = 0; + if (xloc.u.uvalue != xloc.u.lluvalue) WARN("Cropping integral value\n"); loc->offset = xloc.u.uvalue; return TRUE; + case DW_FORM_sdata: + loc->kind = loc_absolute; + loc->reg = 0; + if (xloc.u.svalue != xloc.u.llsvalue) WARN("Cropping integral value\n"); + loc->offset = xloc.u.svalue; + return TRUE; case DW_FORM_data8: if (ctx->head.version >= 4) { @@ -1285,12 +1432,14 @@ static BOOL dwarf2_fill_ranges(const dwarf2_debug_info_t* di, struct addr_range* { case DW_FORM_addr: break; + case DW_FORM_sdata: + case DW_FORM_udata: + if (high_pc.u.uvalue != high_pc.u.lluvalue) WARN("Cropping integral value\n"); + /* fall through */ case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: - case DW_FORM_sdata: - case DW_FORM_udata: /* From dwarf4 on, when FORM's class is constant, high_pc is an offset from low_pc */ high_pc.u.uvalue += low_pc.u.uvalue; break; @@ -1369,7 +1518,7 @@ static BOOL dwarf2_read_one_debug_info(dwarf2_parse_context_t* ctx, else di->data = NULL; if (abbrev->have_child) { - vector_init(&di->children, sizeof(dwarf2_debug_info_t*), 16); + vector_init(&di->children, sizeof(dwarf2_debug_info_t*), 0); while (traverse->data < traverse->end_data) { if (!dwarf2_read_one_debug_info(ctx, traverse, di, &child)) return FALSE; @@ -1501,7 +1650,7 @@ static struct symt* dwarf2_parse_typedef(dwarf2_debug_info_t* di) */ if ((is_c_language(di->unit_ctx) || is_cpp_language(di->unit_ctx)) && !strcmp(name.u.string, "WCHAR")) ref_type = &symt_get_basic(btWChar, 2)->symt; - di->symt = &symt_new_typedef(di->unit_ctx->module_ctx->module, ref_type, name.u.string)->symt; + di->symt = &symt_new_typedef(di->unit_ctx->module_ctx->module, symt_ptr_to_symref(ref_type), name.u.string)->symt; } if (dwarf2_get_di_children(di)) FIXME("Unsupported children\n"); return di->symt; @@ -1673,7 +1822,7 @@ static struct symt* dwarf2_parse_unspecified_type(dwarf2_debug_info_t* di) basic = &symt_get_basic(btVoid, 0)->symt; if (dwarf2_find_attribute(di, DW_AT_name, &name)) /* define the missing type as a typedef to void... */ - di->symt = &symt_new_typedef(di->unit_ctx->module_ctx->module, basic, name.u.string)->symt; + di->symt = &symt_new_typedef(di->unit_ctx->module_ctx->module, symt_ptr_to_symref(basic), name.u.string)->symt; else /* or use void if it doesn't even have a name */ di->symt = basic; @@ -1745,7 +1894,8 @@ static void dwarf2_parse_udt_member(dwarf2_debug_info_t* di, bit_offset.u.uvalue = nbytes.u.uvalue * 8 - bit_offset.u.uvalue - bit_size.u.uvalue; } else bit_offset.u.uvalue = 0; - symt_add_udt_element(di->unit_ctx->module_ctx->module, parent, name.u.string, elt_type, + symt_add_udt_element(di->unit_ctx->module_ctx->module, parent, name.u.string, + symt_ptr_to_symref(elt_type), loc.offset, bit_offset.u.uvalue, bit_size.u.uvalue); @@ -1838,14 +1988,22 @@ static struct symt* dwarf2_parse_udt_type(dwarf2_debug_info_t* di, static void dwarf2_parse_enumerator(dwarf2_debug_info_t* di, struct symt_enum* parent) { + VARIANT v; struct attribute name; struct attribute value; TRACE("%s\n", dwarf2_debug_di(di)); + V_VT(&v) = VT_EMPTY; + if (!dwarf2_find_attribute(di, DW_AT_name, &name)) return; - if (!dwarf2_find_attribute(di, DW_AT_const_value, &value)) value.u.svalue = 0; - symt_add_enum_element(di->unit_ctx->module_ctx->module, parent, name.u.string, value.u.svalue); + if (dwarf2_find_attribute(di, DW_AT_const_value, &value) && + symt_check_tag(parent->base_type, SymTagBaseType)) + { + if (!dwarf2_fill_in_variant(di->unit_ctx->module_ctx->module, &v, &value, parent->base_type)) + TRACE("Failed to get variant\n"); + } + symt_add_enum_element(di->unit_ctx->module_ctx->module, parent, name.u.string, &v); if (dwarf2_get_di_children(di)) FIXME("Unsupported children\n"); } @@ -1855,7 +2013,7 @@ static struct symt* dwarf2_parse_enumeration_type(dwarf2_debug_info_t* di) struct attribute name; struct attribute attrtype; dwarf2_debug_info_t*ditype; - struct symt* type; + struct symt* type = NULL; struct vector* children; dwarf2_debug_info_t*child; unsigned int i; @@ -1866,20 +2024,20 @@ static struct symt* dwarf2_parse_enumeration_type(dwarf2_debug_info_t* di) if (!dwarf2_find_attribute(di, DW_AT_name, &name)) name.u.string = NULL; if (dwarf2_find_attribute(di, DW_AT_type, &attrtype) && (ditype = dwarf2_jump_to_debug_info(&attrtype)) != NULL) - type = ditype->symt; - else /* no type found for this enumeration, construct it from size */ + type = symt_get_real_type(ditype->symt); + if (!type || type->tag != SymTagBaseType) /* no type found for this enumeration, construct it from size */ { struct attribute size; struct symt_basic* basetype; if (!dwarf2_find_attribute(di, DW_AT_byte_size, &size)) size.u.uvalue = 4; - - switch (size.u.uvalue) /* FIXME: that's wrong */ + switch (size.u.uvalue) { case 1: basetype = symt_get_basic(btInt, 1); break; case 2: basetype = symt_get_basic(btInt, 2); break; default: case 4: basetype = symt_get_basic(btInt, 4); break; + case 8: basetype = symt_get_basic(btInt, 8); break; } type = &basetype->symt; } @@ -1961,14 +2119,14 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, if (ext.u.uvalue) WARN("unexpected global inside a function\n"); symt_add_func_local(subpgm->ctx->module_ctx->module, subpgm->current_func, DataIsStaticLocal, &loc, subpgm->current_block, - param_type, dwarf2_get_cpp_name(di, name.u.string)); + symt_ptr_to_symref(param_type), dwarf2_get_cpp_name(di, name.u.string)); } else { symt_new_global_variable(subpgm->ctx->module_ctx->module, ext.u.uvalue ? NULL : subpgm->ctx->compiland, dwarf2_get_cpp_name(di, name.u.string), !ext.u.uvalue, - loc, 0, param_type); + loc, 0, symt_ptr_to_symref(param_type)); } break; default: @@ -1982,7 +2140,7 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, if (subpgm->current_func) symt_add_func_local(subpgm->ctx->module_ctx->module, subpgm->current_func, is_pmt ? DataIsParam : DataIsLocal, - &loc, subpgm->current_block, param_type, name.u.string); + &loc, subpgm->current_block, symt_ptr_to_symref(param_type), name.u.string); break; } } @@ -1990,71 +2148,21 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, { VARIANT v; - switch (value.form) - { - case DW_FORM_data1: - case DW_FORM_data2: - case DW_FORM_data4: - case DW_FORM_udata: - case DW_FORM_addr: - V_VT(&v) = VT_UI4; - V_UI4(&v) = value.u.uvalue; - break; - - case DW_FORM_data8: - case DW_FORM_sec_offset: - V_VT(&v) = VT_UI8; - V_UI8(&v) = value.u.lluvalue; - break; - - case DW_FORM_sdata: - V_VT(&v) = VT_I4; - V_I4(&v) = value.u.svalue; - break; - - case DW_FORM_strp: - case DW_FORM_string: - /* FIXME: native doesn't report const strings from here !! - * however, the value of the string is in the code somewhere - */ - V_VT(&v) = VT_BYREF; - V_BYREF(&v) = pool_strdup(&subpgm->ctx->module_ctx->module->pool, value.u.string); - break; - - case DW_FORM_block: - case DW_FORM_block1: - case DW_FORM_block2: - case DW_FORM_block4: - case DW_FORM_exprloc: - V_VT(&v) = VT_I4; - switch (value.u.block.size) - { - case 1: V_I4(&v) = *(BYTE*)value.u.block.ptr; break; - case 2: V_I4(&v) = *(USHORT*)value.u.block.ptr; break; - case 4: V_I4(&v) = *(DWORD*)value.u.block.ptr; break; - default: - V_VT(&v) = VT_BYREF; - V_BYREF(&v) = pool_alloc(&subpgm->ctx->module_ctx->module->pool, value.u.block.size); - memcpy(V_BYREF(&v), value.u.block.ptr, value.u.block.size); - } - break; - - default: + if (!dwarf2_fill_in_variant(subpgm->ctx->module_ctx->module, &v, &value, param_type)) FIXME("Unsupported form for const value %s (%Ix)\n", debugstr_a(name.u.string), value.form); - V_VT(&v) = VT_EMPTY; - } + if (subpgm->current_func) { if (is_pmt) WARN("Constant parameter %s reported as local variable in function '%s'\n", debugstr_a(name.u.string), debugstr_a(subpgm->current_func->hash_elt.name)); di->symt = &symt_add_func_constant(subpgm->ctx->module_ctx->module, subpgm->current_func, subpgm->current_block, - param_type, name.u.string, &v)->symt; + symt_ptr_to_symref(param_type), name.u.string, &v)->symt; } else di->symt = &symt_new_constant(subpgm->ctx->module_ctx->module, subpgm->ctx->compiland, - name.u.string, param_type, &v)->symt; + name.u.string, symt_ptr_to_symref(param_type), &v)->symt; } else { @@ -2065,7 +2173,7 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, loc.reg = loc_err_no_location; symt_add_func_local(subpgm->ctx->module_ctx->module, subpgm->current_func, is_pmt ? DataIsParam : DataIsLocal, - &loc, subpgm->current_block, param_type, name.u.string); + &loc, subpgm->current_block, symt_ptr_to_symref(param_type), name.u.string); } else { @@ -2076,11 +2184,6 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm, WARN("dropping global variable %s which has been optimized away\n", debugstr_a(name.u.string)); } } - if (is_pmt && subpgm->current_func && symt_check_tag(subpgm->current_func->type, SymTagFunctionType)) - symt_add_function_signature_parameter(subpgm->ctx->module_ctx->module, - (struct symt_function_signature*)subpgm->current_func->type, - param_type); - if (dwarf2_get_di_children(di)) FIXME("Unsupported children\n"); } @@ -2116,8 +2219,6 @@ static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm, dwarf2_debug_info_t* di) { struct attribute name; - struct symt* ret_type; - struct symt_function_signature* sig_type; struct symt_function* inlined; struct vector* children; dwarf2_debug_info_t*child; @@ -2136,16 +2237,12 @@ static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm, FIXME("No name for function... dropping function\n"); return; } - ret_type = dwarf2_lookup_type(di); - - /* FIXME: assuming C source code */ - sig_type = symt_new_function_signature(subpgm->ctx->module_ctx->module, ret_type, CV_CALL_FAR_C); inlined = symt_new_inlinesite(subpgm->ctx->module_ctx->module, subpgm->top_func, subpgm->current_block ? &subpgm->current_block->symt : &subpgm->current_func->symt, dwarf2_get_cpp_name(di, name.u.string), - &sig_type->symt, num_ranges); + symt_ptr_to_symref(dwarf2_parse_subroutine_type(di)), 0, num_ranges); subpgm->current_func = inlined; subpgm->current_block = NULL; @@ -2183,7 +2280,7 @@ static void dwarf2_parse_inlined_subroutine(dwarf2_subprogram_t* subpgm, child->abbrev->tag, dwarf2_debug_di(di)); } } - subpgm->current_block = symt_check_tag(subpgm->current_func->container, SymTagBlock) ? + subpgm->current_block = symt_check_tag(SYMT_SYMREF_TO_PTR(subpgm->current_func->container), SymTagBlock) ? (struct symt_block*)subpgm->current_func->container : NULL; subpgm->current_func = (struct symt_function*)symt_get_upper_inlined(subpgm->current_func); } @@ -2254,7 +2351,8 @@ static void dwarf2_parse_subprogram_block(dwarf2_subprogram_t* subpgm, dwarf2_parse_pointer_type(child); break; case DW_TAG_subroutine_type: - dwarf2_parse_subroutine_type(child); + if (!child->symt) + child->symt = dwarf2_parse_subroutine_type(child); break; case DW_TAG_const_type: dwarf2_parse_const_type(child); @@ -2304,8 +2402,6 @@ static struct symt* dwarf2_parse_subprogram(dwarf2_debug_info_t* di) unsigned num_addr_ranges; struct attribute is_decl; struct attribute inline_flags; - struct symt* ret_type; - struct symt_function_signature* sig_type; dwarf2_subprogram_t subpgm; struct vector* children; dwarf2_debug_info_t* child; @@ -2352,13 +2448,11 @@ static struct symt* dwarf2_parse_subprogram(dwarf2_debug_info_t* di) free(addr_ranges); return NULL; } - ret_type = dwarf2_lookup_type(di); - /* FIXME: assuming C source code */ - sig_type = symt_new_function_signature(di->unit_ctx->module_ctx->module, ret_type, CV_CALL_FAR_C); subpgm.top_func = symt_new_function(di->unit_ctx->module_ctx->module, di->unit_ctx->compiland, dwarf2_get_cpp_name(di, name.u.string), - addr_ranges[0].low, addr_ranges[0].high - addr_ranges[0].low, &sig_type->symt); + addr_ranges[0].low, addr_ranges[0].high - addr_ranges[0].low, + symt_ptr_to_symref(dwarf2_parse_subroutine_type(di)), 0); if (num_addr_ranges > 1) WARN("Function %s has multiple address ranges, only using the first one\n", debugstr_a(name.u.string)); free(addr_ranges); @@ -2446,8 +2540,6 @@ static struct symt* dwarf2_parse_subroutine_type(dwarf2_debug_info_t* di) dwarf2_debug_info_t* child; unsigned int i; - if (di->symt) return di->symt; - TRACE("%s\n", dwarf2_debug_di(di)); ret_type = dwarf2_lookup_type(di); @@ -2472,7 +2564,7 @@ static struct symt* dwarf2_parse_subroutine_type(dwarf2_debug_info_t* di) } } - return di->symt = &sig_type->symt; + return &sig_type->symt; } static void dwarf2_parse_namespace(dwarf2_debug_info_t* di) @@ -2561,7 +2653,8 @@ static void dwarf2_load_one_entry(dwarf2_debug_info_t* di) dwarf2_parse_subprogram(di); break; case DW_TAG_subroutine_type: - dwarf2_parse_subroutine_type(di); + if (!di->symt) + di->symt = dwarf2_parse_subroutine_type(di); break; case DW_TAG_variable: { @@ -2685,7 +2778,7 @@ static BOOL dwarf2_parse_line_numbers(dwarf2_parse_context_t* ctx, opcode_len = traverse.data; traverse.data += opcode_base - 1; - vector_init(&dirs, sizeof(const char*), 4); + vector_init(&dirs, sizeof(const char*), 0); p = vector_add(&dirs, &ctx->pool); *p = compile_dir ? compile_dir : "."; while (traverse.data < traverse.end_data && *traverse.data) @@ -2712,7 +2805,7 @@ static BOOL dwarf2_parse_line_numbers(dwarf2_parse_context_t* ctx, } traverse.data++; - vector_init(&files, sizeof(unsigned), 16); + vector_init(&files, sizeof(unsigned), 0); while (traverse.data < traverse.end_data && *traverse.data) { unsigned int dir_index, mod_time; @@ -2831,22 +2924,22 @@ static BOOL dwarf2_parse_line_numbers(dwarf2_parse_context_t* ctx, return TRUE; } -unsigned dwarf2_cache_cuhead(struct dwarf2_module_info_s* module, struct symt_compiland* c, const dwarf2_cuhead_t* head) +static unsigned dwarf2_cache_cuhead(struct module *module, struct dwarf2_module_info_s* module_info, struct symt_compiland* c, const dwarf2_cuhead_t* head) { dwarf2_cuhead_t* ah; unsigned i; - for (i = 0; i < module->num_cuheads; ++i) + for (i = 0; i < module_info->num_cuheads; ++i) { - if (memcmp(module->cuheads[i], head, sizeof(*head)) == 0) + if (memcmp(module_info->cuheads[i], head, sizeof(*head)) == 0) { - c->user = module->cuheads[i]; + c->user = module_info->cuheads[i]; return TRUE; } } - if (!(ah = pool_alloc(&c->container->module->pool, sizeof(*head)))) return FALSE; + if (!(ah = pool_alloc(&module->pool, sizeof(*head)))) return FALSE; memcpy(ah, head, sizeof(*head)); - module->cuheads = realloc(module->cuheads, ++module->num_cuheads * sizeof(head)); - module->cuheads[module->num_cuheads - 1] = ah; + module_info->cuheads = realloc(module_info->cuheads, ++module_info->num_cuheads * sizeof(head)); + module_info->cuheads[module_info->num_cuheads - 1] = ah; c->user = ah; return TRUE; } @@ -2858,7 +2951,7 @@ static dwarf2_parse_context_t* dwarf2_locate_cu(dwarf2_parse_module_context_t* m const BYTE* where; for (i = 0; i < module_ctx->unit_contexts.num_elts; ++i) { - ctx = vector_at(&module_ctx->unit_contexts, i); + ctx = *(dwarf2_parse_context_t**)vector_at(&module_ctx->unit_contexts, i); where = module_ctx->sections[ctx->section].address + ref; if (where >= ctx->traverse_DIE.data && where < ctx->traverse_DIE.end_data) return ctx; @@ -2955,6 +3048,7 @@ static BOOL dwarf2_parse_compilation_unit(dwarf2_parse_context_t* ctx) struct attribute stmt_list, low_pc; struct attribute comp_dir; struct attribute language; + char *tmp; if (!dwarf2_find_attribute(di, DW_AT_name, &name)) name.u.string = NULL; @@ -2971,10 +3065,11 @@ static BOOL dwarf2_parse_compilation_unit(dwarf2_parse_context_t* ctx) ctx->language = language.u.uvalue; - ctx->compiland = symt_new_compiland(ctx->module_ctx->module, - source_new(ctx->module_ctx->module, comp_dir.u.string, name.u.string)); + tmp = source_build_path(comp_dir.u.string, name.u.string); + ctx->compiland = symt_new_compiland(ctx->module_ctx->module, tmp); + HeapFree(GetProcessHeap(), 0, tmp); ctx->compiland->address = ctx->module_ctx->load_offset + low_pc.u.uvalue; - dwarf2_cache_cuhead(ctx->module_ctx->module->format_info[DFI_DWARF]->u.dwarf2_info, ctx->compiland, &ctx->head); + dwarf2_cache_cuhead(ctx->module_ctx->module, ctx->module_ctx->module->format_info[DFI_DWARF]->u.dwarf2_info, ctx->compiland, &ctx->head); di->symt = &ctx->compiland->symt; children = dwarf2_get_di_children(di); if (children) for (i = 0; i < vector_length(children); i++) @@ -2982,7 +3077,7 @@ static BOOL dwarf2_parse_compilation_unit(dwarf2_parse_context_t* ctx) child = *(dwarf2_debug_info_t**)vector_at(children, i); dwarf2_load_one_entry(child); } - if (dwarf2_find_attribute(di, DW_AT_stmt_list, &stmt_list)) + if ((SymGetOptions() & SYMOPT_LOAD_LINES) && dwarf2_find_attribute(di, DW_AT_stmt_list, &stmt_list)) { if (dwarf2_parse_line_numbers(ctx, comp_dir.u.string, stmt_list.u.uvalue)) ctx->module_ctx->module->module.LineNumbers = TRUE; @@ -3026,9 +3121,9 @@ static const dwarf2_cuhead_t* get_cuhead_from_func(const struct symt_function* f { if (symt_check_tag(&func->symt, SymTagInlineSite)) func = symt_get_function_from_inlined((struct symt_function*)func); - if (symt_check_tag(&func->symt, SymTagFunction) && symt_check_tag(func->container, SymTagCompiland)) + if (symt_check_tag(&func->symt, SymTagFunction) && symt_check_tag(SYMT_SYMREF_TO_PTR(func->container), SymTagCompiland)) { - struct symt_compiland* c = (struct symt_compiland*)func->container; + struct symt_compiland* c = (struct symt_compiland*)SYMT_SYMREF_TO_PTR(func->container); return (const dwarf2_cuhead_t*)c->user; } FIXME("Should have a compilation unit head\n"); @@ -3037,13 +3132,13 @@ static const dwarf2_cuhead_t* get_cuhead_from_func(const struct symt_function* f static enum location_error compute_call_frame_cfa(struct module* module, ULONG_PTR ip, struct location* frame); -static enum location_error loc_compute_frame(struct process* pcs, - const struct module_format* modfmt, +static enum location_error loc_compute_frame(const struct module_format* modfmt, const struct symt_function* func, DWORD_PTR ip, const dwarf2_cuhead_t* head, struct location* frame) { - struct symt** psym = NULL; + struct process *pcs = modfmt->module->process; + struct symt* sym; struct location* pframe; dwarf2_traverse_context_t lctx; enum location_error err; @@ -3051,10 +3146,10 @@ static enum location_error loc_compute_frame(struct process* pcs, for (i=0; ivchildren); i++) { - psym = vector_at(&func->vchildren, i); - if (psym && symt_check_tag(*psym, SymTagCustom)) + sym = SYMT_SYMREF_TO_PTR(*(symref_t*)vector_at(&func->vchildren, i)); + if (symt_check_tag(sym, SymTagCustom)) { - pframe = &((struct symt_hierarchy_point*)*psym)->loc; + pframe = &((struct symt_hierarchy_point*)sym)->loc; /* First, recompute the frame information, if needed */ switch (pframe->kind) @@ -3078,7 +3173,7 @@ static enum location_error loc_compute_frame(struct process* pcs, } break; case loc_dwarf2_frame_cfa: - err = compute_call_frame_cfa(modfmt->module, ip + ((struct symt_compiland*)func->container)->address, frame); + err = compute_call_frame_cfa(modfmt->module, ip + ((struct symt_compiland*)SYMT_SYMREF_TO_PTR(func->container))->address, frame); if (err < 0) return err; break; default: @@ -3915,8 +4010,7 @@ static enum location_error compute_call_frame_cfa(struct module* module, ULONG_P return 0; } -static void dwarf2_location_compute(struct process* pcs, - const struct module_format* modfmt, +static void dwarf2_location_compute(const struct module_format* modfmt, const struct symt_function* func, struct location* loc) { @@ -3934,10 +4028,11 @@ static void dwarf2_location_compute(struct process* pcs, } else { + struct process *pcs = modfmt->module->process; /* instruction pointer relative to compiland's start */ - ip = pcs->localscope_pc - ((struct symt_compiland*)func->container)->address; + ip = pcs->localscope_pc - ((struct symt_compiland*)SYMT_SYMREF_TO_PTR(func->container))->address; - if ((err = loc_compute_frame(pcs, modfmt, func, ip, head, &frame)) == 0) + if ((err = loc_compute_frame(modfmt, func, ip, head, &frame)) == 0) { switch (loc->kind) { @@ -4095,7 +4190,7 @@ static inline void dwarf2_fini_section(dwarf2_section_t* section) HeapFree(GetProcessHeap(), 0, (void*)section->address); } -static void dwarf2_module_remove(struct process* pcs, struct module_format* modfmt) +static void dwarf2_module_remove(struct module_format* modfmt) { dwarf2_fini_section(&modfmt->u.dwarf2_info->debug_loc); dwarf2_fini_section(&modfmt->u.dwarf2_info->debug_frame); @@ -4114,7 +4209,7 @@ static BOOL dwarf2_load_CU_module(dwarf2_parse_module_context_t* module_ctx, str module_ctx->module = module; module_ctx->thunks = thunks; module_ctx->load_offset = load_offset; - vector_init(&module_ctx->unit_contexts, sizeof(dwarf2_parse_context_t), 16); + vector_init(&module_ctx->unit_contexts, sizeof(dwarf2_parse_context_t*), 0); module_ctx->cu_versions = 0; /* phase I: parse all CU heads */ @@ -4122,10 +4217,13 @@ static BOOL dwarf2_load_CU_module(dwarf2_parse_module_context_t* module_ctx, str mod_ctx.end_data = mod_ctx.data + sections[section_debug].size; while (mod_ctx.data < mod_ctx.end_data) { - dwarf2_parse_context_t* unit_ctx = vector_add(&module_ctx->unit_contexts, &module_ctx->module->pool); + dwarf2_parse_context_t **punit_ctx = vector_add(&module_ctx->unit_contexts, &module_ctx->module->pool); + + if (!(*punit_ctx = pool_alloc(&module_ctx->module->pool, sizeof(dwarf2_parse_context_t)))) + return FALSE; - unit_ctx->module_ctx = module_ctx; - dwarf2_parse_compilation_unit_head(unit_ctx, &mod_ctx); + (*punit_ctx)->module_ctx = module_ctx; + dwarf2_parse_compilation_unit_head(*punit_ctx, &mod_ctx); } /* phase2: load content of all CU @@ -4135,7 +4233,7 @@ static BOOL dwarf2_load_CU_module(dwarf2_parse_module_context_t* module_ctx, str */ if (!is_dwz) for (i = 0; i < module_ctx->unit_contexts.num_elts; ++i) - dwarf2_parse_compilation_unit((dwarf2_parse_context_t*)vector_at(&module_ctx->unit_contexts, i)); + dwarf2_parse_compilation_unit(*(dwarf2_parse_context_t**)vector_at(&module_ctx->unit_contexts, i)); return TRUE; } @@ -4189,14 +4287,27 @@ static BOOL dwarf2_unload_CU_module(dwarf2_parse_module_context_t* module_ctx) unsigned i; for (i = 0; i < module_ctx->unit_contexts.num_elts; ++i) { - dwarf2_parse_context_t* unit = vector_at(&module_ctx->unit_contexts, i); - if (unit->status != UNIT_ERROR) + dwarf2_parse_context_t* unit = *(dwarf2_parse_context_t**)vector_at(&module_ctx->unit_contexts, i); + if (unit && unit->status != UNIT_ERROR) pool_destroy(&unit->pool); + pool_free(&module_ctx->module->pool, unit); } dwarf2_unload_dwz(module_ctx->dwz); return TRUE; } +static const struct module_format_vtable dwarf2_module_format_vtable = +{ + dwarf2_module_remove, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + dwarf2_location_compute, +}; + BOOL dwarf2_parse(struct module* module, ULONG_PTR load_offset, const struct elf_thunk_area* thunks, struct image_file_map* fmap) @@ -4208,6 +4319,11 @@ BOOL dwarf2_parse(struct module* module, ULONG_PTR load_offset, struct module_format* dwarf2_modfmt; dwarf2_parse_module_context_t module_ctx; +/* Our DWARF parser has been known to crash winedbg in some cases. Since + * probably no concerned parties are going to be using plain winedbg, just don't + * bother parsing anything. */ +return FALSE; + if (!dwarf2_init_section(&eh_frame, fmap, ".eh_frame", NULL, &eh_frame_sect)) /* lld produces .eh_fram to avoid generating a long name */ dwarf2_init_section(&eh_frame, fmap, ".eh_fram", NULL, &eh_frame_sect); @@ -4244,8 +4360,7 @@ BOOL dwarf2_parse(struct module* module, ULONG_PTR load_offset, goto leave; } dwarf2_modfmt->module = module; - dwarf2_modfmt->remove = dwarf2_module_remove; - dwarf2_modfmt->loc_compute = dwarf2_location_compute; + dwarf2_modfmt->vtable = &dwarf2_module_format_vtable; dwarf2_modfmt->u.dwarf2_info = (struct dwarf2_module_info_s*)(dwarf2_modfmt + 1); dwarf2_modfmt->u.dwarf2_info->word_size = fmap->addr_size / 8; /* set the word_size for eh_frame parsing */ dwarf2_modfmt->module->format_info[DFI_DWARF] = dwarf2_modfmt; diff --git a/dlls/dbghelp/elf_module.c b/dlls/dbghelp/elf_module.c index a4cf37942f05..a62a36f32f6e 100644 --- a/dlls/dbghelp/elf_module.c +++ b/dlls/dbghelp/elf_module.c @@ -602,7 +602,7 @@ BOOL elf_map_handle(HANDLE handle, struct image_file_map* fmap) return elf_map_file(&emfd, fmap); } -static void elf_module_remove(struct process* pcs, struct module_format* modfmt) +static void elf_module_remove(struct module_format* modfmt) { image_unmap_file(&modfmt->u.elf_info->file_map); HeapFree(GetProcessHeap(), 0, modfmt); @@ -699,7 +699,7 @@ static void elf_hash_symtab(struct module* module, struct pool* pool, { case ELF_STT_FILE: if (symname) - compiland = symt_new_compiland(module, source_new(module, NULL, symname)); + compiland = symt_new_compiland(module, symname); else compiland = NULL; continue; @@ -762,7 +762,7 @@ static void elf_hash_symtab(struct module* module, struct pool* pool, */ static const struct elf_sym *elf_lookup_symtab(const struct module* module, const struct hash_table* ht_symtab, - const char* name, const struct symt* compiland) + const char* name, symref_t symref_compiland) { struct symtab_elt* weak_result = NULL; /* without compiland name */ struct symtab_elt* result = NULL; @@ -771,19 +771,19 @@ static const struct elf_sym *elf_lookup_symtab(const struct module* module, const char* compiland_name; const char* compiland_basename; const char* base; + struct symt_compiland *compiland = (struct symt_compiland*)SYMT_SYMREF_TO_PTR(symref_compiland); - /* we need weak match up (at least) when symbols of same name, + /* we need weak match up (at least) when symbols of same name, * defined several times in different compilation units, * are merged in a single one (hence a different filename for c.u.) */ if (compiland) { - compiland_name = source_get(module, - ((const struct symt_compiland*)compiland)->source); + compiland_name = ((const struct symt_compiland*)compiland)->filename; compiland_basename = file_nameA(compiland_name); } else compiland_name = compiland_basename = NULL; - + hash_table_iter_init(ht_symtab, &hti, name); while ((ste = hash_table_iter_up(&hti))) { @@ -794,7 +794,7 @@ static const struct elf_sym *elf_lookup_symtab(const struct module* module, continue; if (ste->compiland && compiland_name) { - const char* filename = source_get(module, ste->compiland->source); + const char* filename = ste->compiland->filename; if (strcmp(filename, compiland_name)) { base = file_nameA(filename); @@ -805,9 +805,9 @@ static const struct elf_sym *elf_lookup_symtab(const struct module* module, { FIXME("Already found symbol %s (%s) in symtab %s @%08x and %s @%08x\n", debugstr_a(name), debugstr_a(compiland_name), - debugstr_a(source_get(module, result->compiland->source)), + debugstr_a(result->compiland->filename), (unsigned int)result->sym.st_value, - debugstr_a(source_get(module, ste->compiland->source)), + debugstr_a(ste->compiland->filename), (unsigned int)ste->sym.st_value); } else @@ -857,7 +857,7 @@ static void elf_finish_stabs_info(struct module* module, const struct hash_table { break; } - symp = elf_lookup_symtab(module, symtab, sym->hash_elt.name, + symp = elf_lookup_symtab(module, symtab, sym->hash_elt.name, ((struct symt_function*)sym)->container); if (symp) { @@ -886,7 +886,7 @@ static void elf_finish_stabs_info(struct module* module, const struct hash_table if (((struct symt_data*)sym)->u.var.kind != loc_absolute || ((struct symt_data*)sym)->u.var.offset != elf_info->elf_addr) break; - symp = elf_lookup_symtab(module, symtab, sym->hash_elt.name, + symp = elf_lookup_symtab(module, symtab, sym->hash_elt.name, ((struct symt_data*)sym)->container); if (symp) { @@ -960,7 +960,7 @@ static int elf_new_wine_thunks(struct module* module, const struct hash_table* h { case ELF_STT_FUNC: symt_new_function(module, ste->compiland, ste->ht_elt.name, - addr, ste->sym.st_size, NULL); + addr, ste->sym.st_size, 0, 0); break; case ELF_STT_OBJECT: loc.kind = loc_absolute; @@ -968,7 +968,7 @@ static int elf_new_wine_thunks(struct module* module, const struct hash_table* h loc.offset = addr; symt_new_global_variable(module, ste->compiland, ste->ht_elt.name, elf_is_local_symbol(ste->sym.st_info), - loc, ste->sym.st_size, NULL); + loc, ste->sym.st_size, 0); break; default: FIXME("Shouldn't happen\n"); @@ -1142,6 +1142,12 @@ static BOOL elf_fetch_file_info(struct process* process, const WCHAR* name, ULON return TRUE; } +static const struct module_format_vtable elf_module_format_vtable = +{ + elf_module_remove, + NULL, +}; + static BOOL elf_load_file_from_fmap(struct process* pcs, const WCHAR* filename, struct image_file_map* fmap, ULONG_PTR load_offset, ULONG_PTR dyn_addr, struct elf_info* elf_info) @@ -1253,8 +1259,7 @@ static BOOL elf_load_file_from_fmap(struct process* pcs, const WCHAR* filename, elf_module_info = (void*)(modfmt + 1); elf_info->module->format_info[DFI_ELF] = modfmt; modfmt->module = elf_info->module; - modfmt->remove = elf_module_remove; - modfmt->loc_compute = NULL; + modfmt->vtable = &elf_module_format_vtable; modfmt->u.elf_info = elf_module_info; elf_module_info->elf_addr = load_offset; @@ -1466,6 +1471,59 @@ static BOOL elf_search_and_load_file(struct process* pcs, const WCHAR* filename, typedef BOOL (*enum_elf_modules_cb)(const WCHAR*, ULONG_PTR load_addr, ULONG_PTR dyn_addr, BOOL is_system, void* user); +static BOOL elf_linkmap_validate_entry(const struct process* pcs, DWORD64 base, DWORD64 name_addr, WCHAR* buffer, SIZE_T buflen) +{ + static DWORD page_size; + MEMORY_BASIC_INFORMATION mem_info; + char bufstr[MAX_PATH]; + + if (!page_size) + { + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + page_size = sys_info.dwPageSize; + } + if (base & (page_size - 1)) + { + WARN("Unaligned base addr=%I64x page_size=%lx\n", base, page_size); + return FALSE; + } + if (VirtualQueryEx(pcs->handle, (void*)(ULONG_PTR)base, &mem_info, sizeof(mem_info))) + { + if (mem_info.BaseAddress != (void*)(ULONG_PTR)base) + { + WARN("Invalid base addr %I64x (beg map at %p)\n", base, mem_info.BaseAddress); + return FALSE; + } + } + else + { + /* Some ELF modules are loaded in 32bit mode above 2G limit, + * and virtual query will fail on these addresses when process is not large address aware. + * Don't consider this as an error for a 32bit debuggee. + */ + if (pcs->is_64bit) + { + WARN("Invalid base addr %I64x\n", base); + return FALSE; + } + } + + memset(bufstr, ' ', sizeof(bufstr)); + if (!read_process_memory(pcs, name_addr, bufstr, sizeof(bufstr))) + { + WARN("Invalid name_address %I64x\n", name_addr); + return FALSE; + } + if (!memchr(bufstr, '\0', sizeof(bufstr))) + { + WARN("Unterminated string %s\n", wine_dbgstr_an(bufstr, sizeof(bufstr))); + return FALSE; + } + MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, buffer, buflen); + return TRUE; +} + /****************************************************************** * elf_enum_modules_internal * @@ -1475,8 +1533,7 @@ static BOOL elf_enum_modules_internal(const struct process* pcs, const WCHAR* main_name, enum_elf_modules_cb cb, void* user) { - WCHAR bufstrW[MAX_PATH]; - char bufstr[256]; + WCHAR bufstr[MAX_PATH]; ULONG_PTR lm_addr; if (pcs->is_host_64bit) @@ -1510,15 +1567,16 @@ static BOOL elf_enum_modules_internal(const struct process* pcs, if (!read_process_memory(pcs, lm_addr, &lm, sizeof(lm))) return FALSE; - if (lm.l_prev && /* skip first entry, normally debuggee itself */ - lm.l_name && read_process_memory(pcs, lm.l_name, bufstr, sizeof(bufstr))) + /* skip first entry(normally debuggee itself) and entries without names */ + if (!lm.l_prev || !lm.l_name) continue; + if (!elf_linkmap_validate_entry(pcs, lm.l_addr, lm.l_name, bufstr, ARRAY_SIZE(bufstr))) { - bufstr[sizeof(bufstr) - 1] = '\0'; - MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, ARRAY_SIZE(bufstrW)); - if (main_name && !bufstrW[0]) lstrcpyW(bufstrW, main_name); - if (!cb(bufstrW, (ULONG_PTR)lm.l_addr, (ULONG_PTR)lm.l_ld, FALSE, user)) - break; + FIXME("Incorrect link_map entry, bailing out\n"); + return FALSE; } + if (main_name && !bufstr[0]) lstrcpyW(bufstr, main_name); + if (!cb(bufstr, (ULONG_PTR)lm.l_addr, (ULONG_PTR)lm.l_ld, FALSE, user)) + break; } } else @@ -1552,15 +1610,16 @@ static BOOL elf_enum_modules_internal(const struct process* pcs, if (!read_process_memory(pcs, lm_addr, &lm, sizeof(lm))) return FALSE; - if (lm.l_prev && /* skip first entry, normally debuggee itself */ - lm.l_name && read_process_memory(pcs, lm.l_name, bufstr, sizeof(bufstr))) + /* skip first entry(normally debuggee itself) and entries without names */ + if (!lm.l_prev || !lm.l_name) continue; + if (!elf_linkmap_validate_entry(pcs, lm.l_addr, lm.l_name, bufstr, ARRAY_SIZE(bufstr))) { - bufstr[sizeof(bufstr) - 1] = '\0'; - MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, ARRAY_SIZE(bufstrW)); - if (main_name && !bufstrW[0]) lstrcpyW(bufstrW, main_name); - if (!cb(bufstrW, (ULONG_PTR)lm.l_addr, (ULONG_PTR)lm.l_ld, FALSE, user)) - break; + FIXME("Incorrect link_map entry, bailing out\n"); + return FALSE; } + if (main_name && !bufstr[0]) lstrcpyW(bufstr, main_name); + if (!cb(bufstr, (ULONG_PTR)lm.l_addr, (ULONG_PTR)lm.l_ld, FALSE, user)) + break; } } diff --git a/dlls/dbghelp/macho_module.c b/dlls/dbghelp/macho_module.c index b1f457d122d2..2b1f35c4d784 100644 --- a/dlls/dbghelp/macho_module.c +++ b/dlls/dbghelp/macho_module.c @@ -1190,7 +1190,7 @@ static void macho_finish_stabs(struct module* module, struct hash_table* ht_symt if (ste->is_code) { symt_new_function(module, ste->compiland, ste->ht_elt.name, - ste->addr, 0, NULL); + ste->addr, 0, 0, 0); } else { @@ -1200,7 +1200,7 @@ static void macho_finish_stabs(struct module* module, struct hash_table* ht_symt loc.reg = 0; loc.offset = ste->addr; symt_new_global_variable(module, ste->compiland, ste->ht_elt.name, - !ste->is_global, loc, 0, NULL); + !ste->is_global, loc, 0, 0); } ste->used = 1; @@ -1479,12 +1479,18 @@ static BOOL macho_fetch_file_info(struct process* process, const WCHAR* name, UL /****************************************************************** * macho_module_remove */ -static void macho_module_remove(struct process* pcs, struct module_format* modfmt) +static void macho_module_remove(struct module_format* modfmt) { macho_unmap_file(&modfmt->u.macho_info->file_map); HeapFree(GetProcessHeap(), 0, modfmt); } +static const struct module_format_vtable macho_module_format_vtable = +{ + macho_module_remove, + NULL, +}; + /****************************************************************** * macho_load_file * @@ -1538,8 +1544,7 @@ static BOOL macho_load_file(struct process* pcs, const WCHAR* filename, macho_info->module->format_info[DFI_MACHO] = modfmt; modfmt->module = macho_info->module; - modfmt->remove = macho_module_remove; - modfmt->loc_compute = NULL; + modfmt->vtable = &macho_module_format_vtable; modfmt->u.macho_info = macho_module_info; macho_module_info->load_addr = load_addr; diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index b8848f4010a7..68adb6ae4bd7 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -253,14 +253,13 @@ struct module* module_new(struct process* pcs, const WCHAR* name, module->cpu = dbghelp_current_cpu; module->debug_format_bitmask = 0; - vector_init(&module->vsymt, sizeof(struct symt*), 128); - vector_init(&module->vcustom_symt, sizeof(struct symt*), 16); + vector_init(&module->vsymt, sizeof(symref_t), 0); + vector_init(&module->vcustom_symt, sizeof(symref_t), 0); /* FIXME: this seems a bit too high (on a per module basis) * need some statistics about this */ hash_table_init(&module->pool, &module->ht_symbols, 4096); hash_table_init(&module->pool, &module->ht_types, 4096); - vector_init(&module->vtypes, sizeof(struct symt*), 32); module->sources_used = 0; module->sources_alloc = 0; @@ -903,6 +902,7 @@ BOOL image_check_alternate(struct image_file_map* fmap, const struct module* mod return FALSE; } +#ifndef _WIN64 /*********************************************************************** * SymLoadModule (DBGHELP.@) */ @@ -912,6 +912,7 @@ DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll, SizeOfDll, NULL, 0); } +#endif /*********************************************************************** * SymLoadModuleEx (DBGHELP.@) @@ -1080,9 +1081,8 @@ DWORD64 WINAPI SymLoadModule64(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, */ BOOL module_remove(struct process* pcs, struct module* module) { - struct module_format*modfmt; + struct module_format_vtable_iterator iter = {}; struct module** p; - unsigned i; TRACE("%s (%p)\n", debugstr_w(module->modulename), module); @@ -1094,20 +1094,20 @@ BOOL module_remove(struct process* pcs, struct module* module) locsym = &symt_get_function_from_inlined((struct symt_function*)locsym)->symt; if (symt_check_tag(locsym, SymTagFunction)) { - locsym = ((struct symt_function*)locsym)->container; - if (symt_check_tag(locsym, SymTagCompiland) && - module == ((struct symt_compiland*)locsym)->container->module) + struct symt_compiland *compiland = (struct symt_compiland*)SYMT_SYMREF_TO_PTR(((struct symt_function*)locsym)->container); + if (symt_check_tag(&compiland->symt, SymTagCompiland)) { - pcs->localscope_pc = 0; - pcs->localscope_symt = NULL; + if (module == ((struct symt_module*)SYMT_SYMREF_TO_PTR(compiland->container))->module) + { + pcs->localscope_pc = 0; + pcs->localscope_symt = NULL; + } } } } - for (i = 0; i < DFI_LAST; i++) - { - if ((modfmt = module->format_info[i]) && modfmt->remove) - modfmt->remove(pcs, module->format_info[i]); - } + while (module_format_vtable_iterator_next(module, &iter, MODULE_FORMAT_VTABLE_INDEX(remove))) + iter.modfmt->vtable->remove(iter.modfmt); + hash_table_destroy(&module->ht_symbols); hash_table_destroy(&module->ht_types); HeapFree(GetProcessHeap(), 0, module->sources); @@ -1129,6 +1129,7 @@ BOOL module_remove(struct process* pcs, struct module* module) return FALSE; } +#ifndef _WIN64 /****************************************************************** * SymUnloadModule (DBGHELP.@) * @@ -1137,6 +1138,7 @@ BOOL WINAPI SymUnloadModule(HANDLE hProcess, DWORD BaseOfDll) { return SymUnloadModule64(hProcess, BaseOfDll); } +#endif /****************************************************************** * SymUnloadModule64 (DBGHELP.@) @@ -1155,6 +1157,7 @@ BOOL WINAPI SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll) return TRUE; } +#ifndef _WIN64 /****************************************************************** * SymEnumerateModules (DBGHELP.@) * @@ -1185,6 +1188,7 @@ BOOL WINAPI SymEnumerateModules(HANDLE hProcess, return SymEnumerateModulesW64(hProcess, enum_modW64_32, &x); } +#endif /****************************************************************** * SymEnumerateModules64 (DBGHELP.@) @@ -1274,6 +1278,7 @@ BOOL WINAPI EnumerateLoadedModules64(HANDLE hProcess, return EnumerateLoadedModulesW64(hProcess, enum_load_modW64_64, &x); } +#ifndef _WIN64 /****************************************************************** * EnumerateLoadedModules (DBGHELP.@) * @@ -1304,6 +1309,7 @@ BOOL WINAPI EnumerateLoadedModules(HANDLE hProcess, return EnumerateLoadedModulesW64(hProcess, enum_load_modW64_32, &x); } +#endif static unsigned int load_and_grow_modules(HANDLE process, HMODULE** hmods, unsigned start, unsigned* alloc, DWORD filter) { @@ -1330,6 +1336,7 @@ BOOL WINAPI EnumerateLoadedModulesW64(HANDLE process, PENUMLOADED_MODULES_CALLBACKW64 enum_cb, PVOID user) { + OBJECT_BASIC_INFORMATION obi; HMODULE* hmods; unsigned alloc = 256, count, count32, i; USHORT pcs_machine, native_machine; @@ -1340,6 +1347,15 @@ BOOL WINAPI EnumerateLoadedModulesW64(HANDLE process, WCHAR* wowdir = NULL; size_t sysdir_len = 0, wowdir_len = 0; + if (process != GetCurrentProcess() && + RtlIsCurrentProcess( process ) && + !NtQueryObject(process, ObjectBasicInformation, &obi, sizeof(obi), NULL) && + obi.GrantedAccess & PROCESS_VM_READ) + { + TRACE("same process.\n"); + process = GetCurrentProcess(); + } + /* process might not be a handle to a live process */ if (!IsWow64Process2(process, &pcs_machine, &native_machine)) { @@ -1429,6 +1445,7 @@ static void dbghelp_str_WtoA(const WCHAR *src, char *dst, int dst_len) dst[dst_len - 1] = 0; } +#ifndef _WIN64 /****************************************************************** * SymGetModuleInfo (DBGHELP.@) * @@ -1489,6 +1506,7 @@ BOOL WINAPI SymGetModuleInfoW(HANDLE hProcess, DWORD dwAddr, return TRUE; } +#endif /****************************************************************** * SymGetModuleInfo64 (DBGHELP.@) @@ -1584,6 +1602,7 @@ BOOL WINAPI SymGetModuleInfoW64(HANDLE hProcess, DWORD64 dwAddr, return TRUE; } +#ifndef _WIN64 /*********************************************************************** * SymGetModuleBase (DBGHELP.@) */ @@ -1591,6 +1610,7 @@ DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr) { return (DWORD)SymGetModuleBase64(hProcess, dwAddr); } +#endif /*********************************************************************** * SymGetModuleBase64 (DBGHELP.@) @@ -1622,7 +1642,6 @@ void module_reset_debug_info(struct module* module) hash_table_destroy(&module->ht_types); module->ht_types.num_buckets = 0; module->ht_types.buckets = NULL; - module->vtypes.num_elts = 0; hash_table_destroy(&module->ht_symbols); module->sources_used = module->sources_alloc = 0; module->sources = NULL; @@ -1665,6 +1684,7 @@ BOOL WINAPI SymRefreshModuleList(HANDLE hProcess) return module_refresh_list(pcs); } +#ifndef _WIN64 /*********************************************************************** * SymFunctionTableAccess (DBGHELP.@) */ @@ -1672,6 +1692,7 @@ PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase) { return SymFunctionTableAccess64(hProcess, AddrBase); } +#endif /*********************************************************************** * SymFunctionTableAccess64 (DBGHELP.@) diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c index 22ec5230f7ae..43ee8509a0dd 100644 --- a/dlls/dbghelp/msc.c +++ b/dlls/dbghelp/msc.c @@ -37,7 +37,6 @@ #include #include -#include #include "windef.h" #include "winbase.h" #include "winternl.h" @@ -62,7 +61,6 @@ enum pdb_kind {PDB_JG, PDB_DS}; struct pdb_file_info { enum pdb_kind kind; - HANDLE hMap; const char* image; struct pdb_stream_name* stream_dict; unsigned fpoext_stream; @@ -81,7 +79,7 @@ struct pdb_file_info /* FIXME: don't make it static */ #define CV_MAX_MODULES 32 -struct pdb_module_info +struct old_pdb_module_info { unsigned used_subfiles; struct pdb_file_info pdb_files[CV_MAX_MODULES]; @@ -137,7 +135,7 @@ struct cv_defined_module BOOL allowed; unsigned int first_type_index; unsigned int last_type_index; - struct symt** defined_types; + struct symt** defined_types; /* when old reader */ }; /* FIXME: don't make it static */ #define CV_MAX_MODULES 32 @@ -180,6 +178,9 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_UINT4] = &symt_get_basic(btUInt, 4)->symt; /* UINT4 */ cv_basic_types[T_INT8] = &symt_get_basic(btInt, 8)->symt; /* INT8 */ cv_basic_types[T_UINT8] = &symt_get_basic(btUInt, 8)->symt; /* UINT8 */ + cv_basic_types[T_OCT] = &symt_get_basic(btInt, 8)->symt; /* INT8 */ + cv_basic_types[T_UOCT] = &symt_get_basic(btUInt, 8)->symt; /* UINT8 */ + cv_basic_types[T_HRESULT]= &symt_get_basic(btUInt, 4)->symt; /* HRESULT */ cv_basic_types[T_32PVOID] = &symt_new_pointer(module, cv_basic_types[T_VOID], 4)->symt; @@ -187,10 +188,12 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_32PSHORT] = &symt_new_pointer(module, cv_basic_types[T_SHORT], 4)->symt; cv_basic_types[T_32PLONG] = &symt_new_pointer(module, cv_basic_types[T_LONG], 4)->symt; cv_basic_types[T_32PQUAD] = &symt_new_pointer(module, cv_basic_types[T_QUAD], 4)->symt; + cv_basic_types[T_32POCT] = &symt_new_pointer(module, cv_basic_types[T_OCT], 4)->symt; cv_basic_types[T_32PUCHAR] = &symt_new_pointer(module, cv_basic_types[T_UCHAR], 4)->symt; cv_basic_types[T_32PUSHORT] = &symt_new_pointer(module, cv_basic_types[T_USHORT], 4)->symt; cv_basic_types[T_32PULONG] = &symt_new_pointer(module, cv_basic_types[T_ULONG], 4)->symt; cv_basic_types[T_32PUQUAD] = &symt_new_pointer(module, cv_basic_types[T_UQUAD], 4)->symt; + cv_basic_types[T_32PUOCT] = &symt_new_pointer(module, cv_basic_types[T_UOCT], 4)->symt; cv_basic_types[T_32PBOOL08] = &symt_new_pointer(module, cv_basic_types[T_BOOL08], 4)->symt; cv_basic_types[T_32PBOOL16] = &symt_new_pointer(module, cv_basic_types[T_BOOL16], 4)->symt; cv_basic_types[T_32PBOOL32] = &symt_new_pointer(module, cv_basic_types[T_BOOL32], 4)->symt; @@ -216,10 +219,12 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_64PSHORT] = &symt_new_pointer(module, cv_basic_types[T_SHORT], 8)->symt; cv_basic_types[T_64PLONG] = &symt_new_pointer(module, cv_basic_types[T_LONG], 8)->symt; cv_basic_types[T_64PQUAD] = &symt_new_pointer(module, cv_basic_types[T_QUAD], 8)->symt; + cv_basic_types[T_64POCT] = &symt_new_pointer(module, cv_basic_types[T_OCT], 8)->symt; cv_basic_types[T_64PUCHAR] = &symt_new_pointer(module, cv_basic_types[T_UCHAR], 8)->symt; cv_basic_types[T_64PUSHORT] = &symt_new_pointer(module, cv_basic_types[T_USHORT], 8)->symt; cv_basic_types[T_64PULONG] = &symt_new_pointer(module, cv_basic_types[T_ULONG], 8)->symt; cv_basic_types[T_64PUQUAD] = &symt_new_pointer(module, cv_basic_types[T_UQUAD], 8)->symt; + cv_basic_types[T_64PUOCT] = &symt_new_pointer(module, cv_basic_types[T_UOCT], 8)->symt; cv_basic_types[T_64PBOOL08] = &symt_new_pointer(module, cv_basic_types[T_BOOL08], 8)->symt; cv_basic_types[T_64PBOOL16] = &symt_new_pointer(module, cv_basic_types[T_BOOL16], 8)->symt; cv_basic_types[T_64PBOOL32] = &symt_new_pointer(module, cv_basic_types[T_BOOL32], 8)->symt; @@ -245,10 +250,12 @@ static void codeview_init_basic_types(struct module* module) cv_basic_types[T_PSHORT] = &symt_new_pointer(module, cv_basic_types[T_SHORT], ptrsz)->symt; cv_basic_types[T_PLONG] = &symt_new_pointer(module, cv_basic_types[T_LONG], ptrsz)->symt; cv_basic_types[T_PQUAD] = &symt_new_pointer(module, cv_basic_types[T_QUAD], ptrsz)->symt; + cv_basic_types[T_POCT] = &symt_new_pointer(module, cv_basic_types[T_OCT], ptrsz)->symt; cv_basic_types[T_PUCHAR] = &symt_new_pointer(module, cv_basic_types[T_UCHAR], ptrsz)->symt; cv_basic_types[T_PUSHORT] = &symt_new_pointer(module, cv_basic_types[T_USHORT], ptrsz)->symt; cv_basic_types[T_PULONG] = &symt_new_pointer(module, cv_basic_types[T_ULONG], ptrsz)->symt; cv_basic_types[T_PUQUAD] = &symt_new_pointer(module, cv_basic_types[T_UQUAD], ptrsz)->symt; + cv_basic_types[T_PUOCT] = &symt_new_pointer(module, cv_basic_types[T_UOCT], ptrsz)->symt; cv_basic_types[T_PBOOL08] = &symt_new_pointer(module, cv_basic_types[T_BOOL08], ptrsz)->symt; cv_basic_types[T_PBOOL16] = &symt_new_pointer(module, cv_basic_types[T_BOOL16], ptrsz)->symt; cv_basic_types[T_PBOOL32] = &symt_new_pointer(module, cv_basic_types[T_BOOL32], ptrsz)->symt; @@ -273,15 +280,15 @@ static int leaf_as_variant(VARIANT *v, const unsigned char *leaf) { unsigned short int type = *(const unsigned short *)leaf; int length = 2; - leaf += length; if (type < LF_NUMERIC) { - V_VT(v) = VT_UINT; - V_UINT(v) = type; + V_VT(v) = VT_I2; + V_I2(v) = type; } else { + leaf += length; switch (type) { case LF_CHAR: @@ -395,7 +402,8 @@ static int leaf_as_variant(VARIANT *v, const unsigned char *leaf) return length; } -static int numeric_leaf(int *value, const unsigned char *leaf) +#define numeric_leaf(v,l) _numeric_leaf(__LINE__,v,l) +static int _numeric_leaf(unsigned line, int *value, const unsigned char *leaf) { unsigned short int type = *(const unsigned short int *)leaf; int length = 2; @@ -436,7 +444,7 @@ static int numeric_leaf(int *value, const unsigned char *leaf) case LF_QUADWORD: case LF_UQUADWORD: - FIXME("Unsupported numeric leaf type %04x\n", type); + FIXME("Unsupported numeric leaf type %04x from %u (%I64x)\n", type, line, *(ULONG64*)leaf); length += 8; *value = 0; /* FIXME */ break; @@ -578,9 +586,10 @@ static inline const void* codeview_jump_to_type(const struct codeview_type_parse ctp->table + ctp->offset[idx - ctp->header.first_index] : NULL; } -static int codeview_add_type(unsigned int typeno, struct symt* dt) +static int codeview_add_type(unsigned int typeno, struct symt* dt, unsigned offset) { unsigned idx; + if (!cv_current_module) { FIXME("Adding %x to non allowed module\n", typeno); @@ -596,6 +605,7 @@ static int codeview_add_type(unsigned int typeno, struct symt* dt) return FALSE; } idx = typeno - cv_current_module->first_type_index; + if (cv_current_module->defined_types[idx]) { if (cv_current_module->defined_types[idx] != dt) @@ -640,6 +650,16 @@ static struct symt* codeview_fetch_type(struct codeview_type_parse* ctp, return symt; } +static symref_t codeview_fetch_symref(struct codeview_type_parse* ctp, unsigned typeno) +{ + return symt_ptr_to_symref(codeview_fetch_type(ctp, typeno)); +} + +static symref_t codeview_get_symref(struct module *module, unsigned typeno) +{ + return symt_ptr_to_symref(codeview_get_type(typeno, TRUE)); +} + static UINT32 codeview_compute_hash(const char* ptr, unsigned len) { const char* last = ptr + len; @@ -891,19 +911,21 @@ static BOOL codeview_add_type_enum_field_list(struct codeview_type_parse* ctp, { case LF_ENUMERATE_V1: { - int value, vlen = numeric_leaf(&value, type->enumerate_v1.data); + VARIANT v; + int vlen = leaf_as_variant(&v, type->enumerate_v1.data); const struct p_string* p_name = (const struct p_string*)&type->enumerate_v1.data[vlen]; - symt_add_enum_element(ctp->module, symt, terminate_string(p_name), value); + symt_add_enum_element(ctp->module, symt, terminate_string(p_name), &v); ptr += 2 + 2 + vlen + (1 + p_name->namelen); break; } case LF_ENUMERATE_V3: { - int value, vlen = numeric_leaf(&value, type->enumerate_v3.data); + VARIANT v; + int vlen = leaf_as_variant(&v, type->enumerate_v3.data); const char* name = (const char*)&type->enumerate_v3.data[vlen]; - symt_add_enum_element(ctp->module, symt, name, value); + symt_add_enum_element(ctp->module, symt, name, &v); ptr += 2 + 2 + vlen + (1 + strlen(name)); break; } @@ -941,13 +963,13 @@ static void codeview_add_udt_element(struct codeview_type_parse* ctp, { case LF_BITFIELD_V1: symt_add_udt_element(ctp->module, symt, name, - codeview_fetch_type(ctp, cv_type->bitfield_v1.type), + codeview_fetch_symref(ctp,cv_type->bitfield_v1.type), value, cv_type->bitfield_v1.bitoff, cv_type->bitfield_v1.nbits); return; case LF_BITFIELD_V2: symt_add_udt_element(ctp->module, symt, name, - codeview_fetch_type(ctp, cv_type->bitfield_v2.type), + codeview_fetch_symref(ctp, cv_type->bitfield_v2.type), value, cv_type->bitfield_v2.bitoff, cv_type->bitfield_v2.nbits); return; @@ -959,7 +981,8 @@ static void codeview_add_udt_element(struct codeview_type_parse* ctp, { DWORD64 elem_size = 0; symt_get_info(ctp->module, subtype, TI_GET_LENGTH, &elem_size); - symt_add_udt_element(ctp->module, symt, name, subtype, value, 0, 0); + symt_add_udt_element(ctp->module, symt, name, codeview_get_symref(ctp->module, type), + value, 0, 0); } } @@ -1395,12 +1418,17 @@ static struct symt* codeview_parse_one_type(struct codeview_type_parse* ctp, symt = &symt_new_udt(ctp->module, buf, 0, UdtStruct)->symt; } break; + /* types we can simply silence for now */ + case LF_LABEL_V1: + case LF_VFTABLE_V3: + break; default: FIXME("Unsupported type-id leaf %x\n", type->generic.id); dump(type, 2 + type->generic.len); return NULL; } - return symt && codeview_add_type(curr_type, symt) ? symt : NULL; + return symt && codeview_add_type(curr_type, symt, + (const BYTE*)type - ctp->table + ctp->header.type_offset) ? symt : NULL; } static struct symt* codeview_load_forwardable_type(struct codeview_type_parse* ctp, @@ -1530,7 +1558,8 @@ static BOOL codeview_parse_type_table(struct codeview_type_parse* ctp) { /* no load it */ if ((symt = codeview_load_forwardable_type(ctp, codeview_jump_to_type(ctp, impl_type)))) - codeview_add_type(impl_type, symt); + codeview_add_type(impl_type, symt, + (const BYTE*)codeview_jump_to_type(ctp, impl_type) - ctp->table + ctp->header.type_offset); else FIXME("forward def of %x => %x, unable to load impl\n", hl->id, impl_type); } @@ -1545,7 +1574,7 @@ static BOOL codeview_parse_type_table(struct codeview_type_parse* ctp) if (!(symt = codeview_get_type(hl->id, TRUE))) symt = codeview_load_forwardable_type(ctp, type); } - codeview_add_type(hl->id, symt); + codeview_add_type(hl->id, symt, (const BYTE*)type - ctp->table + ctp->header.type_offset); } } /* pass II: + non forwardable types: load them, but since they can be indirectly @@ -1569,7 +1598,7 @@ static BOOL codeview_parse_type_table(struct codeview_type_parse* ctp) static ULONG_PTR codeview_get_address(const struct msc_debug_info* msc_dbg, unsigned seg, unsigned offset); -static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const BYTE* linetab, +static BOOL codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const BYTE* linetab, int size, BOOL pascal_str) { const BYTE* ptr = linetab; @@ -1587,6 +1616,7 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B const struct codeview_linetab_block* ltb; nfile = *(const short*)linetab; + if (!nfile) return FALSE; filetab = (const unsigned int*)(linetab + 2 * sizeof(short)); for (i = 0; i < nfile; i++) @@ -1634,11 +1664,12 @@ static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const B } } } + return TRUE; } static const char* pdb_get_string_table_entry(const PDB_STRING_TABLE* table, unsigned offset); -static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const struct cv_module_snarf* cvmod) +static BOOL codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const struct cv_module_snarf* cvmod) { unsigned i; const void* hdr_last = (const char*)cvmod->dbgsubsect + cvmod->dbgsubsect_size; @@ -1664,7 +1695,7 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const if (!hdr_files) { TRACE("No DEBUG_S_FILECHKSMS found\n"); - return; + return FALSE; } for (hdr = cvmod->dbgsubsect; CV_IS_INSIDE(hdr, hdr_last); hdr = hdr_next) @@ -1714,6 +1745,7 @@ static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const } hdr = hdr_next; } + return TRUE; } /*======================================================================== @@ -1754,8 +1786,9 @@ static BOOL func_has_local(struct symt_function* func, const char* name) for (i = 0; i < func->vchildren.num_elts; ++i) { - struct symt* p = *(struct symt**)vector_at(&func->vchildren, i); - if (symt_check_tag(p, SymTagData) && !strcmp(((struct symt_data*)p)->hash_elt.name, name)) + struct symt *lsym = SYMT_SYMREF_TO_PTR(*(symref_t*)vector_at(&func->vchildren, i)); + + if (symt_check_tag(lsym, SymTagData) && !strcmp(((struct symt_data*)lsym)->hash_elt.name, name)) return TRUE; } return FALSE; @@ -1785,7 +1818,7 @@ static inline void codeview_add_variable(const struct msc_debug_info* msc_dbg, { if (!is_local || in_tls) WARN("Unsupported construct\n"); symt_add_func_local(msc_dbg->module, func, DataIsStaticLocal, &loc, block, - codeview_get_type(symtype, FALSE), name); + codeview_get_symref(msc_dbg->module, symtype), name); return; } if (!dontcheck && !in_tls) @@ -1805,7 +1838,7 @@ static inline void codeview_add_variable(const struct msc_debug_info* msc_dbg, if (symdata->kind == (is_local ? DataIsFileStatic : DataIsGlobal) && symdata->u.var.kind == loc.kind && symdata->u.var.offset == loc.offset && - symdata->container == &compiland->symt) + symdata->container == symt_ptr_to_symref(&compiland->symt)) { /* We don't compare types yet... Unfortunately, they are not * always the same typeid... it'd require full type equivalence @@ -1818,7 +1851,7 @@ static inline void codeview_add_variable(const struct msc_debug_info* msc_dbg, } if (is_local ^ (compiland != NULL)) FIXME("Unsupported construct\n"); symt_new_global_variable(msc_dbg->module, compiland, name, is_local, loc, 0, - codeview_get_type(symtype, FALSE)); + codeview_get_symref(msc_dbg->module, symtype)); } } @@ -2128,6 +2161,7 @@ static struct symt_function* codeview_create_inline_site(const struct msc_debug_ struct symt_function* top_func, struct symt* container, cv_itemid_t inlinee, + DWORD_PTR user, const unsigned char* annot, const unsigned char* last_annot) { @@ -2153,15 +2187,15 @@ static struct symt_function* codeview_create_inline_site(const struct msc_debug_ case LF_FUNC_ID: inlined = symt_new_inlinesite(msc_dbg->module, top_func, container, cvt->func_id_v3.name, - codeview_get_type(cvt->func_id_v3.type, FALSE), - num_ranges); + codeview_get_symref(msc_dbg->module, cvt->func_id_v3.type), + user, num_ranges); break; case LF_MFUNC_ID: /* FIXME we just declare a function, not a method */ inlined = symt_new_inlinesite(msc_dbg->module, top_func, container, cvt->mfunc_id_v3.name, - codeview_get_type(cvt->mfunc_id_v3.type, FALSE), - num_ranges); + codeview_get_symref(msc_dbg->module, cvt->mfunc_id_v3.type), + user, num_ranges); break; default: FIXME("unsupported inlinee kind %x\n", cvt->generic.id); @@ -2251,7 +2285,6 @@ static struct symt_function* codeview_create_inline_site(const struct msc_debug_ static struct symt_compiland* codeview_new_compiland(const struct msc_debug_info* msc_dbg, const char* objname) { - unsigned int src_idx = source_new(msc_dbg->module, NULL, objname); unsigned int i; /* In some cases MSVC generates several compiland entries with same pathname in PDB file. @@ -2260,11 +2293,11 @@ static struct symt_compiland* codeview_new_compiland(const struct msc_debug_info */ for (i = 0; i < msc_dbg->module->top->vchildren.num_elts; i++) { - struct symt_compiland** p = vector_at(&msc_dbg->module->top->vchildren, i); - if (symt_check_tag(&(*p)->symt, SymTagCompiland) && (*p)->source == src_idx) - return *p; + struct symt_compiland* p = (struct symt_compiland*)SYMT_SYMREF_TO_PTR(*(symref_t*)vector_at(&msc_dbg->module->top->vchildren, i)); + if (symt_check_tag(&p->symt, SymTagCompiland) && !strcmp(p->filename, objname)) + return p; } - return symt_new_compiland(msc_dbg->module, src_idx); + return symt_new_compiland(msc_dbg->module, objname); } static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, @@ -2276,7 +2309,6 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, struct symt_function* curr_func = NULL; int i, length; struct symt_block* block = NULL; - struct symt* symt; struct symt_compiland* compiland = NULL; struct location loc; unsigned top_frame_size = -1; @@ -2374,47 +2406,53 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, case S_GPROC32_16t: case S_LPROC32_16t: if (top_func) FIXME("nested function\n"); - top_func = symt_new_function(msc_dbg->module, compiland, - terminate_string(&sym->proc_v1.p_name), - codeview_get_address(msc_dbg, sym->proc_v1.segment, sym->proc_v1.offset), - sym->proc_v1.proc_len, - codeview_get_type(sym->proc_v1.proctype, FALSE)); - curr_func = top_func; - loc.kind = loc_absolute; - loc.offset = sym->proc_v1.debug_start; - symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL); - loc.offset = sym->proc_v1.debug_end; - symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugEnd, &loc, NULL); + if ((top_func = symt_new_function(msc_dbg->module, compiland, + terminate_string(&sym->proc_v1.p_name), + codeview_get_address(msc_dbg, sym->proc_v1.segment, sym->proc_v1.offset), + sym->proc_v1.proc_len, + codeview_get_symref(msc_dbg->module, sym->proc_v1.proctype), i))) + { + curr_func = top_func; + loc.kind = loc_absolute; + loc.offset = sym->proc_v1.debug_start; + symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL); + loc.offset = sym->proc_v1.debug_end; + symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugEnd, &loc, NULL); + } break; case S_GPROC32_ST: case S_LPROC32_ST: if (top_func) FIXME("nested function\n"); - top_func = symt_new_function(msc_dbg->module, compiland, - terminate_string(&sym->proc_v2.p_name), - codeview_get_address(msc_dbg, sym->proc_v2.segment, sym->proc_v2.offset), - sym->proc_v2.proc_len, - codeview_get_type(sym->proc_v2.proctype, FALSE)); - curr_func = top_func; - loc.kind = loc_absolute; - loc.offset = sym->proc_v2.debug_start; - symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL); - loc.offset = sym->proc_v2.debug_end; - symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugEnd, &loc, NULL); + if ((top_func = symt_new_function(msc_dbg->module, compiland, + terminate_string(&sym->proc_v2.p_name), + codeview_get_address(msc_dbg, sym->proc_v2.segment, sym->proc_v2.offset), + sym->proc_v2.proc_len, + codeview_get_symref(msc_dbg->module, sym->proc_v2.proctype), i))) + { + curr_func = top_func; + loc.kind = loc_absolute; + loc.offset = sym->proc_v2.debug_start; + symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL); + loc.offset = sym->proc_v2.debug_end; + symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugEnd, &loc, NULL); + } break; case S_GPROC32: case S_LPROC32: if (top_func) FIXME("nested function\n"); - top_func = symt_new_function(msc_dbg->module, compiland, - sym->proc_v3.name, - codeview_get_address(msc_dbg, sym->proc_v3.segment, sym->proc_v3.offset), - sym->proc_v3.proc_len, - codeview_get_type(sym->proc_v3.proctype, FALSE)); - curr_func = top_func; - loc.kind = loc_absolute; - loc.offset = sym->proc_v3.debug_start; - symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL); - loc.offset = sym->proc_v3.debug_end; - symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugEnd, &loc, NULL); + if ((top_func = symt_new_function(msc_dbg->module, compiland, + sym->proc_v3.name, + codeview_get_address(msc_dbg, sym->proc_v3.segment, sym->proc_v3.offset), + sym->proc_v3.proc_len, + codeview_get_symref(msc_dbg->module, sym->proc_v3.proctype), i))) + { + curr_func = top_func; + loc.kind = loc_absolute; + loc.offset = sym->proc_v3.debug_start; + symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL); + loc.offset = sym->proc_v3.debug_end; + symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugEnd, &loc, NULL); + } break; /* * Function parameters and stack variables. @@ -2427,7 +2465,7 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, symt_add_func_local(msc_dbg->module, curr_func, sym->stack_v1.offset > 0 ? DataIsParam : DataIsLocal, &loc, block, - codeview_get_type(sym->stack_v1.symtype, FALSE), + codeview_get_symref(msc_dbg->module, sym->stack_v1.symtype), terminate_string(&sym->stack_v1.p_name)); break; case S_BPREL32_ST: @@ -2438,7 +2476,7 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, symt_add_func_local(msc_dbg->module, curr_func, sym->stack_v2.offset > 0 ? DataIsParam : DataIsLocal, &loc, block, - codeview_get_type(sym->stack_v2.symtype, FALSE), + codeview_get_symref(msc_dbg->module, sym->stack_v2.symtype), terminate_string(&sym->stack_v2.p_name)); break; case S_BPREL32: @@ -2451,7 +2489,7 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, symt_add_func_local(msc_dbg->module, curr_func, sym->stack_v3.offset > 0 ? DataIsParam : DataIsLocal, &loc, block, - codeview_get_type(sym->stack_v3.symtype, FALSE), + codeview_get_symref(msc_dbg->module, sym->stack_v3.symtype), sym->stack_v3.name); break; case S_REGREL32: @@ -2464,7 +2502,7 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, symt_add_func_local(msc_dbg->module, curr_func, sym->regrel_v3.offset >= top_frame_size ? DataIsParam : DataIsLocal, &loc, block, - codeview_get_type(sym->regrel_v3.symtype, FALSE), + codeview_get_symref(msc_dbg->module, sym->regrel_v3.symtype), sym->regrel_v3.name); break; @@ -2473,8 +2511,8 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, loc.reg = sym->register_v1.reg; loc.offset = 0; symt_add_func_local(msc_dbg->module, curr_func, - DataIsLocal, &loc, - block, codeview_get_type(sym->register_v1.type, FALSE), + DataIsLocal, &loc, block, + codeview_get_symref(msc_dbg->module, sym->register_v1.type), terminate_string(&sym->register_v1.p_name)); break; case S_REGISTER_ST: @@ -2482,8 +2520,8 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, loc.reg = sym->register_v2.reg; loc.offset = 0; symt_add_func_local(msc_dbg->module, curr_func, - DataIsLocal, &loc, - block, codeview_get_type(sym->register_v2.type, FALSE), + DataIsLocal, &loc, block, + codeview_get_symref(msc_dbg->module, sym->register_v2.type), terminate_string(&sym->register_v2.p_name)); break; case S_REGISTER: @@ -2493,8 +2531,8 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, loc.reg = sym->register_v3.reg; loc.offset = 0; symt_add_func_local(msc_dbg->module, curr_func, - DataIsLocal, &loc, - block, codeview_get_type(sym->register_v3.type, FALSE), + DataIsLocal, &loc, block, + codeview_get_symref(msc_dbg->module, sym->register_v3.type), sym->register_v3.name); break; @@ -2585,81 +2623,65 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, { int vlen; const struct p_string* name; - struct symt* se; VARIANT v; vlen = leaf_as_variant(&v, sym->constant_v1.data); name = (const struct p_string*)&sym->constant_v1.data[vlen]; - se = codeview_get_type(sym->constant_v1.type, FALSE); TRACE("S-Constant-V1 %u %s %x\n", V_INT(&v), terminate_string(name), sym->constant_v1.type); symt_new_constant(msc_dbg->module, compiland, terminate_string(name), - se, &v); + codeview_get_symref(msc_dbg->module, sym->constant_v1.type), &v); } break; case S_CONSTANT_ST: { int vlen; const struct p_string* name; - struct symt* se; VARIANT v; vlen = leaf_as_variant(&v, sym->constant_v2.data); name = (const struct p_string*)&sym->constant_v2.data[vlen]; - se = codeview_get_type(sym->constant_v2.type, FALSE); TRACE("S-Constant-V2 %u %s %x\n", V_INT(&v), terminate_string(name), sym->constant_v2.type); symt_new_constant(msc_dbg->module, compiland, terminate_string(name), - se, &v); + codeview_get_symref(msc_dbg->module, sym->constant_v2.type), &v); } break; case S_CONSTANT: { int vlen; const char* name; - struct symt* se; VARIANT v; vlen = leaf_as_variant(&v, sym->constant_v3.data); name = (const char*)&sym->constant_v3.data[vlen]; - se = codeview_get_type(sym->constant_v3.type, FALSE); TRACE("S-Constant-V3 %u %s %x\n", V_INT(&v), debugstr_a(name), sym->constant_v3.type); /* FIXME: we should add this as a constant value */ - symt_new_constant(msc_dbg->module, compiland, name, se, &v); + symt_new_constant(msc_dbg->module, compiland, name, + codeview_get_symref(msc_dbg->module, sym->constant_v3.type), &v); } break; case S_UDT_16t: if (sym->udt_v1.type) { - if ((symt = codeview_get_type(sym->udt_v1.type, FALSE))) - symt_new_typedef(msc_dbg->module, symt, - terminate_string(&sym->udt_v1.p_name)); - else - FIXME("S-Udt %s: couldn't find type 0x%x\n", - terminate_string(&sym->udt_v1.p_name), sym->udt_v1.type); + symt_new_typedef(msc_dbg->module, codeview_get_symref(msc_dbg->module, sym->udt_v1.type), + terminate_string(&sym->udt_v1.p_name)); } break; case S_UDT_ST: if (sym->udt_v2.type) { - if ((symt = codeview_get_type(sym->udt_v2.type, FALSE))) - symt_new_typedef(msc_dbg->module, symt, + symt_new_typedef(msc_dbg->module, codeview_get_symref(msc_dbg->module, sym->udt_v2.type), terminate_string(&sym->udt_v2.p_name)); - else - FIXME("S-Udt %s: couldn't find type 0x%x\n", - terminate_string(&sym->udt_v2.p_name), sym->udt_v2.type); } break; case S_UDT: if (sym->udt_v3.type) { - if ((symt = codeview_get_type(sym->udt_v3.type, FALSE))) - symt_new_typedef(msc_dbg->module, symt, sym->udt_v3.name); - else - FIXME("S-Udt %s: couldn't find type 0x%x\n", - debugstr_a(sym->udt_v3.name), sym->udt_v3.type); + symt_new_typedef(msc_dbg->module, codeview_get_symref(msc_dbg->module, sym->udt_v3.type), + sym->udt_v3.name); } break; case S_LOCAL: @@ -2673,7 +2695,7 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, symt_add_func_local(msc_dbg->module, curr_func, sym->local_v3.varflags.is_param ? DataIsParam : DataIsLocal, &loc, block, - codeview_get_type(sym->local_v3.symtype, FALSE), + codeview_get_symref(msc_dbg->module, sym->local_v3.symtype), sym->local_v3.name); } else @@ -2684,6 +2706,7 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, struct symt_function* inlined = codeview_create_inline_site(msc_dbg, cvmod, top_func, block ? &block->symt : &curr_func->symt, sym->inline_site_v3.inlinee, + i, sym->inline_site_v3.binaryAnnotations, (const unsigned char*)sym + length); if (inlined) @@ -2705,6 +2728,7 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, struct symt_function* inlined = codeview_create_inline_site(msc_dbg, cvmod, top_func, block ? &block->symt : &curr_func->symt, sym->inline_site2_v3.inlinee, + i, sym->inline_site2_v3.binaryAnnotations, (const unsigned char*)sym + length); if (inlined) @@ -2723,8 +2747,8 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, break; case S_INLINESITE_END: - block = symt_check_tag(curr_func->container, SymTagBlock) ? - (struct symt_block*)curr_func->container : NULL; + block = symt_check_tag(SYMT_SYMREF_TO_PTR(curr_func->container), SymTagBlock) ? + (struct symt_block *)((struct symt_block*)curr_func->container) : NULL; curr_func = (struct symt_function*)symt_get_upper_inlined(curr_func); break; @@ -2768,7 +2792,7 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, struct symt_function* pfunc = (struct symt_function*)parent; top_func = symt_new_function(msc_dbg->module, compiland, pfunc->hash_elt.name, codeview_get_address(msc_dbg, sym->sepcode_v3.sect, sym->sepcode_v3.off), - sym->sepcode_v3.length, pfunc->type); + sym->sepcode_v3.length, pfunc->type, i); curr_func = top_func; } else @@ -2784,16 +2808,34 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, if (top_frame_size == -1 && curr_func && curr_func == top_func) top_frame_size = sym->frame_info_v2.sz_frame; else - FIXME("Unexpected S_FRAMEPROC %d (%p %p)\n", top_frame_size, top_func, curr_func); + FIXME("Unexpected S_FRAMEPROC %d (%p %p) %x\n", top_frame_size, top_func, curr_func, i); + break; + + case S_GMANPROC: + case S_LMANPROC: + /* skip whole record and sub-records */ + i = sym->managed_proc_v3.pend; + sym = (const union codeview_symbol*)(root + i); + if (i + sizeof(sym->generic) > size || sym->generic.id != S_END) + { + FIXME("Wrong relocation after managed proc, aborting\n"); + return FALSE; + } + length = 2 + sym->generic.len; break; /* the symbols we can safely ignore for now */ + case S_SKIP: case S_TRAMPOLINE: case S_FRAMECOOKIE: case S_SECTION: case S_COFFGROUP: case S_EXPORT: case S_CALLSITEINFO: + case S_ARMSWITCHTABLE: + case S_TOKENREF: + case S_OEM: + case S_MANSLOT: /* even if S_LOCAL groks all the S_DEFRANGE* records following itself, * those kinds of records can also be present after a S_FILESTATIC record * so silence them until (at least) S_FILESTATIC is supported @@ -2819,7 +2861,6 @@ static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, break; } } - if (cvmod) codeview_snarf_linetab2(msc_dbg, cvmod); return TRUE; } @@ -2835,8 +2876,7 @@ static BOOL codeview_is_inside(const struct cv_local_info* locinfo, const struct return TRUE; } -static void pdb_location_compute(struct process* pcs, - const struct module_format* modfmt, +static void pdb_location_compute(const struct module_format* modfmt, const struct symt_function* func, struct location* loc) { @@ -2849,7 +2889,7 @@ static void pdb_location_compute(struct process* pcs, locinfo->kind != 0; locinfo = (const struct cv_local_info*)((const char*)(locinfo + 1) + locinfo->ngaps * sizeof(locinfo->gaps[0]))) { - if (!codeview_is_inside(locinfo, func, pcs->localscope_pc)) continue; + if (!codeview_is_inside(locinfo, func, modfmt->module->process->localscope_pc)) continue; switch (locinfo->kind) { case S_DEFRANGE: @@ -2900,11 +2940,13 @@ static BOOL codeview_snarf_sym_hashtable(const struct msc_debug_info* msc_dbg, c if (hashsize < sizeof(DBI_HASH_HEADER) || hash_hdr->signature != 0xFFFFFFFF || hash_hdr->version != 0xeffe0000 + 19990810 || + !hash_hdr->hash_records_size || (hash_hdr->hash_records_size % sizeof(DBI_HASH_RECORD)) != 0 || sizeof(DBI_HASH_HEADER) + hash_hdr->hash_records_size + DBI_BITMAP_HASH_SIZE > hashsize || (hashsize - (sizeof(DBI_HASH_HEADER) + hash_hdr->hash_records_size + DBI_BITMAP_HASH_SIZE)) % sizeof(unsigned)) { - FIXME("Incorrect hash structure\n"); + if (hash_hdr->hash_records_size) + FIXME("Incorrect hash structure\n"); return FALSE; } @@ -2928,39 +2970,27 @@ static BOOL codeview_snarf_sym_hashtable(const struct msc_debug_info* msc_dbg, c static BOOL pdb_global_feed_types(const struct msc_debug_info* msc_dbg, const union codeview_symbol* sym) { - struct symt* symt; switch (sym->generic.id) { case S_UDT_16t: if (sym->udt_v1.type) { - if ((symt = codeview_get_type(sym->udt_v1.type, FALSE))) - symt_new_typedef(msc_dbg->module, symt, + symt_new_typedef(msc_dbg->module, codeview_get_symref(msc_dbg->module, sym->udt_v1.type), terminate_string(&sym->udt_v1.p_name)); - else - FIXME("S-Udt %s: couldn't find type 0x%x\n", - terminate_string(&sym->udt_v1.p_name), sym->udt_v1.type); } break; case S_UDT_ST: if (sym->udt_v2.type) { - if ((symt = codeview_get_type(sym->udt_v2.type, FALSE))) - symt_new_typedef(msc_dbg->module, symt, - terminate_string(&sym->udt_v2.p_name)); - else - FIXME("S-Udt %s: couldn't find type 0x%x\n", - terminate_string(&sym->udt_v2.p_name), sym->udt_v2.type); + symt_new_typedef(msc_dbg->module, codeview_get_symref(msc_dbg->module, sym->udt_v2.type), + terminate_string(&sym->udt_v2.p_name)); } break; case S_UDT: if (sym->udt_v3.type) { - if ((symt = codeview_get_type(sym->udt_v3.type, FALSE))) - symt_new_typedef(msc_dbg->module, symt, sym->udt_v3.name); - else - FIXME("S-Udt %s: couldn't find type 0x%x\n", - debugstr_a(sym->udt_v3.name), sym->udt_v3.type); + symt_new_typedef(msc_dbg->module, codeview_get_symref(msc_dbg->module, sym->udt_v3.type), + sym->udt_v3.name); } break; default: return FALSE; @@ -3071,12 +3101,12 @@ static void* pdb_ds_read(const struct PDB_DS_HEADER* pdb, const UINT *block_list if (!size) return NULL; num_blocks = (size + pdb->block_size - 1) / pdb->block_size; - buffer = HeapAlloc(GetProcessHeap(), 0, num_blocks * pdb->block_size); + buffer = HeapAlloc(GetProcessHeap(), 0, (SIZE_T)num_blocks * pdb->block_size); if (!buffer) return NULL; for (i = 0; i < num_blocks; i++) memcpy(buffer + i * pdb->block_size, - (const char*)pdb + block_list[i] * pdb->block_size, pdb->block_size); + (const char*)pdb + (DWORD_PTR)block_list[i] * pdb->block_size, pdb->block_size); return buffer; } @@ -3156,6 +3186,9 @@ static void pdb_free_file(struct pdb_file_info* pdb_file) break; } HeapFree(GetProcessHeap(), 0, pdb_file->stream_dict); + pdb_file->stream_dict = NULL; + UnmapViewOfFile(pdb_file->image); + pdb_file->image = NULL; } static struct pdb_stream_name* pdb_load_stream_name_table(const char* str, unsigned cb) @@ -3229,17 +3262,15 @@ static const char* pdb_get_string_table_entry(const PDB_STRING_TABLE* table, uns return (!table || offset >= table->length) ? NULL : (const char*)(table + 1) + offset; } -static void pdb_module_remove(struct process* pcsn, struct module_format* modfmt) +static void pdb_module_remove(struct module_format* modfmt) { unsigned i; - for (i = 0; i < modfmt->u.pdb_info->used_subfiles; i++) + for (i = 0; i < modfmt->u.old_pdb_info->used_subfiles; i++) { - pdb_free_file(&modfmt->u.pdb_info->pdb_files[i]); - if (modfmt->u.pdb_info->pdb_files[i].image) - UnmapViewOfFile(modfmt->u.pdb_info->pdb_files[i].image); - if (modfmt->u.pdb_info->pdb_files[i].hMap) - CloseHandle(modfmt->u.pdb_info->pdb_files[i].hMap); + pdb_free_file(&modfmt->u.old_pdb_info->pdb_files[i]); + if (modfmt->u.old_pdb_info->pdb_files[i].image) + UnmapViewOfFile(modfmt->u.old_pdb_info->pdb_files[i].image); } HeapFree(GetProcessHeap(), 0, modfmt); } @@ -3484,7 +3515,7 @@ static BOOL pdb_init(struct pdb_file_info* pdb_file, const char* image) struct PDB_JG_ROOT* root; struct PDB_JG_TOC* jg_toc; - jg_toc = pdb_jg_read(pdb, pdb->toc_block, pdb->toc.size); + jg_toc = pdb_jg_read(pdb, (unsigned short *)(pdb + 1), pdb->toc.size); if (!jg_toc) { ERR("-Unable to get TOC from .PDB\n"); @@ -3521,7 +3552,7 @@ static BOOL pdb_init(struct pdb_file_info* pdb_file, const char* image) struct PDB_DS_ROOT* root; struct PDB_DS_TOC* ds_toc; - ds_toc = pdb_ds_read(pdb, (const UINT*)((const char*)pdb + pdb->toc_block * pdb->block_size), + ds_toc = pdb_ds_read(pdb, (const UINT*)((const char*)pdb + (DWORD_PTR)pdb->toc_block * pdb->block_size), pdb->toc_size); if (!ds_toc) { @@ -3576,8 +3607,9 @@ static BOOL pdb_init(struct pdb_file_info* pdb_file, const char* image) static BOOL pdb_process_internal(const struct process *pcs, const struct msc_debug_info *msc_dbg, const WCHAR *filename, - struct pdb_module_info *pdb_module_info, - unsigned module_index); + struct old_pdb_module_info *pdb_module_info, + unsigned module_index, + BOOL *has_linenumber_info); DWORD pdb_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info) { @@ -3591,7 +3623,7 @@ DWORD pdb_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info) struct PDB_JG_ROOT* root; DWORD ec = ERROR_SUCCESS; - jg_toc = pdb_jg_read(pdb, pdb->toc_block, pdb->toc.size); + jg_toc = pdb_jg_read(pdb, (unsigned short*)(pdb + 1), pdb->toc.size); root = pdb_read_jg_stream(pdb, jg_toc, 1); if (!root) { @@ -3635,7 +3667,7 @@ DWORD pdb_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info) struct PDB_DS_ROOT* root; DWORD ec = ERROR_SUCCESS; - ds_toc = pdb_ds_read(pdb, (const UINT*)((const char*)pdb + pdb->toc_block * pdb->block_size), + ds_toc = pdb_ds_read(pdb, (const UINT*)((const char*)pdb + (DWORD_PTR)pdb->toc_block * pdb->block_size), pdb->toc_size); root = pdb_read_ds_stream(pdb, ds_toc, 1); if (!root) @@ -3693,7 +3725,7 @@ static void pdb_process_symbol_imports(const struct process *pcs, const PDB_SYMBOLS *symbols, const void *symbols_image, const char *image, - struct pdb_module_info *pdb_module_info, + struct old_pdb_module_info *pdb_module_info, unsigned module_index) { if (module_index == -1 && symbols && symbols->pdbimport_size) @@ -3712,6 +3744,7 @@ static void pdb_process_symbol_imports(const struct process *pcs, while (imp < (const PDB_SYMBOL_IMPORT*)last) { SYMSRV_INDEX_INFOW info; + BOOL line_info; ptr = (const char*)imp + sizeof(*imp) + strlen(imp->filename); if (i >= CV_MAX_MODULES) FIXME("Out of bounds!!!\n"); @@ -3719,7 +3752,7 @@ static void pdb_process_symbol_imports(const struct process *pcs, debugstr_a(imp->filename), imp->Age, imp->TimeDateStamp); if (path_find_symbol_file(pcs, msc_dbg->module, imp->filename, TRUE, NULL, imp->TimeDateStamp, imp->Age, &info, &msc_dbg->module->module.PdbUnmatched)) - pdb_process_internal(pcs, msc_dbg, info.pdbfile, pdb_module_info, i); + pdb_process_internal(pcs, msc_dbg, info.pdbfile, pdb_module_info, i, &line_info); i++; imp = (const PDB_SYMBOL_IMPORT*)((const char*)first + ((ptr - (const char*)first + strlen(ptr) + 1 + 3) & ~3)); } @@ -3738,8 +3771,9 @@ static void pdb_process_symbol_imports(const struct process *pcs, static BOOL pdb_process_internal(const struct process *pcs, const struct msc_debug_info *msc_dbg, const WCHAR *filename, - struct pdb_module_info *pdb_module_info, - unsigned module_index) + struct old_pdb_module_info *pdb_module_info, + unsigned module_index, + BOOL *has_linenumber_info) { HANDLE hFile = NULL, hMap = NULL; char* image = NULL; @@ -3749,6 +3783,7 @@ static BOOL pdb_process_internal(const struct process *pcs, TRACE("Processing PDB file %ls\n", filename); + *has_linenumber_info = FALSE; pdb_file = &pdb_module_info->pdb_files[module_index == -1 ? 0 : module_index]; /* Open and map() .PDB file */ if ((hFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, @@ -3761,15 +3796,16 @@ static BOOL pdb_process_internal(const struct process *pcs, CloseHandle(hFile); return FALSE; } + CloseHandle(hFile); + CloseHandle(hMap); + /* old pdb reader */ if (!pdb_init(pdb_file, image)) { - CloseHandle(hMap); UnmapViewOfFile(image); return FALSE; } - pdb_file->hMap = hMap; pdb_file->image = image; symbols_image = pdb_read_stream(pdb_file, 3); if (symbols_image) @@ -3827,9 +3863,10 @@ static BOOL pdb_process_internal(const struct process *pcs, data = pdb_read_stream(pdb_file, symbols.global_hash_stream); if (data) { - codeview_snarf_sym_hashtable(msc_dbg, globalimage, global_size, - data, pdb_get_stream_size(pdb_file, symbols.global_hash_stream), - pdb_global_feed_types); + if (codeview_snarf_sym_hashtable(msc_dbg, globalimage, global_size, + data, pdb_get_stream_size(pdb_file, symbols.global_hash_stream), + pdb_global_feed_types)) + *has_linenumber_info = TRUE; pdb_free((void*)data); } } @@ -3851,16 +3888,25 @@ static BOOL pdb_process_internal(const struct process *pcs, { struct cv_module_snarf cvmod = {ipi_ok ? &ipi_ctp : NULL, (const void*)(modimage + sfile.symbol_size), sfile.lineno2_size, files_image}; - codeview_snarf(msc_dbg, modimage, sizeof(DWORD), sfile.symbol_size, &cvmod, file_name); + codeview_snarf(msc_dbg, modimage, sizeof(DWORD), sfile.symbol_size, + &cvmod, file_name); if (sfile.lineno_size && sfile.lineno2_size) - FIXME("Both line info present... only supporting second\n"); + FIXME("Both line info present... preferring second\n"); + if (sfile.lineno2_size) + { + if (((SymGetOptions() & SYMOPT_LOAD_LINES) && codeview_snarf_linetab2(msc_dbg, &cvmod))) + *has_linenumber_info = TRUE; + } else if (sfile.lineno_size) - codeview_snarf_linetab(msc_dbg, - modimage + sfile.symbol_size, - sfile.lineno_size, - pdb_file->kind == PDB_JG); - + { + if ((SymGetOptions() & SYMOPT_LOAD_LINES) && + codeview_snarf_linetab(msc_dbg, + modimage + sfile.symbol_size, + sfile.lineno_size, + pdb_file->kind == PDB_JG)) + *has_linenumber_info = TRUE; + } pdb_free(modimage); } file_name += strlen(file_name) + 1; @@ -3876,9 +3922,11 @@ static BOOL pdb_process_internal(const struct process *pcs, data = pdb_read_stream(pdb_file, symbols.global_hash_stream); if (data) { - codeview_snarf_sym_hashtable(msc_dbg, globalimage, global_size, - data, pdb_get_stream_size(pdb_file, symbols.global_hash_stream), - pdb_global_feed_variables); + if (codeview_snarf_sym_hashtable(msc_dbg, globalimage, global_size, + data, pdb_get_stream_size(pdb_file, + symbols.global_hash_stream), + pdb_global_feed_variables)) + *has_linenumber_info = TRUE; pdb_free((void*)data); } if (!(dbghelp_options & SYMOPT_NO_PUBLICS) && (data = pdb_read_stream(pdb_file, symbols.public_stream))) @@ -3900,37 +3948,69 @@ static BOOL pdb_process_internal(const struct process *pcs, pdb_free(symbols_image); pdb_free(files_image); + pdb_free_file(pdb_file); + return TRUE; } +static const struct module_format_vtable old_pdb_module_format_vtable = +{ + pdb_module_remove, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + pdb_location_compute, +}; + +static BOOL old_pdb_process_file(const struct process *pcs, + const struct msc_debug_info *msc_dbg, + const WCHAR *filename, BOOL *has_linenumber_info) +{ + struct module_format* modfmt; + struct old_pdb_module_info* pdb_module_info; + BOOL ret; + + if (!(modfmt = HeapAlloc(GetProcessHeap(), 0, + sizeof(struct module_format) + sizeof(struct old_pdb_module_info)))) + return FALSE; + + pdb_module_info = (void*)(modfmt + 1); + msc_dbg->module->format_info[DFI_OLD_PDB] = modfmt; + modfmt->module = msc_dbg->module; + modfmt->vtable = &old_pdb_module_format_vtable; + modfmt->u.old_pdb_info = pdb_module_info; + + memset(cv_zmodules, 0, sizeof(cv_zmodules)); + codeview_init_basic_types(msc_dbg->module); + ret = pdb_process_internal(pcs, msc_dbg, filename, + msc_dbg->module->format_info[DFI_OLD_PDB]->u.old_pdb_info, -1, has_linenumber_info); + codeview_clear_type_table(); + if (!ret) + { + msc_dbg->module->format_info[DFI_OLD_PDB] = NULL; + HeapFree(GetProcessHeap(), 0, modfmt); + } + return ret; +} + static BOOL pdb_process_file(const struct process *pcs, const struct msc_debug_info *msc_dbg, const char *filename, const GUID *guid, DWORD timestamp, DWORD age) { - struct module_format* modfmt; - struct pdb_module_info* pdb_module_info; SYMSRV_INDEX_INFOW info; - BOOL unmatched; + BOOL unmatched, has_linenumber_info, ret; if (!msc_dbg->module->dont_load_symbols && - path_find_symbol_file(pcs, msc_dbg->module, filename, TRUE, guid, timestamp, age, &info, &unmatched) && - (modfmt = HeapAlloc(GetProcessHeap(), 0, - sizeof(struct module_format) + sizeof(struct pdb_module_info)))) + path_find_symbol_file(pcs, msc_dbg->module, filename, TRUE, guid, timestamp, age, &info, &unmatched)) { - BOOL ret; - - pdb_module_info = (void*)(modfmt + 1); - msc_dbg->module->format_info[DFI_PDB] = modfmt; - modfmt->module = msc_dbg->module; - modfmt->remove = pdb_module_remove; - modfmt->loc_compute = pdb_location_compute; - modfmt->u.pdb_info = pdb_module_info; + if (getenv("WINE_DBGHELP_OLD_PDB")) /* keep using old pdb reader */ + ret = old_pdb_process_file(pcs, msc_dbg, info.pdbfile, &has_linenumber_info); + else + ret = pdb_init_modfmt(pcs, msc_dbg, info.pdbfile, &has_linenumber_info); - memset(cv_zmodules, 0, sizeof(cv_zmodules)); - codeview_init_basic_types(msc_dbg->module); - ret = pdb_process_internal(pcs, msc_dbg, info.pdbfile, - msc_dbg->module->format_info[DFI_PDB]->u.pdb_info, -1); - codeview_clear_type_table(); if (ret) { msc_dbg->module->module.SymType = SymPdb; @@ -3941,7 +4021,7 @@ static BOOL pdb_process_file(const struct process *pcs, wcscpy(msc_dbg->module->module.LoadedPdbName, info.pdbfile); /* FIXME: we could have a finer grain here */ - msc_dbg->module->module.LineNumbers = TRUE; + msc_dbg->module->module.LineNumbers = has_linenumber_info; msc_dbg->module->module.GlobalSymbols = TRUE; msc_dbg->module->module.TypeInfo = TRUE; msc_dbg->module->module.SourceIndexed = TRUE; @@ -3949,8 +4029,6 @@ static BOOL pdb_process_file(const struct process *pcs, return TRUE; } - msc_dbg->module->format_info[DFI_PDB] = NULL; - HeapFree(GetProcessHeap(), 0, modfmt); } msc_dbg->module->module.SymType = SymNone; if (guid) @@ -3962,356 +4040,6 @@ static BOOL pdb_process_file(const struct process *pcs, return FALSE; } -/*======================================================================== - * FPO unwinding code - */ - -/* Stack unwinding is based on postfixed operations. - * Let's define our Postfix EValuator - */ -#define PEV_MAX_LEN 32 -struct pevaluator -{ - struct cpu_stack_walk* csw; - struct pool pool; - struct vector stack; - unsigned stk_index; - struct hash_table values; - char error[64]; -}; - -struct zvalue -{ - DWORD_PTR value; - struct hash_table_elt elt; -}; - -static void pev_set_error(struct pevaluator* pev, const char* msg, ...) __WINE_PRINTF_ATTR(2,3); -static void pev_set_error(struct pevaluator* pev, const char* msg, ...) -{ - va_list args; - - va_start(args, msg); - vsnprintf(pev->error, sizeof(pev->error), msg, args); - va_end(args); -} - -#if 0 -static void pev_dump_stack(struct pevaluator* pev) -{ - unsigned i; - struct hash_table_iter hti; - - FIXME("stack #%d\n", pev->stk_index); - for (i = 0; i < pev->stk_index; i++) - { - FIXME("\t%d) %s\n", i, *(char**)vector_at(&pev->stack, i)); - } - hash_table_iter_init(&pev->values, &hti, str); - FIXME("hash\n"); - while ((ptr = hash_table_iter_up(&hti))) - { - struct zvalue* zval = CONTAINING_RECORD(ptr, struct zvalue, elt); - FIXME("\t%s: Ix\n", zval->elt.name, zval->value); - } - -} -#endif - -/* get the value out of an operand (variable or literal) */ -static BOOL pev_get_val(struct pevaluator* pev, const char* str, DWORD_PTR* val) -{ - char* n; - struct hash_table_iter hti; - void* ptr; - - switch (str[0]) - { - case '$': - case '.': - hash_table_iter_init(&pev->values, &hti, str); - while ((ptr = hash_table_iter_up(&hti))) - { - if (!strcmp(CONTAINING_RECORD(ptr, struct zvalue, elt)->elt.name, str)) - { - *val = CONTAINING_RECORD(ptr, struct zvalue, elt)->value; - return TRUE; - } - } - pev_set_error(pev, "get_zvalue: no value found (%s)", str); - return FALSE; - default: - *val = strtol(str, &n, 10); - if (n != str && *n == '\0') return TRUE; - pev_set_error(pev, "get_val: not a literal (%s)", str); - return FALSE; - } -} - -/* push an operand onto the stack */ -static BOOL pev_push(struct pevaluator* pev, const char* elt) -{ - char** at; - if (pev->stk_index < vector_length(&pev->stack)) - at = vector_at(&pev->stack, pev->stk_index); - else - at = vector_add(&pev->stack, &pev->pool); - if (!at) - { - pev_set_error(pev, "push: out of memory"); - return FALSE; - } - *at = pool_strdup(&pev->pool, elt); - pev->stk_index++; - return TRUE; -} - -/* pop an operand from the stack */ -static BOOL pev_pop(struct pevaluator* pev, char* elt) -{ - char** at = vector_at(&pev->stack, --pev->stk_index); - if (!at) - { - pev_set_error(pev, "pop: stack empty"); - return FALSE; - } - strcpy(elt, *at); - return TRUE; -} - -/* pop an operand from the stack, and gets its value */ -static BOOL pev_pop_val(struct pevaluator* pev, DWORD_PTR* val) -{ - char p[PEV_MAX_LEN]; - - return pev_pop(pev, p) && pev_get_val(pev, p, val); -} - -/* set var 'name' a new value (creates the var if it doesn't exist) */ -static BOOL pev_set_value(struct pevaluator* pev, const char* name, DWORD_PTR val) -{ - struct hash_table_iter hti; - void* ptr; - - hash_table_iter_init(&pev->values, &hti, name); - while ((ptr = hash_table_iter_up(&hti))) - { - if (!strcmp(CONTAINING_RECORD(ptr, struct zvalue, elt)->elt.name, name)) - { - CONTAINING_RECORD(ptr, struct zvalue, elt)->value = val; - break; - } - } - if (!ptr) - { - struct zvalue* zv = pool_alloc(&pev->pool, sizeof(*zv)); - if (!zv) - { - pev_set_error(pev, "set_value: out of memory"); - return FALSE; - } - zv->value = val; - - zv->elt.name = pool_strdup(&pev->pool, name); - hash_table_add(&pev->values, &zv->elt); - } - return TRUE; -} - -/* execute a binary operand from the two top most values on the stack. - * puts result on top of the stack */ -static BOOL pev_binop(struct pevaluator* pev, char op) -{ - char res[PEV_MAX_LEN]; - DWORD_PTR v1, v2, c; - - if (!pev_pop_val(pev, &v1) || !pev_pop_val(pev, &v2)) return FALSE; - if ((op == '/' || op == '%') && v2 == 0) - { - pev_set_error(pev, "binop: division by zero"); - return FALSE; - } - switch (op) - { - case '+': c = v1 + v2; break; - case '-': c = v1 - v2; break; - case '*': c = v1 * v2; break; - case '/': c = v1 / v2; break; - case '%': c = v1 % v2; break; - default: - pev_set_error(pev, "binop: unknown op (%c)", op); - return FALSE; - } - snprintf(res, sizeof(res), "%Id", c); - pev_push(pev, res); - return TRUE; -} - -/* pops top most operand, dereference it, on pushes the result on top of the stack */ -static BOOL pev_deref(struct pevaluator* pev) -{ - char res[PEV_MAX_LEN]; - DWORD_PTR v1, v2 = 0; - - if (!pev_pop_val(pev, &v1)) return FALSE; - if (!sw_read_mem(pev->csw, v1, &v2, pev->csw->cpu->word_size)) - { - pev_set_error(pev, "deref: cannot read mem at %Ix", v1); - return FALSE; - } - snprintf(res, sizeof(res), "%Id", v2); - pev_push(pev, res); - return TRUE; -} - -/* assign value to variable (from two top most operands) */ -static BOOL pev_assign(struct pevaluator* pev) -{ - char p2[PEV_MAX_LEN]; - DWORD_PTR v1; - - if (!pev_pop_val(pev, &v1) || !pev_pop(pev, p2)) return FALSE; - if (p2[0] != '$') - { - pev_set_error(pev, "assign: %s isn't a variable", p2); - return FALSE; - } - pev_set_value(pev, p2, v1); - - return TRUE; -} - -/* initializes the postfix evaluator */ -static void pev_init(struct pevaluator* pev, struct cpu_stack_walk* csw, - const PDB_FPO_DATA* fpoext, struct pdb_cmd_pair* cpair) -{ - pev->csw = csw; - pool_init(&pev->pool, 512); - vector_init(&pev->stack, sizeof(char*), 8); - pev->stk_index = 0; - hash_table_init(&pev->pool, &pev->values, 8); - pev->error[0] = '\0'; - for (; cpair->name; cpair++) - pev_set_value(pev, cpair->name, *cpair->pvalue); - pev_set_value(pev, ".raSearchStart", fpoext->start); - pev_set_value(pev, ".cbLocals", fpoext->locals_size); - pev_set_value(pev, ".cbParams", fpoext->params_size); - pev_set_value(pev, ".cbSavedRegs", fpoext->savedregs_size); -} - -static BOOL pev_free(struct pevaluator* pev, struct pdb_cmd_pair* cpair) -{ - DWORD_PTR val; - - if (cpair) for (; cpair->name; cpair++) - { - if (pev_get_val(pev, cpair->name, &val)) - *cpair->pvalue = val; - } - pool_destroy(&pev->pool); - return TRUE; -} - -static BOOL pdb_parse_cmd_string(struct cpu_stack_walk* csw, PDB_FPO_DATA* fpoext, - const char* cmd, struct pdb_cmd_pair* cpair) -{ - char token[PEV_MAX_LEN]; - char* ptok = token; - const char* ptr; - BOOL over = FALSE; - struct pevaluator pev; - - if (!cmd) return FALSE; - pev_init(&pev, csw, fpoext, cpair); - for (ptr = cmd; !over; ptr++) - { - if (*ptr == ' ' || (over = *ptr == '\0')) - { - *ptok = '\0'; - - if (!strcmp(token, "+") || !strcmp(token, "-") || !strcmp(token, "*") || - !strcmp(token, "/") || !strcmp(token, "%")) - { - if (!pev_binop(&pev, token[0])) goto done; - } - else if (!strcmp(token, "^")) - { - if (!pev_deref(&pev)) goto done; - } - else if (!strcmp(token, "=")) - { - if (!pev_assign(&pev)) goto done; - } - else - { - if (!pev_push(&pev, token)) goto done; - } - ptok = token; - } - else - { - if (ptok - token >= PEV_MAX_LEN - 1) - { - pev_set_error(&pev, "parse: token too long (%s)", ptr - (ptok - token)); - goto done; - } - *ptok++ = *ptr; - } - } - pev_free(&pev, cpair); - return TRUE; -done: - FIXME("Couldn't evaluate %s => %s\n", debugstr_a(cmd), pev.error); - pev_free(&pev, NULL); - return FALSE; -} - -BOOL pdb_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, - union ctx *context, struct pdb_cmd_pair *cpair) -{ - struct module_pair pair; - struct pdb_module_info* pdb_info; - PDB_FPO_DATA* fpoext; - unsigned i, size; - PDB_STRING_TABLE* strbase; - BOOL ret = TRUE; - - if (!module_init_pair(&pair, csw->hProcess, ip)) return FALSE; - if (!pair.effective->format_info[DFI_PDB]) return FALSE; - pdb_info = pair.effective->format_info[DFI_PDB]->u.pdb_info; - TRACE("searching %Ix => %Ix\n", ip, ip - (DWORD_PTR)pair.effective->module.BaseOfImage); - ip -= (DWORD_PTR)pair.effective->module.BaseOfImage; - - strbase = pdb_read_strings(&pdb_info->pdb_files[0]); - if (!strbase) return FALSE; - fpoext = pdb_read_stream(&pdb_info->pdb_files[0], pdb_info->pdb_files[0].fpoext_stream); - size = pdb_get_stream_size(&pdb_info->pdb_files[0], pdb_info->pdb_files[0].fpoext_stream); - if (fpoext && (size % sizeof(*fpoext)) == 0) - { - size /= sizeof(*fpoext); - for (i = 0; i < size; i++) - { - if (fpoext[i].start <= ip && ip < fpoext[i].start + fpoext[i].func_size) - { - TRACE("\t%08x %08x %8x %8x %4x %4x %4x %08x %s\n", - fpoext[i].start, fpoext[i].func_size, fpoext[i].locals_size, - fpoext[i].params_size, fpoext[i].maxstack_size, fpoext[i].prolog_size, - fpoext[i].savedregs_size, fpoext[i].flags, - debugstr_a(pdb_get_string_table_entry(strbase, fpoext[i].str_offset))); - ret = pdb_parse_cmd_string(csw, &fpoext[i], - pdb_get_string_table_entry(strbase, fpoext[i].str_offset), - cpair); - break; - } - } - } - else ret = FALSE; - pdb_free(fpoext); - pdb_free(strbase); - - return ret; -} - /*======================================================================== * Process CodeView debug information. */ @@ -4340,7 +4068,8 @@ static BOOL codeview_process_info(const struct process *pcs, const OMFDirEntry* ent; const OMFDirEntry* prev; const OMFDirEntry* next; - unsigned int i; + unsigned int i; + BOOL has_linenumber_info = FALSE; codeview_init_basic_types(msc_dbg->module); @@ -4381,27 +4110,31 @@ static BOOL codeview_process_info(const struct process *pcs, { codeview_snarf(msc_dbg, msc_dbg->root + ent->lfo, sizeof(DWORD), ent->cb, NULL, NULL); - /* - * Check the next and previous entry. If either is a - * sstSrcModule, it contains the line number info for - * this file. - * - * FIXME: This is not a general solution! - */ - if (next && next->iMod == ent->iMod && next->SubSection == sstSrcModule) - codeview_snarf_linetab(msc_dbg, msc_dbg->root + next->lfo, - next->cb, TRUE); - - if (prev && prev->iMod == ent->iMod && prev->SubSection == sstSrcModule) - codeview_snarf_linetab(msc_dbg, msc_dbg->root + prev->lfo, - prev->cb, TRUE); - + if (SymGetOptions() & SYMOPT_LOAD_LINES) + { + /* + * Check the next and previous entry. If either is a + * sstSrcModule, it contains the line number info for + * this file. + * + * FIXME: This is not a general solution! + */ + if (next && next->iMod == ent->iMod && next->SubSection == sstSrcModule) + if (codeview_snarf_linetab(msc_dbg, msc_dbg->root + next->lfo, + next->cb, TRUE)) + has_linenumber_info = TRUE; + + if (prev && prev->iMod == ent->iMod && prev->SubSection == sstSrcModule) + if (codeview_snarf_linetab(msc_dbg, msc_dbg->root + prev->lfo, + prev->cb, TRUE)) + has_linenumber_info = TRUE; + } } } msc_dbg->module->module.SymType = SymCv; + msc_dbg->module->module.LineNumbers = has_linenumber_info; /* FIXME: we could have a finer grain here */ - msc_dbg->module->module.LineNumbers = TRUE; msc_dbg->module->module.GlobalSymbols = TRUE; msc_dbg->module->module.TypeInfo = TRUE; msc_dbg->module->module.SourceIndexed = TRUE; @@ -4440,8 +4173,9 @@ static BOOL codeview_process_info(const struct process *pcs, if (ret) { msc_dbg->module->module.CVSig = *signature; - memcpy(msc_dbg->module->module.CVData, msc_dbg->root, - sizeof(msc_dbg->module->module.CVData)); + if (*signature == CODEVIEW_RSDS_SIG) + memcpy(msc_dbg->module->module.CVData, msc_dbg->root, + sizeof(msc_dbg->module->module.CVData)); } return ret; } @@ -4631,3 +4365,48 @@ DWORD dbg_get_file_indexinfo(void* image, DWORD size, SYMSRV_INDEX_INFOW* info) return msc_get_file_indexinfo(image, dbg, num_directories, info); } + +BOOL old_pdb_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, union ctx *context) +{ + struct module_pair pair; + struct old_pdb_module_info* pdb_info; + PDB_FPO_DATA* fpoext; + unsigned i, size; + PDB_STRING_TABLE* strbase; + BOOL ret = TRUE; + + if (!module_init_pair(&pair, csw->hProcess, ip)) return FALSE; + if (!pair.effective->format_info[DFI_OLD_PDB]) return FALSE; + pdb_info = pair.effective->format_info[DFI_OLD_PDB]->u.old_pdb_info; + TRACE("searching %Ix => %Ix\n", ip, ip - (DWORD_PTR)pair.effective->module.BaseOfImage); + ip -= (DWORD_PTR)pair.effective->module.BaseOfImage; + + strbase = pdb_read_strings(&pdb_info->pdb_files[0]); + if (!strbase) return FALSE; + fpoext = pdb_read_stream(&pdb_info->pdb_files[0], pdb_info->pdb_files[0].fpoext_stream); + size = pdb_get_stream_size(&pdb_info->pdb_files[0], pdb_info->pdb_files[0].fpoext_stream); + if (fpoext && (size % sizeof(*fpoext)) == 0) + { + size /= sizeof(*fpoext); + for (i = 0; i < size; i++) + { + if (fpoext[i].start <= ip && ip < fpoext[i].start + fpoext[i].func_size) + { + TRACE("\t%08x %08x %8x %8x %4x %4x %4x %08x %s\n", + fpoext[i].start, fpoext[i].func_size, fpoext[i].locals_size, + fpoext[i].params_size, fpoext[i].maxstack_size, fpoext[i].prolog_size, + fpoext[i].savedregs_size, fpoext[i].flags, + debugstr_a(pdb_get_string_table_entry(strbase, fpoext[i].str_offset))); + ret = pdb_fpo_unwind_parse_cmd_string(csw, &fpoext[i], + pdb_get_string_table_entry(strbase, fpoext[i].str_offset), + &context->x86); + break; + } + } + } + else ret = FALSE; + pdb_free(fpoext); + pdb_free(strbase); + + return ret; +} diff --git a/dlls/dbghelp/pdb.c b/dlls/dbghelp/pdb.c new file mode 100644 index 000000000000..c4f4319de43b --- /dev/null +++ b/dlls/dbghelp/pdb.c @@ -0,0 +1,5247 @@ +/* + * File pdb.c - read debug information out of PDB files. + * + * Copyright (C) 1996, Eric Youngdale. + * Copyright (C) 1999-2000, Ulrich Weigand. + * Copyright (C) 2004-2009, Eric Pouech. + * Copyright (C) 2004-2025, Eric Pouech for CodeWeavers. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" + +#include "wine/exception.h" +#include "wine/debug.h" +#include "dbghelp_private.h" +#include "wine/mscvpdb.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_pdb); + +/* Note: this file contains the new implementation for reading PDB files. + * msc.c contains the old implementation. + */ + +/*======================================================================== + * PDB reader. + * Design goal: + * - maximize on-the-fly operations (doesn't use dbghelp internal representation) + * - limit loaded and cached memory size + * Limitations: + * - doesn't support old JG format (could be added, but to be proven worthwile) + */ + +/* Note: + * - we use integer with known size to replicate serialized data inside the PDB file + * and plain integers for the rest of the code. + * - except for file offset and stream offsets + * - functions prefixed with pdb_reader_internal are for internal helpers and shouldn't be used + */ + +/* some internal types */ +typedef uint64_t pdboff_t; /* offset in whole PDB file (64bit) */ +typedef uint32_t pdbsize_t; /* size inside a stream (including offset from beg of stream) (2G max) */ + +struct pdb_reader; +typedef enum pdb_result (*pdb_reader_fetch_block_t)(struct pdb_reader *pdb, unsigned block_no, void **block_buffer); + +struct pdb_reader_walker +{ + unsigned stream_id; + pdbsize_t offset; + pdbsize_t last; +}; + +struct pdb_type_details +{ + pdbsize_t stream_offset; /* inside TPI stream */ + cv_typ_t resolved_cv_typeid; +}; + +enum pdb_action_type +{ + action_type_cv_typ_t, /* cv_typ_t or cv_typ16_t (depending on size) */ + action_type_field, /* union codeview_fieldtype */ + action_type_globals, /* union codeview_symbol in DBI's globals stream */ +}; + +struct pdb_action_entry +{ + enum pdb_action_type action_type : 2; + unsigned action_length : 14; + pdbsize_t stream_offset; + symref_t container_symref; +}; + +struct pdb_type_hash_entry +{ + cv_typ_t cv_typeid; + struct pdb_type_hash_entry *next; +}; + +struct pdb_dbi_hash_entry +{ + pdbsize_t dbi_stream_offset; + struct pdb_dbi_hash_entry *next; +}; + +struct pdb_compiland +{ + pdbsize_t stream_offset; /* in DBI stream for compiland description */ + unsigned short are_symbols_loaded; + unsigned short stream_id; /* for all symbols of given compiland */ + struct symt_compiland* compiland; +}; + +struct pdb_reader +{ + struct module *module; + HANDLE file; + /* using ad hoc pool (not the module one), so that we can measure memory of each PDB reader during transition */ + struct pool pool; + + /* header */ + unsigned block_size; + struct PDB_DS_TOC *toc; + + /* stream information */ + struct + { + const uint32_t *blocks; /* points into toc */ + char *name; + } *streams; + char *stream_names; + + unsigned source_listed : 1, + TPI_types_invalid : 1, + IPI_types_invalid : 1; + + /* types management */ + PDB_TYPES tpi_header; + struct pdb_reader_walker tpi_types_walker; + struct pdb_type_details *tpi_typemap; /* from first to last */ + struct pdb_type_hash_entry *tpi_types_hash; + + PDB_TYPES ipi_header; + struct pdb_reader_walker ipi_walker; + + /* symbol (and types) management */ + PDB_SYMBOLS dbi_header; + unsigned num_action_globals; + unsigned num_action_entries; + struct pdb_action_entry *action_store; + struct pdb_dbi_hash_entry *dbi_symbols_hash; + unsigned short dbi_substreams[16]; /* 0 means non existing stream */ + + /* compilands */ + unsigned num_compilands; + struct pdb_compiland *compilands; + + /* cache PE module sections for mapping... + * we should rather use pe_module information + */ + const IMAGE_SECTION_HEADER *sections; + unsigned num_sections; + + /* PDB file access */ + pdb_reader_fetch_block_t fetch; + struct {unsigned block_no; unsigned age;} cache[4*4]; + char *fetch_cache_blocks; +}; + +enum pdb_result +{ + R_PDB_SUCCESS, + R_PDB_IOERROR, + R_PDB_OUT_OF_MEMORY, + R_PDB_INVALID_ARGUMENT, + R_PDB_INVALID_PDB_FILE, + R_PDB_MISSING_INFORMATION, + R_PDB_NOT_FOUND, + R_PDB_BUFFER_TOO_SMALL, +}; + +#define PDB_REPORT_UNEXPECTED(k,i) pdb_reader_report_unexpected(k, __FUNCTION__, (i)) +static enum pdb_result pdb_reader_report_unexpected(const char *kind, const char *function, unsigned id) +{ + WARN("%s: unexpected %s %x\n", function, kind, id); + return R_PDB_INVALID_PDB_FILE; +} + +static const unsigned short PDB_STREAM_TPI = 2; +static const unsigned short PDB_STREAM_DBI = 3; +static const unsigned short PDB_STREAM_IPI = 4; + +static enum pdb_result pdb_reader_fetch_file_no_cache(struct pdb_reader *pdb, void *buffer, pdboff_t offset, pdbsize_t size) +{ + OVERLAPPED ov = {.Offset = offset, .OffsetHigh = offset >> 32, .hEvent = (HANDLE)(DWORD_PTR)1}; + DWORD num_read; + + return ReadFile(pdb->file, buffer, size, &num_read, &ov) && num_read == size ? R_PDB_SUCCESS : R_PDB_IOERROR; +} + +static enum pdb_result pdb_reader_fetch_block_from_file(struct pdb_reader *pdb, unsigned block_no, void **buffer) +{ + enum pdb_result result; + unsigned i; + unsigned lru = ARRAY_SIZE(pdb->cache), found = ARRAY_SIZE(pdb->cache); + + for (i = 0; i < ARRAY_SIZE(pdb->cache); i++) + { + if (pdb->cache[i].block_no == block_no) + found = i; + else + { + pdb->cache[i].age++; + if (lru == ARRAY_SIZE(pdb->cache) || pdb->cache[lru].age < pdb->cache[i].age) + lru = i; + } + } + if (found == ARRAY_SIZE(pdb->cache)) + { + if ((result = pdb_reader_fetch_file_no_cache(pdb, pdb->fetch_cache_blocks + lru * pdb->block_size, + (pdboff_t)block_no * pdb->block_size, pdb->block_size))) return result; + pdb->cache[lru].block_no = block_no; + found = lru; + } + + pdb->cache[found].age = 0; + *buffer = pdb->fetch_cache_blocks + found * pdb->block_size; + return R_PDB_SUCCESS; +} + +static const char PDB_JG_IDENT[] = "Microsoft C/C++ program database 2.00\r\n\032JG\0"; +static const char PDB_DS_IDENT[] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0"; + +static enum pdb_result pdb_reader_get_segment_address(struct pdb_reader *pdb, unsigned segment, unsigned offset, DWORD64 *address) +{ + if (!segment || segment > pdb->num_sections) return R_PDB_INVALID_PDB_FILE; + *address = pdb->module->module.BaseOfImage + + pdb->sections[segment - 1].VirtualAddress + offset; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_get_segment_offset_from_address(struct pdb_reader *pdb, DWORD64 address, unsigned *segment, unsigned *offset) +{ + unsigned i; + + for (i = 0; i < pdb->num_sections; i++) + { + if (address >= pdb->module->module.BaseOfImage + pdb->sections[i].VirtualAddress && + address < pdb->module->module.BaseOfImage + pdb->sections[i].VirtualAddress + pdb->sections[i].Misc.VirtualSize) + { + *segment = i + 1; + *offset = address - (pdb->module->module.BaseOfImage + pdb->sections[i].VirtualAddress); + return R_PDB_SUCCESS; + } + } + return R_PDB_NOT_FOUND; +} + +static inline enum pdb_result pdb_reader_alloc(struct pdb_reader *pdb, size_t size, void **ptr) +{ + return (*ptr = pool_alloc(&pdb->pool, size)) ? R_PDB_SUCCESS : R_PDB_OUT_OF_MEMORY; +} + +static inline enum pdb_result pdb_reader_realloc(struct pdb_reader *pdb, void **ptr, size_t size) +{ + void *new = pool_realloc(&pdb->pool, *ptr, size); + if (!new) return R_PDB_OUT_OF_MEMORY; + *ptr = new; + return R_PDB_SUCCESS; +} + +static inline void pdb_reader_free(struct pdb_reader *pdb, void *ptr) +{ + pool_free(&pdb->pool, ptr); +} + +static inline unsigned pdb_reader_num_blocks(struct pdb_reader *pdb, pdbsize_t size) +{ + return (size + pdb->block_size - 1) / pdb->block_size; +} + +static enum pdb_result pdb_reader_get_stream_size(struct pdb_reader *pdb, unsigned stream_id, pdbsize_t *size) +{ + if (stream_id >= pdb->toc->num_streams) return R_PDB_INVALID_ARGUMENT; + *size = pdb->toc->stream_size[stream_id]; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_internal_read_from_blocks(struct pdb_reader *pdb, const uint32_t *blocks, pdbsize_t delta, + void *buffer, pdbsize_t size, pdbsize_t *num_read) +{ + enum pdb_result result; + pdbsize_t initial_size = size; + pdbsize_t toread; + void *block_buffer; + + while (size) + { + toread = min(pdb->block_size - delta, size); + + if ((result = (pdb->fetch)(pdb, *blocks, &block_buffer))) return result; + memcpy(buffer, (char *)block_buffer + delta, toread); + size -= toread; + blocks++; + buffer = (char*)buffer + toread; + delta = 0; + } + + if (num_read) *num_read = initial_size - size; + return size != initial_size ? R_PDB_SUCCESS : R_PDB_INVALID_ARGUMENT; +} + +static inline enum pdb_result pdb_reader_walker_init(struct pdb_reader *pdb, unsigned stream_id, struct pdb_reader_walker *walker) +{ + walker->stream_id = stream_id; + walker->offset = 0; + return pdb_reader_get_stream_size(pdb, stream_id, &walker->last); +} + +static inline enum pdb_result pdb_reader_walker_narrow(struct pdb_reader_walker *walker, pdbsize_t offset, pdbsize_t len) +{ + if (offset < walker->offset || offset + len > walker->last) return R_PDB_INVALID_ARGUMENT; + walker->offset = offset; + walker->last = offset + len; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_read_from_stream(struct pdb_reader *pdb, const struct pdb_reader_walker *walker, + void *buffer, pdbsize_t size, pdbsize_t *num_read) +{ + enum pdb_result result; + const uint32_t *blocks; + pdbsize_t delta; + + if (walker->stream_id >= pdb->toc->num_streams) return R_PDB_INVALID_ARGUMENT; + if (walker->offset >= pdb->toc->stream_size[walker->stream_id]) return R_PDB_INVALID_ARGUMENT; + if (walker->offset >= walker->last) return R_PDB_INVALID_ARGUMENT; + blocks = pdb->streams[walker->stream_id].blocks + walker->offset / pdb->block_size; + + if (walker->offset + size > pdb->toc->stream_size[walker->stream_id]) + { + size = pdb->toc->stream_size[walker->stream_id] - walker->offset; + } + if (walker->offset + size > walker->last) + { + size = walker->last - walker->offset; + } + delta = walker->offset % pdb->block_size; + + if ((result = pdb_reader_internal_read_from_blocks(pdb, blocks, delta, buffer, size, num_read))) + return result; + return R_PDB_SUCCESS; +} + +struct symref_code +{ + enum {symref_code_cv_typeid, symref_code_action} kind; + cv_typ_t cv_typeid; + unsigned action; +}; + +static inline struct symref_code *symref_code_init_from_cv_typeid(struct symref_code *code, cv_typ_t cv_typeid) +{ + code->kind = symref_code_cv_typeid; + code->cv_typeid = cv_typeid; + return code; +} + +static inline struct symref_code *symref_code_init_from_action(struct symref_code *code, unsigned action) +{ + code->kind = symref_code_action; + code->action = action; + return code; +} + +static enum pdb_result pdb_reader_encode_symref(struct pdb_reader *pdb, const struct symref_code *code, symref_t *symref) +{ + unsigned v; + switch (code->kind) + { + case symref_code_cv_typeid: + if (!code->cv_typeid) + { + *symref = 0; + return R_PDB_SUCCESS; + } + if (code->cv_typeid < T_MAXPREDEFINEDTYPE) + v = code->cv_typeid; + else if (code->cv_typeid >= pdb->tpi_header.first_index && code->cv_typeid < pdb->tpi_header.last_index) + v = T_MAXPREDEFINEDTYPE + (code->cv_typeid - pdb->tpi_header.first_index); + else + return R_PDB_INVALID_ARGUMENT; + break; + case symref_code_action: + v = T_MAXPREDEFINEDTYPE + pdb->tpi_header.last_index - pdb->tpi_header.first_index + code->action; + break; + default: + return R_PDB_INVALID_ARGUMENT; + } + *symref = (v << 2) | 1; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_decode_symref(struct pdb_reader *pdb, symref_t ref, struct symref_code *code) +{ + if ((ref & 3) != 1) return R_PDB_INVALID_ARGUMENT; + ref >>= 2; + if (ref < T_MAXPREDEFINEDTYPE) + symref_code_init_from_cv_typeid(code, ref); + else if (ref < T_MAXPREDEFINEDTYPE + pdb->tpi_header.last_index - pdb->tpi_header.first_index) + symref_code_init_from_cv_typeid(code, pdb->tpi_header.first_index + (ref - T_MAXPREDEFINEDTYPE)); + else if (ref < T_MAXPREDEFINEDTYPE + pdb->tpi_header.last_index - pdb->tpi_header.first_index + pdb->num_action_entries) + symref_code_init_from_action(code, ref - (T_MAXPREDEFINEDTYPE + pdb->tpi_header.last_index - pdb->tpi_header.first_index)); + else + return R_PDB_INVALID_ARGUMENT; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_push_action(struct pdb_reader *pdb, enum pdb_action_type action, pdbsize_t stream_offset, + unsigned id_size, symref_t container_symref, symref_t *symref) +{ + enum pdb_result result; + struct symref_code code; + + if (!(pdb->num_action_entries & (pdb->num_action_entries - 1))) + { + unsigned n = pdb->num_action_entries; + n = n ? n * 2 : 256; + if ((result = pdb_reader_realloc(pdb, (void**)&pdb->action_store, n * sizeof(pdb->action_store[0])))) return result; + } + if ((result = pdb_reader_encode_symref(pdb, symref_code_init_from_action(&code, pdb->num_action_entries), symref))) return result; + pdb->action_store[pdb->num_action_entries].action_type = action; + pdb->action_store[pdb->num_action_entries].action_length = id_size; + pdb->action_store[pdb->num_action_entries].stream_offset = stream_offset; + pdb->action_store[pdb->num_action_entries].container_symref = container_symref; + pdb->num_action_entries++; + + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_init_DBI(struct pdb_reader *pdb); +static enum pdb_result pdb_reader_internal_binary_search(size_t num_elt, + enum pdb_result (*cmp)(unsigned idx, int *cmp_ressult, void *user), + size_t *found, void *user); +static enum pdb_result pdb_reader_symref_from_cv_typeid(struct pdb_reader *pdb, cv_typ_t cv_typeid, symref_t *symref); + +static enum pdb_result pdb_reader_init(struct pdb_reader *pdb, struct module *module, HANDLE file, + const IMAGE_SECTION_HEADER *sections, unsigned num_sections) +{ + enum pdb_result result; + struct PDB_DS_HEADER hdr; + struct PDB_DS_TOC *toc = NULL; + unsigned i; + unsigned toc_blocks_size; + uint32_t *toc_blocks = NULL; + uint32_t *blocks; + + memset(pdb, 0, sizeof(*pdb)); + pdb->module = module; + pdb->file = file; + pool_init(&pdb->pool, 65536); + + pdb->module = module; + pdb->sections = sections; + pdb->num_sections = num_sections; + + if ((result = pdb_reader_fetch_file_no_cache(pdb, &hdr, 0, sizeof(hdr)))) return result; + if (!memcmp(hdr.signature, PDB_JG_IDENT, sizeof(PDB_JG_IDENT))) + { + FIXME("PDB reader doesn't support old PDB JG file format\n"); + return R_PDB_INVALID_PDB_FILE; + } + if (memcmp(hdr.signature, PDB_DS_IDENT, sizeof(PDB_DS_IDENT))) + { + ERR("PDB reader doesn't recognize format (%s)\n", wine_dbgstr_a((char*)&hdr)); + return R_PDB_INVALID_PDB_FILE; + } + pdb->block_size = hdr.block_size; + if ((result = pdb_reader_alloc(pdb, pdb->block_size * ARRAY_SIZE(pdb->cache), (void **)&pdb->fetch_cache_blocks))) goto failure; + for (i = 0; i < ARRAY_SIZE(pdb->cache); i++) + { + pdb->cache[i].block_no = 0; /* block where PDB header is, so should never be matched by a read operation */ + pdb->cache[i].age = i; + } + pdb->fetch = &pdb_reader_fetch_block_from_file; + toc_blocks_size = pdb_reader_num_blocks(pdb, hdr.toc_size) * sizeof(uint32_t); + if ((result = pdb_reader_alloc(pdb, toc_blocks_size, (void**)&toc_blocks)) || + (result = pdb_reader_fetch_file_no_cache(pdb, toc_blocks, (pdboff_t)hdr.toc_block * hdr.block_size, toc_blocks_size)) || + (result = pdb_reader_alloc(pdb, hdr.toc_size, (void**)&toc)) || + (result = pdb_reader_internal_read_from_blocks(pdb, toc_blocks, 0, toc, hdr.toc_size, NULL)) || + (result = pdb_reader_alloc(pdb, toc->num_streams * sizeof(pdb->streams[0]), (void**)&pdb->streams))) + goto failure; + pdb_reader_free(pdb, toc_blocks); + + pdb->toc = toc; + blocks = &toc->stream_size[toc->num_streams]; + for (i = 0; i < pdb->toc->num_streams; i++) + { + if (toc->stream_size[i] == 0 || toc->stream_size[i] == ~0u) + { + pdb->streams[i].blocks = NULL; + pdb->toc->stream_size[i] = 0; + } + else + { + pdb->streams[i].blocks = blocks; + blocks += pdb_reader_num_blocks(pdb, toc->stream_size[i]); + } + pdb->streams[i].name = NULL; + } + /* hack (must be set before loading debug info so it can be used therein) */ + pdb->module->ops_symref_modfmt = module->format_info[DFI_PDB]; + pdb_reader_init_DBI(pdb); + + return R_PDB_SUCCESS; + +failure: + WARN("Failed to load PDB header\n"); + pdb_reader_free(pdb, toc); + pdb_reader_free(pdb, toc_blocks); + return result; +} + +static void pdb_reader_dispose(struct pdb_reader *pdb) +{ + CloseHandle(pdb->file); + /* note: pdb is allocated inside its pool, so this must be last line */ + pool_destroy(&pdb->pool); +} + +static enum pdb_result pdb_reader_internal_read_advance(struct pdb_reader *pdb, struct pdb_reader_walker *walker, + void *buffer, pdbsize_t size) +{ + pdbsize_t num_read; + enum pdb_result result; + + if (walker->offset + size > walker->last) return R_PDB_INVALID_ARGUMENT; + result = pdb_reader_read_from_stream(pdb, walker, buffer, size, &num_read); + if (result) return result; + if (num_read != size) return R_PDB_IOERROR; + walker->offset += size; + return R_PDB_SUCCESS; +} +/* Handy macro to deserialize: ensure that read length is the type length, and advance offset in case of success */ +#define pdb_reader_READ(pdb, walker, ptr) pdb_reader_internal_read_advance((pdb), (walker), (ptr), sizeof(*(ptr))) + +static enum pdb_result pdb_reader_alloc_and_read(struct pdb_reader *pdb, struct pdb_reader_walker *walker, + pdbsize_t size, void **buffer) +{ + enum pdb_result result; + + if (walker->offset + size > walker->last) return R_PDB_INVALID_ARGUMENT; + if ((result = pdb_reader_alloc(pdb, size, buffer))) return result; + if ((result = pdb_reader_internal_read_advance(pdb, walker, *buffer, size))) + { + pdb_reader_free(pdb, *buffer); + *buffer = NULL; + return result; + } + return R_PDB_SUCCESS; +} + + +static enum pdb_result pdb_reader_fetch_string_from_stream(struct pdb_reader *pdb, struct pdb_reader_walker *walker, char *buffer, pdbsize_t length) +{ + enum pdb_result result; + pdbsize_t num_read; + char *zero; + + if (walker->offset + length > walker->last) + length = walker->last - walker->offset; + if ((result = pdb_reader_read_from_stream(pdb, walker, buffer, length, &num_read))) + return result; + if (!(zero = memchr(buffer, '\0', num_read))) + return num_read == length ? R_PDB_BUFFER_TOO_SMALL : R_PDB_INVALID_ARGUMENT; + walker->offset += zero - buffer + 1; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_load_stream_name_table(struct pdb_reader *pdb) +{ + struct pdb_reader_walker walker; + struct pdb_reader_walker ok_bits_walker; + struct PDB_DS_ROOT ds_root; + enum pdb_result result; + uint32_t count, numok, len, bitfield; + unsigned i; + + if ((result = pdb_reader_walker_init(pdb, 1, &walker)) || + (result = pdb_reader_READ(pdb, &walker, &ds_root))) + return result; + + if (ds_root.Version != 20000404) + { + ERR("-Unknown root block version %u\n", ds_root.Version); + return R_PDB_INVALID_PDB_FILE; + } + + if ((result = pdb_reader_alloc_and_read(pdb, &walker, ds_root.cbNames, (void**)&pdb->stream_names))) + goto failure; + + if ((result = pdb_reader_READ(pdb, &walker, &numok)) || + (result = pdb_reader_READ(pdb, &walker, &count))) + goto failure; + + /* account bitfield vector */ + if ((result = pdb_reader_READ(pdb, &walker, &len))) goto failure; + ok_bits_walker = walker; + walker.offset += len * sizeof(uint32_t); + + /* skip deleted vector */ + if ((result = pdb_reader_READ(pdb, &walker, &len))) goto failure; + walker.offset += len * sizeof(uint32_t); + + for (i = 0; i < count; i++) + { + if ((i & 31u) == 0) + { + if ((result = pdb_reader_READ(pdb, &ok_bits_walker, &bitfield))) + goto failure; + } + if (bitfield & (1u << (i & 31))) + { + uint32_t str_offset, stream_id; + if ((result = pdb_reader_READ(pdb, &walker, &str_offset)) || + (result = pdb_reader_READ(pdb, &walker, &stream_id))) + goto failure; + pdb->streams[stream_id].name = pdb->stream_names + str_offset; + } + } + return R_PDB_SUCCESS; +failure: + pdb_reader_free(pdb, pdb->stream_names); + pdb->stream_names = NULL; + return result; +} + +static enum pdb_result pdb_reader_get_stream_index_from_name(struct pdb_reader *pdb, const char *name, + unsigned *stream_id) +{ + unsigned i; + + if (!pdb->stream_names) + { + enum pdb_result result = pdb_reader_load_stream_name_table(pdb); + if (result) return result; + } + for (i = 0; i < pdb->toc->num_streams; i++) + if (pdb->streams[i].name && !strcmp(pdb->streams[i].name, name)) + { + *stream_id = i; + return R_PDB_SUCCESS; + } + return R_PDB_NOT_FOUND; +} + +static enum pdb_result pdb_reader_alloc_and_fetch_string(struct pdb_reader *pdb, struct pdb_reader_walker *walker, char **string) +{ + static const unsigned int alloc_step = 256; + enum pdb_result result; + unsigned len = alloc_step; + char *buffer; + + /* get string by chunks of alloc_step bytes... */ + /* Note: we never shrink the alloc buffer to its optimal size */ + for (buffer = NULL;; len += alloc_step) + { + if ((result = pdb_reader_realloc(pdb, (void**)&buffer, len))) + { + pdb_reader_free(pdb, buffer); + return result; + } + result = pdb_reader_fetch_string_from_stream(pdb, walker, buffer + len - alloc_step, alloc_step); + if (result != R_PDB_BUFFER_TOO_SMALL) + { + if (result == R_PDB_SUCCESS) + *string = buffer; + else + pdb_reader_free(pdb, buffer); + return result; + } + walker->offset += alloc_step; + } +} + +static enum pdb_result pdb_reader_skip_string(struct pdb_reader *pdb, struct pdb_reader_walker *walker) +{ + char tmp[256]; + enum pdb_result result; + + while ((result = pdb_reader_fetch_string_from_stream(pdb, walker, tmp, ARRAY_SIZE(tmp)))) + { + if (result != R_PDB_BUFFER_TOO_SMALL) break; + walker->offset += ARRAY_SIZE(tmp); + } + return result; +} + +static enum pdb_result pdb_reader_alloc_and_fetch_global_string(struct pdb_reader *pdb, pdbsize_t str_offset, char **buffer) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + unsigned stream_id; + + if ((result = pdb_reader_get_stream_index_from_name(pdb, "/names", &stream_id))) + return result; + if ((result = pdb_reader_walker_init(pdb, stream_id, &walker))) return result; + walker.offset = sizeof(PDB_STRING_TABLE) + str_offset; + return pdb_reader_alloc_and_fetch_string(pdb, &walker, buffer); +} + +static enum pdb_result pdb_reader_read_DBI_header(struct pdb_reader* pdb, PDB_SYMBOLS *dbi_header, struct pdb_reader_walker *walker) +{ + enum pdb_result result; + + /* assuming we always have that size (even for old format) in stream */ + if ((result = pdb_reader_walker_init(pdb, PDB_STREAM_DBI, walker)) || + (result = pdb_reader_READ(pdb, walker, dbi_header))) return result; + if (dbi_header->signature != 0xffffffff) + { + /* Old version of the symbols record header */ + PDB_SYMBOLS_OLD old_dbi_header = *(const PDB_SYMBOLS_OLD*)dbi_header; + + dbi_header->version = 0; + dbi_header->module_size = old_dbi_header.module_size; + dbi_header->sectcontrib_size = old_dbi_header.sectcontrib_size; + dbi_header->segmap_size = old_dbi_header.segmap_size; + dbi_header->srcmodule_size = old_dbi_header.srcmodule_size; + dbi_header->pdbimport_size = 0; + dbi_header->global_hash_stream = old_dbi_header.global_hash_stream; + dbi_header->public_stream = old_dbi_header.public_stream; + dbi_header->gsym_stream = old_dbi_header.gsym_stream; + + walker->offset = sizeof(PDB_SYMBOLS_OLD); + } + + return R_PDB_SUCCESS; +} + +static UINT32 codeview_compute_hash(const char* ptr, unsigned len) +{ + const char* last = ptr + len; + UINT32 ret = 0; + + while (ptr + sizeof(UINT32) <= last) + { + ret ^= *(UINT32*)ptr; + ptr += sizeof(UINT32); + } + if (ptr + sizeof(UINT16) <= last) + { + ret ^= *(UINT16*)ptr; + ptr += sizeof(UINT16); + } + if (ptr + sizeof(BYTE) <= last) + ret ^= *(BYTE*)ptr; + ret |= 0x20202020; + ret ^= (ret >> 11); + return ret ^ (ret >> 16); +} + +static enum pdb_result pdb_reader_read_DBI_cu_header(struct pdb_reader* pdb, DWORD dbi_header_version, + struct pdb_reader_walker *walker, + PDB_SYMBOL_FILE_EX *dbi_cu_header) +{ + enum pdb_result result; + + if (dbi_header_version >= 19970000) + { + result = pdb_reader_READ(pdb, walker, dbi_cu_header); + } + else + { + PDB_SYMBOL_FILE old_dbi_cu_header; + if (!(result = pdb_reader_READ(pdb, walker, &old_dbi_cu_header))) + { + memset(dbi_cu_header, 0, sizeof(*dbi_cu_header)); + dbi_cu_header->stream = old_dbi_cu_header.stream; + dbi_cu_header->range.index = old_dbi_cu_header.range.index; + dbi_cu_header->symbol_size = old_dbi_cu_header.symbol_size; + dbi_cu_header->lineno_size = old_dbi_cu_header.lineno_size; + dbi_cu_header->lineno2_size = old_dbi_cu_header.lineno2_size; + } + } + return result; +} + +struct pdb_reader_compiland_iterator +{ + struct pdb_reader_walker dbi_walker; /* in DBI stream */ + PDB_SYMBOLS dbi_header; + PDB_SYMBOL_FILE_EX dbi_cu_header; +}; + +static enum pdb_result pdb_reader_compiland_iterator_init(struct pdb_reader *pdb, struct pdb_reader_compiland_iterator *iter) +{ + enum pdb_result result; + if ((result = pdb_reader_read_DBI_header(pdb, &iter->dbi_header, &iter->dbi_walker))) return result; + iter->dbi_walker.last = iter->dbi_walker.offset + iter->dbi_header.module_size; + return pdb_reader_read_DBI_cu_header(pdb, iter->dbi_header.version, &iter->dbi_walker, &iter->dbi_cu_header); +} + +static enum pdb_result pdb_reader_compiland_iterator_next(struct pdb_reader *pdb, struct pdb_reader_compiland_iterator *iter) +{ + enum pdb_result result; + + if ((result = pdb_reader_skip_string(pdb, &iter->dbi_walker)) || + (result = pdb_reader_skip_string(pdb, &iter->dbi_walker))) + { + return result; + } + iter->dbi_walker.offset = (iter->dbi_walker.offset + 3) & ~3u; + return pdb_reader_read_DBI_cu_header(pdb, iter->dbi_header.version, &iter->dbi_walker, &iter->dbi_cu_header); +} + +static enum pdb_result pdb_reader_compiland_iterator_alloc_and_read_compiland_name(struct pdb_reader *pdb, const struct pdb_reader_compiland_iterator *iter, + char **obj_name) +{ + struct pdb_reader_walker walker = iter->dbi_walker; + + return pdb_reader_alloc_and_fetch_string(pdb, &walker, obj_name); +} + +struct pdb_compiland_lookup +{ + struct pdb_reader *pdb; + struct pdb_reader_walker walker; + unsigned segment; + unsigned offset; + unsigned range_size; + PDB_SYMBOL_RANGE_EX range; +}; + +static enum pdb_result pdb_reader_contrib_range_cmp(unsigned idx, int *cmp, void *user) +{ + enum pdb_result result; + struct pdb_compiland_lookup *lookup = user; + struct pdb_reader_walker walker = lookup->walker; + + walker.offset += idx * lookup->range_size; + if ((result = pdb_reader_READ(lookup->pdb, &walker, &lookup->range))) return result; + *cmp = lookup->range.segment - lookup->segment; + if (!*cmp) + *cmp = lookup->range.offset - lookup->offset; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_lookup_compiland_by_segment_offset(struct pdb_reader *pdb, unsigned segment, unsigned offset, unsigned *compiland) +{ + enum pdb_result result; + struct pdb_compiland_lookup lookup = {.pdb = pdb, .segment = segment, .offset = offset}; + UINT32 version; + PDB_SYMBOLS dbi_header; + size_t found; + unsigned num_ranges; + + if ((result = pdb_reader_walker_init(pdb, PDB_STREAM_DBI, &lookup.walker))) return result; + if ((result = pdb_reader_read_DBI_header(pdb, &dbi_header, &lookup.walker))) return result; + if ((result = pdb_reader_walker_narrow(&lookup.walker, lookup.walker.offset + dbi_header.module_size, dbi_header.sectcontrib_size))) return result; + + if ((result = pdb_reader_READ(pdb, &lookup.walker, &version))) return result; + lookup.range_size = sizeof(PDB_SYMBOL_RANGE_EX); + switch (version) + { + case 0xeffe0000 + 19970605: break; + case 0xeffe0000 + 20140516: lookup.range_size += sizeof(UINT32); break; + default: + WARN("Unsupported contrib version %x\n", version); + return R_PDB_INVALID_PDB_FILE; + } + if ((lookup.walker.last - lookup.walker.offset) % lookup.range_size) + { + WARN("Unexpected lookup values\n"); + return R_PDB_INVALID_PDB_FILE; + } + num_ranges = (lookup.walker.last - lookup.walker.offset) / lookup.range_size; + /* we assume contributions are stored in ascending order of segment / offset */ + result = pdb_reader_internal_binary_search(num_ranges, pdb_reader_contrib_range_cmp, &found, &lookup); + if (result) + { + if (result != R_PDB_NOT_FOUND) return result; + /* ensure address is within contribution range */ + if (lookup.segment != lookup.range.segment || + lookup.offset < lookup.range.offset || + lookup.offset >= lookup.range.offset + lookup.range.size) return R_PDB_NOT_FOUND; + } + *compiland = lookup.range.index; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_lookup_compiland_by_address(struct pdb_reader *pdb, DWORD_PTR address, unsigned *compiland) +{ + enum pdb_result result; + unsigned segment, offset; + if ((result = pdb_reader_get_segment_offset_from_address(pdb, address, &segment, &offset))) return result; + return pdb_reader_lookup_compiland_by_segment_offset(pdb, segment, offset, compiland); +} + +static enum pdb_result pdb_reader_subsection_next(struct pdb_reader *pdb, struct pdb_reader_walker *in_walker, + enum DEBUG_S_SUBSECTION_TYPE subsection_type, + struct pdb_reader_walker *sub_walker) +{ + enum pdb_result result; + struct CV_DebugSSubsectionHeader_t hdr; + + for (; !(result = pdb_reader_READ(pdb, in_walker, &hdr)); in_walker->offset += hdr.cbLen) + { + if (hdr.type & DEBUG_S_IGNORE) continue; + if (subsection_type && hdr.type != subsection_type) continue; + *sub_walker = *in_walker; + sub_walker->last = sub_walker->offset + hdr.cbLen; + in_walker->offset += hdr.cbLen; + return R_PDB_SUCCESS; + } + return result && result != R_PDB_INVALID_ARGUMENT ? result : R_PDB_NOT_FOUND; +} + +struct pdb_reader_linetab2_location +{ + pdbsize_t dbi_cu_header_offset; /* in DBI stream */ + unsigned cu_stream_id; /* compilation unit stream id */ + pdbsize_t lines_hdr_offset; /* in cu_stream_id */ + pdbsize_t file_hdr_offset; /* in cu_stream_id (inside lines block) */ + pdbsize_t filename_offset; /* in global stream table (after S_FILECHKSUMS redirection) */ +}; + +static enum pdb_result pdb_find_matching_linetab2(struct CV_Line_t *lines, unsigned num_lines, DWORD64 delta, unsigned *index) +{ + unsigned i; + /* since the the address is inside the file_hdr, we assume then it's matched by last entry + * (for which we don't have the next entry) + */ + for (i = 0; i + 1 < num_lines; i++) + { + if (lines[i].offset == delta || + (lines[i].offset <= delta && delta < lines[i + 1].offset)) + break; + } + *index = i; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_walker_init_linetab2(struct pdb_reader *pdb, const PDB_SYMBOL_FILE_EX *dbi_cu_header, struct pdb_reader_walker *walker) +{ + walker->stream_id = dbi_cu_header->stream; + walker->offset = dbi_cu_header->symbol_size; + walker->last = walker->offset + dbi_cu_header->lineno2_size; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_locate_filehdr_in_linetab2(struct pdb_reader *pdb, struct pdb_reader_walker linetab2_walker, + DWORD64 address, DWORD64 *lineblk_base, + struct CV_DebugSLinesFileBlockHeader_t *files_hdr, struct CV_Line_t **lines) +{ + struct pdb_reader_walker sub_walker; + enum pdb_result result; + struct CV_DebugSLinesHeader_t lines_hdr; + + while (!(result = pdb_reader_subsection_next(pdb, &linetab2_walker, DEBUG_S_LINES, &sub_walker))) + { + /* Skip blocks that are too small - Intel C Compiler generates these. */ + if (sub_walker.offset + sizeof(lines_hdr) + sizeof(struct CV_DebugSLinesFileBlockHeader_t) > sub_walker.last) + continue; + if ((result = pdb_reader_READ(pdb, &sub_walker, &lines_hdr))) return result; + if ((result = pdb_reader_get_segment_address(pdb, lines_hdr.segCon, lines_hdr.offCon, lineblk_base))) + return result; + if (*lineblk_base > address || address >= *lineblk_base + lines_hdr.cbCon) + continue; + if ((result = pdb_reader_READ(pdb, &sub_walker, files_hdr))) return result; + return pdb_reader_alloc_and_read(pdb, &sub_walker, files_hdr->nLines * sizeof((*lines)[0]),(void**)lines); + /* + if (lines_hdr.flags & CV_LINES_HAVE_COLUMNS) + sub_walker.offset += files_hdr.nLines * sizeof(struct CV_Column_t); + */ + } + return R_PDB_NOT_FOUND; +} + +static enum pdb_result pdb_reader_set_lineinfo_filename(struct pdb_reader *pdb, struct pdb_reader_walker linetab2_walker, + unsigned file_offset, struct lineinfo_t *line_info) +{ + struct pdb_reader_walker checksum_walker; + struct CV_Checksum_t checksum; + enum pdb_result result; + char *string; + + if ((result = pdb_reader_subsection_next(pdb, &linetab2_walker, DEBUG_S_FILECHKSMS, &checksum_walker))) + { + WARN("No DEBUG_S_FILECHKSMS found\n"); + return R_PDB_MISSING_INFORMATION; + } + checksum_walker.offset += file_offset; + if ((result = pdb_reader_READ(pdb, &checksum_walker, &checksum))) return result; + if ((result = pdb_reader_alloc_and_fetch_global_string(pdb, checksum.strOffset, &string))) return result; + if (!lineinfo_set_nameA(pdb->module->process, line_info, string)) + result = R_PDB_OUT_OF_MEMORY; + pdb_reader_free(pdb, string); + return result; +} + +static enum pdb_result pdb_reader_search_linetab2(struct pdb_reader *pdb, const PDB_SYMBOL_FILE_EX *dbi_cu_header, + DWORD64 address, struct lineinfo_t *line_info) +{ + struct pdb_reader_walker linetab2_walker; + struct CV_DebugSLinesFileBlockHeader_t files_hdr; + enum pdb_result result; + DWORD64 lineblk_base; + struct CV_Line_t *lines; + + if ((result = pdb_reader_walker_init_linetab2(pdb, dbi_cu_header, &linetab2_walker))) return result; + + if (!pdb_reader_locate_filehdr_in_linetab2(pdb, linetab2_walker, address, &lineblk_base, &files_hdr, &lines)) + { + unsigned i; + + if (!pdb_find_matching_linetab2(lines, files_hdr.nLines, address - lineblk_base, &i)) + { + /* found block... */ + line_info->address = lineblk_base + lines[i].offset; + line_info->line_number = lines[i].linenumStart; + return pdb_reader_set_lineinfo_filename(pdb, linetab2_walker, files_hdr.offFile, line_info); + } + pdb_reader_free(pdb, lines); + } + return R_PDB_NOT_FOUND; +} + +static enum pdb_result pdb_reader_get_line_from_address_internal(struct pdb_reader *pdb, + DWORD64 address, struct lineinfo_t *line_info, + pdbsize_t *compiland_offset) +{ + struct pdb_reader_compiland_iterator compiland_iter; + enum pdb_result result; + + if ((result = pdb_reader_compiland_iterator_init(pdb, &compiland_iter))) return result; + do + { + if (compiland_iter.dbi_cu_header.lineno2_size) + { + result = pdb_reader_search_linetab2(pdb, &compiland_iter.dbi_cu_header, address, line_info); + if (!result) + { + *compiland_offset = compiland_iter.dbi_walker.offset - sizeof(compiland_iter.dbi_cu_header); + return result; + } + if (result != R_PDB_NOT_FOUND) return result; + } + } while (pdb_reader_compiland_iterator_next(pdb, &compiland_iter) == R_PDB_SUCCESS); + + return R_PDB_NOT_FOUND; +} + +struct pdb_module_info +{ + struct pdb_reader pdb_reader; +}; + +static inline struct pdb_reader *pdb_get_current_reader(const struct module_format *modfmt) +{ + return &modfmt->u.pdb_info->pdb_reader; +} + +static enum method_result pdb_method_result(enum pdb_result result) +{ + switch (result) + { + case R_PDB_SUCCESS: return MR_SUCCESS; + case R_PDB_NOT_FOUND: return MR_NOT_FOUND; + default: return MR_FAILURE; + } +} + +static enum method_result pdb_method_get_line_from_address(struct module_format *modfmt, + DWORD64 address, struct lineinfo_t *line_info) +{ + enum pdb_result result; + struct pdb_reader *pdb; + pdbsize_t compiland_offset; + + pdb = pdb_get_current_reader(modfmt); + result = pdb_reader_get_line_from_address_internal(pdb, address, line_info, &compiland_offset); + return pdb_method_result(result); +} + +static enum pdb_result pdb_reader_advance_line_info(struct pdb_reader *pdb, + struct lineinfo_t *line_info, BOOL forward) +{ + struct pdb_reader_compiland_iterator compiland_iter; + struct pdb_reader_walker linetab2_walker; + struct CV_DebugSLinesFileBlockHeader_t files_hdr; + DWORD64 lineblk_base; + struct CV_Line_t *lines; + enum pdb_result result; + unsigned i; + + if ((result = pdb_reader_compiland_iterator_init(pdb, &compiland_iter))) + return result; + do + { + if (compiland_iter.dbi_cu_header.lineno2_size) + { + if ((result = pdb_reader_walker_init_linetab2(pdb, &compiland_iter.dbi_cu_header, &linetab2_walker))) + return result; + result = pdb_reader_locate_filehdr_in_linetab2(pdb, linetab2_walker, line_info->address, &lineblk_base, &files_hdr, &lines); + if (result == R_PDB_NOT_FOUND) continue; + if (result) return result; + if ((result = pdb_find_matching_linetab2(lines, files_hdr.nLines, line_info->address - lineblk_base, &i))) + return result; + + /* It happens that several entries have same address (yet potentially different line numbers) + * Simplify handling by getting the first entry (forward or backward) with a different address. + * More tests from native are required. + */ + if (forward) + { + for (; i + 1 < files_hdr.nLines; i++) + if (line_info->address != lineblk_base + lines[i + 1].offset) + { + line_info->address = lineblk_base + lines[i + 1].offset; + line_info->line_number = lines[i + 1].linenumStart; + break; + } + if (i + 1 >= files_hdr.nLines) + result = R_PDB_INVALID_ARGUMENT; + } + else + { + for (; i; --i) + { + if (line_info->address != lineblk_base + lines[i - 1].offset) + { + line_info->address = lineblk_base + lines[i - 1].offset; + line_info->line_number = lines[i - 1].linenumStart; + break; + } + } + if (!i) + result = R_PDB_INVALID_ARGUMENT; + } + pdb_reader_free(pdb, lines); + /* refresh filename in case it has been tempered with */ + return result ? result : pdb_reader_set_lineinfo_filename(pdb, linetab2_walker, files_hdr.offFile, line_info); + } + } while (pdb_reader_compiland_iterator_next(pdb, &compiland_iter) == R_PDB_SUCCESS); + + return R_PDB_NOT_FOUND; +} + +static enum method_result pdb_method_advance_line_info(struct module_format *modfmt, + struct lineinfo_t *line_info, BOOL forward) +{ + struct pdb_reader *pdb; + + pdb = pdb_get_current_reader(modfmt); + return pdb_reader_advance_line_info(pdb, line_info, forward) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; +} + +static enum pdb_result pdb_reader_enum_lines_linetab2(struct pdb_reader *pdb, const PDB_SYMBOL_FILE_EX *dbi_cu_header, + const WCHAR *source_file_regex, SRCCODEINFO *source_code_info, PSYM_ENUMLINES_CALLBACK cb, void *user) +{ + struct pdb_reader_walker linetab2_walker = {dbi_cu_header->stream, dbi_cu_header->symbol_size, dbi_cu_header->symbol_size + dbi_cu_header->lineno2_size}; + struct pdb_reader_walker walker, sub_walker, checksum_walker; + enum pdb_result result; + struct CV_DebugSLinesHeader_t lines_hdr; + struct CV_DebugSLinesFileBlockHeader_t files_hdr; + DWORD64 lineblk_base; + + for (checksum_walker = linetab2_walker; !(result = pdb_reader_subsection_next(pdb, &checksum_walker, DEBUG_S_FILECHKSMS, &sub_walker)); ) + { + checksum_walker = sub_walker; + break; + } + if (result) + { + WARN("No DEBUG_S_FILECHKSMS found\n"); + return R_PDB_MISSING_INFORMATION; + } + + for (walker = linetab2_walker; + !(result = pdb_reader_subsection_next(pdb, &walker, DEBUG_S_LINES, &sub_walker)); + ) + { + /* Skip blocks that are too small - Intel C Compiler generates these. */ + if (sub_walker.offset + sizeof(lines_hdr) + sizeof(struct CV_DebugSLinesFileBlockHeader_t) > sub_walker.last) + continue; + if ((result = pdb_reader_READ(pdb, &sub_walker, &lines_hdr))) return result; + if ((result = pdb_reader_get_segment_address(pdb, lines_hdr.segCon, lines_hdr.offCon, &lineblk_base))) + return result; + for (; (result = pdb_reader_READ(pdb, &sub_walker, &files_hdr)) == R_PDB_SUCCESS; /*lineblk_base += files_hdr.cbBlock*/) + { + pdbsize_t current_stream_offset; + struct CV_Checksum_t checksum; + struct CV_Line_t *lines; + char *string; + unsigned i; + BOOL match = TRUE; + + if ((result = pdb_reader_alloc_and_read(pdb, &sub_walker, files_hdr.nLines * sizeof(lines[0]), + (void**)&lines))) return result; + + /* should filter on filename */ + current_stream_offset = checksum_walker.offset; + checksum_walker.offset += files_hdr.offFile; + if ((result = pdb_reader_READ(pdb, &checksum_walker, &checksum))) return result; + if ((result = pdb_reader_alloc_and_fetch_global_string(pdb, checksum.strOffset, &string))) return result; + checksum_walker.offset = current_stream_offset; + + if (source_file_regex) + match = symt_match_stringAW(string, source_file_regex, FALSE); + if (!match) + { + sub_walker.offset += files_hdr.nLines * sizeof(struct CV_Line_t); + if (lines_hdr.flags & CV_LINES_HAVE_COLUMNS) + sub_walker.offset += files_hdr.nLines * sizeof(struct CV_Column_t); + continue; + } + if (strlen(string) < ARRAY_SIZE(source_code_info->FileName)) + strcpy(source_code_info->FileName, string); + else + source_code_info->FileName[0] = '\0'; + pdb_reader_free(pdb, string); + + for (i = 0; i < files_hdr.nLines; i++) + { + source_code_info->Address = lineblk_base + lines[i].offset; + source_code_info->LineNumber = lines[i].linenumStart; + if (!cb(source_code_info, user)) return R_PDB_NOT_FOUND; + } + pdb_reader_free(pdb, lines); + if (lines_hdr.flags & CV_LINES_HAVE_COLUMNS) + sub_walker.offset += files_hdr.nLines * sizeof(struct CV_Column_t); + } + } + return result == R_PDB_INVALID_ARGUMENT ? R_PDB_SUCCESS : result; +} + +static BOOL pdb_method_enumerate_lines_internal(struct pdb_reader *pdb, const WCHAR* compiland_regex, + const WCHAR *source_file_regex, PSYM_ENUMLINES_CALLBACK cb, void *user) +{ + struct pdb_reader_compiland_iterator compiland_iter; + enum pdb_result result; + SRCCODEINFO source_code_info; + + source_code_info.SizeOfStruct = sizeof(source_code_info); + source_code_info.ModBase = pdb->module->module.BaseOfImage; + + if ((result = pdb_reader_compiland_iterator_init(pdb, &compiland_iter))) return result; + do + { + struct pdb_reader_walker walker = compiland_iter.dbi_walker; + + if ((result = pdb_reader_fetch_string_from_stream(pdb, &walker, source_code_info.Obj, sizeof(source_code_info.Obj)))) + { + if (result == R_PDB_BUFFER_TOO_SMALL) FIXME("NOT EXPECTED --too small\n"); + return result; + } + + /* FIXME should filter on compiland (if present) */ + if (compiland_iter.dbi_cu_header.lineno2_size) + { + result = pdb_reader_enum_lines_linetab2(pdb, &compiland_iter.dbi_cu_header, source_file_regex, &source_code_info, cb, user); + } + + } while (pdb_reader_compiland_iterator_next(pdb, &compiland_iter) == R_PDB_SUCCESS); + return R_PDB_SUCCESS; +} + +static enum method_result pdb_method_enumerate_lines(struct module_format *modfmt, const WCHAR* compiland_regex, + const WCHAR *source_file_regex, PSYM_ENUMLINES_CALLBACK cb, void *user) +{ + struct pdb_reader *pdb; + + pdb = pdb_get_current_reader(modfmt); + return pdb_method_result(pdb_method_enumerate_lines_internal(pdb, compiland_regex, source_file_regex, cb, user)); +} + +static enum pdb_result pdb_reader_load_sources_linetab2(struct pdb_reader *pdb, const PDB_SYMBOL_FILE_EX *dbi_cu_header) +{ + struct pdb_reader_walker linetab2_walker = {dbi_cu_header->stream, dbi_cu_header->symbol_size, dbi_cu_header->symbol_size + dbi_cu_header->lineno2_size}; + struct pdb_reader_walker sub_walker, checksum_walker; + enum pdb_result result; + struct CV_Checksum_t chksum; + + for (checksum_walker = linetab2_walker; !(result = pdb_reader_subsection_next(pdb, &checksum_walker, DEBUG_S_FILECHKSMS, &sub_walker)); ) + { + for (; (result = pdb_reader_READ(pdb, &sub_walker, &chksum)) == R_PDB_SUCCESS; sub_walker.offset = (sub_walker.offset + chksum.size + 3) & ~3) + { + char *string; + if ((result = pdb_reader_alloc_and_fetch_global_string(pdb, chksum.strOffset, &string))) return result; + source_new(pdb->module, NULL, string); + pdb_reader_free(pdb, string); + } + } + return result == R_PDB_NOT_FOUND ? R_PDB_SUCCESS : result; +} + +static enum pdb_result pdb_load_sources_internal(struct pdb_reader *pdb) +{ + enum pdb_result result; + struct pdb_reader_compiland_iterator compiland_iter; + + if ((result = pdb_reader_compiland_iterator_init(pdb, &compiland_iter))) return result; + do + { + if (compiland_iter.dbi_cu_header.lineno2_size) + { + result = pdb_reader_load_sources_linetab2(pdb, &compiland_iter.dbi_cu_header); + } + } while (pdb_reader_compiland_iterator_next(pdb, &compiland_iter) == R_PDB_SUCCESS); + + return R_PDB_SUCCESS; +} + +static enum method_result pdb_method_enumerate_sources(struct module_format *modfmt, const WCHAR *source_file_regex, + PSYM_ENUMSOURCEFILES_CALLBACKW cb, void *user) +{ + struct pdb_reader *pdb; + + pdb = pdb_get_current_reader(modfmt); + + /* Note: in PDB, each compiland lists its used files, which are all in global string table, + * but there's no global source files table AFAICT. + * So, just walk (once) all compilands to grab all sources, and store them in generic source table. + * But don't enumerate here, let generic function take care of it. + */ + if (!pdb->source_listed) + { + enum pdb_result result = pdb_load_sources_internal(pdb); + if (result) return pdb_method_result(result); + pdb->source_listed = 1; + } + return MR_NOT_FOUND; +} + +static unsigned codeview_get_leaf_length(unsigned short type) +{ + static unsigned char codeview_leaf_length[] = + { + [LF_CHAR - LF_NUMERIC] = 1, + [LF_SHORT - LF_NUMERIC] = 2, + [LF_USHORT - LF_NUMERIC] = 2, + [LF_LONG - LF_NUMERIC] = 4, + [LF_ULONG - LF_NUMERIC] = 4, + [LF_REAL32 - LF_NUMERIC] = 4, + [LF_REAL64 - LF_NUMERIC] = 8, + [LF_REAL80 - LF_NUMERIC] = 10, + [LF_REAL128 - LF_NUMERIC] = 16, + [LF_QUADWORD - LF_NUMERIC] = 8, + [LF_UQUADWORD - LF_NUMERIC] = 8, + [LF_REAL48 - LF_NUMERIC] = 6, + [LF_COMPLEX32 - LF_NUMERIC] = 8, + [LF_COMPLEX64 - LF_NUMERIC] = 16, + [LF_COMPLEX80 - LF_NUMERIC] = 20, + [LF_COMPLEX128 - LF_NUMERIC] = 32, + [LF_VARSTRING - LF_NUMERIC] = 0, + [LF_OCTWORD - LF_NUMERIC] = 16, + [LF_UOCTWORD - LF_NUMERIC] = 16, + [LF_DECIMAL - LF_NUMERIC] = 0, + [LF_DATE - LF_NUMERIC] = 0, + [LF_UTF8STRING - LF_NUMERIC] = 0, + [LF_REAL16 - LF_NUMERIC] = 2, + }; + + if (type < LF_NUMERIC) return 0; + type -= LF_NUMERIC; + return type < ARRAY_SIZE(codeview_leaf_length) ? codeview_leaf_length[type] : 0; +} + +static int codeview_leaf_as_variant(const unsigned char *leaf, VARIANT *v) +{ + unsigned short int type = *(const unsigned short *)leaf; + + if (type < LF_NUMERIC) + { + V_VT(v) = VT_I2; + V_I2(v) = type; + return sizeof(unsigned short); + } + leaf += sizeof(unsigned short); + switch (type) + { + case LF_CHAR: + V_VT(v) = VT_I1; + V_I1(v) = *(const char*)leaf; + break; + case LF_SHORT: + V_VT(v) = VT_I2; + V_I2(v) = *(const short*)leaf; + break; + case LF_USHORT: + V_VT(v) = VT_UI2; + V_UI2(v) = *(const unsigned short*)leaf; + break; + case LF_LONG: + V_VT(v) = VT_I4; + V_I4(v) = *(const int*)leaf; + break; + case LF_ULONG: + V_VT(v) = VT_UI4; + V_UI4(v) = *(const unsigned int*)leaf; + break; + case LF_QUADWORD: + V_VT(v) = VT_I8; + V_I8(v) = *(const long long int*)leaf; + break; + case LF_UQUADWORD: + V_VT(v) = VT_UI8; + V_UI8(v) = *(const long long unsigned int*)leaf; + break; + case LF_REAL32: + V_VT(v) = VT_R4; + V_R4(v) = *(const float*)leaf; + break; + case LF_REAL64: + V_VT(v) = VT_R8; + V_R8(v) = *(const double*)leaf; + break; + + case LF_VARSTRING: + PDB_REPORT_UNEXPECTED("numeric leaf", type); + V_VT(v) = VT_EMPTY; /* FIXME */ + return 2 + *leaf; + + case LF_REAL48: + case LF_REAL80: + case LF_REAL128: + case LF_COMPLEX32: + case LF_COMPLEX64: + case LF_COMPLEX80: + case LF_COMPLEX128: + /* we can't convert them into an int */ + default: + PDB_REPORT_UNEXPECTED("numeric leaf", type); + V_VT(v) = VT_EMPTY; /* FIXME */ + return 0; + } + return sizeof(unsigned short) + codeview_get_leaf_length(type); +} + +/* read a codeview numeric leaf */ +static enum pdb_result pdb_reader_read_leaf_as_variant(struct pdb_reader *pdb, struct pdb_reader_walker *walker, VARIANT *v) +{ + enum pdb_result result; + unsigned short int type; + + if ((result = pdb_reader_READ(pdb, walker, &type))) return result; + + if (type < LF_NUMERIC) + { + V_VT(v) = VT_I2; + V_I2(v) = type; + } + else + { + switch (type) + { + case LF_CHAR: V_VT(v) = VT_I1; return pdb_reader_READ(pdb, walker, &V_I1(v)); + case LF_SHORT: V_VT(v) = VT_I2; return pdb_reader_READ(pdb, walker, &V_I2(v)); + case LF_USHORT: V_VT(v) = VT_UI2; return pdb_reader_READ(pdb, walker, &V_UI2(v)); + case LF_LONG: V_VT(v) = VT_I4; return pdb_reader_READ(pdb, walker, &V_I4(v)); + case LF_ULONG: V_VT(v) = VT_UI4; return pdb_reader_READ(pdb, walker, &V_UI4(v)); + case LF_QUADWORD: V_VT(v) = VT_I8; return pdb_reader_READ(pdb, walker, &V_I8(v)); + case LF_UQUADWORD: V_VT(v) = VT_UI8; return pdb_reader_READ(pdb, walker, &V_UI8(v)); + case LF_REAL32: V_VT(v) = VT_R4; return pdb_reader_READ(pdb, walker, &V_R4(v)); + case LF_REAL64: V_VT(v) = VT_R8; return pdb_reader_READ(pdb, walker, &V_R8(v)); + + /* types that don't simply fit inside VARIANT (would need conversion) */ + + case LF_OCTWORD: + case LF_UOCTWORD: + case LF_REAL48: + case LF_REAL80: + case LF_REAL128: + case LF_COMPLEX32: + case LF_COMPLEX64: + case LF_COMPLEX80: + case LF_COMPLEX128: + + /* case LF_VARSTRING: */ + + /* as we don't know the length... will lead to later issues */ + default: + break; + } + PDB_REPORT_UNEXPECTED("numeric leaf", type); + walker->offset += codeview_get_leaf_length(type); + V_VT(v) = VT_EMPTY; + } + + return R_PDB_SUCCESS; +} + +/* read a codeview numeric leaf from a partially loaded codeview type */ +static enum pdb_result codeview_leaf_as_int(const unsigned char *data, int *value) +{ + unsigned short int type; + + type = *(unsigned short int*)data; + if (type < LF_NUMERIC) + { + *value = type; + } + else + { + switch (type) + { + case LF_CHAR: *value = *(char*)(data + 2); break; + case LF_SHORT: *value = (int)*(short*)(data + 2); break; + case LF_USHORT: *value = *(unsigned short*)(data + 2); break; + case LF_LONG: *value = *(int*)(data + 2); break; + case LF_ULONG: *value = *(unsigned*)(data + 2); break; + + /* the leaves we can't convert into an int */ + case LF_QUADWORD: + case LF_UQUADWORD: + case LF_OCTWORD: + case LF_UOCTWORD: + case LF_REAL32: + case LF_REAL48: + case LF_REAL64: + case LF_REAL80: + case LF_REAL128: + case LF_COMPLEX32: + case LF_COMPLEX64: + case LF_COMPLEX80: + case LF_COMPLEX128: + + case LF_VARSTRING: + /* as we don't know the length... will lead to later issues */ + + default: + PDB_REPORT_UNEXPECTED("numeric leaf", type); + return R_PDB_INVALID_ARGUMENT; + } + } + + return R_PDB_SUCCESS; +} + +static enum pdb_result codeview_fetch_leaf_as_int(const union codeview_type *cv_type, const unsigned char *data, int *value) +{ + unsigned data_len = min(sizeof(*cv_type), sizeof(cv_type->generic.len) + cv_type->generic.len) - (data - (const unsigned char*)cv_type); + unsigned short int type; + + if (data_len < sizeof(unsigned short)) return R_PDB_BUFFER_TOO_SMALL; + + type = *(unsigned short int*)data; + if (type >= LF_NUMERIC && data_len < codeview_get_leaf_length(type)) + return R_PDB_BUFFER_TOO_SMALL; + return codeview_leaf_as_int(data, value); +} + +static WCHAR *heap_allocate_symname(const char *string) +{ + unsigned sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0); + WCHAR *stringW; + + stringW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)); + if (stringW) + MultiByteToWideChar(CP_ACP, 0, string, -1, stringW, sz); + return stringW; +} + +#define loc_cv_local_range (loc_user + 0) /* loc.offset contain the copy of all defrange* Codeview records following S_LOCAL */ +#define loc_cv_defrange (loc_user + 1) /* loc.register+offset contain the stream_id+stream_offset of S_LOCAL Codeview record to search into */ + +/* Some data (codeview_symbol, codeview_types...) are layed out with a 2 byte integer, + * designing length of following blob. + * Basic reading of that length + (part) of blob. + * Walker is advanced by 2 only (so that any reading inside blob is possible). + */ +static enum pdb_result pdb_reader_read_partial_blob(struct pdb_reader *pdb, struct pdb_reader_walker *walker, void *blob, unsigned blob_size) +{ + enum pdb_result result; + pdbsize_t num_read, toload; + unsigned short len; + + if ((result = pdb_reader_internal_read_advance(pdb, walker, &len, sizeof(len)))) return result; + toload = min(len, blob_size - sizeof(len)); + + if ((result = pdb_reader_read_from_stream(pdb, walker, (char*)blob + sizeof(len), toload, &num_read))) return result; + if (num_read != toload) return R_PDB_IOERROR; + *(unsigned short*)blob = len; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_alloc_and_read_full_blob(struct pdb_reader *pdb, struct pdb_reader_walker *walker, void **blob) +{ + enum pdb_result result; + unsigned short int len; + + if ((result = pdb_reader_READ(pdb, walker, &len))) return result; + if ((result = pdb_reader_alloc(pdb, len + sizeof(len), blob))) + { + walker->offset -= sizeof(len); + return result; + } + + if ((result = pdb_reader_internal_read_advance(pdb, walker, (char*)*blob + sizeof(len), len))) + { + pdb_reader_free(pdb, *blob); + walker->offset -= sizeof(len); + return result; + } + *(unsigned short int*)*blob = len; + return R_PDB_SUCCESS; +} + +/* Read the fixed part of a CodeView symbol (enough to fit inside the union codeview) */ +static enum pdb_result pdb_reader_read_partial_codeview_symbol(struct pdb_reader *pdb, struct pdb_reader_walker *walker, union codeview_symbol *cv_symbol) +{ + return pdb_reader_read_partial_blob(pdb, walker, (void*)cv_symbol, sizeof(*cv_symbol)); +} + +static enum pdb_result pdb_reader_alloc_and_read_full_codeview_symbol(struct pdb_reader *pdb, struct pdb_reader_walker *walker, + union codeview_symbol **cv_symbol) +{ + return pdb_reader_alloc_and_read_full_blob(pdb, walker, (void **)cv_symbol); +} + +static enum pdb_result pdb_reader_load_DBI_hash_table(struct pdb_reader *pdb) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + DBI_HASH_HEADER dbi_hash_header; + unsigned num_hash_records; + DBI_HASH_RECORD hash_record; + UINT32 bitmap; + UINT32 start_index, end_index; + unsigned index, last_index, i, j; + struct pdb_dbi_hash_entry *entry; + + if ((result = pdb_reader_walker_init(pdb, pdb->dbi_header.global_hash_stream, &walker))) return result; + if ((result = pdb_reader_READ(pdb, &walker, &dbi_hash_header))) return result; + if (dbi_hash_header.signature != 0xFFFFFFFF || + dbi_hash_header.version != 0xeffe0000 + 19990810) + { + WARN("Incorrect hash stream header\n"); + return R_PDB_INVALID_PDB_FILE; + } + if (dbi_hash_header.hash_records_size) + { + if ((dbi_hash_header.hash_records_size % sizeof(DBI_HASH_RECORD)) != 0 || + sizeof(DBI_HASH_HEADER) + dbi_hash_header.hash_records_size + DBI_BITMAP_HASH_SIZE > walker.last || + (walker.last - (sizeof(DBI_HASH_HEADER) + dbi_hash_header.hash_records_size + DBI_BITMAP_HASH_SIZE)) % sizeof(uint32_t)) + { + WARN("Incorrect hash structure\n"); + return R_PDB_INVALID_PDB_FILE; + } + } + + if ((result = pdb_reader_alloc(pdb, sizeof(pdb->dbi_symbols_hash[0]) * (DBI_MAX_HASH + 1), (void **)&pdb->dbi_symbols_hash))) return result; + memset(pdb->dbi_symbols_hash, 0, sizeof(pdb->dbi_symbols_hash[0]) * (DBI_MAX_HASH + 1)); + for (index = 0, i = 0; i <= DBI_MAX_HASH; i++) + pdb->dbi_symbols_hash[i].next = &pdb->dbi_symbols_hash[i]; + + if (!dbi_hash_header.hash_records_size) return R_PDB_SUCCESS; + num_hash_records = dbi_hash_header.hash_records_size / sizeof(DBI_HASH_RECORD); + last_index = (walker.last - (sizeof(DBI_HASH_HEADER) + dbi_hash_header.hash_records_size + DBI_BITMAP_HASH_SIZE)) / sizeof(UINT32); + + for (index = 0, i = 0; i <= DBI_MAX_HASH; i++) + { + if ((i & 31) == 0) + { + walker.offset = sizeof(DBI_HASH_HEADER) + dbi_hash_header.hash_records_size + (i / 32) * 4; + if ((result = pdb_reader_READ(pdb, &walker, &bitmap))) goto on_error; + } + if (bitmap & (1u << (i % 32))) + { + walker.offset = sizeof(DBI_HASH_HEADER) + dbi_hash_header.hash_records_size + DBI_BITMAP_HASH_SIZE + index * sizeof(UINT32); + /* Yes, offsets for accessing the hash_record:s are stored as multiple of 12; + * and not as multiple of sizeof(hash_record) = 8 as one might expect. + * Perhaps, native implementation likes to keep the same offsets between + * in memory representation vs on file representations. + */ + if ((result = pdb_reader_READ(pdb, &walker, &start_index))) goto on_error; + start_index /= 12; + if (index + 1 < last_index) + { + if ((result = pdb_reader_READ(pdb, &walker, &end_index))) goto on_error; + end_index /= 12; + } + else + end_index = num_hash_records; + index++; + + for (j = start_index; j < end_index; j++) + { + walker.offset = sizeof(DBI_HASH_HEADER) + j * sizeof(DBI_HASH_RECORD); + if ((result = pdb_reader_READ(pdb, &walker, &hash_record))) goto on_error; + if (pdb->dbi_symbols_hash[i].next == &pdb->dbi_symbols_hash[i]) /* empty slot */ + { + pdb->dbi_symbols_hash[i].dbi_stream_offset = hash_record.offset - 1; + pdb->dbi_symbols_hash[i].next = NULL; + } + else + { + struct pdb_dbi_hash_entry **last; + if ((result = pdb_reader_alloc(pdb, sizeof(*entry), (void **)&entry))) goto on_error; + entry->dbi_stream_offset = hash_record.offset - 1; + entry->next = NULL; + for (last = &pdb->dbi_symbols_hash[i].next; *last; last = &(*last)->next) {} + *last = entry; + } + } + } + } + return R_PDB_SUCCESS; +on_error: + for (i = 0; i <= DBI_MAX_HASH; i++) + { + struct pdb_dbi_hash_entry *current, *next; + if (pdb->dbi_symbols_hash[i].next == &pdb->dbi_symbols_hash[i]) continue; + for (current = pdb->dbi_symbols_hash[i].next; current; current = next) + { + next = current->next; + pdb_reader_free(pdb, current); + } + } + pdb_reader_free(pdb, pdb->dbi_symbols_hash); + pdb->dbi_symbols_hash = NULL; + return result; +} + +static enum pdb_result pdb_reader_extract_name_out_of_codeview_symbol(union codeview_symbol *cv_symbol, char **name, size_t *length) +{ + switch (cv_symbol->generic.id) + { + case S_UDT: + *name = cv_symbol->udt_v3.name; + break; + case S_PROCREF: + case S_LPROCREF: + case S_DATAREF: + *name = cv_symbol->refsym2_v3.name; + break; + case S_CONSTANT: + *name = (char *)(cv_symbol->constant_v3.data + codeview_get_leaf_length(*(unsigned short*)cv_symbol->constant_v3.data)); + break; + case S_LDATA32: + case S_GDATA32: + *name = cv_symbol->data_v3.name; + break; + case S_LTHREAD32: + case S_GTHREAD32: + *name = cv_symbol->thread_v3.name; + break; + default: + return R_PDB_INVALID_ARGUMENT; + } + *length = strlen(*name); + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_read_DBI_codeview_symbol_by_name(struct pdb_reader *pdb, const char *name, + pdbsize_t *stream_offset, union codeview_symbol *cv_symbol) +{ + enum pdb_result result; + UINT32 hash; + struct pdb_reader_walker walker; + union codeview_symbol *full_cv_symbol; + char *cv_name; + size_t cv_length; + + if ((result = pdb_reader_walker_init(pdb, pdb->dbi_header.gsym_stream, &walker))) return result; + hash = codeview_compute_hash(name, strlen(name)) % DBI_MAX_HASH; + if (pdb->dbi_symbols_hash[hash].next != &pdb->dbi_symbols_hash[hash]) + { + struct pdb_dbi_hash_entry *entry; + for (entry = &pdb->dbi_symbols_hash[hash]; entry; entry = entry->next) + { + walker.offset = entry->dbi_stream_offset; + if ((result = pdb_reader_alloc_and_read_full_codeview_symbol(pdb, &walker, &full_cv_symbol))) return result; + if (pdb_reader_extract_name_out_of_codeview_symbol(full_cv_symbol, &cv_name, &cv_length) == R_PDB_SUCCESS) + { + if (!strcmp(name, cv_name)) + { + *cv_symbol = *full_cv_symbol; + pdb_reader_free(pdb, full_cv_symbol); + *stream_offset = entry->dbi_stream_offset; + return R_PDB_SUCCESS; + } + pdb_reader_free(pdb, full_cv_symbol); + } + } + } + TRACE("not found in hash bucket %s\n", debugstr_a(name)); + return R_PDB_NOT_FOUND; +} + +struct pdb_reader_whole_stream +{ + unsigned short stream_id; + const BYTE *data; +}; + +static enum pdb_result pdb_reader_alloc_and_load_whole_stream(struct pdb_reader *pdb, unsigned short stream_id, struct pdb_reader_whole_stream *whole) +{ + enum pdb_result result; + const uint32_t *blocks; + unsigned num_blocks, i, j; + BYTE *buffer; + + memset(whole, 0, sizeof(*whole)); + if (stream_id >= pdb->toc->num_streams) return R_PDB_INVALID_ARGUMENT; + if (pdb->toc->stream_size[stream_id] == 0 || pdb->toc->stream_size[stream_id] == 0xFFFFFFFF) return R_PDB_NOT_FOUND; + + blocks = pdb->streams[stream_id].blocks; + num_blocks = ((pdboff_t)pdb->toc->stream_size[stream_id] + pdb->block_size - 1) / pdb->block_size; + buffer = HeapAlloc(GetProcessHeap(), 0, num_blocks * pdb->block_size); + if (!buffer) return R_PDB_OUT_OF_MEMORY; + + for (i = 0; i < num_blocks; i = j) + { + /* find all contiguous blocks to read them at once */ + for (j = i + 1; j < num_blocks && blocks[j] == blocks[j - 1] + 1; j++) {} + if ((result = pdb_reader_fetch_file_no_cache(pdb, buffer + i * pdb->block_size, + (pdboff_t)blocks[i] * pdb->block_size, (j - i) * pdb->block_size))) + { + HeapFree(GetProcessHeap(), 0, buffer); + return result; + } + } + whole->stream_id = stream_id; + whole->data = buffer; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_dispose_whole_stream(struct pdb_reader *pdb, struct pdb_reader_whole_stream *whole) +{ + HeapFree(GetProcessHeap(), 0, (void *)whole->data); + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_whole_stream_access_codeview_symbol(struct pdb_reader *pdb, struct pdb_reader_whole_stream *whole, + unsigned offset, const union codeview_symbol **cv_symbol) +{ + const union codeview_symbol *cv = (const void *)(whole->data + offset); + if (!whole->data || + offset + sizeof(cv->generic) > pdb->toc->stream_size[whole->stream_id] || + offset + sizeof(cv->generic.len) + cv->generic.len > pdb->toc->stream_size[whole->stream_id]) return R_PDB_INVALID_ARGUMENT; + *cv_symbol = cv; + return R_PDB_SUCCESS; +} + +static int my_action_global_obj_cmp(const void *p1, const void *p2) +{ + pdbsize_t o1 = ((const struct pdb_action_entry *)p1)->stream_offset; + pdbsize_t o2 = ((const struct pdb_action_entry *)p2)->stream_offset; + + if (o1 < o2) return -1; + if (o1 > o2) return +1; + return 0; +} + +static enum pdb_result pdb_reader_init_DBI_substreams(struct pdb_reader *pdb) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + PDB_SYMBOLS dbi_header; + unsigned i; + unsigned short streamid; + + if ((result = pdb_reader_read_DBI_header(pdb, &dbi_header, &walker))) return result; + walker.offset += dbi_header.module_size + dbi_header.sectcontrib_size + + dbi_header.segmap_size + dbi_header.srcmodule_size + + dbi_header.pdbimport_size + dbi_header.unknown2_size; + walker.last = walker.offset + dbi_header.stream_index_size; + for (i = 0; i < ARRAY_SIZE(pdb->dbi_substreams); i++) + { + if (pdb_reader_READ(pdb, &walker, &streamid)) streamid = 0xffff; + pdb->dbi_substreams[i] = streamid; + } + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_init_DBI(struct pdb_reader *pdb) +{ + enum pdb_result result; + struct pdb_reader_compiland_iterator compiland_iter; + struct pdb_reader_walker walker; + struct pdb_reader_whole_stream whole; + const union codeview_symbol *cv_global_symbol, *cv_global_symbol2; + unsigned hash; + symref_t symref; + unsigned i; + + if ((result = pdb_reader_read_DBI_header(pdb, &pdb->dbi_header, &walker))) return result; + + /* count number of compilands */ + if ((result = pdb_reader_compiland_iterator_init(pdb, &compiland_iter))) return result; + do + { + pdb->num_compilands++; + } while ((result = pdb_reader_compiland_iterator_next(pdb, &compiland_iter)) == R_PDB_SUCCESS); + if ((result = pdb_reader_alloc(pdb, pdb->num_compilands * sizeof(pdb->compilands[0]), (void **)&pdb->compilands))) return result; + memset(pdb->compilands, 0, pdb->num_compilands * sizeof(pdb->compilands[0])); + /* fill-in compiland information */ + if ((result = pdb_reader_compiland_iterator_init(pdb, &compiland_iter))) return result; + for (i = 0; i < pdb->num_compilands; i++) + { + pdb->compilands[i].stream_offset = compiland_iter.dbi_walker.offset; + pdb->compilands[i].compiland = NULL; + pdb->compilands[i].stream_id = compiland_iter.dbi_cu_header.stream; + pdb->compilands[i].are_symbols_loaded = pdb->compilands[i].stream_id == 0xffff; + result = pdb_reader_compiland_iterator_next(pdb, &compiland_iter); + if ((result == R_PDB_SUCCESS) != (i + 1 < pdb->num_compilands)) return result ? result : R_PDB_INVALID_PDB_FILE; + } + if ((result = pdb_reader_load_DBI_hash_table(pdb))) return result; + + if ((result = pdb_reader_alloc_and_load_whole_stream(pdb, pdb->dbi_header.gsym_stream, &whole))) return result; + + for (hash = 0; hash < DBI_MAX_HASH; hash++) + { + struct pdb_dbi_hash_entry *entry, *entry2; + DWORD64 address; + symref_t type_symref; + BOOL found; + + if (pdb->dbi_symbols_hash[hash].next == &pdb->dbi_symbols_hash[hash]) continue; + for (entry = &pdb->dbi_symbols_hash[hash]; entry; entry = entry->next) + { + if (!pdb_reader_whole_stream_access_codeview_symbol(pdb, &whole, entry->dbi_stream_offset, &cv_global_symbol)) + { + switch (cv_global_symbol->generic.id) + { + case S_UDT: + if ((result = pdb_reader_push_action(pdb, action_type_globals, entry->dbi_stream_offset, + cv_global_symbol->generic.len + sizeof(cv_global_symbol->generic.len), 0, &symref))) return result; + break; + case S_GDATA32: + /* There are cases (incremental linking) where we have several entries of same name, but + * only one is valid. + * We discriminate valid with: + * - there's no other entry with same name before this entry in hash bucket, + * - the address is valid + * - the typeid is valid + * Note: checking address map doesn't bring nothing as the invalid entries are also listed + * there. + */ + found = FALSE; + for (entry2 = &pdb->dbi_symbols_hash[hash]; !found && entry2 && entry2 != entry; entry2 = entry2->next) + { + if (!pdb_reader_whole_stream_access_codeview_symbol(pdb, &whole, entry2->dbi_stream_offset, &cv_global_symbol2)) + found = !strcmp(cv_global_symbol->data_v3.name, cv_global_symbol2->data_v3.name); + } + if (!found && + !pdb_reader_get_segment_address(pdb, cv_global_symbol->data_v3.segment, cv_global_symbol->data_v3.offset, &address) && + !pdb_reader_symref_from_cv_typeid(pdb, cv_global_symbol->data_v3.symtype, &type_symref)) + { + struct location loc = {.kind = loc_absolute, .reg = 0, .offset = address}; + symt_new_global_variable(pdb->module, 0, cv_global_symbol->data_v3.name, + FALSE, loc, 0, type_symref); + } + break; + } + } + } + } + if ((result = pdb_reader_dispose_whole_stream(pdb, &whole))) return result; + pdb->num_action_globals = pdb->num_action_entries; + /* as we walked the DBI stream according to hash order, resort by stream_offset */ + qsort(pdb->action_store, pdb->num_action_globals, sizeof(pdb->action_store[0]), + &my_action_global_obj_cmp); + + if ((result = pdb_reader_init_DBI_substreams(pdb))) return result; + + return R_PDB_SUCCESS; +} + +static void pdb_method_location_compute(const struct module_format* modfmt, + const struct symt_function* func, + struct location* loc) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + struct pdb_reader *pdb; + union codeview_symbol cv_local; + union codeview_symbol *cv_def; + DWORD64 ip = modfmt->module->process->localscope_pc; + struct location in_loc = *loc; + + loc->kind = loc_error; + loc->reg = loc_err_internal; + + pdb = pdb_get_current_reader(modfmt); + if (in_loc.kind != loc_cv_defrange || pdb_reader_walker_init(pdb, in_loc.reg, &walker)) return; + walker.offset = in_loc.offset; + + /* we have in location: in_loc.reg = stream_id, in_loc.offset offset in stream_id to point to S_LOCAL */ + if ((result = pdb_reader_read_partial_codeview_symbol(pdb, &walker, &cv_local))) return; + walker.offset += cv_local.generic.len; + + while ((result = pdb_reader_alloc_and_read_full_codeview_symbol(pdb, &walker, &cv_def)) == R_PDB_SUCCESS && + cv_def->generic.id >= S_DEFRANGE && cv_def->generic.id <= S_DEFRANGE_REGISTER_REL) + { + BOOL inside = TRUE; + + /* S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE matches full function scope... + * Assuming that if we're here, ip matches the function for which we're + * considering the S_LOCAL and S_DEFRANGE_*, there's nothing to do. + */ + if (cv_def->generic.id != S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE) + { + const struct cv_addr_range* range; + const struct cv_addr_gap* gap; + DWORD64 range_start; + + switch (cv_def->generic.id) + { + case S_DEFRANGE: range = &cv_def->defrange_v3.range; break; + case S_DEFRANGE_SUBFIELD: range = &cv_def->defrange_subfield_v3.range; break; + case S_DEFRANGE_REGISTER: range = &cv_def->defrange_register_v3.range; break; + case S_DEFRANGE_FRAMEPOINTER_REL: range = &cv_def->defrange_frameptrrel_v3.range; break; + case S_DEFRANGE_SUBFIELD_REGISTER: range = &cv_def->defrange_subfield_register_v3.range; break; + case S_DEFRANGE_REGISTER_REL: range = &cv_def->defrange_registerrel_v3.range; break; + default: range = NULL; + } + + /* check if inside range */ + if ((result = pdb_reader_get_segment_address(pdb, range->isectStart, range->offStart, &range_start))) + { + pdb_reader_free(pdb, cv_def); + return; + } + inside = range_start <= ip && ip < range_start + range->cbRange; + + /* the gaps describe part which shall be excluded from range */ + for (gap = (const void*)(range + 1); + inside && (const char*)(gap + 1) <= (const char*)cv_def + sizeof(cv_def->generic.len) + cv_def->generic.len; + gap++) + { + if (func->ranges[0].low + gap->gapStartOffset <= ip && + ip < func->ranges[0].low + gap->gapStartOffset + gap->cbRange) + inside = FALSE; + } + } + if (!inside) + { + pdb_reader_free(pdb, cv_def); + continue; + } + + switch (cv_def->generic.id) + { + case S_DEFRANGE: + case S_DEFRANGE_SUBFIELD: + default: + WARN("Unsupported defrange %d\n", cv_def->generic.id); + loc->kind = loc_error; + loc->reg = loc_err_internal; + break; + case S_DEFRANGE_SUBFIELD_REGISTER: + WARN("sub-field part not handled\n"); + /* fall through */ + case S_DEFRANGE_REGISTER: + loc->kind = loc_register; + loc->reg = cv_def->defrange_register_v3.reg; + break; + case S_DEFRANGE_REGISTER_REL: + loc->kind = loc_regrel; + loc->reg = cv_def->defrange_registerrel_v3.baseReg; + loc->offset = cv_def->defrange_registerrel_v3.offBasePointer; + break; + case S_DEFRANGE_FRAMEPOINTER_REL: + loc->kind = loc_regrel; + loc->reg = modfmt->module->cpu->frame_regno; + loc->offset = cv_def->defrange_frameptrrel_v3.offFramePointer; + break; + case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + loc->kind = loc_regrel; + loc->reg = modfmt->module->cpu->frame_regno; + loc->offset = cv_def->defrange_frameptr_relfullscope_v3.offFramePointer; + break; + } + pdb_reader_free(pdb, cv_def); + return; + } + if (result == R_PDB_SUCCESS) pdb_reader_free(pdb, cv_def); + loc->kind = loc_error; + loc->reg = loc_err_out_of_scope; +} + +static struct {enum BasicType bt; unsigned char size;} supported_basic[T_MAXBASICTYPE] = +{ + /* all others are defined as 0 = btNoType */ + [T_VOID] = {btVoid, 0}, + [T_CURRENCY] = {btCurrency, 8}, + [T_CHAR] = {btInt, 1}, + [T_SHORT] = {btInt, 2}, + [T_LONG] = {btLong, 4}, + [T_QUAD] = {btInt, 8}, + [T_OCT] = {btInt, 16}, + [T_UCHAR] = {btUInt, 1}, + [T_USHORT] = {btUInt, 2}, + [T_ULONG] = {btULong, 4}, + [T_UQUAD] = {btUInt, 8}, + [T_UOCT] = {btUInt, 16}, + [T_BOOL08] = {btBool, 1}, + [T_BOOL16] = {btBool, 2}, + [T_BOOL32] = {btBool, 4}, + [T_BOOL64] = {btBool, 8}, + [T_REAL16] = {btFloat, 2}, + [T_REAL32] = {btFloat, 4}, + [T_REAL64] = {btFloat, 8}, + [T_REAL80] = {btFloat, 10}, + [T_REAL128] = {btFloat, 16}, + [T_RCHAR] = {btChar, 1}, + [T_WCHAR] = {btWChar, 2}, + [T_CHAR16] = {btChar16, 2}, + [T_CHAR32] = {btChar32, 4}, + [T_CHAR8] = {btChar8, 1}, + [T_INT2] = {btInt, 2}, + [T_UINT2] = {btUInt, 2}, + [T_INT4] = {btInt, 4}, + [T_UINT4] = {btUInt, 4}, + [T_INT8] = {btInt, 8}, + [T_UINT8] = {btUInt, 8}, + [T_HRESULT] = {btUInt, 4}, + [T_CPLX32] = {btComplex, 8}, + [T_CPLX64] = {btComplex, 16}, + [T_CPLX128] = {btComplex, 32}, +}; + +static inline BOOL is_basic_supported(unsigned basic) +{ + return basic < T_MAXBASICTYPE && supported_basic[basic].bt != btNoType; +} + +static enum method_result pdb_reader_default_request(struct pdb_reader *pdb, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + switch (req) + { + case TI_FINDCHILDREN: + return ((TI_FINDCHILDREN_PARAMS*)data)->Count == 0 ? MR_SUCCESS : MR_FAILURE; + case TI_GET_CHILDRENCOUNT: + *((DWORD*)data) = 0; + return MR_SUCCESS; + case TI_GET_LEXICALPARENT: + *((DWORD*)data) = symt_ptr_to_index(pdb->module, &pdb->module->top->symt); + return MR_SUCCESS; + default: + FIXME("Unexpected request %x\n", req); + return MR_FAILURE; + } +} + +static enum method_result pdb_reader_basic_request(struct pdb_reader *pdb, unsigned basic, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + struct symref_code code; + symref_t symref; + + if (!is_basic_supported(basic & T_BASICTYPE_MASK)) + { + PDB_REPORT_UNEXPECTED("basic type", basic); + return MR_FAILURE; + } + + switch (req) + { + case TI_GET_BASETYPE: + if (basic >= T_MAXBASICTYPE) return MR_FAILURE; + *((DWORD*)data) = supported_basic[basic & T_BASICTYPE_MASK].bt; + break; + case TI_GET_LENGTH: + switch (basic & T_MODE_MASK) + { + case 0: *((DWORD64*)data) = supported_basic[basic & T_BASICTYPE_MASK].size; break; + /* pointer type */ + case T_NEARPTR_BITS: *((DWORD64*)data) = pdb->module->cpu->word_size; break; + case T_NEAR32PTR_BITS: *((DWORD64*)data) = 4; break; + case T_NEAR64PTR_BITS: *((DWORD64*)data) = 8; break; + default: return MR_FAILURE; + } + break; + case TI_GET_SYMTAG: + *((DWORD*)data) = (basic < T_MAXBASICTYPE) ? SymTagBaseType : SymTagPointerType; + break; + case TI_GET_TYPE: + case TI_GET_TYPEID: + if (basic < T_MAXBASICTYPE) return MR_FAILURE; + if (pdb_reader_encode_symref(pdb, symref_code_init_from_cv_typeid(&code, basic & T_BASICTYPE_MASK), &symref)) return MR_FAILURE; + *((DWORD*)data) = symt_symref_to_index(pdb->module, symref); + break; + case TI_FINDCHILDREN: + case TI_GET_CHILDRENCOUNT: + case TI_GET_LEXICALPARENT: + return pdb_reader_default_request(pdb, req, data); + default: + return MR_FAILURE; + } + return MR_SUCCESS; +} + +static enum pdb_result pdb_reader_read_cv_typeid_hash(struct pdb_reader *pdb, cv_typ_t cv_typeid, unsigned *hash) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + unsigned value = 0; + + if ((result = pdb_reader_walker_init(pdb, pdb->tpi_header.hash_stream, &walker))) return result; + walker.offset += pdb->tpi_header.hash_offset + (cv_typeid - pdb->tpi_header.first_index) * pdb->tpi_header.hash_value_size; + + /* little endian reading */ + if ((result = pdb_reader_internal_read_advance(pdb, &walker, &value, pdb->tpi_header.hash_value_size))) return result; + if (value >= pdb->tpi_header.hash_num_buckets) + { + WARN("hash value %x isn't within hash table boundaries (0, %x(\n", value, pdb->tpi_header.hash_num_buckets); + return R_PDB_INVALID_PDB_FILE; + } + *hash = value; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_init_TPI(struct pdb_reader *pdb) +{ + enum pdb_result result; + unsigned i; + + if (pdb->TPI_types_invalid) return R_PDB_INVALID_PDB_FILE; + if (!pdb->tpi_typemap) /* load basic types information and hash table */ + { + if ((result = pdb_reader_walker_init(pdb, PDB_STREAM_TPI, &pdb->tpi_types_walker))) goto invalid_file; + /* assuming stream is always big enough go hold a full PDB_TYPES */ + if ((result = pdb_reader_READ(pdb, &pdb->tpi_types_walker, &pdb->tpi_header))) goto invalid_file; + result = R_PDB_INVALID_PDB_FILE; + if (pdb->tpi_header.version < 19960000 || pdb->tpi_header.type_offset < sizeof(PDB_TYPES)) + { + /* not supported yet... */ + FIXME("Old PDB_TYPES header, skipping\n"); + goto invalid_file; + } + /* validate some bits */ + if (pdb->tpi_header.hash_size != (pdb->tpi_header.last_index - pdb->tpi_header.first_index) * pdb->tpi_header.hash_value_size || + pdb->tpi_header.search_size % sizeof(uint32_t[2])) + goto invalid_file; + if (pdb->tpi_header.hash_value_size > sizeof(unsigned)) + { + FIXME("Unexpected hash value size %u\n", pdb->tpi_header.hash_value_size); + goto invalid_file; + } + pdb->tpi_types_walker.offset = pdb->tpi_header.type_offset; + + if ((result = pdb_reader_alloc(pdb, (pdb->tpi_header.last_index - pdb->tpi_header.first_index) * sizeof(pdb->tpi_typemap[0]), + (void **)&pdb->tpi_typemap))) + goto invalid_file; + memset(pdb->tpi_typemap, 0, (pdb->tpi_header.last_index - pdb->tpi_header.first_index) * sizeof(pdb->tpi_typemap[0])); + if ((result = pdb_reader_alloc(pdb, pdb->tpi_header.hash_num_buckets * sizeof(struct pdb_type_hash_entry), (void **)&pdb->tpi_types_hash))) + goto invalid_file; + /* create hash table: mark empty slots */ + for (i = 0; i < pdb->tpi_header.hash_num_buckets; i++) + pdb->tpi_types_hash[i].next = &pdb->tpi_types_hash[i]; + + for (i = pdb->tpi_header.first_index; i < pdb->tpi_header.last_index; i++) + { + unsigned hash; + + if ((result = pdb_reader_read_cv_typeid_hash(pdb, i, &hash))) goto invalid_file; + if (pdb->tpi_types_hash[hash].next == &pdb->tpi_types_hash[hash]) + { + pdb->tpi_types_hash[hash].next = NULL; + } + else + { + struct pdb_type_hash_entry *hash_entry; + if ((result = pdb_reader_alloc(pdb, sizeof(*hash_entry), (void**)&hash_entry))) goto invalid_file; + *hash_entry = pdb->tpi_types_hash[hash]; + pdb->tpi_types_hash[hash].next = hash_entry; + } + pdb->tpi_types_hash[hash].cv_typeid = i; + } + if (pdb->tpi_header.type_remap_size) + { + struct pdb_reader_walker remap_walker, remap_bitset_walker; + struct {uint32_t count, capacity, count_present;} head; + uint32_t deleted_bitset_count, i, mask; + unsigned hash; + + TRACE("Loading TPI remap information\n"); + if ((result = pdb_reader_walker_init(pdb, pdb->tpi_header.hash_stream, &remap_walker))) goto invalid_file; + remap_walker.offset = pdb->tpi_header.type_remap_offset; + if ((result = pdb_reader_READ(pdb, &remap_walker, &head))) goto invalid_file; + remap_bitset_walker = remap_walker; + remap_walker.offset += head.count_present * sizeof(uint32_t); /* skip bitset */ + if ((result = pdb_reader_READ(pdb, &remap_walker, &deleted_bitset_count))) goto invalid_file; + remap_walker.offset += deleted_bitset_count * sizeof(uint32_t); /* skip deleted bitset */ + for (i = 0; i < head.capacity; ++i) + { + if ((i % (8 * sizeof(uint32_t))) == 0 && + (result = pdb_reader_READ(pdb, &remap_bitset_walker, &mask))) goto invalid_file; + if (mask & (1u << (i % (8 * sizeof(uint32_t))))) + { + /* remap[0] is an offset for a string in /string stream, followed by type_id to force */ + uint32_t target_cv_typeid; + struct pdb_type_hash_entry *hash_entry, *prev_hash_entry = NULL; + + remap_walker.offset += sizeof(uint32_t); /* skip offset in /string stream */ + if ((result = pdb_reader_READ(pdb, &remap_walker, &target_cv_typeid))) goto invalid_file; + if ((result = pdb_reader_read_cv_typeid_hash(pdb, target_cv_typeid, &hash))) goto invalid_file; + if (pdb->tpi_types_hash[hash].next == &pdb->tpi_types_hash[hash]) /* empty list */ + goto invalid_file; + for (hash_entry = &pdb->tpi_types_hash[hash]; hash_entry; hash_entry = hash_entry->next) + { + if (hash_entry->cv_typeid == target_cv_typeid) + { + struct pdb_type_hash_entry swap; + + TRACE("Remap: using cv_typeid %x instead of %x\n", hash_entry->cv_typeid, pdb->tpi_types_hash[hash].cv_typeid); + /* put hash_entry content at head in list */ + if (prev_hash_entry) + { + prev_hash_entry->next = hash_entry->next; + swap = pdb->tpi_types_hash[hash]; + pdb->tpi_types_hash[hash] = *hash_entry; + pdb->tpi_types_hash[hash].next = hash_entry; + *hash_entry = swap; + } + break; + } + } + } + } + } + } + return R_PDB_SUCCESS; +invalid_file: + WARN("Invalid TPI hash table\n"); + /* free hash table upon error!! */ + if (pdb->tpi_types_hash) + { + struct pdb_type_hash_entry *hash_entry, *hash_entry_next; + for (i = 0; i < pdb->tpi_header.hash_num_buckets; i++) + if (pdb->tpi_types_hash[i].next != &pdb->tpi_types_hash[i]) + { + for (hash_entry = pdb->tpi_types_hash[i].next; hash_entry; hash_entry = hash_entry_next) + { + hash_entry_next = hash_entry->next; + pdb_reader_free(pdb, hash_entry); + } + } + pdb_reader_free(pdb, pdb->tpi_types_hash); + pdb->tpi_types_hash = NULL; + } + pdb_reader_free(pdb, pdb->tpi_typemap); + pdb->TPI_types_invalid = 1; + + return result; +} + +static enum pdb_result pdb_reader_get_type_details(struct pdb_reader *pdb, cv_typ_t cv_typeid, struct pdb_type_details **type_details) +{ + enum pdb_result result; + + if ((result = pdb_reader_init_TPI(pdb))) return result; + if (cv_typeid < pdb->tpi_header.first_index || cv_typeid >= pdb->tpi_header.last_index) return R_PDB_INVALID_ARGUMENT; + *type_details = &pdb->tpi_typemap[cv_typeid - pdb->tpi_header.first_index]; + return R_PDB_SUCCESS; +} + +/* caller must ensure that num_elt are not zero */ +static enum pdb_result pdb_reader_internal_binary_search(size_t num_elt, + enum pdb_result (*cmp)(unsigned idx, int *cmp_ressult, void *user), + size_t *found, void *user) +{ + enum pdb_result result; + size_t low = 0, high = num_elt, mid; + int res; + + *found = num_elt; + while (high > low + 1) + { + mid = (high + low) / 2; + if ((result = (*cmp)(mid, &res, user))) return result; + if (!res) + { + *found = low; + return R_PDB_SUCCESS; + } + if (res < 0) + low = mid; + else + high = mid; + } + + /* call again cmd so user can be filled with reported index */ + (*cmp)(low, &res, user); + *found = low; + return R_PDB_NOT_FOUND; +} + +struct type_offset +{ + struct pdb_reader *pdb; + struct pdb_reader_walker walker; + cv_typ_t to_search; + uint32_t values[2]; +}; + +static enum pdb_result pdb_reader_type_offset_cmp(unsigned idx, int *cmp, void *user) +{ + enum pdb_result result; + struct type_offset *type_offset = user; + struct pdb_reader_walker walker = type_offset->walker; + + walker.offset += idx * sizeof(uint32_t[2]); + if ((result = pdb_reader_READ(type_offset->pdb, &walker, &type_offset->values))) return result; + *cmp = type_offset->values[0] - type_offset->to_search; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_TPI_offset_from_cv_typeid(struct pdb_reader *pdb, cv_typ_t cv_typeid, pdbsize_t *found_type_offset) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + struct type_offset type_offset; + size_t found; + unsigned short int cv_type_len; + + if ((result = pdb_reader_init_TPI(pdb))) return result; + walker = pdb->tpi_types_walker; + + type_offset.pdb = pdb; + if ((result = pdb_reader_walker_init(pdb, pdb->tpi_header.hash_stream, &type_offset.walker))) return result; + type_offset.to_search = cv_typeid; + if ((result = pdb_reader_walker_narrow(&type_offset.walker, pdb->tpi_header.search_offset, pdb->tpi_header.search_size))) return result; + result = pdb_reader_internal_binary_search(pdb->tpi_header.search_size / sizeof(uint32_t[2]), + pdb_reader_type_offset_cmp, &found, &type_offset); + + if (result) + { + if (result != R_PDB_NOT_FOUND) return result; + + if (type_offset.values[0] > cv_typeid) return R_PDB_INVALID_PDB_FILE; + walker.offset += type_offset.values[1]; + + for ( ; type_offset.values[0] < cv_typeid; type_offset.values[0]++) + { + if ((result = pdb_reader_READ(pdb, &walker, &cv_type_len))) return result; + walker.offset += cv_type_len; + } + } + else walker.offset += type_offset.values[1]; + *found_type_offset = walker.offset; + + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_read_partial_codeview_type(struct pdb_reader *pdb, struct pdb_reader_walker *walker, + union codeview_type *cv_type) +{ + return pdb_reader_read_partial_blob(pdb, walker, cv_type, sizeof(*cv_type)); +} + +/* deserialize the variable part of a codeview_type... + * as output, string and/or decorated are optional + */ +static enum pdb_result pdb_reader_alloc_and_read_codeview_type_variablepart(struct pdb_reader *pdb, struct pdb_reader_walker walker, + const union codeview_type *cv_type, VARIANT *variant, + char **string, char **decorated) +{ + enum pdb_result result; + size_t var_offset; + BOOL has_leaf = TRUE, has_decorated = FALSE; + unsigned leaf_len; + + switch (cv_type->generic.id) + { + case LF_CLASS_V3: + case LF_STRUCTURE_V3: + var_offset = offsetof(union codeview_type, struct_v3.data); + has_decorated = cv_type->struct_v3.property.has_decorated_name; + break; + case LF_UNION_V3: + var_offset = offsetof(union codeview_type, union_v3.data); + has_decorated = cv_type->union_v3.property.has_decorated_name; + break; + case LF_ENUM_V3: + var_offset = offsetof(union codeview_type, enumeration_v3.name); + has_decorated = cv_type->enumeration_v3.property.has_decorated_name; + has_leaf = FALSE; + break; + default: + return R_PDB_NOT_FOUND; + } + walker.offset += var_offset - sizeof(cv_type->generic.len); + leaf_len = walker.offset; + if (!has_leaf) + V_VT(variant) = VT_EMPTY; + else if ((result = pdb_reader_read_leaf_as_variant(pdb, &walker, variant))) return result; + leaf_len = walker.offset - leaf_len; + + if (string) + result = pdb_reader_alloc_and_fetch_string(pdb, &walker, string); + else if (decorated) + result = pdb_reader_skip_string(pdb, &walker); + if (result == R_PDB_SUCCESS && decorated) + { + if (!has_decorated) + *decorated = NULL; + else if ((result = pdb_reader_alloc_and_fetch_string(pdb, &walker, decorated))) return result; + } + return result; +} + +static enum pdb_result pdb_reader_TPI_read_partial_reftype(struct pdb_reader *pdb, cv_typ_t cv_typeid, union codeview_reftype *cv_reftype, + pdbsize_t *tpi_offset) +{ + struct pdb_reader_walker walker; + enum pdb_result result; + + if ((result = pdb_reader_init_TPI(pdb))) return result; + if ((result = pdb_reader_TPI_offset_from_cv_typeid(pdb, cv_typeid, tpi_offset))) return result; + walker = pdb->tpi_types_walker; + walker.offset = *tpi_offset; + + return pdb_reader_read_partial_blob(pdb, &walker, (void*)cv_reftype, sizeof(*cv_reftype)); +} + +static enum pdb_result pdb_reader_TPI_alloc_and_read_full_reftype(struct pdb_reader *pdb, cv_typ_t cv_typeid, union codeview_reftype **cv_reftype, + pdbsize_t *tpi_offset) +{ + struct pdb_reader_walker walker; + enum pdb_result result; + + if ((result = pdb_reader_init_TPI(pdb))) return result; + if ((result = pdb_reader_TPI_offset_from_cv_typeid(pdb, cv_typeid, tpi_offset))) return result; + walker = pdb->tpi_types_walker; + walker.offset = *tpi_offset; + + return pdb_reader_alloc_and_read_full_blob(pdb, &walker, (void**)cv_reftype); +} + +static enum pdb_result pdb_reader_read_codeview_type_by_name(struct pdb_reader *pdb, const char *name, struct pdb_reader_walker *walker, + union codeview_type *cv_type, cv_typ_t *cv_typeid) +{ + enum pdb_result result; + VARIANT v; + UINT32 hash; /* for now we only support 1, 2 or 4 as hash size */ + struct pdb_type_hash_entry *entry; + pdbsize_t tpi_offset; + char *other_name; + + if ((result = pdb_reader_init_TPI(pdb))) return result; + *walker = pdb->tpi_types_walker; + + hash = codeview_compute_hash(name, strlen(name)) % pdb->tpi_header.hash_num_buckets; + entry = &pdb->tpi_types_hash[hash]; + if (entry->next != entry) /* not empty */ + { + for (; entry; entry = entry->next) + { + int cmp; + if ((result = pdb_reader_TPI_offset_from_cv_typeid(pdb, entry->cv_typeid, &tpi_offset))) return result; + walker->offset = tpi_offset; + if ((result = pdb_reader_read_partial_codeview_type(pdb, walker, cv_type))) return result; + result = pdb_reader_alloc_and_read_codeview_type_variablepart(pdb, *walker, cv_type, &v, &other_name, NULL); + if (result == R_PDB_NOT_FOUND) continue; + if (result) return result; + cmp = strcmp(name, other_name); + pdb_reader_free(pdb, other_name); + if (!cmp) + { + *cv_typeid = entry->cv_typeid; + return R_PDB_SUCCESS; + } + } + } + return R_PDB_NOT_FOUND; +} + +static int my_action_global_cmp(const void *p1, const void *p2) +{ + pdbsize_t o1 = *(pdbsize_t*)p1; + pdbsize_t o2 = ((const struct pdb_action_entry *)p2)->stream_offset; + + if (o1 < o2) return -1; + if (o1 > o2) return +1; + return 0; +} + +static enum method_result pdb_method_find_type(struct module_format *modfmt, const char *name, symref_t *ref) +{ + struct pdb_reader *pdb; + enum pdb_result result; + struct pdb_reader_walker walker; + cv_typ_t cv_typeid; + union codeview_type cv_type; + union codeview_symbol cv_symbol; + struct symref_code code; + struct pdb_type_details *type_details; + pdbsize_t stream_offset; + + pdb = pdb_get_current_reader(modfmt); + if ((result = pdb_reader_init_TPI(pdb))) return pdb_method_result(result); + /* search in TPI hash table */ + if ((result = pdb_reader_read_codeview_type_by_name(pdb, name, &walker, &cv_type, &cv_typeid)) == R_PDB_SUCCESS) + { + if ((result = pdb_reader_get_type_details(pdb, cv_typeid, &type_details))) return MR_FAILURE; + return pdb_reader_encode_symref(pdb, symref_code_init_from_cv_typeid(&code, cv_typeid), ref) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + } + /* search in DBI globals' hash table */ + if ((result = pdb_reader_read_DBI_codeview_symbol_by_name(pdb, name, &stream_offset, &cv_symbol)) == R_PDB_SUCCESS) + { + struct pdb_action_entry *entry; + entry = bsearch(&stream_offset, pdb->action_store, pdb->num_action_globals, sizeof(pdb->action_store[0]), + &my_action_global_cmp); + if (entry) + return pdb_reader_encode_symref(pdb, symref_code_init_from_action(&code, entry - pdb->action_store), + ref) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + } + return MR_FAILURE; +} + +static BOOL codeview_type_is_forward(const union codeview_type* cvtype) +{ + cv_property_t property; + + switch (cvtype->generic.id) + { + case LF_STRUCTURE_V3: + case LF_CLASS_V3: property = cvtype->struct_v3.property; break; + case LF_UNION_V3: property = cvtype->union_v3.property; break; + case LF_ENUM_V3: property = cvtype->enumeration_v3.property; break; + default: return FALSE; + } + return property.is_forward_defn; +} + +/* resolves forward declaration to the actual implementation + * resolves incremental linker remap bits + */ +static enum pdb_result pdb_reader_resolve_cv_typeid(struct pdb_reader *pdb, cv_typ_t raw_cv_typeid, cv_typ_t *cv_typeid) +{ + enum pdb_result result; + pdbsize_t tpi_offset; + union codeview_type cv_type; + struct pdb_type_details *type_details; + struct pdb_reader_walker type_walker; + + if (raw_cv_typeid < T_FIRSTDEFINABLETYPE) + { + *cv_typeid = raw_cv_typeid; + return R_PDB_SUCCESS; + } + if ((result = pdb_reader_get_type_details(pdb, raw_cv_typeid, &type_details))) return result; + if (type_details->resolved_cv_typeid) + { + *cv_typeid = type_details->resolved_cv_typeid; + return R_PDB_SUCCESS; + } + if ((result = pdb_reader_TPI_offset_from_cv_typeid(pdb, raw_cv_typeid, &tpi_offset))) return result; + + type_walker = pdb->tpi_types_walker; + type_walker.offset = tpi_offset; + if ((result = pdb_reader_read_partial_codeview_type(pdb, &type_walker, &cv_type))) return result; + + if (codeview_type_is_forward(&cv_type)) + { + VARIANT v; + char *udt_name; + struct pdb_reader_walker other_walker = pdb->tpi_types_walker; + union codeview_type other_cv_type; + cv_typ_t other_cv_typeid; + + if ((result = pdb_reader_alloc_and_read_codeview_type_variablepart(pdb, type_walker, &cv_type, &v, &udt_name, NULL))) return result; + result = pdb_reader_read_codeview_type_by_name(pdb, udt_name, &other_walker, &other_cv_type, &other_cv_typeid); + pdb_reader_free(pdb, udt_name); + switch (result) + { + case R_PDB_SUCCESS: + type_details->resolved_cv_typeid = other_cv_typeid; + if (!type_details->stream_offset) type_details->stream_offset = other_walker.offset; + break; + case R_PDB_NOT_FOUND: /* we can have a forward decl without a real implementation */ + type_details->resolved_cv_typeid = raw_cv_typeid; + if (!type_details->stream_offset) type_details->stream_offset = tpi_offset; + break; + default: + return result; + } + } + else + { + type_details->resolved_cv_typeid = raw_cv_typeid; + if (!type_details->stream_offset) type_details->stream_offset = tpi_offset; + } + + *cv_typeid = type_details->resolved_cv_typeid; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_symref_from_cv_typeid(struct pdb_reader *pdb, cv_typ_t cv_typeid, symref_t *symref) +{ + enum pdb_result result; + struct symref_code code; + + if (cv_typeid > T_MAXPREDEFINEDTYPE) + if ((result = pdb_reader_resolve_cv_typeid(pdb, cv_typeid, &cv_typeid))) return result; + return pdb_reader_encode_symref(pdb, symref_code_init_from_cv_typeid(&code, cv_typeid), symref); +} + +static enum method_result pdb_method_enumerate_types(struct module_format *modfmt, BOOL (*cb)(symref_t, const char *, void*), void *user) +{ + struct pdb_reader *pdb; + enum pdb_result result; + unsigned i; + struct pdb_reader_walker walker; + struct pdb_type_details *type_details; + struct pdb_type_hash_entry *hash_entry; + union codeview_type cv_type; + struct symref_code code; + symref_t symref; + char *name; + VARIANT v; + BOOL ret; + + pdb = pdb_get_current_reader(modfmt); + if ((result = pdb_reader_init_TPI(pdb))) return pdb_method_result(result); + walker = pdb->tpi_types_walker; + /* Note: walking the types through the hash table may not be the most efficient */ + for (i = 0; i < pdb->tpi_header.hash_num_buckets; i++) + { + if (&pdb->tpi_types_hash[i] == pdb->tpi_types_hash[i].next) continue; /* empty */ + for (hash_entry = &pdb->tpi_types_hash[i]; hash_entry; hash_entry = hash_entry->next) + { + cv_typ_t cv_typeid; + + /* We don't advertize a forward declaration unless a real declaration exists. + * So advertize only TPI entries that are resolved to themselves. + */ + if ((result = pdb_reader_resolve_cv_typeid(pdb, hash_entry->cv_typeid, &cv_typeid))) continue; + if (hash_entry->cv_typeid != cv_typeid) continue; + if ((result = pdb_reader_get_type_details(pdb, cv_typeid, &type_details))) continue; + + walker.offset = type_details->stream_offset; + if ((result = pdb_reader_read_partial_codeview_type(pdb, &walker, &cv_type))) return pdb_method_result(result); + result = pdb_reader_alloc_and_read_codeview_type_variablepart(pdb, walker, &cv_type, &v, &name, NULL); + if (!result) + { + if (*name && pdb_reader_encode_symref(pdb, symref_code_init_from_cv_typeid(&code, hash_entry->cv_typeid), &symref) == R_PDB_SUCCESS) + ret = (*cb)(symref, name, user); + else + ret = TRUE; + pdb_reader_free(pdb, name); + if (!ret) return MR_SUCCESS; + } + } + } + + /* typedef:s are stored in DBI globals' stream */ + for (i = 0; i < pdb->num_action_globals; i++) + { + struct pdb_reader_walker walker; + union codeview_symbol *cv_symbol; + struct pdb_action_entry *entry; + pdbsize_t num_read; + + entry = &pdb->action_store[i]; + if ((result = pdb_reader_walker_init(pdb, pdb->dbi_header.gsym_stream, &walker))) return MR_FAILURE; + walker.offset = entry->stream_offset; + if ((result = pdb_reader_alloc(pdb, entry->action_length, (void**)&cv_symbol))) return MR_FAILURE; + if ((result = pdb_reader_read_from_stream(pdb, &walker, cv_symbol, entry->action_length, &num_read))) return MR_FAILURE; + if ((result = pdb_reader_encode_symref(pdb, symref_code_init_from_action(&code, i), &symref))) return MR_FAILURE; + if (num_read == entry->action_length) + { + switch (cv_symbol->generic.id) + { + case S_UDT: + ret = (*cb)(symref, cv_symbol->udt_v3.name, user); + break; + default: + WARN("Got unexpected %x\n", cv_symbol->generic.id); + ret = FALSE; + break; + } + } + else ret = TRUE; + pdb_reader_free(pdb, cv_symbol); + if (!ret) break; + } + return MR_SUCCESS; +} + +static enum pdb_result pdb_reader_index_from_cv_typeid(struct pdb_reader *pdb, cv_typ_t cv_typeid, DWORD *index) +{ + enum pdb_result result; + struct symref_code code; + symref_t symref; + + if (cv_typeid > T_MAXPREDEFINEDTYPE) + if ((result = pdb_reader_resolve_cv_typeid(pdb, cv_typeid, &cv_typeid))) return result; + if ((result = pdb_reader_encode_symref(pdb, symref_code_init_from_cv_typeid(&code, cv_typeid), &symref))) return result; + + *index = symt_symref_to_index(pdb->module, symref); + return R_PDB_SUCCESS; +} + +static enum method_result pdb_reader_request_symref_t(struct pdb_reader *pdb, symref_t symref, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data); + +static enum method_result pdb_reader_request_cv_typeid(struct pdb_reader *pdb, cv_typ_t cv_typeid, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + struct symref_code code; + symref_t target_symref; + + if (pdb_reader_encode_symref(pdb, symref_code_init_from_cv_typeid(&code, cv_typeid), &target_symref)) return MR_FAILURE; + return pdb_reader_request_symref_t(pdb, target_symref, req, data); +} + +static enum method_result pdb_reader_TPI_pointer_request(struct pdb_reader *pdb, const union codeview_type *cv_type, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + switch (req) + { + case TI_GET_SYMTAG: + *((DWORD*)data) = SymTagPointerType; + return MR_SUCCESS; + case TI_GET_LENGTH: + *((DWORD64*)data) = pdb->module->cpu->word_size; + return MR_SUCCESS; + case TI_GET_TYPE: + case TI_GET_TYPEID: + return pdb_reader_index_from_cv_typeid(pdb, cv_type->pointer_v2.datatype, + (DWORD*)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + case TI_FINDCHILDREN: + case TI_GET_CHILDRENCOUNT: + case TI_GET_LEXICALPARENT: + return pdb_reader_default_request(pdb, req, data); + + default: + return MR_FAILURE; + } +} + +static enum method_result pdb_reader_TPI_array_request(struct pdb_reader *pdb, const union codeview_type *cv_type, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + enum method_result mr; + DWORD64 element_length; + int array_size; + + switch (req) + { + case TI_GET_SYMTAG: + *((DWORD*)data) = SymTagArrayType; + return MR_SUCCESS; + case TI_GET_COUNT: + if ((mr = pdb_reader_request_cv_typeid(pdb, cv_type->array_v3.elemtype, TI_GET_LENGTH, &element_length)) != MR_SUCCESS) return mr; + if (codeview_fetch_leaf_as_int(cv_type, cv_type->array_v3.data, &array_size)) return MR_FAILURE; + if (!element_length || (array_size % element_length)) + WARN("Incorrect array %u %I64u\n", array_size, element_length); + *((DWORD*)data) = array_size / element_length; + return MR_SUCCESS; + case TI_GET_LENGTH: + if (codeview_fetch_leaf_as_int(cv_type, cv_type->array_v3.data, &array_size)) return MR_FAILURE; + *((DWORD64*)data) = (unsigned)array_size; + return MR_SUCCESS; + case TI_GET_TYPE: + case TI_GET_TYPEID: + return pdb_reader_index_from_cv_typeid(pdb, cv_type->array_v3.elemtype, (DWORD*)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + case TI_GET_ARRAYINDEXTYPEID: + return pdb_reader_index_from_cv_typeid(pdb, cv_type->array_v3.idxtype, (DWORD*)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + case TI_FINDCHILDREN: + case TI_GET_CHILDRENCOUNT: + case TI_GET_LEXICALPARENT: + return pdb_reader_default_request(pdb, req, data); + default: + return MR_FAILURE; + } +} + +static enum pdb_result pdb_reader_TPI_fillin_arglist(struct pdb_reader *pdb, unsigned num_ids, unsigned id_size, pdbsize_t tpi_offset, + TI_FINDCHILDREN_PARAMS *tfp) +{ + enum pdb_result result; + symref_t symref; + unsigned i; + + for (i = 0; i < num_ids; i++, tpi_offset += id_size) + { + if (i >= tfp->Start + tfp->Count) return R_PDB_BUFFER_TOO_SMALL; + if (i >= tfp->Start) + { + if ((result = pdb_reader_push_action(pdb, action_type_cv_typ_t, tpi_offset, id_size, 0, &symref))) return result; + tfp->ChildId[i] = symt_symref_to_index(pdb->module, symref); + } + } + return R_PDB_SUCCESS; +} + +static enum method_result pdb_reader_TPI_procsignature_request(struct pdb_reader *pdb, const union codeview_type *cv_type, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + enum pdb_result result; + cv_typ_t return_cv_typeid, arglist_cv_typeid; + unsigned char call_conv; + unsigned num_args; + + switch (cv_type->generic.id) + { + case LF_PROCEDURE_V2: + return_cv_typeid = cv_type->procedure_v2.rvtype; + arglist_cv_typeid = cv_type->procedure_v2.arglist; + call_conv = cv_type->procedure_v2.callconv; + num_args = cv_type->procedure_v2.params; + break; + /* FIXME: for C++, this is plain wrong, but as we don't use arg types + * nor class information, this would just do for now + */ + case LF_MFUNCTION_V2: + return_cv_typeid = cv_type->mfunction_v2.rvtype; + arglist_cv_typeid = cv_type->mfunction_v2.arglist; + call_conv = cv_type->mfunction_v2.callconv; + num_args = cv_type->mfunction_v2.params; + break; + default: + return MR_FAILURE; + } + + switch (req) + { + case TI_GET_SYMTAG: + *((DWORD*)data) = SymTagFunctionType; + return MR_SUCCESS; + case TI_FINDCHILDREN: + { + TI_FINDCHILDREN_PARAMS *p = data; + union codeview_reftype cv_reftype; + pdbsize_t tpi_arglist_offset; + + /* sigh... the codeview format doesn't have an explicit storage for the arg list item + * so we have to fake one using the 'action' field in storage + */ + if ((result = pdb_reader_TPI_read_partial_reftype(pdb, arglist_cv_typeid, &cv_reftype, &tpi_arglist_offset))) + return MR_FAILURE; + tpi_arglist_offset += offsetof(union codeview_reftype, arglist_v2.args[0]); + if (num_args > cv_reftype.arglist_v2.num) + return MR_FAILURE; + result = pdb_reader_TPI_fillin_arglist(pdb, cv_reftype.arglist_v2.num, sizeof(cv_typ_t), tpi_arglist_offset, p); + if (result && result != R_PDB_BUFFER_TOO_SMALL) return MR_FAILURE; + if (p->Start + p->Count > cv_reftype.arglist_v2.num) return MR_FAILURE; + } + return MR_SUCCESS; + case TI_GET_CHILDRENCOUNT: + case TI_GET_COUNT: /* should evolve when considering methods */ + { + enum pdb_result result; + union codeview_reftype cv_reftype; + pdbsize_t tpi_offset; + + if ((result = pdb_reader_TPI_read_partial_reftype(pdb, arglist_cv_typeid, &cv_reftype, &tpi_offset))) + return MR_FAILURE; + *((DWORD*)data) = cv_reftype.arglist_v2.num; + } + return MR_SUCCESS; + case TI_GET_TYPE: + case TI_GET_TYPEID: + return pdb_reader_index_from_cv_typeid(pdb, return_cv_typeid, (DWORD*)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + case TI_GET_CALLING_CONVENTION: + *((DWORD*)data) = call_conv; + return MR_SUCCESS; + case TI_GET_LEXICALPARENT: + return pdb_reader_default_request(pdb, req, data); + + default: + return MR_FAILURE; + } +} + +static enum pdb_result pdb_reader_push_action_and_filler(struct pdb_reader *pdb, enum pdb_action_type action, pdbsize_t stream_offset, + unsigned id_size, symref_t container_symref, unsigned *where, TI_FINDCHILDREN_PARAMS *tfp) +{ + enum pdb_result result; + symref_t symref; + + if (tfp) + { + if (*where >= tfp->Start + tfp->Count) return R_PDB_BUFFER_TOO_SMALL; + if (*where >= tfp->Start) + { + if ((result = pdb_reader_push_action(pdb, action, stream_offset, id_size, container_symref, &symref))) return result; + tfp->ChildId[*where] = symt_symref_to_index(pdb->module, symref); + } + } + (*where)++; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_TPI_fillin_enumlist(struct pdb_reader *pdb, symref_t container_symref, + cv_typ_t enumlist_cv_typeid, unsigned *where, + TI_FINDCHILDREN_PARAMS *tfp) + { + enum pdb_result result; + union codeview_reftype *cv_reftype; + pdbsize_t tpi_offset; + const unsigned char *start, *ptr, *last; + const union codeview_fieldtype *cv_field; + unsigned length; + VARIANT v; + symref_t symref; + + if ((result = pdb_reader_TPI_alloc_and_read_full_reftype(pdb, enumlist_cv_typeid, &cv_reftype, &tpi_offset))) return result; + if (cv_reftype->generic.id != LF_FIELDLIST_V2) return PDB_REPORT_UNEXPECTED("enum list", cv_reftype->generic.id); + start = ptr = (const unsigned char *)cv_reftype->fieldlist.list; + last = (const unsigned char *)cv_reftype + sizeof(cv_reftype->generic.id) + cv_reftype->generic.len; + + tpi_offset += offsetof(union codeview_reftype, fieldlist.list); + + while (ptr < last) + { + if (*ptr >= 0xf0) /* Padding */ + { + ptr += *ptr & 0x0f; + continue; + } + cv_field = (const union codeview_fieldtype *)ptr; + switch (cv_field->generic.id) + { + case LF_ENUMERATE_V3: + length = offsetof(union codeview_fieldtype, enumerate_v3.data); + length += codeview_leaf_as_variant(ptr + length, &v); + length += strlen((const char *)ptr + length) + 1; + if (*where >= tfp->Start + tfp->Count) + { + pdb_reader_free(pdb, cv_reftype); + return R_PDB_BUFFER_TOO_SMALL; + } + if (*where >= tfp->Start) + { + if ((result = pdb_reader_push_action(pdb, action_type_field, tpi_offset + (ptr - start), length, container_symref, &symref))) + { + pdb_reader_free(pdb, cv_reftype); + return result; + } + tfp->ChildId[*where] = symt_symref_to_index(pdb->module, symref); + } + (*where)++; + ptr += length; + break; + + case LF_INDEX_V2: + if ((result = pdb_reader_TPI_fillin_enumlist(pdb, container_symref, cv_field->index_v2.ref, + where, tfp))) return result; + ptr += sizeof(cv_field->index_v2); + break; + + default: + pdb_reader_free(pdb, cv_reftype); + return PDB_REPORT_UNEXPECTED("enum field list", cv_field->generic.id); + } + } + pdb_reader_free(pdb, cv_reftype); + return R_PDB_SUCCESS; +} + +static enum method_result pdb_reader_TPI_enum_request(struct pdb_reader *pdb, symref_t symref, const union codeview_type *cv_type, + const struct pdb_reader_walker *walker, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + switch (req) + { + case TI_FINDCHILDREN: + { + TI_FINDCHILDREN_PARAMS *p = data; + unsigned where = 0; + enum pdb_result result; + result = pdb_reader_TPI_fillin_enumlist(pdb, symref, cv_type->enumeration_v3.fieldlist, &where, p); + if (result && result != R_PDB_BUFFER_TOO_SMALL) return MR_FAILURE; + if (p->Start + p->Count > where) return MR_FAILURE; + } + return MR_SUCCESS; + case TI_GET_CHILDRENCOUNT: + *(DWORD*)data = cv_type->enumeration_v3.count; + return MR_SUCCESS; + case TI_GET_SYMNAME: + { + VARIANT v; + char *string; + + if (pdb_reader_alloc_and_read_codeview_type_variablepart(pdb, *walker, cv_type, &v, &string, NULL)) + return MR_FAILURE; + *((WCHAR**)data) = heap_allocate_symname(string); + pdb_reader_free(pdb, string); + } + return *((WCHAR**)data) != NULL ? MR_SUCCESS : MR_FAILURE; + case TI_GET_BASETYPE: + case TI_GET_LENGTH: /* forward to base type */ + if (cv_type->enumeration_v3.type >= T_MAXPREDEFINEDTYPE) return MR_FAILURE; + return pdb_reader_basic_request(pdb, cv_type->enumeration_v3.type, req, data); + case TI_GET_NESTED: + *(DWORD*)data = 0; + return MR_SUCCESS; + case TI_GET_SYMTAG: + *((DWORD*)data) = SymTagEnum; + return MR_SUCCESS; + case TI_GET_TYPE: + case TI_GET_TYPEID: + return pdb_reader_index_from_cv_typeid(pdb, cv_type->enumeration_v3.type, (DWORD*)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + case TI_GET_LEXICALPARENT: + return pdb_reader_default_request(pdb, req, data); + default: + return MR_FAILURE; + } +} + +static enum pdb_result pdb_reader_TPI_fillin_UDTlist(struct pdb_reader *pdb, symref_t container_symref, + cv_typ_t udtlist_cv_typeid, unsigned *where, TI_FINDCHILDREN_PARAMS *tfp) +{ + enum pdb_result result; + union codeview_reftype *cv_reftype; + pdbsize_t tpi_offset; + const unsigned char *start, *ptr, *last; + const union codeview_fieldtype *cv_field; + unsigned length; + VARIANT v; + + if ((result = pdb_reader_TPI_alloc_and_read_full_reftype(pdb, udtlist_cv_typeid, &cv_reftype, &tpi_offset))) return result; + if (cv_reftype->generic.id != LF_FIELDLIST_V2) return PDB_REPORT_UNEXPECTED("list", cv_reftype->generic.id); + start = ptr = (const unsigned char *)cv_reftype->fieldlist.list; + last = (const unsigned char *)cv_reftype + sizeof(cv_reftype->generic.id) + cv_reftype->generic.len; + + tpi_offset += offsetof(union codeview_reftype, fieldlist.list); + + while (ptr < last) + { + if (*ptr >= 0xf0) /* Padding */ + { + ptr += *ptr & 0x0f; + continue; + } + cv_field = (const union codeview_fieldtype *)ptr; + result = R_PDB_SUCCESS; + switch (cv_field->generic.id) + { + case LF_BCLASS_V2: + length = offsetof(union codeview_fieldtype, bclass_v2.data); + length += codeview_leaf_as_variant(ptr + length, &v); + /* FIXME: ignored for now */ + break; + + case LF_VBCLASS_V2: + case LF_IVBCLASS_V2: + length = offsetof(union codeview_fieldtype, vbclass_v2.data); + length += codeview_leaf_as_variant(ptr + length, &v); /* vbpoff */ + length += codeview_leaf_as_variant(ptr + length, &v); /* vboff */ + /* FIXME: ignored for now */ + break; + + case LF_MEMBER_V3: + length = offsetof(union codeview_fieldtype, member_v3.data); + length += codeview_leaf_as_variant(ptr + length, &v); + length += strlen((const char *)ptr + length) + 1; + result = pdb_reader_push_action_and_filler(pdb, action_type_field, tpi_offset + (ptr - start), length, container_symref, where, tfp); + break; + + case LF_STMEMBER_V3: + /* FIXME: ignored for now */ + length = offsetof(union codeview_fieldtype, stmember_v3.name) + strlen(cv_field->stmember_v3.name) + 1; + break; + + case LF_METHOD_V3: + /* FIXME: ignored for now */ + length = offsetof(union codeview_fieldtype, method_v3.name) + strlen(cv_field->method_v3.name) + 1; + break; + + case LF_NESTTYPE_V3: + /* FIXME: ignored for now */ + length = offsetof(union codeview_fieldtype, nesttype_v3.name) + strlen(cv_field->nesttype_v3.name) + 1; + break; + + case LF_VFUNCTAB_V2: + /* FIXME: ignored for now */ + length = sizeof(cv_field->vfunctab_v2); + break; + + case LF_ONEMETHOD_V3: + /* FIXME: ignored for now */ + switch ((cv_field->onemethod_v3.attribute >> 2) & 7) + { + case 4: case 6: /* (pure) introducing virtual method */ + length = offsetof(union codeview_fieldtype, onemethod_virt_v3.name); + break; + default: + length = offsetof(union codeview_fieldtype, onemethod_v3.name); + break; + } + length += strlen((const char *)ptr + length) + 1; + break; + + case LF_INDEX_V2: + if ((result = pdb_reader_TPI_fillin_UDTlist(pdb, container_symref, cv_field->index_v2.ref, where, tfp))) return result; + length = sizeof(cv_field->index_v2); + break; + + default: + result = PDB_REPORT_UNEXPECTED("UDT field list", cv_field->generic.id); + length = 0; /* keep SAST happy */ + } + ptr += length; + if (result) break; + } + + pdb_reader_free(pdb, cv_reftype); + return result; +} + +static enum pdb_result pdb_reader_count_advertized_in_UDT_fieldlist(struct pdb_reader *pdb, symref_t container_symref, + cv_typ_t fieldlist_cv_typeid, DWORD *count) +{ + enum pdb_result result; + unsigned where = 0; + + if ((result = pdb_reader_TPI_fillin_UDTlist(pdb, container_symref, fieldlist_cv_typeid, &where, NULL))) return result; + *count = where; + return R_PDB_SUCCESS; +} + +static enum method_result pdb_reader_TPI_UDT_request(struct pdb_reader *pdb, symref_t symref, const union codeview_type *cv_type, + const struct pdb_reader_walker *walker, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + enum UdtKind kind; + const unsigned char *var; + cv_typ_t fieldlist_cv_typeid; + cv_property_t property; + enum pdb_result result; + + switch (cv_type->generic.id) + { + case LF_CLASS_V3: + case LF_STRUCTURE_V3: + kind = cv_type->generic.id == LF_CLASS_V3 ? UdtClass : UdtStruct; + fieldlist_cv_typeid = cv_type->struct_v3.fieldlist; + property = cv_type->struct_v3.property; + var = cv_type->struct_v3.data; + break; + case LF_UNION_V3: + kind = UdtUnion; + fieldlist_cv_typeid = cv_type->union_v3.fieldlist; + property = cv_type->union_v3.property; + var = cv_type->union_v3.data; + break; + default: + return MR_FAILURE; + } + /* Note: we can have a forward type here when its declared but not defined. */ + + switch (req) + { + case TI_GET_SYMTAG: + *((DWORD*)data) = SymTagUDT; + return MR_SUCCESS; + case TI_FINDCHILDREN: + { + TI_FINDCHILDREN_PARAMS *tfp = data; + unsigned where = 0; + + if (property.is_forward_defn) return !tfp->Count ? MR_SUCCESS : MR_FAILURE; + result = pdb_reader_TPI_fillin_UDTlist(pdb, symref, fieldlist_cv_typeid, &where, tfp); + if (result && result != R_PDB_BUFFER_TOO_SMALL) return MR_FAILURE; + if (tfp->Start + tfp->Count > where) return MR_FAILURE; + } + return MR_SUCCESS; + case TI_GET_CHILDRENCOUNT: + if (!property.is_forward_defn) + /* Unfortunately the count field describes the number of entries in the field_list, not + * the count of entries we currently advertize (we drop a bunch of them in the fillin_ helpers). + * Be on the save side and always recompute. + */ + return pdb_reader_count_advertized_in_UDT_fieldlist(pdb, symref, fieldlist_cv_typeid, (DWORD*)data) ? MR_FAILURE : MR_SUCCESS; + *((DWORD*)data) = 0; + return MR_SUCCESS; + case TI_GET_SYMNAME: + { + VARIANT v; + char *string; + + if (pdb_reader_alloc_and_read_codeview_type_variablepart(pdb, *walker, cv_type, &v, &string, NULL)) + return MR_FAILURE; + *((WCHAR**)data) = heap_allocate_symname(string); + pdb_reader_free(pdb, string); + } + return *((WCHAR**)data) != NULL ? MR_SUCCESS : MR_FAILURE; + case TI_GET_LENGTH: + { + int value; + if (codeview_fetch_leaf_as_int(cv_type, var, &value)) return MR_FAILURE; + *((DWORD64*)data) = (unsigned)value; + } + return MR_SUCCESS; + case TI_GET_NESTED: + *((DWORD*)data) = property.is_nested; + return MR_SUCCESS; + case TI_GET_UDTKIND: + *((DWORD*)data) = kind; + return MR_SUCCESS; + case TI_GET_LEXICALPARENT: + *((DWORD*)data) = symt_ptr_to_index(pdb->module, &pdb->module->top->symt); + return MR_SUCCESS; + default: + return MR_FAILURE; + } +} + +static enum method_result pdb_reader_TPI_modifier_request(struct pdb_reader *pdb, symref_t symref, const union codeview_type *cv_type, + IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + return pdb_reader_request_cv_typeid(pdb, cv_type->modifier_v2.type, req, data); +} + +static enum method_result pdb_reader_TPI_argtype_request(struct pdb_reader *pdb, struct pdb_action_entry *entry, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + enum pdb_result result; + + switch (req) + { + case TI_GET_SYMTAG: + *(DWORD*)data = SymTagFunctionArgType; + return MR_SUCCESS; + case TI_GET_TYPE: + case TI_GET_TYPEID: + { + cv_typ_t cv_typeid; + struct pdb_reader_walker walker = pdb->tpi_types_walker; + walker.offset = entry->stream_offset; + if (entry->action_length == sizeof(cv_typ16_t)) + { + cv_typ16_t cv_typeid16; + result = pdb_reader_READ(pdb, &walker, &cv_typeid16); + cv_typeid = cv_typeid16; + } + else + result = pdb_reader_READ(pdb, &walker, &cv_typeid); + if (result || !cv_typeid) return MR_FAILURE; + return pdb_reader_index_from_cv_typeid(pdb, cv_typeid, (DWORD*)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + } + case TI_FINDCHILDREN: + case TI_GET_CHILDRENCOUNT: + case TI_GET_LEXICALPARENT: + return pdb_reader_default_request(pdb, req, data); + default: + return MR_FAILURE; + } +} + +static enum method_result pdb_reader_TPI_enumerate_request(struct pdb_reader *pdb, struct pdb_action_entry *entry, const union codeview_fieldtype *cv_field, + IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + pdbsize_t var; + VARIANT v; + + switch (req) + { + case TI_GET_SYMTAG: + *((DWORD*)data) = SymTagData; + return MR_SUCCESS; + case TI_GET_SYMNAME: + var = offsetof(union codeview_fieldtype, enumerate_v3.data); + var += codeview_leaf_as_variant((const unsigned char *)cv_field + var, &v); + *((WCHAR **)data) = heap_allocate_symname((const char *)cv_field + var); + return *((WCHAR **)data) != NULL ? MR_SUCCESS : MR_FAILURE; + case TI_GET_DATAKIND: + *((DWORD*)data) = DataIsConstant; + return MR_SUCCESS; + case TI_GET_LEXICALPARENT: + *((DWORD*)data) = symt_symref_to_index(pdb->module, entry->container_symref); + return MR_SUCCESS; + case TI_GET_LENGTH: + case TI_GET_TYPE: + case TI_GET_TYPEID: + /* forward to container type */ + return pdb_reader_request_symref_t(pdb, entry->container_symref, req, data); + case TI_GET_VALUE: + var = offsetof(union codeview_fieldtype, enumerate_v3.data); + return codeview_leaf_as_variant((const unsigned char *)cv_field + var, (VARIANT*)data) != 0 ? MR_SUCCESS : MR_FAILURE; + case TI_FINDCHILDREN: + case TI_GET_CHILDRENCOUNT: + return pdb_reader_default_request(pdb, req, data); + default: + return MR_FAILURE; + } +} + +static enum method_result pdb_reader_TPI_UDT_field_request(struct pdb_reader *pdb, struct pdb_action_entry *entry, const union codeview_fieldtype *cv_field, + IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + union codeview_reftype cv_reftype; + pdbsize_t tpi_offset; + + switch (req) + { + case TI_GET_SYMTAG: + *((DWORD*)data) = SymTagData; + return MR_SUCCESS; + case TI_GET_SYMNAME: + { + const unsigned char *var; + VARIANT v; + var = cv_field->member_v3.data; + var += codeview_leaf_as_variant(var, &v); + *((WCHAR **)data) = heap_allocate_symname((const char *)var); + } + return *((WCHAR **)data) != NULL ? MR_SUCCESS : MR_FAILURE; + case TI_GET_DATAKIND: + *((DWORD*)data) = DataIsMember; + return MR_SUCCESS; + case TI_GET_OFFSET: + return codeview_leaf_as_int( cv_field->member_v3.data, (int*)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + case TI_GET_LENGTH: + if (cv_field->member_v3.type < T_FIRSTDEFINABLETYPE || + pdb_reader_TPI_read_partial_reftype(pdb, cv_field->member_v3.type, &cv_reftype, &tpi_offset) || + cv_reftype.generic.id != LF_BITFIELD_V2) + return MR_FAILURE; + *((DWORD64*)data) = cv_reftype.bitfield_v2.nbits; + return MR_SUCCESS; + case TI_GET_BITPOSITION: + if (cv_field->member_v3.type < T_FIRSTDEFINABLETYPE || + pdb_reader_TPI_read_partial_reftype(pdb, cv_field->member_v3.type, &cv_reftype, &tpi_offset) || + cv_reftype.generic.id != LF_BITFIELD_V2) + return MR_FAILURE; + *((DWORD*)data) = cv_reftype.bitfield_v2.bitoff; + return MR_SUCCESS; + case TI_GET_TYPE: + case TI_GET_TYPEID: + if (cv_field->member_v3.type >= T_FIRSTDEFINABLETYPE && + !pdb_reader_TPI_read_partial_reftype(pdb, cv_field->member_v3.type, &cv_reftype, &tpi_offset) && + cv_reftype.generic.id == LF_BITFIELD_V2) + return pdb_reader_index_from_cv_typeid(pdb, cv_reftype.bitfield_v2.type, (DWORD *)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + return pdb_reader_index_from_cv_typeid(pdb, cv_field->member_v3.type, (DWORD *)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + case TI_FINDCHILDREN: + case TI_GET_CHILDRENCOUNT: + case TI_GET_LEXICALPARENT: + return pdb_reader_default_request(pdb, req, data); + default: + return MR_FAILURE; + } +} + +static enum method_result pdb_reader_TPI_field_request(struct pdb_reader *pdb, struct pdb_action_entry *entry, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + union codeview_fieldtype *cv_field; + pdbsize_t num_read; + enum method_result ret = MR_FAILURE; + + walker = pdb->tpi_types_walker; + walker.offset = entry->stream_offset; + + if ((result = pdb_reader_alloc(pdb, entry->action_length, (void**)&cv_field))) return MR_FAILURE; + if ((result = pdb_reader_read_from_stream(pdb, &walker, cv_field, entry->action_length, &num_read))) return MR_FAILURE; + if (num_read == entry->action_length) + { + switch (cv_field->generic.id) + { + case LF_ENUMERATE_V3: + ret = pdb_reader_TPI_enumerate_request(pdb, entry, cv_field, req, data); + break; + case LF_MEMBER_V3: + ret = pdb_reader_TPI_UDT_field_request(pdb, entry, cv_field, req, data); + break; + default: + PDB_REPORT_UNEXPECTED("field list", cv_field->generic.id); + break; + } + } + pdb_reader_free(pdb, cv_field); + return ret; +} + +static enum method_result pdb_reader_DBI_typedef_request(struct pdb_reader *pdb, struct pdb_action_entry *entry, union codeview_symbol *cv_symbol, + IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + switch (req) + { + case TI_GET_SYMTAG: + *((DWORD*)data) = SymTagTypedef; + return MR_SUCCESS; + case TI_GET_SYMNAME: + *((WCHAR **)data) = heap_allocate_symname(cv_symbol->udt_v3.name); + return *((WCHAR **)data) != NULL ? MR_SUCCESS : MR_FAILURE; + case TI_GET_LENGTH: + return pdb_reader_request_cv_typeid(pdb, cv_symbol->udt_v3.type, req, data); + case TI_GET_TYPE: + case TI_GET_TYPEID: + return pdb_reader_index_from_cv_typeid(pdb, cv_symbol->udt_v3.type, (DWORD*)data) == R_PDB_SUCCESS ? MR_SUCCESS : MR_FAILURE; + case TI_FINDCHILDREN: + case TI_GET_CHILDRENCOUNT: + case TI_GET_LEXICALPARENT: + return pdb_reader_default_request(pdb, req, data); + default: + return MR_FAILURE; + } +} + +static enum method_result pdb_reader_DBI_globals_request(struct pdb_reader *pdb, struct pdb_action_entry *entry, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + union codeview_symbol *cv_symbol; + pdbsize_t num_read; + enum method_result ret = MR_FAILURE; + + if ((result = pdb_reader_walker_init(pdb, pdb->dbi_header.gsym_stream, &walker))) return MR_FAILURE; + walker.offset = entry->stream_offset; + if ((result = pdb_reader_alloc(pdb, entry->action_length, (void**)&cv_symbol))) return MR_FAILURE; + if ((result = pdb_reader_read_from_stream(pdb, &walker, cv_symbol, entry->action_length, &num_read))) return MR_FAILURE; + if (num_read == entry->action_length) + { + switch (cv_symbol->generic.id) + { + case S_UDT: + ret = pdb_reader_DBI_typedef_request(pdb, entry, cv_symbol, req, data); + break; + default: + WARN("Got unexpected %x\n", cv_symbol->generic.id); + break; + } + } + pdb_reader_free(pdb, cv_symbol); + return ret; +} + +static enum method_result pdb_reader_TPI_request(struct pdb_reader *pdb, symref_t symref, struct pdb_type_details *type_details, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + union codeview_type cv_type; + enum method_result ret; + + if ((result = pdb_reader_init_TPI(pdb))) return MR_FAILURE; + walker = pdb->tpi_types_walker; + walker.offset = type_details->stream_offset; + if ((result = pdb_reader_read_partial_codeview_type(pdb, &walker, &cv_type))) return MR_FAILURE; + + switch (cv_type.generic.id) + { + case LF_POINTER_V2: + ret = pdb_reader_TPI_pointer_request(pdb, &cv_type, req, data); + break; + case LF_ARRAY_V3: + ret = pdb_reader_TPI_array_request(pdb, &cv_type, req, data); + break; + + case LF_PROCEDURE_V2: + case LF_MFUNCTION_V2: + return pdb_reader_TPI_procsignature_request(pdb, &cv_type, req, data); + + case LF_ENUM_V3: + return pdb_reader_TPI_enum_request(pdb, symref, &cv_type, &walker, req, data); + + case LF_UNION_V3: + case LF_STRUCTURE_V3: + case LF_CLASS_V3: + return pdb_reader_TPI_UDT_request(pdb, symref, &cv_type, &walker, req, data); + + case LF_MODIFIER_V2: + return pdb_reader_TPI_modifier_request(pdb, symref, &cv_type, req, data); + + default: + PDB_REPORT_UNEXPECTED("codeview type id", cv_type.generic.id); + ret = MR_FAILURE; + break; + } + + return ret; +} + +static enum method_result pdb_reader_request_symref_t(struct pdb_reader *pdb, symref_t symref, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + struct pdb_type_details *type_details; + struct symref_code code; + + if (req == TI_GET_SYMINDEX) + { + *((DWORD*)data) = symt_symref_to_index(pdb->module, symref); + return MR_SUCCESS; + } + + if (pdb_reader_decode_symref(pdb, symref, &code)) return MR_FAILURE; + switch (code.kind) + { + case symref_code_cv_typeid: + if (code.cv_typeid < T_MAXPREDEFINEDTYPE) + return pdb_reader_basic_request(pdb, code.cv_typeid, req, data); + if (pdb_reader_resolve_cv_typeid(pdb, code.cv_typeid, &code.cv_typeid)) return MR_FAILURE; + if (pdb_reader_get_type_details(pdb, code.cv_typeid, &type_details)) return MR_FAILURE; + return pdb_reader_TPI_request(pdb, symref, type_details, req, data); + case symref_code_action: + { + struct pdb_action_entry *entry = &pdb->action_store[code.action]; + + switch (entry->action_type) + { + case action_type_cv_typ_t: + return pdb_reader_TPI_argtype_request(pdb, entry, req, data); + case action_type_field: + return pdb_reader_TPI_field_request(pdb, entry, req, data); + case action_type_globals: + return pdb_reader_DBI_globals_request(pdb, entry, req, data); + default: + return MR_FAILURE; + } + } + return MR_FAILURE; + default: + return MR_FAILURE; + } +} + +static enum method_result pdb_method_request_symref_t(struct module_format *modfmt, symref_t symref, IMAGEHLP_SYMBOL_TYPE_INFO req, void *data) +{ + struct pdb_reader *pdb; + + pdb = pdb_get_current_reader(modfmt); + if (pdb_reader_init_TPI(pdb)) return MR_FAILURE; + return pdb_reader_request_symref_t(pdb, symref, req, data); +} + +BOOL cv_hack_ptr_to_symref(struct pdb_reader *pdb, cv_typ_t cv_typeid, symref_t *symref) +{ + struct symref_code code; + + if (!pdb) return FALSE; + if (pdb_reader_init_TPI(pdb)) return FALSE; + return pdb_reader_encode_symref(pdb, symref_code_init_from_cv_typeid(&code, cv_typeid), symref) == R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_walker_from_compiland_index(struct pdb_reader *pdb, unsigned compiland, + struct pdb_reader_walker *compiland_walker, + /* optional */ + PDB_SYMBOL_FILE_EX *dbi_cu_header, char **obj_name) +{ + enum pdb_result result; + struct pdb_reader_compiland_iterator compiland_iter; + + if ((result = pdb_reader_compiland_iterator_init(pdb, &compiland_iter))) return result; + do + { + if (!compiland--) + { + if ((result = pdb_reader_walker_init(pdb, compiland_iter.dbi_cu_header.stream, compiland_walker))) return result; + if (obj_name && (result = pdb_reader_compiland_iterator_alloc_and_read_compiland_name(pdb, &compiland_iter, obj_name))) return result; + if (dbi_cu_header) *dbi_cu_header = compiland_iter.dbi_cu_header; + compiland_walker->offset += sizeof(UINT32); + return R_PDB_SUCCESS; + } + } while (pdb_reader_compiland_iterator_next(pdb, &compiland_iter) == R_PDB_SUCCESS); + return R_PDB_NOT_FOUND; +} + +static enum pdb_result pdb_reader_init_IPI(struct pdb_reader *pdb) +{ + enum pdb_result result; + + if (pdb->IPI_types_invalid) return R_PDB_INVALID_PDB_FILE; + if (pdb->ipi_walker.stream_id == 0) /* load basic types information and hash table */ + { + if ((result = pdb_reader_walker_init(pdb, PDB_STREAM_IPI, &pdb->ipi_walker))) goto invalid_file; + /* assuming stream is always big enough go hold a full PDB_TYPES */ + if ((result = pdb_reader_READ(pdb, &pdb->ipi_walker, &pdb->ipi_header))) goto invalid_file; + result = R_PDB_INVALID_PDB_FILE; + if (pdb->ipi_header.version < 19960000 || pdb->ipi_header.type_offset < sizeof(PDB_TYPES)) + { + /* not supported yet... */ + FIXME("Old PDB_TYPES header, skipping\n"); + goto invalid_file; + } + /* validate some bits */ + if (pdb->ipi_header.hash_size != (pdb->ipi_header.last_index - pdb->ipi_header.first_index) * pdb->ipi_header.hash_value_size || + pdb->ipi_header.search_size % sizeof(uint32_t[2])) + goto invalid_file; + if (pdb->ipi_header.hash_value_size > sizeof(unsigned)) + { + PDB_REPORT_UNEXPECTED("IPI hash value size", pdb->ipi_header.hash_value_size); + goto invalid_file; + } + pdb->ipi_walker.offset = pdb->ipi_header.type_offset; + } + return R_PDB_SUCCESS; +invalid_file: + memset(&pdb->ipi_walker, 0, sizeof(pdb->ipi_walker)); + pdb->IPI_types_invalid = 1; + return result; +} + +static enum pdb_result pdb_reader_IPI_offset_from_cv_itemid(struct pdb_reader *pdb, cv_itemid_t cv_itemid, pdbsize_t *found_type_offset) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + struct type_offset type_offset; + size_t found; + unsigned short int cv_type_len; + + if ((result = pdb_reader_init_IPI(pdb))) return result; + walker = pdb->ipi_walker; + + type_offset.pdb = pdb; + if ((result = pdb_reader_walker_init(pdb, pdb->ipi_header.hash_stream, &type_offset.walker))) return result; + type_offset.to_search = cv_itemid; + if ((result = pdb_reader_walker_narrow(&type_offset.walker, pdb->ipi_header.search_offset, pdb->ipi_header.search_size))) return result; + result = pdb_reader_internal_binary_search(pdb->ipi_header.search_size / sizeof(uint32_t[2]), + pdb_reader_type_offset_cmp, &found, &type_offset); + + if (result) + { + if (result != R_PDB_NOT_FOUND) return result; + + if (type_offset.values[0] > cv_itemid) {WARN("Out of bounds\n"); return R_PDB_INVALID_PDB_FILE;} + walker.offset += type_offset.values[1]; + + for ( ; type_offset.values[0] < cv_itemid; type_offset.values[0]++) + { + if ((result = pdb_reader_READ(pdb, &walker, &cv_type_len))) return result; + walker.offset += cv_type_len; + } + } + else walker.offset += type_offset.values[1]; + *found_type_offset = walker.offset; + + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_IPI_alloc_and_read_full_codeview_type(struct pdb_reader *pdb, cv_itemid_t cv_itemid, union codeview_type **cv_type) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + + if ((result = pdb_reader_init_IPI(pdb))) return result; + walker = pdb->ipi_walker; + if ((result = pdb_reader_IPI_offset_from_cv_itemid(pdb, cv_itemid, &walker.offset))) return result; + return pdb_reader_alloc_and_read_full_blob(pdb, &walker, (void **)cv_type); +} + +/* walk the top level global symbols to find matching address */ +static enum pdb_result pdb_reader_search_codeview_symbol_by_address(struct pdb_reader *pdb, struct pdb_reader_walker *walker, + DWORD_PTR address, union codeview_symbol *cv_symbol, pdbsize_t *end_stream_offset) +{ + enum pdb_result result; + unsigned short segment; + unsigned offset, pend; + DWORD64 symbol_address; + + while (pdb_reader_read_partial_codeview_symbol(pdb, walker, cv_symbol) == R_PDB_SUCCESS && cv_symbol->generic.id) + { + switch (cv_symbol->generic.id) + { + case S_GDATA32: + case S_LDATA32: + segment = cv_symbol->data_v3.segment; + offset = cv_symbol->data_v3.offset; + pend = 0; + break; + case S_THUNK32: + segment = cv_symbol->thunk_v3.segment; + offset = cv_symbol->thunk_v3.offset; + pend = cv_symbol->thunk_v3.pend; + break; + case S_GPROC32: + case S_LPROC32: + segment = cv_symbol->proc_v3.segment; + offset = cv_symbol->proc_v3.offset; + pend = cv_symbol->proc_v3.pend; + break; + + default: + WARN("Unexpected codeview symbol id %x\n", cv_symbol->generic.id); + /* fall through */ + case S_OBJNAME: + case S_COMPILE: + case S_COMPILE2: + case S_COMPILE3: + case S_BUILDINFO: + case S_UDT: + case S_UNAMESPACE: + segment = 0; + offset = 0; + pend = 0; + break; + } + if (segment) + { + if ((result = pdb_reader_get_segment_address(pdb, segment, offset, &symbol_address))) return result; + if (address == symbol_address) + { + *end_stream_offset = pend; + return R_PDB_SUCCESS; + } + } + if (pend) /* jump to S_END, and skip it */ + { + walker->offset = pend; + if ((result = pdb_reader_read_partial_codeview_symbol(pdb, walker, cv_symbol))) return result; + if (cv_symbol->generic.id != S_END) return R_PDB_INVALID_PDB_FILE; + } + walker->offset += cv_symbol->generic.len; + } + return R_PDB_NOT_FOUND; +} + +static enum pdb_result pdb_reader_alloc_and_fetch_from_checksum(struct pdb_reader *pdb, struct pdb_reader_walker checksum_walker, + unsigned chksum_offset, char **string) +{ + enum pdb_result result; + struct CV_Checksum_t checksum; + + checksum_walker.offset += chksum_offset; + if ((result = pdb_reader_READ(pdb, &checksum_walker, &checksum))) return result; + return pdb_reader_alloc_and_fetch_global_string(pdb, checksum.strOffset, string); +} + +static enum pdb_result pdb_reader_alloc_and_fetch_from_checksum_subsection(struct pdb_reader *pdb, struct pdb_reader_walker linetab2_walker, + cv_itemid_t cv_inlinee, char **string, unsigned *line_number) +{ + enum pdb_result result; + struct pdb_reader_walker sub_walker; + struct pdb_reader_walker checksum_walker; + struct pdb_reader_walker inlineelines_walker; + + sub_walker = linetab2_walker; + if ((result = pdb_reader_subsection_next(pdb, &sub_walker, DEBUG_S_FILECHKSMS, &checksum_walker))) + { + WARN("No DEBUG_S_FILECHKSMS found\n"); + return R_PDB_MISSING_INFORMATION; + } + + for (sub_walker = linetab2_walker; !(result = pdb_reader_subsection_next(pdb, &sub_walker, DEBUG_S_INLINEELINES, &inlineelines_walker)); ) + { + UINT32 inlinee_kind; + struct CV_InlineeSourceLine_t inlsrc; + struct CV_InlineeSourceLineEx_t inlsrcex; + + if ((result = pdb_reader_READ(pdb, &inlineelines_walker, &inlinee_kind))) return result; + switch (inlinee_kind) + { + case CV_INLINEE_SOURCE_LINE_SIGNATURE: + while (!pdb_reader_READ(pdb, &inlineelines_walker, &inlsrc)) + { + if (inlsrc.inlinee == cv_inlinee) + { + if ((result = pdb_reader_alloc_and_fetch_from_checksum(pdb, checksum_walker, inlsrc.fileId, string))) return result; + *line_number = inlsrc.sourceLineNum; + return R_PDB_SUCCESS; + } + } + break; + case CV_INLINEE_SOURCE_LINE_SIGNATURE_EX: + while (!pdb_reader_READ(pdb, &inlineelines_walker, &inlsrcex)) + { + if (inlsrcex.inlinee == cv_inlinee) + { + if ((result = pdb_reader_alloc_and_fetch_from_checksum(pdb, checksum_walker, inlsrcex.fileId, string))) return result; + *line_number = inlsrcex.sourceLineNum; + return R_PDB_SUCCESS; + } + inlineelines_walker.offset += inlsrcex.countOfExtraFiles * sizeof(inlsrcex.extraFileId[0]); + } + break; + default: + WARN("Unknown signature %x in INLINEELINES subsection\n", inlinee_kind); + break; + } + } + return R_PDB_NOT_FOUND; +} + +static enum pdb_result pdb_reader_uncompress_inlinesite_annotation(struct pdb_reader *pdb, struct pdb_reader_walker *walker, unsigned *value) +{ + enum pdb_result result; + unsigned res; + unsigned char ch; + unsigned i, num_shift; + + if ((result = pdb_reader_READ(pdb, walker, &ch))) return result; + + if ((ch & 0x80) == 0x00) + { + res = ch; + num_shift = 0; + } + else if ((ch & 0xC0) == 0x80) + { + res = ch & 0x3f; + num_shift = 1; + } + else if ((ch & 0xE0) == 0xC0) + { + res = (ch & 0x1f); + num_shift = 3; + } + else + { + res = (unsigned)(-1); + num_shift = 0; + } + for (i = 0; i < num_shift; i++) + { + if ((result = pdb_reader_READ(pdb, walker, &ch))) return result; + res <<= 8; + res |= ch; + } + *value = res; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_read_inlinesite_annotation(struct pdb_reader *pdb, struct pdb_reader_walker *annotation_walker, + unsigned *opcode, unsigned *arg1, unsigned *arg2) +{ + enum pdb_result result; + + if ((result = pdb_reader_uncompress_inlinesite_annotation(pdb, annotation_walker, opcode))) return result; + if (*opcode == BA_OP_Invalid) + *arg1 = *arg2 = 0; + else if (*opcode <= BA_OP_ChangeColumnEnd) + { + if ((result = pdb_reader_uncompress_inlinesite_annotation(pdb, annotation_walker, arg1))) return result; + if (*opcode == BA_OP_ChangeCodeOffsetAndLineOffset) + { + *arg2 = *arg1 >> 4; + *arg1 &= 0x0F; + } + else if (*opcode == BA_OP_ChangeCodeLengthAndCodeOffset) + { + if ((result = pdb_reader_uncompress_inlinesite_annotation(pdb, annotation_walker, arg2))) return result; + } + else *arg2 = 0; + } + else + { + WARN("Unexpected BA annotation options %x\n", *opcode); + return R_PDB_INVALID_PDB_FILE; + } + return R_PDB_SUCCESS; +} + +static inline int pdb_reader_convert_binannot_to_signed(unsigned i) +{ + return (i & 1) ? -(int)(i >> 1) : (int)(i >> 1); +} + +static enum pdb_result pdb_method_get_line_from_inlined_address_internal(struct pdb_reader *pdb, struct symt_function *inlined, + DWORD64 address, struct lineinfo_t *line_info) +{ + struct symt_function *function = symt_get_function_from_inlined(inlined); + enum pdb_result result; + PDB_SYMBOL_FILE_EX dbi_cu_header; + struct pdb_reader_walker cu_walker; + struct pdb_reader_walker linetab2_walker; + struct pdb_reader_walker inlinee_walker; + DWORD64 top_function_address; + unsigned compiland; + union codeview_symbol cv_top_function_symbol; + union codeview_symbol cv_inlinee_symbol; + pdbsize_t end_stream_offset; + cv_itemid_t cv_inlinee; + size_t annotation_offset; + char *source_file_name; + unsigned line_number; + unsigned opcode, arg1, arg2; + unsigned offset_top_function; + + if (!symt_get_info(pdb->module, &function->symt, TI_GET_ADDRESS, &top_function_address)) return R_PDB_INVALID_ARGUMENT; + if ((result = pdb_reader_lookup_compiland_by_address(pdb, top_function_address, &compiland))) return result; + if ((result = pdb_reader_walker_from_compiland_index(pdb, compiland, &cu_walker, &dbi_cu_header, NULL))) return result; + + if ((result = pdb_reader_search_codeview_symbol_by_address(pdb, &cu_walker, top_function_address, &cv_top_function_symbol, &end_stream_offset))) return result; + if (inlined->user < cu_walker.offset || inlined->user >= end_stream_offset) return R_PDB_INVALID_ARGUMENT; + + inlinee_walker.stream_id = cu_walker.stream_id; + inlinee_walker.offset = inlined->user; + inlinee_walker.last = end_stream_offset; + if ((result = pdb_reader_read_partial_codeview_symbol(pdb, &inlinee_walker, &cv_inlinee_symbol))) return result; + switch (cv_inlinee_symbol.generic.id) + { + case S_INLINESITE: + cv_inlinee = cv_inlinee_symbol.inline_site_v3.inlinee; + annotation_offset = offsetof(union codeview_symbol, inline_site_v3.binaryAnnotations); + break; + case S_INLINESITE2: + cv_inlinee = cv_inlinee_symbol.inline_site2_v3.inlinee; + annotation_offset = offsetof(union codeview_symbol, inline_site2_v3.binaryAnnotations); + break; + default: + WARN("Unexpected symbol id %x for %u\n", cv_inlinee_symbol.generic.id, inlined->symt.tag); + return R_PDB_INVALID_PDB_FILE; + } + if ((result = pdb_reader_walker_init_linetab2(pdb, &dbi_cu_header, &linetab2_walker))) return result; + + if ((result = pdb_reader_alloc_and_fetch_from_checksum_subsection(pdb, linetab2_walker, cv_inlinee, &source_file_name, &line_number))) return result; + + /* then walk annotations */ + if ((result = pdb_reader_walker_narrow(&inlinee_walker, + inlinee_walker.offset + annotation_offset - sizeof(cv_inlinee_symbol.generic.len), + cv_inlinee_symbol.generic.len - annotation_offset + sizeof(cv_inlinee_symbol.generic.len)))) return result; + offset_top_function = 0; + while (!(result = pdb_reader_read_inlinesite_annotation(pdb, &inlinee_walker, &opcode, &arg1, &arg2)) && + opcode != BA_OP_Invalid) + { + BOOL check_address = FALSE; + switch (opcode) + { + case BA_OP_CodeOffset: + offset_top_function = arg1; + break; + case BA_OP_ChangeCodeOffset: + offset_top_function += arg1; + check_address = TRUE; + break; + case BA_OP_ChangeCodeLength: + /* this op isn't widely used by MSVC, but clang uses it a lot... */ + offset_top_function += arg1; + break; + case BA_OP_ChangeFile: + pdb_reader_free(pdb, source_file_name); + { + struct pdb_reader_walker sub_walker = linetab2_walker; + struct pdb_reader_walker checksum_walker = linetab2_walker; + if ((result = pdb_reader_subsection_next(pdb, &sub_walker, DEBUG_S_FILECHKSMS, &checksum_walker))) + { + WARN("No DEBUG_S_FILECHKSMS found\n"); + return R_PDB_MISSING_INFORMATION; + } + if ((result = pdb_reader_alloc_and_fetch_from_checksum(pdb, checksum_walker, arg1, &source_file_name))) return result; + } + break; + case BA_OP_ChangeLineOffset: + line_number += pdb_reader_convert_binannot_to_signed(arg1); + break; + case BA_OP_ChangeCodeOffsetAndLineOffset: + line_number += pdb_reader_convert_binannot_to_signed(arg2); + offset_top_function += arg1; + check_address = TRUE; + break; + case BA_OP_ChangeCodeLengthAndCodeOffset: + offset_top_function += arg2; + check_address = TRUE; + break; + default: + WARN("Unsupported op %d\n", opcode); + break; + } + if (check_address) + { + if (top_function_address + offset_top_function > address) /* we're above the searched address */ + break; + line_info->address = top_function_address + offset_top_function; + line_info->line_number = line_number; + if (top_function_address + offset_top_function == address) /* we've reached our address */ + break; + } + } + line_info->key = NULL; + result = lineinfo_set_nameA(pdb->module->process, line_info, source_file_name) ? R_PDB_SUCCESS : R_PDB_OUT_OF_MEMORY; + pdb_reader_free(pdb, source_file_name); + + return result; +} + +static enum method_result pdb_method_get_line_from_inlined_address(struct module_format *modfmt, struct symt_function *inlined, + DWORD64 address, struct lineinfo_t *line_info) +{ + struct pdb_reader *pdb; + + pdb = pdb_get_current_reader(modfmt); + return pdb_method_result(pdb_method_get_line_from_inlined_address_internal(pdb, inlined, address, line_info)); +} + +static enum pdb_result pdb_reader_symbol_skip_defranges(struct pdb_reader *pdb, struct pdb_reader_walker *walker) +{ + enum pdb_result result; + union codeview_symbol cv_symbol; + + while ((result = pdb_reader_read_partial_codeview_symbol(pdb, walker, &cv_symbol)) == R_PDB_SUCCESS) + { + if (cv_symbol.generic.id < S_DEFRANGE || cv_symbol.generic.id > S_DEFRANGE_REGISTER_REL) + { + walker->offset -= sizeof(cv_symbol.generic.len); + break; + } + walker->offset += cv_symbol.generic.len; + } + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_symbol_count_range_annotations(struct pdb_reader *pdb, struct pdb_reader_walker annotation_walker, + unsigned *pnum_ranges) +{ + enum pdb_result result; + unsigned num_ranges = 0, opcode, arg1, arg2; + + while ((result = pdb_reader_read_inlinesite_annotation(pdb, &annotation_walker, &opcode, &arg1, &arg2)) == R_PDB_SUCCESS) + { + if (opcode == BA_OP_Invalid) break; + switch (opcode) + { + case BA_OP_CodeOffset: + case BA_OP_ChangeCodeLength: + case BA_OP_ChangeFile: + case BA_OP_ChangeLineOffset: + break; + case BA_OP_ChangeCodeOffset: + case BA_OP_ChangeCodeOffsetAndLineOffset: + case BA_OP_ChangeCodeLengthAndCodeOffset: + num_ranges++; + break; + default: + WARN("Unsupported op %d\n", opcode); + break; + } + } + *pnum_ranges = num_ranges; + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_symbol_skip_if(struct pdb_reader *pdb, struct pdb_reader_walker *walker, unsigned id) +{ + enum pdb_result result; + union codeview_symbol cv_symbol; + + if ((result = pdb_reader_read_partial_codeview_symbol(pdb, walker, &cv_symbol))) return result; + if (cv_symbol.generic.id != id) + { + walker->offset -= sizeof(cv_symbol.generic.len); + return R_PDB_NOT_FOUND; + } + walker->offset += cv_symbol.generic.len; + return R_PDB_SUCCESS; +} + +static inline void inline_site_update_last_range(struct symt_function* inlined, unsigned index, ULONG_PTR hi) +{ + if (index && index <= inlined->num_ranges) + { + struct addr_range* range = &inlined->ranges[index - 1]; + /* only change range if it has no span (code start without code end) */ + if (range->low == range->high) + range->high = hi; + } +} + +static enum pdb_result pdb_reader_create_inline_site(struct pdb_reader *pdb, struct symt_function *top_func, + struct symt *container, + cv_itemid_t cv_inlinee_id, + pdbsize_t symbol_start_offset, + struct pdb_reader_walker *annotation_walker, + struct symt_function **pinlined) +{ + enum pdb_result result; + union codeview_type *cv_type; + struct symt_function *inlined; + unsigned num_ranges; + unsigned offset, index; + symref_t type_symref; + unsigned opcode, arg1, arg2; + + if ((result = pdb_reader_IPI_alloc_and_read_full_codeview_type(pdb, cv_inlinee_id, &cv_type))) + { + WARN("Couldn't find type %x in IPI stream\n", cv_inlinee_id); + return result; + } + if ((result = pdb_reader_symbol_count_range_annotations(pdb, *annotation_walker, &num_ranges))) return result; + if (!num_ranges) return R_PDB_INVALID_PDB_FILE; + + switch (cv_type->generic.id) + { + case LF_FUNC_ID: + if ((result = pdb_reader_symref_from_cv_typeid(pdb, cv_type->func_id_v3.type, &type_symref))) return result; + inlined = symt_new_inlinesite(pdb->module, top_func, container, cv_type->func_id_v3.name, + type_symref, symbol_start_offset, num_ranges); + break; + case LF_MFUNC_ID: + /* FIXME we just declare a function, not a method */ + if ((result = pdb_reader_symref_from_cv_typeid(pdb, cv_type->mfunc_id_v3.type, &type_symref))) return result; + inlined = symt_new_inlinesite(pdb->module, top_func, container, cv_type->mfunc_id_v3.name, + type_symref, symbol_start_offset, num_ranges); + break; + default: + result = PDB_REPORT_UNEXPECTED("inlinee kind", cv_type->generic.id); + pdb_reader_free(pdb, cv_type); + return result; + } + pdb_reader_free(pdb, cv_type); + + /* rescan all annotations and store ranges & line information */ + offset = 0; + index = 0; + + while (pdb_reader_read_inlinesite_annotation(pdb, annotation_walker, &opcode, &arg1, &arg2) == R_PDB_SUCCESS) + { + switch (opcode) + { + case BA_OP_CodeOffset: + offset = arg1; + break; + case BA_OP_ChangeCodeOffset: + offset += arg1; + inline_site_update_last_range(inlined, index, top_func->ranges[0].low + offset); + inlined->ranges[index ].low = top_func->ranges[0].low + offset; + inlined->ranges[index++].high = top_func->ranges[0].low + offset; + break; + case BA_OP_ChangeCodeLength: + /* this op isn't widely used by MSVC, but clang uses it a lot... */ + offset += arg1; + inline_site_update_last_range(inlined, index, top_func->ranges[0].low + offset); + break; + case BA_OP_ChangeFile: + break; + case BA_OP_ChangeLineOffset: + break; + case BA_OP_ChangeCodeOffsetAndLineOffset: + offset += arg1; + inline_site_update_last_range(inlined, index, top_func->ranges[0].low + offset); + inlined->ranges[index ].low = top_func->ranges[0].low + offset; + inlined->ranges[index++].high = top_func->ranges[0].low + offset; + break; + case BA_OP_ChangeCodeLengthAndCodeOffset: + offset += arg2; + inline_site_update_last_range(inlined, index, top_func->ranges[0].low + offset); + inlined->ranges[index ].low = top_func->ranges[0].low + offset; + inlined->ranges[index++].high = top_func->ranges[0].low + offset + arg1; + break; + default: + WARN("Unsupported op %d\n", opcode); + break; + } + } + if (index != num_ranges) /* sanity check */ + return PDB_REPORT_UNEXPECTED("Internal logic error", 0); + if (inlined->num_ranges) + { + struct addr_range* range = &inlined->ranges[inlined->num_ranges - 1]; + if (range->low == range->high) WARN("pending empty range at end of %s inside %s\n", + debugstr_a(inlined->hash_elt.name), + debugstr_a(top_func->hash_elt.name)); + } + *pinlined = inlined; + return R_PDB_SUCCESS; +} + +/* likely to review */ +static enum pdb_result pdb_reader_create_variable(struct pdb_reader *pdb, + struct symt_compiland *compiland, + struct symt_function* func, + struct symt_block* block, + const char* name, + struct location *loc, + cv_typ_t cv_typeid, BOOL is_local) +{ + if (name && *name) + { + enum pdb_result result; + symref_t symref; + + if ((result = pdb_reader_symref_from_cv_typeid(pdb, cv_typeid, &symref))) return result; + if (func) + { + if (!is_local || loc->kind == loc_tlsrel) WARN("Unsupported construct\n"); + symt_add_func_local(pdb->module, func, DataIsStaticLocal, loc, block, symref, name); + return R_PDB_SUCCESS; + } + + if (is_local ^ (compiland != 0)) FIXME("Unsupported construct\n"); + symt_new_global_variable(pdb->module, compiland, name, is_local, *loc, 0, symref); + } + return R_PDB_SUCCESS; +} + +static BOOL symt_function_has_local_variable(struct symt_function* func, const char* name) +{ + int i; + + for (i = 0; i < vector_length(&func->vchildren); ++i) + { + struct symt* p = *(struct symt**)vector_at(&func->vchildren, i); + if (symt_check_tag(p, SymTagData) && !strcmp(((struct symt_data*)p)->hash_elt.name, name)) + return TRUE; + } + return FALSE; +} + +static enum pdb_result pdb_reader_load_compiland_symbols(struct pdb_reader *pdb, struct symt_compiland *compiland, struct pdb_reader_walker *walker) +{ + enum pdb_result result; + union codeview_symbol *cv_symbol; + struct symt_function *top_func = NULL; + struct symt_function *curr_func = NULL; + struct symt_block *block = NULL; + struct location loc; + unsigned top_frame_size = -1; + DWORD64 address; + symref_t type_symref; + /* + * Loop over the different types of records and whenever we + * find something we are interested in, record it and move on. + */ + while ((result = pdb_reader_alloc_and_read_full_codeview_symbol(pdb, walker, &cv_symbol)) == R_PDB_SUCCESS) + { + pdbsize_t symbol_start_offset = walker->offset - (sizeof(cv_symbol->generic.len) + cv_symbol->generic.len); + if (!cv_symbol->generic.id || cv_symbol->generic.len < 2) break; + if ((cv_symbol->generic.len + 2) & 3) WARN("unpadded len %u\n", cv_symbol->generic.len + 2); + + switch (cv_symbol->generic.id) + { + case S_LDATA32: + loc.kind = loc_absolute; + loc.reg = 0; + if ((result = pdb_reader_get_segment_address(pdb, cv_symbol->data_v3.segment, cv_symbol->data_v3.offset, &address))) + goto failure; + loc.offset = address; + + if ((result = pdb_reader_create_variable(pdb, compiland, curr_func, block, cv_symbol->data_v3.name, &loc, + cv_symbol->data_v3.symtype, TRUE))) goto failure; + break; + + /* variables with thread storage */ + case S_GTHREAD32: + case S_LTHREAD32: + loc.kind = loc_tlsrel; + loc.reg = 0; + loc.offset = cv_symbol->thread_v3.offset; + + if ((result = pdb_reader_create_variable(pdb, compiland, curr_func, block, cv_symbol->thread_v3.name, + &loc, cv_symbol->thread_v3.symtype, + cv_symbol->generic.id == S_LTHREAD32))) goto failure; + break; + + case S_THUNK32: + if ((result = pdb_reader_get_segment_address(pdb, cv_symbol->thunk_v3.segment, cv_symbol->thunk_v3.offset, &address))) goto failure; + symt_new_thunk(pdb->module, compiland, + cv_symbol->thunk_v3.name, cv_symbol->thunk_v3.thtype, + address, cv_symbol->thunk_v3.thunk_len); + break; + + /* + * Global and static functions. + */ + case S_GPROC32: + case S_LPROC32: + if (top_func) WARN("nested function\n"); + if ((result = pdb_reader_get_segment_address(pdb, cv_symbol->proc_v3.segment, cv_symbol->proc_v3.offset, &address))) goto failure; + if ((result = pdb_reader_symref_from_cv_typeid(pdb, cv_symbol->proc_v3.proctype, &type_symref))) goto failure; + if ((top_func = symt_new_function(pdb->module, compiland, + cv_symbol->proc_v3.name, + address, cv_symbol->proc_v3.proc_len, + type_symref, symbol_start_offset))) + { + curr_func = top_func; + loc.kind = loc_absolute; + loc.offset = cv_symbol->proc_v3.debug_start; + symt_add_function_point(pdb->module, curr_func, SymTagFuncDebugStart, &loc, NULL); + loc.offset = cv_symbol->proc_v3.debug_end; + symt_add_function_point(pdb->module, curr_func, SymTagFuncDebugEnd, &loc, NULL); + } + break; + /* + * Function parameters and stack variables. + */ + case S_BPREL32: + /* S_BPREL32 can be present after S_LOCAL; prefer S_LOCAL when present */ + if (symt_function_has_local_variable(curr_func, cv_symbol->stack_v3.name)) break; + if ((result = pdb_reader_symref_from_cv_typeid(pdb, cv_symbol->stack_v3.symtype, &type_symref))) goto failure; + loc.kind = loc_regrel; + /* Yes, it's i386 dependent, but that's the symbol purpose. S_REGREL is used on other CPUs */ + loc.reg = CV_REG_EBP; + loc.offset = cv_symbol->stack_v3.offset; + symt_add_func_local(pdb->module, curr_func, + cv_symbol->stack_v3.offset > 0 ? DataIsParam : DataIsLocal, + &loc, block, type_symref, cv_symbol->stack_v3.name); + break; + case S_REGREL32: + /* S_REGREL32 can be present after S_LOCAL; prefer S_LOCAL when present */ + if (symt_function_has_local_variable(curr_func, cv_symbol->regrel_v3.name)) break; + if ((result = pdb_reader_symref_from_cv_typeid(pdb, cv_symbol->regrel_v3.symtype, &type_symref))) goto failure; + loc.kind = loc_regrel; + loc.reg = cv_symbol->regrel_v3.reg; + loc.offset = cv_symbol->regrel_v3.offset; + if (top_frame_size == -1) WARN("S_REGREL32 without frameproc\n"); + symt_add_func_local(pdb->module, curr_func, + cv_symbol->regrel_v3.offset >= top_frame_size ? DataIsParam : DataIsLocal, + &loc, block, type_symref, cv_symbol->regrel_v3.name); + break; + + case S_REGISTER: + /* S_REGISTER can be present after S_LOCAL; prefer S_LOCAL when present */ + if (symt_function_has_local_variable(curr_func, cv_symbol->register_v3.name)) break; + if ((result = pdb_reader_symref_from_cv_typeid(pdb, cv_symbol->register_v3.type, &type_symref))) goto failure; + loc.kind = loc_register; + loc.reg = cv_symbol->register_v3.reg; + loc.offset = 0; + symt_add_func_local(pdb->module, curr_func, + DataIsLocal, &loc, block, type_symref, cv_symbol->register_v3.name); + break; + + case S_BLOCK32: + if ((result = pdb_reader_get_segment_address(pdb, cv_symbol->block_v3.segment, cv_symbol->block_v3.offset, &address))) goto failure; + block = symt_open_func_block(pdb->module, curr_func, block, 1); + block->ranges[0].low = address; + block->ranges[0].high = block->ranges[0].low + cv_symbol->block_v3.length; + break; + + case S_END: + if (block) + { + block = symt_close_func_block(pdb->module, curr_func, block); + } + else if (top_func) + { + if (curr_func != top_func) {FIXME("shouldn't close a top function with an opened inlined function\n"); result = R_PDB_INVALID_PDB_FILE; goto failure;} + top_func = curr_func = NULL; + top_frame_size = -1; + } + break; + + case S_COMPILE2: + TRACE("S-Compile-V3 machine:%x language:%x %s\n", + cv_symbol->compile2_v3.machine, cv_symbol->compile2_v3.flags.iLanguage, debugstr_a(cv_symbol->compile2_v3.name)); + break; + case S_COMPILE3: + TRACE("S-Compile3-V3 machine:%x language:%x %s\n", + cv_symbol->compile3_v3.machine, cv_symbol->compile3_v3.flags.iLanguage, debugstr_a(cv_symbol->compile3_v3.name)); + break; + + case S_ENVBLOCK: + break; + + case S_OBJNAME: + TRACE("S-ObjName-V3 %s\n", debugstr_a(cv_symbol->objname_v3.name)); + break; + + case S_LABEL32: + if ((result = pdb_reader_get_segment_address(pdb, cv_symbol->label_v3.segment, cv_symbol->label_v3.offset, &address))) goto failure; + if (curr_func) + { + loc.kind = loc_absolute; + loc.offset = address - curr_func->ranges[0].low; + symt_add_function_point(pdb->module, curr_func, SymTagLabel, &loc, cv_symbol->label_v3.name); + } + else symt_new_label(pdb->module, compiland, cv_symbol->label_v3.name, address); + break; + + case S_LOCAL: + /* FIXME: don't store global/static variables accessed through registers... we don't support that + * in locals... anyway, global data record should be present as well (so the variable will be available + * through the global definition, but potentially not updated) + */ + if (!cv_symbol->local_v3.varflags.enreg_global && !cv_symbol->local_v3.varflags.enreg_static) + { + loc.kind = loc_cv_defrange; + loc.reg = walker->stream_id; + loc.offset = symbol_start_offset; + + if ((result = pdb_reader_symref_from_cv_typeid(pdb, cv_symbol->local_v3.symtype, &type_symref))) goto failure; + symt_add_func_local(pdb->module, curr_func, + cv_symbol->local_v3.varflags.is_param ? DataIsParam : DataIsLocal, + &loc, block, type_symref, cv_symbol->local_v3.name); + } + if ((result = pdb_reader_symbol_skip_defranges(pdb, walker))) goto failure; + break; + case S_INLINESITE: + { + struct pdb_reader_walker annotation_walker; + struct symt_function* inlined; + + annotation_walker.stream_id = walker->stream_id; + annotation_walker.offset = symbol_start_offset + offsetof(union codeview_symbol, inline_site_v3.binaryAnnotations); + annotation_walker.last = symbol_start_offset + sizeof(cv_symbol->generic.len) + cv_symbol->generic.len; + + if ((result = pdb_reader_create_inline_site(pdb, top_func, block ? &block->symt : &curr_func->symt, + cv_symbol->inline_site_v3.inlinee, symbol_start_offset, &annotation_walker, &inlined))) + { + /* skip whole inlined block */ + walker->offset = cv_symbol->inline_site_v3.pEnd; + if ((result = pdb_reader_symbol_skip_if(pdb, walker, S_INLINESITE_END))) goto failure; + } + else + { + curr_func = inlined; + block = NULL; + } + } + break; + case S_INLINESITE2: + { + struct pdb_reader_walker annotation_walker = *walker; + struct symt_function* inlined; + + annotation_walker.stream_id = walker->stream_id; + annotation_walker.offset = symbol_start_offset + offsetof(union codeview_symbol, inline_site2_v3.binaryAnnotations); + annotation_walker.last = symbol_start_offset + sizeof(cv_symbol->generic.len) + cv_symbol->generic.len; + + if ((result = pdb_reader_create_inline_site(pdb, top_func, block ? &block->symt : &curr_func->symt, + cv_symbol->inline_site2_v3.inlinee, symbol_start_offset, &annotation_walker, &inlined))) + { + /* skip whole inlined block */ + walker->offset = cv_symbol->inline_site2_v3.pEnd; + if ((result = pdb_reader_symbol_skip_if(pdb, walker, S_INLINESITE_END))) goto failure; + } + else + { + curr_func = inlined; + block = NULL; + } + } + break; + + case S_INLINESITE_END: + block = symt_is_symref_ptr(curr_func->container) && symt_check_tag(SYMT_SYMREF_TO_PTR(curr_func->container), SymTagBlock) ? + (struct symt_block*)curr_func->container : NULL; + curr_func = (struct symt_function*)symt_get_upper_inlined(curr_func); + break; + + case S_SSEARCH: + TRACE("Start search: seg=0x%x at offset 0x%08x\n", + cv_symbol->ssearch_v1.segment, cv_symbol->ssearch_v1.offset); + break; + + case S_ALIGN: + TRACE("S-Align V1\n"); + break; + case S_HEAPALLOCSITE: + TRACE("S-heap site V3: offset=0x%08x at sect_idx 0x%04x, inst_len 0x%08x, index 0x%08x\n", + cv_symbol->heap_alloc_site_v3.offset, cv_symbol->heap_alloc_site_v3.sect_idx, + cv_symbol->heap_alloc_site_v3.inst_len, cv_symbol->heap_alloc_site_v3.index); + break; + + case S_SEPCODE: + if (!top_func) + { + struct symt_ht* parent; + if ((result = pdb_reader_get_segment_address(pdb, cv_symbol->sepcode_v3.sectParent, cv_symbol->sepcode_v3.offParent, &address))) goto failure; + parent = symt_find_symbol_at(pdb->module, address); + if (symt_check_tag(&parent->symt, SymTagFunction)) + { + struct symt_function* pfunc = (struct symt_function*)parent; + if ((result = pdb_reader_get_segment_address(pdb, cv_symbol->sepcode_v3.sect, cv_symbol->sepcode_v3.off, &address))) goto failure; + top_func = symt_new_function(pdb->module, compiland, pfunc->hash_elt.name, + address, cv_symbol->sepcode_v3.length, pfunc->type, symbol_start_offset); + curr_func = top_func; + } + else + WARN("Couldn't find function referenced by S_SEPCODE at %04x:%08x\n", + cv_symbol->sepcode_v3.sectParent, cv_symbol->sepcode_v3.offParent); + } + else + { + FIXME("S_SEPCODE inside top-level function %s\n", debugstr_a(top_func->hash_elt.name)); + result = R_PDB_INVALID_PDB_FILE; + goto failure; + } + break; + + case S_FRAMEPROC: + /* expecting only S_FRAMEPROC once for top level functions */ + if (top_frame_size == -1 && curr_func && curr_func == top_func) + top_frame_size = cv_symbol->frame_info_v2.sz_frame; + else + { + FIXME("Unexpected S_FRAMEPROC %d (%p %p) %x\n", top_frame_size, top_func, curr_func, walker->offset); + result = R_PDB_INVALID_PDB_FILE; + goto failure; + } + break; + + case S_GMANPROC: + case S_LMANPROC: + walker->offset = cv_symbol->managed_proc_v3.pend; + if ((result = pdb_reader_symbol_skip_if(pdb, walker, S_END))) goto failure; + break; + + /* symbols only expected in globals' DBI stream */ + case S_PUB32: + case S_PROCREF: + case S_LPROCREF: + case S_TOKENREF: + case S_GDATA32: + case S_UDT: + PDB_REPORT_UNEXPECTED("(compiland stream) symbol id", cv_symbol->generic.id); + break; + + /* the symbols we can safely ignore for now */ + case S_SKIP: + case S_TRAMPOLINE: + case S_FRAMECOOKIE: + case S_SECTION: + case S_COFFGROUP: + case S_EXPORT: + case S_CALLSITEINFO: + case S_ARMSWITCHTABLE: + case S_CONSTANT: + case S_MANSLOT: + case S_OEM: + /* even if S_LOCAL groks all the S_DEFRANGE* records following itself, + * those kinds of records can also be present after a S_FILESTATIC record + * so silence them until (at least) S_FILESTATIC is supported + */ + case S_DEFRANGE_REGISTER: + case S_DEFRANGE_FRAMEPOINTER_REL: + case S_DEFRANGE_SUBFIELD_REGISTER: + case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + case S_DEFRANGE_REGISTER_REL: + case S_BUILDINFO: + case S_FILESTATIC: + case S_CALLEES: + case S_CALLERS: + case S_UNAMESPACE: + case S_INLINEES: + case S_POGODATA: + TRACE("Unsupported symbol id %x\n", cv_symbol->generic.id); + break; + + default: + PDB_REPORT_UNEXPECTED("symbol id", cv_symbol->generic.id); + break; + } + pdb_reader_free(pdb, cv_symbol); + } + return R_PDB_SUCCESS; + +failure: + pdb_reader_free(pdb, cv_symbol); + return result; +} + +static enum pdb_result pdb_reader_ensure_symbols_loaded_from_compiland(struct pdb_reader *pdb, unsigned compiland_index) +{ + enum pdb_result result; + struct pdb_compiland *compiland = &pdb->compilands[compiland_index]; + + if (compiland_index >= pdb->num_compilands) return R_PDB_INVALID_ARGUMENT; + if (!compiland->are_symbols_loaded) + { + struct pdb_reader_walker walker; + char *obj_name; + + if ((result = pdb_reader_walker_init(pdb, PDB_STREAM_DBI, &walker))) return result; + walker.offset = compiland->stream_offset; + if ((result = pdb_reader_alloc_and_fetch_string(pdb, &walker, &obj_name))) return result; + compiland->compiland = symt_new_compiland(pdb->module, obj_name); + pdb_reader_free(pdb, obj_name); + + if ((result = pdb_reader_walker_init(pdb, compiland->stream_id, &walker))) return result; + walker.offset = sizeof(UINT32); + if ((result = pdb_reader_load_compiland_symbols(pdb, (struct symt_compiland *)compiland->compiland, &walker))) return result; + compiland->are_symbols_loaded = TRUE; + } + return R_PDB_SUCCESS; +} + +static enum pdb_result pdb_reader_lookup_top_symbol_by_segment_offset(struct pdb_reader *pdb, unsigned segment, unsigned offset, symref_t *symref) +{ + enum pdb_result result; + unsigned compiland_index; + DWORD64 in_address; + struct symt_ht *symbol; + + if ((result = pdb_reader_get_segment_address(pdb, segment, offset, &in_address))) return result; + result = pdb_reader_lookup_compiland_by_segment_offset(pdb, segment, offset, &compiland_index); + if (result == R_PDB_SUCCESS) + { + if ((result = pdb_reader_ensure_symbols_loaded_from_compiland(pdb, compiland_index))) + return result; + } + /* don't fail if not found as some symbols are only present in DBI, but not in compiland */ + else if (result != R_PDB_NOT_FOUND) return result; + /* fallback to ptr symbols lookup (as ptr should be loaded by now) */ + symbol = symt_find_symbol_at(pdb->module, in_address); + if (!symbol) return R_PDB_NOT_FOUND; + *symref = symt_ptr_to_symref(&symbol->symt); + return R_PDB_SUCCESS; +} + +static enum method_result pdb_method_lookup_symbol_by_address(struct module_format *modfmt, DWORD_PTR address, symref_t *symref) +{ + enum pdb_result result; + struct pdb_reader *pdb; + unsigned segment, offset; + + pdb = pdb_get_current_reader(modfmt); + if ((result = pdb_reader_get_segment_offset_from_address(pdb, address, &segment, &offset))) return MR_FAILURE; + return pdb_method_result(pdb_reader_lookup_top_symbol_by_segment_offset(pdb, segment, offset, symref)); +} + +static enum pdb_result pdb_reader_dereference_procedure(struct pdb_reader *pdb, unsigned compiland_id, pdbsize_t stream_offset, + unsigned *segment, unsigned *offset) +{ + enum pdb_result result; + struct pdb_reader_walker walker; + union codeview_symbol cv_symbol; + unsigned stream_id; + + if (!compiland_id || compiland_id > pdb->num_compilands) return R_PDB_INVALID_ARGUMENT; + compiland_id--; + stream_id = pdb->compilands[compiland_id].stream_id; + + if ((result = pdb_reader_walker_init(pdb, stream_id, &walker))) return result; + walker.offset = stream_offset; + if ((result = pdb_reader_read_partial_codeview_symbol(pdb, &walker, &cv_symbol))) return result; + switch (cv_symbol.generic.id) + { + case S_GPROC32: + case S_LPROC32: + *segment = cv_symbol.proc_v3.segment; + *offset = cv_symbol.proc_v3.offset; + break; + + default: + PDB_REPORT_UNEXPECTED("codeview symbol-id", cv_symbol.generic.id); + /* fall through */ + case S_OBJNAME: + case S_COMPILE: + case S_COMPILE2: + case S_COMPILE3: + case S_BUILDINFO: + case S_UDT: + case S_UNAMESPACE: + case S_GMANPROC: + case S_LMANPROC: + return R_PDB_NOT_FOUND; + } + + return result; +} + +static enum method_result pdb_method_lookup_symbol_by_name(struct module_format *modfmt, const char *name, symref_t *symref) +{ + enum pdb_result result; + struct pdb_reader *pdb; + union codeview_symbol cv_symbol; + pdbsize_t globals_offset; + unsigned segment; + unsigned offset; + + pdb = pdb_get_current_reader(modfmt); + + if ((result = pdb_reader_read_DBI_codeview_symbol_by_name(pdb, name, &globals_offset, &cv_symbol))) + return pdb_method_result(result); + + switch (cv_symbol.generic.id) + { + case S_GDATA32: + case S_LDATA32: + segment = cv_symbol.data_v3.segment; + offset = cv_symbol.data_v3.offset; + break; + case S_PROCREF: + case S_LPROCREF: + if ((result = pdb_reader_dereference_procedure(pdb, cv_symbol.refsym2_v3.imod, cv_symbol.refsym2_v3.ibSym, + &segment, &offset))) + { + return MR_FAILURE; + } + break; + default: + return MR_FAILURE; + } + result = pdb_reader_lookup_top_symbol_by_segment_offset(pdb, segment, offset, symref); + if (result == R_PDB_SUCCESS) return MR_SUCCESS; + TRACE("No symbol %s found...\n", name); + return MR_NOT_FOUND; +} + +static enum method_result pdb_method_enumerate_symbols(struct module_format *modfmt, const WCHAR *match, BOOL (*cb)(symref_t, const char *, void *), void *user) +{ + enum pdb_result result; + struct pdb_reader *pdb; + struct pdb_reader_walker walker, symbol_walker; + union codeview_symbol cv_symbol; + unsigned segment; + unsigned offset; + char *symbol_name; + + pdb = pdb_get_current_reader(modfmt); + + /* FIXME could be optimized if match doesn't contain wild cards */ + /* this is currently ugly, but basically we just ensure that all the compilands which contain matching symbols + * are actually loaded, and fall back to generic mode... + */ + if ((result = pdb_reader_walker_init(pdb, pdb->dbi_header.gsym_stream, &walker))) return pdb_method_result(result); + while (pdb_reader_read_partial_codeview_symbol(pdb, &walker, &cv_symbol) == R_PDB_SUCCESS) + { + symbol_name = NULL; + symbol_walker = walker; + symbol_walker.offset -= sizeof(cv_symbol.generic.len); + switch (cv_symbol.generic.id) + { + case S_GDATA32: + case S_LDATA32: + segment = cv_symbol.data_v3.segment; + offset = cv_symbol.data_v3.offset; + symbol_walker.offset += offsetof(union codeview_symbol, data_v3.name); + if ((result = pdb_reader_alloc_and_fetch_string(pdb, &symbol_walker, &symbol_name))) return pdb_method_result(result); + break; + case S_PROCREF: + case S_LPROCREF: + if ((result = pdb_reader_dereference_procedure(pdb, cv_symbol.refsym2_v3.imod, cv_symbol.refsym2_v3.ibSym, + &segment, &offset))) + { + return pdb_method_result(result); + } + symbol_walker.offset += offsetof(union codeview_symbol, refsym2_v3.name); + if ((result = pdb_reader_alloc_and_fetch_string(pdb, &symbol_walker, &symbol_name))) return pdb_method_result(result); + break; + case S_UDT: + case S_CONSTANT: + case S_PUB32: + break; + default: + PDB_REPORT_UNEXPECTED("codeview symbol-id", cv_symbol.generic.id); + break; + } + if (symbol_name) + { + BOOL do_continue = TRUE; + symref_t symref; + + if (symt_match_stringAW(symbol_name, match, TRUE) && + pdb_reader_lookup_top_symbol_by_segment_offset(pdb, segment, offset, &symref) == R_PDB_SUCCESS) + { + do_continue = cb(symref, symbol_name, user); + } + pdb_reader_free(pdb, symbol_name); + if (!do_continue) return MR_SUCCESS; + } + walker.offset += cv_symbol.generic.len; + } + return MR_FAILURE; +} + +static void pdb_module_remove(struct module_format* modfmt) +{ + pdb_reader_dispose(&modfmt->u.pdb_info->pdb_reader); + HeapFree(GetProcessHeap(), 0, modfmt); +} + +static struct module_format_vtable pdb_module_format_vtable = +{ + pdb_module_remove, + pdb_method_request_symref_t, + pdb_method_lookup_symbol_by_address, + pdb_method_lookup_symbol_by_name, + pdb_method_enumerate_symbols, + pdb_method_find_type, + pdb_method_enumerate_types, + pdb_method_location_compute, + pdb_method_get_line_from_address, + pdb_method_advance_line_info, + pdb_method_enumerate_lines, + pdb_method_get_line_from_inlined_address, + pdb_method_enumerate_sources, +}; + +BOOL pdb_init_modfmt(const struct process *pcs, + const struct msc_debug_info *msc_dbg, + const WCHAR *filename, BOOL *has_linenumber_info) +{ + struct module_format *modfmt; + struct pdb_module_info *pdb_module_info; + IMAGE_SECTION_HEADER *new_sections; + HANDLE file; + + if (!(modfmt = HeapAlloc(GetProcessHeap(), 0, + sizeof(struct module_format) + sizeof(struct pdb_module_info) + msc_dbg->nsect * sizeof(msc_dbg->sectp[0])))) + return FALSE; + + if ((file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) + { + HeapFree(GetProcessHeap(), 0, modfmt); + return FALSE; + } + + pdb_module_info = (void*)(modfmt + 1); + msc_dbg->module->format_info[DFI_PDB] = modfmt; + modfmt->module = msc_dbg->module; + modfmt->vtable = &pdb_module_format_vtable; + modfmt->u.pdb_info = pdb_module_info; + + new_sections = (void*)(pdb_module_info + 1); + memcpy(new_sections, msc_dbg->sectp, msc_dbg->nsect * sizeof(*new_sections)); + if (pdb_reader_init(&pdb_module_info->pdb_reader, msc_dbg->module, file, new_sections, msc_dbg->nsect) == R_PDB_SUCCESS) + { + /* FIXME */ + *has_linenumber_info = TRUE; + return TRUE; + } + msc_dbg->module->format_info[DFI_PDB] = NULL; + HeapFree(GetProcessHeap(), 0, modfmt); + CloseHandle(file); + return FALSE; +} + +/*======================================================================== + * FPO unwinding code + */ + +/* Stack unwinding is based on postfixed operations. + * Let's define our Postfix EValuator + */ +#define PEV_MAX_LEN 32 +struct pevaluator +{ + struct cpu_stack_walk* csw; + struct pool pool; + struct vector stack; + unsigned stk_index; + struct hash_table values; + char error[64]; +}; + +struct zvalue +{ + DWORD_PTR value; + struct hash_table_elt elt; +}; + +static void pev_set_error(struct pevaluator* pev, const char* msg, ...) __WINE_PRINTF_ATTR(2,3); +static void pev_set_error(struct pevaluator* pev, const char* msg, ...) +{ + va_list args; + + va_start(args, msg); + vsnprintf(pev->error, sizeof(pev->error), msg, args); + va_end(args); +} + +#if 0 +static void pev_dump_stack(struct pevaluator* pev) +{ + unsigned i; + struct hash_table_iter hti; + + FIXME("stack #%d\n", pev->stk_index); + for (i = 0; i < pev->stk_index; i++) + { + FIXME("\t%d) %s\n", i, *(char**)vector_at(&pev->stack, i)); + } + hash_table_iter_init(&pev->values, &hti, str); + FIXME("hash\n"); + while ((ptr = hash_table_iter_up(&hti))) + { + struct zvalue* zval = CONTAINING_RECORD(ptr, struct zvalue, elt); + FIXME("\t%s: Ix\n", zval->elt.name, zval->value); + } + +} +#endif + +/* get the value out of an operand (variable or literal) */ +static BOOL pev_get_val(struct pevaluator* pev, const char* str, DWORD_PTR* val) +{ + char* n; + struct hash_table_iter hti; + void* ptr; + + switch (str[0]) + { + case '$': + case '.': + hash_table_iter_init(&pev->values, &hti, str); + while ((ptr = hash_table_iter_up(&hti))) + { + if (!strcmp(CONTAINING_RECORD(ptr, struct zvalue, elt)->elt.name, str)) + { + *val = CONTAINING_RECORD(ptr, struct zvalue, elt)->value; + return TRUE; + } + } + pev_set_error(pev, "get_zvalue: no value found (%s)", str); + return FALSE; + default: + *val = strtol(str, &n, 10); + if (n != str && *n == '\0') return TRUE; + pev_set_error(pev, "get_val: not a literal (%s)", str); + return FALSE; + } +} + +/* push an operand onto the stack */ +static BOOL pev_push(struct pevaluator* pev, const char* elt) +{ + char** at; + if (pev->stk_index < vector_length(&pev->stack)) + at = vector_at(&pev->stack, pev->stk_index); + else + at = vector_add(&pev->stack, &pev->pool); + if (!at) + { + pev_set_error(pev, "push: out of memory"); + return FALSE; + } + *at = pool_strdup(&pev->pool, elt); + pev->stk_index++; + return TRUE; +} + +/* pop an operand from the stack */ +static BOOL pev_pop(struct pevaluator* pev, char* elt) +{ + char** at = vector_at(&pev->stack, --pev->stk_index); + if (!at) + { + pev_set_error(pev, "pop: stack empty"); + return FALSE; + } + strcpy(elt, *at); + return TRUE; +} + +/* pop an operand from the stack, and gets its value */ +static BOOL pev_pop_val(struct pevaluator* pev, DWORD_PTR* val) +{ + char p[PEV_MAX_LEN]; + + return pev_pop(pev, p) && pev_get_val(pev, p, val); +} + +/* set var 'name' a new value (creates the var if it doesn't exist) */ +static BOOL pev_set_value(struct pevaluator* pev, const char* name, DWORD_PTR val) +{ + struct hash_table_iter hti; + void* ptr; + + hash_table_iter_init(&pev->values, &hti, name); + while ((ptr = hash_table_iter_up(&hti))) + { + if (!strcmp(CONTAINING_RECORD(ptr, struct zvalue, elt)->elt.name, name)) + { + CONTAINING_RECORD(ptr, struct zvalue, elt)->value = val; + break; + } + } + if (!ptr) + { + struct zvalue* zv = pool_alloc(&pev->pool, sizeof(*zv)); + if (!zv) + { + pev_set_error(pev, "set_value: out of memory"); + return FALSE; + } + zv->value = val; + + zv->elt.name = pool_strdup(&pev->pool, name); + hash_table_add(&pev->values, &zv->elt); + } + return TRUE; +} + +/* execute a binary operand from the two top most values on the stack. + * puts result on top of the stack */ +static BOOL pev_binop(struct pevaluator* pev, char op) +{ + char res[PEV_MAX_LEN]; + DWORD_PTR v1, v2, c; + + if (!pev_pop_val(pev, &v2) || !pev_pop_val(pev, &v1)) return FALSE; + if ((op == '/' || op == '%') && v2 == 0) + { + pev_set_error(pev, "binop: division by zero"); + return FALSE; + } + switch (op) + { + case '+': c = v1 + v2; break; + case '-': c = v1 - v2; break; + case '*': c = v1 * v2; break; + case '/': c = v1 / v2; break; + case '%': c = v1 % v2; break; + default: + pev_set_error(pev, "binop: unknown op (%c)", op); + return FALSE; + } + snprintf(res, sizeof(res), "%Id", c); + pev_push(pev, res); + return TRUE; +} + +/* pops top most operand, dereference it, on pushes the result on top of the stack */ +static BOOL pev_deref(struct pevaluator* pev) +{ + char res[PEV_MAX_LEN]; + DWORD_PTR v1, v2 = 0; + + if (!pev_pop_val(pev, &v1)) return FALSE; + if (!sw_read_mem(pev->csw, v1, &v2, pev->csw->cpu->word_size)) + { + pev_set_error(pev, "deref: cannot read mem at %Ix", v1); + return FALSE; + } + snprintf(res, sizeof(res), "%Id", v2); + pev_push(pev, res); + return TRUE; +} + +/* assign value to variable (from two top most operands) */ +static BOOL pev_assign(struct pevaluator* pev) +{ + char p2[PEV_MAX_LEN]; + DWORD_PTR v1; + + if (!pev_pop_val(pev, &v1) || !pev_pop(pev, p2)) return FALSE; + if (p2[0] != '$') + { + pev_set_error(pev, "assign: %s isn't a variable", p2); + return FALSE; + } + pev_set_value(pev, p2, v1); + + return TRUE; +} + +/* initializes the postfix evaluator */ +static void pev_init(struct pevaluator* pev, struct cpu_stack_walk* csw) +{ + pev->csw = csw; + pool_init(&pev->pool, 512); + vector_init(&pev->stack, sizeof(char*), 0); + pev->stk_index = 0; + hash_table_init(&pev->pool, &pev->values, 8); + pev->error[0] = '\0'; +} + +static void pev_push_context(struct pevaluator *pev, const WOW64_CONTEXT *context) +{ + pev_set_value(pev, "$ebp", context->Ebp); + pev_set_value(pev, "$esp", context->Esp); + pev_set_value(pev, "$eip", context->Eip); +} + +static void pev_pop_context(struct pevaluator *pev, WOW64_CONTEXT *context) +{ + DWORD_PTR val; + + if (pev_get_val(pev, "$ebp", &val)) context->Ebp = val; + if (pev_get_val(pev, "$esp", &val)) context->Esp = val; + if (pev_get_val(pev, "$eip", &val)) context->Eip = val; +} + +static void pev_push_fpodata(struct pevaluator *pev, const PDB_FPO_DATA* fpoext) +{ + + pev_set_value(pev, ".raSearchStart", fpoext->start); + pev_set_value(pev, ".cbLocals", fpoext->locals_size); + pev_set_value(pev, ".cbParams", fpoext->params_size); + pev_set_value(pev, ".cbSavedRegs", fpoext->savedregs_size); +} + +static BOOL pev_free(struct pevaluator* pev) +{ + pool_destroy(&pev->pool); + return TRUE; +} + +BOOL pdb_fpo_unwind_parse_cmd_string(struct cpu_stack_walk* csw, PDB_FPO_DATA* fpoext, + const char* cmd, WOW64_CONTEXT *context) +{ + char token[PEV_MAX_LEN]; + char* ptok = token; + const char* ptr; + BOOL over = FALSE; + struct pevaluator pev; + + if (!cmd) return FALSE; + pev_init(&pev, csw); + pev_push_context(&pev, context); + pev_push_fpodata(&pev, fpoext); + for (ptr = cmd; !over; ptr++) + { + if (*ptr == ' ' || (over = *ptr == '\0')) + { + *ptok = '\0'; + + if (!strcmp(token, "+") || !strcmp(token, "-") || !strcmp(token, "*") || + !strcmp(token, "/") || !strcmp(token, "%")) + { + if (!pev_binop(&pev, token[0])) goto done; + } + else if (!strcmp(token, "^")) + { + if (!pev_deref(&pev)) goto done; + } + else if (!strcmp(token, "=")) + { + if (!pev_assign(&pev)) goto done; + } + else + { + if (!pev_push(&pev, token)) goto done; + } + ptok = token; + } + else + { + if (ptok - token >= PEV_MAX_LEN - 1) + { + pev_set_error(&pev, "parse: token too long (%s)", ptr - (ptok - token)); + goto done; + } + *ptok++ = *ptr; + } + } + pev_pop_context(&pev, context); + pev_free(&pev); + return TRUE; +done: + FIXME("Couldn't evaluate %s => %s\n", debugstr_a(cmd), pev.error); + pev_free(&pev); + return FALSE; +} + +BOOL pdb_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, union ctx *context) +{ + struct pdb_reader *pdb; + struct pdb_reader_walker walker; + struct module_pair pair; + unsigned fpoext_stream; + PDB_FPO_DATA fpoext; + BOOL ret = FALSE; + + if (!module_init_pair(&pair, csw->hProcess, ip)) return FALSE; + if (!pair.effective->format_info[DFI_PDB]) return FALSE; + pdb = pdb_get_current_reader(pair.effective->format_info[DFI_PDB]); + + TRACE("searching %Ix => %Ix\n", ip, ip - (DWORD_PTR)pair.effective->module.BaseOfImage); + ip -= (DWORD_PTR)pair.effective->module.BaseOfImage; + + fpoext_stream = pdb->dbi_substreams[PDB_SIDX_FPOEXT]; + if (!pdb_reader_walker_init(pdb, fpoext_stream, &walker) && + (walker.last % sizeof(fpoext)) == 0) + { + /* FIXME likely a binary search should be more appropriate here */ + while (pdb_reader_READ(pdb, &walker, &fpoext) == R_PDB_SUCCESS) + { + if (fpoext.start <= ip && ip < fpoext.start + fpoext.func_size) + { + char *cmd; + + if (pdb_reader_alloc_and_fetch_global_string(pdb, fpoext.str_offset, &cmd)) break; + TRACE("\t%08x %08x %8x %8x %4x %4x %4x %08x %s\n", + fpoext.start, fpoext.func_size, fpoext.locals_size, + fpoext.params_size, fpoext.maxstack_size, fpoext.prolog_size, + fpoext.savedregs_size, fpoext.flags, + debugstr_a(cmd)); + + ret = pdb_fpo_unwind_parse_cmd_string(csw, &fpoext, cmd, &context->x86); + pdb_reader_free(pdb, cmd); + break; + } + } + } + + return ret; +} diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index bd3d6000535b..6b5a9a4b425f 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -387,7 +387,7 @@ BOOL pe_unlock_region(struct module *module, const BYTE* region) return TRUE; } -static void pe_module_remove(struct process* pcs, struct module_format* modfmt) +static void pe_module_remove(struct module_format* modfmt) { image_unmap_file(&modfmt->u.pe_info->fmap); HeapFree(GetProcessHeap(), 0, modfmt); @@ -503,7 +503,7 @@ static BOOL pe_load_coff_symbol_table(struct module* module) if (name[0] == '_') name++; if (!compiland && lastfilename) - compiland = symt_new_compiland(module, source_new(module, NULL, lastfilename)); + compiland = symt_new_compiland(module, lastfilename); if (!(dbghelp_options & SYMOPT_NO_PUBLICS)) symt_new_public(module, compiland, name, FALSE, @@ -802,6 +802,12 @@ static BOOL search_builtin_pe(void *param, HANDLE handle, const WCHAR *path) return TRUE; } +static const struct module_format_vtable pe_module_format_vtable = +{ + pe_module_remove, + NULL, +}; + /****************************************************************** * pe_load_native_module * @@ -877,8 +883,7 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, { module->real_path = real_path ? pool_wcsdup(&module->pool, real_path) : NULL; modfmt->module = module; - modfmt->remove = pe_module_remove; - modfmt->loc_compute = NULL; + modfmt->vtable = &pe_module_format_vtable; module->format_info[DFI_PE] = modfmt; module->reloc_delta = base - PE_FROM_OPTHDR(&modfmt->u.pe_info->fmap, ImageBase); } diff --git a/dlls/dbghelp/source.c b/dlls/dbghelp/source.c index f2dc84d47695..79b4ff9989c2 100644 --- a/dlls/dbghelp/source.c +++ b/dlls/dbghelp/source.c @@ -56,6 +56,21 @@ static unsigned source_find(const char* name) return WINE_RB_ENTRY_VALUE(e, struct source_rb, entry)->source; } +char *source_build_path(const char *base, const char *name) +{ + char *dst; + unsigned bsz = strlen(base); + + dst = HeapAlloc(GetProcessHeap(), 0, bsz + 1 + strlen(name) + 1); + if (dst) + { + strcpy(dst, base); + if (bsz && dst[bsz - 1] != '/' && dst[bsz - 1] != '\\') dst[bsz++] = '/'; + strcpy(&dst[bsz], name); + } + return dst; +} + /****************************************************************** * source_new * @@ -71,16 +86,7 @@ unsigned source_new(struct module* module, const char* base, const char* name) if (!base || *name == '/') full = name; else - { - unsigned bsz = strlen(base); - - tmp = HeapAlloc(GetProcessHeap(), 0, bsz + 1 + strlen(name) + 1); - if (!tmp) return ret; - full = tmp; - strcpy(tmp, base); - if (bsz && tmp[bsz - 1] != '/') tmp[bsz++] = '/'; - strcpy(&tmp[bsz], name); - } + full = source_build_path(base, name); rb_module = module; if (!module->sources || (ret = source_find(full)) == (unsigned)-1) { @@ -145,11 +151,12 @@ BOOL WINAPI SymEnumSourceFilesW(HANDLE hProcess, ULONG64 ModBase, PCWSTR Mask, char* ptr; WCHAR* conversion_buffer = NULL; DWORD conversion_buffer_len = 0; + struct module_format_vtable_iterator iter = {}; if (!cbSrcFiles) return FALSE; pair.pcs = process_find_by_handle(hProcess); if (!pair.pcs) return FALSE; - + if (ModBase) { pair.requested = module_find_by_addr(pair.pcs, ModBase); @@ -157,10 +164,18 @@ BOOL WINAPI SymEnumSourceFilesW(HANDLE hProcess, ULONG64 ModBase, PCWSTR Mask, } else { - if (Mask[0] == '!') + WCHAR *bang = wcschr(Mask, '!'); + if (bang) { - pair.requested = module_find_by_nameW(pair.pcs, Mask + 1); + WCHAR *module_name; + + if (!(module_name = HeapAlloc(GetProcessHeap(), 0, (bang - Mask + 1) * sizeof(WCHAR)))) return FALSE; + memcpy(module_name, Mask, (bang - Mask) * sizeof(WCHAR)); + module_name[bang - Mask] = L'\0'; + pair.requested = module_find_by_nameW(pair.pcs, module_name); + HeapFree(GetProcessHeap(), 0, module_name); if (!module_get_debug(&pair)) return FALSE; + Mask = bang + 1; } else { @@ -168,6 +183,23 @@ BOOL WINAPI SymEnumSourceFilesW(HANDLE hProcess, ULONG64 ModBase, PCWSTR Mask, return FALSE; } } + + while ((module_format_vtable_iterator_next(pair.effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(enumerate_sources)))) + { + enum method_result result = iter.modfmt->vtable->enumerate_sources(iter.modfmt, NULL, cbSrcFiles, UserContext); + switch (result) + { + case MR_SUCCESS: + return TRUE; + case MR_NOT_FOUND: /* continue */ + break; + default: + /* SetLastError(...); */ + return FALSE; + } + } + if (!pair.effective->sources) return FALSE; for (ptr = pair.effective->sources; *ptr; ptr += strlen(ptr) + 1) { @@ -183,10 +215,12 @@ BOOL WINAPI SymEnumSourceFilesW(HANDLE hProcess, ULONG64 ModBase, PCWSTR Mask, MultiByteToWideChar(CP_ACP, 0, ptr, -1, conversion_buffer, len); - /* FIXME: not using Mask */ - sf.ModBase = ModBase; - sf.FileName = conversion_buffer; - if (!cbSrcFiles(&sf, UserContext)) break; + if (!Mask || !*Mask || SymMatchStringW(conversion_buffer, Mask, FALSE)) + { + sf.ModBase = pair.requested->module.BaseOfImage; + sf.FileName = conversion_buffer; + if (!cbSrcFiles(&sf, UserContext)) break; + } } HeapFree(GetProcessHeap(), 0, conversion_buffer); diff --git a/dlls/dbghelp/stabs.c b/dlls/dbghelp/stabs.c index 2f3ee9fff4ed..8aa9907449ce 100644 --- a/dlls/dbghelp/stabs.c +++ b/dlls/dbghelp/stabs.c @@ -618,7 +618,8 @@ static inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd, strcpy(tmp, "__inherited_class_"); strcat(tmp, symt_get_name(adt)); - symt_add_udt_element(ptd->module, sdt, tmp, adt, ofs, 0, 0); + symt_add_udt_element(ptd->module, sdt, tmp, symt_ptr_to_symref(adt), + ofs, 0, 0); } PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); } @@ -692,7 +693,8 @@ static inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd, PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &sz) == -1); PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); - if (doadd) symt_add_udt_element(ptd->module, sdt, ptd->buf + idx, adt, ofs, 0, 0); + if (doadd) symt_add_udt_element(ptd->module, sdt, ptd->buf + idx, symt_ptr_to_symref(adt), + ofs, 0, 0); break; case ':': { @@ -718,9 +720,10 @@ static inline int stabs_pts_read_aggregate(struct ParseTypedefData* ptd, return 0; } -static inline int stabs_pts_read_enum(struct ParseTypedefData* ptd, +static inline int stabs_pts_read_enum(struct ParseTypedefData* ptd, struct symt_enum* edt) { + VARIANT v; LONG_PTR value; int idx; @@ -730,7 +733,9 @@ static inline int stabs_pts_read_enum(struct ParseTypedefData* ptd, PTS_ABORTIF(ptd, stabs_pts_read_id(ptd) == -1); PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &value) == -1); PTS_ABORTIF(ptd, *ptd->ptr++ != ','); - symt_add_enum_element(ptd->module, edt, ptd->buf + idx, value); + V_VT(&v) = VT_I4; + V_I4(&v) = value; + symt_add_enum_element(ptd->module, edt, ptd->buf + idx, &v); ptd->idx = idx; } ptd->ptr++; @@ -1168,7 +1173,7 @@ static void pending_flush(struct pending_list* pending, struct module* module, case PENDING_VAR: symt_add_func_local(module, func, pending->objs[i].u.var.kind, &pending->objs[i].u.var.loc, - block, pending->objs[i].u.var.type, pending->objs[i].u.var.name); + block, symt_ptr_to_symref(pending->objs[i].u.var.type), pending->objs[i].u.var.name); break; case PENDING_LINE: if (module->type == DMT_MACHO) @@ -1360,7 +1365,7 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, loc.reg = 0; loc.offset = load_offset + n_value; symt_new_global_variable(module, compiland, symname, TRUE /* FIXME */, - loc, 0, stabs_parse_type(ptr)); + loc, 0, symt_ptr_to_symref(stabs_parse_type(ptr))); break; case N_LCSYM: case N_STSYM: @@ -1375,7 +1380,7 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, loc.reg = 0; loc.offset = load_offset + n_value; symt_new_global_variable(module, compiland, symname, TRUE /* FIXME */, - loc, 0, stabs_parse_type(ptr)); + loc, 0, symt_ptr_to_symref(stabs_parse_type(ptr))); break; case N_LBRAC: if (curr_func) @@ -1409,9 +1414,9 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, loc.offset = n_value; symt_add_func_local(module, curr_func, (int)n_value >= 0 ? DataIsParam : DataIsLocal, - &loc, NULL, param_type, symname); - symt_add_function_signature_parameter(module, - (struct symt_function_signature*)curr_func->type, + &loc, NULL, symt_ptr_to_symref(param_type), symname); + symt_add_function_signature_parameter(module, + (struct symt_function_signature*)curr_func->type, param_type); } break; @@ -1473,9 +1478,9 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, struct symt* param_type = stabs_parse_type(ptr); stab_strcpy(symname, sizeof(symname), ptr); symt_add_func_local(module, curr_func, DataIsParam, &loc, - NULL, param_type, symname); - symt_add_function_signature_parameter(module, - (struct symt_function_signature*)curr_func->type, + NULL, symt_ptr_to_symref(param_type), symname); + symt_add_function_signature_parameter(module, + (struct symt_function_signature*)curr_func->type, param_type); } else @@ -1490,21 +1495,24 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, if (curr_func != NULL) pending_add_var(&pending_block, ptr, DataIsLocal, &loc); break; case N_SLINE: - /* - * This is a line number. These are always relative to the start - * of the function (N_FUN), and this makes the lookup easier. - */ - assert(source_idx >= 0); - if (curr_func != NULL) + if (SymGetOptions() & SYMOPT_LOAD_LINES) { - ULONG_PTR offset = n_value; - if (module->type == DMT_MACHO) - offset -= curr_func->ranges[0].low - load_offset; - symt_add_func_line(module, curr_func, source_idx, - stab_ptr->n_desc, curr_func->ranges[0].low + offset); + /* + * This is a line number. These are always relative to the start + * of the function (N_FUN), and this makes the lookup easier. + */ + assert(source_idx >= 0); + if (curr_func != NULL) + { + ULONG_PTR offset = n_value; + if (module->type == DMT_MACHO) + offset -= curr_func->ranges[0].low - load_offset; + symt_add_func_line(module, curr_func, source_idx, + stab_ptr->n_desc, curr_func->ranges[0].low + offset); + } + else pending_add_line(&pending_func, source_idx, stab_ptr->n_desc, + n_value, load_offset); } - else pending_add_line(&pending_func, source_idx, stab_ptr->n_desc, - n_value, load_offset); break; case N_FUN: /* @@ -1539,11 +1547,11 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, n_value ? (load_offset + n_value - curr_func->ranges[0].low) : 0); } - func_type = symt_new_function_signature(module, + func_type = symt_new_function_signature(module, stabs_parse_type(ptr), -1); - curr_func = symt_new_function(module, compiland, symname, + curr_func = symt_new_function(module, compiland, symname, load_offset + n_value, 0, - &func_type->symt); + symt_ptr_to_symref(&func_type->symt), 0); pending_flush(&pending_func, module, curr_func, NULL); } else @@ -1579,7 +1587,7 @@ BOOL stabs_parse(struct module* module, ULONG_PTR load_offset, { stabs_reset_includes(); source_idx = source_new(module, srcpath, ptr); - compiland = symt_new_compiland(module, source_idx); + compiland = symt_new_compiland(module, source_get(module, source_idx)); } else { diff --git a/dlls/dbghelp/stack.c b/dlls/dbghelp/stack.c index 8b573feee77a..a0fc03206685 100644 --- a/dlls/dbghelp/stack.c +++ b/dlls/dbghelp/stack.c @@ -60,6 +60,7 @@ static DWORD64 WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS64* return 0; } +#ifndef _WIN64 static BOOL CALLBACK read_mem(HANDLE hProcess, DWORD addr, void* buffer, DWORD size, LPDWORD nread) { @@ -68,6 +69,7 @@ static BOOL CALLBACK read_mem(HANDLE hProcess, DWORD addr, void* buffer, if (nread) *nread = r; return TRUE; } +#endif static BOOL CALLBACK read_mem64(HANDLE hProcess, DWORD64 addr, void* buffer, DWORD size, LPDWORD nread) @@ -78,12 +80,14 @@ static BOOL CALLBACK read_mem64(HANDLE hProcess, DWORD64 addr, void* buffer, return TRUE; } +#ifndef _WIN64 static inline void addr_32to64(const ADDRESS* addr32, ADDRESS64* addr64) { addr64->Offset = (ULONG64)addr32->Offset; addr64->Segment = addr32->Segment; addr64->Mode = addr32->Mode; } +#endif static inline void addr_64to32(const ADDRESS64* addr64, ADDRESS* addr32) { @@ -132,6 +136,7 @@ DWORD64 sw_module_base(struct cpu_stack_walk* csw, DWORD64 addr) return csw->u.s64.f_modl_bas(csw->hProcess, addr); } +#ifndef _WIN64 /*********************************************************************** * StackWalk (DBGHELP.@) */ @@ -202,6 +207,7 @@ BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread, return ret; } +#endif /*********************************************************************** @@ -340,6 +346,7 @@ BOOL WINAPI StackWalkEx(DWORD MachineType, HANDLE hProcess, HANDLE hThread, return TRUE; } +#ifndef _WIN64 /****************************************************************** * SymRegisterFunctionEntryCallback (DBGHELP.@) * @@ -352,6 +359,7 @@ BOOL WINAPI SymRegisterFunctionEntryCallback(HANDLE hProc, SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } +#endif /****************************************************************** * SymRegisterFunctionEntryCallback64 (DBGHELP.@) diff --git a/dlls/dbghelp/storage.c b/dlls/dbghelp/storage.c index f7c08adab8a9..d3fea4759013 100644 --- a/dlls/dbghelp/storage.c +++ b/dlls/dbghelp/storage.c @@ -48,6 +48,11 @@ void* pool_realloc(struct pool* pool, void* ptr, size_t len) return ptr ? HeapReAlloc(pool->heap, 0, ptr, len) : pool_alloc(pool, len); } +void pool_free(struct pool* pool, void* ptr) +{ + HeapFree(pool->heap, 0, ptr); +} + char* pool_strdup(struct pool* pool, const char* str) { char* ret; @@ -65,10 +70,11 @@ WCHAR* pool_wcsdup(struct pool* pool, const WCHAR* str) void vector_init(struct vector* v, unsigned esz, unsigned bucket_sz) { v->buckets = NULL; - /* align size on DWORD boundaries */ - v->elt_size = (esz + 3) & ~3; + /* align size */ + v->elt_size = (esz + sizeof(void*) - 1) & ~(sizeof(void*) - 1); switch (bucket_sz) { + case 0: v->shift = 0; break; /* special case see below */ case 2: v->shift = 1; break; case 4: v->shift = 2; break; case 8: v->shift = 3; break; @@ -93,15 +99,44 @@ unsigned vector_length(const struct vector* v) void* vector_at(const struct vector* v, unsigned pos) { - unsigned o; - if (pos >= v->num_elts) return NULL; - o = pos & ((1 << v->shift) - 1); - return (char*)v->buckets[pos >> v->shift] + o * v->elt_size; + if (v->shift) + { + unsigned o = pos & ((1 << v->shift) - 1); + return (char*)v->buckets[pos >> v->shift] + o * v->elt_size; + } + else + { + return (char*)v->buckets + pos * v->elt_size; + } } void* vector_add(struct vector* v, struct pool* pool) { + if (!v->shift) + { + if (v->num_elts == 1024) + { + /* we'll need a second bucket, so go directly for it */ + void **new = pool_alloc(pool, 2 * sizeof(void*)); + if (!new) return NULL; + *new = v->buckets; + v->buckets = new; + v->num_buckets = 1; + v->buckets_allocated = 2; + v->shift = 10; + } + else + { + if (!v->num_elts || !(v->num_elts & (v->num_elts - 1))) + { + void *new = pool_realloc(pool, v->buckets, (v->num_elts ? v->num_elts * 2 : 1) * v->elt_size); + if (!new) return NULL; + v->buckets = new; + } + return vector_at(v, v->num_elts++); + } + } if (v->num_elts == (v->num_buckets << v->shift)) { if (v->num_buckets == v->buckets_allocated) diff --git a/dlls/dbghelp/symbol.c b/dlls/dbghelp/symbol.c index 38382b006d73..29a32ad7dcf3 100644 --- a/dlls/dbghelp/symbol.c +++ b/dlls/dbghelp/symbol.c @@ -70,15 +70,15 @@ int __cdecl symt_cmp_addr(const void* p1, const void* p2) * which is exposed to the caller and index is the index of the symbol in * this array */ -DWORD symt_ptr2index(struct module* module, const struct symt* sym) +DWORD symt_symref_to_index(struct module* module, symref_t symref) { struct vector* vector; DWORD offset; - const struct symt** c; + symref_t *c; int len, i; - if (!sym) return 0; - if (sym->tag == SymTagCustom) + if (!symref) return 0; + if (symt_is_symref_ptr(symref) && ((struct symt*)symref)->tag == SymTagCustom) { vector = &module->vcustom_symt; offset = BASE_CUSTOM_SYMT; @@ -89,23 +89,23 @@ DWORD symt_ptr2index(struct module* module, const struct symt* sym) vector = &module->vsymt; offset = 1; #else - return (DWORD)sym; + return (DWORD)symref; #endif } len = vector_length(vector); /* FIXME: this is inefficient */ for (i = 0; i < len; i++) { - if (*(struct symt**)vector_at(vector, i) == sym) + if (*(symref_t*)vector_at(vector, i) == symref) return i + offset; } /* not found */ c = vector_add(vector, &module->pool); - if (c) *c = sym; + if (c) *c = symref; return len + offset; } -struct symt* symt_index2ptr(struct module* module, DWORD id) +symref_t symt_index_to_symref(struct module* module, DWORD id) { struct vector* vector; if (id >= BASE_CUSTOM_SYMT) @@ -116,13 +116,13 @@ struct symt* symt_index2ptr(struct module* module, DWORD id) else { #ifdef _WIN64 - if (!id--) return NULL; + if (!id--) return 0; vector = &module->vsymt; #else - return (struct symt*)id; + return (symref_t)id; #endif } - return (id >= vector_length(vector)) ? NULL : *(struct symt**)vector_at(vector, id); + return (id >= vector_length(vector)) ? 0 : *(symref_t *)vector_at(vector, id); } static BOOL symt_grow_sorttab(struct module* module, unsigned sz) @@ -226,28 +226,28 @@ struct symt_module* symt_new_module(struct module* module) { sym->symt.tag = SymTagExe; sym->module = module; - vector_init(&sym->vchildren, sizeof(struct symt*), 8); + vector_init(&sym->vchildren, sizeof(symref_t), 0); } return sym; } -struct symt_compiland* symt_new_compiland(struct module* module, unsigned src_idx) +struct symt_compiland* symt_new_compiland(struct module* module, const char *filename) { struct symt_compiland* sym; - struct symt_compiland** p; + symref_t* p; TRACE_(dbghelp_symt)("Adding compiland symbol %s:%s\n", - debugstr_w(module->modulename), debugstr_a(source_get(module, src_idx))); + debugstr_w(module->modulename), debugstr_a(filename)); if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { sym->symt.tag = SymTagCompiland; - sym->container = module->top; + sym->container = symt_ptr_to_symref(&module->top->symt); sym->address = 0; - sym->source = src_idx; - vector_init(&sym->vchildren, sizeof(struct symt*), 32); + sym->filename = pool_strdup(&module->pool, filename); + vector_init(&sym->vchildren, sizeof(symref_t), 0); sym->user = NULL; p = vector_add(&module->top->vchildren, &module->pool); - *p = sym; + if (p) *p = symt_ptr_to_symref(&sym->symt); } return sym; } @@ -259,7 +259,7 @@ struct symt_public* symt_new_public(struct module* module, ULONG_PTR address, unsigned size) { struct symt_public* sym; - struct symt** p; + symref_t* p; TRACE_(dbghelp_symt)("Adding public symbol %s:%s @%Ix\n", debugstr_w(module->modulename), debugstr_a(name), address); @@ -270,7 +270,7 @@ struct symt_public* symt_new_public(struct module* module, { sym->symt.tag = SymTagPublicSymbol; sym->hash_elt.name = pool_strdup(&module->pool, name); - sym->container = compiland ? &compiland->symt : NULL; + sym->container = compiland ? symt_ptr_to_symref(&compiland->symt) : 0; sym->is_function = is_function; sym->address = address; sym->size = size; @@ -278,7 +278,7 @@ struct symt_public* symt_new_public(struct module* module, if (compiland) { p = vector_add(&compiland->vchildren, &module->pool); - *p = &sym->symt; + if (p) *p = symt_ptr_to_symref(&sym->symt); } } return sym; @@ -288,23 +288,23 @@ struct symt_data* symt_new_global_variable(struct module* module, struct symt_compiland* compiland, const char* name, unsigned is_static, struct location loc, ULONG_PTR size, - struct symt* type) + symref_t type) { struct symt_data* sym; - struct symt** p; + symref_t* p; DWORD64 tsz; - TRACE_(dbghelp_symt)("Adding global symbol %s:%s %d@%Ix %p\n", + TRACE_(dbghelp_symt)("Adding global symbol %s:%s %d@%Ix %Ix\n", debugstr_w(module->modulename), debugstr_a(name), loc.kind, loc.offset, type); if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { sym->symt.tag = SymTagData; sym->hash_elt.name = pool_strdup(&module->pool, name); sym->kind = is_static ? DataIsFileStatic : DataIsGlobal; - sym->container = compiland ? &compiland->symt : &module->top->symt; + sym->container = symt_ptr_to_symref(compiland ? &compiland->symt : &module->top->symt); sym->type = type; sym->u.var = loc; - if (type && size && symt_get_info(module, type, TI_GET_LENGTH, &tsz)) + if (type && size && symt_get_info_from_symref(module, type, TI_GET_LENGTH, &tsz)) { if (tsz != size) FIXME("Size mismatch for %s.%s between type (%I64u) and src (%Iu)\n", @@ -312,7 +312,7 @@ struct symt_data* symt_new_global_variable(struct module* module, } symt_add_module_ht(module, (struct symt_ht*)sym); p = vector_add(compiland ? &compiland->vchildren : &module->top->vchildren, &module->pool); - *p = &sym->symt; + if (p) *p = symt_ptr_to_symref(&sym->symt); } return sym; } @@ -321,20 +321,21 @@ static struct symt_function* init_function_or_inlinesite(struct module* module, DWORD tag, struct symt* container, const char* name, - struct symt* sig_type, + symref_t sig_type, + DWORD_PTR user, unsigned num_ranges) { struct symt_function* sym; - assert(!sig_type || sig_type->tag == SymTagFunctionType); if ((sym = pool_alloc(&module->pool, offsetof(struct symt_function, ranges[num_ranges])))) { - sym->symt.tag = tag; + sym->symt.tag = tag; sym->hash_elt.name = pool_strdup(&module->pool, name); - sym->container = container; - sym->type = sig_type; - vector_init(&sym->vlines, sizeof(struct line_info), tag == SymTagFunction ? 8 : 4); - vector_init(&sym->vchildren, sizeof(struct symt*), 8); + sym->container = symt_ptr_to_symref(container); + sym->type = sig_type; + vector_init(&sym->vlines, sizeof(struct line_info), 0); + vector_init(&sym->vchildren, sizeof(symref_t), 0); + sym->user = user; sym->num_ranges = num_ranges; } return sym; @@ -344,15 +345,16 @@ struct symt_function* symt_new_function(struct module* module, struct symt_compiland* compiland, const char* name, ULONG_PTR addr, ULONG_PTR size, - struct symt* sig_type) + symref_t sig_type, DWORD_PTR user) { struct symt_function* sym; TRACE_(dbghelp_symt)("Adding global function %s:%s @%Ix-%Ix\n", debugstr_w(module->modulename), debugstr_a(name), addr, addr + size - 1); - if ((sym = init_function_or_inlinesite(module, SymTagFunction, &compiland->symt, name, sig_type, 1))) + + if ((sym = init_function_or_inlinesite(module, SymTagFunction, &compiland->symt, name, sig_type, user, 1))) { - struct symt** p; + symref_t* p; sym->ranges[0].low = addr; sym->ranges[0].high = addr + size; sym->next_inlinesite = NULL; /* first of list */ @@ -360,7 +362,7 @@ struct symt_function* symt_new_function(struct module* module, if (compiland) { p = vector_add(&compiland->vchildren, &module->pool); - *p = &sym->symt; + if (p) *p = symt_ptr_to_symref(&sym->symt); } } return sym; @@ -370,15 +372,16 @@ struct symt_function* symt_new_inlinesite(struct module* module, struct symt_function* func, struct symt* container, const char* name, - struct symt* sig_type, + symref_t sig_type, + DWORD_PTR user, unsigned num_ranges) { struct symt_function* sym; TRACE_(dbghelp_symt)("Adding inline site %s\n", debugstr_a(name)); - if ((sym = init_function_or_inlinesite(module, SymTagInlineSite, container, name, sig_type, num_ranges))) + if ((sym = init_function_or_inlinesite(module, SymTagInlineSite, container, name, sig_type, user, num_ranges))) { - struct symt** p; + symref_t* p; assert(container); /* chain inline sites */ @@ -391,7 +394,7 @@ struct symt_function* symt_new_inlinesite(struct module* module, assert(container->tag == SymTagBlock); p = vector_add(&((struct symt_block*)container)->vchildren, &module->pool); } - *p = &sym->symt; + if (p) *p = symt_ptr_to_symref(&sym->symt); } return sym; } @@ -429,6 +432,8 @@ void symt_add_func_line(struct module* module, struct symt_function* func, WARN("Duplicate addition of line number in %s\n", debugstr_a(func->hash_elt.name)); return; } + /* clear previous last */ + if (prev) prev->is_last = 0; if (!last_matches) { /* we shouldn't have line changes on first line of function */ @@ -439,8 +444,6 @@ void symt_add_func_line(struct module* module, struct symt_function* func, dli->line_number = 0; dli->u.source_file = source_idx; } - /* clear previous last */ - if (prev) prev->is_last = 0; dli = vector_add(&func->vlines, &module->pool); dli->is_source_file = 0; dli->is_first = 0; /* only a source file can be first */ @@ -461,17 +464,17 @@ void symt_add_func_line(struct module* module, struct symt_function* func, * Otherwise, the variable is stored on the stack: * - offset is then the offset from the frame register */ -struct symt_data* symt_add_func_local(struct module* module, - struct symt_function* func, +struct symt_data* symt_add_func_local(struct module* module, + struct symt_function* func, enum DataKind dt, const struct location* loc, - struct symt_block* block, - struct symt* type, const char* name) + struct symt_block* block, + symref_t type, const char* name) { struct symt_data* locsym; - struct symt** p; + symref_t* p; - TRACE_(dbghelp_symt)("Adding local symbol (%s:%s): %s %p\n", + TRACE_(dbghelp_symt)("Adding local symbol (%s:%s): %s %Ix\n", debugstr_w(module->modulename), debugstr_a(func->hash_elt.name), debugstr_a(name), type); @@ -483,14 +486,14 @@ struct symt_data* symt_add_func_local(struct module* module, locsym->hash_elt.name = pool_strdup(&module->pool, name); locsym->hash_elt.next = NULL; locsym->kind = dt; - locsym->container = block ? &block->symt : &func->symt; + locsym->container = symt_ptr_to_symref(block ? &block->symt : &func->symt); locsym->type = type; locsym->u.var = *loc; if (block) p = vector_add(&block->vchildren, &module->pool); else p = vector_add(&func->vchildren, &module->pool); - *p = &locsym->symt; + if (p) *p = symt_ptr_to_symref(&locsym->symt); if (dt == DataIsStaticLocal) symt_add_module_addr(module, (struct symt_ht*)locsym); return locsym; @@ -504,13 +507,13 @@ struct symt_data* symt_add_func_local(struct module* module, struct symt_data* symt_add_func_constant(struct module* module, struct symt_function* func, struct symt_block* block, - struct symt* type, const char* name, + symref_t type, const char* name, VARIANT* v) { struct symt_data* locsym; - struct symt** p; + symref_t* p; - TRACE_(dbghelp_symt)("Adding local constant (%s:%s): %s %p\n", + TRACE_(dbghelp_symt)("Adding local constant (%s:%s): %s %Ix\n", debugstr_w(module->modulename), debugstr_a(func->hash_elt.name), debugstr_a(name), type); @@ -521,14 +524,14 @@ struct symt_data* symt_add_func_constant(struct module* module, locsym->hash_elt.name = pool_strdup(&module->pool, name); locsym->hash_elt.next = NULL; locsym->kind = DataIsConstant; - locsym->container = block ? &block->symt : &func->symt; + locsym->container = symt_ptr_to_symref(block ? &block->symt : &func->symt); locsym->type = type; locsym->u.value = *v; if (block) p = vector_add(&block->vchildren, &module->pool); else p = vector_add(&func->vchildren, &module->pool); - *p = &locsym->symt; + if (p) *p = symt_ptr_to_symref(&locsym->symt); return locsym; } @@ -538,7 +541,7 @@ struct symt_block* symt_open_func_block(struct module* module, unsigned num_ranges) { struct symt_block* block; - struct symt** p; + symref_t* p; assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite)); assert(num_ranges > 0); @@ -547,13 +550,13 @@ struct symt_block* symt_open_func_block(struct module* module, block = pool_alloc(&module->pool, offsetof(struct symt_block, ranges[num_ranges])); block->symt.tag = SymTagBlock; block->num_ranges = num_ranges; - block->container = parent_block ? &parent_block->symt : &func->symt; - vector_init(&block->vchildren, sizeof(struct symt*), 4); + block->container = symt_ptr_to_symref(parent_block ? &parent_block->symt : &func->symt); + vector_init(&block->vchildren, sizeof(symref_t), 0); if (parent_block) p = vector_add(&parent_block->vchildren, &module->pool); else p = vector_add(&func->vchildren, &module->pool); - *p = &block->symt; + if (p) *p = symt_ptr_to_symref(&block->symt); return block; } @@ -562,10 +565,15 @@ struct symt_block* symt_close_func_block(struct module* module, const struct symt_function* func, struct symt_block* block) { + struct symt *container; + assert(symt_check_tag(&func->symt, SymTagFunction) || symt_check_tag(&func->symt, SymTagInlineSite)); - return (block->container->tag == SymTagBlock) ? - CONTAINING_RECORD(block->container, struct symt_block, symt) : NULL; + container = SYMT_SYMREF_TO_PTR(block->container); + assert(container); + + return (container->tag == SymTagBlock) ? + CONTAINING_RECORD(container, struct symt_block, symt) : NULL; } struct symt_hierarchy_point* symt_add_function_point(struct module* module, @@ -574,17 +582,17 @@ struct symt_hierarchy_point* symt_add_function_point(struct module* module, const struct location* loc, const char* name) { - struct symt_hierarchy_point*sym; - struct symt** p; + struct symt_hierarchy_point *sym; + symref_t *p; if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) { - sym->symt.tag = point; - sym->parent = &func->symt; - sym->loc = *loc; + sym->symt.tag = point; + sym->container = symt_ptr_to_symref(&func->symt); + sym->loc = *loc; sym->hash_elt.name = name ? pool_strdup(&module->pool, name) : NULL; p = vector_add(&func->vchildren, &module->pool); - *p = &sym->symt; + if (p) *p = symt_ptr_to_symref(&sym->symt); } return sym; } @@ -603,16 +611,16 @@ struct symt_thunk* symt_new_thunk(struct module* module, { sym->symt.tag = SymTagThunk; sym->hash_elt.name = pool_strdup(&module->pool, name); - sym->container = &compiland->symt; + sym->container = symt_ptr_to_symref(&compiland->symt); sym->address = addr; sym->size = size; sym->ordinal = ord; symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { - struct symt** p; + symref_t *p; p = vector_add(&compiland->vchildren, &module->pool); - *p = &sym->symt; + if (p) *p = symt_ptr_to_symref(&sym->symt); } } return sym; @@ -620,7 +628,7 @@ struct symt_thunk* symt_new_thunk(struct module* module, struct symt_data* symt_new_constant(struct module* module, struct symt_compiland* compiland, - const char* name, struct symt* type, + const char* name, symref_t type, const VARIANT* v) { struct symt_data* sym; @@ -633,15 +641,15 @@ struct symt_data* symt_new_constant(struct module* module, sym->symt.tag = SymTagData; sym->hash_elt.name = pool_strdup(&module->pool, name); sym->kind = DataIsConstant; - sym->container = compiland ? &compiland->symt : &module->top->symt; + sym->container = symt_ptr_to_symref(compiland ? &compiland->symt : &module->top->symt); sym->type = type; sym->u.value = *v; symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { - struct symt** p; + symref_t *p; p = vector_add(&compiland->vchildren, &module->pool); - *p = &sym->symt; + if (p) *p = symt_ptr_to_symref(&sym->symt); } } return sym; @@ -662,13 +670,13 @@ struct symt_hierarchy_point* symt_new_label(struct module* module, sym->hash_elt.name = pool_strdup(&module->pool, name); sym->loc.kind = loc_absolute; sym->loc.offset = address; - sym->parent = compiland ? &compiland->symt : NULL; + sym->container = compiland ? symt_ptr_to_symref(&compiland->symt) : 0; symt_add_module_ht(module, (struct symt_ht*)sym); if (compiland) { - struct symt** p; + symref_t *p; p = vector_add(&compiland->vchildren, &module->pool); - *p = &sym->symt; + if (p) *p = symt_ptr_to_symref(&sym->symt); } } return sym; @@ -694,7 +702,7 @@ struct symt_custom* symt_new_custom(struct module* module, const char* name, } /* expect sym_info->MaxNameLen to be set before being called */ -static void symt_fill_sym_info(struct module_pair* pair, +static BOOL symt_fill_sym_info(struct module_pair* pair, const struct symt_function* func, const struct symt* sym, SYMBOL_INFO* sym_info) { @@ -704,17 +712,18 @@ static void symt_fill_sym_info(struct module_pair* pair, if (!symt_get_info(pair->effective, sym, TI_GET_TYPE, &sym_info->TypeIndex)) sym_info->TypeIndex = 0; - sym_info->Index = symt_ptr2index(pair->effective, sym); + sym_info->Index = symt_ptr_to_index(pair->effective, sym); sym_info->Reserved[0] = sym_info->Reserved[1] = 0; if (!symt_get_info(pair->effective, sym, TI_GET_LENGTH, &size) && (!sym_info->TypeIndex || - !symt_get_info(pair->effective, symt_index2ptr(pair->effective, sym_info->TypeIndex), - TI_GET_LENGTH, &size))) + !symt_get_info_from_index(pair->effective, sym_info->TypeIndex, TI_GET_LENGTH, &size))) size = 0; sym_info->Size = (DWORD)size; sym_info->ModBase = pair->requested->module.BaseOfImage; sym_info->Flags = 0; sym_info->Value = 0; + sym_info->Address = 0; + sym_info->Register = 0; switch (sym->tag) { @@ -733,28 +742,28 @@ static void symt_fill_sym_info(struct module_pair* pair, if (loc.kind >= loc_user) { - unsigned i; - struct module_format* modfmt; + struct module_format_vtable_iterator iter = {}; - for (i = 0; i < DFI_LAST; i++) + while ((module_format_vtable_iterator_next(pair->effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(loc_compute)))) { - modfmt = pair->effective->format_info[i]; - if (modfmt && modfmt->loc_compute) - { - modfmt->loc_compute(pair->pcs, modfmt, func, &loc); - break; - } + iter.modfmt->vtable->loc_compute(iter.modfmt, func, &loc); + break; } } switch (loc.kind) { case loc_error: + if (loc.reg == loc_err_out_of_scope) + { + sym_info->Flags |= SYMFLAG_NULL; + break; + } /* for now we report error cases as a negative register number */ /* fall through */ case loc_register: sym_info->Flags |= SYMFLAG_REGISTER; sym_info->Register = loc.reg; - sym_info->Address = 0; break; case loc_regrel: sym_info->Flags |= SYMFLAG_REGREL; @@ -783,7 +792,6 @@ static void symt_fill_sym_info(struct module_pair* pair, /* fall through */ case loc_absolute: symt_get_address(sym, &sym_info->Address); - sym_info->Register = 0; break; default: FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", data->u.var.kind); @@ -792,8 +800,8 @@ static void symt_fill_sym_info(struct module_pair* pair, break; case DataIsConstant: sym_info->Flags |= SYMFLAG_VALUEPRESENT; - if (data->container && - (data->container->tag == SymTagFunction || data->container->tag == SymTagBlock)) + if (symt_check_tag(SYMT_SYMREF_TO_PTR(data->container), SymTagFunction) || + symt_check_tag(SYMT_SYMREF_TO_PTR(data->container), SymTagBlock)) sym_info->Flags |= SYMFLAG_LOCAL; switch (V_VT(&data->u.value)) { @@ -843,7 +851,6 @@ static void symt_fill_sym_info(struct module_pair* pair, break; default: symt_get_address(sym, &sym_info->Address); - sym_info->Register = 0; break; } sym_info->Scope = 0; /* FIXME */ @@ -861,6 +868,7 @@ static void symt_fill_sym_info(struct module_pair* pair, TRACE_(dbghelp_symt)("%p => %s %lu %I64x\n", sym, debugstr_a(sym_info->Name), sym_info->Size, sym_info->Address); + return TRUE; } struct sym_enum @@ -877,22 +885,55 @@ struct sym_enum static BOOL send_symbol(const struct sym_enum* se, struct module_pair* pair, const struct symt_function* func, const struct symt* sym) { - symt_fill_sym_info(pair, func, sym, se->sym_info); + if (!symt_fill_sym_info(pair, func, sym, se->sym_info)) return FALSE; if (se->index && se->sym_info->Index != se->index) return FALSE; if (se->tag && se->sym_info->Tag != se->tag) return FALSE; if (se->addr && !(se->addr >= se->sym_info->Address && se->addr < se->sym_info->Address + se->sym_info->Size)) return FALSE; return !se->cb(se->sym_info, se->sym_info->Size, se->user); } +struct symbol_enum_method +{ + struct module_pair *pair; + const struct sym_enum *se; +}; + +static BOOL symbol_enum_method_cb(symref_t symref, const char *name, void *user) +{ + struct symbol_enum_method *sem = user; + + sem->se->sym_info->SizeOfStruct = sizeof(SYMBOL_INFO); + sem->se->sym_info->MaxNameLen = sizeof(sem->se->buffer) - sizeof(SYMBOL_INFO); + + if (symt_is_symref_ptr(symref)) + { + if (send_symbol(sem->se, sem->pair, NULL, (struct symt*)symref)) return TRUE; + } + else FIXME("No support for this case yet %Ix\n", symref); + return TRUE; +} + static BOOL symt_enum_module(struct module_pair* pair, const WCHAR* match, const struct sym_enum* se) { + struct module_format_vtable_iterator iter = {}; void* ptr; struct symt_ht* sym = NULL; struct hash_table_iter hti; WCHAR* nameW; BOOL ret; + while ((module_format_vtable_iterator_next(pair->effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(enumerate_symbols)))) + { + struct symbol_enum_method sem = {pair, se}; + enum method_result result = iter.modfmt->vtable->enumerate_symbols(iter.modfmt, match, symbol_enum_method_cb, &sem); + + if (result == MR_SUCCESS) return TRUE; + if (result == MR_FAILURE) return FALSE; + /* fall back in all the other cases */ + } + hash_table_iter_init(&pair->effective->ht_symbols, &hti, NULL); while ((ptr = hash_table_iter_up(&hti))) { @@ -994,7 +1035,7 @@ static void symt_get_length(struct module* module, const struct symt* symt, ULON return; if (symt_get_info(module, symt, TI_GET_TYPE, &type_index) && - symt_get_info(module, symt_index2ptr(module, type_index), TI_GET_LENGTH, size)) return; + symt_get_info_from_index(module, type_index, TI_GET_LENGTH, size)) return; *size = 1; /* no size info */ } @@ -1026,7 +1067,7 @@ static int symt_get_best_at(struct module* module, int idx_sorttab) } /* assume addr is in module */ -struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr) +static struct symt_ht* symt_find_nearest_internal(struct module* module, DWORD_PTR addr) { int mid, high, low; ULONG64 ref_addr, ref_size; @@ -1072,6 +1113,33 @@ struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr) return module->addr_sorttab[low]; } +struct symt_ht *symt_find_nearest(struct module *module, DWORD_PTR addr) +{ + static int recursive; + struct module_format_vtable_iterator iter = {}; + + /* prevent recursive lookup inside backend */ + if (!recursive++) + { + while ((module_format_vtable_iterator_next(module, &iter, + MODULE_FORMAT_VTABLE_INDEX(lookup_by_address)))) + { + symref_t symref; + enum method_result result = iter.modfmt->vtable->lookup_by_address(iter.modfmt, addr, &symref); + if (result == MR_SUCCESS) + { + recursive--; + if (symt_is_symref_ptr(symref)) return (struct symt_ht*)SYMT_SYMREF_TO_PTR(symref); + FIXME("No support for this case yet\n"); + return NULL; + } + /* fall back in all the other cases */ + } + } + recursive--; + return symt_find_nearest_internal(module, addr); +} + struct symt_ht* symt_find_symbol_at(struct module* module, DWORD_PTR addr) { struct symt_ht* nearest = symt_find_nearest(module, addr); @@ -1090,7 +1158,7 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair, const WCHAR* match, const struct sym_enum* se, struct symt_function* func, const struct vector* v) { - struct symt* lsym = NULL; + const struct symt* lsym; DWORD_PTR pc = pair->pcs->localscope_pc; unsigned int i; WCHAR* nameW; @@ -1098,7 +1166,8 @@ static BOOL symt_enum_locals_helper(struct module_pair* pair, for (i=0; itag) { case SymTagBlock: @@ -1237,9 +1306,9 @@ struct symt* symt_get_upper_inlined(struct symt_function* inlined) { assert(symt); if (symt->tag == SymTagBlock) - symt = ((struct symt_block*)symt)->container; + symt = SYMT_SYMREF_TO_PTR(((struct symt_block*)symt)->container); else - symt = ((struct symt_function*)symt)->container; + symt = SYMT_SYMREF_TO_PTR(((struct symt_function*)symt)->container); } while (symt->tag == SymTagBlock); assert(symt->tag == SymTagFunction || symt->tag == SymTagInlineSite); return symt; @@ -1417,6 +1486,7 @@ BOOL WINAPI SymEnumSymbolsW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask, return doSymEnumSymbols(hProcess, BaseOfDll, Mask, sym_enumW, &sew); } +#ifndef _WIN64 struct sym_enumerate { void* ctx; @@ -1443,6 +1513,7 @@ BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll, return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se); } +#endif struct sym_enumerate64 { @@ -1574,6 +1645,7 @@ BOOL WINAPI SymGetSymFromAddr64(HANDLE hProcess, DWORD64 Address, static BOOL find_name(struct process* pcs, struct module* module, const char* name, SYMBOL_INFO* symbol) { + struct module_format_vtable_iterator iter = {}; struct hash_table_iter hti; void* ptr; struct symt_ht* sym = NULL; @@ -1583,6 +1655,24 @@ static BOOL find_name(struct process* pcs, struct module* module, const char* na if (!(pair.requested = module)) return FALSE; if (!module_get_debug(&pair)) return FALSE; + while ((module_format_vtable_iterator_next(pair.effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(lookup_by_name)))) + { + symref_t symref; + enum method_result result = iter.modfmt->vtable->lookup_by_name(iter.modfmt, name, &symref); + if (result == MR_SUCCESS) + { + if (symt_is_symref_ptr(symref)) + { + symt_fill_sym_info(&pair, NULL, SYMT_SYMREF_TO_PTR(symref), symbol); + return TRUE; + } + FIXME("Not expected case\n"); + return FALSE; + } + if (result != MR_NOT_FOUND) return FALSE; + } + hash_table_iter_init(&pair.effective->ht_symbols, &hti, name); while ((ptr = hash_table_iter_up(&hti))) { @@ -1635,7 +1725,8 @@ BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol) for (i = 0; i < vector_length(v); i++) { - struct symt* lsym = *(struct symt**)vector_at(v, i); + struct symt* lsym = SYMT_SYMREF_TO_PTR(*(symref_t*)vector_at(v, i)); + switch (lsym->tag) { case SymTagBlock: /* no recursion */ @@ -1758,108 +1849,87 @@ BOOL WINAPI SymGetSymFromName(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL Symb return TRUE; } -struct internal_line_t +static void init_lineinfo(struct lineinfo_t* line_info, BOOL unicode) { - BOOL unicode; - PVOID key; - DWORD line_number; - union - { - CHAR* file_nameA; - WCHAR* file_nameW; - }; - DWORD64 address; -}; - -static void init_internal_line(struct internal_line_t* intl, BOOL unicode) -{ - intl->unicode = unicode; - intl->key = NULL; - intl->line_number = 0; - intl->file_nameA = NULL; - intl->address = 0; + line_info->unicode = unicode; + line_info->key = NULL; + line_info->line_number = 0; + line_info->file_nameA = NULL; + line_info->address = 0; } -static BOOL internal_line_copy_toA32(const struct internal_line_t* intl, IMAGEHLP_LINE* l32) +#ifndef _WIN64 +static BOOL lineinfo_copy_toA32(const struct lineinfo_t* line_info, IMAGEHLP_LINE* l32) { - if (intl->unicode) return FALSE; - l32->Key = intl->key; - l32->LineNumber = intl->line_number; - l32->FileName = intl->file_nameA; - l32->Address = intl->address; + if (line_info->unicode) return FALSE; + l32->Key = line_info->key; + l32->LineNumber = line_info->line_number; + l32->FileName = line_info->file_nameA; + l32->Address = line_info->address; return TRUE; } +#endif -static BOOL internal_line_copy_toA64(const struct internal_line_t* intl, IMAGEHLP_LINE64* l64) +static BOOL lineinfo_copy_toA64(const struct lineinfo_t* line_info, IMAGEHLP_LINE64* l64) { - if (intl->unicode) return FALSE; - l64->Key = intl->key; - l64->LineNumber = intl->line_number; - l64->FileName = intl->file_nameA; - l64->Address = intl->address; + if (line_info->unicode) return FALSE; + l64->Key = line_info->key; + l64->LineNumber = line_info->line_number; + l64->FileName = line_info->file_nameA; + l64->Address = line_info->address; return TRUE; } -static BOOL internal_line_copy_toW64(const struct internal_line_t* intl, IMAGEHLP_LINEW64* l64) +static BOOL lineinfo_copy_toW64(const struct lineinfo_t* line_info, IMAGEHLP_LINEW64* l64) { - if (!intl->unicode) return FALSE; - l64->Key = intl->key; - l64->LineNumber = intl->line_number; - l64->FileName = intl->file_nameW; - l64->Address = intl->address; + if (!line_info->unicode) return FALSE; + l64->Key = line_info->key; + l64->LineNumber = line_info->line_number; + l64->FileName = line_info->file_nameW; + l64->Address = line_info->address; return TRUE; } -static BOOL internal_line_set_nameA(struct process* pcs, struct internal_line_t* intl, char* str, BOOL copy) +BOOL lineinfo_set_nameA(struct process* pcs, struct lineinfo_t* line_info, char* str) { DWORD len; - if (intl->unicode) + if (line_info->unicode) { len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); - if (!(intl->file_nameW = fetch_buffer(pcs, len * sizeof(WCHAR)))) return FALSE; - MultiByteToWideChar(CP_ACP, 0, str, -1, intl->file_nameW, len); + if (!(line_info->file_nameW = fetch_buffer(pcs, len * sizeof(WCHAR)))) return FALSE; + MultiByteToWideChar(CP_ACP, 0, str, -1, line_info->file_nameW, len); } else { - if (copy) - { - len = strlen(str) + 1; - if (!(intl->file_nameA = fetch_buffer(pcs, len))) return FALSE; - memcpy(intl->file_nameA, str, len); - } - else - intl->file_nameA = str; + len = strlen(str) + 1; + if (!(line_info->file_nameA = fetch_buffer(pcs, len))) return FALSE; + memcpy(line_info->file_nameA, str, len); } return TRUE; } -static BOOL internal_line_set_nameW(struct process* pcs, struct internal_line_t* intl, WCHAR* wstr, BOOL copy) +static BOOL lineinfo_set_nameW(struct process* pcs, struct lineinfo_t* line_info, WCHAR* wstr) { DWORD len; - if (intl->unicode) + if (line_info->unicode) { - if (copy) - { - len = (lstrlenW(wstr) + 1) * sizeof(WCHAR); - if (!(intl->file_nameW = fetch_buffer(pcs, len))) return FALSE; - memcpy(intl->file_nameW, wstr, len); - } - else - intl->file_nameW = wstr; + len = (lstrlenW(wstr) + 1) * sizeof(WCHAR); + if (!(line_info->file_nameW = fetch_buffer(pcs, len))) return FALSE; + memcpy(line_info->file_nameW, wstr, len); } else { DWORD len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL); - if (!(intl->file_nameA = fetch_buffer(pcs, len))) return FALSE; - WideCharToMultiByte(CP_ACP, 0, wstr, -1, intl->file_nameA, len, NULL, NULL); + if (!(line_info->file_nameA = fetch_buffer(pcs, len))) return FALSE; + WideCharToMultiByte(CP_ACP, 0, wstr, -1, line_info->file_nameA, len, NULL, NULL); } return TRUE; } static BOOL get_line_from_function(struct module_pair* pair, struct symt_function* func, DWORD64 addr, - PDWORD pdwDisplacement, struct internal_line_t* intl) + PDWORD pdwDisplacement, struct lineinfo_t* line_info) { struct line_info* dli = NULL; struct line_info* found_dli = NULL; @@ -1871,9 +1941,9 @@ static BOOL get_line_from_function(struct module_pair* pair, struct symt_functio if (!dli->is_source_file) { if (found_dli || dli->u.address > addr) continue; - intl->line_number = dli->line_number; - intl->address = dli->u.address; - intl->key = dli; + line_info->line_number = dli->line_number; + line_info->address = dli->u.address; + line_info->key = dli; found_dli = dli; continue; } @@ -1883,12 +1953,12 @@ static BOOL get_line_from_function(struct module_pair* pair, struct symt_functio if (dbghelp_opt_source_actual_path) { /* Return native file paths when using winedbg */ - ret = internal_line_set_nameA(pair->pcs, intl, (char*)source_get(pair->effective, dli->u.source_file), FALSE); + ret = lineinfo_set_nameA(pair->pcs, line_info, (char*)source_get(pair->effective, dli->u.source_file)); } else { WCHAR *dospath = wine_get_dos_file_name(source_get(pair->effective, dli->u.source_file)); - ret = internal_line_set_nameW(pair->pcs, intl, dospath, TRUE); + ret = lineinfo_set_nameW(pair->pcs, line_info, dospath); HeapFree( GetProcessHeap(), 0, dospath ); } if (ret && pdwDisplacement) *pdwDisplacement = addr - found_dli->u.address; @@ -1904,16 +1974,29 @@ static BOOL get_line_from_function(struct module_pair* pair, struct symt_functio * fills source file information from an address */ static BOOL get_line_from_addr(HANDLE hProcess, DWORD64 addr, - PDWORD pdwDisplacement, struct internal_line_t* intl) + PDWORD pdwDisplacement, struct lineinfo_t* line_info) { - struct module_pair pair; - struct symt_ht* symt; - + struct module_pair pair; + struct symt_ht* symt; + struct module_format_vtable_iterator iter = {}; + BOOL ret = FALSE; if (!module_init_pair(&pair, hProcess, addr)) return FALSE; - if ((symt = symt_find_symbol_at(pair.effective, addr)) == NULL) return FALSE; - if (symt->symt.tag != SymTagFunction && symt->symt.tag != SymTagInlineSite) return FALSE; - return get_line_from_function(&pair, (struct symt_function*)symt, addr, pdwDisplacement, intl); + while ((module_format_vtable_iterator_next(pair.effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(get_line_from_address)))) + { + if (iter.modfmt->vtable->get_line_from_address(iter.modfmt, addr, line_info) == MR_SUCCESS) + { + if (pdwDisplacement) *pdwDisplacement = addr - line_info->address; + return TRUE; + } + } + + symt = symt_find_symbol_at(pair.effective, addr); + if (symt_check_tag(&symt->symt, SymTagFunction)) + ret = get_line_from_function(&pair, (struct symt_function*)symt, addr, pdwDisplacement, line_info); + + return ret; } /*********************************************************************** @@ -1932,6 +2015,7 @@ BOOL WINAPI SymGetSymNext64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol) return FALSE; } +#ifndef _WIN64 /*********************************************************************** * SymGetSymNext (DBGHELP.@) */ @@ -1941,6 +2025,7 @@ BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } +#endif /*********************************************************************** * SymGetSymPrev64 (DBGHELP.@) @@ -1952,6 +2037,7 @@ BOOL WINAPI SymGetSymPrev64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol) return FALSE; } +#ifndef _WIN64 /*********************************************************************** * SymGetSymPrev (DBGHELP.@) */ @@ -1961,7 +2047,9 @@ BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } +#endif +#ifndef _WIN64 /****************************************************************** * SymGetLineFromAddr (DBGHELP.@) * @@ -1969,15 +2057,16 @@ BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE Line) { - struct internal_line_t intl; + struct lineinfo_t line_info; TRACE("(%p %p)\n", hProcess, Line); if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - init_internal_line(&intl, FALSE); - if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE; - return internal_line_copy_toA32(&intl, Line); + init_lineinfo(&line_info, FALSE); + if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &line_info)) return FALSE; + return lineinfo_copy_toA32(&line_info, Line); } +#endif /****************************************************************** * SymGetLineFromAddr64 (DBGHELP.@) @@ -1986,14 +2075,14 @@ BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line) { - struct internal_line_t intl; + struct lineinfo_t line_info; TRACE("(%p %p)\n", hProcess, Line); if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - init_internal_line(&intl, FALSE); - if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE; - return internal_line_copy_toA64(&intl, Line); + init_lineinfo(&line_info, FALSE); + if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &line_info)) return FALSE; + return lineinfo_copy_toA64(&line_info, Line); } /****************************************************************** @@ -2003,24 +2092,40 @@ BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, BOOL WINAPI SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line) { - struct internal_line_t intl; + struct lineinfo_t line_info; TRACE("(%p %p)\n", hProcess, Line); if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - init_internal_line(&intl, TRUE); - if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &intl)) return FALSE; - return internal_line_copy_toW64(&intl, Line); + init_lineinfo(&line_info, TRUE); + if (!get_line_from_addr(hProcess, dwAddr, pdwDisplacement, &line_info)) return FALSE; + return lineinfo_copy_toW64(&line_info, Line); } -static BOOL symt_get_func_line_prev(HANDLE hProcess, struct internal_line_t* intl, void* key, DWORD64 addr) +static BOOL symt_get_func_line_prev(HANDLE hProcess, struct lineinfo_t* line_info, void* key, DWORD64 addr) { struct module_pair pair; struct line_info* li; struct line_info* srcli; + struct module_format_vtable_iterator iter = {}; if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + line_info->address = addr; + line_info->key = key; + while ((module_format_vtable_iterator_next(pair.effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(advance_line_info)))) + { + switch (iter.modfmt->vtable->advance_line_info(iter.modfmt, line_info, FALSE)) + { + case MR_SUCCESS: + return TRUE; + case MR_NOT_FOUND: /* continue */ + break; + default: + return FALSE; + } + } if (key == NULL) return FALSE; li = key; @@ -2030,13 +2135,13 @@ static BOOL symt_get_func_line_prev(HANDLE hProcess, struct internal_line_t* int li--; if (!li->is_source_file) { - intl->line_number = li->line_number; - intl->address = li->u.address; - intl->key = li; + line_info->line_number = li->line_number; + line_info->address = li->u.address; + line_info->key = li; /* search source file */ for (srcli = li; !srcli->is_source_file; srcli--); - return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE); + return lineinfo_set_nameA(pair.pcs, line_info, (char*)source_get(pair.effective, srcli->u.source_file)); } } SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */ @@ -2049,31 +2154,33 @@ static BOOL symt_get_func_line_prev(HANDLE hProcess, struct internal_line_t* int */ BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) { - struct internal_line_t intl; + struct lineinfo_t line_info; TRACE("(%p %p)\n", hProcess, Line); if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - init_internal_line(&intl, FALSE); - if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE; - return internal_line_copy_toA64(&intl, Line); + init_lineinfo(&line_info, FALSE); + if (!symt_get_func_line_prev(hProcess, &line_info, Line->Key, Line->Address)) return FALSE; + return lineinfo_copy_toA64(&line_info, Line); } +#ifndef _WIN64 /****************************************************************** * SymGetLinePrev (DBGHELP.@) * */ BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) { - struct internal_line_t intl; + struct lineinfo_t line_info; TRACE("(%p %p)\n", hProcess, Line); if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - init_internal_line(&intl, FALSE); - if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE; - return internal_line_copy_toA32(&intl, Line); + init_lineinfo(&line_info, FALSE); + if (!symt_get_func_line_prev(hProcess, &line_info, Line->Key, Line->Address)) return FALSE; + return lineinfo_copy_toA32(&line_info, Line); } +#endif /****************************************************************** * SymGetLinePrevW64 (DBGHELP.@) @@ -2081,25 +2188,38 @@ BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) */ BOOL WINAPI SymGetLinePrevW64(HANDLE hProcess, PIMAGEHLP_LINEW64 Line) { - struct internal_line_t intl; + struct lineinfo_t line_info; TRACE("(%p %p)\n", hProcess, Line); if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - init_internal_line(&intl, TRUE); - if (!symt_get_func_line_prev(hProcess, &intl, Line->Key, Line->Address)) return FALSE; - return internal_line_copy_toW64(&intl, Line); + init_lineinfo(&line_info, TRUE); + if (!symt_get_func_line_prev(hProcess, &line_info, Line->Key, Line->Address)) return FALSE; + return lineinfo_copy_toW64(&line_info, Line); } -static BOOL symt_get_func_line_next(HANDLE hProcess, struct internal_line_t* intl, void* key, DWORD64 addr) +static BOOL symt_get_func_line_next(HANDLE hProcess, struct lineinfo_t* line_info, void* key, DWORD64 addr) { struct module_pair pair; struct line_info* li; struct line_info* srcli; + struct module_format_vtable_iterator iter = {}; - if (key == NULL) return FALSE; if (!module_init_pair(&pair, hProcess, addr)) return FALSE; + line_info->address = addr; + line_info->key = key; + while ((module_format_vtable_iterator_next(pair.effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(advance_line_info)))) + { + switch (iter.modfmt->vtable->advance_line_info(iter.modfmt, line_info, TRUE)) + { + case MR_SUCCESS: return TRUE; + default: break; + } + } + + if (key == NULL) return FALSE; /* search current source file */ for (srcli = key; !srcli->is_source_file; srcli--); @@ -2109,10 +2229,10 @@ static BOOL symt_get_func_line_next(HANDLE hProcess, struct internal_line_t* int li++; if (!li->is_source_file) { - intl->line_number = li->line_number; - intl->address = li->u.address; - intl->key = li; - return internal_line_set_nameA(pair.pcs, intl, (char*)source_get(pair.effective, srcli->u.source_file), FALSE); + line_info->line_number = li->line_number; + line_info->address = li->u.address; + line_info->key = li; + return lineinfo_set_nameA(pair.pcs, line_info, (char*)source_get(pair.effective, srcli->u.source_file)); } srcli = li; } @@ -2126,31 +2246,33 @@ static BOOL symt_get_func_line_next(HANDLE hProcess, struct internal_line_t* int */ BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) { - struct internal_line_t intl; + struct lineinfo_t line_info; TRACE("(%p %p)\n", hProcess, Line); if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - init_internal_line(&intl, FALSE); - if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE; - return internal_line_copy_toA64(&intl, Line); + init_lineinfo(&line_info, FALSE); + if (!symt_get_func_line_next(hProcess, &line_info, Line->Key, Line->Address)) return FALSE; + return lineinfo_copy_toA64(&line_info, Line); } +#ifndef _WIN64 /****************************************************************** * SymGetLineNext (DBGHELP.@) * */ BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) { - struct internal_line_t intl; + struct lineinfo_t line_info; TRACE("(%p %p)\n", hProcess, Line); if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - init_internal_line(&intl, FALSE); - if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE; - return internal_line_copy_toA32(&intl, Line); + init_lineinfo(&line_info, FALSE); + if (!symt_get_func_line_next(hProcess, &line_info, Line->Key, Line->Address)) return FALSE; + return lineinfo_copy_toA32(&line_info, Line); } +#endif /****************************************************************** * SymGetLineNextW64 (DBGHELP.@) @@ -2158,16 +2280,17 @@ BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) */ BOOL WINAPI SymGetLineNextW64(HANDLE hProcess, PIMAGEHLP_LINEW64 Line) { - struct internal_line_t intl; + struct lineinfo_t line_info; TRACE("(%p %p)\n", hProcess, Line); if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; - init_internal_line(&intl, TRUE); - if (!symt_get_func_line_next(hProcess, &intl, Line->Key, Line->Address)) return FALSE; - return internal_line_copy_toW64(&intl, Line); + init_lineinfo(&line_info, TRUE); + if (!symt_get_func_line_next(hProcess, &line_info, Line->Key, Line->Address)) return FALSE; + return lineinfo_copy_toW64(&line_info, Line); } +#ifndef _WIN64 /*********************************************************************** * SymUnDName (DBGHELP.@) */ @@ -2176,6 +2299,7 @@ BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, PSTR UnDecName, DWORD UnDecNameLeng return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, UNDNAME_COMPLETE) != 0; } +#endif /*********************************************************************** * SymUnDName64 (DBGHELP.@) @@ -2359,13 +2483,28 @@ static BOOL re_match_multi(const WCHAR** pstring, const WCHAR** pre, BOOL _case) return TRUE; } +BOOL symt_match_stringAW(const char *string, const WCHAR *re, BOOL _case) +{ + WCHAR* strW; + BOOL ret = FALSE; + DWORD sz; + + sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0); + if ((strW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) + { + MultiByteToWideChar(CP_ACP, 0, string, -1, strW, sz); + ret = SymMatchStringW(strW, re, _case); + HeapFree(GetProcessHeap(), 0, strW); + } + return ret; +} + /****************************************************************** * SymMatchStringA (DBGHELP.@) * */ BOOL WINAPI SymMatchStringA(PCSTR string, PCSTR re, BOOL _case) { - WCHAR* strW; WCHAR* reW; BOOL ret = FALSE; DWORD sz; @@ -2377,17 +2516,13 @@ BOOL WINAPI SymMatchStringA(PCSTR string, PCSTR re, BOOL _case) } TRACE("%s %s %c\n", debugstr_a(string), debugstr_a(re), _case ? 'Y' : 'N'); - sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0); - if ((strW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) - MultiByteToWideChar(CP_ACP, 0, string, -1, strW, sz); sz = MultiByteToWideChar(CP_ACP, 0, re, -1, NULL, 0); if ((reW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) + { MultiByteToWideChar(CP_ACP, 0, re, -1, reW, sz); - - if (strW && reW) - ret = SymMatchStringW(strW, reW, _case); - HeapFree(GetProcessHeap(), 0, strW); - HeapFree(GetProcessHeap(), 0, reW); + ret = symt_match_stringAW(string, reW, _case); + HeapFree(GetProcessHeap(), 0, reW); + } return ret; } @@ -2524,18 +2659,32 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland, struct module_pair pair; struct hash_table_iter hti; struct symt_ht* sym; - WCHAR* srcmask; + WCHAR* compiland_regex; + WCHAR* srcfile_regex; struct line_info* dli; void* ptr; SRCCODEINFO sci; const char* file; + struct module_format_vtable_iterator iter = {}; if (!cb) return FALSE; if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE; if (!module_init_pair(&pair, hProcess, base)) return FALSE; + if (!(compiland_regex = file_regex(compiland))) return FALSE; + if (!(srcfile_regex = file_regex(srcfile))) return FALSE; + + while ((module_format_vtable_iterator_next(pair.effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(enumerate_lines)))) + { + enum method_result result = iter.modfmt->vtable->enumerate_lines(iter.modfmt, compiland_regex, srcfile_regex, cb, user); + HeapFree(GetProcessHeap(), 0, compiland_regex); + HeapFree(GetProcessHeap(), 0, srcfile_regex); + return result == MR_SUCCESS; + } + if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", debugstr_a(compiland)); - if (!(srcmask = file_regex(srcfile))) return FALSE; + HeapFree(GetProcessHeap(), 0, compiland_regex); sci.SizeOfStruct = sizeof(sci); sci.ModBase = base; @@ -2555,20 +2704,10 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland, if (dli->is_source_file) { file = source_get(pair.effective, dli->u.source_file); - if (!file) sci.FileName[0] = '\0'; + if (file && symt_match_stringAW(file, srcfile_regex, FALSE)) + strcpy(sci.FileName, file); else - { - DWORD sz = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0); - WCHAR* fileW; - - if ((fileW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) - MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, sz); - if (SymMatchStringW(fileW, srcmask, FALSE)) - strcpy(sci.FileName, file); - else - sci.FileName[0] = '\0'; - HeapFree(GetProcessHeap(), 0, fileW); - } + sci.FileName[0] = '\0'; } else if (sci.FileName[0]) { @@ -2580,7 +2719,7 @@ BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland, } } } - HeapFree(GetProcessHeap(), 0, srcmask); + HeapFree(GetProcessHeap(), 0, srcfile_regex); return TRUE; } @@ -2615,14 +2754,15 @@ BOOL WINAPI SymGetLineFromNameW64(HANDLE hProcess, PCWSTR ModuleName, PCWSTR Fil BOOL WINAPI SymFromIndex(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFO symbol) { struct module_pair pair; - struct symt* sym; + symref_t symref; TRACE("hProcess = %p, BaseOfDll = %I64x, index = %ld, symbol = %p\n", hProcess, BaseOfDll, index, symbol); if (!module_init_pair(&pair, hProcess, BaseOfDll)) return FALSE; - if ((sym = symt_index2ptr(pair.effective, index)) == NULL) return FALSE; - symt_fill_sym_info(&pair, NULL, sym, symbol); + if ((symref = symt_index_to_symref(pair.effective, index)) == 0) return FALSE; + if (!symt_is_symref_ptr(symref)) return FALSE; + symt_fill_sym_info(&pair, NULL, (struct symt*)symref, symbol); return TRUE; } @@ -2730,7 +2870,7 @@ BOOL WINAPI SymFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ct } static BOOL get_line_from_inline_context(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, - struct internal_line_t* intl) + struct lineinfo_t* line_info) { struct module_pair pair; struct symt_function* inlined; @@ -2740,12 +2880,31 @@ static BOOL get_line_from_inline_context(HANDLE hProcess, DWORD64 addr, ULONG in { case IFC_MODE_INLINE: inlined = symt_find_inlined_site(pair.effective, addr, inline_ctx); - if (inlined && get_line_from_function(&pair, inlined, addr, disp, intl)) + if (symt_check_tag(&inlined->symt, SymTagInlineSite)) + { + struct module_format_vtable_iterator iter = {}; + while ((module_format_vtable_iterator_next(pair.effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(get_line_from_inlined_address)))) + { + enum method_result result = iter.modfmt->vtable->get_line_from_inlined_address(iter.modfmt, inlined, addr, line_info); + switch (result) + { + case MR_SUCCESS: + if (disp) *disp = addr - line_info->address; + return TRUE; + case MR_NOT_FOUND: /* continue */ + break; + default: + return FALSE; + } + } + } + if (inlined && get_line_from_function(&pair, inlined, addr, disp, line_info)) return TRUE; /* fall through: check if we can find line info at top function level */ case IFC_MODE_IGNORE: case IFC_MODE_REGULAR: - return get_line_from_addr(hProcess, addr, disp, intl); + return get_line_from_addr(hProcess, addr, disp, line_info); default: SetLastError(ERROR_INVALID_PARAMETER); return FALSE; @@ -2758,16 +2917,16 @@ static BOOL get_line_from_inline_context(HANDLE hProcess, DWORD64 addr, ULONG in */ BOOL WINAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINE64 line) { - struct internal_line_t intl; + struct lineinfo_t line_info; TRACE("(%p, %#I64x, 0x%lx, %#I64x, %p, %p)\n", hProcess, addr, inline_ctx, mod_addr, disp, line); if (line->SizeOfStruct < sizeof(*line)) return FALSE; - init_internal_line(&intl, FALSE); + init_lineinfo(&line_info, FALSE); - if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE; - return internal_line_copy_toA64(&intl, line); + if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &line_info)) return FALSE; + return lineinfo_copy_toA64(&line_info, line); } /****************************************************************** @@ -2776,16 +2935,16 @@ BOOL WINAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 addr, ULONG inl */ BOOL WINAPI SymGetLineFromInlineContextW(HANDLE hProcess, DWORD64 addr, ULONG inline_ctx, DWORD64 mod_addr, PDWORD disp, PIMAGEHLP_LINEW64 line) { - struct internal_line_t intl; + struct lineinfo_t line_info; TRACE("(%p, %#I64x, 0x%lx, %#I64x, %p, %p)\n", hProcess, addr, inline_ctx, mod_addr, disp, line); if (line->SizeOfStruct < sizeof(*line)) return FALSE; - init_internal_line(&intl, TRUE); + init_lineinfo(&line_info, TRUE); - if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &intl)) return FALSE; - return internal_line_copy_toW64(&intl, line); + if (!get_line_from_inline_context(hProcess, addr, inline_ctx, mod_addr, disp, &line_info)) return FALSE; + return lineinfo_copy_toW64(&line_info, line); } /****************************************************************** diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index f7313c3ab4ff..41398784ef97 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -100,7 +100,7 @@ static void test_stack_walk(void) } while (!count); - ctx.ContextFlags = CONTEXT_CONTROL; + ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; ret = GetThreadContext(thread, &ctx); ok(ret, "got error %u\n", ret); diff --git a/dlls/dbghelp/type.c b/dlls/dbghelp/type.c index b89c63c5b3d6..a0529ec37fbd 100644 --- a/dlls/dbghelp/type.c +++ b/dlls/dbghelp/type.c @@ -102,8 +102,7 @@ const char* symt_get_name(const struct symt* sym) case SymTagEnum: return ((const struct symt_enum*)sym)->hash_elt.name; case SymTagTypedef: return ((const struct symt_typedef*)sym)->hash_elt.name; case SymTagUDT: return ((const struct symt_udt*)sym)->hash_elt.name; - case SymTagCompiland: return source_get(((const struct symt_compiland*)sym)->container->module, - ((const struct symt_compiland*)sym)->source); + case SymTagCompiland: return ((const struct symt_compiland*)sym)->filename; default: FIXME("Unsupported sym-tag %s\n", symt_get_tag_str(sym->tag)); /* fall through */ @@ -160,10 +159,12 @@ BOOL symt_get_address(const struct symt* type, ULONG64* addr) case SymTagFuncDebugStart: case SymTagFuncDebugEnd: case SymTagLabel: - if (!((const struct symt_hierarchy_point*)type)->parent || - !symt_get_address(((const struct symt_hierarchy_point*)type)->parent, addr)) - *addr = 0; - *addr += ((const struct symt_hierarchy_point*)type)->loc.offset; + *addr = 0; + if (SYMT_SYMREF_TO_PTR(((const struct symt_hierarchy_point*)type)->container)) + { + if (symt_get_address(SYMT_SYMREF_TO_PTR(((const struct symt_hierarchy_point*)type)->container), addr)) + *addr += ((const struct symt_hierarchy_point*)type)->loc.offset; + } break; case SymTagThunk: *addr = ((const struct symt_thunk*)type)->address; @@ -213,14 +214,6 @@ static struct symt* symt_find_type_by_name(const struct module* module, return NULL; } -static void symt_add_type(struct module* module, struct symt* symt) -{ - struct symt** p; - p = vector_add(&module->vtypes, &module->pool); - assert(p); - *p = symt; -} - struct symt_basic* symt_get_basic(enum BasicType bt, unsigned size) { static struct symt_basic cache[32] = { { {SymTagBaseType}, btNoType, 0 } }; @@ -260,8 +253,7 @@ struct symt_udt* symt_new_udt(struct module* module, const char* typename, sym->hash_elt.name = pool_strdup(&module->pool, typename); hash_table_add(&module->ht_types, &sym->hash_elt); } else sym->hash_elt.name = NULL; - vector_init(&sym->vchildren, sizeof(struct symt*), 8); - symt_add_type(module, &sym->symt); + vector_init(&sym->vchildren, sizeof(struct symt*), 0); } return sym; } @@ -289,7 +281,7 @@ BOOL symt_set_udt_size(struct module* module, struct symt_udt* udt, unsigned siz * the others (bit fields) */ BOOL symt_add_udt_element(struct module* module, struct symt_udt* udt_type, - const char* name, struct symt* elt_type, + const char* name, symref_t elt_type, unsigned offset, unsigned bit_offset, unsigned bit_size) { struct symt_data* m; @@ -318,13 +310,13 @@ BOOL symt_add_udt_element(struct module* module, struct symt_udt* udt_type, m->hash_elt.next = NULL; m->kind = DataIsMember; - m->container = &module->top->symt; /* native defines lexical parent as module, not udt... */ + m->container = symt_ptr_to_symref(&module->top->symt); /* native defines lexical parent as module, not udt... */ m->type = elt_type; m->u.member.offset = offset; m->u.member.bit_offset = bit_offset; m->u.member.bit_length = bit_size; p = vector_add(&udt_type->vchildren, &module->pool); - *p = &m->symt; + if (p) *p = &m->symt; return TRUE; } @@ -345,14 +337,13 @@ struct symt_enum* symt_new_enum(struct module* module, const char* typename, hash_table_add(&module->ht_types, &sym->hash_elt); } else sym->hash_elt.name = NULL; sym->base_type = basetype; - vector_init(&sym->vchildren, sizeof(struct symt*), 8); - symt_add_type(module, &sym->symt); + vector_init(&sym->vchildren, sizeof(struct symt*), 0); } return sym; } BOOL symt_add_enum_element(struct module* module, struct symt_enum* enum_type, - const char* name, int value) + const char* name, const VARIANT *variant) { struct symt_data* e; struct symt** p; @@ -365,10 +356,9 @@ BOOL symt_add_enum_element(struct module* module, struct symt_enum* enum_type, e->hash_elt.name = pool_strdup(&module->pool, name); e->hash_elt.next = NULL; e->kind = DataIsConstant; - e->container = &enum_type->symt; - e->type = enum_type->base_type; - V_VT(&e->u.value) = VT_I4; - V_I4(&e->u.value) = value; + e->container = symt_ptr_to_symref(&enum_type->symt); + e->type = symt_ptr_to_symref(enum_type->base_type); + e->u.value = *variant; p = vector_add(&enum_type->vchildren, &module->pool); if (!p) return FALSE; /* FIXME we leak e */ @@ -389,7 +379,6 @@ struct symt_array* symt_new_array(struct module* module, int min, DWORD cnt, sym->count = cnt; sym->base_type = base; sym->index_type = index; - symt_add_type(module, &sym->symt); } return sym; } @@ -404,9 +393,8 @@ struct symt_function_signature* symt_new_function_signature(struct module* modul { sym->symt.tag = SymTagFunctionType; sym->rettype = ret_type; - vector_init(&sym->vchildren, sizeof(struct symt*), 4); + vector_init(&sym->vchildren, sizeof(struct symt*), 0); sym->call_conv = call_conv; - symt_add_type(module, &sym->symt); } return sym; } @@ -439,13 +427,12 @@ struct symt_pointer* symt_new_pointer(struct module* module, struct symt* ref_ty sym->symt.tag = SymTagPointerType; sym->pointsto = ref_type; sym->size = size; - symt_add_type(module, &sym->symt); } return sym; } -struct symt_typedef* symt_new_typedef(struct module* module, struct symt* ref, - const char* name) +struct symt_typedef* symt_new_typedef(struct module* module, symref_t ref, + const char* typename) { struct symt_typedef* sym; @@ -453,55 +440,107 @@ struct symt_typedef* symt_new_typedef(struct module* module, struct symt* ref, { sym->symt.tag = SymTagTypedef; sym->type = ref; - sym->hash_elt.name = pool_strdup(&module->pool, name); + sym->hash_elt.name = pool_strdup(&module->pool, typename); hash_table_add(&module->ht_types, &sym->hash_elt); - symt_add_type(module, &sym->symt); } return sym; } -/****************************************************************** - * SymEnumTypes (DBGHELP.@) - * - */ -BOOL WINAPI SymEnumTypes(HANDLE hProcess, ULONG64 BaseOfDll, - PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, - PVOID UserContext) +struct sym_modfmt_type_enum { - struct module_pair pair; - char buffer[sizeof(SYMBOL_INFO) + 256]; - SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer; - struct symt* type; - DWORD64 size; - unsigned int i; + struct module *module; + SYMBOL_INFO *sym_info; + PSYM_ENUMERATESYMBOLS_CALLBACK cb; + void *user; + const char *type_name; +}; - TRACE("(%p %I64x %p %p)\n", hProcess, BaseOfDll, EnumSymbolsCallback, UserContext); +static BOOL sym_modfmt_type_enum_cb(symref_t symref, const char *name, void *user) +{ + struct sym_modfmt_type_enum *info = user; + DWORD64 size; + + if (info->type_name && !SymMatchStringA(name, info->type_name, TRUE)) return TRUE; + info->sym_info->TypeIndex = symt_symref_to_index(info->module, symref); + info->sym_info->Index = 0; + symt_get_info_from_symref(info->module, symref, TI_GET_LENGTH, &size); + info->sym_info->Size = size; + info->sym_info->ModBase = info->module->module.BaseOfImage; + info->sym_info->Flags = 0; /* FIXME */ + info->sym_info->Value = 0; /* FIXME */ + info->sym_info->Address = 0; /* FIXME */ + info->sym_info->Register = 0; /* FIXME */ + info->sym_info->Scope = 0; /* FIXME */ + symt_get_info_from_symref(info->module, symref, TI_GET_SYMTAG, &info->sym_info->Tag); + symbol_setname(info->sym_info, name); + + return (*info->cb)(info->sym_info, info->sym_info->Size, info->user); +} - if (!module_init_pair(&pair, hProcess, BaseOfDll)) return FALSE; +static BOOL sym_enum_types(struct module_pair *pair, const char *type_name, PSYM_ENUMERATESYMBOLS_CALLBACK cb, void *user) +{ + struct module_format_vtable_iterator iter = {}; + char buffer[sizeof(SYMBOL_INFO) + 256]; + SYMBOL_INFO *sym_info = (SYMBOL_INFO*)buffer; + struct hash_table_iter hti; + void* ptr; + struct symt_ht *type; + DWORD64 size; sym_info->SizeOfStruct = sizeof(SYMBOL_INFO); sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO); - for (i=0; ivtypes); i++) + /* FIXME could optim if type_name doesn't contain wild cards */ + while ((module_format_vtable_iterator_next(pair->effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(enumerate_types)))) { - type = *(struct symt**)vector_at(&pair.effective->vtypes, i); - sym_info->TypeIndex = symt_ptr2index(pair.effective, type); + struct sym_modfmt_type_enum info = {pair->effective, sym_info, cb, user, type_name}; + enum method_result result = iter.modfmt->vtable->enumerate_types(iter.modfmt, sym_modfmt_type_enum_cb, &info); + return result != MR_FAILURE; + } + + hash_table_iter_init(&pair->effective->ht_types, &hti, type_name); + while ((ptr = hash_table_iter_up(&hti))) + { + type = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt); + + if (type_name && !SymMatchStringA(type->hash_elt.name, type_name, TRUE)) continue; + + sym_info->TypeIndex = symt_ptr_to_index(pair->effective, &type->symt); sym_info->Index = 0; /* FIXME */ - symt_get_info(pair.effective, type, TI_GET_LENGTH, &size); + symt_get_info(pair->effective, &type->symt, TI_GET_LENGTH, &size); sym_info->Size = size; - sym_info->ModBase = pair.requested->module.BaseOfImage; + sym_info->ModBase = pair->requested->module.BaseOfImage; sym_info->Flags = 0; /* FIXME */ sym_info->Value = 0; /* FIXME */ sym_info->Address = 0; /* FIXME */ sym_info->Register = 0; /* FIXME */ sym_info->Scope = 0; /* FIXME */ - sym_info->Tag = type->tag; - symbol_setname(sym_info, symt_get_name(type)); - if (!EnumSymbolsCallback(sym_info, sym_info->Size, UserContext)) break; + sym_info->Tag = type->symt.tag; + symbol_setname(sym_info, type->hash_elt.name); + if (!cb(sym_info, sym_info->Size, user)) return FALSE; } return TRUE; } +/****************************************************************** + * SymEnumTypes (DBGHELP.@) + * + */ +BOOL WINAPI SymEnumTypes(HANDLE hProcess, ULONG64 BaseOfDll, + PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + PVOID UserContext) +{ + struct module_pair pair; + + TRACE("(%p %I64x %p %p)\n", hProcess, BaseOfDll, EnumSymbolsCallback, UserContext); + + if (!module_init_pair(&pair, hProcess, BaseOfDll)) return FALSE; + + sym_enum_types(&pair, NULL, EnumSymbolsCallback, UserContext); + return TRUE; +} + struct enum_types_AtoW { char buffer[sizeof(SYMBOL_INFOW) + 256 * sizeof(WCHAR)]; @@ -534,41 +573,6 @@ BOOL WINAPI SymEnumTypesW(HANDLE hProcess, ULONG64 BaseOfDll, return SymEnumTypes(hProcess, BaseOfDll, enum_types_AtoW, &et); } -static void enum_types_of_module(struct module_pair* pair, const char* name, PSYM_ENUMERATESYMBOLS_CALLBACK cb, PVOID user) -{ - char buffer[sizeof(SYMBOL_INFO) + 256]; - SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer; - struct symt* type; - DWORD64 size; - unsigned i; - const char* tname; - - sym_info->SizeOfStruct = sizeof(SYMBOL_INFO); - sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO); - - for (i = 0; i < vector_length(&pair->effective->vtypes); i++) - { - type = *(struct symt**)vector_at(&pair->effective->vtypes, i); - tname = symt_get_name(type); - if (tname && SymMatchStringA(tname, name, TRUE)) - { - sym_info->TypeIndex = symt_ptr2index(pair->effective, type); - sym_info->Index = 0; /* FIXME */ - symt_get_info(pair->effective, type, TI_GET_LENGTH, &size); - sym_info->Size = size; - sym_info->ModBase = pair->requested->module.BaseOfImage; - sym_info->Flags = 0; /* FIXME */ - sym_info->Value = 0; /* FIXME */ - sym_info->Address = 0; /* FIXME */ - sym_info->Register = 0; /* FIXME */ - sym_info->Scope = 0; /* FIXME */ - sym_info->Tag = type->tag; - symbol_setname(sym_info, tname); - if (!cb(sym_info, sym_info->Size, user)) break; - } - } -} - static BOOL walk_modules(struct module_pair* pair) { /* first walk PE only modules */ @@ -597,8 +601,7 @@ BOOL WINAPI SymEnumTypesByName(HANDLE proc, ULONG64 base, PCSTR name, PSYM_ENUME TRACE("(%p %I64x %s %p %p)\n", proc, base, debugstr_a(name), cb, user); - if (!name) return SymEnumTypes(proc, base, cb, user); - bang = strchr(name, '!'); + bang = name ? strchr(name, '!') : NULL; if (bang) { DWORD sz; @@ -614,14 +617,15 @@ BOOL WINAPI SymEnumTypesByName(HANDLE proc, ULONG64 base, PCSTR name, PSYM_ENUME while (walk_modules(&pair)) { if (SymMatchStringW(pair.requested->modulename, modW, FALSE)) - enum_types_of_module(&pair, bang + 1, cb, user); + if (!sym_enum_types(&pair, bang + 1, cb, user)) + break; } free(modW); } else { if (!module_init_pair(&pair, proc, base) || !module_get_debug(&pair)) return FALSE; - enum_types_of_module(&pair, name, cb, user); + sym_enum_types(&pair, name, cb, user); } return TRUE; } @@ -670,7 +674,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type, case TI_FINDCHILDREN: { const struct vector* v; - struct symt** pt; + symref_t* symref; unsigned i; TI_FINDCHILDREN_PARAMS* tifp = pInfo; @@ -697,14 +701,14 @@ BOOL symt_get_info(struct module* module, const struct symt* type, /* for those, CHILDRENCOUNT returns 0 */ return tifp->Count == 0; default: - FIXME("Unsupported sym-tag %s for find-children\n", + FIXME("Unsupported sym-tag %s for find-children\n", symt_get_tag_str(type->tag)); return FALSE; } for (i = 0; i < tifp->Count; i++) { - if (!(pt = vector_at(v, tifp->Start + i))) return FALSE; - tifp->ChildId[i] = symt_ptr2index(module, *pt); + if (!(symref = (symref_t *)vector_at(v, tifp->Start + i))) return FALSE; + tifp->ChildId[tifp->Start + i] = symt_symref_to_index(module, *symref); } } break; @@ -842,7 +846,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type, X(DWORD64) = ((const struct symt_data*)type)->u.member.bit_length; break; default: - if (!symt_get_info(module, ((const struct symt_data*)type)->type, TI_GET_LENGTH, pInfo)) + if (!symt_get_info_from_symref(module, ((const struct symt_data*)type)->type, TI_GET_LENGTH, pInfo)) return FALSE; } break; @@ -856,7 +860,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type, X(DWORD64) = ((const struct symt_public*)type)->size; break; case SymTagTypedef: - return symt_get_info(module, ((const struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo); + return symt_get_info_from_symref(module, ((const struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo); case SymTagThunk: X(DWORD64) = ((const struct symt_thunk*)type)->size; break; @@ -883,25 +887,25 @@ BOOL symt_get_info(struct module* module, const struct symt* type, switch (type->tag) { case SymTagCompiland: - X(DWORD) = symt_ptr2index(module, &((const struct symt_compiland*)type)->container->symt); + X(DWORD) = symt_symref_to_index(module, ((const struct symt_compiland*)type)->container); break; case SymTagBlock: - X(DWORD) = symt_ptr2index(module, ((const struct symt_block*)type)->container); + X(DWORD) = symt_symref_to_index(module, ((const struct symt_block*)type)->container); break; case SymTagData: - X(DWORD) = symt_ptr2index(module, ((const struct symt_data*)type)->container); + X(DWORD) = symt_symref_to_index(module, ((const struct symt_data*)type)->container); break; case SymTagFunction: case SymTagInlineSite: - X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->container); + X(DWORD) = symt_symref_to_index(module, ((const struct symt_function*)type)->container); break; case SymTagThunk: - X(DWORD) = symt_ptr2index(module, ((const struct symt_thunk*)type)->container); + X(DWORD) = symt_symref_to_index(module, ((const struct symt_thunk*)type)->container); break; case SymTagFuncDebugStart: case SymTagFuncDebugEnd: case SymTagLabel: - X(DWORD) = symt_ptr2index(module, ((const struct symt_hierarchy_point*)type)->parent); + X(DWORD) = symt_symref_to_index(module, ((const struct symt_hierarchy_point*)type)->container); break; case SymTagUDT: case SymTagEnum: @@ -914,7 +918,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type, case SymTagBaseClass: case SymTagPublicSymbol: case SymTagCustom: - X(DWORD) = symt_ptr2index(module, &module->top->symt); + X(DWORD) = symt_ptr_to_index(module, &module->top->symt); break; default: FIXME("Unsupported sym-tag %s for get-lexical-parent\n", @@ -1019,30 +1023,30 @@ BOOL symt_get_info(struct module* module, const struct symt* type, { /* hierarchical => hierarchical */ case SymTagArrayType: - X(DWORD) = symt_ptr2index(module, ((const struct symt_array*)type)->base_type); + X(DWORD) = symt_ptr_to_index(module, ((const struct symt_array*)type)->base_type); break; case SymTagPointerType: - X(DWORD) = symt_ptr2index(module, ((const struct symt_pointer*)type)->pointsto); + X(DWORD) = symt_ptr_to_index(module, ((const struct symt_pointer*)type)->pointsto); break; case SymTagFunctionType: - X(DWORD) = symt_ptr2index(module, ((const struct symt_function_signature*)type)->rettype); + X(DWORD) = symt_ptr_to_index(module, ((const struct symt_function_signature*)type)->rettype); break; case SymTagTypedef: - X(DWORD) = symt_ptr2index(module, ((const struct symt_typedef*)type)->type); + X(DWORD) = symt_symref_to_index(module, ((const struct symt_typedef*)type)->type); break; /* lexical => hierarchical */ case SymTagData: - X(DWORD) = symt_ptr2index(module, ((const struct symt_data*)type)->type); + X(DWORD) = symt_symref_to_index(module, ((const struct symt_data*)type)->type); break; case SymTagFunction: case SymTagInlineSite: - X(DWORD) = symt_ptr2index(module, ((const struct symt_function*)type)->type); + X(DWORD) = symt_symref_to_index(module, ((const struct symt_function*)type)->type); break; case SymTagEnum: - X(DWORD) = symt_ptr2index(module, ((const struct symt_enum*)type)->base_type); + X(DWORD) = symt_ptr_to_index(module, ((const struct symt_enum*)type)->base_type); break; case SymTagFunctionArgType: - X(DWORD) = symt_ptr2index(module, ((const struct symt_function_arg_type*)type)->arg_type); + X(DWORD) = symt_ptr_to_index(module, ((const struct symt_function_arg_type*)type)->arg_type); break; default: FIXME("Unsupported sym-tag %s for get-type\n", @@ -1077,19 +1081,16 @@ BOOL symt_get_info(struct module* module, const struct symt* type, case DataIsParam: { struct location loc = ((const struct symt_data*)type)->u.var; - unsigned i; - struct module_format* modfmt; + struct module_format_vtable_iterator iter = { 0 }; if (loc.kind < loc_user) return FALSE; - for (i = 0; i < DFI_LAST; i++) + while ((module_format_vtable_iterator_next(module, &iter, + MODULE_FORMAT_VTABLE_INDEX(loc_compute)))) { - modfmt = module->format_info[i]; - if (modfmt && modfmt->loc_compute) - { - modfmt->loc_compute(module->process, modfmt, - (const struct symt_function*)((const struct symt_data*)type)->container, &loc); - break; - } + iter.modfmt->vtable->loc_compute(iter.modfmt, + (const struct symt_function*)SYMT_SYMREF_TO_PTR(((const struct symt_data*)type)->container), + &loc); + break; } if (loc.kind != loc_absolute) return FALSE; V_VT(&X(VARIANT)) = VT_UI4; /* FIXME */ @@ -1111,7 +1112,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type, break; case TI_GET_ARRAYINDEXTYPEID: if (type->tag != SymTagArrayType) return FALSE; - X(DWORD) = symt_ptr2index(module, ((const struct symt_array*)type)->index_type); + X(DWORD) = symt_ptr_to_index(module, ((const struct symt_array*)type)->index_type); break; case TI_GET_SYMINDEX: @@ -1119,7 +1120,7 @@ BOOL symt_get_info(struct module* module, const struct symt* type, * native sometimes (eg for UDT) return id of another instance * of the same UDT definition... maybe forward declaration? */ - X(DWORD) = symt_ptr2index(module, type); + X(DWORD) = symt_ptr_to_index(module, type); break; /* FIXME: we don't support properly C++ for now */ @@ -1153,6 +1154,25 @@ BOOL symt_get_info(struct module* module, const struct symt* type, return TRUE; } +BOOL symt_get_info_from_index(struct module* module, DWORD index, + IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo) +{ + return symt_get_info_from_symref(module, symt_index_to_symref(module, index), req, pInfo); +} + +BOOL symt_get_info_from_symref(struct module* module, symref_t ref, + IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo) +{ + if (symt_is_symref_ptr(ref)) + return symt_get_info(module, (struct symt *)ref, req, pInfo); + if (module->ops_symref_modfmt) + { + enum method_result result = module->ops_symref_modfmt->vtable->request_symref_t(module->ops_symref_modfmt, ref, req, pInfo); + return result == MR_SUCCESS; + } + return FALSE; +} + /****************************************************************** * SymGetTypeInfo (DBGHELP.@) * @@ -1164,7 +1184,7 @@ BOOL WINAPI SymGetTypeInfo(HANDLE hProcess, DWORD64 ModBase, struct module_pair pair; if (!module_init_pair(&pair, hProcess, ModBase)) return FALSE; - return symt_get_info(pair.effective, symt_index2ptr(pair.effective, TypeId), GetType, pInfo); + return symt_get_info_from_index(pair.effective, TypeId, GetType, pInfo); } /****************************************************************** @@ -1177,11 +1197,35 @@ BOOL WINAPI SymGetTypeFromName(HANDLE hProcess, ULONG64 BaseOfDll, struct module_pair pair; struct symt* type; DWORD64 size; + struct module_format_vtable_iterator iter = {}; if (!module_init_pair(&pair, hProcess, BaseOfDll)) return FALSE; + + while ((module_format_vtable_iterator_next(pair.effective, &iter, + MODULE_FORMAT_VTABLE_INDEX(find_type)))) + { + symref_t symref; + enum method_result result = iter.modfmt->vtable->find_type(iter.modfmt, Name, &symref); + if (result == MR_SUCCESS) + { + WCHAR *name; + Symbol->Index = Symbol->TypeIndex = symt_symref_to_index(pair.effective, symref); + symt_get_info_from_symref(pair.effective, symref, TI_GET_SYMNAME, &name); + Symbol->NameLen = WideCharToMultiByte(CP_ACP, 0, name, -1, Symbol->Name, Symbol->MaxNameLen, NULL, NULL); + if (Symbol->NameLen) Symbol->NameLen--; + HeapFree(GetProcessHeap(), 0, name); + symt_get_info_from_symref(pair.effective, symref, TI_GET_LENGTH, &size); + Symbol->Size = size; + Symbol->ModBase = pair.requested->module.BaseOfImage; + symt_get_info_from_symref(pair.effective, symref, TI_GET_SYMTAG, &Symbol->Tag); + return TRUE; + } + if (result == MR_FAILURE) return FALSE; + } + type = symt_find_type_by_name(pair.effective, SymTagNull, Name); if (!type) return FALSE; - Symbol->Index = Symbol->TypeIndex = symt_ptr2index(pair.effective, type); + Symbol->Index = Symbol->TypeIndex = symt_ptr_to_index(pair.effective, type); symbol_setname(Symbol, symt_get_name(type)); symt_get_info(pair.effective, type, TI_GET_LENGTH, &size); Symbol->Size = size; diff --git a/dlls/dcomp/device.c b/dlls/dcomp/device.c index 2744d758e918..d0eb920968a6 100644 --- a/dlls/dcomp/device.c +++ b/dlls/dcomp/device.c @@ -36,6 +36,9 @@ HRESULT WINAPI DCompositionCreateDevice2(IUnknown *rendering_device, REFIID iid, { FIXME("%p, %s, %p.\n", rendering_device, debugstr_guid(iid), device); + /* Try to workaround Chromium race fixed by Chromium commit 1c13c9105b40e83f87ebcad104fab57fcef43eb9. */ + Sleep(50); + return E_NOTIMPL; } diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index ed342bfd7084..214befa9aa0e 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -973,7 +973,7 @@ static HRESULT ddraw_set_cooperative_level(struct ddraw *ddraw, HWND window, topmost bit unless the DDSCL_NOWINDOWCHANGES flag is set in this call that sets it to normal, not in the old coop level. */ if (!(cooplevel & DDSCL_NOWINDOWCHANGES)) - SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + SetWindowPos(ddraw->dest_window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); if (restore_mode_on_normal && FAILED(ddraw7_RestoreDisplayMode(&ddraw->IDirectDraw7_iface))) ERR("RestoreDisplayMode failed\n"); diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index bd1df8e1b822..7e837c40c3b8 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -19,6 +19,10 @@ #ifndef __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H #define __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H +#ifdef __i386__ +#pragma GCC target ("fpmath=387") +#endif + #include #include #include diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index 545c76738cd1..ce3cc5bf29c7 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -64,6 +64,7 @@ HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface, struct wined3d_texture *dst_texture, *wined3d_texture; struct ddraw *ddraw = surface->ddraw; HDC surface_dc, screen_dc; + HWND dest_window = NULL; int x, y, w, h; HRESULT hr; BOOL ret; @@ -156,7 +157,9 @@ HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface, if (surface->palette) wined3d_palette_apply_to_dc(surface->palette->wined3d_palette, surface_dc); - if (!(screen_dc = GetDC(NULL))) + if (ddraw->cooperative_level & DDSCL_EXCLUSIVE && ddraw->dest_window) + dest_window = ddraw->dest_window; + if (!(screen_dc = GetDCEx(dest_window, NULL, DCX_WINDOW | DCX_CACHE))) { wined3d_texture_release_dc(wined3d_texture, surface->sub_resource_idx, surface_dc); ERR("Failed to get screen DC.\n"); @@ -170,7 +173,7 @@ HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface, ret = BitBlt(screen_dc, x, y, w, h, surface_dc, x, y, SRCCOPY); - ReleaseDC(NULL, screen_dc); + ReleaseDC(dest_window, screen_dc); wined3d_texture_release_dc(wined3d_texture, surface->sub_resource_idx, surface_dc); if (!ret) @@ -4646,7 +4649,6 @@ static HRESULT WINAPI ddraw_surface7_SetClipper(IDirectDrawSurface7 *iface, ddraw_set_swapchain_window(This->ddraw, This->ddraw->dest_window); } } - wined3d_mutex_unlock(); return DD_OK; @@ -5362,6 +5364,15 @@ static HRESULT WINAPI ddraw_gamma_control_SetGammaRamp(IDirectDrawGammaControl * return DDERR_INVALIDPARAMS; } + { + const char *sgi = getenv("SteamGameId"); + if (sgi && !strcmp(sgi, "3600700")) + { + FIXME("HACK: not applying gamma.\n"); + return DD_OK; + } + } + wined3d_mutex_lock(); if (surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) { diff --git a/dlls/devenum/createdevenum.c b/dlls/devenum/createdevenum.c index bc91b2358047..16a2dcc565b0 100644 --- a/dlls/devenum/createdevenum.c +++ b/dlls/devenum/createdevenum.c @@ -473,7 +473,7 @@ static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, cons static const WCHAR defaultW[] = L"Default DirectSound Device"; IPropertyBag *prop_bag = NULL; REGFILTERPINS2 rgpins = {0}; - REGPINTYPES rgtypes = {0}; + REGPINTYPES rgtypes[2] = {}; REGFILTER2 rgf = {0}; WCHAR clsid[CHARS_IN_GUID]; VARIANT var; @@ -504,10 +504,12 @@ static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, cons rgf.rgPins2 = &rgpins; rgpins.dwFlags = REG_PINFLAG_B_RENDERER; /* FIXME: native registers many more formats */ - rgpins.nMediaTypes = 1; - rgpins.lpMediaType = &rgtypes; - rgtypes.clsMajorType = &MEDIATYPE_Audio; - rgtypes.clsMinorType = &MEDIASUBTYPE_PCM; + rgpins.nMediaTypes = 2; + rgpins.lpMediaType = rgtypes; + rgtypes[0].clsMajorType = &MEDIATYPE_Audio; + rgtypes[0].clsMinorType = &MEDIASUBTYPE_PCM; + rgtypes[1].clsMajorType = &MEDIATYPE_Audio; + rgtypes[1].clsMinorType = &MEDIASUBTYPE_IEEE_FLOAT; write_filter_data(prop_bag, &rgf); diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index eb38bbe4ee93..62365f0b3231 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -375,6 +375,7 @@ static DWORD WINAPI dinput_thread_proc( void *params ) MSG msg; SetThreadDescription( GetCurrentThread(), L"wine_dinput_worker" ); + SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); di_em_win = CreateWindowW( L"DIEmWin", L"DIEmWin", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, DINPUT_instance, NULL ); input_thread_state = &state; @@ -508,6 +509,8 @@ void check_dinput_events(void) MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, 0); } +HANDLE steam_overlay_event; + BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved ) { TRACE( "inst %p, reason %lu, reserved %p.\n", inst, reason, reserved ); @@ -516,12 +519,14 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved ) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(inst); + steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); DINPUT_instance = inst; register_di_em_win_class(); break; case DLL_PROCESS_DETACH: if (reserved) break; unregister_di_em_win_class(); + CloseHandle(steam_overlay_event); break; } return TRUE; diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index 0609b816b3b5..433dfcf949d1 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -46,6 +46,7 @@ struct dinput extern const IDirectInput7AVtbl dinput7_a_vtbl; extern const IDirectInput8AVtbl dinput8_a_vtbl; +extern HANDLE steam_overlay_event; extern void dinput_internal_addref( struct dinput *dinput ); extern void dinput_internal_release( struct dinput *dinput ); diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 367d6356195f..2f321fd471b5 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -47,6 +47,9 @@ #include "wine/debug.h" #include "wine/hid.h" +#define VID_LOGITECH 0x046D +#define PID_LOGITECH_G920 0xC262 + WINE_DEFAULT_DEBUG_CHANNEL(dinput); DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x47,0x67,0x50,0xc5,0xe1,0xa6 ); @@ -69,8 +72,8 @@ struct pid_effect_update UINT axis_count; UINT direction_coll; UINT direction_count; - struct hid_value_caps *axis_caps[6]; - struct hid_value_caps *direction_caps[6]; + struct hid_value_caps *axis_caps[MAX_PID_AXES]; + struct hid_value_caps *direction_caps[MAX_PID_AXES]; struct hid_value_caps *duration_caps; struct hid_value_caps *gain_caps; struct hid_value_caps *sample_period_caps; @@ -172,6 +175,7 @@ struct pid_effect_state struct hid_joystick { struct dinput_device base; + BOOL wgi_device; HANDLE device; OVERLAPPED read_ovl; @@ -221,11 +225,11 @@ struct hid_joystick_effect struct list entry; struct hid_joystick *joystick; - DWORD axes[6]; - LONG directions[6]; + DWORD axes[MAX_PID_AXES]; + LONG directions[MAX_PID_AXES]; DICONSTANTFORCE constant_force; DIRAMPFORCE ramp_force; - DICONDITION condition[6]; + DICONDITION condition[MAX_PID_AXES]; DIENVELOPE envelope; DIPERIODIC periodic; DIEFFECT params; @@ -239,6 +243,51 @@ struct hid_joystick_effect char *set_envelope_buf; }; +struct joystick_device +{ + WCHAR device_path[MAX_PATH]; +}; + +static CRITICAL_SECTION joystick_devices_crit; +static CRITICAL_SECTION_DEBUG joystick_devices_crit_debug = +{ + 0, 0, &joystick_devices_crit, + { &joystick_devices_crit_debug.ProcessLocksList, &joystick_devices_crit_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": joystick_devices_crit") } +}; +static CRITICAL_SECTION joystick_devices_crit = { &joystick_devices_crit_debug, -1, 0, 0, 0, 0 }; + +static struct joystick_device *joystick_devices; +static unsigned int joystick_device_count; + +static unsigned int get_joystick_index( const WCHAR *device_path ) +{ + unsigned int i; + + EnterCriticalSection( &joystick_devices_crit ); + for (i = 0; i < joystick_device_count; ++i) + if (!wcsicmp( joystick_devices[i].device_path, device_path )) break; + + if (i == joystick_device_count) + { + ++joystick_device_count; + joystick_devices = realloc( joystick_devices, sizeof(*joystick_devices) * joystick_device_count ); + wcscpy( joystick_devices[i].device_path, device_path ); + } + LeaveCriticalSection( &joystick_devices_crit ); + return i; +} + +static BOOL get_default_joystick_device_path( WCHAR *device_path ) +{ + BOOL ret; + + EnterCriticalSection( &joystick_devices_crit ); + if ((ret = !!joystick_device_count)) wcscpy( device_path, joystick_devices[0].device_path ); + LeaveCriticalSection( &joystick_devices_crit ); + return ret; +} + static inline struct hid_joystick_effect *impl_from_IDirectInputEffect( IDirectInputEffect *iface ) { return CONTAINING_RECORD( iface, struct hid_joystick_effect, IDirectInputEffect_iface ); @@ -416,6 +465,9 @@ static const WCHAR *object_usage_to_string( DIDEVICEOBJECTINSTANCEW *instance ) case MAKELONG(PID_USAGE_STATE_REPORT, HID_USAGE_PAGE_PID): return L"PID State Report"; case MAKELONG(PID_USAGE_TRIGGER_BUTTON, HID_USAGE_PAGE_PID): return L"Trigger Button"; + case MAKELONG(PID_USAGE_SET_CONSTANT_FORCE_REPORT, HID_USAGE_PAGE_PID): return L"Set Constant Force Report"; + case MAKELONG(PID_USAGE_SET_RAMP_FORCE_REPORT, HID_USAGE_PAGE_PID): return L"Set Ramp Force Report"; + case MAKELONG(HID_USAGE_SIMULATION_RUDDER, HID_USAGE_PAGE_SIMULATION): return L"Rudder"; case MAKELONG(HID_USAGE_SIMULATION_THROTTLE, HID_USAGE_PAGE_SIMULATION): return L"Throttle"; case MAKELONG(HID_USAGE_SIMULATION_ACCELERATOR, HID_USAGE_PAGE_SIMULATION): return L"Accelerator"; @@ -540,6 +592,8 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, struct hid_collection_node *node, *node_end; WORD version = impl->base.dinput->dwVersion; BOOL ret, seen_axis[6] = {0}; + const GUID *hack_guid; + const WCHAR *hack_name; const WCHAR *tmp; button_ofs += impl->caps.NumberInputValueCaps * sizeof(LONG); @@ -559,6 +613,8 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, value_ofs += (caps->usage_max - caps->usage_min + 1) * sizeof(LONG); else for (j = caps->usage_min; j <= caps->usage_max; ++j) { + hack_name = NULL; + hack_guid = NULL; instance.dwOfs = value_ofs; switch (MAKELONG(j, caps->usage_page)) { @@ -568,7 +624,38 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, case MAKELONG(HID_USAGE_GENERIC_RX, HID_USAGE_PAGE_GENERIC): case MAKELONG(HID_USAGE_GENERIC_RY, HID_USAGE_PAGE_GENERIC): case MAKELONG(HID_USAGE_GENERIC_RZ, HID_USAGE_PAGE_GENERIC): - set_axis_type( &instance, seen_axis, j - HID_USAGE_GENERIC_X, &axis ); + if (!impl->wgi_device && impl->attrs.VendorID == VID_LOGITECH && impl->attrs.ProductID == PID_LOGITECH_G920) + { + if (j == HID_USAGE_GENERIC_X) + { + set_axis_type( &instance, seen_axis, 0, &axis ); + hack_guid = &GUID_XAxis; + hack_name = L"Wheel axis"; + } + else if (j == HID_USAGE_GENERIC_Y) + { + set_axis_type( &instance, seen_axis, 2, &axis ); + hack_guid = &GUID_YAxis; + hack_name = L"Accelerator"; + } + else if (j == HID_USAGE_GENERIC_Z) + { + set_axis_type( &instance, seen_axis, 5, &axis ); + hack_guid = &GUID_RzAxis; + hack_name = L"Brake"; + } + else if (j == HID_USAGE_GENERIC_RZ) + { + instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 6 + axis++ ); + hack_guid = &GUID_Slider; + hack_name = L"Clutch"; + } + else WARN("unknown axis usage page %x usage %lx for Logitech G920\n", caps->usage_page, j); + } + else + { + set_axis_type( &instance, seen_axis, j - HID_USAGE_GENERIC_X, &axis ); + } instance.dwFlags = DIDOI_ASPECTPOSITION; break; case MAKELONG(HID_USAGE_SIMULATION_STEERING, HID_USAGE_PAGE_SIMULATION): @@ -605,12 +692,16 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, } instance.wUsagePage = caps->usage_page; instance.wUsage = j; - instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); + if (hack_guid) + instance.guidType = *hack_guid; + else + instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); instance.wReportId = caps->report_id; instance.wCollectionNumber = caps->link_collection; instance.dwDimension = caps->units; instance.wExponent = caps->units_exp; - if ((tmp = object_usage_to_string( &instance ))) lstrcpynW( instance.tszName, tmp, MAX_PATH ); + if (hack_name) lstrcpynW( instance.tszName, hack_name, MAX_PATH ); + else if ((tmp = object_usage_to_string( &instance ))) lstrcpynW( instance.tszName, tmp, MAX_PATH ); else swprintf( instance.tszName, MAX_PATH, L"Unknown %u", DIDFT_GETINSTANCE( instance.dwType ) ); check_pid_effect_axis_caps( impl, &instance ); ret = enum_object( impl, filter, flags, callback, object, caps, &instance, data ); @@ -749,22 +840,10 @@ static void set_report_value( struct hid_joystick *impl, char *report_buf, { ULONG report_len = impl->caps.OutputReportByteLength; PHIDP_PREPARSED_DATA preparsed = impl->preparsed; - LONG log_min, log_max, phy_min, phy_max; NTSTATUS status; if (!caps) return; - log_min = caps->logical_min; - log_max = caps->logical_max; - phy_min = caps->physical_min; - phy_max = caps->physical_max; - - if (phy_max || phy_min) - { - if (value > phy_max || value < phy_min) value = -1; - else value = log_min + (value - phy_min) * (log_max - log_min) / (phy_max - phy_min); - } - status = HidP_SetUsageValue( HidP_Output, caps->usage_page, caps->link_collection, caps->usage_min, value, preparsed, report_buf, report_len ); if (status != HIDP_STATUS_SUCCESS) WARN( "HidP_SetUsageValue %04x:%04x returned %#lx\n", @@ -814,13 +893,23 @@ static HRESULT hid_joystick_get_property( IDirectInputDevice8W *iface, DWORD pro case (DWORD_PTR)DIPROP_JOYSTICKID: { DIPROPDWORD *value = (DIPROPDWORD *)header; - value->dwData = impl->base.instance.guidInstance.Data3; + value->dwData = get_joystick_index( impl->device_path ); return DI_OK; } case (DWORD_PTR)DIPROP_GUIDANDPATH: { DIPROPGUIDANDPATH *value = (DIPROPGUIDANDPATH *)header; value->guidClass = GUID_DEVCLASS_HIDCLASS; + + /* CW-Bug-Id: #23185 Emulate Steam Input native hooks for native SDL */ + if (impl->attrs.VendorID == 0x28de && impl->attrs.ProductID == 0x11ff) + { + const WCHAR *tmp; + if ((tmp = wcschr( impl->device_path, '#' ))) tmp = wcschr( tmp + 1, '#' ); + lstrcpynW( value->wszPath, impl->device_path, tmp - impl->device_path + 1 ); + return DI_OK; + } + lstrcpynW( value->wszPath, impl->device_path, MAX_PATH ); return DI_OK; } @@ -837,6 +926,37 @@ static HRESULT hid_joystick_get_property( IDirectInputDevice8W *iface, DWORD pro return DIERR_UNSUPPORTED; } +static LONG scale_to_logical_value( LONG value, struct hid_value_caps *caps ) +{ + LONG log_min, log_max, phy_min, phy_max; + + if (!caps) return value; + + log_min = caps->logical_min; + log_max = caps->logical_max; + phy_min = caps->physical_min; + phy_max = caps->physical_max; + + if (phy_max || phy_min) + { + if (value > phy_max || value < phy_min) value = -1; + else value = log_min + (value - phy_min) * (log_max - log_min) / (phy_max - phy_min); + } + + return value; +} + +static LONG clamp_to_physical_value( LONG value, struct hid_value_caps *caps ) +{ + LONG phy_min, phy_max; + + if (!caps) return value; + + phy_min = caps->physical_min; + phy_max = caps->physical_max; + return max( min( value, phy_max ), phy_min ); +} + static HRESULT hid_joystick_send_device_gain( IDirectInputDevice8W *iface, LONG device_gain ) { struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); @@ -852,6 +972,8 @@ static HRESULT hid_joystick_send_device_gain( IDirectInputDevice8W *iface, LONG status = HidP_InitializeReportForID( HidP_Output, report->id, impl->preparsed, report_buf, report_len ); if (status != HIDP_STATUS_SUCCESS) return status; + device_gain = clamp_to_physical_value( device_gain, report->device_gain_caps ); + device_gain = scale_to_logical_value( device_gain, report->device_gain_caps ); set_report_value( impl, report_buf, report->device_gain_caps, device_gain ); if (!WriteFile( impl->device, report_buf, report_len, NULL, NULL )) return DIERR_INPUTLOST; @@ -1101,6 +1223,7 @@ struct parse_device_state_params { BYTE old_state[DEVICE_STATE_MAX_SIZE]; BYTE buttons[128]; + BOOL reset_state; DWORD time; DWORD seq; }; @@ -1116,6 +1239,8 @@ static BOOL check_device_state_button( struct dinput_device *device, UINT index, value = params->buttons[instance->wUsage - 1]; old_value = params->old_state[instance->dwOfs]; + if (params->reset_state) value = 0; + device->device_state[instance->dwOfs] = value; if (old_value != value) queue_event( iface, index, value, params->time, params->seq ); @@ -1201,6 +1326,16 @@ static BOOL read_device_state_value( struct dinput_device *device, UINT index, s if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, properties ); else value = scale_value( logical_value, properties ); + if (params->reset_state) + { + if (instance->dwType & DIDFT_POV) value = -1; + else if (instance->dwType & DIDFT_AXIS) + { + if (!properties->range_min) value = properties->range_max / 2; + else value = round( (properties->range_min + properties->range_max) / 2.0 ); + } + } + old_value = *(LONG *)(params->old_state + instance->dwOfs); *(LONG *)(impl->base.device_state + instance->dwOfs) = value; if (old_value != value) queue_event( iface, index, value, params->time, params->seq ); @@ -1230,6 +1365,11 @@ static HRESULT hid_joystick_read( IDirectInputDevice8W *iface ) ret = GetOverlappedResult( impl->device, &impl->read_ovl, &count, FALSE ); + if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) /* steam overlay is enabled */ + params.reset_state = TRUE; + else + params.reset_state = FALSE; + EnterCriticalSection( &impl->base.crit ); while (ret) { @@ -1264,7 +1404,7 @@ static HRESULT hid_joystick_read( IDirectInputDevice8W *iface ) { usages = impl->usages_buf + count; if (usages->UsagePage != HID_USAGE_PAGE_BUTTON) - FIXME( "unimplemented usage page %x.\n", usages->UsagePage ); + WARN( "unimplemented usage page %x.\n", usages->UsagePage ); else if (usages->Usage >= 128) FIXME( "ignoring extraneous button %d.\n", usages->Usage ); else @@ -1536,6 +1676,9 @@ static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, break; } + if (attrs->VendorID == VID_LOGITECH && attrs->ProductID == PID_LOGITECH_G920) + type = DI8DEVTYPE_DRIVING | (DI8DEVTYPEDRIVING_DUALPEDALS << 8); + instance->dwDevType = device_type_for_version( type, version ) | DIDEVTYPE_HID; TRACE("detected device type %#lx\n", instance->dwDevType); @@ -1602,6 +1745,8 @@ static HRESULT hid_joystick_device_open( int index, const GUID *guid, DIDEVICEIN attrs, caps, instance, version ))) continue; } + /* Assign joystick index if the device path is first seen. */ + get_joystick_index( detail->DevicePath ); /* enumerate device by GUID */ if (IsEqualGUID( guid, &instance->guidProduct ) || IsEqualGUID( guid, &instance->guidInstance )) break; @@ -1828,7 +1973,7 @@ static BOOL init_pid_caps( struct dinput_device *device, UINT index, struct hid_ if (instance->wCollectionNumber == effect_update->axes_coll) { SET_REPORT_ID( effect_update ); - if (effect_update->axis_count >= 6) FIXME( "more than 6 PID axes detected\n" ); + if (effect_update->axis_count >= MAX_PID_AXES) FIXME( "more than %d PID axes detected\n", MAX_PID_AXES ); else effect_update->axis_caps[effect_update->axis_count] = caps; effect_update->axis_count++; } @@ -1837,7 +1982,7 @@ static BOOL init_pid_caps( struct dinput_device *device, UINT index, struct hid_ SET_REPORT_ID( effect_update ); caps->physical_min = 0; caps->physical_max = 35900; - if (effect_update->direction_count >= 6) FIXME( "more than 6 PID directions detected\n" ); + if (effect_update->direction_count >= MAX_PID_AXES) FIXME( "more than %d PID directions detected\n", MAX_PID_AXES ); else effect_update->direction_caps[effect_update->direction_count] = caps; effect_update->direction_count++; } @@ -2018,10 +2163,18 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi impl->base.read_event = CreateEventW( NULL, TRUE, FALSE, NULL ); if (memcmp( device_path_guid.Data4, guid->Data4, sizeof(device_path_guid.Data4) )) + { + /* Let hid_joystick_device_open() populate joystick devices before checking for default joystick GUID. */ hr = hid_joystick_device_open( -1, guid, &impl->base.instance, impl->device_path, &impl->device, &impl->preparsed, &attrs, &impl->caps, dinput->dwVersion ); + if (hr == DIERR_DEVICENOTREG && IsEqualGUID( guid, &GUID_Joystick ) + && get_default_joystick_device_path( impl->device_path )) + hr = hid_joystick_device_try_open( impl->device_path, &impl->device, &impl->preparsed, &attrs, + &impl->caps, &impl->base.instance, dinput->dwVersion ); + } else { + impl->wgi_device = TRUE; wcscpy( impl->device_path, *(const WCHAR **)guid ); hr = hid_joystick_device_try_open( impl->device_path, &impl->device, &impl->preparsed, &attrs, &impl->caps, &impl->base.instance, dinput->dwVersion ); @@ -2350,7 +2503,7 @@ static void convert_directions_from_spherical( const DIEFFECT *in, DIEFFECT *out static void convert_directions( const DIEFFECT *in, DIEFFECT *out ) { DWORD direction_flags = DIEFF_CARTESIAN | DIEFF_POLAR | DIEFF_SPHERICAL; - LONG directions[6] = {0}; + LONG directions[MAX_PID_AXES] = {0}; DIEFFECT spherical = {.rglDirection = directions}; switch (in->dwFlags & direction_flags) @@ -2810,9 +2963,17 @@ static HRESULT WINAPI hid_joystick_effect_GetEffectStatus( IDirectInputEffect *i static void set_parameter_value( struct hid_joystick_effect *impl, char *report_buf, struct hid_value_caps *caps, LONG value ) { + value = scale_to_logical_value( value, caps ); return set_report_value( impl->joystick, report_buf, caps, value ); } +static void set_parameter_value_clamp( struct hid_joystick_effect *impl, char *report_buf, + struct hid_value_caps *caps, LONG value ) +{ + value = clamp_to_physical_value( value, caps ); + return set_parameter_value( impl, report_buf, caps, value ); +} + static void set_parameter_value_angle( struct hid_joystick_effect *impl, char *report_buf, struct hid_value_caps *caps, LONG value ) { @@ -2822,19 +2983,23 @@ static void set_parameter_value_angle( struct hid_joystick_effect *impl, char *r if (caps->units != 0x14) WARN( "unknown angle unit caps %#lx\n", caps->units ); else if (exp < -2) while (exp++ < -2) value *= 10; else if (exp > -2) while (exp-- > -2) value /= 10; - set_parameter_value( impl, report_buf, caps, value ); + set_parameter_value_clamp( impl, report_buf, caps, value ); } static void set_parameter_value_us( struct hid_joystick_effect *impl, char *report_buf, struct hid_value_caps *caps, LONG value ) { LONG exp; + if (!caps) return; + if (value == INFINITE) return set_report_value( impl->joystick, report_buf, caps, caps->physical_min - 1 ); + exp = caps->units_exp; - if (value == INFINITE) value = caps->physical_min - 1; - else if (caps->units != 0x1003) WARN( "unknown time unit caps %#lx\n", caps->units ); + if (caps->units != 0x1003) WARN( "unknown time unit caps %#lx\n", caps->units ); else if (exp < -6) while (exp++ < -6) value *= 10; else if (exp > -6) while (exp-- > -6) value /= 10; + + /* testing shows that duration values are not clamped, any out-of-range values becomes -1 */ set_parameter_value( impl, report_buf, caps, value ); } @@ -2858,7 +3023,7 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) ULONG report_len = impl->joystick->caps.OutputReportByteLength; HANDLE device = impl->joystick->device; struct hid_value_caps *caps; - LONG directions[4] = {0}; + LONG directions[MAX_PID_AXES] = {0}; DWORD i, tmp, count; DIEFFECT spherical; NTSTATUS status; @@ -2904,14 +3069,14 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) case PID_USAGE_ET_SAWTOOTH_DOWN: if (!(impl->modified & DIEP_TYPESPECIFICPARAMS)) break; - set_parameter_value( impl, impl->type_specific_buf, set_periodic->magnitude_caps, - impl->periodic.dwMagnitude ); + set_parameter_value_clamp( impl, impl->type_specific_buf, set_periodic->magnitude_caps, + impl->periodic.dwMagnitude ); set_parameter_value_us( impl, impl->type_specific_buf, set_periodic->period_caps, impl->periodic.dwPeriod ); - set_parameter_value( impl, impl->type_specific_buf, set_periodic->phase_caps, - impl->periodic.dwPhase ); - set_parameter_value( impl, impl->type_specific_buf, set_periodic->offset_caps, - impl->periodic.lOffset ); + set_parameter_value_clamp( impl, impl->type_specific_buf, set_periodic->phase_caps, + impl->periodic.dwPhase ); + set_parameter_value_clamp( impl, impl->type_specific_buf, set_periodic->offset_caps, + impl->periodic.lOffset ); if (!WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DIERR_INPUTLOST; else impl->modified &= ~DIEP_TYPESPECIFICPARAMS; @@ -2928,18 +3093,21 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) i, impl->joystick->preparsed, impl->type_specific_buf, report_len ); if (status != HIDP_STATUS_SUCCESS) WARN( "HidP_SetUsageValue %04x:%04x returned %#lx\n", HID_USAGE_PAGE_PID, PID_USAGE_PARAMETER_BLOCK_OFFSET, status ); - set_parameter_value( impl, impl->type_specific_buf, set_condition->center_point_offset_caps, - impl->condition[i].lOffset ); - set_parameter_value( impl, impl->type_specific_buf, set_condition->positive_coefficient_caps, - impl->condition[i].lPositiveCoefficient ); - set_parameter_value( impl, impl->type_specific_buf, set_condition->negative_coefficient_caps, - impl->condition[i].lNegativeCoefficient ); + set_parameter_value_clamp( impl, impl->type_specific_buf, set_condition->center_point_offset_caps, + impl->condition[i].lOffset ); + set_parameter_value_clamp( impl, impl->type_specific_buf, set_condition->positive_coefficient_caps, + impl->condition[i].lPositiveCoefficient ); + set_parameter_value_clamp( impl, impl->type_specific_buf, set_condition->negative_coefficient_caps, + impl->condition[i].lNegativeCoefficient ); + + /* testing shows that saturation values are not clamped, any out-of-range values becomes -1 */ set_parameter_value( impl, impl->type_specific_buf, set_condition->positive_saturation_caps, impl->condition[i].dwPositiveSaturation ); set_parameter_value( impl, impl->type_specific_buf, set_condition->negative_saturation_caps, impl->condition[i].dwNegativeSaturation ); - set_parameter_value( impl, impl->type_specific_buf, set_condition->dead_band_caps, - impl->condition[i].lDeadBand ); + + set_parameter_value_clamp( impl, impl->type_specific_buf, set_condition->dead_band_caps, + impl->condition[i].lDeadBand ); if (!WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DIERR_INPUTLOST; else impl->modified &= ~DIEP_TYPESPECIFICPARAMS; @@ -2948,8 +3116,8 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) case PID_USAGE_ET_CONSTANT_FORCE: if (!(impl->modified & DIEP_TYPESPECIFICPARAMS)) break; - set_parameter_value( impl, impl->type_specific_buf, set_constant_force->magnitude_caps, - impl->constant_force.lMagnitude ); + set_parameter_value_clamp( impl, impl->type_specific_buf, set_constant_force->magnitude_caps, + impl->constant_force.lMagnitude ); if (!WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DIERR_INPUTLOST; else impl->modified &= ~DIEP_TYPESPECIFICPARAMS; @@ -2957,10 +3125,10 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) case PID_USAGE_ET_RAMP: if (!(impl->modified & DIEP_TYPESPECIFICPARAMS)) break; - set_parameter_value( impl, impl->type_specific_buf, set_ramp_force->start_caps, - impl->ramp_force.lStart ); - set_parameter_value( impl, impl->type_specific_buf, set_ramp_force->end_caps, - impl->ramp_force.lEnd ); + set_parameter_value_clamp( impl, impl->type_specific_buf, set_ramp_force->start_caps, + impl->ramp_force.lStart ); + set_parameter_value_clamp( impl, impl->type_specific_buf, set_ramp_force->end_caps, + impl->ramp_force.lEnd ); if (!WriteFile( device, impl->type_specific_buf, report_len, NULL, NULL )) hr = DIERR_INPUTLOST; else impl->modified &= ~DIEP_TYPESPECIFICPARAMS; @@ -2982,12 +3150,12 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) if (!(impl->flags & DIEP_ENVELOPE)) break; if (!(impl->modified & DIEP_ENVELOPE)) break; - set_parameter_value( impl, impl->set_envelope_buf, set_envelope->attack_level_caps, - impl->envelope.dwAttackLevel ); + set_parameter_value_clamp( impl, impl->set_envelope_buf, set_envelope->attack_level_caps, + impl->envelope.dwAttackLevel ); set_parameter_value_us( impl, impl->set_envelope_buf, set_envelope->attack_time_caps, impl->envelope.dwAttackTime ); - set_parameter_value( impl, impl->set_envelope_buf, set_envelope->fade_level_caps, - impl->envelope.dwFadeLevel ); + set_parameter_value_clamp( impl, impl->set_envelope_buf, set_envelope->fade_level_caps, + impl->envelope.dwFadeLevel ); set_parameter_value_us( impl, impl->set_envelope_buf, set_envelope->fade_time_caps, impl->envelope.dwFadeTime ); @@ -3001,8 +3169,8 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) { set_parameter_value_us( impl, impl->effect_update_buf, effect_update->duration_caps, impl->params.dwDuration ); - set_parameter_value( impl, impl->effect_update_buf, effect_update->gain_caps, - impl->params.dwGain ); + set_parameter_value_clamp( impl, impl->effect_update_buf, effect_update->gain_caps, + impl->params.dwGain ); set_parameter_value_us( impl, impl->effect_update_buf, effect_update->sample_period_caps, impl->params.dwSamplePeriod ); set_parameter_value_us( impl, impl->effect_update_buf, effect_update->start_delay_caps, diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 85c0b79d70e6..52a4d9c0e257 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -50,6 +50,17 @@ struct enum_data }; }; +static void pump_messages(void) +{ + MSG msg; + + while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + } +} + static void flush_events(void) { int min_timeout = 100, diff = 200; @@ -1769,13 +1780,121 @@ static void test_hid_mouse(void) static UINT pointer_enter_count; static UINT pointer_up_count; -static HANDLE touchdown_event, touchleave_event; +static HANDLE touchdown_event, touchmoved_event, touchleave_event; static WPARAM pointer_wparam[16]; static WPARAM pointer_lparam[16]; static UINT pointer_count; +static int touch_test_line; +static POINT last_cursor_pos; +static const BOOL *skip_defwnd_for_pointer_message; +BOOL skip_touch_mouse_tests, touch_missing_leave_todo; + +#define start_touch_test(a) start_touch_test_( __LINE__, a ) +static void start_touch_test_( int line, const BOOL *skip_defwnd ) +{ + pointer_enter_count = pointer_up_count = pointer_count = 0; + memset( pointer_wparam, 0, sizeof(pointer_wparam) ); + memset( pointer_lparam, 0, sizeof(pointer_lparam) ); + + skip_defwnd_for_pointer_message = skip_defwnd; + SetCursorPos( 0, 0 ); + GetCursorPos( &last_cursor_pos ); + touch_test_line = line; +} + +static BOOL get_touch_mouse_message( HWND hwnd, MSG *msg ) +{ + while (PeekMessageW( msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE )) + { + if (msg->message != WM_MOUSEMOVE || (GetMessageExtraInfo() & ~(ULONG_PTR)0xff) == 0xff515700) return TRUE; + } + return FALSE; +} + +static BOOL touch_mouse_message_matches( UINT msg, UINT expect_msg ) +{ + /* Pointer quick up / downs, holds are used to simulate right mouse button and double clicks on Windows. That + * is randomly triggered with the tests. Since currently that is neither avoided nor consciously emulated + * in tests just accept that all. */ + if (expect_msg == WM_LBUTTONDOWN) + return msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_LBUTTONDBLCLK; + if (expect_msg == WM_LBUTTONUP) + return msg == WM_LBUTTONUP || msg == WM_RBUTTONUP; + return msg == expect_msg; +} + +#define expect_touch_mouse_message(a, b, c) expect_touch_mouse_message_( __LINE__, a, b, c ) +static BOOL expect_touch_mouse_message_( int line, HWND hwnd, UINT expect_msg, BOOL optional ) +{ + INPUT_MESSAGE_SOURCE source; + LPARAM extra; + DWORD pos; + BOOL bret; + POINT cp; + MSG msg; + + if (skip_touch_mouse_tests) return TRUE; + + if (!(bret = get_touch_mouse_message( hwnd, &msg )) && !optional) + { + MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_MOUSE ); + bret = get_touch_mouse_message( hwnd, &msg ); + } + + if (!optional) + ok_(__FILE__, line)( bret, "did not receive mouse message, expected %#x.\n", expect_msg ); + if (!bret) return FALSE; + + if (optional && !touch_mouse_message_matches( msg.message, expect_msg )) + { + trace_(__FILE__, line)( "got message %#x instead of optional %#x.\n", msg.message, expect_msg ); + return FALSE; + } + + ok_(__FILE__, line)( touch_mouse_message_matches( msg.message, expect_msg ), + "got message %#x, expected %#x.\n", msg.message, expect_msg ); + + bret = GetCurrentInputMessageSource( &source ); + ok_(__FILE__, line)( bret, "got error %ld.\n", GetLastError() ); + ok_(__FILE__, line)( source.deviceType == IMDT_TOUCH, "got deviceType %#x, expected %#x.\n", + source.deviceType, IMDT_TOUCH ); + ok_(__FILE__, line)( source.originId == IMO_HARDWARE, "got originId %#x, expected %#x.\n", + source.originId, IMO_HARDWARE ); + + cp = last_cursor_pos; + pos = msg.lParam; + ok_(__FILE__, line)( pos == MAKELPARAM(cp.x, cp.y), "got coords (%d, %d), expected (%ld, %ld).\n", + LOWORD(pos), HIWORD(pos), cp.x, cp.y ); + pos = GetMessagePos(); + ok_(__FILE__, line)( pos == MAKELPARAM(cp.x, cp.y), "got coords (%d, %d), expected (%ld, %ld).\n", + LOWORD(pos), HIWORD(pos), cp.x, cp.y ); + + extra = GetMessageExtraInfo(); + ok_(__FILE__, line)( (extra & ~(ULONG_PTR)0xff) == 0xff515700, "got message extra info %#Ix, expected %#x.\n", + extra, 0xff515700 ); + return TRUE; +} static LRESULT CALLBACK touch_screen_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { + static struct + { + UINT pointerid; + BOOL tracking_started; + POINT curr_pos; + } + state[64]; + static unsigned int active_touch_count, total_touch_count; + + BOOL pointer_moved, curpos_changed; + UINT expect_message_after; + unsigned int i; + UINT pointerid; + LRESULT ret; + MSG message; + BOOL bret; + POINT pt; + if (msg == WM_POINTERENTER) { pointer_wparam[pointer_count] = wparam; @@ -1783,8 +1902,6 @@ static LRESULT CALLBACK touch_screen_wndproc( HWND hwnd, UINT msg, WPARAM wparam pointer_count++; pointer_enter_count++; } - if (msg == WM_POINTERDOWN) ReleaseSemaphore( touchdown_event, 1, NULL ); - if (msg == WM_POINTERUP) { pointer_wparam[pointer_count] = wparam; @@ -1792,9 +1909,182 @@ static LRESULT CALLBACK touch_screen_wndproc( HWND hwnd, UINT msg, WPARAM wparam pointer_count++; pointer_up_count++; } - if (msg == WM_POINTERLEAVE) ReleaseSemaphore( touchleave_event, 1, NULL ); - return DefWindowProcW( hwnd, msg, wparam, lparam ); + if (!skip_touch_mouse_tests && msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) + { + INPUT_MESSAGE_SOURCE source; + GetCurrentInputMessageSource( &source ); + ok( source.deviceType != IMDT_TOUCH, "got touch mouse message %#x outside of state tracking.\n", msg ); + } + + if (!(msg >= WM_POINTERUPDATE && msg <= WM_POINTERLEAVE)) + return DefWindowProcW( hwnd, msg, wparam, lparam ); + + pointerid = GET_POINTERID_WPARAM( wparam ); + winetest_push_context( "line %d, pointer msg %#x, wp %#Ix, lp %#Ix, pointerid %#x", + touch_test_line, msg, wparam, lparam, pointerid ); + for (i = 0; i < ARRAY_SIZE(state); ++i) + { + if (state[i].pointerid == pointerid) break; + } + if (msg == WM_POINTERENTER) + { + todo_wine_if(touch_missing_leave_todo) ok( i == ARRAY_SIZE(state), "Duplicate WM_POINTERDOWN for id %#x.\n", pointerid ); + touch_missing_leave_todo = FALSE; + if (i == ARRAY_SIZE(state)) + { + for (i = 0; i < ARRAY_SIZE(state); ++i) + { + if (!state[i].pointerid) break; + } + } + else + { + ok( active_touch_count == 1, "got %u.\n", active_touch_count ); + ok( total_touch_count == 1, "got %u.\n", total_touch_count ); + if (!--active_touch_count) total_touch_count = 0; + } + ok( i < ARRAY_SIZE(state), "No free space in state table.\n" ); + state[i].pointerid = pointerid; + state[i].tracking_started = FALSE; + state[i].curr_pos.x = LOWORD(lparam); + state[i].curr_pos.y = HIWORD(lparam); + ++active_touch_count; + ++total_touch_count; + } + else if (msg != WM_POINTERLEAVE) + { + ok( i < ARRAY_SIZE(state), "Missed WM_POINTERDOWN for id %#x.\n", pointerid ); + } + + pointer_moved = LOWORD(lparam) != state[i].curr_pos.x || HIWORD(lparam) != state[i].curr_pos.y; + curpos_changed = LOWORD(lparam) != last_cursor_pos.x || HIWORD(lparam) != last_cursor_pos.y; + expect_message_after = 0; + + if (winetest_debug > 1) + trace( "msg %#x, msgpos (%d, %d), tracking %d, t %ld, pointer_moved %d, curpos_changed %d.\n", + msg, LOWORD(lparam), HIWORD(lparam), state[i].tracking_started, GetTickCount(), + pointer_moved, curpos_changed); + + if (state[i].tracking_started) + { + if (msg == WM_POINTERUPDATE && (pointer_moved || curpos_changed) + && active_touch_count && total_touch_count == 1) + { + state[i].curr_pos.x = LOWORD(lparam); + state[i].curr_pos.y = HIWORD(lparam); + last_cursor_pos = state[i].curr_pos; + expect_touch_mouse_message( hwnd, WM_MOUSEMOVE, FALSE ); + } + else if (msg == WM_POINTERUP) + { + if (pointer_moved || curpos_changed) + { + state[i].curr_pos.x = LOWORD(lparam); + state[i].curr_pos.y = HIWORD(lparam); + last_cursor_pos = state[i].curr_pos; + expect_touch_mouse_message( hwnd, WM_MOUSEMOVE, FALSE ); + } + if (!expect_touch_mouse_message( hwnd, WM_LBUTTONUP, TRUE )) + { + /* This message arrives here most of the time, but sometimes it is delayed until after DefWindowProc + * call, maybe based on timing between WM_POINTERUPDATE which changed the position first time + * and WM_POINTERUP. */ + expect_message_after = WM_LBUTTONUP; + } + } + } + else + { + if (!skip_touch_mouse_tests) do + { + bret = get_touch_mouse_message( hwnd, &message ); + + ok( !bret, "got mouse message before DefWindowProc, msg %#x, wp %#Ix, lp %#Ix.\n", + message.message, message.wParam, message.lParam ); + } while (bret); + } + + if (skip_defwnd_for_pointer_message && skip_defwnd_for_pointer_message[msg - WM_POINTERUPDATE]) + { + ret = 0; + } + else + { + /* The handling in DefWindowProc() doesn't depend on pointer flags in wparam and position in lparam */ + ret = DefWindowProcW( hwnd, msg, LOWORD(wparam), 0 ); + ok( !ret, "got %Id from DefWindowProcW.\n", ret ); + + if (skip_defwnd_for_pointer_message && skip_defwnd_for_pointer_message[WM_POINTERDOWN - WM_POINTERUPDATE]) + { + /* No mouse messages al all if DefWindowProcW() wasn't called for WM_POINTERDOWN. */ + } + else if (msg == WM_POINTERUPDATE && pointer_moved && !state[i].tracking_started && active_touch_count && total_touch_count == 1) + { + last_cursor_pos = state[i].curr_pos; + expect_touch_mouse_message( hwnd, WM_MOUSEMOVE, FALSE ); + state[i].curr_pos.x = LOWORD(lparam); + state[i].curr_pos.y = HIWORD(lparam); + if (!state[i].tracking_started) + { + state[i].tracking_started = TRUE; + expect_touch_mouse_message( hwnd, WM_LBUTTONDOWN, FALSE ); + last_cursor_pos = state[i].curr_pos; + expect_touch_mouse_message( hwnd, WM_MOUSEMOVE, FALSE ); + } + } + else if (msg == WM_POINTERUP && active_touch_count == 1 && total_touch_count == 1) + { + if (!state[i].tracking_started) + { + last_cursor_pos = state[i].curr_pos; + if (!expect_touch_mouse_message( hwnd, WM_MOUSEMOVE, TRUE )) + { + /* A lot of details go different before Win10, so don't perform the rest of mouse message tests. */ + win_skip( "Old behaviour detected, skipping remaining mouse tracking tests.\n" ); + skip_touch_mouse_tests = TRUE; + } + expect_touch_mouse_message( hwnd, WM_LBUTTONDOWN, FALSE ); + expect_touch_mouse_message( hwnd, WM_LBUTTONUP, FALSE ); + } + } + + if (!skip_touch_mouse_tests) + { + GetCursorPos( &pt ); + /* This is flaky because GetCursorPos() currently periodically updated from mouse position from + * display driver. While we try to update that on mouse position update from pointer that may + * still fail. */ + flaky_wine ok( pt.x == last_cursor_pos.x && pt.y == last_cursor_pos.y, "got (%ld, %ld), expected (%ld, %ld).\n", + pt.x, pt.y, last_cursor_pos.x, last_cursor_pos.y ); + } + } + + if (expect_message_after) expect_touch_mouse_message( hwnd, expect_message_after, FALSE ); + if (msg == WM_POINTERDOWN && total_touch_count > 1) + { + /* With double touch, depending on WM_POINTERDOWN / WM_POINTERUPDATE timing, we may get mouse down message + * here (both on Windows and Wine). Then we are going to get mouse up before DefWindowProc which will be + * handled by our test state tracker with 'tracking_started' set. */ + if (expect_touch_mouse_message( hwnd, WM_LBUTTONDOWN, TRUE )) + { + trace( "Got WM_LBUTTONDOWN on WM_POINTERDOWN.\n" ); + state[i].tracking_started = TRUE; + } + } + + if (msg == WM_POINTERUP) + { + state[i].pointerid = 0; + ok( active_touch_count, "got 0.\n" ); + if (!--active_touch_count) total_touch_count = 0; + } + + winetest_pop_context(); + if (msg == WM_POINTERUPDATE && pointer_moved) SetEvent( touchmoved_event ); + if (msg == WM_POINTERDOWN) ReleaseSemaphore( touchdown_event, 1, NULL ); + if (msg == WM_POINTERLEAVE) ReleaseSemaphore( touchleave_event, 1, NULL ); + return ret; } static void test_hid_touch_screen(void) @@ -1910,6 +2200,16 @@ static void test_hid_touch_screen(void) .code = IOCTL_HID_READ_REPORT, .report_buf = {1, 1, 0x01,0x02,0x08,0x10}, }; + struct hid_expect touch_single2 = + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1, 1, 0x01,0x02,0x18,0x20}, + }; + struct hid_expect touch_single3 = + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1, 1, 0x01,0x02,0x40,0x50}, + }; struct hid_expect touch_multiple = { .code = IOCTL_HID_READ_REPORT, @@ -1928,11 +2228,26 @@ static void test_hid_touch_screen(void) .report_buf = {1,0x02}, }; + static struct + { + BOOL skip_message[5]; + } + mouse_tests[] = + { + /* WM_POINTERUPDATE, WM_POINTERDOWN, WM_POINTERUP, WM_POINTERENTER, WM_POINTERLEAVE */ + {{ FALSE }}, + {{ FALSE, TRUE }}, + {{ TRUE }}, + {{ FALSE, FALSE, TRUE }}, + {{ TRUE, FALSE, TRUE }}, + }; + RAWINPUTDEVICE rawdevice = {.usUsagePage = HID_USAGE_PAGE_DIGITIZER, .usUsage = HID_USAGE_DIGITIZER_TOUCH_SCREEN}; UINT rawbuffer_count, rawbuffer_size, expect_flags, id, width, height; WCHAR device_path[MAX_PATH]; char rawbuffer[1024]; RAWINPUT *rawinput; + unsigned int i, j; HANDLE file; DWORD res; HWND hwnd; @@ -1943,6 +2258,8 @@ static void test_hid_touch_screen(void) touchdown_event = CreateSemaphoreW( NULL, 0, LONG_MAX, NULL ); ok( !!touchdown_event, "CreateSemaphoreW failed, error %lu\n", GetLastError() ); + touchmoved_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!touchmoved_event, "CreateEventW failed, error %lu\n", GetLastError() ); touchleave_event = CreateSemaphoreW( NULL, 0, LONG_MAX, NULL ); ok( !!touchleave_event, "CreateSemaphoreW failed, error %lu\n", GetLastError() ); @@ -1986,17 +2303,13 @@ static void test_hid_touch_screen(void) /* check basic touch_screen input injection to window message */ - SetCursorPos( 0, 0 ); - hwnd = create_foreground_window( TRUE ); SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)touch_screen_wndproc ); /* a single touch is automatically released if we don't send continuous updates */ - pointer_enter_count = pointer_up_count = pointer_count = 0; - memset( pointer_wparam, 0, sizeof(pointer_wparam) ); - memset( pointer_lparam, 0, sizeof(pointer_lparam) ); + start_touch_test( NULL ); bus_send_hid_input( file, &desc, &touch_single, sizeof(touch_single) ); res = MsgWaitForMultipleObjects( 0, NULL, FALSE, 500, QS_POINTER ); @@ -2033,6 +2346,8 @@ static void test_hid_touch_screen(void) todo_wine ok( HIWORD( pointer_lparam[1] ) * 128 / height == 0x10, "got lparam %#Ix\n", pointer_lparam[1] ); + /* Wine is currently missing WM_POINTERUP generation in this case. */ + touch_missing_leave_todo = TRUE; /* test that we receive HID rawinput type with the touchscreen */ @@ -2143,9 +2458,7 @@ static void test_hid_touch_screen(void) /* now the touch is continuously updated */ - pointer_enter_count = pointer_up_count = pointer_count = 0; - memset( pointer_wparam, 0, sizeof(pointer_wparam) ); - memset( pointer_lparam, 0, sizeof(pointer_lparam) ); + start_touch_test( NULL ); bus_send_hid_input( file, &desc, &touch_single, sizeof(touch_single) ); res = msg_wait_for_events( 1, &touchdown_event, 1000 ); @@ -2194,12 +2507,14 @@ static void test_hid_touch_screen(void) pointer_enter_count = pointer_up_count = pointer_count = 0; memset( pointer_wparam, 0, sizeof(pointer_wparam) ); memset( pointer_lparam, 0, sizeof(pointer_lparam) ); + bus_send_hid_input( file, &desc, &touch_multiple, sizeof(touch_multiple) ); res = msg_wait_for_events( 1, &touchdown_event, 1000 ); ok( res == 0, "WaitForSingleObject returned %#lx\n", res ); res = msg_wait_for_events( 1, &touchdown_event, 1000 ); ok( res == 0, "WaitForSingleObject returned %#lx\n", res ); + res = msg_wait_for_events( 1, &touchleave_event, 10 ); ok( res == WAIT_TIMEOUT, "WaitForSingleObject returned %#lx\n", res ); ok( pointer_enter_count == 2, "got pointer_enter_count %u\n", pointer_enter_count ); @@ -2256,7 +2571,57 @@ static void test_hid_touch_screen(void) ok( LOWORD( pointer_lparam[1] ) * 128 / width == 0x18, "got lparam %#Ix\n", pointer_lparam[1] ); ok( HIWORD( pointer_lparam[1] ) * 128 / height == 0x20, "got lparam %#Ix\n", pointer_lparam[1] ); + /* Test mouse messages generation. */ + SetCapture( hwnd ); + pump_messages(); + for (i = 0; i < ARRAY_SIZE(mouse_tests); ++i) + { + for (j = 0; j < 2; ++j) + { + winetest_push_context( "test %u, %u", i, j ); + + res = WaitForSingleObject( touchdown_event, 0 ); + ok( res == WAIT_TIMEOUT, "WaitForSingleObject returned %#lx\n", res ); + res = WaitForSingleObject( touchleave_event, 0 ); + ok( res == WAIT_TIMEOUT, "WaitForSingleObject returned %#lx\n", res ); + + start_touch_test( mouse_tests[i].skip_message ); + bus_send_hid_input( file, &desc, &touch_single, sizeof(touch_single) ); + ResetEvent( touchmoved_event ); + res = msg_wait_for_events( 1, &touchdown_event, 1000 ); + ok( res == 0, "WaitForSingleObject returned %#lx\n", res ); + + if (j) + { + /* Current cursor positon affects WM_MOUSEMOVE messages. */ + start_touch_test( mouse_tests[i].skip_message ); + } + ResetEvent( touchmoved_event ); + bus_send_hid_input( file, &desc, &touch_single2, sizeof(touch_single2) ); + + res = msg_wait_for_events( 1, &touchmoved_event, 1000 ); + ok( res == 0, "WaitForSingleObject returned %#lx\n", res ); + + if (j) start_touch_test( mouse_tests[i].skip_message ); + ResetEvent( touchmoved_event ); + bus_send_hid_input( file, &desc, &touch_single3, sizeof(touch_single3) ); + res = msg_wait_for_events( 1, &touchmoved_event, 1000 ); + ok( res == 0, "WaitForSingleObject returned %#lx\n", res ); + + if (j) start_touch_test( mouse_tests[i].skip_message ); + bus_send_hid_input( file, & desc, &touch_release, sizeof(touch_release) ); + res = msg_wait_for_events( 1, &touchleave_event, 1000 ); + ok( res == 0, "WaitForSingleObject returned %#lx\n", res ); + + start_touch_test( NULL ); + pump_messages(); + + winetest_pop_context(); + } + } + ret = ReleaseCapture(); + ok( ret, "ReleaseCapture() failed.\n" ); DestroyWindow( hwnd ); CloseHandle( file ); @@ -2265,6 +2630,7 @@ static void test_hid_touch_screen(void) hid_device_stop( &desc, 1 ); CloseHandle( touchdown_event ); + CloseHandle( touchmoved_event ); CloseHandle( touchleave_event ); } diff --git a/dlls/dinput/tests/driver_bus.c b/dlls/dinput/tests/driver_bus.c index cf42a1bcf6ee..320b47057a55 100644 --- a/dlls/dinput/tests/driver_bus.c +++ b/dlls/dinput/tests/driver_bus.c @@ -563,7 +563,7 @@ static NTSTATUS remove_child_device( struct func_device *impl, DEVICE_OBJECT *de for (i = 0; i < impl->devices->Count; ++i) if (impl->devices->Objects[i] == device) break; if (i == impl->devices->Count) status = STATUS_NOT_FOUND; - else impl->devices->Objects[i] = impl->devices->Objects[impl->devices->Count--]; + else impl->devices->Objects[i] = impl->devices->Objects[--impl->devices->Count]; KeReleaseSpinLock( &impl->base.lock, irql ); return status; diff --git a/dlls/dinput/tests/driver_hid.c b/dlls/dinput/tests/driver_hid.c index 7b20af07493c..5d92c8b230a5 100644 --- a/dlls/dinput/tests/driver_hid.c +++ b/dlls/dinput/tests/driver_hid.c @@ -57,8 +57,6 @@ static void check_device( DEVICE_OBJECT *device ) ok( device == impl->expect_hid_fdo, "got device %p\n", device ); ok( device->DriverObject == expect_driver, "got DriverObject %p\n", device->DriverObject ); - if (!device->NextDevice) ok( device == impl->expect_hid_fdo, "got device %p\n", device ); - else ok( device->NextDevice == impl->expect_hid_fdo, "got NextDevice %p\n", device->NextDevice ); ok( !device->AttachedDevice, "got AttachedDevice %p\n", device->AttachedDevice ); ok( ext->MiniDeviceExtension == impl->expect_hid_ext, "got MiniDeviceExtension %p\n", ext->MiniDeviceExtension ); diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index 841f627d842f..89caa86af9d6 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -1610,6 +1610,40 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file, DW .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0x00}, }, }; + struct hid_expect expect_create_4[] = + { + /* set condition, saturation 5000 */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 8, + .report_buf = {0x07,0x00,0xa6,0x19,0xd9,0x7f,0x7f,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x3f,0x00}, + }, + }; + struct hid_expect expect_create_5[] = + { + /* set condition, saturation out-of-bounds (-1) */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 8, + .report_buf = {0x07,0x00,0xa6,0x19,0xd9,0xff,0xff,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x3f,0x00}, + }, + }; struct hid_expect expect_destroy = { .code = IOCTL_HID_WRITE_REPORT, @@ -1636,7 +1670,7 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file, DW .dwFadeLevel = 3000, .dwFadeTime = 4000, }; - static const DICONDITION expect_condition[3] = + static const DICONDITION expect_condition[4] = { { .lOffset = -500, @@ -1656,11 +1690,19 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file, DW }, { .lOffset = -7000, - .lPositiveCoefficient = -8000, - .lNegativeCoefficient = 9000, - .dwPositiveSaturation = 10000, - .dwNegativeSaturation = 11000, - .lDeadBand = -12000, + .lPositiveCoefficient = 2000, + .lNegativeCoefficient = -3000, + .dwPositiveSaturation = 5000, + .dwNegativeSaturation = 5000, + .lDeadBand = 1000, + }, + { + .lOffset = -7000, + .lPositiveCoefficient = 2000, + .lNegativeCoefficient = -3000, + .dwPositiveSaturation = 11000, + .dwNegativeSaturation = -11000, + .lDeadBand = 1000, }, }; const DIEFFECT expect_desc = @@ -1828,557 +1870,857 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file, DW ok( desc.cbTypeSpecificParams == 0 * sizeof(DICONDITION), "got %lu\n", desc.cbTypeSpecificParams ); ref = IDirectInputEffect_Release( effect ); ok( ref == 0, "Release returned %ld\n", ref ); -} - -static BOOL test_force_feedback_joystick( DWORD version ) -{ -#include "psh_hid_macros.h" - const unsigned char report_descriptor[] = - { - USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Application), - USAGE(1, HID_USAGE_GENERIC_JOYSTICK), - COLLECTION(1, Report), - REPORT_ID(1, 1), - - USAGE(1, HID_USAGE_GENERIC_X), - USAGE(1, HID_USAGE_GENERIC_Y), - USAGE(1, HID_USAGE_GENERIC_Z), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 3), - INPUT(1, Data|Var|Abs), - - USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), - USAGE_MINIMUM(1, 1), - USAGE_MAXIMUM(1, 2), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 2), - INPUT(1, Data|Var|Abs), - REPORT_COUNT(1, 6), - INPUT(1, Cnst|Var|Abs), - END_COLLECTION, - - USAGE_PAGE(1, HID_USAGE_PAGE_PID), - USAGE(1, PID_USAGE_STATE_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 2), - - USAGE(1, PID_USAGE_DEVICE_PAUSED), - USAGE(1, PID_USAGE_ACTUATORS_ENABLED), - USAGE(1, PID_USAGE_SAFETY_SWITCH), - USAGE(1, PID_USAGE_ACTUATOR_OVERRIDE_SWITCH), - USAGE(1, PID_USAGE_ACTUATOR_POWER), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 5), - INPUT(1, Data|Var|Abs), - REPORT_COUNT(1, 3), - INPUT(1, Cnst|Var|Abs), - - USAGE(1, PID_USAGE_EFFECT_PLAYING), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 1), - INPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MAXIMUM(1, 0x7f), - LOGICAL_MINIMUM(1, 0x00), - REPORT_SIZE(1, 7), - REPORT_COUNT(1, 1), - INPUT(1, Data|Var|Abs), - END_COLLECTION, - - USAGE_PAGE(1, HID_USAGE_PAGE_PID), - USAGE(1, PID_USAGE_DEVICE_CONTROL_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 1), - USAGE(1, PID_USAGE_DEVICE_CONTROL), - COLLECTION(1, Logical), - USAGE(1, PID_USAGE_DC_DEVICE_RESET), - USAGE(1, PID_USAGE_DC_STOP_ALL_EFFECTS), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 2), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Ary|Abs), - END_COLLECTION, - END_COLLECTION, - USAGE(1, PID_USAGE_EFFECT_OPERATION_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 2), + /* check saturation coefficients */ + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); + desc.lpvTypeSpecificParams = (void *)&expect_condition[2]; - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), + set_hid_expect( file, expect_create_4, sizeof(expect_create_4) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); - USAGE(1, PID_USAGE_EFFECT_OPERATION), - COLLECTION(1, NamedArray), - USAGE(1, PID_USAGE_OP_EFFECT_START), - USAGE(1, PID_USAGE_OP_EFFECT_START_SOLO), - USAGE(1, PID_USAGE_OP_EFFECT_STOP), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 3), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 3), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Ary|Abs), - END_COLLECTION, + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); - USAGE(1, PID_USAGE_LOOP_COUNT), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); + desc.lpvTypeSpecificParams = (void *)&expect_condition[3]; - USAGE(1, PID_USAGE_SET_EFFECT_REPORT), - COLLECTION(1, Report), - REPORT_ID(1, 3), + set_hid_expect( file, expect_create_5, sizeof(expect_create_5) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); - USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 0x7f), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); +} - USAGE(1, PID_USAGE_EFFECT_TYPE), - COLLECTION(1, NamedArray), - USAGE(1, PID_USAGE_ET_SQUARE), - USAGE(1, PID_USAGE_ET_SINE), - USAGE(1, PID_USAGE_ET_SPRING), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 3), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 3), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Ary|Abs), - END_COLLECTION, +static void test_constantforce_effect( IDirectInputDevice8W *device, HANDLE file, DWORD version ) +{ + struct hid_expect expect_create_0[] = + { + /* set constant force, magnitude 5000 */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 9, + .report_len = 3, + .report_buf = {0x09,0x88,0x13}, + }, + /* set envelope */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 6, + .report_len = 7, + .report_buf = {0x06,0x19,0x4c,0x02,0x00,0x04,0x00}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x04,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0x00}, + }, + }; + struct hid_expect expect_create_1[] = + { + /* set constantforce, magnitude 10000 */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 9, + .report_len = 3, + .report_buf = {0x09,0x10,0x27}, + }, + /* update envelope */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 6, + .report_len = 7, + .report_buf = {0x06,0x19,0x4c,0x02,0x00,0x04,0x00}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x04,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x3f,0x00}, + }, + }; - USAGE(1, PID_USAGE_AXES_ENABLE), - COLLECTION(1, Logical), - USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_X), - USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Y), - USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Z), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 1), - REPORT_COUNT(1, 3), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - USAGE(1, PID_USAGE_DIRECTION_ENABLE), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - REPORT_COUNT(1, 4), - OUTPUT(1, Cnst|Var|Abs), - - USAGE(1, PID_USAGE_DURATION), - USAGE(1, PID_USAGE_START_DELAY), - UNIT(2, 0x1003), /* Eng Lin:Time */ - UNIT_EXPONENT(1, -3), /* 10^-3 */ - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x7fff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x7fff), - REPORT_SIZE(1, 16), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - UNIT(1, 0), - UNIT_EXPONENT(1, 0), - - USAGE(1, PID_USAGE_TRIGGER_BUTTON), - LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 0x08), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 0x08), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_DIRECTION), - COLLECTION(1, Logical), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), - UNIT(1, 0x14), /* Eng Rot:Angular Pos */ - UNIT_EXPONENT(1, -2), /* 10^-2 */ - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x00ff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(4, 0x00008ca0), - UNIT(1, 0), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - UNIT_EXPONENT(1, 0), - UNIT(1, 0), - END_COLLECTION, - END_COLLECTION, - - USAGE(1, PID_USAGE_SET_PERIODIC_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 5), - - USAGE(1, PID_USAGE_MAGNITUDE), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x00ff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - - USAGE(1, PID_USAGE_SET_ENVELOPE_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 6), - - USAGE(1, PID_USAGE_ATTACK_LEVEL), - USAGE(1, PID_USAGE_FADE_LEVEL), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x00ff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_ATTACK_TIME), - USAGE(1, PID_USAGE_FADE_TIME), - UNIT(2, 0x1003), /* Eng Lin:Time */ - UNIT_EXPONENT(1, -3), /* 10^-3 */ - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x7fff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x7fff), - REPORT_SIZE(1, 16), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - PHYSICAL_MAXIMUM(1, 0), - UNIT_EXPONENT(1, 0), - UNIT(1, 0), - END_COLLECTION, - - - USAGE(1, PID_USAGE_SET_CONDITION_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 7), - - USAGE(1, PID_USAGE_TYPE_SPECIFIC_BLOCK_OFFSET), - COLLECTION(1, Logical), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), - USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(1, 1), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(1, 1), - REPORT_SIZE(1, 2), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - REPORT_SIZE(1, 4), - REPORT_COUNT(1, 1), - OUTPUT(1, Cnst|Var|Abs), - - USAGE(1, PID_USAGE_CP_OFFSET), - LOGICAL_MINIMUM(1, 0x80), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(2, 0xd8f0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_POSITIVE_COEFFICIENT), - USAGE(1, PID_USAGE_NEGATIVE_COEFFICIENT), - LOGICAL_MINIMUM(1, 0x80), - LOGICAL_MAXIMUM(1, 0x7f), - PHYSICAL_MINIMUM(2, 0xd8f0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_POSITIVE_SATURATION), - USAGE(1, PID_USAGE_NEGATIVE_SATURATION), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x00ff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 2), - OUTPUT(1, Data|Var|Abs), - - USAGE(1, PID_USAGE_DEAD_BAND), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x00ff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - - - USAGE(1, PID_USAGE_DEVICE_GAIN_REPORT), - COLLECTION(1, Logical), - REPORT_ID(1, 8), - - USAGE(1, PID_USAGE_DEVICE_GAIN), - LOGICAL_MINIMUM(1, 0), - LOGICAL_MAXIMUM(2, 0x00ff), - PHYSICAL_MINIMUM(1, 0), - PHYSICAL_MAXIMUM(2, 0x2710), - REPORT_SIZE(1, 8), - REPORT_COUNT(1, 1), - OUTPUT(1, Data|Var|Abs), - END_COLLECTION, - END_COLLECTION, - }; - C_ASSERT(sizeof(report_descriptor) < MAX_HID_DESCRIPTOR_LEN); -#include "pop_hid_macros.h" - - struct hid_device_desc desc = + struct hid_expect expect_create_2[] = { - .use_report_id = TRUE, - .caps = + /* set constantforce, magnitude -10000 */ { - .InputReportByteLength = 5, - .OutputReportByteLength = 11, + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 9, + .report_len = 3, + .report_buf = {0x09,0xf0,0xd8}, }, - .attributes = default_attributes, - }; - const DIDEVCAPS expect_caps = - { - .dwSize = sizeof(DIDEVCAPS), - .dwFlags = DIDC_FORCEFEEDBACK | DIDC_ATTACHED | DIDC_EMULATED | DIDC_STARTDELAY | - DIDC_FFFADE | DIDC_FFATTACK | DIDC_DEADBAND | DIDC_SATURATION, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK - : DIDEVTYPE_HID | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_JOYSTICK, - .dwAxes = 3, - .dwButtons = 2, - .dwFFSamplePeriod = 1000000, - .dwFFMinTimeResolution = 1000000, - .dwHardwareRevision = 1, - .dwFFDriverVersion = 1, - }; - struct hid_expect expect_acquire_autocenter_on[] = - { + /* update envelope */ { .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x01}, + .report_id = 6, + .report_len = 7, + .report_buf = {0x06,0x19,0x4c,0x02,0x00,0x04,0x00}, }, + /* update effect */ { .code = IOCTL_HID_WRITE_REPORT, - .report_id = 8, - .report_len = 2, - .report_buf = {8, 0x19}, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x04,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x3f,0x00}, }, }; - struct hid_expect expect_acquire_autocenter_off[] = + struct hid_expect expect_destroy = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {0x02, 0x01, 0x03, 0x00}, + }; + static const DWORD expect_axes[3] = + { + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR, + }; + static const LONG expect_directions[3] = { + +3000, + 0, + 0, + }; + static const DIENVELOPE expect_envelope = + { + .dwSize = sizeof(DIENVELOPE), + .dwAttackLevel = 1000, + .dwAttackTime = 2000, + .dwFadeLevel = 3000, + .dwFadeTime = 4000, + }; + static const DICONSTANTFORCE input_constant_force[4] = { { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x01}, + .lMagnitude = 5000 }, { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x02}, - .broken_id = 8, /* Win8 sends them in the reverse order */ + .lMagnitude = 10000 }, { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 8, - .report_len = 2, - .report_buf = {8, 0x19}, - .broken_id = 1, /* Win8 sends them in the reverse order */ - }, - }; - struct hid_expect expect_reset[] = - { - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x01}, + .lMagnitude = 16000 }, - }; - struct hid_expect expect_set_device_gain_1 = - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 8, - .report_len = 2, - .report_buf = {8, 0x19}, - }; - struct hid_expect expect_set_device_gain_2 = - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 8, - .report_len = 2, - .report_buf = {8, 0x33}, - }; - struct hid_expect expect_stop_all[] = - { { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 1, - .report_len = 2, - .report_buf = {1, 0x02}, + .lMagnitude = -16000 }, }; - const DIDEVICEINSTANCEW expect_devinst = + const DIEFFECT expect_desc = { - .dwSize = sizeof(DIDEVICEINSTANCEW), - .guidInstance = expect_guid_product, - .guidProduct = expect_guid_product, - .dwDevType = version >= 0x800 ? DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK - : DIDEVTYPE_HID | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_JOYSTICK, - .tszInstanceName = L"Wine Test", - .tszProductName = L"Wine Test", - .guidFFDriver = IID_IDirectInputPIDDriver, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_JOYSTICK, + .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), + .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, + .dwDuration = 1000, + .dwSamplePeriod = 2000, + .dwGain = 3000, + .dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, + .dwTriggerRepeatInterval = 5000, + .cAxes = 3, + .rgdwAxes = (void *)expect_axes, + .rglDirection = (void *)expect_directions, + .lpEnvelope = (void *)&expect_envelope, + .cbTypeSpecificParams = sizeof(DICONSTANTFORCE), + .lpvTypeSpecificParams = (void *)input_constant_force, + .dwStartDelay = 6000, }; - const DIDEVICEOBJECTINSTANCEW expect_objects_5[] = + struct check_created_effect_params check_params = {0}; + DIENVELOPE envelope = {.dwSize = sizeof(DIENVELOPE)}; + DICONSTANTFORCE constant_force[1] = {{0}}; + IDirectInputEffect *effect; + LONG directions[3] = {0,0,0}; + DWORD axes[3] = {0,0,0}; + DIEFFECT desc = { - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_XAxis, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"X Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_X, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_YAxis, - .dwOfs = 0x4, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"Y Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_Y, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_ZAxis, - .dwOfs = 0x8, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(2)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"Z Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_Z, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Button, - .dwOfs = 0x30, - .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0)|DIDFT_FFEFFECTTRIGGER, - .dwFlags = DIDOI_FFEFFECTTRIGGER, - .tszName = L"Button 0", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_BUTTON, - .wUsage = 0x1, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Button, - .dwOfs = 0x31, - .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1)|DIDFT_FFEFFECTTRIGGER, - .dwFlags = DIDOI_FFEFFECTTRIGGER, - .tszName = L"Button 1", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_BUTTON, - .wUsage = 0x2, - .wReportId = 1, - }, + .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), + .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, + .cAxes = 3, + .rgdwAxes = axes, + .rglDirection = directions, + .lpEnvelope = &envelope, + .cbTypeSpecificParams = sizeof(DICONSTANTFORCE), + .lpvTypeSpecificParams = constant_force, }; - const DIDEVICEOBJECTINSTANCEW expect_objects[] = + HRESULT hr; + ULONG ref; + GUID guid; + + set_hid_expect( file, expect_create_0, sizeof(expect_create_0) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_ConstantForce, &expect_desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + check_params.expect_effect = effect; + hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_created_effect_objects, &check_params, 0 ); + ok( hr == DI_OK, "EnumCreatedEffectObjects returned %#lx\n", hr ); + ok( check_params.count == 1, "got count %lu, expected 1\n", check_params.count ); + + hr = IDirectInputEffect_GetEffectGuid( effect, &guid ); + ok( hr == DI_OK, "GetEffectGuid returned %#lx\n", hr ); + ok( IsEqualGUID( &guid, &GUID_ConstantForce ), "got guid %s, expected %s\n", debugstr_guid( &guid ), + debugstr_guid( &GUID_ConstantForce ) ); + + hr = IDirectInputEffect_GetParameters( effect, &desc, version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5 ); + ok( hr == DI_OK, "GetParameters returned %#lx\n", hr ); + check_member( desc, expect_desc, "%lu", dwDuration ); + check_member( desc, expect_desc, "%lu", dwSamplePeriod ); + check_member( desc, expect_desc, "%lu", dwGain ); + check_member( desc, expect_desc, "%#lx", dwTriggerButton ); + check_member( desc, expect_desc, "%lu", dwTriggerRepeatInterval ); + check_member( desc, expect_desc, "%lu", cAxes ); + check_member( desc, expect_desc, "%#lx", rgdwAxes[0] ); + check_member( desc, expect_desc, "%#lx", rgdwAxes[1] ); + check_member( desc, expect_desc, "%ld", rglDirection[0] ); + check_member( desc, expect_desc, "%ld", rglDirection[1] ); + check_member( desc, expect_desc, "%lu", cbTypeSpecificParams ); + if (version >= 0x700) check_member( desc, expect_desc, "%lu", dwStartDelay ); + else ok( desc.dwStartDelay == 0, "got dwStartDelay %#lx\n", desc.dwStartDelay ); + check_member( envelope, expect_envelope, "%lu", dwAttackLevel ); + check_member( envelope, expect_envelope, "%lu", dwAttackTime ); + check_member( envelope, expect_envelope, "%lu", dwFadeLevel ); + check_member( envelope, expect_envelope, "%lu", dwFadeTime ); + check_member( constant_force[0], input_constant_force[0], "%ld", lMagnitude ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); + + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = 2 * sizeof(DICONSTANTFORCE); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_ConstantForce, &desc, &effect, NULL ); + ok( hr == DIERR_INVALIDPARAM, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + desc.lpvTypeSpecificParams = (void *)&input_constant_force[1]; + + set_hid_expect( file, expect_create_1, sizeof(expect_create_1) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_ConstantForce, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); + + + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + desc.lpvTypeSpecificParams = (void *)&input_constant_force[2]; + + set_hid_expect( file, expect_create_1, sizeof(expect_create_1) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_ConstantForce, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); + + + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + desc.lpvTypeSpecificParams = (void *)&input_constant_force[3]; + + set_hid_expect( file, expect_create_2, sizeof(expect_create_2) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_ConstantForce, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); +} + + +static BOOL test_force_feedback_joystick( DWORD version ) +{ +#include "psh_hid_macros.h" + const unsigned char report_descriptor[] = { - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_ZAxis, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(2)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"Z Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_Z, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_YAxis, - .dwOfs = 0x4, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"Y Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_Y, - .wReportId = 1, - }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_XAxis, - .dwOfs = 0x8, - .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0)|DIDFT_FFACTUATOR, - .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, - .tszName = L"X Axis", - .wCollectionNumber = 1, - .wUsagePage = HID_USAGE_PAGE_GENERIC, - .wUsage = HID_USAGE_GENERIC_X, - .wReportId = 1, - }, - { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + USAGE(1, HID_USAGE_GENERIC_Z), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 3), + INPUT(1, Data|Var|Abs), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 6), + INPUT(1, Cnst|Var|Abs), + END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_PID), + USAGE(1, PID_USAGE_STATE_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 2), + + USAGE(1, PID_USAGE_DEVICE_PAUSED), + USAGE(1, PID_USAGE_ACTUATORS_ENABLED), + USAGE(1, PID_USAGE_SAFETY_SWITCH), + USAGE(1, PID_USAGE_ACTUATOR_OVERRIDE_SWITCH), + USAGE(1, PID_USAGE_ACTUATOR_POWER), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 5), + INPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 3), + INPUT(1, Cnst|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_PLAYING), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MAXIMUM(1, 0x7f), + LOGICAL_MINIMUM(1, 0x00), + REPORT_SIZE(1, 7), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_PID), + USAGE(1, PID_USAGE_DEVICE_CONTROL_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, PID_USAGE_DEVICE_CONTROL), + COLLECTION(1, Logical), + USAGE(1, PID_USAGE_DC_DEVICE_RESET), + USAGE(1, PID_USAGE_DC_STOP_ALL_EFFECTS), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 2), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + END_COLLECTION, + + USAGE(1, PID_USAGE_EFFECT_OPERATION_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 2), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_OPERATION), + COLLECTION(1, NamedArray), + USAGE(1, PID_USAGE_OP_EFFECT_START), + USAGE(1, PID_USAGE_OP_EFFECT_START_SOLO), + USAGE(1, PID_USAGE_OP_EFFECT_STOP), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 3), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 3), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_LOOP_COUNT), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_EFFECT_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 3), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_TYPE), + COLLECTION(1, NamedArray), + USAGE(1, PID_USAGE_ET_SQUARE), + USAGE(1, PID_USAGE_ET_SINE), + USAGE(1, PID_USAGE_ET_SPRING), + USAGE(1, PID_USAGE_ET_CONSTANT_FORCE), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 4), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 4), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_AXES_ENABLE), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_X), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Y), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Z), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 3), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + USAGE(1, PID_USAGE_DIRECTION_ENABLE), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 4), + OUTPUT(1, Cnst|Var|Abs), + + USAGE(1, PID_USAGE_DURATION), + USAGE(1, PID_USAGE_START_DELAY), + UNIT(2, 0x1003), /* Eng Lin:Time */ + UNIT_EXPONENT(1, -3), /* 10^-3 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x7fff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x7fff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + UNIT(1, 0), + UNIT_EXPONENT(1, 0), + + USAGE(1, PID_USAGE_TRIGGER_BUTTON), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 0x08), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 0x08), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_DIRECTION), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), + UNIT(1, 0x14), /* Eng Rot:Angular Pos */ + UNIT_EXPONENT(1, -2), /* 10^-2 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(4, 0x00008ca0), + UNIT(1, 0), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + UNIT_EXPONENT(1, 0), + UNIT(1, 0), + END_COLLECTION, + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_PERIODIC_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 5), + + USAGE(1, PID_USAGE_MAGNITUDE), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_ENVELOPE_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 6), + + USAGE(1, PID_USAGE_ATTACK_LEVEL), + USAGE(1, PID_USAGE_FADE_LEVEL), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_ATTACK_TIME), + USAGE(1, PID_USAGE_FADE_TIME), + UNIT(2, 0x1003), /* Eng Lin:Time */ + UNIT_EXPONENT(1, -3), /* 10^-3 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x7fff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x7fff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + PHYSICAL_MAXIMUM(1, 0), + UNIT_EXPONENT(1, 0), + UNIT(1, 0), + END_COLLECTION, + + + USAGE(1, PID_USAGE_SET_CONDITION_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 7), + + USAGE(1, PID_USAGE_TYPE_SPECIFIC_BLOCK_OFFSET), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 2), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + REPORT_SIZE(1, 4), + REPORT_COUNT(1, 1), + OUTPUT(1, Cnst|Var|Abs), + + USAGE(1, PID_USAGE_CP_OFFSET), + LOGICAL_MINIMUM(1, 0x80), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(2, 0xd8f0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_POSITIVE_COEFFICIENT), + USAGE(1, PID_USAGE_NEGATIVE_COEFFICIENT), + LOGICAL_MINIMUM(1, 0x80), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(2, 0xd8f0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_POSITIVE_SATURATION), + USAGE(1, PID_USAGE_NEGATIVE_SATURATION), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_DEAD_BAND), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + + USAGE(1, PID_USAGE_DEVICE_GAIN_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 8), + + USAGE(1, PID_USAGE_DEVICE_GAIN), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_CONSTANT_FORCE_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 9), + + USAGE(1, PID_USAGE_MAGNITUDE), + LOGICAL_MINIMUM(2, 0xd8f0), + LOGICAL_MAXIMUM(2, 0x2710), + PHYSICAL_MINIMUM(2, 0xd8f0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + END_COLLECTION, + }; + C_ASSERT(sizeof(report_descriptor) < MAX_HID_DESCRIPTOR_LEN); +#include "pop_hid_macros.h" + + struct hid_device_desc desc = + { + .use_report_id = TRUE, + .caps = + { + .InputReportByteLength = 5, + .OutputReportByteLength = 11, + }, + .attributes = default_attributes, + }; + const DIDEVCAPS expect_caps = + { + .dwSize = sizeof(DIDEVCAPS), + .dwFlags = DIDC_FORCEFEEDBACK | DIDC_ATTACHED | DIDC_EMULATED | DIDC_STARTDELAY | + DIDC_FFFADE | DIDC_FFATTACK | DIDC_DEADBAND | DIDC_SATURATION, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK + : DIDEVTYPE_HID | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_JOYSTICK, + .dwAxes = 3, + .dwButtons = 2, + .dwFFSamplePeriod = 1000000, + .dwFFMinTimeResolution = 1000000, + .dwHardwareRevision = 1, + .dwFFDriverVersion = 1, + }; + struct hid_expect expect_acquire_autocenter_on[] = + { + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 8, + .report_len = 2, + .report_buf = {8, 0x19}, + }, + }; + struct hid_expect expect_acquire_autocenter_off[] = + { + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x02}, + .broken_id = 8, /* Win8 sends them in the reverse order */ + }, + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 8, + .report_len = 2, + .report_buf = {8, 0x19}, + .broken_id = 1, /* Win8 sends them in the reverse order */ + }, + }; + struct hid_expect expect_reset[] = + { + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, + }; + struct hid_expect expect_set_device_gain_1 = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 8, + .report_len = 2, + .report_buf = {8, 0x19}, + }; + struct hid_expect expect_set_device_gain_2 = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 8, + .report_len = 2, + .report_buf = {8, 0x33}, + }; + struct hid_expect expect_stop_all[] = + { + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x02}, + }, + }; + const DIDEVICEINSTANCEW expect_devinst = + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = version >= 0x800 ? DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK + : DIDEVTYPE_HID | (DIDEVTYPEJOYSTICK_UNKNOWN << 8) | DIDEVTYPE_JOYSTICK, + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", + .guidFFDriver = IID_IDirectInputPIDDriver, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }; + const DIDEVICEOBJECTINSTANCEW expect_objects_5[] = + { + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_XAxis, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"X Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_X, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_YAxis, + .dwOfs = 0x4, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"Y Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Y, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_ZAxis, + .dwOfs = 0x8, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(2)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"Z Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Z, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Button, + .dwOfs = 0x30, + .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0)|DIDFT_FFEFFECTTRIGGER, + .dwFlags = DIDOI_FFEFFECTTRIGGER, + .tszName = L"Button 0", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_BUTTON, + .wUsage = 0x1, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Button, + .dwOfs = 0x31, + .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1)|DIDFT_FFEFFECTTRIGGER, + .dwFlags = DIDOI_FFEFFECTTRIGGER, + .tszName = L"Button 1", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_BUTTON, + .wUsage = 0x2, + .wReportId = 1, + }, + }; + const DIDEVICEOBJECTINSTANCEW expect_objects[] = + { + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_ZAxis, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(2)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"Z Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Z, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_YAxis, + .dwOfs = 0x4, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"Y Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Y, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_XAxis, + .dwOfs = 0x8, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0)|DIDFT_FFACTUATOR, + .dwFlags = DIDOI_ASPECTPOSITION|DIDOI_FFACTUATOR, + .tszName = L"X Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_X, + .wReportId = 1, + }, + { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Button, - .dwOfs = version >= 0x800 ? 0x68 : 0x10, + .dwOfs = version >= 0x800 ? 0x6c : 0x10, .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0)|DIDFT_FFEFFECTTRIGGER, .dwFlags = DIDOI_FFEFFECTTRIGGER, .tszName = L"Button 0", @@ -2390,7 +2732,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Button, - .dwOfs = version >= 0x800 ? 0x69 : 0x11, + .dwOfs = version >= 0x800 ? 0x6d : 0x11, .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1)|DIDFT_FFEFFECTTRIGGER, .dwFlags = DIDOI_FFEFFECTTRIGGER, .tszName = L"Button 1", @@ -2402,7 +2744,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x70 : 0, + .dwOfs = version >= 0x800 ? 0x74 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(12)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"DC Device Reset", @@ -2414,7 +2756,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x71 : 0, + .dwOfs = version >= 0x800 ? 0x75 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(13)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"DC Stop All Effects", @@ -2438,7 +2780,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x72 : 0, + .dwOfs = version >= 0x800 ? 0x76 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(15)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Start", @@ -2450,7 +2792,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x73 : 0, + .dwOfs = version >= 0x800 ? 0x77 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(16)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Start Solo", @@ -2462,7 +2804,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x74 : 0, + .dwOfs = version >= 0x800 ? 0x78 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(17)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Stop", @@ -2498,7 +2840,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x75 : 0, + .dwOfs = version >= 0x800 ? 0x79 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(20)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Square", @@ -2510,7 +2852,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x76 : 0, + .dwOfs = version >= 0x800 ? 0x7a : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(21)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Sine", @@ -2522,7 +2864,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x77 : 0, + .dwOfs = version >= 0x800 ? 0x7b : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(22)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Spring", @@ -2534,9 +2876,21 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x78 : 0, + .dwOfs = version >= 0x800 ? 0x7c : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(23)|DIDFT_OUTPUT, .dwFlags = 0x80008000, + .tszName = L"ET Constant Force", + .wCollectionNumber = 8, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_ET_CONSTANT_FORCE, + .wReportId = 3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x7d : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(24)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, .tszName = L"Z Axis", .wCollectionNumber = 9, .wUsagePage = HID_USAGE_PAGE_GENERIC, @@ -2546,8 +2900,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x79 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(24)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x7e : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(25)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Y Axis", .wCollectionNumber = 9, @@ -2558,8 +2912,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x7a : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(25)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x7f : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(26)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"X Axis", .wCollectionNumber = 9, @@ -2570,8 +2924,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x7b : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(26)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x80 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(27)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Direction Enable", .wCollectionNumber = 7, @@ -2583,7 +2937,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x1c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(27)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(28)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Start Delay", .wCollectionNumber = 7, @@ -2597,7 +2951,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x20 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(28)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(29)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Duration", .wCollectionNumber = 7, @@ -2611,7 +2965,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x24 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(29)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(30)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Trigger Button", .wCollectionNumber = 7, @@ -2623,9 +2977,9 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x28 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(30)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(31)|DIDFT_OUTPUT, .dwFlags = 0x80008000, - .tszName = L"Unknown 30", + .tszName = L"Unknown 31", .wCollectionNumber = 10, .wUsagePage = HID_USAGE_PAGE_ORDINAL, .wUsage = 2, @@ -2636,9 +2990,9 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x2c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(31)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(32)|DIDFT_OUTPUT, .dwFlags = 0x80008000, - .tszName = L"Unknown 31", + .tszName = L"Unknown 32", .wCollectionNumber = 10, .wUsagePage = HID_USAGE_PAGE_ORDINAL, .wUsage = 1, @@ -2649,7 +3003,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x30 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(32)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(33)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Magnitude", .wCollectionNumber = 11, @@ -2661,7 +3015,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x34 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(33)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(34)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Fade Level", .wCollectionNumber = 12, @@ -2673,7 +3027,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x38 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(34)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(35)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Attack Level", .wCollectionNumber = 12, @@ -2685,7 +3039,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x3c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(35)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(36)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Fade Time", .wCollectionNumber = 12, @@ -2699,7 +3053,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x40 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(36)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(37)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Attack Time", .wCollectionNumber = 12, @@ -2713,9 +3067,9 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x44 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(37)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(38)|DIDFT_OUTPUT, .dwFlags = 0x80008000, - .tszName = L"Unknown 37", + .tszName = L"Unknown 38", .wCollectionNumber = 14, .wUsagePage = HID_USAGE_PAGE_ORDINAL, .wUsage = 2, @@ -2725,9 +3079,9 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x48 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(38)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(39)|DIDFT_OUTPUT, .dwFlags = 0x80008000, - .tszName = L"Unknown 38", + .tszName = L"Unknown 39", .wCollectionNumber = 14, .wUsagePage = HID_USAGE_PAGE_ORDINAL, .wUsage = 1, @@ -2737,7 +3091,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x4c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(39)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(40)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"CP Offset", .wCollectionNumber = 13, @@ -2749,7 +3103,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x50 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(40)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(41)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Negative Coefficient", .wCollectionNumber = 13, @@ -2761,7 +3115,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x54 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(41)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(42)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Positive Coefficient", .wCollectionNumber = 13, @@ -2773,7 +3127,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x58 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(42)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(43)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Negative Saturation", .wCollectionNumber = 13, @@ -2785,7 +3139,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x5c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(43)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(44)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Positive Saturation", .wCollectionNumber = 13, @@ -2797,7 +3151,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x60 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(44)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(45)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Dead Band", .wCollectionNumber = 13, @@ -2809,7 +3163,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x64 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(45)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(46)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Device Gain", .wCollectionNumber = 15, @@ -2817,6 +3171,18 @@ static BOOL test_force_feedback_joystick( DWORD version ) .wUsage = PID_USAGE_DEVICE_GAIN, .wReportId = 8, }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x68 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(47)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Magnitude", + .wCollectionNumber = 16, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_MAGNITUDE, + .wReportId = 9, + }, { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, @@ -2834,176 +3200,1068 @@ static BOOL test_force_feedback_joystick( DWORD version ) .wUsage = HID_USAGE_GENERIC_JOYSTICK, }, { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(2), - .tszName = L"Collection 2 - PID State Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_STATE_REPORT, + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(2), + .tszName = L"Collection 2 - PID State Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_STATE_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(3), + .tszName = L"Collection 3 - PID Device Control Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DEVICE_CONTROL_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(4), + .tszName = L"Collection 4 - PID Device Control", + .wCollectionNumber = 3, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DEVICE_CONTROL, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(5), + .tszName = L"Collection 5 - Effect Operation Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_EFFECT_OPERATION_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(6), + .tszName = L"Collection 6 - Effect Operation", + .wCollectionNumber = 5, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_EFFECT_OPERATION, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(7), + .tszName = L"Collection 7 - Set Effect Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_SET_EFFECT_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(8), + .tszName = L"Collection 8 - Effect Type", + .wCollectionNumber = 7, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_EFFECT_TYPE, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(9), + .tszName = L"Collection 9 - Axes Enable", + .wCollectionNumber = 7, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_AXES_ENABLE, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(10), + .tszName = L"Collection 10 - Direction", + .wCollectionNumber = 7, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DIRECTION, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(11), + .tszName = L"Collection 11 - Set Periodic Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_SET_PERIODIC_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(12), + .tszName = L"Collection 12 - Set Envelope Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_SET_ENVELOPE_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(13), + .tszName = L"Collection 13 - Set Condition Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_SET_CONDITION_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(14), + .tszName = L"Collection 14 - Type Specific Block Offset", + .wCollectionNumber = 13, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_TYPE_SPECIFIC_BLOCK_OFFSET, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(15), + .tszName = L"Collection 15 - Device Gain Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DEVICE_GAIN_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(16), + .tszName = L"Collection 16 - Set Constant Force Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_SET_CONSTANT_FORCE_REPORT, + }, + }; + const DIEFFECTINFOW expect_effects[] = + { + { + .dwSize = sizeof(DIEFFECTINFOW), + .guid = GUID_ConstantForce, + .dwEffType = DIEFT_CONSTANTFORCE | DIEFT_STARTDELAY | DIEFT_FFFADE | DIEFT_FFATTACK, + .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .tszName = L"GUID_ConstantForce", + }, + { + .dwSize = sizeof(DIEFFECTINFOW), + .guid = GUID_Square, + .dwEffType = DIEFT_PERIODIC | DIEFT_STARTDELAY | DIEFT_FFFADE | DIEFT_FFATTACK, + .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .tszName = L"GUID_Square", + }, + { + .dwSize = sizeof(DIEFFECTINFOW), + .guid = GUID_Sine, + .dwEffType = DIEFT_PERIODIC | DIEFT_STARTDELAY | DIEFT_FFFADE | DIEFT_FFATTACK, + .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .tszName = L"GUID_Sine", + }, + { + .dwSize = sizeof(DIEFFECTINFOW), + .guid = GUID_Spring, + .dwEffType = DIEFT_CONDITION | DIEFT_STARTDELAY | DIEFT_DEADBAND | DIEFT_SATURATION, + .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION, + .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION, + .tszName = L"GUID_Spring", + } + }; + + struct check_objects_todos todo_objects_5[ARRAY_SIZE(expect_objects_5)] = + { + {.guid = TRUE, .type = TRUE, .usage = TRUE, .name = TRUE}, + {0}, + {.guid = TRUE, .type = TRUE, .usage = TRUE, .name = TRUE}, + }; + struct check_objects_params check_objects_params = + { + .version = version, + .expect_count = version < 0x700 ? ARRAY_SIZE(expect_objects_5) : ARRAY_SIZE(expect_objects), + .expect_objs = version < 0x700 ? expect_objects_5 : expect_objects, + .todo_objs = version < 0x700 ? todo_objects_5 : NULL, + .todo_extra = version < 0x700, + }; + struct check_effects_params check_effects_params = + { + .expect_count = ARRAY_SIZE(expect_effects), + .expect_effects = expect_effects, + }; + DIPROPDWORD prop_dword = + { + .diph = + { + .dwSize = sizeof(DIPROPDWORD), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + DIPROPGUIDANDPATH prop_guid_path = + { + .diph = + { + .dwSize = sizeof(DIPROPGUIDANDPATH), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + IDirectInputDevice8W *device = NULL; + DIDEVICEOBJECTDATA objdata = {0}; + DIEFFECTINFOW effectinfo = {0}; + DIEFFESCAPE escape = {0}; + DIDEVCAPS caps = {0}; + char buffer[1024]; + ULONG res, ref; + HANDLE file; + HRESULT hr; + HWND hwnd; + + winetest_push_context( "%#lx", version ); + cleanup_registry_keys(); + + desc.report_descriptor_len = sizeof(report_descriptor); + memcpy( desc.report_descriptor_buf, report_descriptor, sizeof(report_descriptor) ); + fill_context( desc.context, ARRAY_SIZE(desc.context) ); + + if (!hid_device_start( &desc, 1 )) goto done; + if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) goto done; + + check_dinput_devices( version, &devinst ); + + hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); + ok( hr == DI_OK, "GetDeviceInfo returned %#lx\n", hr ); + check_member( devinst, expect_devinst, "%lu", dwSize ); + todo_wine + check_member_guid( devinst, expect_devinst, guidInstance ); + check_member_guid( devinst, expect_devinst, guidProduct ); + check_member( devinst, expect_devinst, "%#lx", dwDevType ); + check_member_wstr( devinst, expect_devinst, tszInstanceName ); + check_member_wstr( devinst, expect_devinst, tszProductName ); + check_member_guid( devinst, expect_devinst, guidFFDriver ); + check_member( devinst, expect_devinst, "%04x", wUsagePage ); + check_member( devinst, expect_devinst, "%04x", wUsage ); + + caps.dwSize = sizeof(DIDEVCAPS); + hr = IDirectInputDevice8_GetCapabilities( device, &caps ); + ok( hr == DI_OK, "GetCapabilities returned %#lx\n", hr ); + check_member( caps, expect_caps, "%lu", dwSize ); + check_member( caps, expect_caps, "%#lx", dwFlags ); + check_member( caps, expect_caps, "%#lx", dwDevType ); + check_member( caps, expect_caps, "%lu", dwAxes ); + check_member( caps, expect_caps, "%lu", dwButtons ); + check_member( caps, expect_caps, "%lu", dwPOVs ); + check_member( caps, expect_caps, "%lu", dwFFSamplePeriod ); + check_member( caps, expect_caps, "%lu", dwFFMinTimeResolution ); + check_member( caps, expect_caps, "%lu", dwFirmwareRevision ); + check_member( caps, expect_caps, "%lu", dwHardwareRevision ); + check_member( caps, expect_caps, "%lu", dwFFDriverVersion ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_FFGAIN returned %#lx\n", hr ); + ok( prop_dword.dwData == 10000, "got %lu expected %u\n", prop_dword.dwData, 10000 ); + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetProperty DIPROP_FFLOAD returned %#lx\n", hr ); + + hr = IDirectInputDevice8_EnumObjects( device, check_objects, &check_objects_params, DIDFT_ALL ); + ok( hr == DI_OK, "EnumObjects returned %#lx\n", hr ); + ok( check_objects_params.index >= check_objects_params.expect_count, "missing %u objects\n", + check_objects_params.expect_count - check_objects_params.index ); + + res = 0; + hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, 0xfe ); + ok( hr == DI_OK, "EnumEffects returned %#lx\n", hr ); + ok( res == 0, "got %lu expected %u\n", res, 0 ); + res = 0; + hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, DIEFT_PERIODIC ); + ok( hr == DI_OK, "EnumEffects returned %#lx\n", hr ); + ok( res == 2, "got %lu expected %u\n", res, 2 ); + hr = IDirectInputDevice8_EnumEffects( device, check_effects, &check_effects_params, DIEFT_ALL ); + ok( hr == DI_OK, "EnumEffects returned %#lx\n", hr ); + ok( check_effects_params.index >= check_effects_params.expect_count, "missing %u effects\n", + check_effects_params.expect_count - check_effects_params.index ); + + effectinfo.dwSize = sizeof(DIEFFECTINFOW); + hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_ConstantForce ); + ok( hr == DI_OK, "GetEffectInfo returned %#lx\n", hr ); + check_member_guid( effectinfo, expect_effects[0], guid ); + check_member( effectinfo, expect_effects[0], "%#lx", dwEffType ); + check_member( effectinfo, expect_effects[0], "%#lx", dwStaticParams ); + check_member( effectinfo, expect_effects[0], "%#lx", dwDynamicParams ); + check_member_wstr( effectinfo, expect_effects[0], tszName ); + + effectinfo.dwSize = sizeof(DIEFFECTINFOW); + hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Square ); + ok( hr == DI_OK, "GetEffectInfo returned %#lx\n", hr ); + check_member_guid( effectinfo, expect_effects[1], guid ); + check_member( effectinfo, expect_effects[1], "%#lx", dwEffType ); + check_member( effectinfo, expect_effects[1], "%#lx", dwStaticParams ); + check_member( effectinfo, expect_effects[1], "%#lx", dwDynamicParams ); + check_member_wstr( effectinfo, expect_effects[1], tszName ); + + hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); + ok( hr == DI_OK, "SetDataFormat returned: %#lx\n", hr ); + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); + ok( hr == DI_OK, "GetProperty DIPROP_GUIDANDPATH returned %#lx\n", hr ); + + file = CreateFileW( prop_guid_path.wszPath, FILE_READ_ACCESS | FILE_WRITE_ACCESS, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL ); + ok( file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError() ); + + hwnd = create_foreground_window( FALSE ); + + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned: %#lx\n", hr ); + + prop_dword.diph.dwHow = DIPH_BYUSAGE; + prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); + prop_dword.dwData = DIPROPAUTOCENTER_ON; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_AUTOCENTER returned %#lx\n", hr ); + prop_dword.diph.dwHow = DIPH_DEVICE; + prop_dword.diph.dwObj = 0; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_AUTOCENTER returned %#lx\n", hr ); + + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_FFGAIN returned %#lx\n", hr ); + prop_dword.dwData = 1000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#lx\n", hr ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DIERR_READONLY, "SetProperty DIPROP_FFLOAD returned %#lx\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetProperty DIPROP_FFLOAD returned %#lx\n", hr ); + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetForceFeedbackState returned %#lx\n", hr ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "SendForceFeedbackCommand returned %#lx\n", hr ); + + escape.dwSize = sizeof(DIEFFESCAPE); + escape.dwCommand = 0; + escape.lpvInBuffer = buffer; + escape.cbInBuffer = 10; + escape.lpvOutBuffer = buffer + 10; + escape.cbOutBuffer = 10; + hr = IDirectInputDevice8_Escape( device, &escape ); + todo_wine + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "Escape returned: %#lx\n", hr ); + + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#lx\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); + ok( hr == DI_OK, "SetCooperativeLevel returned: %#lx\n", hr ); + prop_dword.dwData = DIPROPAUTOCENTER_OFF; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_AUTOCENTER returned %#lx\n", hr ); + + set_hid_expect( file, expect_acquire_autocenter_off, sizeof(expect_acquire_autocenter_off) ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ + + set_hid_expect( file, expect_reset, sizeof(expect_reset) ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#lx\n", hr ); + prop_dword.dwData = DIPROPAUTOCENTER_ON; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_AUTOCENTER returned %#lx\n", hr ); + + set_hid_expect( file, expect_acquire_autocenter_on, sizeof(expect_acquire_autocenter_on) ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ + + set_hid_expect( file, &expect_set_device_gain_2, sizeof(expect_set_device_gain_2) ); + prop_dword.dwData = 2000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#lx\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ + + set_hid_expect( file, &expect_set_device_gain_1, sizeof(expect_set_device_gain_1) ); + prop_dword.dwData = 1000; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#lx\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ + + hr = IDirectInputDevice8_Escape( device, &escape ); + todo_wine + ok( hr == DIERR_UNSUPPORTED, "Escape returned: %#lx\n", hr ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + todo_wine + ok( hr == 0x80040301, "GetProperty DIPROP_FFLOAD returned %#lx\n", hr ); + res = 0xdeadbeef; + hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); + todo_wine + ok( hr == 0x80040301, "GetForceFeedbackState returned %#lx\n", hr ); + + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, 0xdeadbeef ); + ok( hr == DIERR_INVALIDPARAM, "SendForceFeedbackCommand returned %#lx\n", hr ); + + set_hid_expect( file, expect_acquire_autocenter_on, sizeof(expect_acquire_autocenter_on) ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); + ok( hr == DI_OK, "SendForceFeedbackCommand returned %#lx\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ + + set_hid_expect( file, expect_stop_all, sizeof(expect_stop_all) ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_STOPALL ); + ok( hr == DI_OK, "SendForceFeedbackCommand returned %#lx\n", hr ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_PAUSE ); + ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#lx\n", hr ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_CONTINUE ); + ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#lx\n", hr ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSON ); + ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#lx\n", hr ); + hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSOFF ); + ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#lx\n", hr ); + + objdata.dwOfs = 0x1e; + objdata.dwData = 0x80; + res = 1; + hr = IDirectInputDevice8_SendDeviceData( device, sizeof(DIDEVICEOBJECTDATA), &objdata, &res, 0 ); + if (version < 0x800) ok( hr == DI_OK, "SendDeviceData returned %#lx\n", hr ); + else todo_wine ok( hr == DIERR_INVALIDPARAM, "SendDeviceData returned %#lx\n", hr ); + + test_constantforce_effect( device, file, version ); + test_periodic_effect( device, file, version ); + test_condition_effect( device, file, version ); + + set_hid_expect( file, expect_reset, sizeof(expect_reset) ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "Release returned %ld\n", ref ); + + DestroyWindow( hwnd ); + CloseHandle( file ); + +done: + hid_device_stop( &desc, 1 ); + cleanup_registry_keys(); + winetest_pop_context(); + + return device != NULL; +} + +static void test_condition_effect_six_axes( IDirectInputDevice8W *device, HANDLE file ) +{ + struct hid_expect expect_create[] = + { + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 9, + .report_buf = {0x07,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00}, }, - { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(3), - .tszName = L"Collection 3 - PID Device Control Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_DEVICE_CONTROL_REPORT, + /* set condition */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 9, + .report_buf = {0x07,0x00,0x00,0x7f,0x7f,0x7f,0xff,0xff,0xff}, }, + /* set condition */ { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(4), - .tszName = L"Collection 4 - PID Device Control", - .wCollectionNumber = 3, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_DEVICE_CONTROL, + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 9, + .report_buf = {0x07,0x00,0x00,0x80,0x7f,0x80,0xff,0xff,0x00}, }, + /* set condition */ { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(5), - .tszName = L"Collection 5 - Effect Operation Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_EFFECT_OPERATION_REPORT, + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 9, + .report_buf = {0x07,0x00,0x00,0x7f,0xff,0x80,0x00,0xff,0xff}, }, + /* set condition */ { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(6), - .tszName = L"Collection 6 - Effect Operation", - .wCollectionNumber = 5, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_EFFECT_OPERATION, + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 9, + .report_buf = {0x07,0x00,0x00,0xff,0x7f,0xff,0xff,0x00,0x00}, }, + /* set condition */ { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(7), - .tszName = L"Collection 7 - Set Effect Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_SET_EFFECT_REPORT, + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 9, + .report_buf = {0x07,0x00,0x00,0x7f,0x7f,0xff,0xff,0x00,0xff}, }, + /* create effect */ { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(8), - .tszName = L"Collection 8 - Effect Type", - .wCollectionNumber = 7, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_EFFECT_TYPE, + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 15, + .report_buf = {0x03,0x01,0x03,0x40,0x01,0x00,0x06,0x00,0x01,0x7f,0x2a,0xea,0xf5,0x1f,0x00}, }, + }; + struct hid_expect expect_destroy[] = + { + /* effect operation */ { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(9), - .tszName = L"Collection 9 - Axes Enable", - .wCollectionNumber = 7, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_AXES_ENABLE, + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {0x02,0x01,0x03,0x00}, }, + }; + static const DWORD expect_axes[6] = + { + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 4 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 5 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 3 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR, + }; + static const LONG expect_directions[6] = + { + 9000, + 6000, + 33000, + 34500, + 4500, + 0, + }; + static const DIENVELOPE expect_envelope = + { + .dwSize = sizeof(DIENVELOPE), + .dwAttackLevel = 1000, + .dwAttackTime = 2000, + .dwFadeLevel = 3000, + .dwFadeTime = 4000, + }; + static const DICONDITION expect_condition[6] = + { { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(10), - .tszName = L"Collection 10 - Direction", - .wCollectionNumber = 7, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_DIRECTION, + .lOffset = -10000, + .lPositiveCoefficient = -10000, + .lNegativeCoefficient = -10000, + .dwPositiveSaturation = 0, + .dwNegativeSaturation = 0, + .lDeadBand = 0, }, { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(11), - .tszName = L"Collection 11 - Set Periodic Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_SET_PERIODIC_REPORT, + .lOffset = 10000, + .lPositiveCoefficient = 10000, + .lNegativeCoefficient = 10000, + .dwPositiveSaturation = 10000, + .dwNegativeSaturation = 10000, + .lDeadBand = 10000, }, { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(12), - .tszName = L"Collection 12 - Set Envelope Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_SET_ENVELOPE_REPORT, + .lOffset = -10000, + .lPositiveCoefficient = +10000, + .lNegativeCoefficient = -10000, + .dwPositiveSaturation = +10000, + .dwNegativeSaturation = -10000, + .lDeadBand = 0, }, { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(13), - .tszName = L"Collection 13 - Set Condition Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_SET_CONDITION_REPORT, + .lOffset = +10000, + .lPositiveCoefficient = 0, + .lNegativeCoefficient = -10000, + .dwPositiveSaturation = 0, + .dwNegativeSaturation = -10000, + .lDeadBand = 20000, }, { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(14), - .tszName = L"Collection 14 - Type Specific Block Offset", - .wCollectionNumber = 13, - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_TYPE_SPECIFIC_BLOCK_OFFSET, + .lOffset = 0, + .lPositiveCoefficient = +10000, + .lNegativeCoefficient = 0, + .dwPositiveSaturation = +10000, + .dwNegativeSaturation = 0, + .lDeadBand = 0, }, { - .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), - .guidType = GUID_Unknown, - .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(15), - .tszName = L"Collection 15 - Device Gain Report", - .wUsagePage = HID_USAGE_PAGE_PID, - .wUsage = PID_USAGE_DEVICE_GAIN_REPORT, + .lOffset = 10000, + .lPositiveCoefficient = +10000, + .lNegativeCoefficient = 0, + .dwPositiveSaturation = +10000, + .dwNegativeSaturation = 0, + .lDeadBand = 20000, }, }; - const DIEFFECTINFOW expect_effects[] = + const DIEFFECT expect_desc = + { + .dwSize = sizeof(DIEFFECT_DX6), + .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, + .dwDuration = 1000, + .dwSamplePeriod = 2000, + .dwGain = 3000, + .dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, + .dwTriggerRepeatInterval = 5000, + .cAxes = 6, + .rgdwAxes = (void *)expect_axes, + .rglDirection = (void *)expect_directions, + .lpEnvelope = (void *)&expect_envelope, + .cbTypeSpecificParams = 6 * sizeof(DICONDITION), + .lpvTypeSpecificParams = (void *)expect_condition, + .dwStartDelay = 6000, + }; + struct check_created_effect_params check_params = {0}; + DIENVELOPE envelope = {.dwSize = sizeof(DIENVELOPE)}; + DICONDITION condition[6] = {{0}}; + IDirectInputEffect *effect; + LONG directions[6] = {0}; + DWORD axes[6] = {0}; + DIEFFECT desc = + { + .dwSize = sizeof(DIEFFECT_DX6), + .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, + .cAxes = 6, + .rgdwAxes = axes, + .rglDirection = directions, + .lpEnvelope = &envelope, + .cbTypeSpecificParams = 6 * sizeof(DICONDITION), + .lpvTypeSpecificParams = condition, + }; + HRESULT hr; + ULONG ref; + GUID guid; + + set_hid_expect( file, expect_create, sizeof(expect_create) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &expect_desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + check_params.expect_effect = effect; + hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_created_effect_objects, &check_params, 0 ); + ok( hr == DI_OK, "EnumCreatedEffectObjects returned %#lx\n", hr ); + ok( check_params.count == 1, "got count %lu, expected 1\n", check_params.count ); + + hr = IDirectInputEffect_GetEffectGuid( effect, &guid ); + ok( hr == DI_OK, "GetEffectGuid returned %#lx\n", hr ); + ok( IsEqualGUID( &guid, &GUID_Spring ), "got guid %s, expected %s\n", debugstr_guid( &guid ), + debugstr_guid( &GUID_Spring ) ); + + hr = IDirectInputEffect_GetParameters( effect, &desc, DIEP_ALLPARAMS ); + ok( hr == DI_OK, "GetParameters returned %#lx\n", hr ); + check_member( desc, expect_desc, "%lu", cAxes ); + check_member( desc, expect_desc, "%#lx", rgdwAxes[0] ); + check_member( desc, expect_desc, "%#lx", rgdwAxes[1] ); + check_member( desc, expect_desc, "%#lx", rgdwAxes[2] ); + check_member( desc, expect_desc, "%#lx", rgdwAxes[3] ); + check_member( desc, expect_desc, "%#lx", rgdwAxes[4] ); + check_member( desc, expect_desc, "%#lx", rgdwAxes[5] ); + check_member( desc, expect_desc, "%ld", rglDirection[0] ); + check_member( desc, expect_desc, "%ld", rglDirection[1] ); + check_member( desc, expect_desc, "%ld", rglDirection[2] ); + check_member( desc, expect_desc, "%ld", rglDirection[3] ); + check_member( desc, expect_desc, "%ld", rglDirection[4] ); + check_member( desc, expect_desc, "%ld", rglDirection[5] ); + check_member( desc, expect_desc, "%lu", cbTypeSpecificParams ); + + set_hid_expect( file, expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); +} + +static BOOL test_force_feedback_six_axes(void) +{ +#include "psh_hid_macros.h" + const unsigned char report_descriptor[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + USAGE(1, HID_USAGE_GENERIC_Z), + USAGE(1, HID_USAGE_GENERIC_RX), + USAGE(1, HID_USAGE_GENERIC_RY), + USAGE(1, HID_USAGE_GENERIC_RZ), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 6), + INPUT(1, Data|Var|Abs), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 6), + INPUT(1, Cnst|Var|Abs), + END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_PID), + USAGE(1, PID_USAGE_STATE_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 2), + + USAGE(1, PID_USAGE_DEVICE_PAUSED), + USAGE(1, PID_USAGE_ACTUATORS_ENABLED), + USAGE(1, PID_USAGE_SAFETY_SWITCH), + USAGE(1, PID_USAGE_ACTUATOR_OVERRIDE_SWITCH), + USAGE(1, PID_USAGE_ACTUATOR_POWER), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 5), + INPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 3), + INPUT(1, Cnst|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_PLAYING), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MAXIMUM(1, 0x7f), + LOGICAL_MINIMUM(1, 0x00), + REPORT_SIZE(1, 7), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_PID), + USAGE(1, PID_USAGE_DEVICE_CONTROL_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, PID_USAGE_DEVICE_CONTROL), + COLLECTION(1, Logical), + USAGE(1, PID_USAGE_DC_DEVICE_RESET), + USAGE(1, PID_USAGE_DC_STOP_ALL_EFFECTS), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 2), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + END_COLLECTION, + + USAGE(1, PID_USAGE_EFFECT_OPERATION_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 2), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_OPERATION), + COLLECTION(1, NamedArray), + USAGE(1, PID_USAGE_OP_EFFECT_START), + USAGE(1, PID_USAGE_OP_EFFECT_START_SOLO), + USAGE(1, PID_USAGE_OP_EFFECT_STOP), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 3), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 3), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_LOOP_COUNT), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_EFFECT_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 3), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_TYPE), + COLLECTION(1, NamedArray), + USAGE(1, PID_USAGE_ET_SQUARE), + USAGE(1, PID_USAGE_ET_SINE), + USAGE(1, PID_USAGE_ET_SPRING), + USAGE(1, PID_USAGE_ET_CONSTANT_FORCE), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 4), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 4), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_AXES_ENABLE), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_X), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Y), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_Z), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_RX), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_RY), + USAGE(4, (HID_USAGE_PAGE_GENERIC << 16)|HID_USAGE_GENERIC_RZ), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 6), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + USAGE(1, PID_USAGE_DIRECTION_ENABLE), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 1), + OUTPUT(1, Cnst|Var|Abs), + + USAGE(1, PID_USAGE_DURATION), + USAGE(1, PID_USAGE_START_DELAY), + UNIT(2, 0x1003), /* Eng Lin:Time */ + UNIT_EXPONENT(1, -3), /* 10^-3 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x7fff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x7fff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + UNIT(1, 0), + UNIT_EXPONENT(1, 0), + + USAGE(1, PID_USAGE_TRIGGER_BUTTON), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 0x08), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 0x08), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_DIRECTION), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|3), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|4), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|5), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|6), + UNIT(1, 0x14), /* Eng Rot:Angular Pos */ + UNIT_EXPONENT(1, -2), /* 10^-2 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(4, 0x00008ca0), + UNIT(1, 0), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 6), + OUTPUT(1, Data|Var|Abs), + UNIT_EXPONENT(1, 0), + UNIT(1, 0), + END_COLLECTION, + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_PERIODIC_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 5), + + USAGE(1, PID_USAGE_MAGNITUDE), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_ENVELOPE_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 6), + + USAGE(1, PID_USAGE_ATTACK_LEVEL), + USAGE(1, PID_USAGE_FADE_LEVEL), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_ATTACK_TIME), + USAGE(1, PID_USAGE_FADE_TIME), + UNIT(2, 0x1003), /* Eng Lin:Time */ + UNIT_EXPONENT(1, -3), /* 10^-3 */ + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x7fff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x7fff), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 2), + OUTPUT(1, Data|Var|Abs), + PHYSICAL_MAXIMUM(1, 0), + UNIT_EXPONENT(1, 0), + UNIT(1, 0), + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_CONDITION_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 7), + + USAGE(1, PID_USAGE_TYPE_SPECIFIC_BLOCK_OFFSET), + COLLECTION(1, Logical), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|1), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|2), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|3), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|4), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|5), + USAGE(4, (HID_USAGE_PAGE_ORDINAL << 16)|6), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 2), + REPORT_COUNT(1, 6), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + REPORT_SIZE(1, 2), + REPORT_COUNT(1, 2), + OUTPUT(1, Cnst|Var|Abs), + + USAGE(1, PID_USAGE_CP_OFFSET), + USAGE(1, PID_USAGE_POSITIVE_COEFFICIENT), + USAGE(1, PID_USAGE_NEGATIVE_COEFFICIENT), + LOGICAL_MINIMUM(1, 0x80), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(2, 0xd8f0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 3), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_POSITIVE_SATURATION), + USAGE(1, PID_USAGE_NEGATIVE_SATURATION), + USAGE(1, PID_USAGE_DEAD_BAND), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 3), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + + USAGE(1, PID_USAGE_DEVICE_GAIN_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 8), + + USAGE(1, PID_USAGE_DEVICE_GAIN), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(2, 0x00ff), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_SET_CONSTANT_FORCE_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 9), + + USAGE(1, PID_USAGE_MAGNITUDE), + LOGICAL_MINIMUM(2, 0xd8f0), + LOGICAL_MAXIMUM(2, 0x2710), + PHYSICAL_MINIMUM(2, 0xd8f0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + + END_COLLECTION, + }; + C_ASSERT(sizeof(report_descriptor) < MAX_HID_DESCRIPTOR_LEN); +#include "pop_hid_macros.h" + + struct hid_device_desc desc = { + .use_report_id = TRUE, + .caps = { - .dwSize = sizeof(DIEFFECTINFOW), - .guid = GUID_Square, - .dwEffType = DIEFT_PERIODIC | DIEFT_STARTDELAY | DIEFT_FFFADE | DIEFT_FFATTACK, - .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, - .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, - .tszName = L"GUID_Square", - }, - { - .dwSize = sizeof(DIEFFECTINFOW), - .guid = GUID_Sine, - .dwEffType = DIEFT_PERIODIC | DIEFT_STARTDELAY | DIEFT_FFFADE | DIEFT_FFATTACK, - .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, - .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, - .tszName = L"GUID_Sine", + .InputReportByteLength = 8, + .OutputReportByteLength = 15, }, - { - .dwSize = sizeof(DIEFFECTINFOW), - .guid = GUID_Spring, - .dwEffType = DIEFT_CONDITION | DIEFT_STARTDELAY | DIEFT_DEADBAND | DIEFT_SATURATION, - .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION, - .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | - DIEP_DURATION, - .tszName = L"GUID_Spring", - } - }; - - struct check_objects_todos todo_objects_5[ARRAY_SIZE(expect_objects_5)] = - { - {.guid = TRUE, .type = TRUE, .usage = TRUE, .name = TRUE}, - {0}, - {.guid = TRUE, .type = TRUE, .usage = TRUE, .name = TRUE}, + .attributes = default_attributes, }; - struct check_objects_params check_objects_params = + const DIDEVCAPS expect_caps = { - .version = version, - .expect_count = version < 0x700 ? ARRAY_SIZE(expect_objects_5) : ARRAY_SIZE(expect_objects), - .expect_objs = version < 0x700 ? expect_objects_5 : expect_objects, - .todo_objs = version < 0x700 ? todo_objects_5 : NULL, - .todo_extra = version < 0x700, + .dwSize = sizeof(DIDEVCAPS), + .dwFlags = DIDC_FORCEFEEDBACK | DIDC_ATTACHED | DIDC_EMULATED | DIDC_STARTDELAY | + DIDC_FFFADE | DIDC_FFATTACK | DIDC_DEADBAND | DIDC_SATURATION, + .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPE1STPERSON_LIMITED << 8) | DI8DEVTYPE_1STPERSON, + .dwAxes = 6, + .dwButtons = 2, + .dwFFSamplePeriod = 1000000, + .dwFFMinTimeResolution = 1000000, + .dwHardwareRevision = 1, + .dwFFDriverVersion = 1, }; - struct check_effects_params check_effects_params = + const DIDEVICEINSTANCEW expect_devinst = { - .expect_count = ARRAY_SIZE(expect_effects), - .expect_effects = expect_effects, + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPE1STPERSON_LIMITED << 8) | DI8DEVTYPE_1STPERSON, + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", + .guidFFDriver = IID_IDirectInputPIDDriver, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, }; DIPROPDWORD prop_dword = { @@ -3023,17 +4281,41 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwHow = DIPH_DEVICE, }, }; + struct hid_expect expect_acquire[] = + { + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, + /* device gain */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 8, + .report_len = 2, + .report_buf = {8, 0xff}, + }, + }; + struct hid_expect expect_reset[] = + { + /* device control */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, + }; DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; IDirectInputDevice8W *device = NULL; - DIDEVICEOBJECTDATA objdata = {0}; - DIEFFECTINFOW effectinfo = {0}; - DIEFFESCAPE escape = {0}; DIDEVCAPS caps = {0}; - char buffer[1024]; - ULONG res, ref; + DWORD version = 0x800; HANDLE file; HRESULT hr; HWND hwnd; + ULONG ref; winetest_push_context( "%#lx", version ); cleanup_registry_keys(); @@ -3050,10 +4332,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); ok( hr == DI_OK, "GetDeviceInfo returned %#lx\n", hr ); check_member( devinst, expect_devinst, "%lu", dwSize ); - todo_wine - check_member_guid( devinst, expect_devinst, guidInstance ); check_member_guid( devinst, expect_devinst, guidProduct ); - check_member( devinst, expect_devinst, "%#lx", dwDevType ); + todo_wine check_member( devinst, expect_devinst, "%#lx", dwDevType ); check_member_wstr( devinst, expect_devinst, tszInstanceName ); check_member_wstr( devinst, expect_devinst, tszProductName ); check_member_guid( devinst, expect_devinst, guidFFDriver ); @@ -3065,7 +4345,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) ok( hr == DI_OK, "GetCapabilities returned %#lx\n", hr ); check_member( caps, expect_caps, "%lu", dwSize ); check_member( caps, expect_caps, "%#lx", dwFlags ); - check_member( caps, expect_caps, "%#lx", dwDevType ); + todo_wine check_member( caps, expect_caps, "%#lx", dwDevType ); check_member( caps, expect_caps, "%lu", dwAxes ); check_member( caps, expect_caps, "%lu", dwButtons ); check_member( caps, expect_caps, "%lu", dwPOVs ); @@ -3083,33 +4363,6 @@ static BOOL test_force_feedback_joystick( DWORD version ) hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetProperty DIPROP_FFLOAD returned %#lx\n", hr ); - hr = IDirectInputDevice8_EnumObjects( device, check_objects, &check_objects_params, DIDFT_ALL ); - ok( hr == DI_OK, "EnumObjects returned %#lx\n", hr ); - ok( check_objects_params.index >= check_objects_params.expect_count, "missing %u objects\n", - check_objects_params.expect_count - check_objects_params.index ); - - res = 0; - hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, 0xfe ); - ok( hr == DI_OK, "EnumEffects returned %#lx\n", hr ); - ok( res == 0, "got %lu expected %u\n", res, 0 ); - res = 0; - hr = IDirectInputDevice8_EnumEffects( device, check_effect_count, &res, DIEFT_PERIODIC ); - ok( hr == DI_OK, "EnumEffects returned %#lx\n", hr ); - ok( res == 2, "got %lu expected %u\n", res, 2 ); - hr = IDirectInputDevice8_EnumEffects( device, check_effects, &check_effects_params, DIEFT_ALL ); - ok( hr == DI_OK, "EnumEffects returned %#lx\n", hr ); - ok( check_effects_params.index >= check_effects_params.expect_count, "missing %u effects\n", - check_effects_params.expect_count - check_effects_params.index ); - - effectinfo.dwSize = sizeof(DIEFFECTINFOW); - hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Sine ); - ok( hr == DI_OK, "GetEffectInfo returned %#lx\n", hr ); - check_member_guid( effectinfo, expect_effects[1], guid ); - check_member( effectinfo, expect_effects[1], "%#lx", dwEffType ); - check_member( effectinfo, expect_effects[1], "%#lx", dwStaticParams ); - check_member( effectinfo, expect_effects[1], "%#lx", dwDynamicParams ); - check_member_wstr( effectinfo, expect_effects[1], tszName ); - hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); ok( hr == DI_OK, "SetDataFormat returned: %#lx\n", hr ); @@ -3123,130 +4376,16 @@ static BOOL test_force_feedback_joystick( DWORD version ) hwnd = create_foreground_window( FALSE ); - hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE ); - ok( hr == DI_OK, "SetCooperativeLevel returned: %#lx\n", hr ); - - prop_dword.diph.dwHow = DIPH_BYUSAGE; - prop_dword.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); - prop_dword.dwData = DIPROPAUTOCENTER_ON; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); - ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_AUTOCENTER returned %#lx\n", hr ); - prop_dword.diph.dwHow = DIPH_DEVICE; - prop_dword.diph.dwObj = 0; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_AUTOCENTER returned %#lx\n", hr ); - - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); - ok( hr == DIERR_INVALIDPARAM, "SetProperty DIPROP_FFGAIN returned %#lx\n", hr ); - prop_dword.dwData = 1000; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#lx\n", hr ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - ok( hr == DIERR_READONLY, "SetProperty DIPROP_FFLOAD returned %#lx\n", hr ); - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetProperty DIPROP_FFLOAD returned %#lx\n", hr ); - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "GetForceFeedbackState returned %#lx\n", hr ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "SendForceFeedbackCommand returned %#lx\n", hr ); - - escape.dwSize = sizeof(DIEFFESCAPE); - escape.dwCommand = 0; - escape.lpvInBuffer = buffer; - escape.cbInBuffer = 10; - escape.lpvOutBuffer = buffer + 10; - escape.cbOutBuffer = 10; - hr = IDirectInputDevice8_Escape( device, &escape ); - todo_wine - ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "Escape returned: %#lx\n", hr ); - - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#lx\n", hr ); hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); ok( hr == DI_OK, "SetCooperativeLevel returned: %#lx\n", hr ); - prop_dword.dwData = DIPROPAUTOCENTER_OFF; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_AUTOCENTER returned %#lx\n", hr ); - - set_hid_expect( file, expect_acquire_autocenter_off, sizeof(expect_acquire_autocenter_off) ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); - wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ - - set_hid_expect( file, expect_reset, sizeof(expect_reset) ); - hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#lx\n", hr ); - prop_dword.dwData = DIPROPAUTOCENTER_ON; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_AUTOCENTER returned %#lx\n", hr ); - - set_hid_expect( file, expect_acquire_autocenter_on, sizeof(expect_acquire_autocenter_on) ); + set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); hr = IDirectInputDevice8_Acquire( device ); ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); - wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ - - set_hid_expect( file, &expect_set_device_gain_2, sizeof(expect_set_device_gain_2) ); - prop_dword.dwData = 2000; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#lx\n", hr ); - wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ - - set_hid_expect( file, &expect_set_device_gain_1, sizeof(expect_set_device_gain_1) ); - prop_dword.dwData = 1000; - hr = IDirectInputDevice8_SetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); - ok( hr == DI_OK, "SetProperty DIPROP_FFGAIN returned %#lx\n", hr ); - wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ - - hr = IDirectInputDevice8_Escape( device, &escape ); - todo_wine - ok( hr == DIERR_UNSUPPORTED, "Escape returned: %#lx\n", hr ); - - prop_dword.dwData = 0xdeadbeef; - hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); - todo_wine - ok( hr == 0x80040301, "GetProperty DIPROP_FFLOAD returned %#lx\n", hr ); - res = 0xdeadbeef; - hr = IDirectInputDevice8_GetForceFeedbackState( device, &res ); - todo_wine - ok( hr == 0x80040301, "GetForceFeedbackState returned %#lx\n", hr ); - - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, 0xdeadbeef ); - ok( hr == DIERR_INVALIDPARAM, "SendForceFeedbackCommand returned %#lx\n", hr ); - - set_hid_expect( file, expect_acquire_autocenter_on, sizeof(expect_acquire_autocenter_on) ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); - ok( hr == DI_OK, "SendForceFeedbackCommand returned %#lx\n", hr ); - wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ - - set_hid_expect( file, expect_stop_all, sizeof(expect_stop_all) ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_STOPALL ); - ok( hr == DI_OK, "SendForceFeedbackCommand returned %#lx\n", hr ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_PAUSE ); - ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#lx\n", hr ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_CONTINUE ); - ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#lx\n", hr ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSON ); - ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#lx\n", hr ); - hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSOFF ); - ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#lx\n", hr ); - - objdata.dwOfs = 0x1e; - objdata.dwData = 0x80; - res = 1; - hr = IDirectInputDevice8_SendDeviceData( device, sizeof(DIDEVICEOBJECTDATA), &objdata, &res, 0 ); - if (version < 0x800) ok( hr == DI_OK, "SendDeviceData returned %#lx\n", hr ); - else todo_wine ok( hr == DIERR_INVALIDPARAM, "SendDeviceData returned %#lx\n", hr ); + wait_hid_expect( file, 100 ); - test_periodic_effect( device, file, version ); - test_condition_effect( device, file, version ); + test_condition_effect_six_axes( device, file ); - set_hid_expect( file, expect_reset, sizeof(expect_reset) ); + set_hid_expect( file, expect_reset, sizeof(struct hid_expect) ); hr = IDirectInputDevice8_Unacquire( device ); ok( hr == DI_OK, "Unacquire returned: %#lx\n", hr ); set_hid_expect( file, NULL, 0 ); @@ -3261,7 +4400,6 @@ static BOOL test_force_feedback_joystick( DWORD version ) hid_device_stop( &desc, 1 ); cleanup_registry_keys(); winetest_pop_context(); - return device != NULL; } @@ -6831,7 +7969,8 @@ START_TEST( force_feedback ) test_force_feedback_joystick( 0x500 ); test_force_feedback_joystick( 0x700 ); test_device_managed_effect(); - test_windows_gaming_input(); + test_force_feedback_six_axes(); + test_windows_gaming_input(); /* keep it last, seems to mess with other tests */ } done: diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index 5e48050738be..06f1e4ee7e55 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -719,7 +719,8 @@ void hid_device_stop( struct hid_device_desc *desc, UINT count ) NULL, OPEN_EXISTING, 0, NULL ); ok( control != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu\n", GetLastError() ); ret = sync_ioctl( control, IOCTL_WINETEST_REMOVE_DEVICE, desc, sizeof(*desc), NULL, 0, 5000 ); - ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "IOCTL_WINETEST_REMOVE_DEVICE failed, last error %lu\n", GetLastError() ); + ok( ret || (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_NO_SUCH_DEVICE), + "IOCTL_WINETEST_REMOVE_DEVICE failed, last error %lu\n", GetLastError() ); CloseHandle( control ); if (!ret) return; diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 30ebdbacaf8f..afc24e49c8fd 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -2077,7 +2077,6 @@ static void test_simple_joystick( DWORD version ) prop_dword.dwData = 0xdeadbeef; hr = IDirectInputDevice8_GetProperty( device, DIPROP_JOYSTICKID, &prop_dword.diph ); ok( hr == DI_OK, "GetProperty DIPROP_JOYSTICKID returned %#lx\n", hr ); - todo_wine ok( prop_dword.dwData == 0, "got %#lx expected 0\n", prop_dword.dwData ); prop_dword.dwData = 0xdeadbeef; @@ -5174,7 +5173,6 @@ static void test_windows_gaming_input(void) ok( hr == S_OK, "get_Gamepads returned %#lx\n", hr ); hr = IVectorView_Gamepad_get_Size( gamepads_view, &size ); ok( hr == S_OK, "get_Size returned %#lx\n", hr ); - todo_wine /* but Wine currently intentionally does */ ok( size == 0, "got size %u\n", size ); IVectorView_Gamepad_Release( gamepads_view ); IGamepadStatics_Release( gamepad_statics ); @@ -5216,16 +5214,12 @@ static void test_windows_gaming_input(void) ok( hr == S_OK, "QueryInterface returned %#lx\n", hr ); hr = IRawGameController2_get_DisplayName( raw_controller2, &str ); - todo_wine ok( hr == S_OK, "get_DisplayName returned %#lx\n", hr ); - if (hr == S_OK) - { - buffer = pWindowsGetStringRawBuffer( str, &length ); - todo_wine - ok( !wcscmp( buffer, L"HID-compliant game controller" ), - "get_DisplayName returned %s\n", debugstr_wn( buffer, length ) ); - pWindowsDeleteString( str ); - } + buffer = pWindowsGetStringRawBuffer( str, &length ); + todo_wine + ok( !wcscmp( buffer, L"HID-compliant game controller" ), + "get_DisplayName returned %s\n", debugstr_wn( buffer, length ) ); + pWindowsDeleteString( str ); hr = IRawGameController2_get_NonRoamableId( raw_controller2, &str ); todo_wine @@ -5970,6 +5964,158 @@ static void test_rawinput_desktop( const char *path, BOOL input ) DestroyWindow( hwnd ); } +struct select_default_instance_data +{ + IDirectInput8W *di8; + DIDEVICEINSTANCEW default_instance; + BOOL default_instance_found; +}; + +static BOOL CALLBACK select_default_instance( const DIDEVICEINSTANCEW *devinst, void *context ) +{ + DIPROPGUIDANDPATH prop_guid_path = + { + .diph = + { + .dwSize = sizeof(DIPROPGUIDANDPATH), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + + DIPROPDWORD prop_dword = + { + .diph = + { + .dwSize = sizeof(DIPROPDWORD), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + struct select_default_instance_data *d = context; + IDirectInputDevice8W *device; + HRESULT hr; + + hr = IDirectInput8_CreateDevice( d->di8, &devinst->guidInstance, &device, NULL ); + ok( hr == DI_OK, "got hr %#lx.\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_JOYSTICKID, &prop_dword.diph ); + ok( hr == DI_OK, "got hr %#lx.\n", hr ); + ok( prop_dword.dwData < 100, "got %lu.\n", prop_dword.dwData ); + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph ); + ok( hr == DI_OK, "got hr %#lx.\n", hr ); + trace( "%s, id %lu, inst %s, path %s.\n", debugstr_w(devinst->tszInstanceName), prop_dword.dwData, + debugstr_guid(&devinst->guidInstance), debugstr_w(prop_guid_path.wszPath) ); + if (!prop_dword.dwData) + { + ok( !d->default_instance_found, "duplicate joystick with id 0.\n" ); + d->default_instance = *devinst; + d->default_instance_found = TRUE; + } + IDirectInputDevice8_Release( device ); + return DIENUM_CONTINUE; +} + +static void test_joystick_id(void) +{ +#include "psh_hid_macros.h" + const unsigned char report_desc[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Physical), + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 6), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 8), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; + C_ASSERT(sizeof(report_desc) < MAX_HID_DESCRIPTOR_LEN); +#include "pop_hid_macros.h" + struct hid_device_desc desc = + { + .use_report_id = TRUE, + .caps = { .InputReportByteLength = 1 }, + }; + struct hid_device_desc desc2; + + DIPROPDWORD prop_dword = + { + .diph = + { + .dwSize = sizeof(DIPROPDWORD), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + struct select_default_instance_data d = { NULL }; + IDirectInputDevice8W *device; + IDirectInput8W *di8; + HRESULT hr; + + cleanup_registry_keys(); + + hr = DirectInput8Create( instance, DIRECTINPUT_VERSION, &IID_IDirectInput8W, (void **)&di8, NULL ); + if (FAILED(hr)) + { + win_skip( "DirectInput8Create returned %#lx.\n", hr ); + return; + } + + desc.report_descriptor_len = sizeof(report_desc); + memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) ); + fill_context( desc.context, ARRAY_SIZE(desc.context) ); + + desc.attributes = default_attributes; + desc2 = desc; + desc2.attributes.ProductID++; + if (!hid_device_start( &desc, 1 )) goto done; + if (!hid_device_start( &desc2, 1 )) goto done; + + d.di8 = di8; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_GAMECTRL, select_default_instance, &d, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "got hr %#lx.\n", hr ); + + hr = IDirectInput8_CreateDevice( di8, &GUID_Joystick, &device, NULL ); + if (d.default_instance_found) + { + ok( hr == DI_OK, "got %#lx.\n", hr ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_JOYSTICKID, &prop_dword.diph ); + ok( hr == DI_OK, "got hr %#lx.\n", hr ); + ok( !prop_dword.dwData, "got %lu.\n", prop_dword.dwData ); + IDirectInputDevice8_Release( device ); + } + else + { + ok( hr == DIERR_DEVICENOTREG, "got %#lx.\n", hr ); + } + + hid_device_stop( &desc, 1 ); + + memset( &d, 0, sizeof(d) ); + d.di8 = di8; + hr = IDirectInput8_EnumDevices( di8, DI8DEVCLASS_GAMECTRL, select_default_instance, &d, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "got hr %#lx.\n", hr ); + ok( !d.default_instance_found, "found joystick id 0.\n" ); + hr = IDirectInput8_CreateDevice( di8, &GUID_Joystick, &device, NULL ); + ok( hr == DIERR_DEVICENOTREG, "got %#lx.\n", hr ); + +done: + IDirectInput8_Release( di8 ); + hid_device_stop( &desc, 1 ); + hid_device_stop( &desc2, 1 ); + cleanup_registry_keys(); +} + START_TEST( joystick8 ) { char **argv; @@ -5981,11 +6127,11 @@ START_TEST( joystick8 ) dinput_test_init(); if (!bus_device_start()) goto done; - winetest_mute_threshold = 3; if (test_device_types( 0x800 )) { + test_joystick_id(); /* This needs to be done before doing anything involving dinput.dll * on Windows, or the tests will fail, dinput8.dll is fine though. */ test_winmm_joystick(); diff --git a/dlls/dinput8/Makefile.in b/dlls/dinput8/Makefile.in index f3f5fdc4fd84..ac5b89747f78 100644 --- a/dlls/dinput8/Makefile.in +++ b/dlls/dinput8/Makefile.in @@ -2,6 +2,7 @@ MODULE = dinput8.dll IMPORTLIB = dinput8 IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi EXTRADEFS = -DDIRECTINPUT_VERSION=0x0800 +EXTRADLLFLAGS = -Wb,--prefer-native PARENTSRC = ../dinput SOURCES = \ diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index f2d1947d9a17..b3a297bebe81 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -77,7 +77,7 @@ extern void set_audiopath_perf_pointer(IDirectMusicAudioPath*,IDirectMusicPerfor extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*); extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*); -extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, +extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, DWORD segment_flags, IDirectMusicPerformance8 *performance, IDirectMusicSegmentState **ret_iface); extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); diff --git a/dlls/dmime/midi.c b/dlls/dmime/midi.c index 57b6a3adf90a..57fd5b078ad1 100644 --- a/dlls/dmime/midi.c +++ b/dlls/dmime/midi.c @@ -327,20 +327,36 @@ static HRESULT midi_parser_parse(struct midi_parser *parser, IDirectMusicSegment MUSIC_TIME music_length = 0; DMUS_IO_SEQ_ITEM *seq_items = NULL; struct midi_seqtrack_item *item; + DMUS_OBJECTDESC default_desc = + { + .dwSize = sizeof(DMUS_OBJECTDESC), + .dwValidData = DMUS_OBJ_OBJECT | DMUS_OBJ_CLASS, + .guidClass = CLSID_DirectMusicCollection, + .guidObject = GUID_DefaultGMCollection, + }; + IDirectMusicObject *collection = NULL; TRACE("(%p, %p): semi-stub\n", parser, segment); + if (FAILED(hr = stream_get_object(parser->stream, &default_desc, &IID_IDirectMusicCollection, + (void **)&collection))) + WARN("Failed to load default collection from loader, hr %#lx\n", hr); for (i = 0;; i++) { - BYTE magic[4] = {0}, last_status = 0; + BYTE magic[4], last_status = 0; DWORD length_be; ULONG length; ULONG read = 0; struct midi_event event = {0}; TRACE("Start parsing track %u\n", i); - if ((hr = IStream_Read(parser->stream, magic, sizeof(magic), &read)) != S_OK) break; - if (read < sizeof(magic)) break; + hr = IStream_Read(parser->stream, magic, sizeof(magic), &read); + if (read < sizeof(magic)) + { + if (hr == E_FAIL) hr = S_OK; + break; + } + if (FAILED(hr)) break; if (memcmp(magic, "MTrk", 4) != 0) break; if ((hr = IStream_Read(parser->stream, &length_be, sizeof(length_be), &read)) != S_OK) @@ -399,6 +415,7 @@ static HRESULT midi_parser_parse(struct midi_parser *parser, IDirectMusicSegment qsort(seq_items, parser->seqtrack_items_count, sizeof(DMUS_IO_SEQ_ITEM), midi_seqtrack_item_compare); music_length = (ULONGLONG)music_length * DMUS_PPQ / parser->division + 1; + if (collection) IDirectMusicTrack_SetParam(parser->bandtrack, &GUID_ConnectToDLSCollection, 0, collection); if (SUCCEEDED(hr)) hr = IDirectMusicSegment8_SetLength(segment, music_length); if (SUCCEEDED(hr)) hr = IDirectMusicSegment8_InsertTrack(segment, parser->bandtrack, 0xffff); if (SUCCEEDED(hr)) hr = IDirectMusicSegment8_InsertTrack(segment, parser->chordtrack, 0xffff); diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 500bc8b536f6..d9efe7167963 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1583,13 +1583,20 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, if (FAILED(hr = IUnknown_QueryInterface(source, &IID_IDirectMusicSegment, (void **)&segment))) return hr; + if (primary && SUCCEEDED(hr = IDirectMusicPerformance8_GetSegmentState(iface, &state, start_time))) + { + if (FAILED(hr = IDirectMusicPerformance_Stop(&This->IDirectMusicPerformance8_iface, NULL, state, start_time, 0))) + ERR("Failed to stop current previous segment, hr %#lx\n", hr); + IDirectMusicSegmentState_Release(state); + } + EnterCriticalSection(&This->safe); if (primary) performance_set_primary_segment(This, segment); if (control) performance_set_control_segment(This, segment); if ((!(music_time = start_time) && FAILED(hr = IDirectMusicPerformance8_GetTime(iface, NULL, &music_time))) - || FAILED(hr = segment_state_create(segment, music_time, iface, &state))) + || FAILED(hr = segment_state_create(segment, music_time, segment_flags, iface, &state))) { if (primary) performance_set_primary_segment(This, NULL); if (control) performance_set_control_segment(This, NULL); diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 4fece4181e18..2c6f88930d88 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -61,6 +61,7 @@ struct segment_state BOOL auto_download; DWORD repeats, actual_repeats; DWORD track_flags; + DWORD segment_flags; struct list tracks; }; @@ -118,7 +119,7 @@ static ULONG WINAPI segment_state_Release(IDirectMusicSegmentState8 *iface) if (!ref) { - segment_state_end_play((IDirectMusicSegmentState *)iface, NULL); + if (!(This->segment_flags & DMUS_SEGF_SECONDARY)) segment_state_end_play((IDirectMusicSegmentState *)iface, NULL); if (This->segment) IDirectMusicSegment_Release(This->segment); if (This->parent_graph) IDirectMusicGraph_Release(This->parent_graph); free(This); @@ -309,7 +310,7 @@ HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) return hr; } -HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, +HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, DWORD segment_flags, IDirectMusicPerformance8 *performance, IDirectMusicSegmentState **ret_iface) { IDirectMusicSegmentState *iface; @@ -324,6 +325,7 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time if (FAILED(hr = create_dmsegmentstate(&IID_IDirectMusicSegmentState, (void **)&iface))) return hr; This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + This->segment_flags = segment_flags; This->segment = segment; IDirectMusicSegment_AddRef(This->segment); @@ -436,6 +438,7 @@ static HRESULT segment_state_play_chunk(struct segment_state *This, IDirectMusic { MUSIC_TIME end_time = This->start_time + This->played; + if (This->segment_flags & DMUS_SEGF_SECONDARY) return S_OK; if (FAILED(hr = performance_send_segment_end(performance, end_time, iface, FALSE))) { ERR("Failed to send segment end, hr %#lx\n", hr); diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index 64480c6422f2..f34e8eeab8f5 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -139,7 +139,20 @@ static HRESULT WINAPI wave_track_InitPlay(IDirectMusicTrack8 *iface, static HRESULT WINAPI wave_track_EndPlay(IDirectMusicTrack8 *iface, void *pStateData) { struct wave_track *This = impl_from_IDirectMusicTrack8(iface); + struct wave_part *part; + struct wave_item *item; + FIXME("(%p, %p): stub\n", This, pStateData); + + LIST_FOR_EACH_ENTRY(part, &This->parts, struct wave_part, entry) + { + LIST_FOR_EACH_ENTRY(item, &part->items, struct wave_item, entry) + { + if (!item->buffer) continue; + IDirectSoundBuffer_Stop(item->buffer); + } + } + return S_OK; } diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index 3798a0851a0d..19c1c2ac9917 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -886,11 +886,40 @@ static const IDirectMusicLoader8Vtbl loader_vtbl = loader_LoadObjectFromFile, }; +static inline void touch_soundfont_used_tag(void) +{ + WCHAR env[MAX_PATH]; + + if (GetEnvironmentVariableW(L"STEAM_COMPAT_TRANSCODED_MEDIA_PATH", env, ARRAY_SIZE(env))) + { + WCHAR buffer[MAX_PATH]; + HANDLE file; + + swprintf(buffer, ARRAY_SIZE(buffer), L"\\??\\unix%s/soundfont-used", env); + + file = CreateFileW(buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (file == INVALID_HANDLE_VALUE) + { + ERR("Failed to open/create %s\n", debugstr_w(buffer)); + return; + } + + CloseHandle(file); + } + else + { + ERR("STEAM_COMPAT_TRANSCODED_MEDIA_PATH not set, cannot create soundfont-used file.\n"); + } +} + static HRESULT get_default_gm_path(WCHAR *path, DWORD max_len) { DWORD ret; HKEY hkey; + touch_soundfont_used_tag(); + if (!(ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\DirectMusic" , 0, KEY_READ, &hkey))) { DWORD type, size = max_len * sizeof(WCHAR); diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c index 7629810db505..e548cbbd5b1b 100644 --- a/dlls/dsound/dsound.c +++ b/dlls/dsound/dsound.c @@ -23,7 +23,6 @@ #include #include #include -#include #define COBJMACROS @@ -137,9 +136,9 @@ static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice) device->ref = 1; device->priolevel = DSSCL_NORMAL; device->stopped = 1; - device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE); - DSOUND_ParseSpeakerConfig(device); + device->speaker_config = 0; + device->num_speakers = 0; /* 3D listener initial parameters */ device->ds3dl.dwSize = sizeof(DS3DLISTENER); @@ -1128,75 +1127,3 @@ HRESULT WINAPI DirectSoundCreate8( return hr; } - -void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device) -{ - switch (DSSPEAKER_CONFIG(device->speaker_config)) { - case DSSPEAKER_MONO: - device->speaker_angles[0] = M_PI/180.0f * 0.0f; - device->speaker_num[0] = 0; - device->num_speakers = 1; - device->lfe_channel = -1; - break; - - case DSSPEAKER_STEREO: - case DSSPEAKER_HEADPHONE: - device->speaker_angles[0] = M_PI/180.0f * -90.0f; - device->speaker_angles[1] = M_PI/180.0f * 90.0f; - device->speaker_num[0] = 0; /* Left */ - device->speaker_num[1] = 1; /* Right */ - device->num_speakers = 2; - device->lfe_channel = -1; - break; - - case DSSPEAKER_QUAD: - device->speaker_angles[0] = M_PI/180.0f * -135.0f; - device->speaker_angles[1] = M_PI/180.0f * -45.0f; - device->speaker_angles[2] = M_PI/180.0f * 45.0f; - device->speaker_angles[3] = M_PI/180.0f * 135.0f; - device->speaker_num[0] = 2; /* Rear left */ - device->speaker_num[1] = 0; /* Front left */ - device->speaker_num[2] = 1; /* Front right */ - device->speaker_num[3] = 3; /* Rear right */ - device->num_speakers = 4; - device->lfe_channel = -1; - break; - - case DSSPEAKER_5POINT1_BACK: - device->speaker_angles[0] = M_PI/180.0f * -135.0f; - device->speaker_angles[1] = M_PI/180.0f * -45.0f; - device->speaker_angles[2] = M_PI/180.0f * 0.0f; - device->speaker_angles[3] = M_PI/180.0f * 45.0f; - device->speaker_angles[4] = M_PI/180.0f * 135.0f; - device->speaker_angles[5] = 9999.0f; - device->speaker_num[0] = 4; /* Rear left */ - device->speaker_num[1] = 0; /* Front left */ - device->speaker_num[2] = 2; /* Front centre */ - device->speaker_num[3] = 1; /* Front right */ - device->speaker_num[4] = 5; /* Rear right */ - device->speaker_num[5] = 3; /* LFE */ - device->num_speakers = 6; - device->lfe_channel = 3; - break; - - case DSSPEAKER_5POINT1_SURROUND: - device->speaker_angles[0] = M_PI/180.0f * -90.0f; - device->speaker_angles[1] = M_PI/180.0f * -30.0f; - device->speaker_angles[2] = M_PI/180.0f * 0.0f; - device->speaker_angles[3] = M_PI/180.0f * 30.0f; - device->speaker_angles[4] = M_PI/180.0f * 90.0f; - device->speaker_angles[5] = 9999.0f; - device->speaker_num[0] = 4; /* Rear left */ - device->speaker_num[1] = 0; /* Front left */ - device->speaker_num[2] = 2; /* Front centre */ - device->speaker_num[3] = 1; /* Front right */ - device->speaker_num[4] = 5; /* Rear right */ - device->speaker_num[5] = 3; /* LFE */ - device->num_speakers = 6; - device->lfe_channel = 3; - break; - - default: - WARN("unknown speaker_config %lu\n", device->speaker_config); - } -} diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c index bb373a4304d3..19e94c1071db 100644 --- a/dlls/dsound/dsound_main.c +++ b/dlls/dsound/dsound_main.c @@ -296,12 +296,22 @@ struct morecontext static BOOL CALLBACK a_to_w_callback(LPGUID guid, LPCWSTR descW, LPCWSTR modW, LPVOID data) { struct morecontext *context = data; - char descA[MAXPNAMELEN], modA[MAXPNAMELEN]; + char *descA, *modA; + DWORD len; + BOOL ret; + + len = WideCharToMultiByte(CP_ACP, 0, descW, -1, NULL, 0, NULL, NULL); + if ((descA = malloc(len))) + WideCharToMultiByte(CP_ACP, 0, descW, -1, descA, len, NULL, NULL); + len = WideCharToMultiByte(CP_ACP, 0, modW, -1, NULL, 0, NULL, NULL); + if ((modA = malloc(len))) + WideCharToMultiByte(CP_ACP, 0, modW, -1, modA, len, NULL, NULL); - WideCharToMultiByte(CP_ACP, 0, descW, -1, descA, sizeof(descA), NULL, NULL); - WideCharToMultiByte(CP_ACP, 0, modW, -1, modA, sizeof(modA), NULL, NULL); + ret = context->callA(guid, descA, modA, context->data); - return context->callA(guid, descA, modA, context->data); + free(descA); + free(modA); + return ret; } /*************************************************************************** diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 28bba6cd64ec..6b9fbfd6048c 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -209,7 +209,6 @@ HRESULT IKsPrivatePropertySetImpl_Create(REFIID riid, void **ppv); HRESULT DSOUND_Create(REFIID riid, void **ppv); HRESULT DSOUND_Create8(REFIID riid, void **ppv); HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8); -void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device); /* primary.c */ diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c index 2073a32240cd..c9b5a08cf5ef 100644 --- a/dlls/dsound/primary.c +++ b/dlls/dsound/primary.c @@ -24,6 +24,7 @@ */ #include +#include #define COBJMACROS #include "windef.h" @@ -107,6 +108,78 @@ static DWORD DSOUND_FindSpeakerConfig(IMMDevice *mmdevice, int channels) return def; } +static void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device) +{ + switch (DSSPEAKER_CONFIG(device->speaker_config)) { + case DSSPEAKER_MONO: + device->speaker_angles[0] = M_PI/180.0f * 0.0f; + device->speaker_num[0] = 0; + device->num_speakers = 1; + device->lfe_channel = -1; + break; + + case DSSPEAKER_STEREO: + case DSSPEAKER_HEADPHONE: + device->speaker_angles[0] = M_PI/180.0f * -90.0f; + device->speaker_angles[1] = M_PI/180.0f * 90.0f; + device->speaker_num[0] = 0; /* Left */ + device->speaker_num[1] = 1; /* Right */ + device->num_speakers = 2; + device->lfe_channel = -1; + break; + + case DSSPEAKER_QUAD: + device->speaker_angles[0] = M_PI/180.0f * -135.0f; + device->speaker_angles[1] = M_PI/180.0f * -45.0f; + device->speaker_angles[2] = M_PI/180.0f * 45.0f; + device->speaker_angles[3] = M_PI/180.0f * 135.0f; + device->speaker_num[0] = 2; /* Rear left */ + device->speaker_num[1] = 0; /* Front left */ + device->speaker_num[2] = 1; /* Front right */ + device->speaker_num[3] = 3; /* Rear right */ + device->num_speakers = 4; + device->lfe_channel = -1; + break; + + case DSSPEAKER_5POINT1_BACK: + device->speaker_angles[0] = M_PI/180.0f * -135.0f; + device->speaker_angles[1] = M_PI/180.0f * -45.0f; + device->speaker_angles[2] = M_PI/180.0f * 0.0f; + device->speaker_angles[3] = M_PI/180.0f * 45.0f; + device->speaker_angles[4] = M_PI/180.0f * 135.0f; + device->speaker_angles[5] = 9999.0f; + device->speaker_num[0] = 4; /* Rear left */ + device->speaker_num[1] = 0; /* Front left */ + device->speaker_num[2] = 2; /* Front centre */ + device->speaker_num[3] = 1; /* Front right */ + device->speaker_num[4] = 5; /* Rear right */ + device->speaker_num[5] = 3; /* LFE */ + device->num_speakers = 6; + device->lfe_channel = 3; + break; + + case DSSPEAKER_5POINT1_SURROUND: + device->speaker_angles[0] = M_PI/180.0f * -90.0f; + device->speaker_angles[1] = M_PI/180.0f * -30.0f; + device->speaker_angles[2] = M_PI/180.0f * 0.0f; + device->speaker_angles[3] = M_PI/180.0f * 30.0f; + device->speaker_angles[4] = M_PI/180.0f * 90.0f; + device->speaker_angles[5] = 9999.0f; + device->speaker_num[0] = 4; /* Rear left */ + device->speaker_num[1] = 0; /* Front left */ + device->speaker_num[2] = 2; /* Front centre */ + device->speaker_num[3] = 1; /* Front right */ + device->speaker_num[4] = 5; /* Rear right */ + device->speaker_num[5] = 3; /* LFE */ + device->num_speakers = 6; + device->lfe_channel = 3; + break; + + default: + WARN("unknown speaker_config %lu\n", device->speaker_config); + } +} + static HRESULT DSOUND_WaveFormat(DirectSoundDevice *device, IAudioClient *client, BOOL forcewave, WAVEFORMATEX **wfx) { @@ -121,7 +194,7 @@ static HRESULT DSOUND_WaveFormat(DirectSoundDevice *device, IAudioClient *client if (FAILED(hr)) return hr; - if (mixwfe->Format.nChannels < device->num_speakers) { + if (device->num_speakers == 0 || mixwfe->Format.nChannels < device->num_speakers) { device->speaker_config = DSOUND_FindSpeakerConfig(device->mmdevice, mixwfe->Format.nChannels); DSOUND_ParseSpeakerConfig(device); } else if (mixwfe->Format.nChannels > device->num_speakers) { diff --git a/dlls/dwmapi/dwmapi_main.c b/dlls/dwmapi/dwmapi_main.c index adc02552ba72..67b2d2bc25f0 100644 --- a/dlls/dwmapi/dwmapi_main.c +++ b/dlls/dwmapi/dwmapi_main.c @@ -83,18 +83,6 @@ HRESULT WINAPI DwmGetColorizationColor(DWORD *colorization, BOOL *opaque_blend) return E_NOTIMPL; } -/********************************************************************** - * DwmFlush (DWMAPI.@) - */ -HRESULT WINAPI DwmFlush(void) -{ - static BOOL once; - - if (!once++) FIXME("() stub\n"); - - return S_OK; -} - /********************************************************************** * DwmInvalidateIconicBitmaps (DWMAPI.@) */ @@ -205,15 +193,24 @@ HRESULT WINAPI DwmGetWindowAttribute(HWND hwnd, DWORD attribute, PVOID pv_attrib return E_HANDLE; if (!IsWindow(hwnd)) return E_HANDLE; + if (!pv_attribute) + return E_INVALIDARG; switch (attribute) { + case DWMWA_NCRENDERING_ENABLED: + if (size < sizeof(BOOL)) + return E_INVALIDARG; + + WARN("DWMWA_NCRENDERING_ENABLED: always returning FALSE.\n"); + *(BOOL*)(pv_attribute) = FALSE; + hr = S_OK; + break; + case DWMWA_EXTENDED_FRAME_BOUNDS: { RECT *rect = (RECT *)pv_attribute; DPI_AWARENESS_CONTEXT context; - if (!rect) - return E_INVALIDARG; if (size < sizeof(*rect)) return E_NOT_SUFFICIENT_BUFFER; if (GetWindowLongW(hwnd, GWL_STYLE) & WS_CHILD) @@ -229,6 +226,15 @@ HRESULT WINAPI DwmGetWindowAttribute(HWND hwnd, DWORD attribute, PVOID pv_attrib SetThreadDpiAwarenessContext(context); break; } + case DWMWA_CLOAKED: + if (size < sizeof(DWORD)) + return E_INVALIDARG; + + FIXME("DWMWA_CLOAKED: always returning 0.\n"); + *(DWORD*)(pv_attribute) = 0; + hr = S_OK; + break; + default: FIXME("attribute %ld not implemented.\n", attribute); hr = E_NOTIMPL; @@ -301,6 +307,31 @@ HRESULT WINAPI DwmGetCompositionTimingInfo(HWND hwnd, DWM_TIMING_INFO *info) return S_OK; } +/********************************************************************** + * DwmFlush (DWMAPI.@) + */ +HRESULT WINAPI DwmFlush(void) +{ + LARGE_INTEGER qpf, qpc, delay; + LONG64 qpc_refresh_period; + int display_frequency; + static BOOL once; + + if (!once++) + FIXME("() stub\n"); + else + TRACE(".\n"); + + display_frequency = get_display_frequency(); + NtQueryPerformanceCounter(&qpc, &qpf); + qpc_refresh_period = qpf.QuadPart / display_frequency; + delay.QuadPart = (qpc.QuadPart - ((qpc.QuadPart + qpc_refresh_period - 1) / qpc_refresh_period) * qpc_refresh_period) + * 10000000 / qpf.QuadPart; + NtDelayExecution(FALSE, &delay); + + return S_OK; +} + /********************************************************************** * DwmAttachMilContent (DWMAPI.@) */ diff --git a/dlls/dwmapi/tests/dwmapi.c b/dlls/dwmapi/tests/dwmapi.c index a89a1fd705bc..1f13d2949a7a 100644 --- a/dlls/dwmapi/tests/dwmapi.c +++ b/dlls/dwmapi/tests/dwmapi.c @@ -83,6 +83,27 @@ static void test_DwmGetCompositionTimingInfo(void) "Got wrong monitor refresh period %s.\n", wine_dbgstr_longlong(timing_info.qpcRefreshPeriod)); } +static void test_DWMWA_NCRENDERING_ENABLED(void) +{ + BOOL nc_rendering; + HRESULT hr; + HWND hwnd; + + hwnd = CreateWindowW(L"static", L"static", WS_OVERLAPPEDWINDOW | WS_POPUP | WS_VISIBLE, 10, 10, 200, 200, NULL, NULL, NULL, NULL); + + hr = DwmGetWindowAttribute(hwnd, DWMWA_NCRENDERING_ENABLED, NULL, sizeof(nc_rendering)); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + hr = DwmGetWindowAttribute(hwnd, DWMWA_NCRENDERING_ENABLED, &nc_rendering, 0); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + + nc_rendering = 0xdeadbeef; + hr = DwmGetWindowAttribute(hwnd, DWMWA_NCRENDERING_ENABLED, &nc_rendering, sizeof(nc_rendering)); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(nc_rendering == FALSE || nc_rendering == TRUE, "non-boolean value %#x.\n", nc_rendering); + + DestroyWindow(hwnd); +} + static void test_DWMWA_EXTENDED_FRAME_BOUNDS(void) { DPI_AWARENESS_CONTEXT (WINAPI *pSetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); @@ -144,5 +165,6 @@ START_TEST(dwmapi) { test_DwmIsCompositionEnabled(); test_DwmGetCompositionTimingInfo(); + test_DWMWA_NCRENDERING_ENABLED(); test_DWMWA_EXTENDED_FRAME_BOUNDS(); } diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 783312f68e8d..4b9c19618f72 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -223,6 +223,9 @@ system_fallback_config[] = { "0000-007F, 0080-00FF, 0100-017F, 0180-024F, " "0250-02AF, 02B0-02FF, 0300-036F", L"Tahoma" }, + /* Cyrillic, Cyrillic Supplement */ + { "0400-052F", L"Tahoma" }, + { "0530-058F, FB10-FB1C", L"Noto Sans Armenian" }, { "0590-05FF, FB1D-FB4F", L"Noto Sans Hebrew" }, @@ -248,7 +251,7 @@ system_fallback_config[] = { "0D00-0D7F", L"Noto Sans Malayalam" }, { "0D80-0DFF", L"Noto Sans Sinhala" }, - { "0E00-0E7F", L"Noto Sans Thai" }, + { "0E00-0E7F", L"Microsoft Sans Serif" }, { "0E80-0EFF", L"Noto Sans Lao" }, { "0F00-0FFF", L"Noto Serif Tibetan" }, @@ -268,7 +271,7 @@ system_fallback_config[] = { "1100-11FF, 3130-318F, " "3200-321F, 3260-327F, " "A960-A97F, AC00-D7FF, " - "D7B0-D7FF", L"Noto Sans CJK KR" }, + "D7B0-D7FF", L"Malgun Gothic" }, { "1680-169F", L"Noto Sans Ogham" }, @@ -292,37 +295,40 @@ system_fallback_config[] = { "1C00-1C4F", L"Noto Sans Lepcha" }, { "1C50-1C7F", L"Noto Sans Ol Chiki" }, + /* Dingbats - 2700-27BF */ + { "2700-27BF", L"Noto Sans Symbols2, Noto Sans Symbols 2" }, + { "2C80-2CFF", L"Noto Sans Coptic" }, { "2D30-2D7F", L"Noto Sans Tifinagh" }, /* CJK Radicals Supplement - 2E80-2EFF */ - { "2E80-2EFF", L"Noto Sans CJK SC", L"zh-Hans" }, + { "2E80-2EFF", L"Microsoft YaHei", L"zh-Hans" }, { "2E80-2EFF", L"Noto Sans CJK TC", L"zh-Hant" }, - { "2E80-2EFF", L"Noto Sans CJK KR", L"ko" }, + { "2E80-2EFF", L"Malgun Gothic", L"ko" }, /* CJK Symbols and Punctuation - 3000-303F Hiragana - 3040-309F Katakana - 30A0-30FF Katakana Phonetic Ext. - 31F0-31FF */ - { "3000-30FF, 31F0-31FF", L"Noto Sans CJK SC", L"zh-Hans" }, + { "3000-30FF, 31F0-31FF", L"Microsoft YaHei", L"zh-Hans" }, { "3000-30FF, 31F0-31FF", L"Noto Sans CJK TC", L"zh-Hant" }, - { "3000-30FF, 31F0-31FF", L"Noto Sans CJK KR", L"ko" }, - { "3000-30FF, 31F0-31FF", L"Noto Sans CJK JP" }, + { "3000-30FF, 31F0-31FF", L"Malgun Gothic", L"ko" }, + { "3000-30FF, 31F0-31FF", L"MS Gothic" }, /* CJK Unified Ext A - 3400-4DBF CJK Unified - 4E00-9FFF */ - { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK SC", L"zh-Hans" }, + { "3400-4DBF, 4E00-9FFF", L"Microsoft YaHei", L"zh-Hans" }, { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK TC", L"zh-Hant" }, - { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK KR", L"ko" }, - { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK JP" }, + { "3400-4DBF, 4E00-9FFF", L"Malgun Gothic", L"ko" }, + { "3400-4DBF, 4E00-9FFF", L"MS Gothic" }, { "A000-A4CF", L"Noto Sans Yi" }, { "A4D0-A4FF", L"Noto Sans Lisu" }, { "A500-A63F", L"Noto Sans Vai" }, - { "A6A0-A6FF", L"Noto Sans Bamum" }, + { "A6A0-A6FF, 16800-16A38", L"Noto Sans Bamum" }, { "A800-A82F", L"Noto Sans Syloti Nagri" }, { "A840-A87F", L"Noto Sans PhagsPa" }, { "A880-A8DF", L"Noto Sans Saurashtra" }, @@ -333,30 +339,32 @@ system_fallback_config[] = /* CJK Compatibility Ideographs - F900-FAFF */ - { "F900-FAFF", L"Noto Sans CJK SC", L"zh-Hans" }, + { "F900-FAFF", L"Microsoft YaHei", L"zh-Hans" }, { "F900-FAFF", L"Noto Sans CJK TC", L"zh-Hant" }, - { "F900-FAFF", L"Noto Sans CJK KR", L"ko" }, - { "F900-FAFF", L"Noto Sans CJK JP" }, + { "F900-FAFF", L"Malgun Gothic", L"ko" }, + { "F900-FAFF", L"MS Gothic" }, /* Vertical Forms - FE10-FE1F */ - { "FE10-FE1F", L"Noto Sans CJK SC", L"zh-Hans" }, - { "FE10-FE1F", L"Noto Sans CJK KR", L"ko" }, + { "FE10-FE1F", L"Microsoft YaHei", L"zh-Hans" }, + { "FE10-FE1F", L"Malgun Gothic", L"ko" }, { "FE10-FE1F", L"Noto Sans CJK TC" }, /* CJK Compatibility Forms - FE30-FE4F Small Form Variants - FE50-FE6F */ - { "FE30-FE6F", L"Noto Sans CJK SC", L"zh-Hans" }, - { "FE30-FE6F", L"Noto Sans CJK KR", L"ko" }, - { "FE30-FE6F", L"Noto Sans CJK JP", L"ja" }, + { "FE30-FE6F", L"Microsoft YaHei", L"zh-Hans" }, + { "FE30-FE6F", L"Malgun Gothic", L"ko" }, + { "FE30-FE6F", L"MS Gothic", L"ja" }, { "FE30-FE6F", L"Noto Sans CJK TC" }, /* Halfwidth and Fullwidth Forms */ - { "FF00-FFEF", L"Noto Sans CJK SC", L"zh-Hans" }, + { "FF00-FFEF", L"Microsoft YaHei", L"zh-Hans" }, { "FF00-FFEF", L"Noto Sans CJK TC", L"zh-Hant" }, - { "FF00-FFEF", L"Noto Sans CJK KR", L"ko" }, - { "FF00-FFEF", L"Noto Sans CJK JP" }, + { "FF00-FFEF", L"Malgun Gothic", L"ko" }, + { "FF00-FFEF", L"MS Gothic" }, + + { "1F800-1F8FF", L"Noto Sans Symbols2, Noto Sans Symbols 2" }, }; struct text_source_context diff --git a/dlls/dxdiagn/provider.c b/dlls/dxdiagn/provider.c index 88011ac87d22..48167f1d6ae9 100644 --- a/dlls/dxdiagn/provider.c +++ b/dlls/dxdiagn/provider.c @@ -613,7 +613,7 @@ static HRESULT build_systeminfo_tree(IDxDiagContainerImpl_Container *node) WCHAR buffer[MAX_PATH], computer_name[MAX_COMPUTERNAME_LENGTH + 1], print_buf[200], localized_pagefile_fmt[200]; DWORD_PTR args[2]; - hr = add_ui4_property(node, L"dwDirectXVersionMajor", 9); + hr = add_ui4_property(node, L"dwDirectXVersionMajor", 12); if (FAILED(hr)) return hr; @@ -621,15 +621,15 @@ static HRESULT build_systeminfo_tree(IDxDiagContainerImpl_Container *node) if (FAILED(hr)) return hr; - hr = add_bstr_property(node, L"szDirectXVersionLetter", L"c"); + hr = add_bstr_property(node, L"szDirectXVersionLetter", L" "); if (FAILED(hr)) return hr; - hr = add_bstr_property(node, L"szDirectXVersionEnglish", L"4.09.0000.0904"); + hr = add_bstr_property(node, L"szDirectXVersionEnglish", L""); if (FAILED(hr)) return hr; - hr = add_bstr_property(node, L"szDirectXVersionLongEnglish", L"= \"DirectX 9.0c (4.09.0000.0904)"); + hr = add_bstr_property(node, L"szDirectXVersionLongEnglish", L"DirectX 12"); if (FAILED(hr)) return hr; diff --git a/dlls/dxgi/factory.c b/dlls/dxgi/factory.c index 32d54f033eb1..ebdb42a3806e 100644 --- a/dlls/dxgi/factory.c +++ b/dlls/dxgi/factory.c @@ -617,6 +617,7 @@ HWND dxgi_factory_get_device_window(struct dxgi_factory *factory) ERR("Failed to create a window.\n"); return NULL; } + SetWindowPos(factory->device_window, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); TRACE("Created device window %p for factory %p.\n", factory->device_window, factory); } diff --git a/dlls/gameinput/Makefile.in b/dlls/gameinput/Makefile.in new file mode 100644 index 000000000000..7b239def911b --- /dev/null +++ b/dlls/gameinput/Makefile.in @@ -0,0 +1,7 @@ +MODULE = gameinput.dll +EXTRADEFS = -D_GAMEINPUT_ + +EXTRADLLFLAGS = -Wb,--prefer-native + +SOURCES = \ + gameinput.c diff --git a/dlls/gameinput/gameinput.c b/dlls/gameinput/gameinput.c new file mode 100644 index 000000000000..c3923bf2efcc --- /dev/null +++ b/dlls/gameinput/gameinput.c @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" + +#include "gameinput.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ginput); + +HRESULT WINAPI GameInputCreate( v0_IGameInput **out ) +{ + FIXME( "out %p, stub!\n", out ); + return E_NOTIMPL; +} + +HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID riid, void **out ) +{ + FIXME( "clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out ); + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/dlls/gameinput/gameinput.spec b/dlls/gameinput/gameinput.spec new file mode 100644 index 000000000000..398594120b4e --- /dev/null +++ b/dlls/gameinput/gameinput.spec @@ -0,0 +1,3 @@ +@ stdcall GameInputCreate(ptr) +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetClassObject(ptr ptr ptr) diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c index 3a7944e9c022..14e7ec128bb2 100644 --- a/dlls/gdi32/tests/driver.c +++ b/dlls/gdi32/tests/driver.c @@ -906,7 +906,7 @@ static void test_D3DKMTOpenAdapterFromDeviceName_deviface(const GUID *devinterfa ok(ret, "Got unexpected ret %d, GetLastError() %lu.\n", ret, GetLastError()); status = pD3DKMTOpenAdapterFromDeviceName(&device_name); - todo_wine_if(todo) ok(status == expected_status, "Got status %#lx, expected %#lx.\n", status, expected_status); + ok(status == expected_status, "Got status %#lx, expected %#lx.\n", status, expected_status); if (!status) { @@ -918,7 +918,7 @@ static void test_D3DKMTOpenAdapterFromDeviceName_deviface(const GUID *devinterfa if (ret) { ret = RtlEqualLuid( &luid, &device_name.AdapterLuid); - todo_wine ok(ret, "Luid does not match.\n"); + ok(ret, "Luid does not match.\n"); } else { diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 06d3b042debf..4c57e6f388e9 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -7837,6 +7837,136 @@ static void test_font_weight(void) ok(bret, "got error %ld\n", GetLastError()); } +static void test_text_out_fill(void) +{ + HBRUSH black = GetStockObject(GRAY_BRUSH); + RECT r = {0, 0, 256, 256}; + HBITMAP hbmp, hbmpprev; + int i, j, ystart, yend; + ABC neg_a, neg_c, abc; + BITMAPINFO bmi; + char str[3]; + HFONT hfont; + LOGFONTA lf; + DWORD *data; + BOOL bret; + SIZE sz; + HDC hdc; + int w; + + hdc = CreateCompatibleDC(0); + ok(!!hdc, "CreateCompatibleDC failed.\n"); + + memset(&bmi, 0, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biWidth = r.right; + bmi.bmiHeader.biHeight = r.bottom; + bmi.bmiHeader.biCompression = BI_RGB; + + hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void **)&data, NULL, 0); + ok(!!hbmp, "failed, err %lu.\n", GetLastError()); + hbmpprev = SelectObject(hdc, hbmp); + + memset(&lf, 0, sizeof(lf)); + strcpy(lf.lfFaceName, "Arial"); + lf.lfQuality = NONANTIALIASED_QUALITY; + lf.lfHeight = 90; + + hfont = CreateFontIndirectA(&lf); + ok(!!hfont, "failed, err %lu.\n", GetLastError()); + hfont = SelectObject(hdc, hfont); + + FillRect(hdc, &r, black); + + str[2] = 0; + memset(&neg_a, 0, sizeof(neg_a)); + memset(&neg_c, 0, sizeof(neg_c)); + for (i = 'A'; i <= 'z'; ++i) + { + if (!GetCharABCWidthsW(hdc, i, i, &abc)) continue; + if (abc.abcA < neg_a.abcA) + { + str[0] = i; + neg_a = abc; + } + if (abc.abcC < neg_c.abcC) + { + str[1] = i; + neg_c = abc; + } + } + if (neg_a.abcA >= 0 || neg_c.abcC >= 0) + { + skip("Could not find suitable characters.\n"); + goto done; + } + trace("Found %s.\n", debugstr_a(str)); + + for (i = 0; i < r.bottom; ++i) + { + for (j = 0; j < r.right; ++j) + { + if (data[i * r.right + j] != 0x808080) + break; + } + if (j != r.right) + break; + } + ok(i == r.bottom, "got %d.\n", i); + + bret = GetTextExtentExPointA(hdc, str, strlen(str), 32767, NULL, NULL, &sz); + ok(bret, "got error %lu.\n", GetLastError()); + w = neg_a.abcA + neg_a.abcB + neg_a.abcC + neg_c.abcA + neg_c.abcB + neg_c.abcC; + ok(sz.cx == w, "got %ld, expected %d.\n", sz.cx, w); + + bret = ExtTextOutA(hdc, 10, 0, ETO_OPAQUE, NULL, str, strlen(str), NULL); + ok(bret, "got error %lu.\n", GetLastError()); + + ystart = r.bottom - sz.cy; + yend = r.bottom; + for (j = 0; j < r.right; ++j) + { + if (data[ystart * r.right + j] != 0x808080) + break; + } + ok(j < r.right, "Expected to find white pixel.\n"); + if (j == r.right) + goto done; + ok(j == 10 + neg_a.abcA - 1 || j == 10 + neg_a.abcA, "got %d, neg_a.abcA %d.\n", j, neg_a.abcA); + + for (i = ystart; i < yend; ++i) + { + if (data[i * r.right + j] == 0x808080) + break; + } + ok(i == yend, "got i %d, expected %d.\n", i, yend); + + for (j = r.right - 1; j >= 0; --j) + { + if (data[ystart * r.right + j] == 0xffffff) + break; + } + ok(j >= 0, "Expected to find white pixel.\n"); + if (j < 0) + goto done; + ok(j == 10 + sz.cx - neg_c.abcC || j == 10 + sz.cx - neg_c.abcC - 1, "got %d, neg_c.abcC %ld.\n", j, 10 + sz.cx - neg_c.abcC); + for (i = ystart; i < yend; ++i) + { + if (data[i * r.right + j] == 0x808080) + break; + } + ok(i == yend, "got i %d.\n", i); + +done: + SelectObject(hdc, hbmpprev); + hfont = SelectObject(hdc, hfont); + DeleteObject(hfont); + DeleteObject(hbmp); + DeleteDC(hdc); +} + START_TEST(font) { static const char *test_names[] = @@ -7927,6 +8057,7 @@ START_TEST(font) test_char_width(); test_select_object(); test_font_weight(); + test_text_out_fill(); /* These tests should be last test until RemoveFontResource * is properly implemented. diff --git a/dlls/gdi32/text.c b/dlls/gdi32/text.c index 583244fb8635..e6effe26b4ca 100644 --- a/dlls/gdi32/text.c +++ b/dlls/gdi32/text.c @@ -966,6 +966,44 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *rect, if (dc_attr->emf && !EMFDC_ExtTextOut( dc_attr, x, y, flags, rect, str, count, dx )) return FALSE; + /* HACK: Use Microsoft Sans Serif for Thai. */ + do + { + BOOL is_thai = FALSE; + int i; + + for (i = 0; i < count; ++i) + { + if (str[i] >= 0x0e00 && str[i] <= 0x0e7f) + is_thai = TRUE; + } + + if (is_thai) + { + const WCHAR *font_name = L"Microsoft Sans Serif"; + HFONT old_font, new_font; + LOGFONTW log_font; + + if (!(old_font = GetCurrentObject(hdc, OBJ_FONT)) + || !GetObjectW(old_font, sizeof(log_font), &log_font)) + break; + + if (wcscmp(log_font.lfFaceName, font_name) != 0) + { + wcscpy(log_font.lfFaceName, font_name); + if (!(new_font = CreateFontIndirectW(&log_font))) + break; + + SelectObject(hdc, new_font); + ret = ExtTextOutW(hdc, x, y, flags, rect, str, count, dx); + DeleteObject(new_font); + SelectObject(hdc, old_font); + + return ret; + } + } + } while (0); + if (!(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0) { UINT bidi_flags; diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 3ad40a7de13a..624e16c49835 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -5903,6 +5903,15 @@ GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics, if(!graphics || !string || !font || !rect || !bounds) return InvalidParameter; + if (length == 1 && string[0] == '\n') + { + /* Proton hack for SpriteFontX class used by TouHou Makuka Sai. + * Returned size is passed to Bitmap constructor, but we currently measure "\n" as zero size. */ + char const *sgi = getenv("SteamGameId"); + if (sgi && (!strcmp(sgi, "882710") || !strcmp(sgi, "1031480"))) + string = L" "; + } + if(!has_gdi_dc(graphics)) { hdc = temp_hdc = CreateCompatibleDC(0); diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 8725ca7bba94..88e632e2881b 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -216,20 +216,23 @@ static struct hid_report *hid_queue_pop_report( struct hid_queue *queue ) return report; } -static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *packet, BOOL polled ) +static void hid_device_queue_input( struct phys_device *pdo, HID_XFER_PACKET *packet, BOOL polled ) { - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - HIDP_COLLECTION_DESC *desc = ext->u.pdo.collection_desc; + HIDP_COLLECTION_DESC *desc = pdo->collection_desc; ULONG size, report_len = polled ? packet->reportBufferLen : desc->InputLength; struct hid_report *last_report, *report; + BOOL steam_overlay_open = FALSE; struct hid_queue *queue; LIST_ENTRY completed, *entry; KIRQL irql; IRP *irp; - TRACE("device %p, packet %p\n", device, packet); + TRACE( "pdo %p, packet %p\n", pdo, packet ); - if (IsEqualGUID( ext->class_guid, &GUID_DEVINTERFACE_HID )) + if (WaitForSingleObject( pdo->base.steam_overlay_event, 0 ) == WAIT_OBJECT_0) /* steam overlay is open */ + steam_overlay_open = TRUE; + + if (IsEqualGUID( pdo->base.class_guid, &GUID_DEVINTERFACE_HID ) && !steam_overlay_open) { struct hid_packet *hid; @@ -243,7 +246,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack input.hi.wParamH = HIWORD(RIM_INPUT); input.hi.wParamL = LOWORD(RIM_INPUT); - hid->head.device = ext->u.pdo.rawinput_handle; + hid->head.device = pdo->rawinput_handle; hid->head.usage = MAKELONG(desc->Usage, desc->UsagePage); hid->head.count = 1; @@ -264,9 +267,9 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack InitializeListHead( &completed ); - KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); - if (ext->u.pdo.removed) WARN( "Device has been removed, dropping report\n" ); - else LIST_FOR_EACH_ENTRY( queue, &ext->u.pdo.queues, struct hid_queue, entry ) + KeAcquireSpinLock( &pdo->lock, &irql ); + if (pdo->removed) WARN( "Device has been removed, dropping report\n" ); + else LIST_FOR_EACH_ENTRY( queue, &pdo->queues, struct hid_queue, entry ) { if (!polled) hid_queue_push_report( queue, last_report ); @@ -284,7 +287,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack } while (polled); } - KeReleaseSpinLock( &ext->u.pdo.lock, irql ); + KeReleaseSpinLock( &pdo->lock, irql ); while ((entry = RemoveHeadList( &completed )) != &completed) { @@ -295,7 +298,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack hid_report_decref( last_report ); } -static HIDP_REPORT_IDS *find_report_with_type_and_id( HIDP_DEVICE_DESC *desc, UCHAR collection, BYTE type, BYTE id, BOOL any_id ) +HIDP_REPORT_IDS *find_report_with_type_and_id( HIDP_DEVICE_DESC *desc, UCHAR collection, BYTE type, BYTE id, BOOL any_id ) { HIDP_REPORT_IDS *report, *reports = desc->ReportIDs; ULONG report_count = desc->ReportIDsLength; @@ -315,75 +318,55 @@ static HIDP_REPORT_IDS *find_report_with_type_and_id( HIDP_DEVICE_DESC *desc, UC DWORD CALLBACK hid_device_thread(void *args) { DEVICE_OBJECT *device = (DEVICE_OBJECT*)args; - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - ULONG i, input_length = 0, report_id = 0; + struct func_device *fdo = fdo_from_DEVICE_OBJECT( device ); HIDP_REPORT_IDS *report; - HID_XFER_PACKET *packet; - HIDP_DEVICE_DESC *desc; - IO_STATUS_BLOCK io; NTSTATUS status; - BYTE *buffer; - IRP *irp; - - for (i = 0; i < ext->u.fdo.device_desc.CollectionDescLength; i++) - { - HIDP_COLLECTION_DESC *desc = ext->u.fdo.device_desc.CollectionDesc + i; - input_length = max(input_length, desc->InputLength); - } - - packet = malloc( sizeof(*packet) + input_length ); - buffer = (BYTE *)(packet + 1); - - desc = &ext->u.fdo.device_desc; - report = find_report_with_type_and_id( desc, 0, HidP_Input, 0, TRUE ); - if (!report) WARN("no input report found.\n"); - else report_id = report->ReportID; do { - LARGE_INTEGER delay = {.QuadPart = (LONGLONG)ext->u.fdo.poll_interval * -10000}; - KEVENT irp_event; - - packet->reportId = buffer[0] = report_id; - packet->reportBuffer = buffer; - packet->reportBufferLen = input_length; + LARGE_INTEGER delay = {.QuadPart = (LONGLONG)fdo->poll_interval * -10000}; + HID_XFER_PACKET packet = *fdo->io_packet; + BYTE *buffer = packet.reportBuffer; + KEVENT *io_event = &fdo->io_event; + IO_STATUS_BLOCK *io = &fdo->io; - if (!report_id) + if (!(packet.reportBuffer[0] = packet.reportId)) { - packet->reportBuffer++; - packet->reportBufferLen--; + packet.reportBuffer++; + packet.reportBufferLen--; } - KeInitializeEvent( &irp_event, NotificationEvent, FALSE ); - irp = IoBuildDeviceIoControlRequest( IOCTL_HID_READ_REPORT, device, NULL, 0, packet->reportBuffer, - packet->reportBufferLen, TRUE, &irp_event, &io ); - if (IoCallDriver( device, irp ) == STATUS_PENDING) + KeInitializeEvent( io_event, NotificationEvent, FALSE ); + fdo->io_irp = IoBuildDeviceIoControlRequest( IOCTL_HID_READ_REPORT, device, NULL, 0, packet.reportBuffer, + packet.reportBufferLen, TRUE, io_event, io ); + if (IoCallDriver( device, fdo->io_irp ) == STATUS_PENDING) { - void *events[2] = {&irp_event, &ext->u.fdo.halt_event}; + void *events[2] = {io_event, &fdo->halt_event}; status = KeWaitForMultipleObjects( 2, events, WaitAny, Executive, KernelMode, FALSE, NULL, NULL ); if (status) break; } + fdo->io_irp = NULL; - if (io.Status == STATUS_SUCCESS) + if (io->Status == STATUS_SUCCESS) { - if (!report_id) io.Information++; - if (!(report = find_report_with_type_and_id( desc, 0, HidP_Input, buffer[0], FALSE ))) + if (!packet.reportId) io->Information++; + if (!(report = find_report_with_type_and_id( &fdo->device_desc, 0, HidP_Input, buffer[0], FALSE ))) ERR( "dropping unknown input id %u\n", buffer[0] ); - else if (!ext->u.fdo.poll_interval && io.Information < report->InputLength) - ERR( "dropping short report, len %Iu expected %u\n", io.Information, report->InputLength ); - else if (!report->CollectionNumber || report->CollectionNumber > ext->u.fdo.child_count) + else if (!fdo->poll_interval && io->Information < report->InputLength) + ERR( "dropping short report, len %Iu expected %u\n", io->Information, report->InputLength ); + else if (!report->CollectionNumber || report->CollectionNumber > fdo->child_count) ERR( "dropping report for unknown child %u\n", report->CollectionNumber ); else { - DEVICE_OBJECT *pdo = ext->u.fdo.child_pdos[report->CollectionNumber - 1]; - packet->reportId = buffer[0]; - packet->reportBuffer = buffer; - packet->reportBufferLen = io.Information; - hid_device_queue_input( pdo, packet, !!ext->u.fdo.poll_interval ); + struct phys_device *pdo = pdo_from_DEVICE_OBJECT( fdo->child_pdos[report->CollectionNumber - 1] ); + packet.reportId = buffer[0]; + packet.reportBuffer = buffer; + packet.reportBufferLen = io->Information; + hid_device_queue_input( pdo, &packet, !!fdo->poll_interval ); } } - status = KeWaitForSingleObject( &ext->u.fdo.halt_event, Executive, KernelMode, FALSE, &delay ); + status = KeWaitForSingleObject( &fdo->halt_event, Executive, KernelMode, FALSE, &delay ); } while (status == STATUS_TIMEOUT); if (status) WARN( "device thread exiting with status %#lx\n", status ); @@ -399,6 +382,8 @@ struct device_strings static const struct device_strings device_strings[] = { + /* CW-Bug-Id: #23185 Emulate Steam Input native hooks for native SDL */ + { .id = L"VID_28DE&PID_11FF", .product = L"Controller (XBOX 360 For Windows)" }, /* Microsoft controllers */ { .id = L"VID_045E&PID_028E", .product = L"Controller (XBOX 360 For Windows)" }, { .id = L"VID_045E&PID_028F", .product = L"Controller (XBOX 360 For Windows)" }, @@ -456,12 +441,12 @@ static NTSTATUS CALLBACK xfer_completion( DEVICE_OBJECT *device, IRP *irp, void return STATUS_SUCCESS; } -static NTSTATUS hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, IRP *irp ) +static NTSTATUS hid_device_xfer_report( struct phys_device *pdo, ULONG code, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); - ULONG offset, report_len = 0, buffer_len = 0, collection = ext->u.pdo.collection_desc->CollectionNumber; - BASE_DEVICE_EXTENSION *fdo_ext = ext->u.pdo.parent_fdo->DeviceExtension; - HIDP_DEVICE_DESC *desc = &fdo_ext->u.fdo.device_desc; + ULONG offset, report_len = 0, buffer_len = 0, collection = pdo->collection_desc->CollectionNumber; + struct func_device *fdo = fdo_from_DEVICE_OBJECT( pdo->parent_fdo ); + HIDP_DEVICE_DESC *desc = &fdo->device_desc; struct completion_params *params; HIDP_REPORT_IDS *report = NULL; BYTE *buffer = NULL; @@ -515,7 +500,7 @@ static NTSTATUS hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, case IOCTL_HID_GET_FEATURE: case IOCTL_HID_GET_INPUT_REPORT: params->packet.reportBufferLen = buffer_len - offset; - irp = IoBuildDeviceIoControlRequest( code, ext->u.pdo.parent_fdo, NULL, 0, ¶ms->packet, + irp = IoBuildDeviceIoControlRequest( code, pdo->parent_fdo, NULL, 0, ¶ms->packet, sizeof(params->packet), TRUE, NULL, NULL ); break; case IOCTL_HID_WRITE_REPORT: @@ -524,7 +509,7 @@ static NTSTATUS hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, case IOCTL_HID_SET_FEATURE: case IOCTL_HID_SET_OUTPUT_REPORT: params->packet.reportBufferLen = report_len - offset; - irp = IoBuildDeviceIoControlRequest( code, ext->u.pdo.parent_fdo, NULL, sizeof(params->packet), + irp = IoBuildDeviceIoControlRequest( code, pdo->parent_fdo, NULL, sizeof(params->packet), ¶ms->packet, 0, TRUE, NULL, NULL ); break; } @@ -537,14 +522,14 @@ static NTSTATUS hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, IoMarkIrpPending( params->irp ); IoSetCompletionRoutine( irp, xfer_completion, params, TRUE, TRUE, TRUE ); - IoCallDriver( ext->u.pdo.parent_fdo, irp ); + IoCallDriver( pdo->parent_fdo, irp ); return STATUS_PENDING; } -NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) +NTSTATUS WINAPI pdo_ioctl( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct phys_device *pdo = pdo_from_DEVICE_OBJECT( device ); NTSTATUS status = irp->IoStatus.Status; ULONG code, index; const WCHAR *str; @@ -555,9 +540,9 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) TRACE( "device %p code %#lx\n", device, irpsp->Parameters.DeviceIoControl.IoControlCode ); - KeAcquireSpinLock(&ext->u.pdo.lock, &irql); - removed = ext->u.pdo.removed; - KeReleaseSpinLock(&ext->u.pdo.lock, irql); + KeAcquireSpinLock( &pdo->lock, &irql ); + removed = pdo->removed; + KeReleaseSpinLock( &pdo->lock, irql ); if (removed) { @@ -573,7 +558,8 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) status = STATUS_BUFFER_OVERFLOW; else { - *(ULONG *)irp->AssociatedIrp.SystemBuffer = ext->u.fdo.poll_interval; + struct func_device *fdo = fdo_from_DEVICE_OBJECT( pdo->parent_fdo ); + *(ULONG *)irp->AssociatedIrp.SystemBuffer = fdo->poll_interval; irp->IoStatus.Information = sizeof(ULONG); status = STATUS_SUCCESS; } @@ -585,8 +571,9 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) status = STATUS_BUFFER_TOO_SMALL; else { + struct func_device *fdo = fdo_from_DEVICE_OBJECT( pdo->parent_fdo ); poll_interval = *(ULONG *)irp->AssociatedIrp.SystemBuffer; - if (poll_interval) ext->u.fdo.poll_interval = min( poll_interval, MAX_POLL_INTERVAL_MSEC ); + if (poll_interval) fdo->poll_interval = min( poll_interval, MAX_POLL_INTERVAL_MSEC ); status = STATUS_SUCCESS; } break; @@ -602,7 +589,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) if (code == IOCTL_HID_GET_SERIALNUMBER_STRING) index = HID_STRING_ID_ISERIALNUMBER; if (code == IOCTL_HID_GET_MANUFACTURER_STRING) index = HID_STRING_ID_IMANUFACTURER; - if ((str = find_device_string( ext->device_id, index ))) + if ((str = find_device_string( pdo->base.device_id, index ))) { irp->IoStatus.Information = (wcslen( str ) + 1) * sizeof(WCHAR); if (irp->IoStatus.Information > output_len) @@ -615,7 +602,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) break; } - call_minidriver( IOCTL_HID_GET_STRING, ext->u.pdo.parent_fdo, ULongToPtr( index ), + call_minidriver( IOCTL_HID_GET_STRING, pdo->parent_fdo, ULongToPtr( index ), sizeof(index), output_buf, output_len, &irp->IoStatus ); status = irp->IoStatus.Status; break; @@ -627,7 +614,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) status = STATUS_BUFFER_OVERFLOW; else { - memcpy( irp->AssociatedIrp.SystemBuffer, &ext->u.pdo.information, + memcpy( irp->AssociatedIrp.SystemBuffer, &pdo->information, sizeof(HID_COLLECTION_INFORMATION) ); status = STATUS_SUCCESS; } @@ -635,7 +622,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) } case IOCTL_HID_GET_COLLECTION_DESCRIPTOR: { - HIDP_COLLECTION_DESC *desc = ext->u.pdo.collection_desc; + HIDP_COLLECTION_DESC *desc = pdo->collection_desc; irp->IoStatus.Information = desc->PreparsedDataLength; if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < desc->PreparsedDataLength) @@ -675,7 +662,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) case IOCTL_HID_SET_FEATURE: case IOCTL_HID_GET_INPUT_REPORT: case IOCTL_HID_SET_OUTPUT_REPORT: - status = hid_device_xfer_report( ext, code, irp ); + status = hid_device_xfer_report( pdo, code, irp ); break; case IOCTL_HID_GET_WINE_RAWINPUT_HANDLE: @@ -683,7 +670,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) status = STATUS_BUFFER_OVERFLOW; else { - *(ULONG *)irp->AssociatedIrp.SystemBuffer = ext->u.pdo.rawinput_handle; + *(ULONG *)irp->AssociatedIrp.SystemBuffer = pdo->rawinput_handle; irp->IoStatus.Information = sizeof(ULONG); status = STATUS_SUCCESS; } @@ -707,19 +694,19 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) return status; } -NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) +NTSTATUS WINAPI pdo_read( DEVICE_OBJECT *device, IRP *irp ) { struct hid_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - HIDP_COLLECTION_DESC *desc = ext->u.pdo.collection_desc; + struct phys_device *pdo = pdo_from_DEVICE_OBJECT( device ); + HIDP_COLLECTION_DESC *desc = pdo->collection_desc; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); struct hid_report *report; BOOL removed; KIRQL irql; - KeAcquireSpinLock(&ext->u.pdo.lock, &irql); - removed = ext->u.pdo.removed; - KeReleaseSpinLock(&ext->u.pdo.lock, irql); + KeAcquireSpinLock( &pdo->lock, &irql ); + removed = pdo->removed; + KeReleaseSpinLock( &pdo->lock, irql ); if (removed) { @@ -751,10 +738,10 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) } -NTSTATUS WINAPI pdo_write(DEVICE_OBJECT *device, IRP *irp) +NTSTATUS WINAPI pdo_write( DEVICE_OBJECT *device, IRP *irp ) { - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - NTSTATUS status = hid_device_xfer_report( ext, IOCTL_HID_WRITE_REPORT, irp ); + struct phys_device *pdo = pdo_from_DEVICE_OBJECT( device ); + NTSTATUS status = hid_device_xfer_report( pdo, IOCTL_HID_WRITE_REPORT, irp ); if (status != STATUS_PENDING) { irp->IoStatus.Status = status; @@ -763,18 +750,18 @@ NTSTATUS WINAPI pdo_write(DEVICE_OBJECT *device, IRP *irp) return status; } -NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp) +NTSTATUS WINAPI pdo_create( DEVICE_OBJECT *device, IRP *irp ) { - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct phys_device *pdo = pdo_from_DEVICE_OBJECT( device ); struct hid_queue *queue; BOOL removed; KIRQL irql; TRACE("Open handle on device %p\n", device); - KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); - removed = ext->u.pdo.removed; - KeReleaseSpinLock( &ext->u.pdo.lock, irql ); + KeAcquireSpinLock( &pdo->lock, &irql ); + removed = pdo->removed; + KeReleaseSpinLock( &pdo->lock, irql ); if (removed) { @@ -786,9 +773,9 @@ NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp) if (!(queue = hid_queue_create())) irp->IoStatus.Status = STATUS_NO_MEMORY; else { - KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); - list_add_tail( &ext->u.pdo.queues, &queue->entry ); - KeReleaseSpinLock( &ext->u.pdo.lock, irql ); + KeAcquireSpinLock( &pdo->lock, &irql ); + list_add_tail( &pdo->queues, &queue->entry ); + KeReleaseSpinLock( &pdo->lock, irql ); irp->Tail.Overlay.OriginalFileObject->FsContext = queue; irp->IoStatus.Status = STATUS_SUCCESS; @@ -798,18 +785,18 @@ NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp) return STATUS_SUCCESS; } -NTSTATUS WINAPI pdo_close(DEVICE_OBJECT *device, IRP *irp) +NTSTATUS WINAPI pdo_close( DEVICE_OBJECT *device, IRP *irp ) { struct hid_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct phys_device *pdo = pdo_from_DEVICE_OBJECT( device ); BOOL removed; KIRQL irql; TRACE("Close handle on device %p\n", device); - KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); - removed = ext->u.pdo.removed; - KeReleaseSpinLock( &ext->u.pdo.lock, irql ); + KeAcquireSpinLock( &pdo->lock, &irql ); + removed = pdo->removed; + KeReleaseSpinLock( &pdo->lock, irql ); if (removed) { @@ -820,9 +807,9 @@ NTSTATUS WINAPI pdo_close(DEVICE_OBJECT *device, IRP *irp) if (queue) { - KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); + KeAcquireSpinLock( &pdo->lock, &irql ); list_remove( &queue->entry ); - KeReleaseSpinLock( &ext->u.pdo.lock, irql ); + KeReleaseSpinLock( &pdo->lock, irql ); hid_queue_destroy( queue ); } diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index 3924c72dcc37..21de22161e44 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -39,57 +39,73 @@ /* Ring buffer functions */ struct ReportRingBuffer; -typedef struct _BASE_DEVICE_EXTENSION +struct device { - union - { - struct - { - /* this must be the first member */ - HID_DEVICE_EXTENSION hid_ext; - - HID_DEVICE_ATTRIBUTES attrs; - HIDP_DEVICE_DESC device_desc; - WCHAR serial[256]; - - ULONG poll_interval; - KEVENT halt_event; - HANDLE thread; - - DEVICE_OBJECT **child_pdos; - UINT child_count; - } fdo; - - struct - { - DEVICE_OBJECT *parent_fdo; - - HIDP_COLLECTION_DESC *collection_desc; - HID_COLLECTION_INFORMATION information; - - UINT32 rawinput_handle; - UNICODE_STRING link_name; - - KSPIN_LOCK lock; - struct list queues; - BOOL removed; - - BOOL is_mouse; - UNICODE_STRING mouse_link_name; - BOOL is_keyboard; - UNICODE_STRING keyboard_link_name; - } pdo; - } u; - - /* These are unique to the parent FDO, but stored in the children as well - * for convenience. */ + HID_DEVICE_EXTENSION hid; /* must be first */ + WCHAR device_id[MAX_DEVICE_ID_LEN]; WCHAR instance_id[MAX_DEVICE_ID_LEN]; WCHAR container_id[MAX_GUID_STRING_LEN]; const GUID *class_guid; + HANDLE steam_overlay_event; + BOOL is_fdo; -} BASE_DEVICE_EXTENSION; +}; + +struct func_device +{ + struct device base; + HID_DEVICE_ATTRIBUTES attrs; + HIDP_DEVICE_DESC device_desc; + WCHAR serial[256]; + + ULONG poll_interval; + KEVENT halt_event; + HANDLE thread; + + HID_XFER_PACKET *io_packet; + IO_STATUS_BLOCK io; + KEVENT io_event; + IRP *io_irp; + + DEVICE_OBJECT **child_pdos; + UINT child_count; +}; + +struct phys_device +{ + struct device base; + DEVICE_OBJECT *parent_fdo; + + HIDP_COLLECTION_DESC *collection_desc; + HID_COLLECTION_INFORMATION information; + + UINT32 rawinput_handle; + UNICODE_STRING link_name; + + KSPIN_LOCK lock; + struct list queues; + BOOL removed; + + BOOL is_mouse; + UNICODE_STRING mouse_link_name; + BOOL is_keyboard; + UNICODE_STRING keyboard_link_name; +}; + +static inline struct phys_device *pdo_from_DEVICE_OBJECT( DEVICE_OBJECT *device ) +{ + struct device *impl = device->DeviceExtension; + return CONTAINING_RECORD( impl, struct phys_device, base ); +} + +static inline struct func_device *fdo_from_DEVICE_OBJECT( DEVICE_OBJECT *device ) +{ + struct device *impl = device->DeviceExtension; + if (!impl->is_fdo) impl = pdo_from_DEVICE_OBJECT( device )->parent_fdo->DeviceExtension; + return CONTAINING_RECORD( impl, struct func_device, base ); +} struct hid_report { @@ -119,10 +135,14 @@ typedef struct _minidriver PDRIVER_ADD_DEVICE AddDevice; PDRIVER_DISPATCH PNPDispatch; + + HANDLE steam_overlay_event; } minidriver; void call_minidriver( ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in_size, void *out_buff, ULONG out_size, IO_STATUS_BLOCK *io ); +HIDP_REPORT_IDS *find_report_with_type_and_id( HIDP_DEVICE_DESC *desc, UCHAR collection, + BYTE type, BYTE id, BOOL any_id ); /* Internal device functions */ DWORD CALLBACK hid_device_thread(void *args); diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 156b9a65f9f3..f4533301652a 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -111,21 +111,21 @@ static UINT32 alloc_rawinput_handle(void) /* make sure bRawData can hold UsagePage and Usage without requiring additional allocation */ C_ASSERT(offsetof(RAWINPUT, data.hid.bRawData[2 * sizeof(USAGE)]) < sizeof(RAWINPUT)); -static void send_wm_input_device_change(BASE_DEVICE_EXTENSION *ext, LPARAM param) +static void send_wm_input_device_change( struct phys_device *pdo, LPARAM param ) { - HIDP_COLLECTION_DESC *desc = ext->u.pdo.collection_desc; + HIDP_COLLECTION_DESC *desc = pdo->collection_desc; INPUT input = {.type = INPUT_HARDWARE}; struct hid_packet hid = {0}; - TRACE("ext %p, lparam %p\n", ext, (void *)param); + TRACE( "pdo %p, lparam %p\n", pdo, (void *)param ); - if (!IsEqualGUID( ext->class_guid, &GUID_DEVINTERFACE_HID )) return; + if (!IsEqualGUID( pdo->base.class_guid, &GUID_DEVINTERFACE_HID )) return; input.hi.uMsg = WM_INPUT_DEVICE_CHANGE; input.hi.wParamH = HIWORD(param); input.hi.wParamL = LOWORD(param); - hid.head.device = ext->u.pdo.rawinput_handle; + hid.head.device = pdo->rawinput_handle; hid.head.usage = MAKELONG(desc->Usage, desc->UsagePage); NtUserSendHardwareInput(0, 0, &input, (LPARAM)&hid); } @@ -133,9 +133,9 @@ static void send_wm_input_device_change(BASE_DEVICE_EXTENSION *ext, LPARAM param static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *bus_pdo) { WCHAR device_id[MAX_DEVICE_ID_LEN], instance_id[MAX_DEVICE_ID_LEN]; - BASE_DEVICE_EXTENSION *ext; + struct func_device *fdo; BOOL is_xinput_class; - DEVICE_OBJECT *fdo; + DEVICE_OBJECT *device; NTSTATUS status; minidriver *minidriver; @@ -154,37 +154,39 @@ static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *b TRACE("Adding device to PDO %p, id %s\\%s.\n", bus_pdo, debugstr_w(device_id), debugstr_w(instance_id)); minidriver = find_minidriver(driver); - if ((status = IoCreateDevice(driver, sizeof(*ext) + minidriver->minidriver.DeviceExtensionSize, - NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &fdo))) + if ((status = IoCreateDevice( driver, sizeof(*fdo) + minidriver->minidriver.DeviceExtensionSize, + NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &device ))) { ERR( "Failed to create bus FDO, status %#lx.\n", status ); return status; } - ext = fdo->DeviceExtension; - ext->is_fdo = TRUE; - ext->u.fdo.hid_ext.MiniDeviceExtension = ext + 1; - ext->u.fdo.hid_ext.PhysicalDeviceObject = bus_pdo; - ext->u.fdo.hid_ext.NextDeviceObject = bus_pdo; - swprintf(ext->device_id, ARRAY_SIZE(ext->device_id), L"HID\\%s", wcsrchr(device_id, '\\') + 1); - wcscpy(ext->instance_id, instance_id); + fdo = device->DeviceExtension; + fdo->base.is_fdo = TRUE; + fdo->base.hid.MiniDeviceExtension = fdo + 1; + fdo->base.hid.PhysicalDeviceObject = bus_pdo; + fdo->base.hid.NextDeviceObject = bus_pdo; + swprintf( fdo->base.device_id, ARRAY_SIZE(fdo->base.device_id), L"HID\\%s", wcsrchr( device_id, '\\' ) + 1 ); + wcscpy( fdo->base.instance_id, instance_id ); - if (get_device_id(bus_pdo, BusQueryContainerID, ext->container_id)) - ext->container_id[0] = 0; + if (get_device_id( bus_pdo, BusQueryContainerID, fdo->base.container_id )) + fdo->base.container_id[0] = 0; + + fdo->base.steam_overlay_event = minidriver->steam_overlay_event; is_xinput_class = !wcsncmp(device_id, L"WINEXINPUT\\", 7) && wcsstr(device_id, L"&XI_") != NULL; - if (is_xinput_class) ext->class_guid = &GUID_DEVINTERFACE_WINEXINPUT; - else ext->class_guid = &GUID_DEVINTERFACE_HID; + if (is_xinput_class) fdo->base.class_guid = &GUID_DEVINTERFACE_WINEXINPUT; + else fdo->base.class_guid = &GUID_DEVINTERFACE_HID; - status = minidriver->AddDevice(minidriver->minidriver.DriverObject, fdo); + status = minidriver->AddDevice( minidriver->minidriver.DriverObject, device ); if (status != STATUS_SUCCESS) { ERR( "Minidriver AddDevice failed (%lx)\n", status ); - IoDeleteDevice(fdo); + IoDeleteDevice( device ); return status; } - IoAttachDeviceToDeviceStack(fdo, bus_pdo); - fdo->Flags &= ~DO_DEVICE_INITIALIZING; + IoAttachDeviceToDeviceStack( device, bus_pdo ); + device->Flags &= ~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS; } @@ -217,13 +219,13 @@ static NTSTATUS get_hid_device_desc( minidriver *minidriver, DEVICE_OBJECT *devi static NTSTATUS initialize_device( minidriver *minidriver, DEVICE_OBJECT *device ) { - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct func_device *fdo = fdo_from_DEVICE_OBJECT( device ); ULONG index = HID_STRING_ID_ISERIALNUMBER; IO_STATUS_BLOCK io; NTSTATUS status; - call_minidriver( IOCTL_HID_GET_DEVICE_ATTRIBUTES, device, NULL, 0, &ext->u.fdo.attrs, - sizeof(ext->u.fdo.attrs), &io ); + call_minidriver( IOCTL_HID_GET_DEVICE_ATTRIBUTES, device, NULL, 0, &fdo->attrs, + sizeof(fdo->attrs), &io ); if (io.Status != STATUS_SUCCESS) { ERR( "Minidriver failed to get attributes, status %#lx.\n", io.Status ); @@ -231,100 +233,127 @@ static NTSTATUS initialize_device( minidriver *minidriver, DEVICE_OBJECT *device } call_minidriver( IOCTL_HID_GET_STRING, device, ULongToPtr(index), sizeof(index), - &ext->u.fdo.serial, sizeof(ext->u.fdo.serial), &io ); + &fdo->serial, sizeof(fdo->serial), &io ); if (io.Status != STATUS_SUCCESS) { ERR( "Minidriver failed to get serial number, status %#lx.\n", io.Status ); return io.Status; } - if ((status = get_hid_device_desc( minidriver, device, &ext->u.fdo.device_desc ))) + if ((status = get_hid_device_desc( minidriver, device, &fdo->device_desc ))) { ERR( "Failed to get HID device description, status %#lx\n", status ); return status; } - if (!(ext->u.fdo.child_pdos = malloc( ext->u.fdo.device_desc.CollectionDescLength * sizeof(*ext->u.fdo.child_pdos) ))) + if (!(fdo->child_pdos = malloc( fdo->device_desc.CollectionDescLength * sizeof(*fdo->child_pdos) ))) { ERR( "Cannot allocate child PDOs array\n" ); return STATUS_NO_MEMORY; } - ext->u.fdo.poll_interval = minidriver->minidriver.DevicesArePolled ? DEFAULT_POLL_INTERVAL : 0; - KeInitializeEvent( &ext->u.fdo.halt_event, NotificationEvent, FALSE ); + fdo->poll_interval = minidriver->minidriver.DevicesArePolled ? DEFAULT_POLL_INTERVAL : 0; + KeInitializeEvent( &fdo->halt_event, NotificationEvent, FALSE ); return STATUS_SUCCESS; } static NTSTATUS create_child_pdos( minidriver *minidriver, DEVICE_OBJECT *device ) { - BASE_DEVICE_EXTENSION *fdo_ext = device->DeviceExtension, *pdo_ext; - DEVICE_OBJECT *child_pdo; + struct func_device *fdo = fdo_from_DEVICE_OBJECT( device ); + DEVICE_OBJECT *child_device; + struct phys_device *pdo; UNICODE_STRING string; WCHAR pdo_name[255]; USAGE page, usage; NTSTATUS status; INT i; - for (i = 0; i < fdo_ext->u.fdo.device_desc.CollectionDescLength; ++i) + for (i = 0; i < fdo->device_desc.CollectionDescLength; ++i) { - if (fdo_ext->u.fdo.device_desc.CollectionDescLength > 1) + if (fdo->device_desc.CollectionDescLength > 1) swprintf( pdo_name, ARRAY_SIZE(pdo_name), L"\\Device\\HID#%p&%p&%d", device->DriverObject, - fdo_ext->u.fdo.hid_ext.PhysicalDeviceObject, i ); + fdo->base.hid.PhysicalDeviceObject, i ); else swprintf( pdo_name, ARRAY_SIZE(pdo_name), L"\\Device\\HID#%p&%p", device->DriverObject, - fdo_ext->u.fdo.hid_ext.PhysicalDeviceObject ); + fdo->base.hid.PhysicalDeviceObject ); RtlInitUnicodeString(&string, pdo_name); - if ((status = IoCreateDevice( device->DriverObject, sizeof(*pdo_ext), &string, 0, 0, FALSE, &child_pdo ))) + if ((status = IoCreateDevice( device->DriverObject, sizeof(*pdo), &string, 0, 0, FALSE, &child_device ))) { ERR( "Failed to create child PDO, status %#lx.\n", status ); return status; } - fdo_ext->u.fdo.child_pdos[i] = child_pdo; - fdo_ext->u.fdo.child_count++; + fdo->child_pdos[i] = child_device; + fdo->child_count++; - pdo_ext = child_pdo->DeviceExtension; - pdo_ext->u.pdo.parent_fdo = device; - list_init( &pdo_ext->u.pdo.queues ); - KeInitializeSpinLock( &pdo_ext->u.pdo.lock ); + pdo = pdo_from_DEVICE_OBJECT( child_device ); + pdo->base.hid = fdo->base.hid; + pdo->parent_fdo = device; + list_init( &pdo->queues ); + KeInitializeSpinLock( &pdo->lock ); - pdo_ext->u.pdo.collection_desc = fdo_ext->u.fdo.device_desc.CollectionDesc + i; + pdo->collection_desc = fdo->device_desc.CollectionDesc + i; - if (fdo_ext->u.fdo.device_desc.CollectionDescLength > 1) + if (fdo->device_desc.CollectionDescLength > 1) { - swprintf( pdo_ext->device_id, ARRAY_SIZE(pdo_ext->device_id), L"%s&Col%02d", - fdo_ext->device_id, pdo_ext->u.pdo.collection_desc->CollectionNumber ); - swprintf( pdo_ext->instance_id, ARRAY_SIZE(pdo_ext->instance_id), L"%u&%s&%x&%u&%04u", - fdo_ext->u.fdo.attrs.VersionNumber, fdo_ext->u.fdo.serial, 0, 0, i ); + swprintf( pdo->base.device_id, ARRAY_SIZE(pdo->base.device_id), L"%s&Col%02d", + fdo->base.device_id, pdo->collection_desc->CollectionNumber ); + swprintf( pdo->base.instance_id, ARRAY_SIZE(pdo->base.instance_id), L"%u&%s&%x&%u&%04u", + fdo->attrs.VersionNumber, fdo->serial, 0, 0, i ); } else { - wcscpy( pdo_ext->device_id, fdo_ext->device_id ); - wcscpy( pdo_ext->instance_id, fdo_ext->instance_id ); + wcscpy( pdo->base.device_id, fdo->base.device_id ); + wcscpy( pdo->base.instance_id, fdo->base.instance_id ); } - wcscpy(pdo_ext->container_id, fdo_ext->container_id); - pdo_ext->class_guid = fdo_ext->class_guid; + wcscpy( pdo->base.container_id, fdo->base.container_id ); + pdo->base.class_guid = fdo->base.class_guid; + + pdo->information.VendorID = fdo->attrs.VendorID; + pdo->information.ProductID = fdo->attrs.ProductID; + pdo->information.VersionNumber = fdo->attrs.VersionNumber; + pdo->information.Polled = minidriver->minidriver.DevicesArePolled; + pdo->information.DescriptorSize = pdo->collection_desc->PreparsedDataLength; - pdo_ext->u.pdo.information.VendorID = fdo_ext->u.fdo.attrs.VendorID; - pdo_ext->u.pdo.information.ProductID = fdo_ext->u.fdo.attrs.ProductID; - pdo_ext->u.pdo.information.VersionNumber = fdo_ext->u.fdo.attrs.VersionNumber; - pdo_ext->u.pdo.information.Polled = minidriver->minidriver.DevicesArePolled; - pdo_ext->u.pdo.information.DescriptorSize = pdo_ext->u.pdo.collection_desc->PreparsedDataLength; + pdo->base.steam_overlay_event = minidriver->steam_overlay_event; - page = pdo_ext->u.pdo.collection_desc->UsagePage; - usage = pdo_ext->u.pdo.collection_desc->Usage; + page = pdo->collection_desc->UsagePage; + usage = pdo->collection_desc->Usage; if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_MOUSE) - pdo_ext->u.pdo.rawinput_handle = WINE_MOUSE_HANDLE; + pdo->rawinput_handle = WINE_MOUSE_HANDLE; else if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_KEYBOARD) - pdo_ext->u.pdo.rawinput_handle = WINE_KEYBOARD_HANDLE; + pdo->rawinput_handle = WINE_KEYBOARD_HANDLE; else - pdo_ext->u.pdo.rawinput_handle = alloc_rawinput_handle(); + pdo->rawinput_handle = alloc_rawinput_handle(); + + TRACE( "created pdo %p, rawinput handle %#x\n", pdo, pdo->rawinput_handle ); + } + + IoInvalidateDeviceRelations( fdo->base.hid.PhysicalDeviceObject, BusRelations ); + return STATUS_SUCCESS; +} - TRACE( "created device %p, rawinput handle %#x\n", pdo_ext, pdo_ext->u.pdo.rawinput_handle ); +static NTSTATUS create_device_thread( DEVICE_OBJECT *device ) +{ + struct func_device *fdo = fdo_from_DEVICE_OBJECT( device ); + ULONG i, input_length = 0; + HIDP_REPORT_IDS *report; + + for (i = 0; i < fdo->device_desc.CollectionDescLength; i++) + { + HIDP_COLLECTION_DESC *desc = fdo->device_desc.CollectionDesc + i; + input_length = max( input_length, desc->InputLength ); } - IoInvalidateDeviceRelations( fdo_ext->u.fdo.hid_ext.PhysicalDeviceObject, BusRelations ); + if (!(fdo->io_packet = malloc( sizeof(*fdo->io_packet) + input_length ))) return STATUS_NO_MEMORY; + + if (!(report = find_report_with_type_and_id( &fdo->device_desc, 0, HidP_Input, 0, TRUE ))) WARN( "no input report found.\n" ); + fdo->io_packet->reportId = report ? report->ReportID : 0; + fdo->io_packet->reportBuffer = (BYTE *)(fdo->io_packet + 1); + fdo->io_packet->reportBufferLen = input_length; + + if (!(fdo->thread = CreateThread( NULL, 0, hid_device_thread, device, 0, NULL ))) return STATUS_UNSUCCESSFUL; return STATUS_SUCCESS; } @@ -332,7 +361,7 @@ static NTSTATUS fdo_pnp(DEVICE_OBJECT *device, IRP *irp) { minidriver *minidriver = find_minidriver(device->DriverObject); IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct func_device *fdo = fdo_from_DEVICE_OBJECT( device ); NTSTATUS status; TRACE("irp %p, minor function %#x.\n", irp, stack->MinorFunction); @@ -347,49 +376,53 @@ static NTSTATUS fdo_pnp(DEVICE_OBJECT *device, IRP *irp) if (stack->Parameters.QueryDeviceRelations.Type != BusRelations) return minidriver->PNPDispatch(device, irp); - if (!(devices = ExAllocatePool(PagedPool, offsetof(DEVICE_RELATIONS, Objects[ext->u.fdo.child_count])))) + if (!(devices = ExAllocatePool( PagedPool, offsetof( DEVICE_RELATIONS, Objects[fdo->child_count] ) ))) { irp->IoStatus.Status = STATUS_NO_MEMORY; IoCompleteRequest(irp, IO_NO_INCREMENT); return STATUS_NO_MEMORY; } - for (i = 0, devices->Count = 0; i < ext->u.fdo.child_count; ++i) + for (i = 0, devices->Count = 0; i < fdo->child_count; ++i) { - devices->Objects[i] = ext->u.fdo.child_pdos[i]; - call_fastcall_func1(ObfReferenceObject, ext->u.fdo.child_pdos[i]); + devices->Objects[i] = fdo->child_pdos[i]; + call_fastcall_func1( ObfReferenceObject, fdo->child_pdos[i] ); devices->Count++; } irp->IoStatus.Information = (ULONG_PTR)devices; irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(irp); - return IoCallDriver(ext->u.fdo.hid_ext.NextDeviceObject, irp); + return IoCallDriver( fdo->base.hid.NextDeviceObject, irp ); } case IRP_MN_START_DEVICE: status = minidriver->PNPDispatch( device, irp ); if (!status) status = initialize_device( minidriver, device ); if (!status) status = create_child_pdos( minidriver, device ); - if (!status) ext->u.fdo.thread = CreateThread(NULL, 0, hid_device_thread, device, 0, NULL); + if (!status) status = create_device_thread( device ); return status; case IRP_MN_REMOVE_DEVICE: - if (ext->u.fdo.thread) + if (fdo->thread) { - KeSetEvent( &ext->u.fdo.halt_event, IO_NO_INCREMENT, FALSE ); - WaitForSingleObject(ext->u.fdo.thread, INFINITE); + KeSetEvent( &fdo->halt_event, IO_NO_INCREMENT, FALSE ); + WaitForSingleObject( fdo->thread, INFINITE ); } - status = minidriver->PNPDispatch( device, irp ); - HidP_FreeCollectionDescription( &ext->u.fdo.device_desc ); - free( ext->u.fdo.child_pdos ); - IoDetachDevice( ext->u.fdo.hid_ext.NextDeviceObject ); + if ((status = minidriver->PNPDispatch( device, irp ))) return status; + if (fdo->io_irp) KeWaitForSingleObject( &fdo->io_event, Executive, KernelMode, FALSE, NULL ); + free( fdo->io_packet ); + + HidP_FreeCollectionDescription( &fdo->device_desc ); + free( fdo->child_pdos ); + IoDetachDevice( fdo->base.hid.NextDeviceObject ); IoDeleteDevice( device ); return status; case IRP_MN_SURPRISE_REMOVAL: - KeSetEvent( &ext->u.fdo.halt_event, IO_NO_INCREMENT, FALSE ); + if ((status = minidriver->PNPDispatch( device, irp ))) return status; + KeSetEvent( &fdo->halt_event, IO_NO_INCREMENT, FALSE ); return STATUS_SUCCESS; default: @@ -404,9 +437,9 @@ static WCHAR *query_hardware_ids(DEVICE_OBJECT *device) static const WCHAR usage_format[] = L"HID_DEVICE_UP:%04X_U:%04X"; static const WCHAR hid_format[] = L"HID_DEVICE"; - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - HIDP_COLLECTION_DESC *desc = ext->u.pdo.collection_desc; - HID_COLLECTION_INFORMATION *info = &ext->u.pdo.information; + struct phys_device *pdo = pdo_from_DEVICE_OBJECT( device ); + HIDP_COLLECTION_DESC *desc = pdo->collection_desc; + HID_COLLECTION_INFORMATION *info = &pdo->information; WCHAR *dst; DWORD size; @@ -437,7 +470,7 @@ static WCHAR *query_compatible_ids(DEVICE_OBJECT *device) static WCHAR *query_device_id(DEVICE_OBJECT *device) { - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct device *ext = device->DeviceExtension; DWORD size = (wcslen(ext->device_id) + 1) * sizeof(WCHAR); WCHAR *dst; @@ -449,7 +482,7 @@ static WCHAR *query_device_id(DEVICE_OBJECT *device) static WCHAR *query_instance_id(DEVICE_OBJECT *device) { - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct device *ext = device->DeviceExtension; DWORD size = (wcslen(ext->instance_id) + 1) * sizeof(WCHAR); WCHAR *dst; @@ -461,7 +494,7 @@ static WCHAR *query_instance_id(DEVICE_OBJECT *device) static WCHAR *query_container_id(DEVICE_OBJECT *device) { - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct device *ext = device->DeviceExtension; DWORD size = (wcslen(ext->container_id) + 1) * sizeof(WCHAR); WCHAR *dst; @@ -471,11 +504,11 @@ static WCHAR *query_container_id(DEVICE_OBJECT *device) return dst; } -static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) +static NTSTATUS pdo_pnp( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - HIDP_COLLECTION_DESC *desc = ext->u.pdo.collection_desc; + struct phys_device *pdo = pdo_from_DEVICE_OBJECT( device ); + HIDP_COLLECTION_DESC *desc = pdo->collection_desc; NTSTATUS status = irp->IoStatus.Status; struct hid_queue *queue, *next; KIRQL irql; @@ -510,7 +543,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) else status = STATUS_SUCCESS; break; case BusQueryContainerID: - if (ext->container_id[0]) + if (pdo->base.container_id[0]) { irp->IoStatus.Information = (ULONG_PTR)query_container_id(device); if (!irp->IoStatus.Information) status = STATUS_NO_MEMORY; @@ -534,9 +567,9 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) } case IRP_MN_START_DEVICE: - send_wm_input_device_change(ext, GIDC_ARRIVAL); + send_wm_input_device_change( pdo, GIDC_ARRIVAL ); - if ((status = IoRegisterDeviceInterface(device, ext->class_guid, NULL, &ext->u.pdo.link_name))) + if ((status = IoRegisterDeviceInterface( device, pdo->base.class_guid, NULL, &pdo->link_name ))) { ERR( "Failed to register interface, status %#lx.\n", status ); break; @@ -545,40 +578,36 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) /* FIXME: This should probably be done in mouhid.sys. */ if (desc->UsagePage == HID_USAGE_PAGE_GENERIC && desc->Usage == HID_USAGE_GENERIC_MOUSE) { - if (!IoRegisterDeviceInterface(device, &GUID_DEVINTERFACE_MOUSE, NULL, &ext->u.pdo.mouse_link_name)) - ext->u.pdo.is_mouse = TRUE; + if (!IoRegisterDeviceInterface( device, &GUID_DEVINTERFACE_MOUSE, NULL, &pdo->mouse_link_name )) + pdo->is_mouse = TRUE; } if (desc->UsagePage == HID_USAGE_PAGE_GENERIC && desc->Usage == HID_USAGE_GENERIC_KEYBOARD) { - if (!IoRegisterDeviceInterface(device, &GUID_DEVINTERFACE_KEYBOARD, NULL, &ext->u.pdo.keyboard_link_name)) - ext->u.pdo.is_keyboard = TRUE; + if (!IoRegisterDeviceInterface( device, &GUID_DEVINTERFACE_KEYBOARD, NULL, &pdo->keyboard_link_name )) + pdo->is_keyboard = TRUE; } - IoSetDeviceInterfaceState(&ext->u.pdo.link_name, TRUE); - if (ext->u.pdo.is_mouse) - IoSetDeviceInterfaceState(&ext->u.pdo.mouse_link_name, TRUE); - if (ext->u.pdo.is_keyboard) - IoSetDeviceInterfaceState(&ext->u.pdo.keyboard_link_name, TRUE); + IoSetDeviceInterfaceState( &pdo->link_name, TRUE ); + if (pdo->is_mouse) IoSetDeviceInterfaceState( &pdo->mouse_link_name, TRUE ); + if (pdo->is_keyboard) IoSetDeviceInterfaceState( &pdo->keyboard_link_name, TRUE ); - ext->u.pdo.removed = FALSE; + pdo->removed = FALSE; status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: - send_wm_input_device_change(ext, GIDC_REMOVAL); + send_wm_input_device_change( pdo, GIDC_REMOVAL ); - IoSetDeviceInterfaceState(&ext->u.pdo.link_name, FALSE); - if (ext->u.pdo.is_mouse) - IoSetDeviceInterfaceState(&ext->u.pdo.mouse_link_name, FALSE); - if (ext->u.pdo.is_keyboard) - IoSetDeviceInterfaceState(&ext->u.pdo.keyboard_link_name, FALSE); + IoSetDeviceInterfaceState( &pdo->link_name, FALSE ); + if (pdo->is_mouse) IoSetDeviceInterfaceState( &pdo->mouse_link_name, FALSE ); + if (pdo->is_keyboard) IoSetDeviceInterfaceState( &pdo->keyboard_link_name, FALSE ); - KeAcquireSpinLock( &ext->u.pdo.lock, &irql ); - LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.queues, struct hid_queue, entry ) + KeAcquireSpinLock( &pdo->lock, &irql ); + LIST_FOR_EACH_ENTRY_SAFE( queue, next, &pdo->queues, struct hid_queue, entry ) hid_queue_destroy( queue ); - KeReleaseSpinLock( &ext->u.pdo.lock, irql ); + KeReleaseSpinLock( &pdo->lock, irql ); - RtlFreeUnicodeString(&ext->u.pdo.link_name); + RtlFreeUnicodeString( &pdo->link_name ); irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(irp, IO_NO_INCREMENT); @@ -586,15 +615,23 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) return STATUS_SUCCESS; case IRP_MN_SURPRISE_REMOVAL: - KeAcquireSpinLock(&ext->u.pdo.lock, &irql); - ext->u.pdo.removed = TRUE; - LIST_FOR_EACH_ENTRY_SAFE( queue, next, &ext->u.pdo.queues, struct hid_queue, entry ) + KeAcquireSpinLock( &pdo->lock, &irql ); + pdo->removed = TRUE; + LIST_FOR_EACH_ENTRY_SAFE( queue, next, &pdo->queues, struct hid_queue, entry ) hid_queue_remove_pending_irps( queue ); - KeReleaseSpinLock( &ext->u.pdo.lock, irql ); + KeReleaseSpinLock( &pdo->lock, irql ); status = STATUS_SUCCESS; break; + case IRP_MN_QUERY_DEVICE_TEXT: + { + DEVICE_TEXT_TYPE type = irpsp->Parameters.QueryDeviceText.DeviceTextType; + WARN("Ignoring IRP_MN_QUERY_TEXT type %u.\n", type); + status = STATUS_NOT_SUPPORTED; + break; + } + default: FIXME("Unhandled minor function %#x.\n", irpsp->MinorFunction); } @@ -606,7 +643,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp) { - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct device *ext = device->DeviceExtension; if (ext->is_fdo) return fdo_pnp(device, irp); @@ -616,7 +653,7 @@ static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp) static NTSTATUS WINAPI driver_create(DEVICE_OBJECT *device, IRP *irp) { - BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + struct device *ext = device->DeviceExtension; if (ext->is_fdo) { @@ -659,6 +696,8 @@ static void WINAPI driver_unload(DRIVER_OBJECT *driver) if (md->DriverUnload) md->DriverUnload(md->minidriver.DriverObject); list_remove(&md->entry); + + CloseHandle(md->steam_overlay_event); free(md); } } @@ -674,6 +713,8 @@ NTSTATUS WINAPI HidRegisterMinidriver(HID_MINIDRIVER_REGISTRATION *registration) if (!(driver = calloc(1, sizeof(*driver)))) return STATUS_NO_MEMORY; + driver->steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); + driver->DriverUnload = registration->DriverObject->DriverUnload; registration->DriverObject->DriverUnload = driver_unload; diff --git a/dlls/icu/Makefile.in b/dlls/icu/Makefile.in new file mode 100644 index 000000000000..ca8ca9030486 --- /dev/null +++ b/dlls/icu/Makefile.in @@ -0,0 +1,3 @@ +MODULE = icu.dll + +EXTRADLLFLAGS = -Wb,--prefer-native diff --git a/dlls/icu/icu.spec b/dlls/icu/icu.spec new file mode 100644 index 000000000000..2573e120a45b --- /dev/null +++ b/dlls/icu/icu.spec @@ -0,0 +1,1031 @@ +@ stub CloseDefaultICUGroupingLetters +@ stub GetDefaultICUGroupingLetters +@ stub GetICUGroupingLetter +@ stub SortCloseHandle +@ stub SortGetHandle +@ stub SortGetSearchKey +@ cdecl -norelay UCNV_FROM_U_CALLBACK_ESCAPE() icuuc68.UCNV_FROM_U_CALLBACK_ESCAPE_68 +@ cdecl -norelay UCNV_FROM_U_CALLBACK_SKIP() icuuc68.UCNV_FROM_U_CALLBACK_SKIP_68 +@ cdecl -norelay UCNV_FROM_U_CALLBACK_STOP() icuuc68.UCNV_FROM_U_CALLBACK_STOP_68 +@ cdecl -norelay UCNV_FROM_U_CALLBACK_SUBSTITUTE() icuuc68.UCNV_FROM_U_CALLBACK_SUBSTITUTE_68 +@ cdecl -norelay UCNV_TO_U_CALLBACK_ESCAPE() icuuc68.UCNV_TO_U_CALLBACK_ESCAPE_68 +@ cdecl -norelay UCNV_TO_U_CALLBACK_SKIP() icuuc68.UCNV_TO_U_CALLBACK_SKIP_68 +@ cdecl -norelay UCNV_TO_U_CALLBACK_STOP() icuuc68.UCNV_TO_U_CALLBACK_STOP_68 +@ cdecl -norelay UCNV_TO_U_CALLBACK_SUBSTITUTE() icuuc68.UCNV_TO_U_CALLBACK_SUBSTITUTE_68 +@ cdecl -norelay u_UCharsToChars() icuuc68.u_UCharsToChars_68 +@ cdecl -norelay u_austrcpy() icuuc68.u_austrcpy_68 +@ cdecl -norelay u_austrncpy() icuuc68.u_austrncpy_68 +@ cdecl -norelay u_catclose() icuuc68.u_catclose_68 +@ cdecl -norelay u_catgets() icuuc68.u_catgets_68 +@ cdecl -norelay u_catopen() icuuc68.u_catopen_68 +@ cdecl -norelay u_charAge() icuuc68.u_charAge_68 +@ cdecl -norelay u_charDigitValue() icuuc68.u_charDigitValue_68 +@ cdecl -norelay u_charDirection() icuuc68.u_charDirection_68 +@ cdecl -norelay u_charFromName() icuuc68.u_charFromName_68 +@ cdecl -norelay u_charMirror() icuuc68.u_charMirror_68 +@ cdecl -norelay u_charName() icuuc68.u_charName_68 +@ cdecl -norelay u_charType() icuuc68.u_charType_68 +@ cdecl -norelay u_charsToUChars() icuuc68.u_charsToUChars_68 +@ cdecl -norelay u_cleanup() icuuc68.u_cleanup_68 +@ cdecl -norelay u_countChar32() icuuc68.u_countChar32_68 +@ cdecl -norelay u_digit() icuuc68.u_digit_68 +@ cdecl -norelay u_enumCharNames() icuuc68.u_enumCharNames_68 +@ cdecl -norelay u_enumCharTypes() icuuc68.u_enumCharTypes_68 +@ cdecl -norelay u_errorName() icuuc68.u_errorName_68 +@ cdecl -norelay u_foldCase() icuuc68.u_foldCase_68 +@ cdecl -norelay u_forDigit() icuuc68.u_forDigit_68 +@ cdecl -norelay u_formatMessage() icuin68.u_formatMessage_68 +@ cdecl -norelay u_formatMessageWithError() icuin68.u_formatMessageWithError_68 +@ cdecl -norelay u_getBidiPairedBracket() icuuc68.u_getBidiPairedBracket_68 +@ cdecl -norelay u_getBinaryPropertySet() icuuc68.u_getBinaryPropertySet_68 +@ cdecl -norelay u_getCombiningClass() icuuc68.u_getCombiningClass_68 +@ cdecl -norelay u_getDataVersion() icuuc68.u_getDataVersion_68 +@ cdecl -norelay u_getFC_NFKC_Closure() icuuc68.u_getFC_NFKC_Closure_68 +@ cdecl -norelay u_getIntPropertyMap() icuuc68.u_getIntPropertyMap_68 +@ cdecl -norelay u_getIntPropertyMaxValue() icuuc68.u_getIntPropertyMaxValue_68 +@ cdecl -norelay u_getIntPropertyMinValue() icuuc68.u_getIntPropertyMinValue_68 +@ cdecl -norelay u_getIntPropertyValue() icuuc68.u_getIntPropertyValue_68 +@ cdecl -norelay u_getNumericValue() icuuc68.u_getNumericValue_68 +@ cdecl -norelay u_getPropertyEnum() icuuc68.u_getPropertyEnum_68 +@ cdecl -norelay u_getPropertyName() icuuc68.u_getPropertyName_68 +@ cdecl -norelay u_getPropertyValueEnum() icuuc68.u_getPropertyValueEnum_68 +@ cdecl -norelay u_getPropertyValueName() icuuc68.u_getPropertyValueName_68 +@ cdecl -norelay u_getUnicodeVersion() icuuc68.u_getUnicodeVersion_68 +@ cdecl -norelay u_getVersion() icuuc68.u_getVersion_68 +@ cdecl -norelay u_hasBinaryProperty() icuuc68.u_hasBinaryProperty_68 +@ cdecl -norelay u_init() icuuc68.u_init_68 +@ cdecl -norelay u_isIDIgnorable() icuuc68.u_isIDIgnorable_68 +@ cdecl -norelay u_isIDPart() icuuc68.u_isIDPart_68 +@ cdecl -norelay u_isIDStart() icuuc68.u_isIDStart_68 +@ cdecl -norelay u_isISOControl() icuuc68.u_isISOControl_68 +@ cdecl -norelay u_isJavaIDPart() icuuc68.u_isJavaIDPart_68 +@ cdecl -norelay u_isJavaIDStart() icuuc68.u_isJavaIDStart_68 +@ cdecl -norelay u_isJavaSpaceChar() icuuc68.u_isJavaSpaceChar_68 +@ cdecl -norelay u_isMirrored() icuuc68.u_isMirrored_68 +@ cdecl -norelay u_isUAlphabetic() icuuc68.u_isUAlphabetic_68 +@ cdecl -norelay u_isULowercase() icuuc68.u_isULowercase_68 +@ cdecl -norelay u_isUUppercase() icuuc68.u_isUUppercase_68 +@ cdecl -norelay u_isUWhiteSpace() icuuc68.u_isUWhiteSpace_68 +@ cdecl -norelay u_isWhitespace() icuuc68.u_isWhitespace_68 +@ cdecl -norelay u_isalnum() icuuc68.u_isalnum_68 +@ cdecl -norelay u_isalpha() icuuc68.u_isalpha_68 +@ cdecl -norelay u_isbase() icuuc68.u_isbase_68 +@ cdecl -norelay u_isblank() icuuc68.u_isblank_68 +@ cdecl -norelay u_iscntrl() icuuc68.u_iscntrl_68 +@ cdecl -norelay u_isdefined() icuuc68.u_isdefined_68 +@ cdecl -norelay u_isdigit() icuuc68.u_isdigit_68 +@ cdecl -norelay u_isgraph() icuuc68.u_isgraph_68 +@ cdecl -norelay u_islower() icuuc68.u_islower_68 +@ cdecl -norelay u_isprint() icuuc68.u_isprint_68 +@ cdecl -norelay u_ispunct() icuuc68.u_ispunct_68 +@ cdecl -norelay u_isspace() icuuc68.u_isspace_68 +@ cdecl -norelay u_istitle() icuuc68.u_istitle_68 +@ cdecl -norelay u_isupper() icuuc68.u_isupper_68 +@ cdecl -norelay u_isxdigit() icuuc68.u_isxdigit_68 +@ cdecl -norelay u_memcasecmp() icuuc68.u_memcasecmp_68 +@ cdecl -norelay u_memchr() icuuc68.u_memchr_68 +@ cdecl -norelay u_memchr32() icuuc68.u_memchr32_68 +@ cdecl -norelay u_memcmp() icuuc68.u_memcmp_68 +@ cdecl -norelay u_memcmpCodePointOrder() icuuc68.u_memcmpCodePointOrder_68 +@ cdecl -norelay u_memcpy() icuuc68.u_memcpy_68 +@ cdecl -norelay u_memmove() icuuc68.u_memmove_68 +@ cdecl -norelay u_memrchr() icuuc68.u_memrchr_68 +@ cdecl -norelay u_memrchr32() icuuc68.u_memrchr32_68 +@ cdecl -norelay u_memset() icuuc68.u_memset_68 +@ cdecl -norelay u_parseMessage() icuin68.u_parseMessage_68 +@ cdecl -norelay u_parseMessageWithError() icuin68.u_parseMessageWithError_68 +@ cdecl -norelay u_setMemoryFunctions() icuuc68.u_setMemoryFunctions_68 +@ cdecl -norelay u_shapeArabic() icuuc68.u_shapeArabic_68 +@ cdecl -norelay u_strCaseCompare() icuuc68.u_strCaseCompare_68 +@ cdecl -norelay u_strCompare() icuuc68.u_strCompare_68 +@ cdecl -norelay u_strCompareIter() icuuc68.u_strCompareIter_68 +@ cdecl -norelay u_strFindFirst() icuuc68.u_strFindFirst_68 +@ cdecl -norelay u_strFindLast() icuuc68.u_strFindLast_68 +@ cdecl -norelay u_strFoldCase() icuuc68.u_strFoldCase_68 +@ cdecl -norelay u_strFromJavaModifiedUTF8WithSub() icuuc68.u_strFromJavaModifiedUTF8WithSub_68 +@ cdecl -norelay u_strFromUTF32() icuuc68.u_strFromUTF32_68 +@ cdecl -norelay u_strFromUTF32WithSub() icuuc68.u_strFromUTF32WithSub_68 +@ cdecl -norelay u_strFromUTF8() icuuc68.u_strFromUTF8_68 +@ cdecl -norelay u_strFromUTF8Lenient() icuuc68.u_strFromUTF8Lenient_68 +@ cdecl -norelay u_strFromUTF8WithSub() icuuc68.u_strFromUTF8WithSub_68 +@ cdecl -norelay u_strFromWCS() icuuc68.u_strFromWCS_68 +@ cdecl -norelay u_strHasMoreChar32Than() icuuc68.u_strHasMoreChar32Than_68 +@ cdecl -norelay u_strToJavaModifiedUTF8() icuuc68.u_strToJavaModifiedUTF8_68 +@ cdecl -norelay u_strToLower() icuuc68.u_strToLower_68 +@ cdecl -norelay u_strToTitle() icuuc68.u_strToTitle_68 +@ cdecl -norelay u_strToUTF32() icuuc68.u_strToUTF32_68 +@ cdecl -norelay u_strToUTF32WithSub() icuuc68.u_strToUTF32WithSub_68 +@ cdecl -norelay u_strToUTF8() icuuc68.u_strToUTF8_68 +@ cdecl -norelay u_strToUTF8WithSub() icuuc68.u_strToUTF8WithSub_68 +@ cdecl -norelay u_strToUpper() icuuc68.u_strToUpper_68 +@ cdecl -norelay u_strToWCS() icuuc68.u_strToWCS_68 +@ cdecl -norelay u_strcasecmp() icuuc68.u_strcasecmp_68 +@ cdecl -norelay u_strcat() icuuc68.u_strcat_68 +@ cdecl -norelay u_strchr() icuuc68.u_strchr_68 +@ cdecl -norelay u_strchr32() icuuc68.u_strchr32_68 +@ cdecl -norelay u_strcmp() icuuc68.u_strcmp_68 +@ cdecl -norelay u_strcmpCodePointOrder() icuuc68.u_strcmpCodePointOrder_68 +@ cdecl -norelay u_strcpy() icuuc68.u_strcpy_68 +@ cdecl -norelay u_strcspn() icuuc68.u_strcspn_68 +@ cdecl -norelay u_strlen() icuuc68.u_strlen_68 +@ cdecl -norelay u_strncasecmp() icuuc68.u_strncasecmp_68 +@ cdecl -norelay u_strncat() icuuc68.u_strncat_68 +@ cdecl -norelay u_strncmp() icuuc68.u_strncmp_68 +@ cdecl -norelay u_strncmpCodePointOrder() icuuc68.u_strncmpCodePointOrder_68 +@ cdecl -norelay u_strncpy() icuuc68.u_strncpy_68 +@ cdecl -norelay u_strpbrk() icuuc68.u_strpbrk_68 +@ cdecl -norelay u_strrchr() icuuc68.u_strrchr_68 +@ cdecl -norelay u_strrchr32() icuuc68.u_strrchr32_68 +@ cdecl -norelay u_strrstr() icuuc68.u_strrstr_68 +@ cdecl -norelay u_strspn() icuuc68.u_strspn_68 +@ cdecl -norelay u_strstr() icuuc68.u_strstr_68 +@ cdecl -norelay u_strtok_r() icuuc68.u_strtok_r_68 +@ cdecl -norelay u_tolower() icuuc68.u_tolower_68 +@ cdecl -norelay u_totitle() icuuc68.u_totitle_68 +@ cdecl -norelay u_toupper() icuuc68.u_toupper_68 +@ cdecl -norelay u_uastrcpy() icuuc68.u_uastrcpy_68 +@ cdecl -norelay u_uastrncpy() icuuc68.u_uastrncpy_68 +@ cdecl -norelay u_unescape() icuuc68.u_unescape_68 +@ cdecl -norelay u_unescapeAt() icuuc68.u_unescapeAt_68 +@ cdecl -norelay u_versionFromString() icuuc68.u_versionFromString_68 +@ cdecl -norelay u_versionFromUString() icuuc68.u_versionFromUString_68 +@ cdecl -norelay u_versionToString() icuuc68.u_versionToString_68 +@ cdecl -norelay u_vformatMessage() icuin68.u_vformatMessage_68 +@ cdecl -norelay u_vformatMessageWithError() icuin68.u_vformatMessageWithError_68 +@ cdecl -norelay u_vparseMessage() icuin68.u_vparseMessage_68 +@ cdecl -norelay u_vparseMessageWithError() icuin68.u_vparseMessageWithError_68 +@ cdecl -norelay ubidi_close() icuuc68.ubidi_close_68 +@ cdecl -norelay ubidi_countParagraphs() icuuc68.ubidi_countParagraphs_68 +@ cdecl -norelay ubidi_countRuns() icuuc68.ubidi_countRuns_68 +@ cdecl -norelay ubidi_getBaseDirection() icuuc68.ubidi_getBaseDirection_68 +@ cdecl -norelay ubidi_getClassCallback() icuuc68.ubidi_getClassCallback_68 +@ cdecl -norelay ubidi_getCustomizedClass() icuuc68.ubidi_getCustomizedClass_68 +@ cdecl -norelay ubidi_getDirection() icuuc68.ubidi_getDirection_68 +@ cdecl -norelay ubidi_getLength() icuuc68.ubidi_getLength_68 +@ cdecl -norelay ubidi_getLevelAt() icuuc68.ubidi_getLevelAt_68 +@ cdecl -norelay ubidi_getLevels() icuuc68.ubidi_getLevels_68 +@ cdecl -norelay ubidi_getLogicalIndex() icuuc68.ubidi_getLogicalIndex_68 +@ cdecl -norelay ubidi_getLogicalMap() icuuc68.ubidi_getLogicalMap_68 +@ cdecl -norelay ubidi_getLogicalRun() icuuc68.ubidi_getLogicalRun_68 +@ cdecl -norelay ubidi_getParaLevel() icuuc68.ubidi_getParaLevel_68 +@ cdecl -norelay ubidi_getParagraph() icuuc68.ubidi_getParagraph_68 +@ cdecl -norelay ubidi_getParagraphByIndex() icuuc68.ubidi_getParagraphByIndex_68 +@ cdecl -norelay ubidi_getProcessedLength() icuuc68.ubidi_getProcessedLength_68 +@ cdecl -norelay ubidi_getReorderingMode() icuuc68.ubidi_getReorderingMode_68 +@ cdecl -norelay ubidi_getReorderingOptions() icuuc68.ubidi_getReorderingOptions_68 +@ cdecl -norelay ubidi_getResultLength() icuuc68.ubidi_getResultLength_68 +@ cdecl -norelay ubidi_getText() icuuc68.ubidi_getText_68 +@ cdecl -norelay ubidi_getVisualIndex() icuuc68.ubidi_getVisualIndex_68 +@ cdecl -norelay ubidi_getVisualMap() icuuc68.ubidi_getVisualMap_68 +@ cdecl -norelay ubidi_getVisualRun() icuuc68.ubidi_getVisualRun_68 +@ cdecl -norelay ubidi_invertMap() icuuc68.ubidi_invertMap_68 +@ cdecl -norelay ubidi_isInverse() icuuc68.ubidi_isInverse_68 +@ cdecl -norelay ubidi_isOrderParagraphsLTR() icuuc68.ubidi_isOrderParagraphsLTR_68 +@ cdecl -norelay ubidi_open() icuuc68.ubidi_open_68 +@ cdecl -norelay ubidi_openSized() icuuc68.ubidi_openSized_68 +@ cdecl -norelay ubidi_orderParagraphsLTR() icuuc68.ubidi_orderParagraphsLTR_68 +@ cdecl -norelay ubidi_reorderLogical() icuuc68.ubidi_reorderLogical_68 +@ cdecl -norelay ubidi_reorderVisual() icuuc68.ubidi_reorderVisual_68 +@ cdecl -norelay ubidi_setClassCallback() icuuc68.ubidi_setClassCallback_68 +@ cdecl -norelay ubidi_setContext() icuuc68.ubidi_setContext_68 +@ cdecl -norelay ubidi_setInverse() icuuc68.ubidi_setInverse_68 +@ cdecl -norelay ubidi_setLine() icuuc68.ubidi_setLine_68 +@ cdecl -norelay ubidi_setPara() icuuc68.ubidi_setPara_68 +@ cdecl -norelay ubidi_setReorderingMode() icuuc68.ubidi_setReorderingMode_68 +@ cdecl -norelay ubidi_setReorderingOptions() icuuc68.ubidi_setReorderingOptions_68 +@ cdecl -norelay ubidi_writeReordered() icuuc68.ubidi_writeReordered_68 +@ cdecl -norelay ubidi_writeReverse() icuuc68.ubidi_writeReverse_68 +@ cdecl -norelay ubiditransform_close() icuuc68.ubiditransform_close_68 +@ cdecl -norelay ubiditransform_open() icuuc68.ubiditransform_open_68 +@ cdecl -norelay ubiditransform_transform() icuuc68.ubiditransform_transform_68 +@ cdecl -norelay ublock_getCode() icuuc68.ublock_getCode_68 +@ cdecl -norelay ubrk_close() icuuc68.ubrk_close_68 +@ cdecl -norelay ubrk_countAvailable() icuuc68.ubrk_countAvailable_68 +@ cdecl -norelay ubrk_current() icuuc68.ubrk_current_68 +@ cdecl -norelay ubrk_first() icuuc68.ubrk_first_68 +@ cdecl -norelay ubrk_following() icuuc68.ubrk_following_68 +@ cdecl -norelay ubrk_getAvailable() icuuc68.ubrk_getAvailable_68 +@ cdecl -norelay ubrk_getBinaryRules() icuuc68.ubrk_getBinaryRules_68 +@ cdecl -norelay ubrk_getLocaleByType() icuuc68.ubrk_getLocaleByType_68 +@ cdecl -norelay ubrk_getRuleStatus() icuuc68.ubrk_getRuleStatus_68 +@ cdecl -norelay ubrk_getRuleStatusVec() icuuc68.ubrk_getRuleStatusVec_68 +@ cdecl -norelay ubrk_isBoundary() icuuc68.ubrk_isBoundary_68 +@ cdecl -norelay ubrk_last() icuuc68.ubrk_last_68 +@ cdecl -norelay ubrk_next() icuuc68.ubrk_next_68 +@ cdecl -norelay ubrk_open() icuuc68.ubrk_open_68 +@ cdecl -norelay ubrk_openBinaryRules() icuuc68.ubrk_openBinaryRules_68 +@ cdecl -norelay ubrk_openRules() icuuc68.ubrk_openRules_68 +@ cdecl -norelay ubrk_preceding() icuuc68.ubrk_preceding_68 +@ cdecl -norelay ubrk_previous() icuuc68.ubrk_previous_68 +@ cdecl -norelay ubrk_refreshUText() icuuc68.ubrk_refreshUText_68 +@ cdecl -norelay ubrk_safeClone() icuuc68.ubrk_safeClone_68 +@ cdecl -norelay ubrk_setText() icuuc68.ubrk_setText_68 +@ cdecl -norelay ubrk_setUText() icuuc68.ubrk_setUText_68 +@ cdecl -norelay ucal_add() icuin68.ucal_add_68 +@ cdecl -norelay ucal_clear() icuin68.ucal_clear_68 +@ cdecl -norelay ucal_clearField() icuin68.ucal_clearField_68 +@ cdecl -norelay ucal_clone() icuin68.ucal_clone_68 +@ cdecl -norelay ucal_close() icuin68.ucal_close_68 +@ cdecl -norelay ucal_countAvailable() icuin68.ucal_countAvailable_68 +@ cdecl -norelay ucal_equivalentTo() icuin68.ucal_equivalentTo_68 +@ cdecl -norelay ucal_get() icuin68.ucal_get_68 +@ cdecl -norelay ucal_getAttribute() icuin68.ucal_getAttribute_68 +@ cdecl -norelay ucal_getAvailable() icuin68.ucal_getAvailable_68 +@ cdecl -norelay ucal_getCanonicalTimeZoneID() icuin68.ucal_getCanonicalTimeZoneID_68 +@ cdecl -norelay ucal_getDSTSavings() icuin68.ucal_getDSTSavings_68 +@ cdecl -norelay ucal_getDayOfWeekType() icuin68.ucal_getDayOfWeekType_68 +@ cdecl -norelay ucal_getDefaultTimeZone() icuin68.ucal_getDefaultTimeZone_68 +@ cdecl -norelay ucal_getFieldDifference() icuin68.ucal_getFieldDifference_68 +@ cdecl -norelay ucal_getGregorianChange() icuin68.ucal_getGregorianChange_68 +@ cdecl -norelay ucal_getHostTimeZone() icuin68.ucal_getHostTimeZone_68 +@ cdecl -norelay ucal_getKeywordValuesForLocale() icuin68.ucal_getKeywordValuesForLocale_68 +@ cdecl -norelay ucal_getLimit() icuin68.ucal_getLimit_68 +@ cdecl -norelay ucal_getLocaleByType() icuin68.ucal_getLocaleByType_68 +@ cdecl -norelay ucal_getMillis() icuin68.ucal_getMillis_68 +@ cdecl -norelay ucal_getNow() icuin68.ucal_getNow_68 +@ cdecl -norelay ucal_getTZDataVersion() icuin68.ucal_getTZDataVersion_68 +@ cdecl -norelay ucal_getTimeZoneDisplayName() icuin68.ucal_getTimeZoneDisplayName_68 +@ cdecl -norelay ucal_getTimeZoneID() icuin68.ucal_getTimeZoneID_68 +@ cdecl -norelay ucal_getTimeZoneIDForWindowsID() icuin68.ucal_getTimeZoneIDForWindowsID_68 +@ cdecl -norelay ucal_getTimeZoneTransitionDate() icuin68.ucal_getTimeZoneTransitionDate_68 +@ cdecl -norelay ucal_getType() icuin68.ucal_getType_68 +@ cdecl -norelay ucal_getWeekendTransition() icuin68.ucal_getWeekendTransition_68 +@ cdecl -norelay ucal_getWindowsTimeZoneID() icuin68.ucal_getWindowsTimeZoneID_68 +@ cdecl -norelay ucal_inDaylightTime() icuin68.ucal_inDaylightTime_68 +@ cdecl -norelay ucal_isSet() icuin68.ucal_isSet_68 +@ cdecl -norelay ucal_isWeekend() icuin68.ucal_isWeekend_68 +@ cdecl -norelay ucal_open() icuin68.ucal_open_68 +@ cdecl -norelay ucal_openCountryTimeZones() icuin68.ucal_openCountryTimeZones_68 +@ cdecl -norelay ucal_openTimeZoneIDEnumeration() icuin68.ucal_openTimeZoneIDEnumeration_68 +@ cdecl -norelay ucal_openTimeZones() icuin68.ucal_openTimeZones_68 +@ cdecl -norelay ucal_roll() icuin68.ucal_roll_68 +@ cdecl -norelay ucal_set() icuin68.ucal_set_68 +@ cdecl -norelay ucal_setAttribute() icuin68.ucal_setAttribute_68 +@ cdecl -norelay ucal_setDate() icuin68.ucal_setDate_68 +@ cdecl -norelay ucal_setDateTime() icuin68.ucal_setDateTime_68 +@ cdecl -norelay ucal_setDefaultTimeZone() icuin68.ucal_setDefaultTimeZone_68 +@ cdecl -norelay ucal_setGregorianChange() icuin68.ucal_setGregorianChange_68 +@ cdecl -norelay ucal_setMillis() icuin68.ucal_setMillis_68 +@ cdecl -norelay ucal_setTimeZone() icuin68.ucal_setTimeZone_68 +@ cdecl -norelay ucasemap_close() icuuc68.ucasemap_close_68 +@ cdecl -norelay ucasemap_getBreakIterator() icuuc68.ucasemap_getBreakIterator_68 +@ cdecl -norelay ucasemap_getLocale() icuuc68.ucasemap_getLocale_68 +@ cdecl -norelay ucasemap_getOptions() icuuc68.ucasemap_getOptions_68 +@ cdecl -norelay ucasemap_open() icuuc68.ucasemap_open_68 +@ cdecl -norelay ucasemap_setBreakIterator() icuuc68.ucasemap_setBreakIterator_68 +@ cdecl -norelay ucasemap_setLocale() icuuc68.ucasemap_setLocale_68 +@ cdecl -norelay ucasemap_setOptions() icuuc68.ucasemap_setOptions_68 +@ cdecl -norelay ucasemap_toTitle() icuuc68.ucasemap_toTitle_68 +@ cdecl -norelay ucasemap_utf8FoldCase() icuuc68.ucasemap_utf8FoldCase_68 +@ cdecl -norelay ucasemap_utf8ToLower() icuuc68.ucasemap_utf8ToLower_68 +@ cdecl -norelay ucasemap_utf8ToTitle() icuuc68.ucasemap_utf8ToTitle_68 +@ cdecl -norelay ucasemap_utf8ToUpper() icuuc68.ucasemap_utf8ToUpper_68 +@ cdecl -norelay ucfpos_close() icuin68.ucfpos_close_68 +@ cdecl -norelay ucfpos_constrainCategory() icuin68.ucfpos_constrainCategory_68 +@ cdecl -norelay ucfpos_constrainField() icuin68.ucfpos_constrainField_68 +@ cdecl -norelay ucfpos_getCategory() icuin68.ucfpos_getCategory_68 +@ cdecl -norelay ucfpos_getField() icuin68.ucfpos_getField_68 +@ cdecl -norelay ucfpos_getIndexes() icuin68.ucfpos_getIndexes_68 +@ cdecl -norelay ucfpos_getInt64IterationContext() icuin68.ucfpos_getInt64IterationContext_68 +@ cdecl -norelay ucfpos_matchesField() icuin68.ucfpos_matchesField_68 +@ cdecl -norelay ucfpos_open() icuin68.ucfpos_open_68 +@ cdecl -norelay ucfpos_reset() icuin68.ucfpos_reset_68 +@ cdecl -norelay ucfpos_setInt64IterationContext() icuin68.ucfpos_setInt64IterationContext_68 +@ cdecl -norelay ucfpos_setState() icuin68.ucfpos_setState_68 +@ cdecl -norelay ucnv_cbFromUWriteBytes() icuuc68.ucnv_cbFromUWriteBytes_68 +@ cdecl -norelay ucnv_cbFromUWriteSub() icuuc68.ucnv_cbFromUWriteSub_68 +@ cdecl -norelay ucnv_cbFromUWriteUChars() icuuc68.ucnv_cbFromUWriteUChars_68 +@ cdecl -norelay ucnv_cbToUWriteSub() icuuc68.ucnv_cbToUWriteSub_68 +@ cdecl -norelay ucnv_cbToUWriteUChars() icuuc68.ucnv_cbToUWriteUChars_68 +@ cdecl -norelay ucnv_close() icuuc68.ucnv_close_68 +@ cdecl -norelay ucnv_compareNames() icuuc68.ucnv_compareNames_68 +@ cdecl -norelay ucnv_convert() icuuc68.ucnv_convert_68 +@ cdecl -norelay ucnv_convertEx() icuuc68.ucnv_convertEx_68 +@ cdecl -norelay ucnv_countAliases() icuuc68.ucnv_countAliases_68 +@ cdecl -norelay ucnv_countAvailable() icuuc68.ucnv_countAvailable_68 +@ cdecl -norelay ucnv_countStandards() icuuc68.ucnv_countStandards_68 +@ cdecl -norelay ucnv_detectUnicodeSignature() icuuc68.ucnv_detectUnicodeSignature_68 +@ cdecl -norelay ucnv_fixFileSeparator() icuuc68.ucnv_fixFileSeparator_68 +@ cdecl -norelay ucnv_flushCache() icuuc68.ucnv_flushCache_68 +@ cdecl -norelay ucnv_fromAlgorithmic() icuuc68.ucnv_fromAlgorithmic_68 +@ cdecl -norelay ucnv_fromUChars() icuuc68.ucnv_fromUChars_68 +@ cdecl -norelay ucnv_fromUCountPending() icuuc68.ucnv_fromUCountPending_68 +@ cdecl -norelay ucnv_fromUnicode() icuuc68.ucnv_fromUnicode_68 +@ cdecl -norelay ucnv_getAlias() icuuc68.ucnv_getAlias_68 +@ cdecl -norelay ucnv_getAliases() icuuc68.ucnv_getAliases_68 +@ cdecl -norelay ucnv_getAvailableName() icuuc68.ucnv_getAvailableName_68 +@ cdecl -norelay ucnv_getCCSID() icuuc68.ucnv_getCCSID_68 +@ cdecl -norelay ucnv_getCanonicalName() icuuc68.ucnv_getCanonicalName_68 +@ cdecl -norelay ucnv_getDefaultName() icuuc68.ucnv_getDefaultName_68 +@ cdecl -norelay ucnv_getDisplayName() icuuc68.ucnv_getDisplayName_68 +@ cdecl -norelay ucnv_getFromUCallBack() icuuc68.ucnv_getFromUCallBack_68 +@ cdecl -norelay ucnv_getInvalidChars() icuuc68.ucnv_getInvalidChars_68 +@ cdecl -norelay ucnv_getInvalidUChars() icuuc68.ucnv_getInvalidUChars_68 +@ cdecl -norelay ucnv_getMaxCharSize() icuuc68.ucnv_getMaxCharSize_68 +@ cdecl -norelay ucnv_getMinCharSize() icuuc68.ucnv_getMinCharSize_68 +@ cdecl -norelay ucnv_getName() icuuc68.ucnv_getName_68 +@ cdecl -norelay ucnv_getNextUChar() icuuc68.ucnv_getNextUChar_68 +@ cdecl -norelay ucnv_getPlatform() icuuc68.ucnv_getPlatform_68 +@ cdecl -norelay ucnv_getStandard() icuuc68.ucnv_getStandard_68 +@ cdecl -norelay ucnv_getStandardName() icuuc68.ucnv_getStandardName_68 +@ cdecl -norelay ucnv_getStarters() icuuc68.ucnv_getStarters_68 +@ cdecl -norelay ucnv_getSubstChars() icuuc68.ucnv_getSubstChars_68 +@ cdecl -norelay ucnv_getToUCallBack() icuuc68.ucnv_getToUCallBack_68 +@ cdecl -norelay ucnv_getType() icuuc68.ucnv_getType_68 +@ cdecl -norelay ucnv_getUnicodeSet() icuuc68.ucnv_getUnicodeSet_68 +@ cdecl -norelay ucnv_isAmbiguous() icuuc68.ucnv_isAmbiguous_68 +@ cdecl -norelay ucnv_isFixedWidth() icuuc68.ucnv_isFixedWidth_68 +@ cdecl -norelay ucnv_open() icuuc68.ucnv_open_68 +@ cdecl -norelay ucnv_openAllNames() icuuc68.ucnv_openAllNames_68 +@ cdecl -norelay ucnv_openCCSID() icuuc68.ucnv_openCCSID_68 +@ cdecl -norelay ucnv_openPackage() icuuc68.ucnv_openPackage_68 +@ cdecl -norelay ucnv_openStandardNames() icuuc68.ucnv_openStandardNames_68 +@ cdecl -norelay ucnv_openU() icuuc68.ucnv_openU_68 +@ cdecl -norelay ucnv_reset() icuuc68.ucnv_reset_68 +@ cdecl -norelay ucnv_resetFromUnicode() icuuc68.ucnv_resetFromUnicode_68 +@ cdecl -norelay ucnv_resetToUnicode() icuuc68.ucnv_resetToUnicode_68 +@ cdecl -norelay ucnv_safeClone() icuuc68.ucnv_safeClone_68 +@ cdecl -norelay ucnv_setDefaultName() icuuc68.ucnv_setDefaultName_68 +@ cdecl -norelay ucnv_setFallback() icuuc68.ucnv_setFallback_68 +@ cdecl -norelay ucnv_setFromUCallBack() icuuc68.ucnv_setFromUCallBack_68 +@ cdecl -norelay ucnv_setSubstChars() icuuc68.ucnv_setSubstChars_68 +@ cdecl -norelay ucnv_setSubstString() icuuc68.ucnv_setSubstString_68 +@ cdecl -norelay ucnv_setToUCallBack() icuuc68.ucnv_setToUCallBack_68 +@ cdecl -norelay ucnv_toAlgorithmic() icuuc68.ucnv_toAlgorithmic_68 +@ cdecl -norelay ucnv_toUChars() icuuc68.ucnv_toUChars_68 +@ cdecl -norelay ucnv_toUCountPending() icuuc68.ucnv_toUCountPending_68 +@ cdecl -norelay ucnv_toUnicode() icuuc68.ucnv_toUnicode_68 +@ cdecl -norelay ucnv_usesFallback() icuuc68.ucnv_usesFallback_68 +@ cdecl -norelay ucnvsel_close() icuuc68.ucnvsel_close_68 +@ cdecl -norelay ucnvsel_open() icuuc68.ucnvsel_open_68 +@ cdecl -norelay ucnvsel_openFromSerialized() icuuc68.ucnvsel_openFromSerialized_68 +@ cdecl -norelay ucnvsel_selectForString() icuuc68.ucnvsel_selectForString_68 +@ cdecl -norelay ucnvsel_selectForUTF8() icuuc68.ucnvsel_selectForUTF8_68 +@ cdecl -norelay ucnvsel_serialize() icuuc68.ucnvsel_serialize_68 +@ cdecl -norelay ucol_cloneBinary() icuin68.ucol_cloneBinary_68 +@ cdecl -norelay ucol_close() icuin68.ucol_close_68 +@ cdecl -norelay ucol_closeElements() icuin68.ucol_closeElements_68 +@ cdecl -norelay ucol_countAvailable() icuin68.ucol_countAvailable_68 +@ cdecl -norelay ucol_equal() icuin68.ucol_equal_68 +@ cdecl -norelay ucol_getAttribute() icuin68.ucol_getAttribute_68 +@ cdecl -norelay ucol_getAvailable() icuin68.ucol_getAvailable_68 +@ cdecl -norelay ucol_getBound() icuin68.ucol_getBound_68 +@ cdecl -norelay ucol_getContractionsAndExpansions() icuin68.ucol_getContractionsAndExpansions_68 +@ cdecl -norelay ucol_getDisplayName() icuin68.ucol_getDisplayName_68 +@ cdecl -norelay ucol_getEquivalentReorderCodes() icuin68.ucol_getEquivalentReorderCodes_68 +@ cdecl -norelay ucol_getFunctionalEquivalent() icuin68.ucol_getFunctionalEquivalent_68 +@ cdecl -norelay ucol_getKeywordValues() icuin68.ucol_getKeywordValues_68 +@ cdecl -norelay ucol_getKeywordValuesForLocale() icuin68.ucol_getKeywordValuesForLocale_68 +@ cdecl -norelay ucol_getKeywords() icuin68.ucol_getKeywords_68 +@ cdecl -norelay ucol_getLocaleByType() icuin68.ucol_getLocaleByType_68 +@ cdecl -norelay ucol_getMaxExpansion() icuin68.ucol_getMaxExpansion_68 +@ cdecl -norelay ucol_getMaxVariable() icuin68.ucol_getMaxVariable_68 +@ cdecl -norelay ucol_getOffset() icuin68.ucol_getOffset_68 +@ cdecl -norelay ucol_getReorderCodes() icuin68.ucol_getReorderCodes_68 +@ cdecl -norelay ucol_getRules() icuin68.ucol_getRules_68 +@ cdecl -norelay ucol_getRulesEx() icuin68.ucol_getRulesEx_68 +@ cdecl -norelay ucol_getSortKey() icuin68.ucol_getSortKey_68 +@ cdecl -norelay ucol_getStrength() icuin68.ucol_getStrength_68 +@ cdecl -norelay ucol_getTailoredSet() icuin68.ucol_getTailoredSet_68 +@ cdecl -norelay ucol_getUCAVersion() icuin68.ucol_getUCAVersion_68 +@ cdecl -norelay ucol_getVariableTop() icuin68.ucol_getVariableTop_68 +@ cdecl -norelay ucol_getVersion() icuin68.ucol_getVersion_68 +@ cdecl -norelay ucol_greater() icuin68.ucol_greater_68 +@ cdecl -norelay ucol_greaterOrEqual() icuin68.ucol_greaterOrEqual_68 +@ cdecl -norelay ucol_keyHashCode() icuin68.ucol_keyHashCode_68 +@ cdecl -norelay ucol_mergeSortkeys() icuin68.ucol_mergeSortkeys_68 +@ cdecl -norelay ucol_next() icuin68.ucol_next_68 +@ cdecl -norelay ucol_nextSortKeyPart() icuin68.ucol_nextSortKeyPart_68 +@ cdecl -norelay ucol_open() icuin68.ucol_open_68 +@ cdecl -norelay ucol_openAvailableLocales() icuin68.ucol_openAvailableLocales_68 +@ cdecl -norelay ucol_openBinary() icuin68.ucol_openBinary_68 +@ cdecl -norelay ucol_openElements() icuin68.ucol_openElements_68 +@ cdecl -norelay ucol_openRules() icuin68.ucol_openRules_68 +@ cdecl -norelay ucol_previous() icuin68.ucol_previous_68 +@ cdecl -norelay ucol_primaryOrder() icuin68.ucol_primaryOrder_68 +@ cdecl -norelay ucol_reset() icuin68.ucol_reset_68 +@ cdecl -norelay ucol_safeClone() icuin68.ucol_safeClone_68 +@ cdecl -norelay ucol_secondaryOrder() icuin68.ucol_secondaryOrder_68 +@ cdecl -norelay ucol_setAttribute() icuin68.ucol_setAttribute_68 +@ cdecl -norelay ucol_setMaxVariable() icuin68.ucol_setMaxVariable_68 +@ cdecl -norelay ucol_setOffset() icuin68.ucol_setOffset_68 +@ cdecl -norelay ucol_setReorderCodes() icuin68.ucol_setReorderCodes_68 +@ cdecl -norelay ucol_setStrength() icuin68.ucol_setStrength_68 +@ cdecl -norelay ucol_setText() icuin68.ucol_setText_68 +@ cdecl -norelay ucol_strcoll() icuin68.ucol_strcoll_68 +@ cdecl -norelay ucol_strcollIter() icuin68.ucol_strcollIter_68 +@ cdecl -norelay ucol_strcollUTF8() icuin68.ucol_strcollUTF8_68 +@ cdecl -norelay ucol_tertiaryOrder() icuin68.ucol_tertiaryOrder_68 +@ cdecl -norelay ucpmap_get() icuuc68.ucpmap_get_68 +@ cdecl -norelay ucpmap_getRange() icuuc68.ucpmap_getRange_68 +@ cdecl -norelay ucptrie_close() icuuc68.ucptrie_close_68 +@ cdecl -norelay ucptrie_get() icuuc68.ucptrie_get_68 +@ cdecl -norelay ucptrie_getRange() icuuc68.ucptrie_getRange_68 +@ cdecl -norelay ucptrie_getType() icuuc68.ucptrie_getType_68 +@ cdecl -norelay ucptrie_getValueWidth() icuuc68.ucptrie_getValueWidth_68 +@ cdecl -norelay ucptrie_internalSmallIndex() icuuc68.ucptrie_internalSmallIndex_68 +@ cdecl -norelay ucptrie_internalSmallU8Index() icuuc68.ucptrie_internalSmallU8Index_68 +@ cdecl -norelay ucptrie_internalU8PrevIndex() icuuc68.ucptrie_internalU8PrevIndex_68 +@ cdecl -norelay ucptrie_openFromBinary() icuuc68.ucptrie_openFromBinary_68 +@ cdecl -norelay ucptrie_toBinary() icuuc68.ucptrie_toBinary_68 +@ cdecl -norelay ucsdet_close() icuin68.ucsdet_close_68 +@ cdecl -norelay ucsdet_detect() icuin68.ucsdet_detect_68 +@ cdecl -norelay ucsdet_detectAll() icuin68.ucsdet_detectAll_68 +@ cdecl -norelay ucsdet_enableInputFilter() icuin68.ucsdet_enableInputFilter_68 +@ cdecl -norelay ucsdet_getAllDetectableCharsets() icuin68.ucsdet_getAllDetectableCharsets_68 +@ cdecl -norelay ucsdet_getConfidence() icuin68.ucsdet_getConfidence_68 +@ cdecl -norelay ucsdet_getLanguage() icuin68.ucsdet_getLanguage_68 +@ cdecl -norelay ucsdet_getName() icuin68.ucsdet_getName_68 +@ cdecl -norelay ucsdet_getUChars() icuin68.ucsdet_getUChars_68 +@ cdecl -norelay ucsdet_isInputFilterEnabled() icuin68.ucsdet_isInputFilterEnabled_68 +@ cdecl -norelay ucsdet_open() icuin68.ucsdet_open_68 +@ cdecl -norelay ucsdet_setDeclaredEncoding() icuin68.ucsdet_setDeclaredEncoding_68 +@ cdecl -norelay ucsdet_setText() icuin68.ucsdet_setText_68 +@ cdecl -norelay ucurr_countCurrencies() icuuc68.ucurr_countCurrencies_68 +@ cdecl -norelay ucurr_forLocale() icuuc68.ucurr_forLocale_68 +@ cdecl -norelay ucurr_forLocaleAndDate() icuuc68.ucurr_forLocaleAndDate_68 +@ cdecl -norelay ucurr_getDefaultFractionDigits() icuuc68.ucurr_getDefaultFractionDigits_68 +@ cdecl -norelay ucurr_getDefaultFractionDigitsForUsage() icuuc68.ucurr_getDefaultFractionDigitsForUsage_68 +@ cdecl -norelay ucurr_getKeywordValuesForLocale() icuuc68.ucurr_getKeywordValuesForLocale_68 +@ cdecl -norelay ucurr_getName() icuuc68.ucurr_getName_68 +@ cdecl -norelay ucurr_getNumericCode() icuuc68.ucurr_getNumericCode_68 +@ cdecl -norelay ucurr_getPluralName() icuuc68.ucurr_getPluralName_68 +@ cdecl -norelay ucurr_getRoundingIncrement() icuuc68.ucurr_getRoundingIncrement_68 +@ cdecl -norelay ucurr_getRoundingIncrementForUsage() icuuc68.ucurr_getRoundingIncrementForUsage_68 +@ cdecl -norelay ucurr_isAvailable() icuuc68.ucurr_isAvailable_68 +@ cdecl -norelay ucurr_openISOCurrencies() icuuc68.ucurr_openISOCurrencies_68 +@ cdecl -norelay ucurr_register() icuuc68.ucurr_register_68 +@ cdecl -norelay ucurr_unregister() icuuc68.ucurr_unregister_68 +@ cdecl -norelay udat_adoptNumberFormat() icuin68.udat_adoptNumberFormat_68 +@ cdecl -norelay udat_adoptNumberFormatForFields() icuin68.udat_adoptNumberFormatForFields_68 +@ cdecl -norelay udat_applyPattern() icuin68.udat_applyPattern_68 +@ cdecl -norelay udat_clone() icuin68.udat_clone_68 +@ cdecl -norelay udat_close() icuin68.udat_close_68 +@ cdecl -norelay udat_countAvailable() icuin68.udat_countAvailable_68 +@ cdecl -norelay udat_countSymbols() icuin68.udat_countSymbols_68 +@ cdecl -norelay udat_format() icuin68.udat_format_68 +@ cdecl -norelay udat_formatCalendar() icuin68.udat_formatCalendar_68 +@ cdecl -norelay udat_formatCalendarForFields() icuin68.udat_formatCalendarForFields_68 +@ cdecl -norelay udat_formatForFields() icuin68.udat_formatForFields_68 +@ cdecl -norelay udat_get2DigitYearStart() icuin68.udat_get2DigitYearStart_68 +@ cdecl -norelay udat_getAvailable() icuin68.udat_getAvailable_68 +@ cdecl -norelay udat_getBooleanAttribute() icuin68.udat_getBooleanAttribute_68 +@ cdecl -norelay udat_getCalendar() icuin68.udat_getCalendar_68 +@ cdecl -norelay udat_getContext() icuin68.udat_getContext_68 +@ cdecl -norelay udat_getLocaleByType() icuin68.udat_getLocaleByType_68 +@ cdecl -norelay udat_getNumberFormat() icuin68.udat_getNumberFormat_68 +@ cdecl -norelay udat_getNumberFormatForField() icuin68.udat_getNumberFormatForField_68 +@ cdecl -norelay udat_getSymbols() icuin68.udat_getSymbols_68 +@ cdecl -norelay udat_isLenient() icuin68.udat_isLenient_68 +@ cdecl -norelay udat_open() icuin68.udat_open_68 +@ cdecl -norelay udat_parse() icuin68.udat_parse_68 +@ cdecl -norelay udat_parseCalendar() icuin68.udat_parseCalendar_68 +@ cdecl -norelay udat_set2DigitYearStart() icuin68.udat_set2DigitYearStart_68 +@ cdecl -norelay udat_setBooleanAttribute() icuin68.udat_setBooleanAttribute_68 +@ cdecl -norelay udat_setCalendar() icuin68.udat_setCalendar_68 +@ cdecl -norelay udat_setContext() icuin68.udat_setContext_68 +@ cdecl -norelay udat_setLenient() icuin68.udat_setLenient_68 +@ cdecl -norelay udat_setNumberFormat() icuin68.udat_setNumberFormat_68 +@ cdecl -norelay udat_setSymbols() icuin68.udat_setSymbols_68 +@ cdecl -norelay udat_toCalendarDateField() icuin68.udat_toCalendarDateField_68 +@ cdecl -norelay udat_toPattern() icuin68.udat_toPattern_68 +@ cdecl -norelay udatpg_addPattern() icuin68.udatpg_addPattern_68 +@ cdecl -norelay udatpg_clone() icuin68.udatpg_clone_68 +@ cdecl -norelay udatpg_close() icuin68.udatpg_close_68 +@ cdecl -norelay udatpg_getAppendItemFormat() icuin68.udatpg_getAppendItemFormat_68 +@ cdecl -norelay udatpg_getAppendItemName() icuin68.udatpg_getAppendItemName_68 +@ cdecl -norelay udatpg_getBaseSkeleton() icuin68.udatpg_getBaseSkeleton_68 +@ cdecl -norelay udatpg_getBestPattern() icuin68.udatpg_getBestPattern_68 +@ cdecl -norelay udatpg_getBestPatternWithOptions() icuin68.udatpg_getBestPatternWithOptions_68 +@ cdecl -norelay udatpg_getDateTimeFormat() icuin68.udatpg_getDateTimeFormat_68 +@ cdecl -norelay udatpg_getDecimal() icuin68.udatpg_getDecimal_68 +@ cdecl -norelay udatpg_getFieldDisplayName() icuin68.udatpg_getFieldDisplayName_68 +@ cdecl -norelay udatpg_getPatternForSkeleton() icuin68.udatpg_getPatternForSkeleton_68 +@ cdecl -norelay udatpg_getSkeleton() icuin68.udatpg_getSkeleton_68 +@ cdecl -norelay udatpg_open() icuin68.udatpg_open_68 +@ cdecl -norelay udatpg_openBaseSkeletons() icuin68.udatpg_openBaseSkeletons_68 +@ cdecl -norelay udatpg_openEmpty() icuin68.udatpg_openEmpty_68 +@ cdecl -norelay udatpg_openSkeletons() icuin68.udatpg_openSkeletons_68 +@ cdecl -norelay udatpg_replaceFieldTypes() icuin68.udatpg_replaceFieldTypes_68 +@ cdecl -norelay udatpg_replaceFieldTypesWithOptions() icuin68.udatpg_replaceFieldTypesWithOptions_68 +@ cdecl -norelay udatpg_setAppendItemFormat() icuin68.udatpg_setAppendItemFormat_68 +@ cdecl -norelay udatpg_setAppendItemName() icuin68.udatpg_setAppendItemName_68 +@ cdecl -norelay udatpg_setDateTimeFormat() icuin68.udatpg_setDateTimeFormat_68 +@ cdecl -norelay udatpg_setDecimal() icuin68.udatpg_setDecimal_68 +@ cdecl -norelay udtitvfmt_close() icuin68.udtitvfmt_close_68 +@ cdecl -norelay udtitvfmt_closeResult() icuin68.udtitvfmt_closeResult_68 +@ cdecl -norelay udtitvfmt_format() icuin68.udtitvfmt_format_68 +@ cdecl -norelay udtitvfmt_open() icuin68.udtitvfmt_open_68 +@ cdecl -norelay udtitvfmt_openResult() icuin68.udtitvfmt_openResult_68 +@ cdecl -norelay udtitvfmt_resultAsValue() icuin68.udtitvfmt_resultAsValue_68 +@ cdecl -norelay uenum_close() icuuc68.uenum_close_68 +@ cdecl -norelay uenum_count() icuuc68.uenum_count_68 +@ cdecl -norelay uenum_next() icuuc68.uenum_next_68 +@ cdecl -norelay uenum_openCharStringsEnumeration() icuuc68.uenum_openCharStringsEnumeration_68 +@ cdecl -norelay uenum_openUCharStringsEnumeration() icuuc68.uenum_openUCharStringsEnumeration_68 +@ cdecl -norelay uenum_reset() icuuc68.uenum_reset_68 +@ cdecl -norelay uenum_unext() icuuc68.uenum_unext_68 +@ cdecl -norelay ufieldpositer_close() icuin68.ufieldpositer_close_68 +@ cdecl -norelay ufieldpositer_next() icuin68.ufieldpositer_next_68 +@ cdecl -norelay ufieldpositer_open() icuin68.ufieldpositer_open_68 +@ cdecl -norelay ufmt_close() icuin68.ufmt_close_68 +@ cdecl -norelay ufmt_getArrayItemByIndex() icuin68.ufmt_getArrayItemByIndex_68 +@ cdecl -norelay ufmt_getArrayLength() icuin68.ufmt_getArrayLength_68 +@ cdecl -norelay ufmt_getDate() icuin68.ufmt_getDate_68 +@ cdecl -norelay ufmt_getDecNumChars() icuin68.ufmt_getDecNumChars_68 +@ cdecl -norelay ufmt_getDouble() icuin68.ufmt_getDouble_68 +@ cdecl -norelay ufmt_getInt64() icuin68.ufmt_getInt64_68 +@ cdecl -norelay ufmt_getLong() icuin68.ufmt_getLong_68 +@ cdecl -norelay ufmt_getObject() icuin68.ufmt_getObject_68 +@ cdecl -norelay ufmt_getType() icuin68.ufmt_getType_68 +@ cdecl -norelay ufmt_getUChars() icuin68.ufmt_getUChars_68 +@ cdecl -norelay ufmt_isNumeric() icuin68.ufmt_isNumeric_68 +@ cdecl -norelay ufmt_open() icuin68.ufmt_open_68 +@ cdecl -norelay ufmtval_getString() icuin68.ufmtval_getString_68 +@ cdecl -norelay ufmtval_nextPosition() icuin68.ufmtval_nextPosition_68 +@ cdecl -norelay ugender_getInstance() icuin68.ugender_getInstance_68 +@ cdecl -norelay ugender_getListGender() icuin68.ugender_getListGender_68 +@ cdecl -norelay uidna_close() icuuc68.uidna_close_68 +@ cdecl -norelay uidna_labelToASCII() icuuc68.uidna_labelToASCII_68 +@ cdecl -norelay uidna_labelToASCII_UTF8() icuuc68.uidna_labelToASCII_UTF8_68 +@ cdecl -norelay uidna_labelToUnicode() icuuc68.uidna_labelToUnicode_68 +@ cdecl -norelay uidna_labelToUnicodeUTF8() icuuc68.uidna_labelToUnicodeUTF8_68 +@ cdecl -norelay uidna_nameToASCII() icuuc68.uidna_nameToASCII_68 +@ cdecl -norelay uidna_nameToASCII_UTF8() icuuc68.uidna_nameToASCII_UTF8_68 +@ cdecl -norelay uidna_nameToUnicode() icuuc68.uidna_nameToUnicode_68 +@ cdecl -norelay uidna_nameToUnicodeUTF8() icuuc68.uidna_nameToUnicodeUTF8_68 +@ cdecl -norelay uidna_openUTS46() icuuc68.uidna_openUTS46_68 +@ cdecl -norelay uiter_current32() icuuc68.uiter_current32_68 +@ cdecl -norelay uiter_getState() icuuc68.uiter_getState_68 +@ cdecl -norelay uiter_next32() icuuc68.uiter_next32_68 +@ cdecl -norelay uiter_previous32() icuuc68.uiter_previous32_68 +@ cdecl -norelay uiter_setState() icuuc68.uiter_setState_68 +@ cdecl -norelay uiter_setString() icuuc68.uiter_setString_68 +@ cdecl -norelay uiter_setUTF16BE() icuuc68.uiter_setUTF16BE_68 +@ cdecl -norelay uiter_setUTF8() icuuc68.uiter_setUTF8_68 +@ cdecl -norelay uldn_close() icuuc68.uldn_close_68 +@ cdecl -norelay uldn_getContext() icuuc68.uldn_getContext_68 +@ cdecl -norelay uldn_getDialectHandling() icuuc68.uldn_getDialectHandling_68 +@ cdecl -norelay uldn_getLocale() icuuc68.uldn_getLocale_68 +@ cdecl -norelay uldn_keyDisplayName() icuuc68.uldn_keyDisplayName_68 +@ cdecl -norelay uldn_keyValueDisplayName() icuuc68.uldn_keyValueDisplayName_68 +@ cdecl -norelay uldn_languageDisplayName() icuuc68.uldn_languageDisplayName_68 +@ cdecl -norelay uldn_localeDisplayName() icuuc68.uldn_localeDisplayName_68 +@ cdecl -norelay uldn_open() icuuc68.uldn_open_68 +@ cdecl -norelay uldn_openForContext() icuuc68.uldn_openForContext_68 +@ cdecl -norelay uldn_regionDisplayName() icuuc68.uldn_regionDisplayName_68 +@ cdecl -norelay uldn_scriptCodeDisplayName() icuuc68.uldn_scriptCodeDisplayName_68 +@ cdecl -norelay uldn_scriptDisplayName() icuuc68.uldn_scriptDisplayName_68 +@ cdecl -norelay uldn_variantDisplayName() icuuc68.uldn_variantDisplayName_68 +@ cdecl -norelay ulistfmt_close() icuin68.ulistfmt_close_68 +@ cdecl -norelay ulistfmt_closeResult() icuin68.ulistfmt_closeResult_68 +@ cdecl -norelay ulistfmt_format() icuin68.ulistfmt_format_68 +@ cdecl -norelay ulistfmt_formatStringsToResult() icuin68.ulistfmt_formatStringsToResult_68 +@ cdecl -norelay ulistfmt_open() icuin68.ulistfmt_open_68 +@ cdecl -norelay ulistfmt_openForType() icuin68.ulistfmt_openForType_68 +@ cdecl -norelay ulistfmt_openResult() icuin68.ulistfmt_openResult_68 +@ cdecl -norelay ulistfmt_resultAsValue() icuin68.ulistfmt_resultAsValue_68 +@ cdecl -norelay uloc_acceptLanguage() icuuc68.uloc_acceptLanguage_68 +@ cdecl -norelay uloc_acceptLanguageFromHTTP() icuuc68.uloc_acceptLanguageFromHTTP_68 +@ cdecl -norelay uloc_addLikelySubtags() icuuc68.uloc_addLikelySubtags_68 +@ cdecl -norelay uloc_canonicalize() icuuc68.uloc_canonicalize_68 +@ cdecl -norelay uloc_countAvailable() icuuc68.uloc_countAvailable_68 +@ cdecl -norelay uloc_forLanguageTag() icuuc68.uloc_forLanguageTag_68 +@ cdecl -norelay uloc_getAvailable() icuuc68.uloc_getAvailable_68 +@ cdecl -norelay uloc_getBaseName() icuuc68.uloc_getBaseName_68 +@ cdecl -norelay uloc_getCharacterOrientation() icuuc68.uloc_getCharacterOrientation_68 +@ cdecl -norelay uloc_getCountry() icuuc68.uloc_getCountry_68 +@ cdecl -norelay uloc_getDefault() icuuc68.uloc_getDefault_68 +@ cdecl -norelay uloc_getDisplayCountry() icuuc68.uloc_getDisplayCountry_68 +@ cdecl -norelay uloc_getDisplayKeyword() icuuc68.uloc_getDisplayKeyword_68 +@ cdecl -norelay uloc_getDisplayKeywordValue() icuuc68.uloc_getDisplayKeywordValue_68 +@ cdecl -norelay uloc_getDisplayLanguage() icuuc68.uloc_getDisplayLanguage_68 +@ cdecl -norelay uloc_getDisplayName() icuuc68.uloc_getDisplayName_68 +@ cdecl -norelay uloc_getDisplayScript() icuuc68.uloc_getDisplayScript_68 +@ cdecl -norelay uloc_getDisplayVariant() icuuc68.uloc_getDisplayVariant_68 +@ cdecl -norelay uloc_getISO3Country() icuuc68.uloc_getISO3Country_68 +@ cdecl -norelay uloc_getISO3Language() icuuc68.uloc_getISO3Language_68 +@ cdecl -norelay uloc_getISOCountries() icuuc68.uloc_getISOCountries_68 +@ cdecl -norelay uloc_getISOLanguages() icuuc68.uloc_getISOLanguages_68 +@ cdecl -norelay uloc_getKeywordValue() icuuc68.uloc_getKeywordValue_68 +@ cdecl -norelay uloc_getLCID() icuuc68.uloc_getLCID_68 +@ cdecl -norelay uloc_getLanguage() icuuc68.uloc_getLanguage_68 +@ cdecl -norelay uloc_getLineOrientation() icuuc68.uloc_getLineOrientation_68 +@ cdecl -norelay uloc_getLocaleForLCID() icuuc68.uloc_getLocaleForLCID_68 +@ cdecl -norelay uloc_getName() icuuc68.uloc_getName_68 +@ cdecl -norelay uloc_getParent() icuuc68.uloc_getParent_68 +@ cdecl -norelay uloc_getScript() icuuc68.uloc_getScript_68 +@ cdecl -norelay uloc_getVariant() icuuc68.uloc_getVariant_68 +@ cdecl -norelay uloc_isRightToLeft() icuuc68.uloc_isRightToLeft_68 +@ cdecl -norelay uloc_minimizeSubtags() icuuc68.uloc_minimizeSubtags_68 +@ cdecl -norelay uloc_openAvailableByType() icuuc68.uloc_openAvailableByType_68 +@ cdecl -norelay uloc_openKeywords() icuuc68.uloc_openKeywords_68 +@ cdecl -norelay uloc_setDefault() icuuc68.uloc_setDefault_68 +@ cdecl -norelay uloc_setKeywordValue() icuuc68.uloc_setKeywordValue_68 +@ cdecl -norelay uloc_toLanguageTag() icuuc68.uloc_toLanguageTag_68 +@ cdecl -norelay uloc_toLegacyKey() icuuc68.uloc_toLegacyKey_68 +@ cdecl -norelay uloc_toLegacyType() icuuc68.uloc_toLegacyType_68 +@ cdecl -norelay uloc_toUnicodeLocaleKey() icuuc68.uloc_toUnicodeLocaleKey_68 +@ cdecl -norelay uloc_toUnicodeLocaleType() icuuc68.uloc_toUnicodeLocaleType_68 +@ cdecl -norelay ulocdata_close() icuin68.ulocdata_close_68 +@ cdecl -norelay ulocdata_getCLDRVersion() icuin68.ulocdata_getCLDRVersion_68 +@ cdecl -norelay ulocdata_getDelimiter() icuin68.ulocdata_getDelimiter_68 +@ cdecl -norelay ulocdata_getExemplarSet() icuin68.ulocdata_getExemplarSet_68 +@ cdecl -norelay ulocdata_getLocaleDisplayPattern() icuin68.ulocdata_getLocaleDisplayPattern_68 +@ cdecl -norelay ulocdata_getLocaleSeparator() icuin68.ulocdata_getLocaleSeparator_68 +@ cdecl -norelay ulocdata_getMeasurementSystem() icuin68.ulocdata_getMeasurementSystem_68 +@ cdecl -norelay ulocdata_getNoSubstitute() icuin68.ulocdata_getNoSubstitute_68 +@ cdecl -norelay ulocdata_getPaperSize() icuin68.ulocdata_getPaperSize_68 +@ cdecl -norelay ulocdata_open() icuin68.ulocdata_open_68 +@ cdecl -norelay ulocdata_setNoSubstitute() icuin68.ulocdata_setNoSubstitute_68 +@ cdecl -norelay umsg_applyPattern() icuin68.umsg_applyPattern_68 +@ cdecl -norelay umsg_autoQuoteApostrophe() icuin68.umsg_autoQuoteApostrophe_68 +@ cdecl -norelay umsg_clone() icuin68.umsg_clone_68 +@ cdecl -norelay umsg_close() icuin68.umsg_close_68 +@ cdecl -norelay umsg_format() icuin68.umsg_format_68 +@ cdecl -norelay umsg_getLocale() icuin68.umsg_getLocale_68 +@ cdecl -norelay umsg_open() icuin68.umsg_open_68 +@ cdecl -norelay umsg_parse() icuin68.umsg_parse_68 +@ cdecl -norelay umsg_setLocale() icuin68.umsg_setLocale_68 +@ cdecl -norelay umsg_toPattern() icuin68.umsg_toPattern_68 +@ cdecl -norelay umsg_vformat() icuin68.umsg_vformat_68 +@ cdecl -norelay umsg_vparse() icuin68.umsg_vparse_68 +@ cdecl -norelay umutablecptrie_buildImmutable() icuuc68.umutablecptrie_buildImmutable_68 +@ cdecl -norelay umutablecptrie_clone() icuuc68.umutablecptrie_clone_68 +@ cdecl -norelay umutablecptrie_close() icuuc68.umutablecptrie_close_68 +@ cdecl -norelay umutablecptrie_fromUCPMap() icuuc68.umutablecptrie_fromUCPMap_68 +@ cdecl -norelay umutablecptrie_fromUCPTrie() icuuc68.umutablecptrie_fromUCPTrie_68 +@ cdecl -norelay umutablecptrie_get() icuuc68.umutablecptrie_get_68 +@ cdecl -norelay umutablecptrie_getRange() icuuc68.umutablecptrie_getRange_68 +@ cdecl -norelay umutablecptrie_open() icuuc68.umutablecptrie_open_68 +@ cdecl -norelay umutablecptrie_set() icuuc68.umutablecptrie_set_68 +@ cdecl -norelay umutablecptrie_setRange() icuuc68.umutablecptrie_setRange_68 +@ cdecl -norelay unorm2_append() icuuc68.unorm2_append_68 +@ cdecl -norelay unorm2_close() icuuc68.unorm2_close_68 +@ cdecl -norelay unorm2_composePair() icuuc68.unorm2_composePair_68 +@ cdecl -norelay unorm2_getCombiningClass() icuuc68.unorm2_getCombiningClass_68 +@ cdecl -norelay unorm2_getDecomposition() icuuc68.unorm2_getDecomposition_68 +@ cdecl -norelay unorm2_getInstance() icuuc68.unorm2_getInstance_68 +@ cdecl -norelay unorm2_getNFCInstance() icuuc68.unorm2_getNFCInstance_68 +@ cdecl -norelay unorm2_getNFDInstance() icuuc68.unorm2_getNFDInstance_68 +@ cdecl -norelay unorm2_getNFKCCasefoldInstance() icuuc68.unorm2_getNFKCCasefoldInstance_68 +@ cdecl -norelay unorm2_getNFKCInstance() icuuc68.unorm2_getNFKCInstance_68 +@ cdecl -norelay unorm2_getNFKDInstance() icuuc68.unorm2_getNFKDInstance_68 +@ cdecl -norelay unorm2_getRawDecomposition() icuuc68.unorm2_getRawDecomposition_68 +@ cdecl -norelay unorm2_hasBoundaryAfter() icuuc68.unorm2_hasBoundaryAfter_68 +@ cdecl -norelay unorm2_hasBoundaryBefore() icuuc68.unorm2_hasBoundaryBefore_68 +@ cdecl -norelay unorm2_isInert() icuuc68.unorm2_isInert_68 +@ cdecl -norelay unorm2_isNormalized() icuuc68.unorm2_isNormalized_68 +@ cdecl -norelay unorm2_normalize() icuuc68.unorm2_normalize_68 +@ cdecl -norelay unorm2_normalizeSecondAndAppend() icuuc68.unorm2_normalizeSecondAndAppend_68 +@ cdecl -norelay unorm2_openFiltered() icuuc68.unorm2_openFiltered_68 +@ cdecl -norelay unorm2_quickCheck() icuuc68.unorm2_quickCheck_68 +@ cdecl -norelay unorm2_spanQuickCheckYes() icuuc68.unorm2_spanQuickCheckYes_68 +@ cdecl -norelay unorm_compare() icuuc68.unorm_compare_68 +@ cdecl -norelay unum_applyPattern() icuin68.unum_applyPattern_68 +@ cdecl -norelay unum_clone() icuin68.unum_clone_68 +@ cdecl -norelay unum_close() icuin68.unum_close_68 +@ cdecl -norelay unum_countAvailable() icuin68.unum_countAvailable_68 +@ cdecl -norelay unum_format() icuin68.unum_format_68 +@ cdecl -norelay unum_formatDecimal() icuin68.unum_formatDecimal_68 +@ cdecl -norelay unum_formatDouble() icuin68.unum_formatDouble_68 +@ cdecl -norelay unum_formatDoubleCurrency() icuin68.unum_formatDoubleCurrency_68 +@ cdecl -norelay unum_formatDoubleForFields() icuin68.unum_formatDoubleForFields_68 +@ cdecl -norelay unum_formatInt64() icuin68.unum_formatInt64_68 +@ cdecl -norelay unum_formatUFormattable() icuin68.unum_formatUFormattable_68 +@ cdecl -norelay unum_getAttribute() icuin68.unum_getAttribute_68 +@ cdecl -norelay unum_getAvailable() icuin68.unum_getAvailable_68 +@ cdecl -norelay unum_getContext() icuin68.unum_getContext_68 +@ cdecl -norelay unum_getDoubleAttribute() icuin68.unum_getDoubleAttribute_68 +@ cdecl -norelay unum_getLocaleByType() icuin68.unum_getLocaleByType_68 +@ cdecl -norelay unum_getSymbol() icuin68.unum_getSymbol_68 +@ cdecl -norelay unum_getTextAttribute() icuin68.unum_getTextAttribute_68 +@ cdecl -norelay unum_open() icuin68.unum_open_68 +@ cdecl -norelay unum_parse() icuin68.unum_parse_68 +@ cdecl -norelay unum_parseDecimal() icuin68.unum_parseDecimal_68 +@ cdecl -norelay unum_parseDouble() icuin68.unum_parseDouble_68 +@ cdecl -norelay unum_parseDoubleCurrency() icuin68.unum_parseDoubleCurrency_68 +@ cdecl -norelay unum_parseInt64() icuin68.unum_parseInt64_68 +@ cdecl -norelay unum_parseToUFormattable() icuin68.unum_parseToUFormattable_68 +@ cdecl -norelay unum_setAttribute() icuin68.unum_setAttribute_68 +@ cdecl -norelay unum_setContext() icuin68.unum_setContext_68 +@ cdecl -norelay unum_setDoubleAttribute() icuin68.unum_setDoubleAttribute_68 +@ cdecl -norelay unum_setSymbol() icuin68.unum_setSymbol_68 +@ cdecl -norelay unum_setTextAttribute() icuin68.unum_setTextAttribute_68 +@ cdecl -norelay unum_toPattern() icuin68.unum_toPattern_68 +@ cdecl -norelay unumf_close() icuin68.unumf_close_68 +@ cdecl -norelay unumf_closeResult() icuin68.unumf_closeResult_68 +@ cdecl -norelay unumf_formatDecimal() icuin68.unumf_formatDecimal_68 +@ cdecl -norelay unumf_formatDouble() icuin68.unumf_formatDouble_68 +@ cdecl -norelay unumf_formatInt() icuin68.unumf_formatInt_68 +@ cdecl -norelay unumf_openForSkeletonAndLocale() icuin68.unumf_openForSkeletonAndLocale_68 +@ cdecl -norelay unumf_openForSkeletonAndLocaleWithError() icuin68.unumf_openForSkeletonAndLocaleWithError_68 +@ cdecl -norelay unumf_openResult() icuin68.unumf_openResult_68 +@ cdecl -norelay unumf_resultAsValue() icuin68.unumf_resultAsValue_68 +@ cdecl -norelay unumf_resultGetAllFieldPositions() icuin68.unumf_resultGetAllFieldPositions_68 +@ cdecl -norelay unumf_resultNextFieldPosition() icuin68.unumf_resultNextFieldPosition_68 +@ cdecl -norelay unumf_resultToString() icuin68.unumf_resultToString_68 +@ cdecl -norelay unumsys_close() icuin68.unumsys_close_68 +@ cdecl -norelay unumsys_getDescription() icuin68.unumsys_getDescription_68 +@ cdecl -norelay unumsys_getName() icuin68.unumsys_getName_68 +@ cdecl -norelay unumsys_getRadix() icuin68.unumsys_getRadix_68 +@ cdecl -norelay unumsys_isAlgorithmic() icuin68.unumsys_isAlgorithmic_68 +@ cdecl -norelay unumsys_open() icuin68.unumsys_open_68 +@ cdecl -norelay unumsys_openAvailableNames() icuin68.unumsys_openAvailableNames_68 +@ cdecl -norelay unumsys_openByName() icuin68.unumsys_openByName_68 +@ cdecl -norelay uplrules_close() icuin68.uplrules_close_68 +@ cdecl -norelay uplrules_getKeywords() icuin68.uplrules_getKeywords_68 +@ cdecl -norelay uplrules_open() icuin68.uplrules_open_68 +@ cdecl -norelay uplrules_openForType() icuin68.uplrules_openForType_68 +@ cdecl -norelay uplrules_select() icuin68.uplrules_select_68 +@ cdecl -norelay uplrules_selectFormatted() icuin68.uplrules_selectFormatted_68 +@ cdecl -norelay uregex_appendReplacement() icuin68.uregex_appendReplacement_68 +@ cdecl -norelay uregex_appendReplacementUText() icuin68.uregex_appendReplacementUText_68 +@ cdecl -norelay uregex_appendTail() icuin68.uregex_appendTail_68 +@ cdecl -norelay uregex_appendTailUText() icuin68.uregex_appendTailUText_68 +@ cdecl -norelay uregex_clone() icuin68.uregex_clone_68 +@ cdecl -norelay uregex_close() icuin68.uregex_close_68 +@ cdecl -norelay uregex_end() icuin68.uregex_end_68 +@ cdecl -norelay uregex_end64() icuin68.uregex_end64_68 +@ cdecl -norelay uregex_find() icuin68.uregex_find_68 +@ cdecl -norelay uregex_find64() icuin68.uregex_find64_68 +@ cdecl -norelay uregex_findNext() icuin68.uregex_findNext_68 +@ cdecl -norelay uregex_flags() icuin68.uregex_flags_68 +@ cdecl -norelay uregex_getFindProgressCallback() icuin68.uregex_getFindProgressCallback_68 +@ cdecl -norelay uregex_getMatchCallback() icuin68.uregex_getMatchCallback_68 +@ cdecl -norelay uregex_getStackLimit() icuin68.uregex_getStackLimit_68 +@ cdecl -norelay uregex_getText() icuin68.uregex_getText_68 +@ cdecl -norelay uregex_getTimeLimit() icuin68.uregex_getTimeLimit_68 +@ cdecl -norelay uregex_getUText() icuin68.uregex_getUText_68 +@ cdecl -norelay uregex_group() icuin68.uregex_group_68 +@ cdecl -norelay uregex_groupCount() icuin68.uregex_groupCount_68 +@ cdecl -norelay uregex_groupNumberFromCName() icuin68.uregex_groupNumberFromCName_68 +@ cdecl -norelay uregex_groupNumberFromName() icuin68.uregex_groupNumberFromName_68 +@ cdecl -norelay uregex_groupUText() icuin68.uregex_groupUText_68 +@ cdecl -norelay uregex_hasAnchoringBounds() icuin68.uregex_hasAnchoringBounds_68 +@ cdecl -norelay uregex_hasTransparentBounds() icuin68.uregex_hasTransparentBounds_68 +@ cdecl -norelay uregex_hitEnd() icuin68.uregex_hitEnd_68 +@ cdecl -norelay uregex_lookingAt() icuin68.uregex_lookingAt_68 +@ cdecl -norelay uregex_lookingAt64() icuin68.uregex_lookingAt64_68 +@ cdecl -norelay uregex_matches() icuin68.uregex_matches_68 +@ cdecl -norelay uregex_matches64() icuin68.uregex_matches64_68 +@ cdecl -norelay uregex_open() icuin68.uregex_open_68 +@ cdecl -norelay uregex_openC() icuin68.uregex_openC_68 +@ cdecl -norelay uregex_openUText() icuin68.uregex_openUText_68 +@ cdecl -norelay uregex_pattern() icuin68.uregex_pattern_68 +@ cdecl -norelay uregex_patternUText() icuin68.uregex_patternUText_68 +@ cdecl -norelay uregex_refreshUText() icuin68.uregex_refreshUText_68 +@ cdecl -norelay uregex_regionEnd() icuin68.uregex_regionEnd_68 +@ cdecl -norelay uregex_regionEnd64() icuin68.uregex_regionEnd64_68 +@ cdecl -norelay uregex_regionStart() icuin68.uregex_regionStart_68 +@ cdecl -norelay uregex_regionStart64() icuin68.uregex_regionStart64_68 +@ cdecl -norelay uregex_replaceAll() icuin68.uregex_replaceAll_68 +@ cdecl -norelay uregex_replaceAllUText() icuin68.uregex_replaceAllUText_68 +@ cdecl -norelay uregex_replaceFirst() icuin68.uregex_replaceFirst_68 +@ cdecl -norelay uregex_replaceFirstUText() icuin68.uregex_replaceFirstUText_68 +@ cdecl -norelay uregex_requireEnd() icuin68.uregex_requireEnd_68 +@ cdecl -norelay uregex_reset() icuin68.uregex_reset_68 +@ cdecl -norelay uregex_reset64() icuin68.uregex_reset64_68 +@ cdecl -norelay uregex_setFindProgressCallback() icuin68.uregex_setFindProgressCallback_68 +@ cdecl -norelay uregex_setMatchCallback() icuin68.uregex_setMatchCallback_68 +@ cdecl -norelay uregex_setRegion() icuin68.uregex_setRegion_68 +@ cdecl -norelay uregex_setRegion64() icuin68.uregex_setRegion64_68 +@ cdecl -norelay uregex_setRegionAndStart() icuin68.uregex_setRegionAndStart_68 +@ cdecl -norelay uregex_setStackLimit() icuin68.uregex_setStackLimit_68 +@ cdecl -norelay uregex_setText() icuin68.uregex_setText_68 +@ cdecl -norelay uregex_setTimeLimit() icuin68.uregex_setTimeLimit_68 +@ cdecl -norelay uregex_setUText() icuin68.uregex_setUText_68 +@ cdecl -norelay uregex_split() icuin68.uregex_split_68 +@ cdecl -norelay uregex_splitUText() icuin68.uregex_splitUText_68 +@ cdecl -norelay uregex_start() icuin68.uregex_start_68 +@ cdecl -norelay uregex_start64() icuin68.uregex_start64_68 +@ cdecl -norelay uregex_useAnchoringBounds() icuin68.uregex_useAnchoringBounds_68 +@ cdecl -norelay uregex_useTransparentBounds() icuin68.uregex_useTransparentBounds_68 +@ cdecl -norelay uregion_areEqual() icuin68.uregion_areEqual_68 +@ cdecl -norelay uregion_contains() icuin68.uregion_contains_68 +@ cdecl -norelay uregion_getAvailable() icuin68.uregion_getAvailable_68 +@ cdecl -norelay uregion_getContainedRegions() icuin68.uregion_getContainedRegions_68 +@ cdecl -norelay uregion_getContainedRegionsOfType() icuin68.uregion_getContainedRegionsOfType_68 +@ cdecl -norelay uregion_getContainingRegion() icuin68.uregion_getContainingRegion_68 +@ cdecl -norelay uregion_getContainingRegionOfType() icuin68.uregion_getContainingRegionOfType_68 +@ cdecl -norelay uregion_getNumericCode() icuin68.uregion_getNumericCode_68 +@ cdecl -norelay uregion_getPreferredValues() icuin68.uregion_getPreferredValues_68 +@ cdecl -norelay uregion_getRegionCode() icuin68.uregion_getRegionCode_68 +@ cdecl -norelay uregion_getRegionFromCode() icuin68.uregion_getRegionFromCode_68 +@ cdecl -norelay uregion_getRegionFromNumericCode() icuin68.uregion_getRegionFromNumericCode_68 +@ cdecl -norelay uregion_getType() icuin68.uregion_getType_68 +@ cdecl -norelay ureldatefmt_close() icuin68.ureldatefmt_close_68 +@ cdecl -norelay ureldatefmt_closeResult() icuin68.ureldatefmt_closeResult_68 +@ cdecl -norelay ureldatefmt_combineDateAndTime() icuin68.ureldatefmt_combineDateAndTime_68 +@ cdecl -norelay ureldatefmt_format() icuin68.ureldatefmt_format_68 +@ cdecl -norelay ureldatefmt_formatNumeric() icuin68.ureldatefmt_formatNumeric_68 +@ cdecl -norelay ureldatefmt_formatNumericToResult() icuin68.ureldatefmt_formatNumericToResult_68 +@ cdecl -norelay ureldatefmt_formatToResult() icuin68.ureldatefmt_formatToResult_68 +@ cdecl -norelay ureldatefmt_open() icuin68.ureldatefmt_open_68 +@ cdecl -norelay ureldatefmt_openResult() icuin68.ureldatefmt_openResult_68 +@ cdecl -norelay ureldatefmt_resultAsValue() icuin68.ureldatefmt_resultAsValue_68 +@ cdecl -norelay ures_close() icuuc68.ures_close_68 +@ cdecl -norelay ures_getBinary() icuuc68.ures_getBinary_68 +@ cdecl -norelay ures_getByIndex() icuuc68.ures_getByIndex_68 +@ cdecl -norelay ures_getByKey() icuuc68.ures_getByKey_68 +@ cdecl -norelay ures_getInt() icuuc68.ures_getInt_68 +@ cdecl -norelay ures_getIntVector() icuuc68.ures_getIntVector_68 +@ cdecl -norelay ures_getKey() icuuc68.ures_getKey_68 +@ cdecl -norelay ures_getLocaleByType() icuuc68.ures_getLocaleByType_68 +@ cdecl -norelay ures_getNextResource() icuuc68.ures_getNextResource_68 +@ cdecl -norelay ures_getNextString() icuuc68.ures_getNextString_68 +@ cdecl -norelay ures_getSize() icuuc68.ures_getSize_68 +@ cdecl -norelay ures_getString() icuuc68.ures_getString_68 +@ cdecl -norelay ures_getStringByIndex() icuuc68.ures_getStringByIndex_68 +@ cdecl -norelay ures_getStringByKey() icuuc68.ures_getStringByKey_68 +@ cdecl -norelay ures_getType() icuuc68.ures_getType_68 +@ cdecl -norelay ures_getUInt() icuuc68.ures_getUInt_68 +@ cdecl -norelay ures_getUTF8String() icuuc68.ures_getUTF8String_68 +@ cdecl -norelay ures_getUTF8StringByIndex() icuuc68.ures_getUTF8StringByIndex_68 +@ cdecl -norelay ures_getUTF8StringByKey() icuuc68.ures_getUTF8StringByKey_68 +@ cdecl -norelay ures_getVersion() icuuc68.ures_getVersion_68 +@ cdecl -norelay ures_hasNext() icuuc68.ures_hasNext_68 +@ cdecl -norelay ures_open() icuuc68.ures_open_68 +@ cdecl -norelay ures_openAvailableLocales() icuuc68.ures_openAvailableLocales_68 +@ cdecl -norelay ures_openDirect() icuuc68.ures_openDirect_68 +@ cdecl -norelay ures_openU() icuuc68.ures_openU_68 +@ cdecl -norelay ures_resetIterator() icuuc68.ures_resetIterator_68 +@ cdecl -norelay uscript_breaksBetweenLetters() icuuc68.uscript_breaksBetweenLetters_68 +@ cdecl -norelay uscript_getCode() icuuc68.uscript_getCode_68 +@ cdecl -norelay uscript_getName() icuuc68.uscript_getName_68 +@ cdecl -norelay uscript_getSampleString() icuuc68.uscript_getSampleString_68 +@ cdecl -norelay uscript_getScript() icuuc68.uscript_getScript_68 +@ cdecl -norelay uscript_getScriptExtensions() icuuc68.uscript_getScriptExtensions_68 +@ cdecl -norelay uscript_getShortName() icuuc68.uscript_getShortName_68 +@ cdecl -norelay uscript_getUsage() icuuc68.uscript_getUsage_68 +@ cdecl -norelay uscript_hasScript() icuuc68.uscript_hasScript_68 +@ cdecl -norelay uscript_isCased() icuuc68.uscript_isCased_68 +@ cdecl -norelay uscript_isRightToLeft() icuuc68.uscript_isRightToLeft_68 +@ cdecl -norelay usearch_close() icuin68.usearch_close_68 +@ cdecl -norelay usearch_first() icuin68.usearch_first_68 +@ cdecl -norelay usearch_following() icuin68.usearch_following_68 +@ cdecl -norelay usearch_getAttribute() icuin68.usearch_getAttribute_68 +@ cdecl -norelay usearch_getBreakIterator() icuin68.usearch_getBreakIterator_68 +@ cdecl -norelay usearch_getCollator() icuin68.usearch_getCollator_68 +@ cdecl -norelay usearch_getMatchedLength() icuin68.usearch_getMatchedLength_68 +@ cdecl -norelay usearch_getMatchedStart() icuin68.usearch_getMatchedStart_68 +@ cdecl -norelay usearch_getMatchedText() icuin68.usearch_getMatchedText_68 +@ cdecl -norelay usearch_getOffset() icuin68.usearch_getOffset_68 +@ cdecl -norelay usearch_getPattern() icuin68.usearch_getPattern_68 +@ cdecl -norelay usearch_getText() icuin68.usearch_getText_68 +@ cdecl -norelay usearch_last() icuin68.usearch_last_68 +@ cdecl -norelay usearch_next() icuin68.usearch_next_68 +@ cdecl -norelay usearch_open() icuin68.usearch_open_68 +@ cdecl -norelay usearch_openFromCollator() icuin68.usearch_openFromCollator_68 +@ cdecl -norelay usearch_preceding() icuin68.usearch_preceding_68 +@ cdecl -norelay usearch_previous() icuin68.usearch_previous_68 +@ cdecl -norelay usearch_reset() icuin68.usearch_reset_68 +@ cdecl -norelay usearch_setAttribute() icuin68.usearch_setAttribute_68 +@ cdecl -norelay usearch_setBreakIterator() icuin68.usearch_setBreakIterator_68 +@ cdecl -norelay usearch_setCollator() icuin68.usearch_setCollator_68 +@ cdecl -norelay usearch_setOffset() icuin68.usearch_setOffset_68 +@ cdecl -norelay usearch_setPattern() icuin68.usearch_setPattern_68 +@ cdecl -norelay usearch_setText() icuin68.usearch_setText_68 +@ cdecl -norelay uset_add() icuuc68.uset_add_68 +@ cdecl -norelay uset_addAll() icuuc68.uset_addAll_68 +@ cdecl -norelay uset_addAllCodePoints() icuuc68.uset_addAllCodePoints_68 +@ cdecl -norelay uset_addRange() icuuc68.uset_addRange_68 +@ cdecl -norelay uset_addString() icuuc68.uset_addString_68 +@ cdecl -norelay uset_applyIntPropertyValue() icuuc68.uset_applyIntPropertyValue_68 +@ cdecl -norelay uset_applyPattern() icuuc68.uset_applyPattern_68 +@ cdecl -norelay uset_applyPropertyAlias() icuuc68.uset_applyPropertyAlias_68 +@ cdecl -norelay uset_charAt() icuuc68.uset_charAt_68 +@ cdecl -norelay uset_clear() icuuc68.uset_clear_68 +@ cdecl -norelay uset_clone() icuuc68.uset_clone_68 +@ cdecl -norelay uset_cloneAsThawed() icuuc68.uset_cloneAsThawed_68 +@ cdecl -norelay uset_close() icuuc68.uset_close_68 +@ cdecl -norelay uset_closeOver() icuuc68.uset_closeOver_68 +@ cdecl -norelay uset_compact() icuuc68.uset_compact_68 +@ cdecl -norelay uset_complement() icuuc68.uset_complement_68 +@ cdecl -norelay uset_complementAll() icuuc68.uset_complementAll_68 +@ cdecl -norelay uset_contains() icuuc68.uset_contains_68 +@ cdecl -norelay uset_containsAll() icuuc68.uset_containsAll_68 +@ cdecl -norelay uset_containsAllCodePoints() icuuc68.uset_containsAllCodePoints_68 +@ cdecl -norelay uset_containsNone() icuuc68.uset_containsNone_68 +@ cdecl -norelay uset_containsRange() icuuc68.uset_containsRange_68 +@ cdecl -norelay uset_containsSome() icuuc68.uset_containsSome_68 +@ cdecl -norelay uset_containsString() icuuc68.uset_containsString_68 +@ cdecl -norelay uset_equals() icuuc68.uset_equals_68 +@ cdecl -norelay uset_freeze() icuuc68.uset_freeze_68 +@ cdecl -norelay uset_getItem() icuuc68.uset_getItem_68 +@ cdecl -norelay uset_getItemCount() icuuc68.uset_getItemCount_68 +@ cdecl -norelay uset_getSerializedRange() icuuc68.uset_getSerializedRange_68 +@ cdecl -norelay uset_getSerializedRangeCount() icuuc68.uset_getSerializedRangeCount_68 +@ cdecl -norelay uset_getSerializedSet() icuuc68.uset_getSerializedSet_68 +@ cdecl -norelay uset_indexOf() icuuc68.uset_indexOf_68 +@ cdecl -norelay uset_isEmpty() icuuc68.uset_isEmpty_68 +@ cdecl -norelay uset_isFrozen() icuuc68.uset_isFrozen_68 +@ cdecl -norelay uset_open() icuuc68.uset_open_68 +@ cdecl -norelay uset_openEmpty() icuuc68.uset_openEmpty_68 +@ cdecl -norelay uset_openPattern() icuuc68.uset_openPattern_68 +@ cdecl -norelay uset_openPatternOptions() icuuc68.uset_openPatternOptions_68 +@ cdecl -norelay uset_remove() icuuc68.uset_remove_68 +@ cdecl -norelay uset_removeAll() icuuc68.uset_removeAll_68 +@ cdecl -norelay uset_removeAllStrings() icuuc68.uset_removeAllStrings_68 +@ cdecl -norelay uset_removeRange() icuuc68.uset_removeRange_68 +@ cdecl -norelay uset_removeString() icuuc68.uset_removeString_68 +@ cdecl -norelay uset_resemblesPattern() icuuc68.uset_resemblesPattern_68 +@ cdecl -norelay uset_retain() icuuc68.uset_retain_68 +@ cdecl -norelay uset_retainAll() icuuc68.uset_retainAll_68 +@ cdecl -norelay uset_serialize() icuuc68.uset_serialize_68 +@ cdecl -norelay uset_serializedContains() icuuc68.uset_serializedContains_68 +@ cdecl -norelay uset_set() icuuc68.uset_set_68 +@ cdecl -norelay uset_setSerializedToOne() icuuc68.uset_setSerializedToOne_68 +@ cdecl -norelay uset_size() icuuc68.uset_size_68 +@ cdecl -norelay uset_span() icuuc68.uset_span_68 +@ cdecl -norelay uset_spanBack() icuuc68.uset_spanBack_68 +@ cdecl -norelay uset_spanBackUTF8() icuuc68.uset_spanBackUTF8_68 +@ cdecl -norelay uset_spanUTF8() icuuc68.uset_spanUTF8_68 +@ cdecl -norelay uset_toPattern() icuuc68.uset_toPattern_68 +@ cdecl -norelay uspoof_areConfusable() icuin68.uspoof_areConfusable_68 +@ cdecl -norelay uspoof_areConfusableUTF8() icuin68.uspoof_areConfusableUTF8_68 +@ cdecl -norelay uspoof_check() icuin68.uspoof_check_68 +@ cdecl -norelay uspoof_check2() icuin68.uspoof_check2_68 +@ cdecl -norelay uspoof_check2UTF8() icuin68.uspoof_check2UTF8_68 +@ cdecl -norelay uspoof_checkUTF8() icuin68.uspoof_checkUTF8_68 +@ cdecl -norelay uspoof_clone() icuin68.uspoof_clone_68 +@ cdecl -norelay uspoof_close() icuin68.uspoof_close_68 +@ cdecl -norelay uspoof_closeCheckResult() icuin68.uspoof_closeCheckResult_68 +@ cdecl -norelay uspoof_getAllowedChars() icuin68.uspoof_getAllowedChars_68 +@ cdecl -norelay uspoof_getAllowedLocales() icuin68.uspoof_getAllowedLocales_68 +@ cdecl -norelay uspoof_getCheckResultChecks() icuin68.uspoof_getCheckResultChecks_68 +@ cdecl -norelay uspoof_getCheckResultNumerics() icuin68.uspoof_getCheckResultNumerics_68 +@ cdecl -norelay uspoof_getCheckResultRestrictionLevel() icuin68.uspoof_getCheckResultRestrictionLevel_68 +@ cdecl -norelay uspoof_getChecks() icuin68.uspoof_getChecks_68 +@ cdecl -norelay uspoof_getInclusionSet() icuin68.uspoof_getInclusionSet_68 +@ cdecl -norelay uspoof_getRecommendedSet() icuin68.uspoof_getRecommendedSet_68 +@ cdecl -norelay uspoof_getRestrictionLevel() icuin68.uspoof_getRestrictionLevel_68 +@ cdecl -norelay uspoof_getSkeleton() icuin68.uspoof_getSkeleton_68 +@ cdecl -norelay uspoof_getSkeletonUTF8() icuin68.uspoof_getSkeletonUTF8_68 +@ cdecl -norelay uspoof_open() icuin68.uspoof_open_68 +@ cdecl -norelay uspoof_openCheckResult() icuin68.uspoof_openCheckResult_68 +@ cdecl -norelay uspoof_openFromSerialized() icuin68.uspoof_openFromSerialized_68 +@ cdecl -norelay uspoof_openFromSource() icuin68.uspoof_openFromSource_68 +@ cdecl -norelay uspoof_serialize() icuin68.uspoof_serialize_68 +@ cdecl -norelay uspoof_setAllowedChars() icuin68.uspoof_setAllowedChars_68 +@ cdecl -norelay uspoof_setAllowedLocales() icuin68.uspoof_setAllowedLocales_68 +@ cdecl -norelay uspoof_setChecks() icuin68.uspoof_setChecks_68 +@ cdecl -norelay uspoof_setRestrictionLevel() icuin68.uspoof_setRestrictionLevel_68 +@ cdecl -norelay usprep_close() icuuc68.usprep_close_68 +@ cdecl -norelay usprep_open() icuuc68.usprep_open_68 +@ cdecl -norelay usprep_openByType() icuuc68.usprep_openByType_68 +@ cdecl -norelay usprep_prepare() icuuc68.usprep_prepare_68 +@ cdecl -norelay utext_char32At() icuuc68.utext_char32At_68 +@ cdecl -norelay utext_clone() icuuc68.utext_clone_68 +@ cdecl -norelay utext_close() icuuc68.utext_close_68 +@ cdecl -norelay utext_copy() icuuc68.utext_copy_68 +@ cdecl -norelay utext_current32() icuuc68.utext_current32_68 +@ cdecl -norelay utext_equals() icuuc68.utext_equals_68 +@ cdecl -norelay utext_extract() icuuc68.utext_extract_68 +@ cdecl -norelay utext_freeze() icuuc68.utext_freeze_68 +@ cdecl -norelay utext_getNativeIndex() icuuc68.utext_getNativeIndex_68 +@ cdecl -norelay utext_getPreviousNativeIndex() icuuc68.utext_getPreviousNativeIndex_68 +@ cdecl -norelay utext_hasMetaData() icuuc68.utext_hasMetaData_68 +@ cdecl -norelay utext_isLengthExpensive() icuuc68.utext_isLengthExpensive_68 +@ cdecl -norelay utext_isWritable() icuuc68.utext_isWritable_68 +@ cdecl -norelay utext_moveIndex32() icuuc68.utext_moveIndex32_68 +@ cdecl -norelay utext_nativeLength() icuuc68.utext_nativeLength_68 +@ cdecl -norelay utext_next32() icuuc68.utext_next32_68 +@ cdecl -norelay utext_next32From() icuuc68.utext_next32From_68 +@ cdecl -norelay utext_openUChars() icuuc68.utext_openUChars_68 +@ cdecl -norelay utext_openUTF8() icuuc68.utext_openUTF8_68 +@ cdecl -norelay utext_previous32() icuuc68.utext_previous32_68 +@ cdecl -norelay utext_previous32From() icuuc68.utext_previous32From_68 +@ cdecl -norelay utext_replace() icuuc68.utext_replace_68 +@ cdecl -norelay utext_setNativeIndex() icuuc68.utext_setNativeIndex_68 +@ cdecl -norelay utext_setup() icuuc68.utext_setup_68 +@ cdecl -norelay utf8_appendCharSafeBody() icuuc68.utf8_appendCharSafeBody_68 +@ cdecl -norelay utf8_back1SafeBody() icuuc68.utf8_back1SafeBody_68 +@ cdecl -norelay utf8_nextCharSafeBody() icuuc68.utf8_nextCharSafeBody_68 +@ cdecl -norelay utf8_prevCharSafeBody() icuuc68.utf8_prevCharSafeBody_68 +@ cdecl -norelay utmscale_fromInt64() icuin68.utmscale_fromInt64_68 +@ cdecl -norelay utmscale_getTimeScaleValue() icuin68.utmscale_getTimeScaleValue_68 +@ cdecl -norelay utmscale_toInt64() icuin68.utmscale_toInt64_68 +@ cdecl -norelay utrace_format() icuuc68.utrace_format_68 +@ cdecl -norelay utrace_functionName() icuuc68.utrace_functionName_68 +@ cdecl -norelay utrace_getFunctions() icuuc68.utrace_getFunctions_68 +@ cdecl -norelay utrace_getLevel() icuuc68.utrace_getLevel_68 +@ cdecl -norelay utrace_setFunctions() icuuc68.utrace_setFunctions_68 +@ cdecl -norelay utrace_setLevel() icuuc68.utrace_setLevel_68 +@ cdecl -norelay utrace_vformat() icuuc68.utrace_vformat_68 +@ cdecl -norelay utrans_clone() icuin68.utrans_clone_68 +@ cdecl -norelay utrans_close() icuin68.utrans_close_68 +@ cdecl -norelay utrans_countAvailableIDs() icuin68.utrans_countAvailableIDs_68 +@ cdecl -norelay utrans_getSourceSet() icuin68.utrans_getSourceSet_68 +@ cdecl -norelay utrans_getUnicodeID() icuin68.utrans_getUnicodeID_68 +@ cdecl -norelay utrans_openIDs() icuin68.utrans_openIDs_68 +@ cdecl -norelay utrans_openInverse() icuin68.utrans_openInverse_68 +@ cdecl -norelay utrans_openU() icuin68.utrans_openU_68 +@ cdecl -norelay utrans_register() icuin68.utrans_register_68 +@ cdecl -norelay utrans_setFilter() icuin68.utrans_setFilter_68 +@ cdecl -norelay utrans_toRules() icuin68.utrans_toRules_68 +@ cdecl -norelay utrans_trans() icuin68.utrans_trans_68 +@ cdecl -norelay utrans_transIncremental() icuin68.utrans_transIncremental_68 +@ cdecl -norelay utrans_transIncrementalUChars() icuin68.utrans_transIncrementalUChars_68 +@ cdecl -norelay utrans_transUChars() icuin68.utrans_transUChars_68 +@ cdecl -norelay utrans_unregisterID() icuin68.utrans_unregisterID_68 diff --git a/dlls/ieframe/navigate.c b/dlls/ieframe/navigate.c index 48cd59979396..ad175537ccef 100644 --- a/dlls/ieframe/navigate.c +++ b/dlls/ieframe/navigate.c @@ -851,6 +851,31 @@ static void doc_navigate_proc(DocHost *This, task_header_t *t) } } +static void hack_pump_messages(void) +{ + static int enabled = -1; + MSG msg; + + if (enabled == -1) + { + const char *sgi = getenv("SteamGameId"); + + enabled = sgi && !strcmp(sgi, "2767030"); + if (enabled) + ERR("HACK: injecting PeekMessage loop in async_doc_navigate.\n"); + } + + if (!enabled) + return; + + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + TRACE("dispatching.\n"); + DispatchMessageW(&msg); + } + TRACE("no more messages.\n"); +} + static HRESULT async_doc_navigate(DocHost *This, LPCWSTR url, LPCWSTR headers, PBYTE post_data, ULONG post_data_size, BOOL async_notif) { @@ -899,6 +924,7 @@ static HRESULT async_doc_navigate(DocHost *This, LPCWSTR url, LPCWSTR headers, P task->async_notif = async_notif; abort_dochost_tasks(This, doc_navigate_proc); + hack_pump_messages(); push_dochost_task(This, &task->header, doc_navigate_proc, doc_navigate_task_destr, FALSE); return S_OK; } diff --git a/dlls/ieframe/tests/webbrowser.c b/dlls/ieframe/tests/webbrowser.c index 521b18bb599a..e3e35f7b0899 100644 --- a/dlls/ieframe/tests/webbrowser.c +++ b/dlls/ieframe/tests/webbrowser.c @@ -172,6 +172,7 @@ static HRESULT hr_site_TranslateAccelerator = E_NOTIMPL; static const WCHAR *current_url; static int wb_version, expect_update_commands_enable, set_update_commands_enable; static BOOL nav_back_todo, nav_forward_todo; /* FIXME */ +static BOOL navigation_cancelled; enum SessionOp { @@ -191,6 +192,8 @@ static LONG (WINAPI *pSetQueryNetSessionCount)(DWORD); #define DWL_HTTP 0x10 #define DWL_REFRESH 0x20 #define DWL_BACK_ENABLE 0x40 +#define DWL_IFRAME_NAV_CANCEL 0x80 +#define DWL_FROM_IFRAME_NAV_CANCEL 0x100 static DWORD dwl_flags; @@ -290,6 +293,8 @@ static void _test_ready_state(unsigned line, READYSTATE exstate, VARIANT_BOOL ex hres = IWebBrowser2_get_Busy(wb, &busy); if(expect_busy != BUSY_FAIL) { ok_(__FILE__,line)(hres == S_OK, "get_ReadyState failed: %08lx\n", hres); + todo_wine_if(dwl_flags & DWL_FROM_IFRAME_NAV_CANCEL && state == READYSTATE_LOADING + && busy != expect_busy) ok_(__FILE__,line)(busy == expect_busy, "Busy = %x, expected %x for ready state %d\n", busy, expect_busy, state); }else { @@ -415,13 +420,13 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID ok(nCmdexecopt == OLECMDEXECOPT_DONTPROMPTUSER || !nCmdexecopt, "nCmdexecopts=%08lx\n", nCmdexecopt); else - ok(!nCmdexecopt, "nCmdexecopts=%08lx\n", nCmdexecopt); + todo_wine_if(dwl_flags & DWL_IFRAME_NAV_CANCEL) ok(!nCmdexecopt, "nCmdexecopts=%08lx\n", nCmdexecopt); ok(pvaOut == NULL, "pvaOut=%p\n", pvaOut); ok(pvaIn != NULL, "pvaIn == NULL\n"); ok(V_VT(pvaIn) == VT_I4, "V_VT(pvaIn)=%d\n", V_VT(pvaIn)); switch(V_I4(pvaIn)) { case 0: - CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_0); + todo_wine_if(dwl_flags & DWL_IFRAME_NAV_CANCEL) CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_0); break; case 1: CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_1); @@ -480,6 +485,7 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) { switch(nCmdID) { case 63: /* win10 */ + case 65: case 105: /* TODO */ case 132: /* win10 */ case 133: /* IE11 */ @@ -719,11 +725,11 @@ static void _test_invoke_bool(unsigned line, const DISPPARAMS *params, BOOL stri static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const VARIANT *flags, const VARIANT *frame, const VARIANT *post_data, const VARIANT *headers, const VARIANT *cancel) { + BOOL cancel_nav = FALSE; BSTR str; ok(V_VT(disp) == VT_DISPATCH, "V_VT(disp)=%d, expected VT_DISPATCH\n", V_VT(disp)); ok(V_DISPATCH(disp) != NULL, "V_DISPATCH(disp) == NULL\n"); - ok(V_DISPATCH(disp) == (IDispatch*)wb, "V_DISPATCH(disp)=%p, wb=%p\n", V_DISPATCH(disp), wb); ok(V_VT(url) == (VT_BYREF|VT_VARIANT), "V_VT(url)=%x, expected VT_BYREF|VT_VARIANT\n", V_VT(url)); ok(V_VARIANTREF(url) != NULL, "V_VARIANTREF(url) == NULL)\n"); @@ -731,10 +737,21 @@ static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const ok(V_VT(V_VARIANTREF(url)) == VT_BSTR, "V_VT(V_VARIANTREF(url))=%d, expected VT_BSTR\n", V_VT(V_VARIANTREF(url))); ok(V_BSTR(V_VARIANTREF(url)) != NULL, "V_BSTR(V_VARIANTREF(url)) == NULL\n"); - ok(!lstrcmpW(V_BSTR(V_VARIANTREF(url)), current_url), "unexpected url %s, expected %s\n", - wine_dbgstr_w(V_BSTR(V_VARIANTREF(url))), wine_dbgstr_w(current_url)); + if (!wcscmp(V_BSTR(V_VARIANTREF(url)), L"invalid:///")) + cancel_nav = TRUE; + if (!(dwl_flags & DWL_IFRAME_NAV_CANCEL && cancel_nav)) + ok(!lstrcmpW(V_BSTR(V_VARIANTREF(url)), current_url), "unexpected url %s, expected %s\n", + wine_dbgstr_w(V_BSTR(V_VARIANTREF(url))), wine_dbgstr_w(current_url)); } + if (dwl_flags & DWL_IFRAME_NAV_CANCEL && cancel_nav) + { + ok(!!V_DISPATCH(disp), "Got NULL disp.\n"); + todo_wine ok(V_DISPATCH(disp) != (IDispatch*)wb, "Got the same browser.\n"); + } + else + ok(V_DISPATCH(disp) == (IDispatch*)wb, "V_DISPATCH(disp)=%p, wb=%p\n", V_DISPATCH(disp), wb); + ok(V_VT(flags) == (VT_BYREF|VT_VARIANT), "V_VT(flags)=%x, expected VT_BYREF|VT_VARIANT\n", V_VT(flags)); ok(V_VT(flags) == (VT_BYREF|VT_VARIANT), "V_VT(flags)=%x, expected VT_BYREF|VT_VARIANT\n", @@ -805,8 +822,15 @@ static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const V_VT(cancel)); ok(V_BOOLREF(cancel) != NULL, "V_BOOLREF(pDispParams->rgvarg[0] == NULL)\n"); if(V_BOOLREF(cancel)) + { ok(*V_BOOLREF(cancel) == VARIANT_FALSE, "*V_BOOLREF(cancel) = %x, expected VARIANT_FALSE\n", *V_BOOLREF(cancel)); + if (cancel_nav) + { + *V_BOOLREF(cancel) = TRUE; + navigation_cancelled = TRUE; + } + } } static void test_navigatecomplete2(DISPPARAMS *dp) @@ -821,6 +845,7 @@ static void test_navigatecomplete2(DISPPARAMS *dp) ok(V_VT(dp->rgvarg) == (VT_BYREF|VT_VARIANT), "V_VT(dp->rgvarg) = %d\n", V_VT(dp->rgvarg)); v = V_VARIANTREF(dp->rgvarg); ok(V_VT(v) == VT_BSTR, "V_VT(url) = %d\n", V_VT(v)); + todo_wine_if(!memcmp(V_BSTR(v), L"file:", 10)) ok(!lstrcmpW(V_BSTR(v), current_url), "url=%s, expected %s\n", wine_dbgstr_w(V_BSTR(v)), wine_dbgstr_w(current_url)); @@ -845,6 +870,8 @@ static void test_documentcomplete(DISPPARAMS *dp) ok(V_VT(dp->rgvarg) == (VT_BYREF|VT_VARIANT), "V_VT(dp->rgvarg) = %d\n", V_VT(dp->rgvarg)); v = V_VARIANTREF(dp->rgvarg); ok(V_VT(v) == VT_BSTR, "V_VT(url) = %d\n", V_VT(v)); + + todo_wine_if(!memcmp(V_BSTR(v), L"file:", 10)) ok(!lstrcmpW(V_BSTR(v), current_url), "url=%s, expected %s\n", wine_dbgstr_w(V_BSTR(v)), wine_dbgstr_w(current_url)); @@ -907,9 +934,19 @@ static HRESULT WINAPI WebBrowserEvents2_Invoke(IDispatch *iface, DISPID dispIdMe pDispParams->rgvarg+3, pDispParams->rgvarg+2, pDispParams->rgvarg+1, pDispParams->rgvarg); if(dwl_flags & (DWL_FROM_PUT_HREF|DWL_FROM_GOFORWARD)) + { test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE); + } + else if (dwl_flags & DWL_IFRAME_NAV_CANCEL) + { + test_ready_state(READYSTATE_LOADING, navigation_cancelled ? VARIANT_TRUE : VARIANT_FALSE); + if (!navigation_cancelled) + SET_EXPECT(Invoke_BEFORENAVIGATE2); + } else - test_ready_state(READYSTATE_LOADING, VARIANT_FALSE); + { + test_ready_state(READYSTATE_LOADING, dwl_flags & DWL_FROM_IFRAME_NAV_CANCEL ? VARIANT_TRUE : VARIANT_FALSE); + } break; case DISPID_SETSECURELOCKICON: @@ -948,7 +985,7 @@ static HRESULT WINAPI WebBrowserEvents2_Invoke(IDispatch *iface, DISPID dispIdMe CHECK_EXPECT2(Invoke_COMMANDSTATECHANGE_NAVIGATEFORWARD_FALSE); } } - else if (V_I4(pDispParams->rgvarg+1) == CSC_NAVIGATEBACK) + else if (V_I4(pDispParams->rgvarg+1) == CSC_NAVIGATEBACK && !(dwl_flags & DWL_FROM_IFRAME_NAV_CANCEL)) { todo_wine_if(nav_back_todo) { if(V_BOOL(pDispParams->rgvarg)) @@ -1681,6 +1718,8 @@ static HRESULT WINAPI DocHostUIHandler_TranslateUrl(IDocHostUIHandler2 *iface, D { todo_wine_if(is_downloading && !(dwl_flags & DWL_EXPECT_BEFORE_NAVIGATE)) CHECK_EXPECT(TranslateUrl); + if (dwl_flags & DWL_IFRAME_NAV_CANCEL && wcscmp(pchURLIn, L"invalid:///")) + SET_EXPECT(TranslateUrl); return E_NOTIMPL; } @@ -2814,12 +2853,16 @@ static void test_ConnectionPoint(IWebBrowser2 *unk, BOOL init) static void test_Navigate2(IWebBrowser2 *webbrowser, const WCHAR *nav_url) { const WCHAR *title = L"WineHQ - Run Windows applications on Linux, BSD, Solaris and Mac OS X"; + const WCHAR *file_title = L"wine_test"; VARIANT url; BOOL is_file; HRESULT hres; test_LocationURL(webbrowser, is_first_load ? L"" : current_url); - test_LocationName(webbrowser, is_first_load ? L"" : (is_http ? title : current_url)); + if (current_url && !memcmp(current_url, L"file:", 10)) + test_LocationName(webbrowser, file_title); + else + test_LocationName(webbrowser, is_first_load ? L"" : (is_http ? title : current_url)); test_ready_state(is_first_load ? READYSTATE_UNINITIALIZED : READYSTATE_COMPLETE, VARIANT_FALSE); is_http = !memcmp(nav_url, "http:", 5); @@ -2990,6 +3033,8 @@ static void test_download(DWORD flags) BOOL *b = &called_Invoke_DOCUMENTCOMPLETE; MSG msg; + navigation_cancelled = FALSE; + if(flags & DWL_REFRESH) b = use_container_olecmd ? &called_Exec_SETDOWNLOADSTATE_0 : &called_Invoke_DOWNLOADCOMPLETE; else if((flags & DWL_FROM_PUT_HREF) && !use_container_olecmd && 0) @@ -3066,7 +3111,7 @@ static void test_download(DWORD flags) SET_EXPECT(GetOverridesKeyPath); /* Called randomly on some VMs. */ trace("Downloading...\n"); - while(!*b && GetMessageW(&msg, NULL, 0, 0)) { + while(!navigation_cancelled && !*b && GetMessageW(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); } @@ -3097,11 +3142,14 @@ static void test_download(DWORD flags) CLEAR_CALLED(EnableModeless_FALSE); /* IE 8 */ if(!(flags & DWL_REFRESH)) { - todo_wine_if(nav_back_todo) { - if(flags & (DWL_FROM_GOFORWARD|DWL_BACK_ENABLE)) - CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_TRUE); - else - CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_FALSE); + if (!(flags & DWL_FROM_IFRAME_NAV_CANCEL)) + { + todo_wine_if(nav_back_todo) { + if(flags & (DWL_FROM_GOFORWARD|DWL_BACK_ENABLE)) + CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_TRUE); + else + CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_FALSE); + } } if(flags & DWL_FROM_GOBACK) CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEFORWARD_TRUE); @@ -3118,20 +3166,26 @@ static void test_download(DWORD flags) if(!is_first_load) todo_wine CHECK_CALLED(GetHostInfo); if(use_container_olecmd) - CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); + todo_wine_if(flags & DWL_IFRAME_NAV_CANCEL) CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); else - CHECK_CALLED(Invoke_DOWNLOADCOMPLETE); + todo_wine_if(flags & DWL_IFRAME_NAV_CANCEL) CHECK_CALLED(Invoke_DOWNLOADCOMPLETE); todo_wine CHECK_CALLED(Invoke_TITLECHANGE); if(!(flags & DWL_REFRESH)) CHECK_CALLED(Invoke_NAVIGATECOMPLETE2); if(is_first_load) todo_wine CHECK_CALLED(GetDropTarget); - if(!(flags & DWL_REFRESH)) + if(!(flags & (DWL_REFRESH | DWL_IFRAME_NAV_CANCEL))) CHECK_CALLED(Invoke_DOCUMENTCOMPLETE); is_downloading = FALSE; - test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE); + if (flags & DWL_IFRAME_NAV_CANCEL) + { + test_ready_state(READYSTATE_INTERACTIVE, VARIANT_TRUE); + SET_EXPECT(Invoke_TITLECHANGE); + } + else + test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE); while(use_container_olecmd && !called_Exec_UPDATECOMMANDS && GetMessageA(&msg, NULL, 0, 0)) { TranslateMessage(&msg); @@ -3840,6 +3894,51 @@ static void init_test(IWebBrowser2 *webbrowser, DWORD flags) use_container_dochostui = !(flags & TEST_NODOCHOST); } +static const char iframe_doc_str[] = + ""; + +static void test_iframe_load(IWebBrowser2 *webbrowser) +{ + WCHAR file_path[MAX_PATH]; + WCHAR file_url[MAX_PATH]; + HRESULT hres; + HANDLE file; + VARIANT url; + DWORD size; + BOOL bret; + + GetTempPathW(MAX_PATH, file_path); + lstrcatW(file_path, L"wine_ifr_test.html"); + + file = CreateFileW(file_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed, error %u.\n", GetLastError()); + if(file == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS){ + ok(0, "CreateFile failed\n"); + return; + } + WriteFile(file, iframe_doc_str, strlen(iframe_doc_str), &size, NULL); + CloseHandle(file); + + GetLongPathNameW(file_path, file_path, ARRAY_SIZE(file_path)); + lstrcpyW(file_url, L"file://"); + lstrcatW(file_url, file_path); + + trace("iframe load...\n"); + test_Navigate2(webbrowser, file_url); + test_download(DWL_EXPECT_BEFORE_NAVIGATE|DWL_IFRAME_NAV_CANCEL|DWL_BACK_ENABLE); + + V_VT(&url) = VT_BSTR; + V_BSTR(&url) = SysAllocString(current_url = L"about:blank"); + hres = IWebBrowser2_Navigate2(webbrowser, &url, NULL, NULL, NULL, NULL); + ok(hres == S_OK, "Navigate2 failed: %08x\n", hres); + VariantClear(&url); + + test_download(DWL_EXPECT_BEFORE_NAVIGATE|DWL_FROM_IFRAME_NAV_CANCEL); + + bret = DeleteFileW(file_path); + ok(bret, "DeleteFileW failed, err %u.\n", GetLastError()); +} + static void test_WebBrowser(DWORD flags, BOOL do_close) { IWebBrowser2 *webbrowser; @@ -3868,6 +3967,7 @@ static void test_WebBrowser(DWORD flags, BOOL do_close) test_LocationURL(webbrowser, L""); test_ConnectionPoint(webbrowser, TRUE); + test_ClientSite(webbrowser, &ClientSite, !do_download); test_Extent(webbrowser); test_wb_funcs(webbrowser, TRUE); @@ -3934,6 +4034,8 @@ static void test_WebBrowser(DWORD flags, BOOL do_close) trace("GoForward...\n"); test_go_forward(webbrowser, L"http://test.winehq.org/tests/winehq_snapshot/", -1, 0); test_download(DWL_FROM_GOFORWARD|DWL_HTTP); + if (!(flags & TEST_NOOLECMD)) + test_iframe_load(webbrowser); }else { trace("Navigate2 repeated with the same URL...\n"); test_Navigate2(webbrowser, L"about:blank"); @@ -3942,7 +4044,6 @@ static void test_WebBrowser(DWORD flags, BOOL do_close) test_EnumVerbs(webbrowser); test_TranslateAccelerator(webbrowser); - test_dochost_qs(webbrowser); }else { test_ExecWB(webbrowser, TRUE); diff --git a/dlls/imagehlp/imagehlp.spec b/dlls/imagehlp/imagehlp.spec index 7d934dcc96e5..4e784f8bf222 100644 --- a/dlls/imagehlp/imagehlp.spec +++ b/dlls/imagehlp/imagehlp.spec @@ -51,16 +51,16 @@ @ stdcall -import SymEnumerateModules64(long ptr ptr) @ stdcall -import SymEnumerateModules(long ptr ptr) @ stdcall -import SymEnumerateSymbols64(long int64 ptr ptr) -@ stdcall -import SymEnumerateSymbols(long long ptr ptr) +@ stdcall -import SymEnumerateSymbols(long ptr ptr ptr) @ stub SymEnumerateSymbolsW64 @ stub SymEnumerateSymbolsW @ stdcall -import SymFindFileInPath(long str str ptr long long long ptr ptr ptr) @ stdcall -import SymFromAddr(ptr int64 ptr ptr) @ stdcall -import SymFromName(long str ptr) @ stdcall -import SymFunctionTableAccess64(long int64) -@ stdcall -import SymFunctionTableAccess(long long) +@ stdcall -import SymFunctionTableAccess(long ptr) @ stdcall -import SymGetLineFromAddr64(long int64 ptr ptr) -@ stdcall -import SymGetLineFromAddr(long long ptr ptr) +@ stdcall -import SymGetLineFromAddr(long ptr ptr ptr) @ stub SymGetLineFromName64 @ stub SymGetLineFromName @ stdcall -import SymGetLineNext64(long ptr) @@ -68,15 +68,15 @@ @ stdcall -import SymGetLinePrev64(long ptr) @ stdcall -import SymGetLinePrev(long ptr) @ stdcall -import SymGetModuleBase64(long int64) -@ stdcall -import SymGetModuleBase(long long) +@ stdcall -import SymGetModuleBase(long ptr) @ stdcall -import SymGetModuleInfo64(long int64 ptr) -@ stdcall -import SymGetModuleInfo(long long ptr) +@ stdcall -import SymGetModuleInfo(long ptr ptr) @ stdcall -import SymGetModuleInfoW64(long int64 ptr) -@ stdcall -import SymGetModuleInfoW(long long ptr) +@ stdcall -import SymGetModuleInfoW(long ptr ptr) @ stdcall -import SymGetOptions() @ stdcall -import SymGetSearchPath(long ptr long) @ stdcall -import SymGetSymFromAddr64(long int64 ptr ptr) -@ stdcall -import SymGetSymFromAddr(long long ptr ptr) +@ stdcall -import SymGetSymFromAddr(long ptr ptr ptr) @ stdcall -import SymGetSymFromName64(long str ptr) @ stdcall -import SymGetSymFromName(long str ptr) @ stdcall -import SymGetSymNext64(long ptr) @@ -87,7 +87,7 @@ @ stdcall -import SymGetTypeInfo(ptr int64 long long ptr) @ stdcall -import SymInitialize(long str long) @ stdcall -import SymLoadModule64(long long str str int64 long) -@ stdcall -import SymLoadModule(long long str str long long) +@ stdcall -import SymLoadModule(long long str str ptr long) @ stdcall -import SymMatchFileName(str str ptr ptr) @ stdcall -import SymMatchString(str str long) @ stdcall -import SymRegisterCallback64(long ptr int64) @@ -100,7 +100,7 @@ @ stdcall -import SymUnDName64(ptr str long) @ stdcall -import SymUnDName(ptr str long) @ stdcall -import SymUnloadModule64(long int64) -@ stdcall -import SymUnloadModule(long long) +@ stdcall -import SymUnloadModule(long ptr) @ stdcall TouchFileTimes(long ptr) @ stdcall -import UnDecorateSymbolName(str str long long) @ stdcall UnMapAndLoad(ptr) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 24270e89291a..6f1d68ad0d4f 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -433,7 +433,7 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP case WM_IME_CONTROL: FIXME( "hwnd %p, himc %p, msg %s, wparam %s, lparam %#Ix stub!\n", hwnd, himc, debugstr_wm_ime(msg), debugstr_imc(wparam), lparam ); - return 1; + return 0; } return DefWindowProcW( hwnd, msg, wparam, lparam ); diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index dbf8db63e114..5639c2ae11c6 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -948,6 +948,7 @@ static HWND get_ime_ui_window(void) { imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, ime->ui_class, NULL, WS_POPUP, 0, 0, 1, 1, ImmGetDefaultIMEWnd( 0 ), 0, ime->module, 0 ); + SetWindowPos( imc->ui_hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE ); SetWindowLongPtrW( imc->ui_hwnd, IMMGWL_IMC, (LONG_PTR)NtUserGetWindowInputContext( GetFocus() ) ); } return imc->ui_hwnd; diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index db73463ef497..5b4e194c367f 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -8037,8 +8037,57 @@ static void test_nihongo_no(void) ime_call_count = 0; } +static BOOL CALLBACK enum_first_current_thread_window_proc( HWND hwnd, LPARAM lparam ) +{ + if (GetWindowThreadProcessId( hwnd, NULL ) == GetCurrentThreadId()) + { + *(HWND *)lparam = hwnd; + return FALSE; + } + return TRUE; +} + +static void test_ime_ui_window_child( void ) +{ + HWND hwnd, result_hwnd = 0; + + /* Unity expects the first window in the current thread to be its game window, not Wine IME */ + hwnd = CreateWindowW( L"static", L"", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( 0, hwnd, HWND, "%p" ); + EnumWindows( enum_first_current_thread_window_proc, (LPARAM)&result_hwnd ); + ok_eq( result_hwnd, hwnd, HWND, "%p" ); + DestroyWindow( hwnd ); +} + +static void test_ime_ui_window( const char *argv0 ) +{ + PROCESS_INFORMATION info; + STARTUPINFOA startup; + char cmd[MAX_PATH]; + + /* Run in a new process to avoid interference from windows in the current process */ + sprintf( cmd, "%s imm32 test_ime_ui_window_child", argv0 ); + memset( &startup, 0, sizeof(startup) ); + startup.cb = sizeof(startup); + CreateProcessA( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); + + wait_child_process( info.hProcess ); + CloseHandle( info.hProcess ); + CloseHandle( info.hThread ); +} + START_TEST(imm32) { + char **argv; + int argc; + + argc = winetest_get_mainargs( &argv ); + if (argc == 3 && !strcmp( argv[2], "test_ime_ui_window_child" )) + { + test_ime_ui_window_child(); + return; + } + default_hkl = GetKeyboardLayout( 0 ); test_class.hInstance = GetModuleHandleW( NULL ); @@ -8050,6 +8099,7 @@ START_TEST(imm32) return; } + test_ime_ui_window( argv[0] ); test_com_initialization(); test_ImmEnumInputContext(); diff --git a/dlls/iphlpapi/iphlpapi.spec b/dlls/iphlpapi/iphlpapi.spec index facb52e04487..d8173c0b33c6 100644 --- a/dlls/iphlpapi/iphlpapi.spec +++ b/dlls/iphlpapi/iphlpapi.spec @@ -106,7 +106,7 @@ @ stdcall GetIpForwardTable( ptr ptr long ) @ stdcall GetIpForwardTable2( long ptr ) @ stub GetIpForwardTableFromStack -#@ stub GetIpInterfaceEntry +@ stdcall GetIpInterfaceEntry( ptr ) @ stdcall GetIpInterfaceTable( long ptr ) #@ stub GetIpNetEntry2 @ stdcall GetIpNetTable( ptr ptr long ) @@ -123,8 +123,8 @@ @ stdcall GetNetworkParams( ptr ptr ) @ stdcall GetNumberOfInterfaces( ptr ) #@ stub GetOwnerModuleFromPidAndInfo -#@ stub GetOwnerModuleFromTcp6Entry -#@ stub GetOwnerModuleFromTcpEntry +@ stdcall GetOwnerModuleFromTcp6Entry( ptr long ptr ptr ) +@ stdcall GetOwnerModuleFromTcpEntry( ptr long ptr ptr ) #@ stub GetOwnerModuleFromUdp6Entry #@ stub GetOwnerModuleFromUdpEntry @ stdcall GetPerAdapterInfo( long ptr ptr ) diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index 172afbd62b85..66d0a66f39ee 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -21,6 +21,8 @@ #include #define IPHLPAPI_DLL_LINKAGE +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winreg.h" @@ -36,6 +38,7 @@ #include "ip2string.h" #include "netiodef.h" #include "icmpapi.h" +#include "psapi.h" #include "wine/nsi.h" #include "wine/debug.h" @@ -1387,27 +1390,21 @@ DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex) * Success: NO_ERROR * Failure: error code from winerror.h */ -DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr, PDWORD pdwBestIfIndex) +DWORD WINAPI GetBestInterfaceEx( struct sockaddr *dst, DWORD *best_index ) { - DWORD ret; + SOCKADDR_INET best_address; + MIB_IPFORWARD_ROW2 row; + DWORD ret; - TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex); - if (!pDestAddr || !pdwBestIfIndex) - ret = ERROR_INVALID_PARAMETER; - else { - MIB_IPFORWARDROW ipRow; + TRACE( "dst %p, best_index %p\n", dst, best_index ); - if (pDestAddr->sa_family == AF_INET) { - ret = GetBestRoute(((struct sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow); - if (ret == ERROR_SUCCESS) - *pdwBestIfIndex = ipRow.dwForwardIfIndex; - } else { - FIXME("address family %d not supported\n", pDestAddr->sa_family); - ret = ERROR_NOT_SUPPORTED; - } - } - TRACE("returning %ld\n", ret); - return ret; + if (!dst || !best_index) return ERROR_INVALID_PARAMETER; + + ret = GetBestRoute2( NULL, 0, NULL, (const SOCKADDR_INET *)dst, 0, &row, &best_address ); + if (!ret) *best_index = row.InterfaceIndex; + + TRACE( "returning %ld\n", ret ); + return ret; } @@ -2078,10 +2075,15 @@ DWORD WINAPI AllocateAndGetIpAddrTableFromStack( MIB_IPADDRTABLE **table, BOOL s static int ipforward_row_cmp( const void *a, const void *b ) { const MIB_IPFORWARDROW *rowA = a, *rowB = b; - return DWORD_cmp(RtlUlongByteSwap( rowA->dwForwardDest ), RtlUlongByteSwap( rowB->dwForwardDest )) || - DWORD_cmp(rowA->dwForwardProto, rowB->dwForwardProto) || - DWORD_cmp(rowA->dwForwardPolicy, rowB->dwForwardPolicy) || - DWORD_cmp(RtlUlongByteSwap( rowA->dwForwardNextHop ), RtlUlongByteSwap( rowB->dwForwardNextHop )); + int ret; + + if ((ret = DWORD_cmp(RtlUlongByteSwap( rowA->dwForwardDest ), RtlUlongByteSwap( rowB->dwForwardDest )))) + return ret; + if ((ret = DWORD_cmp(rowA->dwForwardProto, rowB->dwForwardProto))) + return ret; + if ((ret = DWORD_cmp(rowA->dwForwardPolicy, rowB->dwForwardPolicy))) + return ret; + return DWORD_cmp(RtlUlongByteSwap( rowA->dwForwardNextHop ), RtlUlongByteSwap( rowB->dwForwardNextHop )); } /****************************************************************** @@ -3265,6 +3267,68 @@ DWORD WINAPI GetExtendedTcpTable( void *table, DWORD *size, BOOL sort, ULONG fam return get_extended_tcp_table( table, size, sort, family, table_class ); } +static DWORD get_owner_module_from_pid( TCPIP_OWNER_MODULE_INFO_CLASS class, void *buffer, DWORD *size, DWORD pid ) +{ + WCHAR path[(MAX_PATH + 1) * sizeof(WCHAR)], *name; + TCPIP_OWNER_MODULE_BASIC_INFO *info = buffer; + DWORD len, ret_size; + HANDLE process; + + if (class != TCPIP_OWNER_MODULE_INFO_BASIC) + { + FIXME( "Unsupported class %d.\n", class ); + return ERROR_INVALID_PARAMETER; + } + + if (!size) return ERROR_INVALID_PARAMETER; + if (!pid) return ERROR_NOT_FOUND; + if (!(process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid ))) return GetLastError(); + len = GetModuleFileNameExW( process, NULL, path, ARRAY_SIZE(path) ); + CloseHandle( process ); + if (!len) return ERROR_NOT_FOUND; + if (len == ARRAY_SIZE(path)) return ERROR_PATH_NOT_FOUND; + if (!(name = wcsrchr( path, '\\' ))) return ERROR_PATH_NOT_FOUND; + ++name; + len = wcslen( name ) + 1; + ret_size = sizeof(*info) + (len + wcslen( path ) + 1) * sizeof(WCHAR); + if (*size < ret_size) + { + *size = ret_size; + return ERROR_INSUFFICIENT_BUFFER; + } + info->pModuleName = (WCHAR *)(info + 1); + info->pModulePath = info->pModuleName + len; + memcpy( info->pModuleName, name, len * sizeof(WCHAR) ); + wcscpy( info->pModulePath, path ); + return ERROR_SUCCESS; +} + +/****************************************************************** + * GetOwnerModuleFromTcpEntry (IPHLPAPI.@) + */ +DWORD WINAPI GetOwnerModuleFromTcpEntry( PMIB_TCPROW_OWNER_MODULE entry, TCPIP_OWNER_MODULE_INFO_CLASS class, + void *buffer, DWORD *size ) +{ + TRACE( "entry %p, class %d, buffer %p, size %p.\n", entry, class, buffer, size ); + + if (!entry) return ERROR_INVALID_PARAMETER; + + return get_owner_module_from_pid( class, buffer, size, entry->dwOwningPid ); +} + +/****************************************************************** + * GetOwnerModuleFromTcp6Entry (IPHLPAPI.@) + */ +DWORD WINAPI GetOwnerModuleFromTcp6Entry( PMIB_TCP6ROW_OWNER_MODULE entry, TCPIP_OWNER_MODULE_INFO_CLASS class, + void *buffer, DWORD *size ) +{ + TRACE( "entry %p, class %d, buffer %p, size %p.\n", entry, class, buffer, size ); + + if (!entry) return ERROR_INVALID_PARAMETER; + + return get_owner_module_from_pid( class, buffer, size, entry->dwOwningPid ); +} + /****************************************************************** * GetTcpTable (IPHLPAPI.@) * @@ -3545,9 +3609,12 @@ static void udp_row_fill( void *table, DWORD num, ULONG family, ULONG table_clas static int udp_row_cmp( const void *a, const void *b ) { const MIB_UDPROW *rowA = a, *rowB = b; + int ret; + + if ((ret = DWORD_cmp(RtlUlongByteSwap( rowA->dwLocalAddr), RtlUlongByteSwap( rowB->dwLocalAddr )))) + return ret; - return DWORD_cmp(RtlUlongByteSwap( rowA->dwLocalAddr), RtlUlongByteSwap( rowB->dwLocalAddr )) || - RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort ); + return RtlUshortByteSwap( rowA->dwLocalPort ) - RtlUshortByteSwap( rowB->dwLocalPort ); } static int udp6_row_cmp( const void *a, const void *b ) @@ -3644,19 +3711,16 @@ static void unicast_row_fill( MIB_UNICASTIPADDRESS_ROW *row, USHORT fam, void *k struct nsi_ipv4_unicast_key *key4 = (struct nsi_ipv4_unicast_key *)key; struct nsi_ipv6_unicast_key *key6 = (struct nsi_ipv6_unicast_key *)key; + memset( &row->Address, 0, sizeof(row->Address) ); if (fam == AF_INET) { row->Address.Ipv4.sin_family = fam; - row->Address.Ipv4.sin_port = 0; row->Address.Ipv4.sin_addr = key4->addr; - memset( row->Address.Ipv4.sin_zero, 0, sizeof(row->Address.Ipv4.sin_zero) ); row->InterfaceLuid.Value = key4->luid.Value; } else { row->Address.Ipv6.sin6_family = fam; - row->Address.Ipv6.sin6_port = 0; - row->Address.Ipv6.sin6_flowinfo = 0; row->Address.Ipv6.sin6_addr = key6->addr; row->Address.Ipv6.sin6_scope_id = dyn->scope_id; row->InterfaceLuid.Value = key6->luid.Value; @@ -4530,33 +4594,373 @@ char *WINAPI IPHLP_if_indextoname( NET_IFINDEX index, char *name ) return name; } +static void fill_ip_interface_table_row( ADDRESS_FAMILY fam, MIB_IPINTERFACE_ROW *row, struct nsi_ip_interface_key *key, + struct nsi_ip_interface_rw *rw, struct nsi_ip_interface_dynamic *dyn ) +{ + row->Family = fam; + row->InterfaceLuid = key->luid; + row->InterfaceIndex = dyn->if_index; + row->RouterDiscoveryBehavior = rw->router_discovery_behaviour; + row->DadTransmits = rw->dad_transmits; + row->BaseReachableTime = rw->base_reachable_time; + row->RetransmitTime = rw->retransmit_time; + row->PathMtuDiscoveryTimeout = rw->path_mtu_discovery_timeout; + row->LinkLocalAddressBehavior = rw->link_local_address_behavior; + row->LinkLocalAddressTimeout = rw->link_local_address_timeout; + memcpy( row->ZoneIndices, rw->zone_indices, sizeof(row->ZoneIndices) ); + row->SitePrefixLength = rw->site_prefix_len; + row->Metric = rw->metric; + row->NlMtu = rw->mtu; + row->Connected = dyn->connected; + row->SupportsWakeUpPatterns = dyn->supports_wakeup_patterns; + row->ReachableTime = dyn->reachable_time; + row->TransmitOffload = dyn->transmit_offload; + + /* MinRouterAdvertisementInterval / MaxRouterAdvertisementInterval don't seem to have an + * entry in NSI interface table, or maybe these fields are usually default and NSI tables have 0 in that case + * and thus weren't discovered. */ + row->MinRouterAdvertisementInterval = 200; + row->MaxRouterAdvertisementInterval = 600; + + /* Flags exact locations were not yet discovered in NSI table. */ + row->UseAutomaticMetric = 1; + row->UseNeighborUnreachabilityDetection = 1; + row->SupportsNeighborDiscovery = 1; + row->SupportsRouterDiscovery = 1; +} + /****************************************************************** * GetIpInterfaceTable (IPHLPAPI.@) */ -DWORD WINAPI GetIpInterfaceTable(ADDRESS_FAMILY family, PMIB_IPINTERFACE_TABLE *table) +DWORD WINAPI GetIpInterfaceTable( ADDRESS_FAMILY family, MIB_IPINTERFACE_TABLE **table ) +{ + struct nsi_ip_interface_dynamic *dyn; + struct nsi_ip_interface_key *keys; + DWORD err, count, total_count = 0; + MIB_IPINTERFACE_TABLE *new_alloc; + struct nsi_ip_interface_rw *rw; + ADDRESS_FAMILY fam[3] = { 0 }; + unsigned int i, family_idx; + + TRACE( "(%u %p).\n", family, table ); + + if (!table) return ERROR_INVALID_PARAMETER; + + if (family == AF_UNSPEC) + { + fam[0] = AF_INET; + fam[1] = AF_INET6; + } + else fam[0] = family; + + *table = NULL; + for (family_idx = 0; fam[family_idx]; ++family_idx) + { + err = NsiAllocateAndGetTable( 1, ip_module_id( fam[family_idx] ), NSI_IP_INTERFACE_TABLE, + (void **)&keys, sizeof(*keys), (void **)&rw, sizeof(*rw), + (void **)&dyn, sizeof(*dyn), NULL, 0, &count, 0 ); + if (err) + { + heap_free( *table ); + return err; + } + total_count += count; + new_alloc = heap_alloc_zero( offsetof(MIB_IPINTERFACE_TABLE, Table[total_count]) ); + if (!new_alloc) + { + heap_free( *table ); + NsiFreeTable( keys, rw, dyn, NULL ); + return ERROR_NOT_ENOUGH_MEMORY; + } + if (*table) + { + memcpy( new_alloc, *table, offsetof(MIB_IPINTERFACE_TABLE, Table[(*table)->NumEntries]) ); + free( *table ); + } + *table = new_alloc; + for (i = 0; i < count; ++i) + { + fill_ip_interface_table_row( fam[family_idx], &(*table)->Table[(*table)->NumEntries], + &keys[i], &rw[i], &dyn[i] ); + ++(*table)->NumEntries; + } + NsiFreeTable( keys, rw, dyn, NULL ); + } + return ERROR_SUCCESS; +} + +/****************************************************************** + * GetIpInterfaceEntry (IPHLPAPI.@) + */ +DWORD WINAPI GetIpInterfaceEntry( MIB_IPINTERFACE_ROW *row ) +{ + struct nsi_ip_interface_dynamic dyn; + struct nsi_ip_interface_key key; + struct nsi_ip_interface_rw rw; + DWORD err; + + TRACE( "%p.\n", row ); + + if (!row) return ERROR_INVALID_PARAMETER; + if (row->Family != AF_INET && row->Family != AF_INET6) return ERROR_INVALID_PARAMETER; + + key.luid = row->InterfaceLuid; + if (!key.luid.Value && ConvertInterfaceIndexToLuid( row->InterfaceIndex, &key.luid )) return ERROR_NOT_FOUND; + + err = NsiGetAllParameters( 1, ip_module_id( row->Family ), NSI_IP_INTERFACE_TABLE, + &key, sizeof(key), &rw, sizeof(rw), + &dyn, sizeof(dyn), NULL, 0 ); + if (err) return err; + fill_ip_interface_table_row( row->Family, row, &key, &rw, &dyn ); + return ERROR_SUCCESS; +} + + +static BOOL match_ip_address_with_prefix( const SOCKADDR_INET *addr, const IP_ADDRESS_PREFIX *pfx ) +{ + const BYTE *p1, *p2; + unsigned int len; + BYTE mask; + + if (addr->si_family != pfx->Prefix.si_family) return FALSE; + if (!(len = pfx->PrefixLength)) return TRUE; + + if (addr->si_family == AF_INET6) + { + if (len > 128) return FALSE; + p1 = (const BYTE *)&addr->Ipv6.sin6_addr; + p2 = (const BYTE *)&pfx->Prefix.Ipv6.sin6_addr; + } + else + { + if (len > 32) return FALSE; + p1 = (const BYTE *)&addr->Ipv4.sin_addr; + p2 = (const BYTE *)&pfx->Prefix.Ipv4.sin_addr; + } + if (memcmp( p1, p2, len / 8 )) return FALSE; + mask = 0xffu << (8 - (len % 8)); + if (!mask) return TRUE; + return (p1[len / 8] & mask) == (p2[len / 8] & mask); +} + +static MIB_UNICASTIPADDRESS_ROW *find_first_matching_unicast_addr( MIB_UNICASTIPADDRESS_TABLE *uni, BOOL v6, + const SOCKADDR_INET *src, const SOCKADDR_INET *dst, + NET_IFINDEX if_index ) +{ + unsigned int i; + + for (i = 0; i < uni->NumEntries; ++i) + { + if (if_index && uni->Table[i].InterfaceIndex != if_index) continue; + if (src) + { + if (v6) + { + if (src->Ipv6.sin6_scope_id && IN6_IS_ADDR_LINKLOCAL(&src->Ipv6.sin6_addr) + && src->Ipv6.sin6_scope_id != uni->Table[i].InterfaceIndex) continue; + if (memcmp( &src->Ipv6.sin6_addr, &uni->Table[i].Address.Ipv6.sin6_addr, sizeof(src->Ipv6.sin6_addr) )) + continue; + } + else if (src->Ipv4.sin_addr.s_addr != uni->Table[i].Address.Ipv4.sin_addr.s_addr) continue; + } + if (v6 && dst) + { + if (IN6_IS_ADDR_LINKLOCAL(&dst->Ipv6.sin6_addr) + != IN6_IS_ADDR_LINKLOCAL(&uni->Table[i].Address.Ipv6.sin6_addr)) + continue; + } + return &uni->Table[i]; + } + return NULL; +} + +static BOOL is_addr_unspecified( const SOCKADDR_INET *addr, BOOL v6 ) { - FIXME("(%u %p): stub\n", family, table); - return ERROR_NOT_SUPPORTED; + if (v6 && IN6_IS_ADDR_UNSPECIFIED(&addr->Ipv6.sin6_addr)) return TRUE; + if (!v6 && !addr->Ipv4.sin_addr.s_addr) return TRUE; + return FALSE; } /****************************************************************** * GetBestRoute2 (IPHLPAPI.@) */ -DWORD WINAPI GetBestRoute2(NET_LUID *luid, NET_IFINDEX index, - const SOCKADDR_INET *source, const SOCKADDR_INET *destination, - ULONG options, PMIB_IPFORWARD_ROW2 bestroute, - SOCKADDR_INET *bestaddress) -{ - static int once; +DWORD WINAPI GetBestRoute2( NET_LUID *luid, NET_IFINDEX index, + const SOCKADDR_INET *src, const SOCKADDR_INET *dst, + ULONG options, PMIB_IPFORWARD_ROW2 bestroute, + SOCKADDR_INET *bestaddress ) +{ + MIB_UNICASTIPADDRESS_ROW *uni_row = NULL; + MIB_UNICASTIPADDRESS_TABLE *uni; + MIB_IPFORWARD_TABLE2 *fwd; + unsigned int i, best_idx; + int max_prefix_len; + DWORD ret; + BOOL v6; + + TRACE( "(%p, %ld, %p, %p, 0x%08lx, %p, %p).\n", luid, index, src, dst, options, bestroute, bestaddress ); + + if (!dst || !bestroute || !bestaddress) + return ERROR_INVALID_PARAMETER; - if (!once++) - FIXME("(%p, %ld, %p, %p, 0x%08lx, %p, %p): stub\n", luid, index, source, - destination, options, bestroute, bestaddress); + memset( bestroute, 0, sizeof(*bestroute) ); + memset( bestaddress, 0, sizeof(*bestaddress) ); - if (!destination || !bestroute || !bestaddress) + if (dst->si_family != AF_INET && dst->si_family != AF_INET6) return ERROR_INVALID_PARAMETER; + v6 = dst->si_family == AF_INET6; + if (src) + { + if (src->si_family != dst->si_family) src = NULL; + else if (is_addr_unspecified( src, v6 )) src = NULL; + } + + if (v6 && !IN6_IS_ADDR_LINKLOCAL(&dst->Ipv6.sin6_addr) && dst->Ipv6.sin6_scope_id) + return ERROR_INVALID_PARAMETER; + if (v6 && src && !IN6_IS_ADDR_LINKLOCAL(&src->Ipv6.sin6_addr) && src->Ipv6.sin6_scope_id) return ERROR_INVALID_PARAMETER; - return ERROR_NOT_SUPPORTED; + if ((ret = GetUnicastIpAddressTable( dst->si_family, &uni ))) return ret; + if ((ret = GetIpForwardTable2( dst->si_family, &fwd ))) + { + FreeMibTable( &uni ); + return ret; + } + + if (!luid && index) + { + for (i = 0; i < uni->NumEntries; ++i) + { + if (uni->Table[i].InterfaceIndex == index) break; + } + if (i == uni->NumEntries) + { + ret = ERROR_FILE_NOT_FOUND; + goto done; + } + luid = &uni->Table[i].InterfaceLuid; + } + if (src && !(uni_row = find_first_matching_unicast_addr( uni, v6, src, NULL, 0 ))) + { + ret = ERROR_NOT_FOUND; + goto done; + } + if (!uni_row && luid && luid->Value) + { + for (i = 0; i < uni->NumEntries; ++i) + { + if (uni->Table[i].InterfaceLuid.Value == luid->Value) break; + } + if (i == uni->NumEntries) + { + ret = ERROR_NOT_FOUND; + goto done; + } + uni_row = &uni->Table[i]; + } + + if (uni_row) index = uni_row->InterfaceIndex; + else index = 0; + + if (v6) + { + if (!index) index = dst->Ipv6.sin6_scope_id; + if (IN6_IS_ADDR_LINKLOCAL(&dst->Ipv6.sin6_addr) && dst->Ipv6.sin6_scope_id + && dst->Ipv6.sin6_scope_id != index) + { + ret = ERROR_INVALID_PARAMETER; + goto done; + } + } + + uni_row = NULL; + if (!src && !(v6 && IN6_IS_ADDR_LINKLOCAL(&dst->Ipv6.sin6_addr))) + { + static const struct in6_addr ipv6_default_addr = {{{ 0x20, 0x01, 0x0d, 0xb8 }}}; + SOCKADDR_INET src_addr, dst_addr; + WORD ver = MAKEWORD (2, 2); + WSADATA data; + SOCKET s; + int len; + + WSAStartup ( ver, &data ); + if ((s = socket( dst->si_family, SOCK_DGRAM, IPPROTO_UDP )) == -1) goto skip_system_route; + dst_addr = *dst; + if (is_addr_unspecified( dst, v6 )) + { + /* GetBestRoute2() should return default route in this case while connect() while unspecified address for + * connect() has different semantics. So use some global IP address instead. */ + if (v6) dst_addr.Ipv6.sin6_addr = ipv6_default_addr; + else dst_addr.Ipv4.sin_addr.s_addr = 0x01010101; + } + if (connect( s, (struct sockaddr *)&dst_addr, sizeof(dst_addr) ) == -1) + { + WARN( "Resolving destination address failed.\n" ); + goto skip_system_route; + } + len = sizeof(src_addr); + if (getsockname( s, (struct sockaddr *)&src_addr, &len )) + { + WARN( "getsockname failed, error %d.\n", WSAGetLastError() ); + goto skip_system_route; + } + if (!(uni_row = find_first_matching_unicast_addr( uni, v6, &src_addr, &dst_addr, index ))) + { + WARN( "Could not find matching unicast addr for system route.\n" ); + goto skip_system_route; + } + if (index && uni_row->InterfaceIndex != index) + { + WARN( "Specified index %lu doesn't match system %lu.\n", index, uni_row->InterfaceIndex ); + uni_row = NULL; + goto skip_system_route; + } + index = uni_row->InterfaceIndex; +skip_system_route: + if (s != -1) closesocket(s); + WSACleanup(); + } + + max_prefix_len = -1; + best_idx = 0; + for (i = 0; i < fwd->NumEntries; ++i) + { + if (index && fwd->Table[i].InterfaceIndex != index) continue; + + if (match_ip_address_with_prefix( dst, &fwd->Table[i].DestinationPrefix ) + && max_prefix_len < fwd->Table[i].DestinationPrefix.PrefixLength ) + { + max_prefix_len = fwd->Table[i].DestinationPrefix.PrefixLength; + best_idx = i; + } + } + + if (max_prefix_len == -1) + { + ret = ERROR_NETWORK_UNREACHABLE; + goto done; + } + index = fwd->Table[best_idx].InterfaceIndex; + if (!fwd->Table[best_idx].Loopback && ((v6 && IN6_IS_ADDR_LOOPBACK(&dst->Ipv6.sin6_addr)) + || (!v6 && dst->Ipv4.sin_addr.S_un.S_un_b.s_b1 == 127))) + { + ret = ERROR_INVALID_PARAMETER; + goto done; + } + + if (!uni_row && !(uni_row = find_first_matching_unicast_addr( uni, v6, src, dst, index ))) + { + WARN( "Could not find source address.\n" ); + ret = ERROR_NOT_FOUND; + goto done; + } + *bestaddress = uni_row->Address; + *bestroute = fwd->Table[best_idx]; + + ret = ERROR_SUCCESS; +done: + FreeMibTable( fwd ); + FreeMibTable( uni ); + TRACE( "-> %lu.\n", ret ); + return ret; } /****************************************************************** @@ -4659,6 +5063,43 @@ struct icmp_handle_data HANDLE nsi_device; }; +struct icmp_apc_ctxt +{ + HANDLE event; + HANDLE thread; + void *apc_ctxt; + PIO_APC_ROUTINE apc_routine; + IO_STATUS_BLOCK iosb; +}; + +static void CALLBACK icmp_apc_routine( ULONG_PTR context ) +{ + struct icmp_apc_ctxt *ctx = (struct icmp_apc_ctxt *)context; + + ctx->apc_routine( ctx->apc_ctxt, &ctx->iosb, 0 ); + heap_free( ctx ); +} + +static void CALLBACK icmp_iocp_callback( DWORD error, DWORD count, OVERLAPPED *ovr ) +{ + struct icmp_apc_ctxt *ctx = (struct icmp_apc_ctxt *)ovr; + HANDLE thread; + BOOL ret; + + if (!ctx) return; + if (ctx->event) SetEvent( ctx->event ); + else if (ctx->apc_routine) + { + /* Don't access ctx after successful APC queue, it will be freed there. */ + thread = ctx->thread; + ctx->thread = NULL; + ret = QueueUserAPC( icmp_apc_routine, thread, (ULONG_PTR)ctx ); + CloseHandle( thread ); + if (ret) return; + } + heap_free( ctx ); +} + /*********************************************************************** * IcmpCloseHandle (IPHLPAPI.@) */ @@ -4696,7 +5137,13 @@ HANDLE WINAPI IcmpCreateFile( void ) heap_free( data ); return INVALID_HANDLE_VALUE; } - + if (!BindIoCompletionCallback( data->nsi_device, icmp_iocp_callback, 0 )) + { + ERR( "BindIoCompletionCallback failed.\n" ); + CloseHandle( data->nsi_device ); + heap_free( data ); + return INVALID_HANDLE_VALUE; + } return (HANDLE)data; } @@ -4735,96 +5182,114 @@ DWORD WINAPI IcmpSendEcho2( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_rou opts, reply, reply_size, timeout ); } -struct icmp_apc_ctxt -{ - void *apc_ctxt; - PIO_APC_ROUTINE apc_routine; - IO_STATUS_BLOCK iosb; -}; - -void WINAPI icmp_apc_routine( void *context, IO_STATUS_BLOCK *iosb, ULONG reserved ) -{ - struct icmp_apc_ctxt *ctxt = context; - - ctxt->apc_routine( ctxt->apc_ctxt, iosb, reserved ); - heap_free( ctxt ); -} - -/*********************************************************************** - * IcmpSendEcho2Ex (IPHLPAPI.@) - */ -DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_routine, void *apc_ctxt, - IPAddr src, IPAddr dst, void *request, WORD request_size, IP_OPTION_INFORMATION *opts, - void *reply, DWORD reply_size, DWORD timeout ) +static NTSTATUS icmp_send_echo( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_routine, void *apc_ctxt, + SOCKADDR_INET *src_addr, SOCKADDR_INET *dst_addr, void *request, + WORD request_size, IP_OPTION_INFORMATION *opts, void *reply, DWORD reply_size, + DWORD timeout ) { struct icmp_handle_data *data = (struct icmp_handle_data *)handle; - struct icmp_apc_ctxt *ctxt = heap_alloc( sizeof(*ctxt) ); - IO_STATUS_BLOCK *iosb = &ctxt->iosb; - DWORD opt_size, in_size, ret = 0; + struct icmp_apc_ctxt *ctxt = NULL; + IO_STATUS_BLOCK *iosb, iosb_local; + DWORD opt_size, in_size; struct nsiproxy_icmp_echo *in; - HANDLE request_event; + HANDLE request_event = NULL; NTSTATUS status; - if (handle == INVALID_HANDLE_VALUE || !reply) - { - heap_free( ctxt ); - SetLastError( ERROR_INVALID_PARAMETER ); - return 0; - } - - ctxt->apc_routine = apc_routine; - ctxt->apc_ctxt = apc_ctxt; + if (handle == INVALID_HANDLE_VALUE || !reply) return STATUS_INVALID_PARAMETER; opt_size = opts ? (opts->OptionsSize + 3) & ~3 : 0; in_size = FIELD_OFFSET(struct nsiproxy_icmp_echo, data[opt_size + request_size]); in = heap_alloc_zero( in_size ); - if (!in) - { - heap_free( ctxt ); - SetLastError( IP_NO_RESOURCES ); - return 0; - } + if (!in) return STATUS_NO_MEMORY; in->user_reply_ptr = (ULONG_PTR)reply; in->bits = sizeof(void*) * 8; - in->src.Ipv4.sin_family = AF_INET; - in->src.Ipv4.sin_addr.s_addr = src; - in->dst.Ipv4.sin_family = AF_INET; - in->dst.Ipv4.sin_addr.s_addr = dst; + in->src = *src_addr; + in->dst = *dst_addr; if (opts) { in->ttl = opts->Ttl; + in->hop_limit = opts->Ttl; in->tos = opts->Tos; in->flags = opts->Flags; memcpy( in->data, opts->OptionsData, opts->OptionsSize ); in->opt_size = opts->OptionsSize; } + else in->hop_limit = -1; in->req_size = request_size; in->timeout = timeout; memcpy( in->data + opt_size, request, request_size ); - request_event = event ? event : (apc_routine ? NULL : CreateEventW( NULL, 0, 0, NULL )); + if (event || apc_routine) + { + if (!(ctxt = heap_alloc( sizeof(*ctxt) ))) + { + heap_free( in ); + return STATUS_NO_MEMORY; + } + iosb = &ctxt->iosb; + ctxt->apc_routine = apc_routine; + ctxt->apc_ctxt = apc_ctxt; + ctxt->event = event; + ctxt->thread = NULL; + if (!event) + { + if (!DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), + &ctxt->thread, 0, FALSE, DUPLICATE_SAME_ACCESS )) + { + heap_free( ctxt ); + heap_free( in ); + return STATUS_NO_MEMORY; + } + } + } + else + { + iosb = &iosb_local; + request_event = CreateEventW( NULL, 0, 0, NULL ); + } - status = NtDeviceIoControlFile( data->nsi_device, request_event, apc_routine ? icmp_apc_routine : NULL, - apc_routine ? ctxt : apc_ctxt, iosb, IOCTL_NSIPROXY_WINE_ICMP_ECHO, + status = NtDeviceIoControlFile( data->nsi_device, request_event, NULL, ctxt, + iosb, IOCTL_NSIPROXY_WINE_ICMP_ECHO, in, in_size, reply, reply_size ); + if (!ctxt && status == STATUS_PENDING && !WaitForSingleObject( request_event, INFINITE )) + status = iosb->Status; - if (status == STATUS_PENDING) + if (request_event) CloseHandle( request_event ); + if (ctxt && status != STATUS_PENDING) { - if (!event && !apc_routine && !WaitForSingleObject( request_event, INFINITE )) - status = iosb->Status; + if (ctxt->thread) CloseHandle( ctxt->thread ); + heap_free( ctxt ); } - - if (!status) - ret = IcmpParseReplies( reply, reply_size ); - - if (!event && request_event) CloseHandle( request_event ); - if (!apc_routine || status != STATUS_PENDING) heap_free( ctxt ); heap_free( in ); + return status; +} - if (status) SetLastError( RtlNtStatusToDosError( status ) ); - return ret; +/*********************************************************************** + * IcmpSendEcho2Ex (IPHLPAPI.@) + */ +DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_routine, void *apc_ctxt, + IPAddr src, IPAddr dst, void *request, WORD request_size, IP_OPTION_INFORMATION *opts, + void *reply, DWORD reply_size, DWORD timeout ) +{ + SOCKADDR_INET src_addr, dst_addr; + NTSTATUS status; + + TRACE( "(%p %p %p %p %#lx %#lx %p %u %p %p %lu %lu).\n", handle, event, apc_routine, apc_ctxt, src, dst, + request, request_size, opts, reply, reply_size, timeout ); + + memset( &src_addr, 0, sizeof(src_addr) ); + src_addr.Ipv4.sin_family = AF_INET; + src_addr.Ipv4.sin_addr.s_addr = src; + memset( &dst_addr, 0, sizeof(dst_addr) ); + dst_addr.Ipv4.sin_family = AF_INET; + dst_addr.Ipv4.sin_addr.s_addr = dst; + status = icmp_send_echo( handle, event, apc_routine, apc_ctxt, &src_addr, &dst_addr, request, request_size, + opts, reply, reply_size, timeout ); + if (!status) return IcmpParseReplies( reply, reply_size ); + SetLastError( RtlNtStatusToDosError( status ) ); + return 0; } /*********************************************************************** @@ -4832,9 +5297,21 @@ DWORD WINAPI IcmpSendEcho2Ex( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_r */ HANDLE WINAPI Icmp6CreateFile( void ) { - FIXME( "stub\n" ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return INVALID_HANDLE_VALUE; + TRACE( ".\n" ); + + return IcmpCreateFile(); +} + +/****************************************************************** + * Icmp6ParseReplies (IPHLPAPI.@) + */ +DWORD WINAPI Icmp6ParseReplies( void *reply, DWORD reply_size ) +{ + ICMPV6_ECHO_REPLY *icmp_reply = reply; + + if (!icmp_reply->Status) return 1; + SetLastError( icmp_reply->Status ); + return 0; } /*********************************************************************** @@ -4844,9 +5321,20 @@ DWORD WINAPI Icmp6SendEcho2( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc_ro struct sockaddr_in6 *src, struct sockaddr_in6 *dst, void *request, WORD request_size, IP_OPTION_INFORMATION *opts, void *reply, DWORD reply_size, DWORD timeout ) { - FIXME( "(%p, %p, %p, %p, %p, %p, %p, %d, %p, %p, %ld, %ld): stub\n", handle, event, + SOCKADDR_INET src_addr, dst_addr; + NTSTATUS status; + + TRACE( "(%p, %p, %p, %p, %p, %p, %p, %d, %p, %p, %ld, %ld).\n", handle, event, apc_routine, apc_ctxt, src, dst, request, request_size, opts, reply, reply_size, timeout ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + + src_addr.Ipv6 = *src; + if (!src_addr.si_family) src_addr.si_family = AF_INET6; + dst_addr.Ipv6 = *dst; + if (!dst_addr.si_family) dst_addr.si_family = AF_INET6; + status = icmp_send_echo( handle, event, apc_routine, apc_ctxt, &src_addr, &dst_addr, request, request_size, + opts, reply, reply_size, timeout ); + if (!status) return Icmp6ParseReplies( reply, reply_size ); + SetLastError( RtlNtStatusToDosError( status ) ); return 0; } diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c index 397b2e8fad90..3d3c64e4b85b 100644 --- a/dlls/iphlpapi/tests/iphlpapi.c +++ b/dlls/iphlpapi/tests/iphlpapi.c @@ -35,6 +35,8 @@ */ #include +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "winsock2.h" #include "windef.h" #include "winbase.h" @@ -67,6 +69,8 @@ static DWORD (WINAPI *pParseNetworkString)(const WCHAR*,DWORD,NET_ADDRESS_INFO*, static DWORD (WINAPI *pNotifyUnicastIpAddressChange)(ADDRESS_FAMILY, PUNICAST_IPADDRESS_CHANGE_CALLBACK, PVOID, BOOLEAN, HANDLE *); static DWORD (WINAPI *pCancelMibChangeNotify2)(HANDLE); +static DWORD (WINAPI *pGetIpInterfaceEntry)(MIB_IPINTERFACE_ROW*); +static DWORD (WINAPI *pGetIpInterfaceTable)(ADDRESS_FAMILY family, MIB_IPINTERFACE_TABLE **table); DWORD WINAPI ConvertGuidToStringA( const GUID *, char *, DWORD ); DWORD WINAPI ConvertGuidToStringW( const GUID *, WCHAR *, DWORD ); @@ -88,6 +92,8 @@ static void loadIPHlpApi(void) pParseNetworkString = (void *)GetProcAddress(hLibrary, "ParseNetworkString"); pNotifyUnicastIpAddressChange = (void *)GetProcAddress(hLibrary, "NotifyUnicastIpAddressChange"); pCancelMibChangeNotify2 = (void *)GetProcAddress(hLibrary, "CancelMibChangeNotify2"); + pGetIpInterfaceTable = (void *)GetProcAddress(hLibrary, "GetIpInterfaceTable"); + pGetIpInterfaceEntry = (void *)GetProcAddress(hLibrary, "GetIpInterfaceEntry"); } } @@ -939,34 +945,55 @@ static void testSetTcpEntry(void) } static BOOL icmp_send_echo_test_apc_expect; -static void WINAPI icmp_send_echo_test_apc_xp(void *context) +static int icmp_send_echo_test_line; +static IO_STATUS_BLOCK icmp_send_echo_io; + +static void WINAPI icmp_send_echo_test_apc(void *context, IO_STATUS_BLOCK *io_status, ULONG reserved) { - ok(icmp_send_echo_test_apc_expect, "Unexpected APC execution\n"); - ok(context == (void*)0xdeadc0de, "Wrong context: %p\n", context); + ok_(__FILE__, icmp_send_echo_test_line)(icmp_send_echo_test_apc_expect, "Unexpected APC execution\n"); + ok_(__FILE__, icmp_send_echo_test_line)(!reserved, "Got reserved %#lx\n", reserved); + ok_(__FILE__, icmp_send_echo_test_line)(context == (void*)0xdeadc0de, "Wrong context: %p\n", context); icmp_send_echo_test_apc_expect = FALSE; + icmp_send_echo_io = *io_status; } -static void WINAPI icmp_send_echo_test_apc(void *context, IO_STATUS_BLOCK *io_status, ULONG reserved) +struct test_echo_thread_params { - icmp_send_echo_test_apc_xp(context); - ok(io_status->Status == 0, "Got IO Status 0x%08lx\n", io_status->Status); - ok(io_status->Information == sizeof(ICMP_ECHO_REPLY) + 32 /* sizeof(senddata) */, - "Got IO Information %Iu\n", io_status->Information); + HANDLE icmp; + HANDLE event; + PIO_APC_ROUTINE apc; + void *apc_context; + IPAddr address; + char *senddata; + DWORD send_data_size; + char *replydata; + DWORD replysz; + DWORD timeout; +}; + +static DWORD CALLBACK test_echo_thread(void *params) +{ + struct test_echo_thread_params *p = params; + BOOL ret; + + ret = IcmpSendEcho2(p->icmp, p->event, p->apc, p->apc_context, p->address, p->senddata, p->send_data_size, + NULL, p->replydata, p->replysz, p->timeout); + ok(!ret && GetLastError() == ERROR_IO_PENDING, "got ret %d, error %ld.\n", ret, GetLastError()); + return 0; } static void testIcmpSendEcho(void) { /* The APC's signature is different pre-Vista */ - const PIO_APC_ROUTINE apc = broken(LOBYTE(LOWORD(GetVersion())) < 6) - ? (PIO_APC_ROUTINE)icmp_send_echo_test_apc_xp - : icmp_send_echo_test_apc; HANDLE icmp; char senddata[32], replydata[sizeof(senddata) + sizeof(ICMP_ECHO_REPLY)]; char replydata2[sizeof(replydata) + sizeof(IO_STATUS_BLOCK)]; DWORD ret, error, replysz = sizeof(replydata); + struct test_echo_thread_params p; + IP_OPTION_INFORMATION opt; IPAddr address; ICMP_ECHO_REPLY *reply; - HANDLE event; + HANDLE event, thread; INT i; memset(senddata, 0, sizeof(senddata)); @@ -1023,6 +1050,12 @@ static void testIcmpSendEcho(void) error = GetLastError(); ok (ret, "IcmpSendEcho failed unexpectedly with error %ld\n", error); + memset(&opt, 0, sizeof(opt)); + SetLastError(0xdeadbeef); + ret = IcmpSendEcho(icmp, address, NULL, 0, &opt, replydata, replysz, 1000); + error = GetLastError(); + ok (ret, "IcmpSendEcho failed unexpectedly with error %ld\n", error); + SetLastError(0xdeadbeef); ret = IcmpSendEcho(icmp, address, senddata, sizeof(senddata), NULL, NULL, replysz, 1000); error = GetLastError(); @@ -1236,6 +1269,12 @@ static void testIcmpSendEcho(void) ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, senddata, ICMP_MINLEN, NULL, replydata2, replysz, 1000); ok(ret, "IcmpSendEcho2 failed unexpectedly with error %ld\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = IcmpSendEcho2Ex(icmp, NULL, NULL, NULL, 0x01010101, address, senddata, ICMP_MINLEN, NULL, replydata2, replysz, 1000); + ok(!ret, "IcmpSendEcho2 succeded unexpectedly\n"); + error = GetLastError(); + ok(error == ERROR_INVALID_NETNAME, "got %ld\n", error); + SetLastError(0xdeadbeef); replysz = sizeof(replydata2); ret = IcmpSendEcho2(icmp, NULL, NULL, NULL, address, senddata, sizeof(senddata), NULL, replydata2, replysz, 1000); @@ -1271,6 +1310,37 @@ static void testIcmpSendEcho(void) ok(!memcmp(senddata, reply->Data, min(sizeof(senddata), reply->DataSize)), "Data mismatch\n"); /* asynchronous tests with event */ + + replysz = sizeof(replydata2); + ResetEvent(event); + p.icmp = icmp; + p.event = event; + p.apc = icmp_send_echo_test_apc; + p.apc_context = (void *)0xdeadbeef; + ret = inet_pton(AF_INET, "192.18.1.1", &address); + ok(ret, "got error %u.\n", WSAGetLastError()); + p.address = address; + p.senddata = senddata; + p.send_data_size = sizeof(senddata); + p.replydata = replydata2; + p.replysz = replysz; + p.timeout = 30; + memset(replydata2, 0xcc, sizeof(replydata2)); + reply = (ICMP_ECHO_REPLY*)replydata2; + thread = CreateThread(NULL, 0, test_echo_thread, &p, 0, NULL); + + ret = WaitForSingleObject(thread, INFINITE); + ok(ret == WAIT_OBJECT_0, "got %lu.\n", ret); + IcmpCloseHandle(icmp); /* completion is delivered even if icmp handle is closed */ + icmp = IcmpCreateFile(); + ok (icmp != INVALID_HANDLE_VALUE, "IcmpCreateFile failed unexpectedly with error %ld\n", GetLastError()); + + CloseHandle(thread); + ret = WaitForSingleObject(event, INFINITE); + ok(ret == WAIT_OBJECT_0, "got %lu.\n", ret); + ok(reply->Status == IP_REQ_TIMED_OUT, "Expect status: 0x%08x, got: 0x%08lx\n", IP_REQ_TIMED_OUT, reply->Status); + ok(!reply->DataSize, "got size %d.\n", reply->DataSize); + SetLastError(0xdeadbeef); replysz = sizeof(replydata2); address = htonl(INADDR_LOOPBACK); @@ -1285,6 +1355,9 @@ static void testIcmpSendEcho(void) { ok(!ret, "IcmpSendEcho2 returned success unexpectedly\n"); ok(error == ERROR_IO_PENDING, "Expect last error: 0x%08x, got: 0x%08lx\n", ERROR_IO_PENDING, error); + IcmpCloseHandle(icmp); /* completion is delivered even if icmp handle is closed */ + icmp = IcmpCreateFile(); + ok (icmp != INVALID_HANDLE_VALUE, "IcmpCreateFile failed unexpectedly with error %ld\n", GetLastError()); ret = WaitForSingleObjectEx(event, 2000, TRUE); ok(ret == WAIT_OBJECT_0, "WaitForSingleObjectEx failed unexpectedly with %lu\n", ret); reply = (ICMP_ECHO_REPLY*)replydata2; @@ -1322,6 +1395,22 @@ static void testIcmpSendEcho(void) /* pre-Vista, reply->Data is an offset; otherwise it's a pointer, so hardcode the offset */ ok(!memcmp(senddata, reply + 1, min(sizeof(senddata), reply->DataSize)), "Data mismatch\n"); + SetLastError(0xdeadbeef); + for (i = 0; i < ARRAY_SIZE(senddata); i++) senddata[i] = i & 0xff; + ret = IcmpSendEcho2(icmp, event, icmp_send_echo_test_apc, NULL, address, senddata, sizeof(senddata), + NULL, replydata2, replysz, 1000); + error = GetLastError(); + ok(!ret, "IcmpSendEcho2 returned success unexpectedly\n"); + ok(error == ERROR_IO_PENDING, "Expect last error: 0x%08x, got: 0x%08lx\n", ERROR_IO_PENDING, error); + ret = WaitForSingleObjectEx(event, 2000, TRUE); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObjectEx failed unexpectedly with %lu\n", ret); + reply = (ICMP_ECHO_REPLY*)replydata2; + ok(ntohl(reply->Address) == INADDR_LOOPBACK, "Address mismatch, expect: %s, got: %s\n", ntoa(INADDR_LOOPBACK), + ntoa(reply->Address)); + ok(reply->Status == IP_SUCCESS, "Expect status: 0x%08x, got: 0x%08lx\n", IP_SUCCESS, reply->Status); + ok(reply->DataSize == sizeof(senddata), "Got size: %d\n", reply->DataSize); + ok(!memcmp(senddata, reply + 1, min(sizeof(senddata), reply->DataSize)), "Data mismatch\n"); + CloseHandle(event); /* asynchronous tests with APC */ @@ -1330,16 +1419,22 @@ static void testIcmpSendEcho(void) address = htonl(INADDR_LOOPBACK); for (i = 0; i < ARRAY_SIZE(senddata); i++) senddata[i] = ~i & 0xff; icmp_send_echo_test_apc_expect = TRUE; - /* - NOTE: Supplying both event and apc has varying behavior across Windows versions, so not tested. - */ - ret = IcmpSendEcho2(icmp, NULL, apc, (void*)0xdeadc0de, address, senddata, sizeof(senddata), NULL, replydata2, replysz, 1000); + memset(&icmp_send_echo_io, 0xcc, sizeof(icmp_send_echo_io)); + icmp_send_echo_test_line = __LINE__; + ret = IcmpSendEcho2(icmp, NULL, icmp_send_echo_test_apc, (void*)0xdeadc0de, address, senddata, sizeof(senddata), + NULL, replydata2, replysz, 1000); error = GetLastError(); ok(!ret, "IcmpSendEcho2 returned success unexpectedly\n"); ok(error == ERROR_IO_PENDING, "Expect last error: 0x%08x, got: 0x%08lx\n", ERROR_IO_PENDING, error); + IcmpCloseHandle(icmp); + icmp = IcmpCreateFile(); + ok (icmp != INVALID_HANDLE_VALUE, "IcmpCreateFile failed unexpectedly with error %ld\n", GetLastError()); + SleepEx(200, TRUE); SleepEx(0, TRUE); ok(icmp_send_echo_test_apc_expect == FALSE, "APC was not executed!\n"); + ok(!icmp_send_echo_io.Status, "got %#lx.\n", icmp_send_echo_io.Status); + ok(icmp_send_echo_io.Information == sizeof(replydata), "got %Iu.\n", icmp_send_echo_io.Information); reply = (ICMP_ECHO_REPLY*)replydata2; ok(ntohl(reply->Address) == INADDR_LOOPBACK, "Address mismatch, expect: %s, got: %s\n", ntoa(INADDR_LOOPBACK), ntoa(reply->Address)); @@ -1385,6 +1480,184 @@ static void testIcmpParseReplies( void ) ok( !reply.Reserved, "reserved %d\n", reply.Reserved ); } +static void test_Icmp6SendEcho(void) +{ + char senddata[32], replydata[sizeof(senddata) + sizeof(ICMPV6_ECHO_REPLY)]; + struct sockaddr_in6 src_addr, address; + IP_OPTION_INFORMATION opt; + ICMPV6_ECHO_REPLY *reply; + DWORD ret, replysz; + char str[256]; + HANDLE event; + HANDLE icmp; + + icmp = Icmp6CreateFile(); + ok(icmp != INVALID_HANDLE_VALUE, "got error %ld.\n", GetLastError()); + + memset(senddata, 0xdd, sizeof(senddata)); + + memset(&src_addr, 0, sizeof(src_addr)); + memset(&address, 0, sizeof(address)); + ret = inet_pton( AF_INET6, "::1", &address.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + + SetLastError(0xdeadbeef); + replysz = sizeof(replydata); + memset(replydata, 0xcc, sizeof(replydata)); + reply = (ICMPV6_ECHO_REPLY*)replydata; + ret = Icmp6SendEcho2(icmp, NULL, NULL, NULL, &src_addr, &address, senddata, sizeof(senddata), NULL, + replydata, replysz, 1000); + todo_wine_if(!ret && GetLastError() == ERROR_ACCESS_DENIED) + ok(ret == 1, "got ret %lu, error %ld.\n", ret, GetLastError()); + if (!ret) + { + skip( "ipv6 ping is prohibited.\n" ); + IcmpCloseHandle(icmp); + return; + } + ok(!GetLastError(), "got %ld.\n", GetLastError()); + ok(!reply->Status, "got %lu.\n", reply->Status); + ok(!memcmp(reply->Address.sin6_addr, &address.sin6_addr, sizeof(address.sin6_addr)), "got %s.\n", + inet_ntop(AF_INET6, (void *)&reply->Address.sin6_addr, str, sizeof(str))); + ok(!reply->Address.sin6_port, "got %#x.\n", reply->Address.sin6_port); + ok(!reply->Address.sin6_flowinfo, "got %#lx.\n", reply->Address.sin6_flowinfo); + ok(!reply->Address.sin6_scope_id, "got %#lx.\n", reply->Address.sin6_scope_id); + ok(!memcmp(reply + 1, senddata, sizeof(senddata)), "reply data does not match.\n"); + + memset(&src_addr, 0, sizeof(src_addr)); + memset(&address, 0, sizeof(address)); + memset(&opt, 0, sizeof(opt)); + ret = inet_pton( AF_INET6, "::1", &address.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + ret = inet_pton( AF_INET6, "::1", &src_addr.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + memset(replydata, 0xcc, sizeof(replydata)); + ret = Icmp6SendEcho2(icmp, NULL, NULL, NULL, &src_addr, &address, senddata, sizeof(senddata), &opt, + replydata, replysz, 1000); + ok(!ret && GetLastError() == IP_GENERAL_FAILURE, "got ret %#lx, error %ld.\n", ret, GetLastError()); + ok(reply->Status == IP_GENERAL_FAILURE, "got %#lx.\n", reply->Status); + + opt.Ttl = 1; + ret = Icmp6SendEcho2(icmp, NULL, NULL, NULL, &src_addr, &address, senddata, sizeof(senddata), &opt, + replydata, replysz, 1000); + ok(ret == 1, "got ret %lu, error %ld.\n", ret, GetLastError()); + ok(!GetLastError(), "got %ld.\n", GetLastError()); + ok(!reply->Status, "got %#lx.\n", reply->Status); + ok(!memcmp(reply->Address.sin6_addr, &address.sin6_addr, sizeof(address.sin6_addr)), "got %s.\n", + inet_ntop(AF_INET6, (void *)&reply->Address.sin6_addr, str, sizeof(str))); + ok(!reply->Address.sin6_port, "got %#x.\n", reply->Address.sin6_port); + ok(!reply->Address.sin6_flowinfo, "got %#lx.\n", reply->Address.sin6_flowinfo); + ok(!reply->Address.sin6_scope_id, "got %#lx.\n", reply->Address.sin6_scope_id); + ok(!memcmp(reply + 1, senddata, sizeof(senddata)), "reply data does not match.\n"); + + memset(&src_addr, 0, sizeof(src_addr)); + memset(&address, 0, sizeof(address)); + event = CreateEventW(NULL, FALSE, FALSE, NULL); + + icmp_send_echo_test_apc_expect = FALSE; + icmp_send_echo_test_line = __LINE__; + memset(&icmp_send_echo_io, 0xcc, sizeof(icmp_send_echo_io)); + memset(replydata, 0xcc, sizeof(replydata)); + replysz = sizeof(replydata); + ret = Icmp6SendEcho2(icmp, NULL, icmp_send_echo_test_apc, (void*)0xdeadc0de, &src_addr, &address, senddata, + sizeof(senddata), NULL, replydata, replysz, 1000); + ok(!ret && GetLastError() == ERROR_INVALID_NETNAME, "got ret %lu, error %ld.\n", ret, GetLastError()); + + ret = inet_pton( AF_INET6, "::1", &address.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + + icmp_send_echo_test_apc_expect = TRUE; + icmp_send_echo_test_line = __LINE__; + memset(&icmp_send_echo_io, 0xcc, sizeof(icmp_send_echo_io)); + memset(replydata, 0xcc, sizeof(replydata)); + replysz = sizeof(replydata); + ret = Icmp6SendEcho2(icmp, NULL, icmp_send_echo_test_apc, (void*)0xdeadc0de, &src_addr, &address, senddata, + sizeof(senddata), NULL, replydata, replysz, 1000); + ok(!ret && GetLastError() == ERROR_IO_PENDING, "got ret %lu, error %ld.\n", ret, GetLastError()); + ret = WaitForSingleObjectEx(event, INFINITE, TRUE); + ok(ret == WAIT_IO_COMPLETION, "got %#lx.\n", ret); + ok(!icmp_send_echo_io.Status, "got %#lx.\n", icmp_send_echo_io.Status); + ok(icmp_send_echo_io.Information == sizeof(replydata), "got %Iu.\n", icmp_send_echo_io.Information); + ok(!reply->Status, "got %#lx.\n", reply->Status); + ok(!icmp_send_echo_test_apc_expect, "APC was not called.\n"); + ok(!memcmp(reply->Address.sin6_addr, &address.sin6_addr, sizeof(address.sin6_addr)), "got %s.\n", + inet_ntop(AF_INET6, (void *)&reply->Address.sin6_addr, str, sizeof(str))); + ok(!reply->Address.sin6_port, "got %#x.\n", reply->Address.sin6_port); + ok(!reply->Address.sin6_flowinfo, "got %#lx.\n", reply->Address.sin6_flowinfo); + ok(!reply->Address.sin6_scope_id, "got %#lx.\n", reply->Address.sin6_scope_id); + ok(!memcmp(reply + 1, senddata, sizeof(senddata)), "reply data does not match.\n"); + + ret = inet_pton( AF_INET6, "::1", &address.sin6_addr); + icmp_send_echo_test_apc_expect = FALSE; + icmp_send_echo_test_line = __LINE__; + memset(replydata, 0xcc, sizeof(replydata)); + replysz = sizeof(replydata); + ret = Icmp6SendEcho2(icmp, event, icmp_send_echo_test_apc, (void*)0xdeadc0de, &src_addr, &address, senddata, + sizeof(senddata), NULL, replydata, replysz, 1000); + ok(!ret && GetLastError() == ERROR_IO_PENDING, "got ret %lu, error %ld.\n", ret, GetLastError()); + ret = WaitForSingleObjectEx(event, INFINITE, TRUE); + ok(ret == WAIT_OBJECT_0, "got %#lx.\n", ret); + icmp_send_echo_test_line = __LINE__; + SleepEx(0, TRUE); + ok(!reply->Status, "got %#lx.\n", reply->Status); + ok(!memcmp(reply->Address.sin6_addr, &address.sin6_addr, sizeof(address.sin6_addr)), "got %s.\n", + inet_ntop(AF_INET6, (void *)&reply->Address.sin6_addr, str, sizeof(str))); + ok(!reply->Address.sin6_port, "got %#x.\n", reply->Address.sin6_port); + ok(!reply->Address.sin6_flowinfo, "got %#lx.\n", reply->Address.sin6_flowinfo); + ok(!reply->Address.sin6_scope_id, "got %#lx.\n", reply->Address.sin6_scope_id); + ok(!memcmp(reply + 1, senddata, sizeof(senddata)), "reply data does not match.\n"); + + memset(replydata, 0xcc, sizeof(replydata)); + replysz = sizeof(replydata); + opt.Ttl = 0; + icmp_send_echo_test_apc_expect = TRUE; + icmp_send_echo_test_line = __LINE__; + memset(&icmp_send_echo_io, 0xcc, sizeof(icmp_send_echo_io)); + ret = Icmp6SendEcho2(icmp, NULL, icmp_send_echo_test_apc, (void*)0xdeadc0de, &src_addr, &address, senddata, + sizeof(senddata), &opt, replydata, replysz, 1000); + ok(!ret && GetLastError() == ERROR_IO_PENDING, "got ret %lu, error %ld.\n", ret, GetLastError()); + ret = WaitForSingleObjectEx(event, INFINITE, TRUE); + ok(ret == WAIT_IO_COMPLETION, "got %#lx.\n", ret); + ok(!icmp_send_echo_test_apc_expect, "APC was not called.\n"); + todo_wine ok(icmp_send_echo_io.Status == STATUS_INVALID_PARAMETER, "got %#lx.\n", icmp_send_echo_io.Status); + ok(icmp_send_echo_io.Information == sizeof(ICMPV6_ECHO_REPLY), "got %Iu.\n", icmp_send_echo_io.Information); + ok(reply->Status == IP_GENERAL_FAILURE, "got %#lx.\n", reply->Status); + ok(IN6_IS_ADDR_UNSPECIFIED((IN6_ADDR *)&reply->Address.sin6_addr), "got %s.\n", + inet_ntop(AF_INET6, (void *)&reply->Address.sin6_addr, str, sizeof(str))); + ok(!reply->Address.sin6_port, "got %#x.\n", reply->Address.sin6_port); + ok(!reply->Address.sin6_flowinfo, "got %#lx.\n", reply->Address.sin6_flowinfo); + ok(!reply->Address.sin6_scope_id, "got %#lx.\n", reply->Address.sin6_scope_id); + + ResetEvent(event); + ret = inet_pton( AF_INET6, "::ffff", &src_addr.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + ret = Icmp6SendEcho2(icmp, event, NULL, NULL, &src_addr, &address, senddata, + sizeof(senddata), NULL, replydata, replysz, 1000); + ok(!ret && GetLastError() == ERROR_INVALID_NETNAME, "got ret %lu, error %ld.\n", ret, GetLastError()); + + CloseHandle(event); + ret = IcmpCloseHandle(icmp); + ok(ret, "got error %u.\n", WSAGetLastError()); +} + +static void testIcmp6ParseReplies( void ) +{ + ICMPV6_ECHO_REPLY reply = { 0 }; + DWORD ret; + + SetLastError( 0xdeadbeef ); + ret = Icmp6ParseReplies( &reply, sizeof(reply) ); + ok( ret == 1, "got %ld.\n", ret ); + ok( GetLastError() == 0xdeadbeef, "got error %ld.\n", GetLastError() ); + + reply.Status = 12345; + SetLastError( 0xdeadbeef ); + ret = Icmp6ParseReplies( &reply, sizeof(reply) ); + ok( ret == 0, "ret %ld\n", ret ); + ok( GetLastError() == 12345, "got error %ld.\n", GetLastError() ); + ok( reply.Status == 12345, "got %ld,\n", reply.Status ); +} + static void testWinNT4Functions(void) { testGetNumberOfInterfaces(); @@ -1405,6 +1678,8 @@ static void testWinNT4Functions(void) testSetTcpEntry(); testIcmpSendEcho(); testIcmpParseReplies(); + test_Icmp6SendEcho(); + testIcmp6ParseReplies(); } static void testGetInterfaceInfo(void) @@ -1602,26 +1877,34 @@ static void testGetBestInterfaceEx(void) static void testGetBestRoute(void) { - DWORD apiReturn; + MIB_IFROW if_row; + DWORD err; MIB_IPFORWARDROW bestRoute; - apiReturn = GetBestRoute( INADDR_ANY, 0, &bestRoute ); - trace( "GetBestRoute([0.0.0.0], 0, [...]) = %lu\n", apiReturn ); - if (apiReturn == ERROR_NOT_SUPPORTED) + err = GetBestRoute( INADDR_ANY, 0, &bestRoute ); + trace( "GetBestRoute([0.0.0.0], 0, [...]) = %lu\n", err ); + if (err == ERROR_NOT_SUPPORTED) { skip( "GetBestRoute is not supported\n" ); return; } - apiReturn = GetBestRoute( INADDR_ANY, 0, NULL ); - ok( apiReturn == ERROR_INVALID_PARAMETER, + err = GetBestRoute( INADDR_ANY, 0, NULL ); + ok( err == ERROR_INVALID_PARAMETER, "GetBestRoute([0.0.0.0], 0, NULL) returned %lu, expected %d\n", - apiReturn, ERROR_INVALID_PARAMETER ); + err, ERROR_INVALID_PARAMETER ); - apiReturn = GetBestRoute( INADDR_LOOPBACK, 0, &bestRoute ); - ok( apiReturn == NO_ERROR, + memset( &bestRoute, 0xcc, sizeof(bestRoute)); + err = GetBestRoute( htonl( INADDR_LOOPBACK ), 0, &bestRoute ); + ok( err == NO_ERROR, "GetBestRoute([127.0.0.1], 0, NULL) returned %lu, expected %d\n", - apiReturn, NO_ERROR ); + err, NO_ERROR ); + ok( bestRoute.dwForwardMask == 0xffffffff, "got %#lx.\n", bestRoute.dwForwardMask ); + + if_row.dwIndex = bestRoute.dwForwardIfIndex; + err = GetIfEntry( &if_row ); + ok( !err, "got %lu.\n", err ); + ok( if_row.dwType == IF_TYPE_SOFTWARE_LOOPBACK, "got %#lx.\n", if_row.dwType ); } /* @@ -1928,6 +2211,7 @@ static void test_GetExtendedTcpTable(void) we make, and associates it with our process. */ static void test_GetExtendedTcpTable_owner( int family ) { + BOOL found_it; SOCKET sock; int port; DWORD i, ret; @@ -1983,7 +2267,7 @@ static void test_GetExtendedTcpTable_owner( int family ) if (family == AF_INET) { MIB_TCPTABLE_OWNER_PID *table = raw_table; - BOOL found_it = FALSE; + found_it = FALSE; for (i = 0; i < table->dwNumEntries; i++) { MIB_TCPROW_OWNER_PID *row = &table->table[i]; @@ -2000,7 +2284,7 @@ static void test_GetExtendedTcpTable_owner( int family ) else { MIB_TCP6TABLE_OWNER_PID *table = raw_table; - BOOL found_it = FALSE; + found_it = FALSE; for (i = 0; i < table->dwNumEntries; i++) { MIB_TCP6ROW_OWNER_PID *row = &table->table[i]; @@ -2015,6 +2299,186 @@ static void test_GetExtendedTcpTable_owner( int family ) ok( found_it, "no table entry for socket\n" ); } + free( raw_table ); + raw_table = NULL; + ret = get_extended_tcp_table( family, TCP_TABLE_OWNER_MODULE_ALL, &raw_table ); + if (ret != ERROR_SUCCESS) + { + skip( "error %lu getting TCP table\n", ret ); + goto done; + } + + if (family == AF_INET) + { + MIB_TCPTABLE_OWNER_MODULE *t = raw_table; + TCPIP_OWNER_MODULE_BASIC_INFO *info; + MIB_TCPROW_OWNER_MODULE entry; + WCHAR mod[MAX_PATH], *name; + DWORD sz, expected, name_len; + BYTE buf[MAX_PATH + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 128]; + HANDLE process; + char *p; + + info = (TCPIP_OWNER_MODULE_BASIC_INFO *)buf; + + mod[0] = 0; + GetModuleFileNameW( NULL, mod, ARRAY_SIZE(mod) ); + name = wcsrchr( mod, '\\' ); + ok( !!name, "could not get name, mod %s.\n", debugstr_w(mod) ); + ++name; + name_len = (wcslen( name ) + 1) * sizeof(WCHAR); + expected = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + name_len + (wcslen( mod ) + 1) * sizeof(WCHAR); + memset( &entry, 0, sizeof(entry) ); + + sz = sizeof(buf); + ret = GetOwnerModuleFromTcpEntry( NULL, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret ); + + entry.dwOwningPid = 0; + ret = GetOwnerModuleFromTcpEntry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_NOT_FOUND, "got %lu.\n", ret ); + + entry.dwOwningPid = 0xffff; + ret = GetOwnerModuleFromTcpEntry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret ); + + entry.dwOwningPid = GetCurrentProcessId(); + sz = 1; + ret = GetOwnerModuleFromTcpEntry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INSUFFICIENT_BUFFER, "got %lu.\n", ret ); + ok( sz == expected, "got %lu, expected %lu.\n", sz, expected ); + + ret = GetOwnerModuleFromTcpEntry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( !ret, "got %lu.\n", ret ); + + p = (char *)(info + 1); + ok( (char *)info->pModuleName == p, "got %p, %p.\n", info, p ); + p += name_len; + ok( (char *)info->pModulePath == p, "got %p, %p.\n", info, p); + ok( !wcscmp( info->pModuleName, name ), "got %s, %s.\n", debugstr_w(info->pModuleName), debugstr_w(name) ); + + found_it = FALSE; + for (i = 0; i < t->dwNumEntries; ++i) + { + info = (TCPIP_OWNER_MODULE_BASIC_INFO *)buf; + + memset(buf, 0xcc, sizeof(buf)); + sz = sizeof(buf) + 1; + ret = GetOwnerModuleFromTcpEntry( &t->table[i], TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok(sz == sizeof(buf) + 1, "got %ld.\n", sz); + ok( !ret || ret == ERROR_NOT_FOUND || ret == ERROR_ACCESS_DENIED + || ret == ERROR_MOD_NOT_FOUND, + /* This is weird, newer Windows seems to return non-zero OwningModuleInfo[0] sometimes but then + * GetOwnerModuleFromTcp6Entry always fails with ERROR_MOD_NOT_FOUND, while that succeeds for the + * same PID in MIB_TCPTABLE_OWNER_MODULE and zeroed OwningModuleInfo */ + "got %#lx, pid %ld, info %#I64x.\n", ret, t->table[i].dwOwningPid, t->table[i].OwningModuleInfo[0] ); + + memset( &entry, 0, sizeof(entry) ); + entry.dwOwningPid = t->table[i].dwOwningPid; + if (entry.dwOwningPid == GetCurrentProcessId()) + found_it = TRUE; + ret = GetOwnerModuleFromTcpEntry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.dwOwningPid ); + ok( !ret || ret == ERROR_NOT_FOUND || ret == ERROR_ACCESS_DENIED, + "got %#lx, pid %ld, info %#I64x.\n", ret, t->table[i].dwOwningPid, t->table[i].OwningModuleInfo[0] ); + if (!ret && !wcscmp( info->pModuleName, L"System" )) + { + ok( !wcscmp( info->pModulePath, L"System" ), "got %s.\n", debugstr_w(info->pModulePath) ); + } + else if (ret == ERROR_ACCESS_DENIED) + { + process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.dwOwningPid ); + ok( !process && GetLastError() == ERROR_ACCESS_DENIED, "got process %p, err %lu.\n", process, GetLastError() ); + } + } + ok( found_it, "no table entry for socket\n" ); + } + else + { + MIB_TCP6TABLE_OWNER_MODULE *t = raw_table; + TCPIP_OWNER_MODULE_BASIC_INFO *info; + MIB_TCP6ROW_OWNER_MODULE entry; + WCHAR mod[MAX_PATH], *name; + DWORD sz, expected, name_len; + BYTE buf[MAX_PATH + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 128]; + HANDLE process; + char *p; + + info = (TCPIP_OWNER_MODULE_BASIC_INFO *)buf; + + mod[0] = 0; + GetModuleFileNameW( NULL, mod, ARRAY_SIZE(mod) ); + name = wcsrchr( mod, '\\' ); + ok( !!name, "could not get name, mod %s.\n", debugstr_w(mod) ); + ++name; + name_len = (wcslen( name ) + 1) * sizeof(WCHAR); + expected = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + name_len + (wcslen( mod ) + 1) * sizeof(WCHAR); + memset( &entry, 0, sizeof(entry) ); + + sz = sizeof(buf); + ret = GetOwnerModuleFromTcp6Entry( NULL, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret ); + + entry.dwOwningPid = 0; + ret = GetOwnerModuleFromTcp6Entry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_NOT_FOUND, "got %lu.\n", ret ); + + entry.dwOwningPid = 0xffff; + ret = GetOwnerModuleFromTcp6Entry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret ); + + entry.dwOwningPid = GetCurrentProcessId(); + sz = 1; + ret = GetOwnerModuleFromTcp6Entry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INSUFFICIENT_BUFFER, "got %lu.\n", ret ); + ok( sz == expected, "got %lu, expected %lu.\n", sz, expected ); + + ret = GetOwnerModuleFromTcp6Entry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( !ret, "got %lu.\n", ret ); + + p = (char *)(info + 1); + ok( (char *)info->pModuleName == p, "got %p, %p.\n", info, p ); + p += name_len; + ok( (char *)info->pModulePath == p, "got %p, %p.\n", info, p); + ok( !wcscmp( info->pModuleName, name ), "got %s, %s.\n", debugstr_w(info->pModuleName), debugstr_w(name) ); + + found_it = FALSE; + for (i = 0; i < t->dwNumEntries; ++i) + { + info = (TCPIP_OWNER_MODULE_BASIC_INFO *)buf; + + memset(buf, 0xcc, sizeof(buf)); + sz = sizeof(buf) + 1; + ret = GetOwnerModuleFromTcp6Entry( &t->table[i], TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok(sz == sizeof(buf) + 1, "got %ld.\n", sz); + ok( !ret || ret == ERROR_NOT_FOUND || ret == ERROR_ACCESS_DENIED + || ret == ERROR_MOD_NOT_FOUND, + /* This is weird, newer Windows seems to return non-zero OwningModuleInfo[0] sometimes but then + * GetOwnerModuleFromTcp6Entry always fails with ERROR_MOD_NOT_FOUND, while that succeeds for the + * same PID in MIB_TCPTABLE_OWNER_MODULE and zeroed OwningModuleInfo */ + "got %#lx, pid %ld, info %#I64x.\n", ret, t->table[i].dwOwningPid, t->table[i].OwningModuleInfo[0] ); + + memset( &entry, 0, sizeof(entry) ); + entry.dwOwningPid = t->table[i].dwOwningPid; + if (entry.dwOwningPid == GetCurrentProcessId()) + found_it = TRUE; + ret = GetOwnerModuleFromTcp6Entry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.dwOwningPid ); + ok( !ret || ret == ERROR_NOT_FOUND || ret == ERROR_ACCESS_DENIED, + "got %#lx, pid %ld, info %#I64x.\n", ret, t->table[i].dwOwningPid, t->table[i].OwningModuleInfo[0] ); + if (!ret && !wcscmp( info->pModuleName, L"System" )) + { + ok( !wcscmp( info->pModulePath, L"System" ), "got %s.\n", debugstr_w(info->pModulePath) ); + } + else if (ret == ERROR_ACCESS_DENIED) + { + process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.dwOwningPid ); + ok( !process && GetLastError() == ERROR_ACCESS_DENIED, "got process %p, err %lu.\n", process, GetLastError() ); + } + } + ok( found_it, "no table entry for socket\n" ); + } + done: closesocket( sock ); free( raw_table ); @@ -3106,6 +3570,589 @@ static void test_compartments(void) ok(id == NET_IF_COMPARTMENT_ID_PRIMARY, "got %u\n", id); } +static void test_GetIpInterface(void) +{ + MIB_IPINTERFACE_ROW entry_row; + MIB_IPINTERFACE_TABLE *table; + MIB_IF_ROW2 *if_info = NULL; + MIB_IPINTERFACE_ROW *row; + MIB_IF_TABLE2 *if_table; + unsigned int i, j; + BOOL connected, is_loopback, loopback_found = FALSE; + DWORD err; + + if (!pGetIpInterfaceTable || !pGetIpInterfaceEntry) + { + win_skip( "GetIpInterfaceTable or GetIpInterfaceEntry is not available\n" ); + return; + } + + err = GetIfTable2( &if_table ); + ok( !err, "got %ld\n", err ); + + err = pGetIpInterfaceTable( AF_UNSPEC, NULL ); + ok( err == ERROR_INVALID_PARAMETER, "got %lu.\n", err ); + + err = pGetIpInterfaceTable( AF_UNSPEC, &table ); + ok( !err, "got %lu.\n", err ); + for (i = 0; i < table->NumEntries; ++i) + { + row = &table->Table[i]; + ok( row->Family == AF_INET || row->Family == AF_INET6, "got %d.\n", row->Family ); + for (j = 0; j < if_table->NumEntries; ++j) + { + if_info = &if_table->Table[j]; + if (if_info->InterfaceIndex == row->InterfaceIndex) break; + } + ok( j < if_table->NumEntries, "could not find interface.\n" ); + ok( row->InterfaceLuid.Value == if_info->InterfaceLuid.Value, "luid doesn't match.\n" ); + is_loopback = (if_info->Type == IF_TYPE_SOFTWARE_LOOPBACK); + if (is_loopback) loopback_found = TRUE; + if (row->Family == AF_INET) + ok( row->SitePrefixLength == 64, "got %lu.\n", row->SitePrefixLength ); + if (is_loopback) + { + ok( !row->DadTransmits, "got %lu.\n", row->DadTransmits ); + ok( row->SitePrefixLength == 64, "got %lu.\n", row->SitePrefixLength ); + } + ok( row->MinRouterAdvertisementInterval == 200, "got %lu.\n", row->MinRouterAdvertisementInterval ); + ok( row->MaxRouterAdvertisementInterval == 600, "got %lu.\n", row->MaxRouterAdvertisementInterval ); + if (is_loopback) + todo_wine ok( row->NlMtu == ~0u, "got %lu.\n", row->NlMtu ); + connected = (if_info->MediaConnectState == MediaConnectStateConnected); + ok( row->Connected == connected, "got %d, expected %d.\n", row->Connected, connected ); + + err = GetIpInterfaceEntry( NULL ); + ok( err == ERROR_INVALID_PARAMETER, "got %ld\n", err ); + + memset( &entry_row, 0, sizeof(entry_row) ); + entry_row.Family = AF_UNSPEC; + entry_row.InterfaceLuid = row->InterfaceLuid; + err = GetIpInterfaceEntry( &entry_row ); + ok( err == ERROR_INVALID_PARAMETER, "got %ld\n", err ); + + memset( &entry_row, 0xcc, sizeof(entry_row) ); + entry_row.Family = row->Family; + entry_row.InterfaceLuid = row->InterfaceLuid; + err = pGetIpInterfaceEntry( &entry_row ); + ok( !err, "got %ld\n", err ); + ok( entry_row.Family == row->Family, "got %d, expected %d.\n", entry_row.Family, row->Family ); + ok( entry_row.InterfaceLuid.Value == row->InterfaceLuid.Value, "got %#I64x, expected %#I64x.\n", + entry_row.InterfaceLuid.Value, row->InterfaceLuid.Value ); + ok( entry_row.InterfaceIndex == row->InterfaceIndex, "got %lu, expected %lu.\n", + entry_row.InterfaceIndex, row->InterfaceIndex ); + ok( entry_row.BaseReachableTime == row->BaseReachableTime, "got %lu, expected %lu.\n", + entry_row.BaseReachableTime, row->BaseReachableTime ); + + memset( &entry_row, 0xcc, sizeof(entry_row) ); + entry_row.Family = row->Family; + entry_row.InterfaceIndex = row->InterfaceIndex; + err = GetIpInterfaceEntry( &entry_row ); + ok( err == ERROR_NOT_FOUND, "got %ld\n", err ); + + memset( &entry_row, 0xcc, sizeof(entry_row) ); + entry_row.Family = row->Family; + entry_row.InterfaceLuid.Value = 0; + entry_row.InterfaceIndex = row->InterfaceIndex; + err = GetIpInterfaceEntry( &entry_row ); + ok( !err, "got %ld\n", err ); + ok( entry_row.Family == row->Family, "got %d, expected %d.\n", entry_row.Family, row->Family ); + ok( entry_row.InterfaceLuid.Value == row->InterfaceLuid.Value, "got %#I64x, expected %#I64x.\n", + entry_row.InterfaceLuid.Value, row->InterfaceLuid.Value ); + ok( entry_row.InterfaceIndex == row->InterfaceIndex, "got %lu, expected %lu.\n", + entry_row.InterfaceIndex, row->InterfaceIndex ); + ok( entry_row.BaseReachableTime == row->BaseReachableTime, "got %lu, expected %lu.\n", + entry_row.BaseReachableTime, row->BaseReachableTime ); + } + ok( loopback_found, "loopback not found.\n" ); + FreeMibTable( table ); + FreeMibTable( if_table ); +} + +static MIB_IPFORWARD_ROW2 *find_ipforward_row( MIB_IPFORWARD_TABLE2 *table, DWORD ifindex ) +{ + unsigned int i; + + for (i = 0; i < table->NumEntries; ++i) + { + if (ifindex == table->Table[i].InterfaceIndex) return &table->Table[i]; + } + return NULL; +} + +static void test_best_routes(void) +{ + static const IN6_ADDR link_local_prefix = {{ IN6ADDR_LINKLOCALPREFIX_INIT }}; + + DWORD ret, index, link_local_index = ~0u, loopback_index = ~0u, default_route_index = ~0u; + struct sockaddr_in6 dst6, src6, best6, link_local_addr6, global_addr6; + struct sockaddr_in dst4, src4, global_addr4; + NET_LUID link_local_luid = { 0 }, luid; + MIB_UNICASTIPADDRESS_ROW uni_row; + MIB_IPFORWARD_ROW2 fwd_row, *r; + MIB_IPFORWARD_TABLE2 *table; + char s[256], s2[256]; + SOCKADDR_INET best4; + unsigned int i; + + memset( &dst6, 0, sizeof(src6) ); + dst6.sin6_family = AF_INET6; + ret = inet_pton( AF_INET6, "::1", &dst6.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + ret = GetBestRoute2( NULL, 0, NULL, (SOCKADDR_INET *)&dst6, 0, NULL, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + ret = GetBestRoute2( NULL, 0, NULL, NULL, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + ret = GetBestRoute2( NULL, 0, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, NULL ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + + ret = GetIpForwardTable2( AF_INET6, &table ); + ok( !ret, "got error %lu.\n", ret ); + + for (i = 0; i < table->NumEntries; ++i) + { + if (IN6_IS_ADDR_LINKLOCAL(&table->Table[i].DestinationPrefix.Prefix.Ipv6.sin6_addr)) + { + if (link_local_index == ~0u) + { + link_local_index = table->Table[i].InterfaceIndex; + link_local_luid = table->Table[i].InterfaceLuid; + } + } + if (IN6_IS_ADDR_LOOPBACK(&table->Table[i].DestinationPrefix.Prefix.Ipv6.sin6_addr)) + loopback_index = table->Table[i].InterfaceIndex; + } + ok( link_local_index != ~0u, "could not find any link local route.\n" ); + ok( loopback_index != ~0u, "could not find loopback route.\n" ); + + /* Test with link local address. */ + memset( &dst6, 0, sizeof(dst6) ); + dst6.sin6_family = AF_INET6; + dst6.sin6_addr = link_local_prefix; + dst6.sin6_scope_id = link_local_index; + dst6.sin6_addr.u.Byte[15] = 1; + ret = GetBestInterfaceEx( (struct sockaddr *)&dst6, &index ); + ok( !ret, "got error %lu.\n", ret ); + ok( index == link_local_index, "got %lu, expected %lu.\n", index, link_local_index ); + + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + ret = GetBestRoute2( NULL, 0xdeadbeef, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_FILE_NOT_FOUND, "got error %lu.\n", ret ); + ok( !fwd_row.InterfaceIndex, "got %#lx.\n", fwd_row.InterfaceIndex ); + + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + dst6.sin6_scope_id = loopback_index; + ret = GetBestRoute2( NULL, link_local_index, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + ok( !fwd_row.InterfaceIndex, "got %#lx.\n", fwd_row.InterfaceIndex ); + + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + dst6.sin6_scope_id = link_local_index; + ret = GetBestRoute2( NULL, loopback_index, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + ok( !fwd_row.InterfaceIndex, "got %#lx.\n", fwd_row.InterfaceIndex ); + + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + dst6.sin6_scope_id = 0xdeadbeef; + ret = GetBestRoute2( NULL, link_local_index, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + ok( !fwd_row.InterfaceIndex, "got %#lx.\n", fwd_row.InterfaceIndex ); + + dst6.sin6_scope_id = link_local_index; + + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + memset( &best6, 0xcc, sizeof(best6) ); + ret = GetBestRoute2( NULL, link_local_index, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == link_local_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, link_local_index ); + ok( !fwd_row.Loopback, "got %d.\n", fwd_row.Loopback ); + ok( IN6_IS_ADDR_LINKLOCAL(&fwd_row.DestinationPrefix.Prefix.Ipv6.sin6_addr), "expected link local prefix.\n" ); + ok( IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr), "expected unspecifed address.\n" ); + ok( best6.sin6_family == AF_INET6, "got %u.\n", best6.sin6_family ); + ok( best6.sin6_scope_id == link_local_index, "got %lu, expected %lu.\n", best6.sin6_scope_id, link_local_index ); + memset( &uni_row, 0, sizeof(uni_row) ); + *(struct sockaddr_in6 *)&uni_row.Address = best6; + uni_row.InterfaceIndex = fwd_row.InterfaceIndex; + ret = GetUnicastIpAddressEntry( &uni_row ); + ok( !ret, "got error %lu.\n", ret ); + ok( !memcmp( &uni_row.Address, &best6, sizeof(best6) ), "got different address.\n" ); + link_local_addr6 = best6; + + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + dst6.sin6_scope_id = link_local_index; + ret = GetBestRoute2( &link_local_luid, 0xdeadbeef, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == link_local_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, link_local_index ); + ok( IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr), "expected unspecifed address.\n" ); + + dst6.sin6_scope_id = link_local_index; + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + ret = GetBestRoute2( NULL, 0, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == link_local_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, link_local_index ); + ok( !fwd_row.Loopback, "got %d.\n", fwd_row.Loopback ); + + dst6.sin6_scope_id = 0; + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + ret = GetBestRoute2( NULL, link_local_index, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == link_local_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, link_local_index ); + ok( !fwd_row.Loopback, "got %d.\n", fwd_row.Loopback ); + ok( best6.sin6_scope_id == link_local_index, "got %lu, expected %lu.\n", best6.sin6_scope_id, link_local_index ); + ok( IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr), "expected unspecifed address.\n" ); + + /* With both scope_id in destination address and interface unspecified Windows returns a row for a random + * matching route, not even necessarily a link local one. */ + dst6.sin6_scope_id = 0; + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + ret = GetBestRoute2( NULL, 0, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + r = find_ipforward_row( table, fwd_row.InterfaceIndex ); + ok( !!r, "got NULL.\n" ); + ok( best6.sin6_scope_id == fwd_row.InterfaceIndex, "got %lu, expected %lu.\n", best6.sin6_scope_id, + fwd_row.InterfaceIndex ); + ok( IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr), "expected unspecifed address.\n" ); + + dst6.sin6_scope_id = 0; + ret = GetBestInterfaceEx( (struct sockaddr *)&dst6, &index ); + ok( !ret, "got error %lu.\n", ret ); + r = find_ipforward_row( table, index ); + ok( !!r, "got NULL.\n" ); + + memset( &src6, 0, sizeof(src6) ); + src6.sin6_family = AF_INET6; + ret = inet_pton( AF_INET6, "dead:beaf:dead:beaf::beaf", &src6.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + dst6.sin6_scope_id = 0; + ret = GetBestRoute2( NULL, 0, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_NOT_FOUND, "got error %lu.\n", ret ); + + ret = GetBestRoute2( NULL, 0, (SOCKADDR_INET *)&link_local_addr6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( best6.sin6_scope_id == link_local_index, "got %lu, expected %lu.\n", best6.sin6_scope_id, link_local_index ); + + dst6.sin6_scope_id = 0; + ret = GetBestRoute2( &link_local_luid, 0, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_NOT_FOUND, "got error %lu.\n", ret ); + + dst6.sin6_scope_id = link_local_index; + ret = GetBestRoute2( &link_local_luid, 0, (SOCKADDR_INET *)&link_local_addr6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( best6.sin6_scope_id == link_local_index, "got %lu, expected %lu.\n", best6.sin6_scope_id, link_local_index ); + + /* src address with non-matching or unknown family is ignored. */ + src6.sin6_family = AF_INET; + ret = GetBestRoute2( NULL, 0, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + src6.sin6_family = 0xbeed; + ret = GetBestRoute2( NULL, 0, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + + /* zero src address is ignored. */ + memset( &src6, 0, sizeof(src6) ); + src6.sin6_family = AF_INET6; + ret = GetBestRoute2( NULL, 0, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + + /* Specified source address not matching destination, result is weird. */ + memset( &src6, 0, sizeof(src6) ); + src6.sin6_family = AF_INET6; + ret = inet_pton( AF_INET6, "::1", &src6.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + dst6.sin6_scope_id = 0; + memset( &best6, 0xcc, sizeof(best6) ); + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + ret = GetBestRoute2( &link_local_luid, 0, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + todo_wine ok( !ret, "got error %lu.\n", ret ); + todo_wine ok( !memcmp( &src6, &best6, sizeof(best6) ), "got different address %s.\n", + inet_ntop( AF_INET6, &best6.sin6_addr, s, sizeof(s) )); + ok( !fwd_row.InterfaceIndex, "got %lu.\n", fwd_row.InterfaceIndex ); + ok( IN6_IS_ADDR_UNSPECIFIED(&fwd_row.DestinationPrefix.Prefix.Ipv6.sin6_addr), "expected unspecifed address.\n" ); + + /* Specified source address takes precedence over specified interface. */ + dst6.sin6_scope_id = 0; + memset( &best6, 0xcc, sizeof(best6) ); + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + src6 = link_local_addr6; + src6.sin6_port = 1; + ret = GetBestRoute2( &link_local_luid, loopback_index, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == link_local_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, link_local_index ); + ok( !fwd_row.Loopback, "got %d.\n", fwd_row.Loopback ); + ok( best6.sin6_scope_id == link_local_index, "got %lu, expected %lu.\n", best6.sin6_scope_id, link_local_index ); + ok( !memcmp( &best6, &link_local_addr6, sizeof(best6) ), "got different address.\n" ); + + src6.sin6_scope_id = 0; + ret = GetBestRoute2( NULL, loopback_index, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == link_local_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, link_local_index ); + + src6.sin6_scope_id = 0xffff; + ret = GetBestRoute2( NULL, loopback_index, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_NOT_FOUND, "got error %lu.\n", ret ); + ok( !fwd_row.InterfaceIndex, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, link_local_index ); + + src6.sin6_scope_id = link_local_index; + ret = GetBestRoute2( NULL, loopback_index, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == link_local_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, link_local_index ); + + luid.Value = 0xdeadbeef; + ret = GetBestRoute2( &luid, 0xdeadbeef, (SOCKADDR_INET *)&link_local_addr6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == link_local_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, link_local_index ); + + /* ... but if iface index is specified without luid that will still fail for invalid index. */ + ret = GetBestRoute2( NULL, 0xdeadbeef, (SOCKADDR_INET *)&link_local_addr6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_FILE_NOT_FOUND, "got error %lu.\n", ret ); + + luid.Value = 0xdeadbeef; + ret = GetBestRoute2( &luid, 0xdeadbeef, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_NOT_FOUND, "got error %lu.\n", ret ); + + /* Test with global address. */ + ret = inet_pton( AF_INET6, "2ead:beaf:dead:beaf::beaf", &dst6.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + + dst6.sin6_scope_id = 0xdeadbeef; + ret = GetBestInterfaceEx( (struct sockaddr *)&dst6, &index ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + + dst6.sin6_scope_id = link_local_index; + ret = GetBestInterfaceEx( (struct sockaddr *)&dst6, &index ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + + dst6.sin6_scope_id = 0; + ret = GetBestInterfaceEx( (struct sockaddr *)&dst6, &index ); + if (ret == ERROR_NETWORK_UNREACHABLE) + { + skip( "Global IPv6 address is unreachable.\n" ); + goto loopback_ipv6; + } + ok( !ret, "got error %lu.\n", ret ); + r = find_ipforward_row( table, index ); + ok( !!r, "got NULL.\n" ); + default_route_index = index; + dst6.sin6_scope_id = index; + ret = GetBestInterfaceEx( (struct sockaddr *)&dst6, &index ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + + ret = GetBestRoute2( NULL, 0, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + + dst6.sin6_scope_id = 0; + ret = GetBestRoute2( NULL, 0, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == index, "got %lu, %lu.\n", fwd_row.InterfaceIndex, index ); + ok( !IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr) + || broken( IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr) /* Win10 1507-1709 */), + "got unspecified address.\n" ); + + ret = GetBestRoute2( NULL, index, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == index, "got %lu, %lu.\n", fwd_row.InterfaceIndex, index ); + global_addr6 = best6; + + memset( &src6, 0, sizeof(src6) ); + src6.sin6_family = AF_INET6; + ret = inet_pton( AF_INET6, "dead:beaf:dead:beaf::beaf", &src6.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + + ret = GetBestRoute2( NULL, 0, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_NOT_FOUND, "got error %lu.\n", ret ); + + src6 = global_addr6; + src6.sin6_port = 28; + ret = GetBestRoute2( NULL, link_local_index, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == index, "got %lu, %lu.\n", fwd_row.InterfaceIndex, index ); + ok( !best6.sin6_scope_id, "got %lu.\n", best6.sin6_scope_id ); + ok( !memcmp( &global_addr6, &best6, sizeof(best6) ), "got different address.\n" ); + ok( !IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr) + || broken( IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr) /* Win10 1507-1709 */), + "got unspecified address.\n" ); + + src6.sin6_scope_id = 1; + ret = GetBestRoute2( NULL, link_local_index, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + + memset( &src6, 0, sizeof(src6) ); + src6.sin6_family = AF_INET6; + ret = inet_pton( AF_INET6, "::1", &src6.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + memset( &best6, 0xcc, sizeof(best6) ); + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + ret = GetBestRoute2( NULL, 0, (SOCKADDR_INET *)&src6, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_NETWORK_UNREACHABLE, "got error %lu.\n", ret ); + ok( !fwd_row.InterfaceIndex, "got %lu.\n", fwd_row.InterfaceIndex ); + ok( !fwd_row.InterfaceLuid.Value, "got %#I64x.\n", fwd_row.InterfaceLuid.Value ); + ok( IN6_IS_ADDR_UNSPECIFIED(&best6.sin6_addr), "expected unspecifed address.\n" ); + ok( IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr), "expected unspecifed address.\n" ); + + luid.Value = 0; + ret = GetBestRoute2( &luid, 0xdeadbeef, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == index, "got %lu, %lu.\n", fwd_row.InterfaceIndex, index ); + ok( !best6.sin6_scope_id, "got %lu.\n", best6.sin6_scope_id ); + memset( &uni_row, 0, sizeof(uni_row) ); + *(struct sockaddr_in6 *)&uni_row.Address = best6; + uni_row.InterfaceIndex = fwd_row.InterfaceIndex; + ret = GetUnicastIpAddressEntry( &uni_row ); + ok( !ret, "got error %lu.\n", ret ); + ok( !memcmp( &uni_row.Address, &best6, sizeof(best6) ), "got different address.\n" ); + ok( !IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr) + || broken( IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr) /* Win10 1507-1709 */), + "got unspecified address.\n" ); + + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + memset( &best6, 0xcc, sizeof(best6) ); + ret = GetBestRoute2( NULL, loopback_index, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_NETWORK_UNREACHABLE, "got error %lu.\n", ret ); + ok( !fwd_row.InterfaceIndex, "got %#lx.\n", fwd_row.InterfaceIndex ); + ok( !best6.sin6_scope_id, "got %lu.\n", best6.sin6_scope_id ); + ok( IN6_IS_ADDR_UNSPECIFIED(&fwd_row.NextHop.Ipv6.sin6_addr), "expected unspecifed address.\n" ); + + memset( &dst6.sin6_addr, 0, sizeof(dst6.sin6_addr) ); + ret = GetBestRoute2( NULL, 0, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == index, "got %lu, %lu.\n", fwd_row.InterfaceIndex, index ); + ok( !memcmp( &global_addr6, &best6, sizeof(best6) ), "got different address.\n" ); + + /* Test with loopback address. */ +loopback_ipv6: + ret = inet_pton( AF_INET6, "::1", &dst6.sin6_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + dst6.sin6_scope_id = loopback_index; + ret = GetBestInterfaceEx( (struct sockaddr *)&dst6, &index ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + + dst6.sin6_scope_id = 0; + ret = GetBestInterfaceEx( (struct sockaddr *)&dst6, &index ); + ok( !ret, "got error %lu.\n", ret ); + ok( index == loopback_index, "got %lu, expected %lu.\n", index, loopback_index ); + ok( !best6.sin6_scope_id, "got %lu.\n", best6.sin6_scope_id ); + + dst6.sin6_scope_id = loopback_index; + ret = GetBestRoute2( NULL, loopback_index, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + + dst6.sin6_scope_id = 0; + ret = GetBestRoute2( NULL, loopback_index, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == loopback_index, "got %lu, %lu.\n", fwd_row.InterfaceIndex, loopback_index ); + ret = GetBestRoute2( NULL, 0, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, (SOCKADDR_INET *)&best6 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == loopback_index, "got %lu, %lu.\n", fwd_row.InterfaceIndex, loopback_index ); + ok( !best6.sin6_scope_id, "got %lu.\n", best6.sin6_scope_id ); + ok( !memcmp( &dst6, &best6, sizeof(best6) ), "got different address.\n" ); + + memset( &best6, 0xcc, sizeof(best6) ); + if (default_route_index != ~0u) + { + ok( default_route_index != loopback_index, "got same interfaces.\n" ); + ret = GetBestRoute2( NULL, default_route_index, NULL, (SOCKADDR_INET *)&dst6, 0, &fwd_row, + (SOCKADDR_INET *)&best6 ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + ok( !fwd_row.InterfaceIndex, "got %#lx.\n", fwd_row.InterfaceIndex ); + } + + /* Test with ipv4 */ + memset( &dst4, 0xcc, sizeof(dst4) ); + dst4.sin_family = AF_INET; + ret = inet_pton( AF_INET, "25.25.0.0", &dst4.sin_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + + ret = GetBestInterfaceEx( (struct sockaddr *)&dst4, &index ); + if (ret == ERROR_NETWORK_UNREACHABLE) + { + skip( "Global IPv4 address is unreachable.\n" ); + goto done; + } + ok( !ret, "got error %lu.\n", ret ); + default_route_index = index; + + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + memset( &best4, 0xcc, sizeof(best4) ); + ret = GetBestRoute2( NULL, default_route_index, NULL, (SOCKADDR_INET *)&dst4, 0, &fwd_row, (SOCKADDR_INET *)&best4 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == default_route_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, + default_route_index ); + ok( fwd_row.NextHop.Ipv4.sin_addr.s_addr, "expected specified next hop.\n" ); + memset( &uni_row, 0, sizeof(uni_row) ); + *(struct sockaddr_in *)&uni_row.Address = best4.Ipv4; + uni_row.InterfaceIndex = fwd_row.InterfaceIndex; + ret = GetUnicastIpAddressEntry( &uni_row ); + ok( !ret, "got error %lu.\n", ret ); + ok( !memcmp( &uni_row.Address, &best4, sizeof(best4) ), "got different address, %s, %s.\n", + inet_ntop( AF_INET, &best4.Ipv4.sin_addr, s, sizeof(s) ), inet_ntop( AF_INET, + &uni_row.Address.Ipv4.sin_addr, s2, sizeof(s2) ) ); + /* GetBestRoute2 zeroes the whole SOCKADDR_INET, not just IPv4 part. */ + ok( !best4.Ipv6.sin6_addr.u.Word[7], "got %#x.\n", best4.Ipv6.sin6_addr.u.Word[7] ); + global_addr4 = best4.Ipv4; + + src4.sin_family = AF_INET; + ret = inet_pton( AF_INET, "127.0.0.1", &src4.sin_addr ); + ok(ret, "got error %u.\n", WSAGetLastError()); + memset( &best4, 0xcc, sizeof(best4) ); + ret = GetBestRoute2( NULL, 0, (SOCKADDR_INET *)&src4, (SOCKADDR_INET *)&dst4, 0, &fwd_row, (SOCKADDR_INET *)&best4 ); + ok( ret == ERROR_NETWORK_UNREACHABLE, "got error %lu.\n", ret ); + ok( !best4.Ipv4.sin_family, "got %u.\n", best4.Ipv4.sin_family ); + ok( !best4.Ipv6.sin6_addr.u.Word[7], "got %#x.\n", best4.Ipv6.sin6_addr.u.Word[7] ); + + src4 = global_addr4; + ret = GetBestRoute2( NULL, loopback_index, (SOCKADDR_INET *)&src4, (SOCKADDR_INET *)&dst4, 0, &fwd_row, + (SOCKADDR_INET *)&best4 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == default_route_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, + link_local_index ); + ok( fwd_row.NextHop.Ipv4.sin_addr.s_addr, "expected specified next hop.\n" ); + ok( !memcmp( &global_addr4, &best4, sizeof(best4.Ipv4) ), "got different address.\n" ); + + memset( &src4, 0xcc, sizeof(src4) ); + memset( &fwd_row, 0xcc, sizeof(fwd_row) ); + ret = GetBestRoute2( NULL, default_route_index, (SOCKADDR_INET *)&src4, (SOCKADDR_INET *)&dst4, 0, &fwd_row, + (SOCKADDR_INET *)&best4 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == default_route_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, + link_local_index ); + + src4 = best4.Ipv4; + ret = GetBestRoute2( NULL, default_route_index, (SOCKADDR_INET *)&src4, (SOCKADDR_INET *)&dst4, 0, &fwd_row, + (SOCKADDR_INET *)&best4 ); + ok( !ret, "got error %lu.\n", ret ); + ok( fwd_row.InterfaceIndex == default_route_index, "got %lu, expected %lu.\n", fwd_row.InterfaceIndex, + link_local_index ); + ok( fwd_row.NextHop.Ipv4.sin_addr.s_addr, "expected specified next hop.\n" ); + + ret = GetBestRoute2( NULL, loopback_index, NULL, (SOCKADDR_INET *)&dst4, 0, &fwd_row, (SOCKADDR_INET *)&best4 ); + ok( ret == ERROR_NETWORK_UNREACHABLE, "got error %lu.\n", ret ); + + ret = inet_pton( AF_INET, "127.0.0.1", &dst4.sin_addr); + ok(ret, "got error %u.\n", WSAGetLastError()); + ret = GetBestRoute2( NULL, default_route_index, NULL, (SOCKADDR_INET *)&dst4, 0, &fwd_row, (SOCKADDR_INET *)&best4 ); + ok( ret == ERROR_INVALID_PARAMETER, "got error %lu.\n", ret ); + + ret = GetBestRoute2( NULL, 0, NULL, (SOCKADDR_INET *)&dst4, 0, &fwd_row, (SOCKADDR_INET *)&best4 ); + ok( !ret, "got error %lu.\n", ret ); + ok( !fwd_row.NextHop.Ipv4.sin_addr.s_addr, "expected unspecified next hop.\n" ); + +done: + FreeMibTable( table ); +} + START_TEST(iphlpapi) { WSADATA wsa_data; @@ -3147,6 +4194,8 @@ START_TEST(iphlpapi) test_NotifyUnicastIpAddressChange(); test_ConvertGuidToString(); test_compartments(); + test_GetIpInterface(); + test_best_routes(); freeIPHlpApi(); } diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index fc01773338f3..69e95125ba45 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -17,8 +17,17 @@ */ +#include #include - +#include +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "ntsecapi.h" #include "jscript.h" #include "wine/debug.h" @@ -39,6 +48,14 @@ typedef struct { DWORD size; } DataViewInstance; +typedef struct { + jsdisp_t dispex; + + ArrayBufferInstance *buffer; + DWORD offset; + DWORD length; +} TypedArrayInstance; + static inline ArrayBufferInstance *arraybuf_from_jsdisp(jsdisp_t *jsdisp) { return CONTAINING_RECORD(jsdisp, ArrayBufferInstance, dispex); @@ -49,6 +66,11 @@ static inline DataViewInstance *dataview_from_jsdisp(jsdisp_t *jsdisp) return CONTAINING_RECORD(jsdisp, DataViewInstance, dispex); } +static inline TypedArrayInstance *typedarr_from_jsdisp(jsdisp_t *jsdisp) +{ + return CONTAINING_RECORD(jsdisp, TypedArrayInstance, dispex); +} + static inline ArrayBufferInstance *arraybuf_this(jsval_t vthis) { jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; @@ -155,12 +177,37 @@ static HRESULT create_arraybuf(script_ctx_t *ctx, DWORD size, ArrayBufferInstanc return S_OK; } +HRESULT create_arraybuffer(script_ctx_t *ctx, DWORD size, IWineJSDispatch **ret, void **data) +{ + ArrayBufferInstance *buf; + HRESULT hres; + + hres = create_arraybuf(ctx, size, &buf); + if(FAILED(hres)) + return hres; + + *ret = &buf->dispex.IWineJSDispatch_iface; + *data = buf->buf; + return S_OK; +} + static HRESULT ArrayBufferConstr_isView(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - FIXME("not implemented\n"); + BOOL ret = FALSE; + jsdisp_t *obj; + + TRACE("\n"); + + if(!r) + return S_OK; - return E_NOTIMPL; + if(argc && is_object_instance(argv[0]) && (obj = to_jsdisp(get_object(argv[0]))) && + obj->builtin_info->class >= FIRST_VIEW_JSCLASS && obj->builtin_info->class <= LAST_VIEW_JSCLASS) + ret = TRUE; + + *r = jsval_bool(ret); + return S_OK; } static HRESULT ArrayBufferConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, @@ -600,18 +647,27 @@ static HRESULT DataView_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op o return gc_process_linked_obj(gc_ctx, op, dispex, &view->buffer->dispex, (void**)&view->buffer); } +static void DataView_cc_traverse(jsdisp_t *dispex, nsCycleCollectionTraversalCallback *cb) +{ + DataViewInstance *view = dataview_from_jsdisp(dispex); + if(view->buffer) + cc_api.note_edge((IUnknown*)&view->buffer->dispex.IWineJSDispatch_iface, "buffer", cb); +} + static const builtin_info_t DataView_info = { .class = JSCLASS_DATAVIEW, .props_cnt = ARRAY_SIZE(DataView_props), .props = DataView_props, .destructor = DataView_destructor, - .gc_traverse = DataView_gc_traverse + .gc_traverse = DataView_gc_traverse, + .cc_traverse = DataView_cc_traverse }; static const builtin_info_t DataViewInst_info = { .class = JSCLASS_DATAVIEW, .destructor = DataView_destructor, - .gc_traverse = DataView_gc_traverse + .gc_traverse = DataView_gc_traverse, + .cc_traverse = DataView_cc_traverse }; static HRESULT DataViewConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, @@ -684,6 +740,585 @@ static const builtin_info_t DataViewConstr_info = { .call = Function_value, }; +static HRESULT clamped_u8(script_ctx_t *ctx, jsval_t v, UINT8 *ret) +{ + HRESULT hres; + double n; + + hres = to_number(ctx, v, &n); + if(FAILED(hres)) + return hres; + + if(!isfinite(n)) + *ret = (n == INFINITY ? 255 : 0); + else + *ret = (n >= 255.0 ? 255 : n <= 0 ? 0 : lround(n)); + return S_OK; +} + +#define TYPEDARRAY_LIST \ +X(Int8Array, JSCLASS_INT8ARRAY, INT8, to_int32, INT) \ +X(Int16Array, JSCLASS_INT16ARRAY, INT16, to_int32, INT) \ +X(Int32Array, JSCLASS_INT32ARRAY, INT32, to_int32, INT) \ +X(Uint8Array, JSCLASS_UINT8ARRAY, UINT8, to_int32, INT) \ +X(Uint8ClampedArray, JSCLASS_UINT8CLAMPEDARRAY, UINT8, clamped_u8, UINT8) \ +X(Uint16Array, JSCLASS_UINT16ARRAY, UINT16, to_int32, INT) \ +X(Uint32Array, JSCLASS_UINT32ARRAY, UINT32, to_int32, INT) \ +X(Float32Array, JSCLASS_FLOAT32ARRAY, float, to_number, double) \ +X(Float64Array, JSCLASS_FLOAT64ARRAY, double, to_number, double) + +#define TYPEDARRAY_INDEX(JSCLASS) ((JSCLASS) - FIRST_TYPEDARRAY_JSCLASS) + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) [TYPEDARRAY_INDEX(JSCLASS)] = L"" #NAME, +static const WCHAR *const TypedArray_name[] = { TYPEDARRAY_LIST }; +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) [TYPEDARRAY_INDEX(JSCLASS)] = sizeof(TYPE), +static const unsigned TypedArray_elem_size[] = { TYPEDARRAY_LIST }; +#undef X + +static inline TypedArrayInstance *typedarr_this(jsval_t vthis, jsclass_t jsclass) +{ + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, jsclass)) ? typedarr_from_jsdisp(jsdisp) : NULL; +} + +static HRESULT create_typedarr(script_ctx_t*,jsclass_t,ArrayBufferInstance*,DWORD,DWORD,jsdisp_t**); + +static HRESULT TypedArray_get_buffer(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + TRACE("%p\n", jsthis); + + *r = jsval_obj(jsdisp_addref(&typedarr_from_jsdisp(jsthis)->buffer->dispex)); + return S_OK; +} + +static HRESULT TypedArray_get_byteLength(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + TRACE("%p\n", jsthis); + + *r = jsval_number(typedarr_from_jsdisp(jsthis)->length * TypedArray_elem_size[TYPEDARRAY_INDEX(jsthis->builtin_info->class)]); + return S_OK; +} + +static HRESULT TypedArray_get_byteOffset(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + TRACE("%p\n", jsthis); + + *r = jsval_number(typedarr_from_jsdisp(jsthis)->offset); + return S_OK; +} + +static HRESULT TypedArray_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + TRACE("%p\n", jsthis); + + *r = jsval_number(typedarr_from_jsdisp(jsthis)->length); + return S_OK; +} + +static HRESULT fill_typedarr_data_from_object(script_ctx_t *ctx, BYTE *data, jsdisp_t *obj, DWORD length, jsclass_t jsclass) +{ + HRESULT hres = S_OK; + jsval_t val; + UINT32 i; + + switch(jsclass) { +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ + case JSCLASS: \ + for(i = 0; i < length; i++) { \ + NUM_TYPE n; \ + \ + hres = jsdisp_get_idx(obj, i, &val); \ + if(FAILED(hres)) { \ + if(hres != DISP_E_UNKNOWNNAME) \ + break; \ + val = jsval_undefined(); \ + } \ + \ + hres = CONVERT(ctx, val, &n); \ + jsval_release(val); \ + if(FAILED(hres)) \ + break; \ + *(TYPE*)&data[i * sizeof(TYPE)] = n; \ + } \ + break; + TYPEDARRAY_LIST + DEFAULT_UNREACHABLE; +#undef X + } + + return hres; +} + +static HRESULT TypedArray_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r, jsclass_t jsclass) +{ + const unsigned elem_size = TypedArray_elem_size[TYPEDARRAY_INDEX(jsclass)]; + TypedArrayInstance *typedarr; + DWORD begin = 0, size; + BYTE *dest, *data; + IDispatch *disp; + jsdisp_t *obj; + HRESULT hres; + jsval_t val; + UINT32 len; + double n; + + TRACE("\n"); + + if(!(typedarr = typedarr_this(vthis, jsclass))) + return JS_E_NOT_TYPEDARRAY; + if(!argc) + return JS_E_TYPEDARRAY_INVALID_SOURCE; + + hres = to_object(ctx, argv[0], &disp); + if(FAILED(hres)) + return JS_E_TYPEDARRAY_INVALID_SOURCE; + + if(!(obj = to_jsdisp(disp))) { + FIXME("Non-JS array object\n"); + hres = JS_E_TYPEDARRAY_INVALID_SOURCE; + goto done; + } + + hres = jsdisp_propget_name(obj, L"length", &val); + if(FAILED(hres)) + goto done; + + hres = to_uint32(ctx, val, &len); + jsval_release(val); + if(FAILED(hres)) + goto done; + + if(argc > 1) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + goto done; + if(n < 0.0 || n > typedarr->length) { + hres = JS_E_TYPEDARRAY_INVALID_OFFSLEN; + goto done; + } + begin = n; + } + + if(len > typedarr->length - begin) { + hres = JS_E_TYPEDARRAY_INVALID_OFFSLEN; + goto done; + } + size = len * elem_size; + dest = data = &typedarr->buffer->buf[typedarr->offset + begin * elem_size]; + + /* If they overlap, make a temporary copy */ + if(obj->builtin_info->class >= FIRST_TYPEDARRAY_JSCLASS && obj->builtin_info->class <= LAST_TYPEDARRAY_JSCLASS) { + TypedArrayInstance *src_arr = typedarr_from_jsdisp(obj); + const BYTE *src = src_arr->buffer->buf + src_arr->offset; + + if(dest < src + len * TypedArray_elem_size[TYPEDARRAY_INDEX(obj->builtin_info->class)] && + dest + size > src) { + if(!(data = malloc(size))) { + hres = E_OUTOFMEMORY; + goto done; + } + } + } + + hres = fill_typedarr_data_from_object(ctx, data, obj, len, jsclass); + if(SUCCEEDED(hres) && dest != data) { + memcpy(dest, data, size); + free(data); + } + +done: + IDispatch_Release(disp); + return hres; +} + +static HRESULT TypedArray_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r, jsclass_t jsclass) +{ + TypedArrayInstance *typedarr; + DWORD begin = 0, end; + jsdisp_t *obj; + HRESULT hres; + double n; + + TRACE("\n"); + + if(!(typedarr = typedarr_this(vthis, jsclass))) + return JS_E_NOT_TYPEDARRAY; + if(!argc) + return JS_E_TYPEDARRAY_INVALID_SUBARRAY; + if(!r) + return S_OK; + + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + end = typedarr->length; + if(n < 0.0) + n += typedarr->length; + if(n >= 0.0) + begin = n < typedarr->length ? n : typedarr->length; + + if(argc > 1 && !is_undefined(argv[1])) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + n += typedarr->length; + if(n >= 0.0) { + end = n < typedarr->length ? n : typedarr->length; + end = end < begin ? begin : end; + }else + end = begin; + } + + hres = create_typedarr(ctx, jsclass, typedarr->buffer, + typedarr->offset + begin * TypedArray_elem_size[TYPEDARRAY_INDEX(jsclass)], + end - begin, &obj); + if(FAILED(hres)) + return hres; + + *r = jsval_obj(obj); + return S_OK; +} + +static void TypedArray_destructor(jsdisp_t *dispex) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + if(typedarr->buffer) + jsdisp_release(&typedarr->buffer->dispex); +} + +static unsigned TypedArray_indexed_len(jsdisp_t *dispex) +{ + /* Typed Arrays override every positive index */ + return INT_MAX; +} + +static HRESULT TypedArray_prop_get_desc(jsdisp_t *dispex, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + + if(!is_indexed_prop_id(id)) + return S_FALSE; + + if(indexed_prop_id_to_idx(id) >= typedarr->length) + return DISP_E_UNKNOWNNAME; + + if(!flags_only) { + HRESULT hres = dispex->builtin_info->prop_get(dispex, id, &desc->value); + if(hres != S_OK) + return hres; + } + + desc->flags = PROPF_ENUMERABLE | PROPF_WRITABLE; + return S_OK; +} + +static HRESULT TypedArray_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + return gc_process_linked_obj(gc_ctx, op, dispex, &typedarr->buffer->dispex, (void**)&typedarr->buffer); +} + +static void TypedArray_cc_traverse(jsdisp_t *dispex, nsCycleCollectionTraversalCallback *cb) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + if(typedarr->buffer) + cc_api.note_edge((IUnknown*)&typedarr->buffer->dispex.IWineJSDispatch_iface, "buffer", cb); +} + +static const builtin_prop_t TypedArrayInst_props[] = { + {L"buffer", NULL, 0, TypedArray_get_buffer}, + {L"byteLength", NULL, 0, TypedArray_get_byteLength}, + {L"byteOffset", NULL, 0, TypedArray_get_byteOffset}, + {L"length", NULL, 0, TypedArray_get_length}, +}; + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +static HRESULT NAME ##_prop_get(jsdisp_t *dispex, DISPID id, jsval_t *r) \ +{ \ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); \ + unsigned idx = indexed_prop_id_to_idx(id); \ + \ + if(!is_indexed_prop_id(id)) \ + return S_FALSE; \ + \ + TRACE("%p[%u]\n", typedarr, idx); \ + \ + if(idx >= typedarr->length) \ + *r = jsval_undefined(); \ + else \ + *r = jsval_number(*(TYPE*)&typedarr->buffer->buf[typedarr->offset + idx * sizeof(TYPE)]); \ + return S_OK; \ +} \ + \ +static HRESULT NAME ##_prop_put(jsdisp_t *dispex, DISPID id, jsval_t val) \ +{ \ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); \ + unsigned idx = indexed_prop_id_to_idx(id); \ + HRESULT hres; \ + NUM_TYPE n; \ + \ + if(!is_indexed_prop_id(id)) \ + return S_FALSE; \ + \ + TRACE("%p[%u] = %s\n", typedarr, idx, debugstr_jsval(val)); \ + \ + if(idx >= typedarr->length) \ + return S_OK; \ + \ + hres = CONVERT(typedarr->dispex.ctx, val, &n); \ + if(SUCCEEDED(hres)) \ + *(TYPE*)&typedarr->buffer->buf[typedarr->offset + idx * sizeof(TYPE)] = n; \ + return hres; \ +} \ + \ +static HRESULT NAME ##_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ +{ \ + return TypedArray_set(ctx, vthis, flags, argc, argv, r, JSCLASS); \ +} \ + \ +static HRESULT NAME ##_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ +{ \ + return TypedArray_subarray(ctx, vthis, flags, argc, argv, r, JSCLASS); \ +} \ + \ +static const builtin_prop_t NAME ##_props[] = { \ + {L"buffer", NULL, 0, TypedArray_get_buffer}, \ + {L"byteLength", NULL, 0, TypedArray_get_byteLength}, \ + {L"byteOffset", NULL, 0, TypedArray_get_byteOffset}, \ + {L"length", NULL, 0, TypedArray_get_length}, \ + {L"set", NAME ##_set, PROPF_METHOD|2}, \ + {L"subarray", NAME ##_subarray, PROPF_METHOD|2}, \ +}; +TYPEDARRAY_LIST +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +[TYPEDARRAY_INDEX(JSCLASS)] = \ +{ \ + .class = JSCLASS, \ + .props_cnt = ARRAY_SIZE(NAME ##_props), \ + .props = NAME ##_props, \ + .destructor = TypedArray_destructor, \ + .indexed_len = TypedArray_indexed_len, \ + .prop_get = NAME ##_prop_get, \ + .prop_put = NAME ##_prop_put, \ + .prop_get_desc = TypedArray_prop_get_desc, \ + .gc_traverse = TypedArray_gc_traverse, \ + .cc_traverse = TypedArray_cc_traverse, \ +}, +static const builtin_info_t TypedArray_info[] = { TYPEDARRAY_LIST }; +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +[TYPEDARRAY_INDEX(JSCLASS)] = \ +{ \ + .class = JSCLASS, \ + .props_cnt = ARRAY_SIZE(TypedArrayInst_props), \ + .props = TypedArrayInst_props, \ + .destructor = TypedArray_destructor, \ + .indexed_len = TypedArray_indexed_len, \ + .prop_get = NAME ##_prop_get, \ + .prop_put = NAME ##_prop_put, \ + .prop_get_desc = TypedArray_prop_get_desc, \ + .gc_traverse = TypedArray_gc_traverse, \ + .cc_traverse = TypedArray_cc_traverse, \ +}, +static const builtin_info_t TypedArrayInst_info[] = { TYPEDARRAY_LIST }; +#undef X + +static HRESULT create_typedarr(script_ctx_t *ctx, jsclass_t jsclass, ArrayBufferInstance *buffer, DWORD offset, DWORD length, jsdisp_t **ret) +{ + TypedArrayInstance *typedarr; + HRESULT hres; + + if(!(typedarr = calloc(1, sizeof(TypedArrayInstance)))) + return E_OUTOFMEMORY; + + hres = init_dispex_from_constr(&typedarr->dispex, ctx, &TypedArrayInst_info[TYPEDARRAY_INDEX(jsclass)], + ctx->typedarr_constr[TYPEDARRAY_INDEX(jsclass)]); + if(FAILED(hres)) { + free(typedarr); + return hres; + } + + jsdisp_addref(&buffer->dispex); + typedarr->buffer = buffer; + typedarr->offset = offset; + typedarr->length = length; + + *ret = &typedarr->dispex; + return S_OK; +} + +HRESULT typed_array_get_random_values(IDispatch *disp) +{ + jsdisp_t *obj = to_jsdisp(disp); + TypedArrayInstance *typedarr; + DWORD size; + + if(!obj || obj->builtin_info->class < FIRST_TYPEDARRAY_JSCLASS || obj->builtin_info->class > LAST_TYPEDARRAY_JSCLASS) + return E_INVALIDARG; + + if(obj->builtin_info->class == JSCLASS_FLOAT32ARRAY || obj->builtin_info->class == JSCLASS_FLOAT64ARRAY) { + /* FIXME: Return TypeMismatchError */ + return E_FAIL; + } + + typedarr = typedarr_from_jsdisp(obj); + size = typedarr->length * TypedArray_elem_size[TYPEDARRAY_INDEX(obj->builtin_info->class)]; + if(size > 65536) { + /* FIXME: Return QuotaExceededError */ + return E_FAIL; + } + + if(!RtlGenRandom(&typedarr->buffer->buf[typedarr->offset], size)) + return HRESULT_FROM_WIN32(GetLastError()); + + return S_OK; +} + +static HRESULT TypedArrayConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r, jsclass_t jsclass) +{ + const unsigned typedarr_idx = TYPEDARRAY_INDEX(jsclass); + unsigned elem_size = TypedArray_elem_size[typedarr_idx]; + ArrayBufferInstance *buffer = NULL; + DWORD offset = 0, length = 0; + jsdisp_t *typedarr; + HRESULT hres; + double n; + + TRACE("\n"); + + switch(flags) { + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: { + if(argc) { + if(is_object_instance(argv[0])) { + jsdisp_t *obj = to_jsdisp(get_object(argv[0])); + + if(!obj) + return JS_E_TYPEDARRAY_BAD_CTOR_ARG; + + if(obj->builtin_info->class == JSCLASS_ARRAYBUFFER) { + buffer = arraybuf_from_jsdisp(obj); + if(argc > 1) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0 || n > buffer->size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + offset = n; + if(offset % elem_size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + } + if(argc > 2 && !is_undefined(argv[2])) { + hres = to_integer(ctx, argv[2], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0 || n > UINT_MAX) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + length = n; + if(offset + length * elem_size > buffer->size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + }else { + length = buffer->size - offset; + if(length % elem_size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + length /= elem_size; + } + jsdisp_addref(&buffer->dispex); + }else { + jsval_t val; + UINT32 len; + DWORD size; + + hres = jsdisp_propget_name(obj, L"length", &val); + if(FAILED(hres)) + return hres; + if(is_undefined(val)) + return JS_E_TYPEDARRAY_BAD_CTOR_ARG; + + hres = to_uint32(ctx, val, &len); + jsval_release(val); + if(FAILED(hres)) + return hres; + + length = len; + size = length * elem_size; + if(size < length || size > (UINT_MAX - FIELD_OFFSET(ArrayBufferInstance, buf[0]))) + return E_OUTOFMEMORY; + + hres = create_arraybuf(ctx, size, &buffer); + if(FAILED(hres)) + return hres; + + hres = fill_typedarr_data_from_object(ctx, buffer->buf, obj, length, jsclass); + if(FAILED(hres)) { + jsdisp_release(&buffer->dispex); + return hres; + } + } + }else if(is_number(argv[0])) { + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + if(n * elem_size > (UINT_MAX - FIELD_OFFSET(ArrayBufferInstance, buf[0]))) + return E_OUTOFMEMORY; + length = n; + }else + return JS_E_TYPEDARRAY_BAD_CTOR_ARG; + } + + if(!r) + return S_OK; + + if(!buffer) { + hres = create_arraybuf(ctx, length * elem_size, &buffer); + if(FAILED(hres)) + return hres; + } + + hres = create_typedarr(ctx, jsclass, buffer, offset, length, &typedarr); + jsdisp_release(&buffer->dispex); + if(FAILED(hres)) + return hres; + + *r = jsval_obj(typedarr); + break; + } + default: + FIXME("unimplemented flags: %x\n", flags); + return E_NOTIMPL; + } + + return S_OK; +} + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +static HRESULT NAME ## Constr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ +{ \ + return TypedArrayConstr_value(ctx, vthis, flags, argc, argv, r, JSCLASS); \ +} +TYPEDARRAY_LIST +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) [TYPEDARRAY_INDEX(JSCLASS)] = NAME ## Constr_value, +static const builtin_invoke_t TypedArray_constr[] = { TYPEDARRAY_LIST }; +#undef X + +static const builtin_info_t TypedArrayConstr_info = { + .class = JSCLASS_FUNCTION, + .call = Function_value, +}; + HRESULT init_arraybuf_constructors(script_ctx_t *ctx) { static const struct { @@ -695,6 +1330,7 @@ HRESULT init_arraybuf_constructors(script_ctx_t *ctx) { L"byteOffset", DataView_get_byteOffset }, }; ArrayBufferInstance *arraybuf; + TypedArrayInstance *typedarr; DataViewInstance *view; property_desc_t desc; HRESULT hres; @@ -766,6 +1402,42 @@ HRESULT init_arraybuf_constructors(script_ctx_t *ctx) hres = jsdisp_define_data_property(ctx->global, L"DataView", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->dataview_constr)); + if(FAILED(hres)) + return hres; + + for(i = 0; i < ARRAY_SIZE(TypedArray_info); i++) { + if(!(typedarr = calloc(1, sizeof(TypedArrayInstance)))) + return E_OUTOFMEMORY; + + hres = create_arraybuf(ctx, 0, &typedarr->buffer); + if(FAILED(hres)) { + free(typedarr); + return hres; + } + + hres = init_dispex(&typedarr->dispex, ctx, &TypedArray_info[i], ctx->object_prototype); + if(FAILED(hres)) { + jsdisp_release(&typedarr->buffer->dispex); + free(typedarr); + return hres; + } + + hres = create_builtin_constructor(ctx, TypedArray_constr[i], TypedArray_name[i], &TypedArrayConstr_info, + PROPF_CONSTR|1, &typedarr->dispex, &ctx->typedarr_constr[i]); + jsdisp_release(&typedarr->dispex); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(ctx->typedarr_constr[i], L"BYTES_PER_ELEMENT", 0, + jsval_number(TypedArray_elem_size[i])); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(ctx->global, TypedArray_name[i], PROPF_CONFIGURABLE | PROPF_WRITABLE, + jsval_obj(ctx->typedarr_constr[i])); + if(FAILED(hres)) + return hres; + } return hres; } diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index d5ed3adf4fb0..479f2a0a3d14 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -30,6 +30,12 @@ static const GUID GUID_JScriptTypeInfo = {0xc59c6b12,0xf6c1,0x11cf,{0x88,0x35,0x #define FDEX_VERSION_MASK 0xf0000000 #define GOLDEN_RATIO 0x9E3779B9U +typedef enum { + INVALID_PROP, + DISPEX_PROP, + INDEXED_PROP, +} prop_kind_t; + typedef enum { PROP_JSVAL, PROP_BUILTIN, @@ -60,6 +66,11 @@ struct _dispex_prop_t { int bucket_next; }; +static inline DWORD prop_id_to_idx(DISPID id) +{ + return id - 1; +} + static void fix_protref_prop(jsdisp_t *jsdisp, dispex_prop_t *prop) { DWORD ref; @@ -69,7 +80,12 @@ static void fix_protref_prop(jsdisp_t *jsdisp, dispex_prop_t *prop) ref = prop->u.ref; while((jsdisp = jsdisp->prototype)) { - if(ref >= jsdisp->prop_cnt || jsdisp->props[ref].type == PROP_DELETED) + if(ref >= jsdisp->prop_cnt) { + if(jsdisp->builtin_info->indexed_len && indexed_prop_id_to_idx(ref + 1) < jsdisp->builtin_info->indexed_len(jsdisp)) + return; + break; + } + if(jsdisp->props[ref].type == PROP_DELETED) break; if(jsdisp->props[ref].type != PROP_PROTREF) return; @@ -84,15 +100,17 @@ static inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop) return prop - This->props + 1; } -static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id) +static inline prop_kind_t prop_kind(jsdisp_t *This, DISPID id) { - DWORD idx = id - 1; + DWORD idx = prop_id_to_idx(id); if(idx >= This->prop_cnt) - return NULL; + return This->builtin_info->indexed_len && indexed_prop_id_to_idx(id) < This->builtin_info->indexed_len(This) ? INDEXED_PROP : INVALID_PROP; fix_protref_prop(This, &This->props[idx]); - return This->props[idx].type == PROP_DELETED ? NULL : &This->props[idx]; + if(This->props[idx].type == PROP_DELETED) + return INVALID_PROP; + return DISPEX_PROP; } static inline BOOL is_function_prop(dispex_prop_t *prop) @@ -108,23 +126,25 @@ static inline BOOL is_function_prop(dispex_prop_t *prop) return ret; } -static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop) +static BOOL is_enumerable(jsdisp_t *This, dispex_prop_t *prop) { if(prop->type == PROP_PROTREF) { dispex_prop_t *parent = NULL; if(prop->u.ref < This->prototype->prop_cnt) parent = &This->prototype->props[prop->u.ref]; + else if(This->prototype->builtin_info->indexed_len && indexed_prop_id_to_idx(prop->u.ref + 1) < This->prototype->builtin_info->indexed_len(This->prototype)) + return TRUE; if(!parent || parent->type == PROP_DELETED) { prop->type = PROP_DELETED; - return 0; + return FALSE; } - return get_flags(This->prototype, parent); + return is_enumerable(This->prototype, parent); } - return prop->flags; + return !!(prop->flags & PROPF_ENUMERABLE); } static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name, BOOL case_insens) @@ -244,6 +264,23 @@ static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref return ret; } +static void release_prop(dispex_prop_t *prop) +{ + switch(prop->type) { + case PROP_JSVAL: + jsval_release(prop->u.val); + break; + case PROP_ACCESSOR: + if(prop->u.accessor.getter) + jsdisp_release(prop->u.accessor.getter); + if(prop->u.accessor.setter) + jsdisp_release(prop->u.accessor.setter); + break; + default: + break; + } +} + static dispex_prop_t *lookup_dispex_prop(jsdisp_t *obj, unsigned hash, const WCHAR *name, BOOL case_insens) { unsigned bucket, pos, prev = ~0; @@ -275,7 +312,7 @@ static HRESULT update_external_prop(jsdisp_t *obj, const WCHAR *name, dispex_pro if(desc->name) name = desc->name; - if(!desc->iid) { + if(!desc->prototype_id) { if(!prop && !(prop = alloc_prop(obj, name, PROP_DELETED, 0))) return E_OUTOFMEMORY; prop->type = PROP_EXTERN; @@ -322,7 +359,7 @@ static HRESULT update_external_prop(jsdisp_t *obj, const WCHAR *name, dispex_pro static HRESULT find_external_prop(jsdisp_t *This, const WCHAR *name, BOOL case_insens, dispex_prop_t *prop, dispex_prop_t **ret) { - if(This->builtin_info->lookup_prop) { + if((!prop || prop->type != PROP_EXTERN || This->has_volatile_props) && This->builtin_info->lookup_prop) { struct property_info desc; HRESULT hres; @@ -351,17 +388,30 @@ static HRESULT find_external_prop(jsdisp_t *This, const WCHAR *name, BOOL case_i } static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, - dispex_prop_t *prop, dispex_prop_t **ret) + dispex_prop_t *prop, DISPID *ret) { const builtin_prop_t *builtin; HRESULT hres; - if(!prop) + if(!prop) { + if(This->builtin_info->indexed_len) { + unsigned idx = 0, len = This->builtin_info->indexed_len(This); + const WCHAR *ptr; + + for(ptr = name; is_digit(*ptr); ptr++) { + idx = idx * 10 + (*ptr - '0'); + if(idx >= len) + break; + } + if(idx < len && !*ptr) { + *ret = indexed_prop_idx_to_id(idx); + return S_OK; + } + } prop = lookup_dispex_prop(This, hash, name, case_insens); - if(prop && prop->type != PROP_DELETED && prop->type != PROP_EXTERN) { - *ret = prop; - return S_OK; } + if(prop && prop->type != PROP_DELETED && prop->type != PROP_EXTERN) + goto ret; if(!prop && (builtin = find_builtin_prop(This, name, case_insens))) { unsigned flags = builtin->flags; @@ -380,8 +430,7 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, prop->type = PROP_JSVAL; prop->u.val = jsval_obj(obj); - *ret = prop; - return S_OK; + goto ret; }else if(builtin->setter) flags |= PROPF_WRITABLE; flags &= PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE; @@ -390,129 +439,116 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, return E_OUTOFMEMORY; prop->u.p = builtin; - *ret = prop; - return S_OK; + goto ret; } - return find_external_prop(This, name, case_insens, prop, ret); + hres = find_external_prop(This, name, case_insens, prop, &prop); + if(FAILED(hres)) + return hres; + if(!prop) { + *ret = 0; + return S_FALSE; + } + +ret: + *ret = prop_to_id(This, prop); + return prop->type != PROP_DELETED ? S_OK : S_FALSE; } static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, - dispex_prop_t *own_prop, dispex_prop_t **ret) + dispex_prop_t *own_prop, DISPID *ret) { dispex_prop_t *prot_prop = NULL; HRESULT hres; - hres = find_prop_name(This, hash, name, case_insens, own_prop, &own_prop); + hres = find_prop_name(This, hash, name, case_insens, own_prop, ret); if(FAILED(hres)) return hres; - if(own_prop) { - if(own_prop->type == PROP_PROTREF) { + + if(is_dispex_prop_id(*ret)) { + own_prop = &This->props[prop_id_to_idx(*ret)]; + if(hres == S_OK) { + if(own_prop->type != PROP_PROTREF) + return S_OK; + if(is_indexed_prop_id(own_prop->u.ref + 1)) + goto ret; prot_prop = &This->prototype->props[own_prop->u.ref]; - }else if(own_prop->type != PROP_DELETED) { - *ret = own_prop; - return S_OK; } + }else if(is_indexed_prop_id(*ret)) { + /* indexed props can't be PROTREFs or DELETED */ + return S_OK; } if(This->prototype) { - hres = find_prop_name_prot(This->prototype, hash, name, case_insens, prot_prop, &prot_prop); + hres = find_prop_name_prot(This->prototype, hash, name, case_insens, prot_prop, ret); if(FAILED(hres)) return hres; - if(prot_prop && prot_prop->type != PROP_DELETED) { - if(own_prop && case_insens && wcscmp(prot_prop->name, own_prop->name)) { - hres = find_prop_name(This, prot_prop->hash, prot_prop->name, FALSE, NULL, &own_prop); - if(FAILED(hres)) - return hres; - if(own_prop && own_prop->type != PROP_DELETED) { - *ret = own_prop; - return S_OK; + if(hres == S_OK) { + DWORD ref = prop_id_to_idx(*ret); + + if(is_dispex_prop_id(*ret)) { + prot_prop = &This->prototype->props[ref]; + name = prot_prop->name; + + if(own_prop && case_insens && wcscmp(name, own_prop->name)) { + hres = find_prop_name(This, prot_prop->hash, name, FALSE, NULL, ret); + if(FAILED(hres)) + return hres; + if(hres == S_OK) + return S_OK; + own_prop = is_dispex_prop_id(*ret) ? &This->props[prop_id_to_idx(*ret)] : NULL; } } if(own_prop) { own_prop->type = PROP_PROTREF; - own_prop->u.ref = prot_prop - This->prototype->props; - }else { - own_prop = alloc_protref(This, prot_prop->name, prot_prop - This->prototype->props); - if(!own_prop) - return E_OUTOFMEMORY; + own_prop->u.ref = ref; + }else if(!(own_prop = alloc_protref(This, name, ref))) { + return E_OUTOFMEMORY; } }else if(own_prop) { own_prop->type = PROP_DELETED; } } - *ret = own_prop; - return S_OK; + if(!own_prop) { + *ret = 0; + return S_FALSE; + } + +ret: + *ret = prop_to_id(This, own_prop); + return own_prop->type != PROP_DELETED ? S_OK : S_FALSE; } -static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, BOOL case_insens, dispex_prop_t **ret) +static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, BOOL case_insens, DISPID *ret) { dispex_prop_t *prop; HRESULT hres; - hres = find_prop_name_prot(This, string_hash(name), name, case_insens, NULL, &prop); - if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) { - TRACE("creating prop %s flags %lx\n", debugstr_w(name), create_flags); - - if(!prop) { - prop = alloc_prop(This, name, PROP_DELETED, 0); - if(!prop) - return E_OUTOFMEMORY; - } - - if(This->builtin_info->lookup_prop) { - struct property_info desc; - hres = This->builtin_info->lookup_prop(This, name, fdexNameEnsure, &desc); - if(hres == S_OK) - return update_external_prop(This, name, prop, &desc, ret); - } + hres = find_prop_name_prot(This, string_hash(name), name, case_insens, NULL, ret); + if(hres != S_FALSE) + return hres; - hres = S_OK; - prop->type = PROP_JSVAL; - prop->flags = create_flags; - prop->u.val = jsval_undefined(); + if(is_dispex_prop_id(*ret)) + prop = &This->props[prop_id_to_idx(*ret)]; + else { + if(!(prop = alloc_prop(This, name, PROP_JSVAL, create_flags))) + return E_OUTOFMEMORY; + *ret = prop_to_id(This, prop); } - *ret = prop; - return hres; -} - -HRESULT jsdisp_index_lookup(jsdisp_t *obj, const WCHAR *name, unsigned length, struct property_info *desc) -{ - const WCHAR *ptr; - unsigned idx = 0; + TRACE("creating prop %s flags %lx\n", debugstr_w(name), create_flags); - for(ptr = name; is_digit(*ptr); ptr++) { - idx = idx * 10 + (*ptr - '0'); - if (idx >= length) - return DISP_E_UNKNOWNNAME; + if(This->has_volatile_props && This->builtin_info->lookup_prop) { + struct property_info desc; + hres = This->builtin_info->lookup_prop(This, name, fdexNameEnsure, &desc); + if(hres == S_OK) + return update_external_prop(This, name, prop, &desc, &prop); } - if(*ptr) - return DISP_E_UNKNOWNNAME; - - desc->id = idx; - desc->flags = PROPF_ENUMERABLE; - if(obj->builtin_info->prop_put) - desc->flags |= PROPF_WRITABLE; - desc->name = NULL; - desc->index = idx; - desc->iid = 0; - return S_OK; -} - -HRESULT jsdisp_next_index(jsdisp_t *obj, unsigned length, unsigned id, struct property_info *desc) -{ - if(id + 1 == length) - return S_FALSE; - desc->id = id + 1; - desc->flags = PROPF_ENUMERABLE; - if(obj->builtin_info->prop_put) - desc->flags |= PROPF_WRITABLE; - desc->name = NULL; - desc->index = desc->id; - desc->iid = 0; + prop->type = PROP_JSVAL; + prop->flags = create_flags; + prop->u.val = jsval_undefined(); return S_OK; } @@ -567,14 +603,25 @@ static HRESULT convert_params(script_ctx_t *ctx, const DISPPARAMS *dp, jsval_t * return S_OK; } -static HRESULT prop_get(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, jsval_t *r) +static HRESULT prop_get(jsdisp_t *This, IDispatch *jsthis, DISPID id, jsval_t *r) { jsdisp_t *prop_obj = This; + dispex_prop_t *prop; HRESULT hres; - while(prop->type == PROP_PROTREF) { + for(;;) { + if(prop_obj->builtin_info->prop_get) { + hres = prop_obj->builtin_info->prop_get(prop_obj, id, r); + if(hres != S_FALSE) + return hres; + } + + prop = &prop_obj->props[prop_id_to_idx(id)]; + if(prop->type != PROP_PROTREF) + break; + prop_obj = prop_obj->prototype; - prop = prop_obj->props + prop->u.ref; + id = prop->u.ref + 1; } switch(prop->type) { @@ -593,11 +640,9 @@ static HRESULT prop_get(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, hres = S_OK; } break; - case PROP_EXTERN: - hres = prop_obj->builtin_info->prop_get(prop_obj, prop->u.id, r); - break; default: ERR("type %d\n", prop->type); + assert(0); return E_FAIL; } @@ -610,15 +655,25 @@ static HRESULT prop_get(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, return hres; } -static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) +static HRESULT prop_put(jsdisp_t *This, DISPID id, jsval_t val) { + dispex_prop_t *prop; HRESULT hres; + if(This->builtin_info->prop_put) { + hres = This->builtin_info->prop_put(This, id, val); + if(hres != S_FALSE) + return hres; + } + + prop = &This->props[prop_id_to_idx(id)]; if(prop->type == PROP_PROTREF) { dispex_prop_t *prop_iter = prop; jsdisp_t *prototype_iter = This; do { + if(!is_dispex_prop_id(prop_iter->u.ref + 1)) + break; prototype_iter = prototype_iter->prototype; prop_iter = prototype_iter->props + prop_iter->u.ref; } while(prop_iter->type == PROP_PROTREF); @@ -654,20 +709,9 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) return S_OK; } return jsdisp_call_value(prop->u.accessor.setter, jsval_obj(This), DISPATCH_METHOD, 1, &val, NULL); - case PROP_EXTERN: - if(!This->builtin_info->prop_put) { - TRACE("no prop_put\n"); - return S_OK; - } - hres = This->builtin_info->prop_put(This, prop->u.id, val); - if(hres != S_FALSE) - return hres; - prop->type = PROP_JSVAL; - prop->flags = PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE; - prop->u.val = jsval_undefined(); - break; default: ERR("type %d\n", prop->type); + assert(0); return E_FAIL; } @@ -683,59 +727,61 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) return S_OK; } -static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags, +static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) { HRESULT hres; + jsval_t val; - switch(prop->type) { - case PROP_BUILTIN: - return JS_E_FUNCTION_EXPECTED; - case PROP_PROTREF: - return invoke_prop_func(This->prototype, jsthis ? jsthis : to_disp(This), - This->prototype->props+prop->u.ref, flags, argc, argv, r, caller); - case PROP_JSVAL: { - if(!is_object_instance(prop->u.val)) { - FIXME("value %s is not a function\n", debugstr_jsval(prop->u.val)); - return JS_E_FUNCTION_EXPECTED; - } - - TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val)); + if(is_dispex_prop_id(id)) { + dispex_prop_t *prop = &This->props[prop_id_to_idx(id)]; - return disp_call_value_with_caller(This->ctx, get_object(prop->u.val), - jsval_disp(jsthis ? jsthis : to_disp(This)), - flags, argc, argv, r, caller); - } - case PROP_ACCESSOR: - case PROP_EXTERN: { - jsval_t val; + switch(prop->type) { + case PROP_BUILTIN: + return JS_E_FUNCTION_EXPECTED; + case PROP_PROTREF: + return invoke_prop_func(This->prototype, jsthis ? jsthis : to_disp(This), + prop->u.ref + 1, flags, argc, argv, r, caller); + case PROP_JSVAL: { + if(!is_object_instance(prop->u.val)) { + FIXME("value %s is not a function\n", debugstr_jsval(prop->u.val)); + return JS_E_FUNCTION_EXPECTED; + } - hres = prop_get(This, jsthis ? jsthis : to_disp(This), prop, &val); - if(FAILED(hres)) - return hres; + TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val)); - if(is_object_instance(val)) { - jsdisp_t *jsfunc = to_jsdisp(get_object(val)); - if(!jsfunc || is_class(jsfunc, JSCLASS_FUNCTION)) - hres = disp_call_value_with_caller(This->ctx, get_object(val), - jsval_disp(jsthis ? jsthis : to_disp(This)), - flags, argc, argv, r, caller); - else - hres = JS_E_INVALID_PROPERTY; - }else { - WARN("value %s is not a function\n", debugstr_jsval(val)); - hres = JS_E_FUNCTION_EXPECTED; + return disp_call_value_with_caller(This->ctx, get_object(prop->u.val), + jsval_disp(jsthis ? jsthis : to_disp(This)), + flags, argc, argv, r, caller); + } + case PROP_ACCESSOR: + case PROP_EXTERN: + break; + default: + assert(0); + break; } + } - jsval_release(val); + hres = prop_get(This, jsthis ? jsthis : to_disp(This), id, &val); + if(FAILED(hres)) return hres; - } - case PROP_DELETED: - assert(0); - break; + + if(is_object_instance(val)) { + jsdisp_t *jsfunc = to_jsdisp(get_object(val)); + if(!jsfunc || is_class(jsfunc, JSCLASS_FUNCTION)) + hres = disp_call_value_with_caller(This->ctx, get_object(val), + jsval_disp(jsthis ? jsthis : to_disp(This)), + flags, argc, argv, r, caller); + else + hres = JS_E_INVALID_PROPERTY; + }else { + WARN("value %s is not a function\n", debugstr_jsval(val)); + hres = JS_E_FUNCTION_EXPECTED; } - return E_FAIL; + jsval_release(val); + return hres; } HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) @@ -746,42 +792,53 @@ HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value) static HRESULT fill_props(jsdisp_t *obj) { - dispex_prop_t *prop; HRESULT hres; + DISPID id; + DWORD i; - if(obj->builtin_info->next_prop) { - struct property_info desc; - unsigned id = ~0; - WCHAR buf[12]; - - for(;;) { - hres = obj->builtin_info->next_prop(obj, id, &desc); - if(FAILED(hres)) - return hres; - if(hres == S_FALSE) - break; + if(obj->props_filled) + return S_OK; - if(!desc.name) { - swprintf(buf, ARRAYSIZE(buf), L"%u", desc.index); - desc.name = buf; - } + for(i = 0; i < obj->builtin_info->props_cnt; i++) { + hres = find_prop_name(obj, string_hash(obj->builtin_info->props[i].name), obj->builtin_info->props[i].name, FALSE, NULL, &id); + if(FAILED(hres)) + return hres; + } + hres = S_OK; - prop = lookup_dispex_prop(obj, string_hash(desc.name), desc.name, FALSE); - if(!prop) { - hres = update_external_prop(obj, desc.name, NULL, &desc, &prop); - if(FAILED(hres)) - return hres; - } - id = desc.id; - } + if(obj->builtin_info->fill_props) { + hres = obj->builtin_info->fill_props(obj); + if(FAILED(hres)) + return hres; } + if(hres == S_OK) + obj->props_filled = TRUE; + return S_OK; +} + +static HRESULT fill_protref(jsdisp_t *This, unsigned hash, const WCHAR *name, DWORD ref) +{ + HRESULT hres; + DISPID id; + + hres = find_prop_name(This, hash, name, FALSE, NULL, &id); + if(hres != S_FALSE) + return hres; + if(is_dispex_prop_id(id)) { + dispex_prop_t *prop = &This->props[prop_id_to_idx(id)]; + prop->type = PROP_PROTREF; + prop->flags = 0; + prop->u.ref = ref; + }else if(!alloc_protref(This, name, ref)) { + return E_OUTOFMEMORY; + } return S_OK; } static HRESULT fill_protrefs(jsdisp_t *This) { - dispex_prop_t *iter, *prop; + dispex_prop_t *iter; HRESULT hres; hres = fill_props(This); @@ -795,21 +852,26 @@ static HRESULT fill_protrefs(jsdisp_t *This) if(FAILED(hres)) return hres; + if(This->prototype->builtin_info->indexed_len) { + jsdisp_t *prot = This->prototype; + unsigned i, len = This->prototype->builtin_info->indexed_len(prot); + property_desc_t desc; + WCHAR buf[11]; + + for(i = 0; i < len; i++) { + if(prot->builtin_info->prop_get_desc(prot, indexed_prop_idx_to_id(i), TRUE, &desc) != S_OK) + break; + swprintf(buf, ARRAY_SIZE(buf), L"%u", i); + hres = fill_protref(This, string_hash(buf), buf, prop_id_to_idx(indexed_prop_idx_to_id(i))); + if(hres != S_OK) + return hres; + } + } + for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) { - hres = find_prop_name(This, iter->hash, iter->name, FALSE, NULL, &prop); - if(FAILED(hres)) + hres = fill_protref(This, iter->hash, iter->name, iter - This->prototype->props); + if(hres != S_OK) return hres; - if(!prop || prop->type==PROP_DELETED) { - if(prop) { - prop->type = PROP_PROTREF; - prop->flags = 0; - prop->u.ref = iter - This->prototype->props; - }else { - prop = alloc_protref(This, iter->name, iter - This->prototype->props); - if(!prop) - return E_OUTOFMEMORY; - } - } } return S_OK; @@ -820,21 +882,7 @@ static void unlink_jsdisp(jsdisp_t *jsdisp) dispex_prop_t *prop = jsdisp->props, *end; for(end = prop + jsdisp->prop_cnt; prop < end; prop++) { - switch(prop->type) { - case PROP_DELETED: - continue; - case PROP_JSVAL: - jsval_release(prop->u.val); - break; - case PROP_ACCESSOR: - if(prop->u.accessor.getter) - jsdisp_release(prop->u.accessor.getter); - if(prop->u.accessor.setter) - jsdisp_release(prop->u.accessor.setter); - break; - default: - break; - } + release_prop(prop); prop->type = PROP_DELETED; } @@ -945,6 +993,11 @@ HRESULT gc_run(script_ctx_t *ctx) if(thread_data->gc_is_unlinking) return S_OK; + thread_data->gc_is_unlinking = TRUE; + if(cc_api.collect) + cc_api.collect(); + thread_data->gc_is_unlinking = FALSE; + if(!(head = malloc(sizeof(*head)))) return E_OUTOFMEMORY; head->next = NULL; @@ -968,7 +1021,7 @@ HRESULT gc_run(script_ctx_t *ctx) } LIST_FOR_EACH_ENTRY(obj, &thread_data->objects, jsdisp_t, entry) { /* Skip objects with external reference counter */ - if(obj->builtin_info->addref) { + if(obj->builtin_info->get_host_disp) { obj->gc_marked = FALSE; continue; } @@ -1874,19 +1927,7 @@ static void jsdisp_free(jsdisp_t *obj) } for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) { - switch(prop->type) { - case PROP_JSVAL: - jsval_release(prop->u.val); - break; - case PROP_ACCESSOR: - if(prop->u.accessor.getter) - jsdisp_release(prop->u.accessor.getter); - if(prop->u.accessor.setter) - jsdisp_release(prop->u.accessor.setter); - break; - default: - break; - }; + release_prop(prop); free(prop->name); } free(obj->props); @@ -1901,8 +1942,8 @@ static void jsdisp_free(jsdisp_t *obj) jsdisp_t *jsdisp_addref(jsdisp_t *obj) { - if(obj->builtin_info->addref) - obj->builtin_info->addref(obj); + if(obj->builtin_info->get_host_disp) + IWineJSDispatchHost_AddRef(obj->builtin_info->get_host_disp(obj)); else ++obj->ref; return obj; @@ -1912,8 +1953,8 @@ ULONG jsdisp_release(jsdisp_t *obj) { ULONG ref; - if(obj->builtin_info->release) - return obj->builtin_info->release(obj); + if(obj->builtin_info->get_host_disp) + return IWineJSDispatchHost_Release(obj->builtin_info->get_host_disp(obj)); ref = --obj->ref; if(!ref) @@ -1942,6 +1983,21 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IWineJSDispatch *iface, REFIID r }else if(IsEqualGUID(&IID_IWineJSDispatch, riid)) { TRACE("(%p)->(IID_IWineJSDispatch %p)\n", This, ppv); *ppv = &This->IWineJSDispatch_iface; + }else if(IsEqualGUID(&IID_nsXPCOMCycleCollectionParticipant, riid)) { + /* Only expose these during a full CC, as we can't have their refs change between incremental CC phases */ + if(!This->builtin_info->get_host_disp && cc_api.is_full_cc && cc_api.is_full_cc()) { + *ppv = &cc_api.participant; + return S_OK; + } + *ppv = NULL; + return E_NOINTERFACE; + }else if(IsEqualGUID(&IID_nsCycleCollectionISupports, riid)) { + if(!This->builtin_info->get_host_disp && cc_api.is_full_cc && cc_api.is_full_cc()) { + *ppv = &This->IWineJSDispatch_iface; + return S_OK; + } + *ppv = NULL; + return E_NOINTERFACE; }else { WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); *ppv = NULL; @@ -1955,8 +2011,8 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IWineJSDispatch *iface, REFIID r static ULONG WINAPI DispatchEx_AddRef(IWineJSDispatch *iface) { jsdisp_t *This = impl_from_IWineJSDispatch(iface); - if(This->builtin_info->addref) - return This->builtin_info->addref(This); + if(This->builtin_info->get_host_disp) + return IWineJSDispatchHost_AddRef(This->builtin_info->get_host_disp(This)); jsdisp_addref(This); return This->ref; } @@ -2135,7 +2191,6 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatch *iface, DISPID id, LCI { jsdisp_t *This = impl_from_IWineJSDispatch(iface); IServiceProvider *prev_caller; - dispex_prop_t *prop; jsexcept_t ei; HRESULT hres; @@ -2144,8 +2199,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatch *iface, DISPID id, LCI if(pvarRes) V_VT(pvarRes) = VT_EMPTY; - prop = get_prop(This, id); - if(!prop && id != DISPID_VALUE) { + if(prop_kind(This, id) == INVALID_PROP && id != DISPID_VALUE) { TRACE("invalid id\n"); return DISP_E_MEMBERNOTFOUND; } @@ -2172,8 +2226,8 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatch *iface, DISPID id, LCI break; passed_this = get_this(pdp); - if(prop) - hres = invoke_prop_func(This, passed_this, prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller); + if(id != DISPID_VALUE) + hres = invoke_prop_func(This, passed_this, id, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller); else hres = jsdisp_call_value(This, passed_this ? jsval_disp(passed_this) : jsval_undefined(), wFlags, argc, argv, pvarRes ? &r : NULL); @@ -2190,8 +2244,8 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatch *iface, DISPID id, LCI case DISPATCH_PROPERTYGET: { jsval_t r; - if(prop) - hres = prop_get(This, to_disp(This), prop, &r); + if(id != DISPID_VALUE) + hres = prop_get(This, to_disp(This), id, &r); else { hres = to_primitive(This->ctx, jsval_obj(This), &r, NO_HINT); if(hres == JS_E_TO_PRIMITIVE) @@ -2210,7 +2264,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatch *iface, DISPID id, LCI jsval_t val; DWORD i; - if(!prop) { + if(id == DISPID_VALUE) { hres = DISP_E_MEMBERNOTFOUND; break; } @@ -2230,7 +2284,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatch *iface, DISPID id, LCI if(FAILED(hres)) break; - hres = prop_put(This, prop, val); + hres = prop_put(This, id, val); jsval_release(val); break; } @@ -2246,8 +2300,26 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IWineJSDispatch *iface, DISPID id, LCI return leave_script(This->ctx, hres); } -static HRESULT delete_prop(jsdisp_t *obj, dispex_prop_t *prop, BOOL *ret) +static HRESULT delete_prop(jsdisp_t *obj, DISPID id, BOOL *ret) { + dispex_prop_t *prop; + HRESULT hres; + + if(obj->builtin_info->prop_delete) { + hres = obj->builtin_info->prop_delete(obj, id); + if(hres != S_FALSE) { + *ret = TRUE; + return hres; + } + } + + if(is_indexed_prop_id(id)) { + /* indexed props are not configurable */ + *ret = FALSE; + return S_OK; + } + + prop = &obj->props[prop_id_to_idx(id)]; if(prop->type == PROP_PROTREF || prop->type == PROP_DELETED) { *ret = TRUE; return S_OK; @@ -2260,27 +2332,7 @@ static HRESULT delete_prop(jsdisp_t *obj, dispex_prop_t *prop, BOOL *ret) *ret = TRUE; - switch(prop->type) { - case PROP_JSVAL: - jsval_release(prop->u.val); - break; - case PROP_ACCESSOR: - if(prop->u.accessor.getter) - jsdisp_release(prop->u.accessor.getter); - if(prop->u.accessor.setter) - jsdisp_release(prop->u.accessor.setter); - break; - case PROP_EXTERN: - if(obj->builtin_info->prop_delete) { - HRESULT hres; - hres = obj->builtin_info->prop_delete(obj, prop->u.id); - if(FAILED(hres)) - return hres; - } - break; - default: - break; - } + release_prop(prop); prop->type = PROP_DELETED; return S_OK; } @@ -2288,7 +2340,7 @@ static HRESULT delete_prop(jsdisp_t *obj, dispex_prop_t *prop, BOOL *ret) static HRESULT WINAPI DispatchEx_DeleteMemberByName(IWineJSDispatch *iface, BSTR bstrName, DWORD grfdex) { jsdisp_t *This = impl_from_IWineJSDispatch(iface); - dispex_prop_t *prop; + DISPID id; BOOL b; HRESULT hres; @@ -2297,43 +2349,39 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IWineJSDispatch *iface, BSTR if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) FIXME("Unsupported grfdex %lx\n", grfdex); - hres = find_prop_name(This, string_hash(bstrName), bstrName, grfdex & fdexNameCaseInsensitive, NULL, &prop); + hres = find_prop_name(This, string_hash(bstrName), bstrName, grfdex & fdexNameCaseInsensitive, NULL, &id); if(FAILED(hres)) return hres; - if(!prop) { + if(hres != S_OK) { TRACE("not found\n"); return S_OK; } - return delete_prop(This, prop, &b); + return delete_prop(This, id, &b); } static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IWineJSDispatch *iface, DISPID id) { jsdisp_t *This = impl_from_IWineJSDispatch(iface); - dispex_prop_t *prop; BOOL b; TRACE("(%p)->(%lx)\n", This, id); - prop = get_prop(This, id); - if(!prop) { + if(prop_kind(This, id) == INVALID_PROP) { WARN("invalid id\n"); return DISP_E_MEMBERNOTFOUND; } - return delete_prop(This, prop, &b); + return delete_prop(This, id, &b); } static HRESULT WINAPI DispatchEx_GetMemberProperties(IWineJSDispatch *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) { jsdisp_t *This = impl_from_IWineJSDispatch(iface); - dispex_prop_t *prop; TRACE("(%p)->(%lx %lx %p)\n", This, id, grfdexFetch, pgrfdex); - prop = get_prop(This, id); - if(!prop) + if(prop_kind(This, id) == INVALID_PROP) return DISP_E_MEMBERNOTFOUND; *pgrfdex = 0; @@ -2348,17 +2396,23 @@ static HRESULT WINAPI DispatchEx_GetMemberProperties(IWineJSDispatch *iface, DIS static HRESULT WINAPI DispatchEx_GetMemberName(IWineJSDispatch *iface, DISPID id, BSTR *pbstrName) { jsdisp_t *This = impl_from_IWineJSDispatch(iface); - dispex_prop_t *prop; + WCHAR buf[11]; TRACE("(%p)->(%lx %p)\n", This, id, pbstrName); - prop = get_prop(This, id); - if(!prop) + switch(prop_kind(This, id)) { + case DISPEX_PROP: + if(!(*pbstrName = SysAllocString(This->props[prop_id_to_idx(id)].name))) + return E_OUTOFMEMORY; + break; + case INDEXED_PROP: + swprintf(buf, ARRAY_SIZE(buf), L"%u", indexed_prop_id_to_idx(id)); + if(!(*pbstrName = SysAllocString(buf))) + return E_OUTOFMEMORY; + break; + default: return DISP_E_MEMBERNOTFOUND; - - *pbstrName = SysAllocString(prop->name); - if(!*pbstrName) - return E_OUTOFMEMORY; + } return S_OK; } @@ -2390,18 +2444,88 @@ static void WINAPI WineJSDispatch_Free(IWineJSDispatch *iface) jsdisp_free(This); } +static void WINAPI WineJSDispatch_Traverse(IWineJSDispatch *iface, nsCycleCollectionTraversalCallback *cb) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + note_edge_t note_edge = cc_api.note_edge; + dispex_prop_t *prop = This->props, *end; + + for(end = prop + This->prop_cnt; prop < end; prop++) { + switch(prop->type) { + case PROP_JSVAL: + if(is_object_instance(prop->u.val)) + note_edge(get_edge_obj(get_object(prop->u.val)), "prop", cb); + break; + case PROP_ACCESSOR: + if(prop->u.accessor.getter) + note_edge(jsdisp_get_edge_obj(prop->u.accessor.getter), "prop", cb); + if(prop->u.accessor.setter) + note_edge(jsdisp_get_edge_obj(prop->u.accessor.setter), "prop", cb); + break; + default: + break; + } + } + + if(This->prototype) + note_edge(jsdisp_get_edge_obj(This->prototype), "prototype", cb); + + if(This->builtin_info->cc_traverse) + This->builtin_info->cc_traverse(This, cb); +} + +static void WINAPI WineJSDispatch_Unlink(IWineJSDispatch *iface) +{ + unlink_jsdisp(impl_from_IWineJSDispatch(iface)); +} + static HRESULT WINAPI WineJSDispatch_GetPropertyFlags(IWineJSDispatch *iface, DISPID id, UINT32 *ret) { jsdisp_t *This = impl_from_IWineJSDispatch(iface); - dispex_prop_t *prop = get_prop(This, id); - if(!prop || prop->type == PROP_DELETED || prop->type == PROP_PROTREF) + switch(prop_kind(This, id)) { + case DISPEX_PROP: { + dispex_prop_t *prop = &This->props[prop_id_to_idx(id)]; + + if(prop->type == PROP_PROTREF) + return DISP_E_MEMBERNOTFOUND; + *ret = prop->flags & PROPF_PUBLIC_MASK; + break; + } + case INDEXED_PROP: { + property_desc_t prop_desc; + + if(This->builtin_info->prop_get_desc(This, id, TRUE, &prop_desc) != S_OK) + return DISP_E_MEMBERNOTFOUND; + *ret = prop_desc.flags & PROPF_PUBLIC_MASK; + break; + } + default: return DISP_E_MEMBERNOTFOUND; + } - *ret = prop->flags & PROPF_PUBLIC_MASK; return S_OK; } +static HRESULT WINAPI WineJSDispatch_UpdateProperty(IWineJSDispatch *iface, struct property_info *desc) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(iface); + const WCHAR *name = desc->name; + dispex_prop_t *prop; + HRESULT hres = S_OK; + WCHAR buf[12]; + + if(!name) { + swprintf(buf, ARRAYSIZE(buf), L"%u", desc->index); + name = buf; + } + + if(!(prop = lookup_dispex_prop(This, string_hash(name), name, FALSE))) + hres = update_external_prop(This, name, NULL, desc, &prop); + + return hres; +} + static HRESULT WINAPI WineJSDispatch_GetScriptGlobal(IWineJSDispatch *iface, IWineJSDispatchHost **ret) { jsdisp_t *This = impl_from_IWineJSDispatch(iface); @@ -2417,6 +2541,11 @@ static HRESULT WINAPI WineJSDispatch_GetScriptGlobal(IWineJSDispatch *iface, IWi return S_OK; } +static HRESULT WINAPI WineJSDispatch_GetRandomValues(IWineJSDispatch *iface, IDispatch *typedarr) +{ + return typed_array_get_random_values(typedarr); +} + static IWineJSDispatchVtbl DispatchExVtbl = { DispatchEx_QueryInterface, DispatchEx_AddRef, @@ -2434,8 +2563,12 @@ static IWineJSDispatchVtbl DispatchExVtbl = { DispatchEx_GetNextDispID, DispatchEx_GetNameSpaceParent, WineJSDispatch_Free, + WineJSDispatch_Traverse, + WineJSDispatch_Unlink, WineJSDispatch_GetPropertyFlags, + WineJSDispatch_UpdateProperty, WineJSDispatch_GetScriptGlobal, + WineJSDispatch_GetRandomValues, }; jsdisp_t *as_jsdisp(IDispatch *disp) @@ -2512,14 +2645,14 @@ HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsd HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *constr) { jsdisp_t *prot = NULL; - dispex_prop_t *prop; HRESULT hres; + DISPID id; - hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", FALSE, NULL, &prop); - if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) { + hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", FALSE, NULL, &id); + if(hres == S_OK) { jsval_t val; - hres = prop_get(constr, to_disp(constr), prop, &val); + hres = prop_get(constr, to_disp(constr), id, &val); if(FAILED(hres)) { ERR("Could not get prototype\n"); return hres; @@ -2547,24 +2680,46 @@ jsdisp_t *iface_to_jsdisp(IDispatch *iface) : NULL; } +static HRESULT WINAPI jsdisp_cc_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb) +{ + jsdisp_t *This = impl_from_IWineJSDispatch(p); + + cc_api.describe_node(This->ref, "jsdisp", cb); + WineJSDispatch_Traverse(&This->IWineJSDispatch_iface, cb); + return S_OK; +} + +static HRESULT WINAPI jsdisp_cc_unlink(void *p) +{ + unlink_jsdisp(impl_from_IWineJSDispatch(p)); + return S_OK; +} + +struct jshost_cc_api cc_api; + +void init_cc_api(IWineJSDispatchHost *host_obj) +{ + static const CCObjCallback jsdisp_ccp_callback = { + jsdisp_cc_traverse, + jsdisp_cc_unlink, + NULL /* delete_cycle_collectable shouldn't ever be called, since we're never part of the purple buffer */ + }; + + IWineJSDispatchHost_InitCC(host_obj, &cc_api, &jsdisp_ccp_callback); +} + HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id) { - dispex_prop_t *prop; HRESULT hres; if(jsdisp->extensible && (flags & fdexNameEnsure)) hres = ensure_prop_name(jsdisp, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, - flags & fdexNameCaseInsensitive, &prop); + flags & fdexNameCaseInsensitive, id); else - hres = find_prop_name_prot(jsdisp, string_hash(name), name, flags & fdexNameCaseInsensitive, NULL, &prop); - if(FAILED(hres)) + hres = find_prop_name_prot(jsdisp, string_hash(name), name, flags & fdexNameCaseInsensitive, NULL, id); + if(hres != S_FALSE) return hres; - if(prop && prop->type!=PROP_DELETED) { - *id = prop_to_id(jsdisp, prop); - return S_OK; - } - TRACE("not found %s\n", debugstr_w(name)); *id = DISPID_UNKNOWN; return DISP_E_UNKNOWNNAME; @@ -2603,28 +2758,22 @@ HRESULT jsdisp_call_value(jsdisp_t *jsfunc, jsval_t vthis, WORD flags, unsigned HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - dispex_prop_t *prop; - - prop = get_prop(disp, id); - if(!prop) + if(prop_kind(disp, id) == INVALID_PROP) return DISP_E_MEMBERNOTFOUND; - return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); + return invoke_prop_func(disp, to_disp(disp), id, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); } HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - dispex_prop_t *prop; HRESULT hres; + DISPID id; - hres = find_prop_name_prot(disp, string_hash(name), name, FALSE, NULL, &prop); - if(FAILED(hres)) - return hres; - - if(!prop || prop->type == PROP_DELETED) - return JS_E_INVALID_PROPERTY; + hres = find_prop_name_prot(disp, string_hash(name), name, FALSE, NULL, &id); + if(hres != S_OK) + return FAILED(hres) ? hres : JS_E_INVALID_PROPERTY; - return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); + return invoke_prop_func(disp, to_disp(disp), id, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); } static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *params, VARIANT *r, @@ -2841,19 +2990,19 @@ HRESULT disp_call_value_with_caller(script_ctx_t *ctx, IDispatch *disp, jsval_t HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, BOOL throw, jsval_t val) { - dispex_prop_t *prop; HRESULT hres; + DISPID id; if(obj->extensible) - hres = ensure_prop_name(obj, name, flags, FALSE, &prop); + hres = ensure_prop_name(obj, name, flags, FALSE, &id); else - hres = find_prop_name(obj, string_hash(name), name, FALSE, NULL, &prop); + hres = find_prop_name(obj, string_hash(name), name, FALSE, NULL, &id); if(FAILED(hres)) return hres; - if(!prop || (prop->type == PROP_DELETED && !obj->extensible)) + if(hres != S_OK && (!id || !obj->extensible)) return throw ? JS_E_INVALID_ACTION : S_OK; - return prop_put(obj, prop, val); + return prop_put(obj, id, val); } HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val) @@ -2876,11 +3025,8 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val) jsdisp = iface_to_jsdisp(disp); if(jsdisp && jsdisp->ctx == ctx) { - dispex_prop_t *prop; - - prop = get_prop(jsdisp, id); - if(prop) - hres = prop_put(jsdisp, prop, val); + if(prop_kind(jsdisp, id) != INVALID_PROP) + hres = prop_put(jsdisp, id, val); else hres = DISP_E_MEMBERNOTFOUND; @@ -2945,50 +3091,47 @@ HRESULT disp_propput_name(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val) { - dispex_prop_t *prop; HRESULT hres; + DISPID id; - hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, NULL, &prop); + hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, NULL, &id); if(FAILED(hres)) return hres; - if(!prop || prop->type==PROP_DELETED) { + if(hres != S_OK) { *val = jsval_undefined(); return S_OK; } - return prop_get(obj, to_disp(obj), prop, val); + return prop_get(obj, to_disp(obj), id, val); } HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) { WCHAR name[12]; - dispex_prop_t *prop; HRESULT hres; + DISPID id; swprintf(name, ARRAY_SIZE(name), L"%d", idx); - hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, NULL, &prop); + hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, NULL, &id); if(FAILED(hres)) return hres; - if(!prop || prop->type==PROP_DELETED) { + if(hres != S_OK) { *r = jsval_undefined(); return DISP_E_UNKNOWNNAME; } - return prop_get(obj, to_disp(obj), prop, r); + return prop_get(obj, to_disp(obj), id, r); } HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val) { - dispex_prop_t *prop; - - prop = get_prop(jsdisp, id); - if(!prop) + if(prop_kind(jsdisp, id) == INVALID_PROP) return DISP_E_MEMBERNOTFOUND; - return prop_get(jsdisp, to_disp(jsdisp), prop, val); + return prop_get(jsdisp, to_disp(jsdisp), id, val); } HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val) @@ -3019,17 +3162,17 @@ HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx) { WCHAR buf[12]; - dispex_prop_t *prop; + DISPID id; BOOL b; HRESULT hres; swprintf(buf, ARRAY_SIZE(buf), L"%d", idx); - hres = find_prop_name(obj, string_hash(buf), buf, FALSE, NULL, &prop); - if(FAILED(hres) || !prop) - return hres; + hres = find_prop_name(obj, string_hash(buf), buf, FALSE, NULL, &id); + if(hres != S_OK) + return FAILED(hres) ? hres : S_OK; - hres = delete_prop(obj, prop, &b); + hres = delete_prop(obj, id, &b); if(FAILED(hres)) return hres; return b ? S_OK : JS_E_INVALID_ACTION; @@ -3043,11 +3186,8 @@ HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret) jsdisp = iface_to_jsdisp(disp); if(jsdisp) { - dispex_prop_t *prop; - - prop = get_prop(jsdisp, id); - if(prop) - hres = delete_prop(jsdisp, prop, ret); + if(prop_kind(jsdisp, id) != INVALID_PROP) + hres = delete_prop(jsdisp, id, ret); else hres = DISP_E_MEMBERNOTFOUND; @@ -3073,15 +3213,28 @@ HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret) HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_type, DISPID *ret) { dispex_prop_t *iter; - DWORD idx = id; + BOOL fill = FALSE; HRESULT hres; + DWORD idx; + + id = (id == DISPID_STARTENUM) ? indexed_prop_idx_to_id(0) : id + 1; + if(is_indexed_prop_id(id)) { + property_desc_t desc; + + if(obj->builtin_info->indexed_len && indexed_prop_id_to_idx(id) < obj->builtin_info->indexed_len(obj) && + obj->builtin_info->prop_get_desc(obj, id, TRUE, &desc) == S_OK) { + *ret = id; + return S_OK; + } + fill = TRUE; + id = 1; + } + idx = prop_id_to_idx(id); - if(id == DISPID_STARTENUM || idx >= obj->prop_cnt) { + if(fill || idx >= obj->prop_cnt) { hres = (enum_type == JSDISP_ENUM_ALL) ? fill_protrefs(obj) : fill_props(obj); if(FAILED(hres)) return hres; - if(id == DISPID_STARTENUM) - idx = 0; if(idx >= obj->prop_cnt) return S_FALSE; } @@ -3097,7 +3250,7 @@ HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_ty continue; if(enum_type != JSDISP_ENUM_ALL && iter->type == PROP_PROTREF) continue; - if(enum_type != JSDISP_ENUM_OWN && !(get_flags(obj, iter) & PROPF_ENUMERABLE)) + if(enum_type != JSDISP_ENUM_OWN && !is_enumerable(obj, iter)) continue; *ret = prop_to_id(obj, iter); return S_OK; @@ -3118,8 +3271,8 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL jsdisp = iface_to_jsdisp(disp); if(jsdisp) { - dispex_prop_t *prop; const WCHAR *ptr; + DISPID id; ptr = jsstr_flatten(name); if(!ptr) { @@ -3127,10 +3280,10 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL return E_OUTOFMEMORY; } - hres = find_prop_name(jsdisp, string_hash(ptr), ptr, FALSE, NULL, &prop); - if(prop) { - hres = delete_prop(jsdisp, prop, ret); - }else { + hres = find_prop_name(jsdisp, string_hash(ptr), ptr, FALSE, NULL, &id); + if(hres == S_OK) + hres = delete_prop(jsdisp, id, ret); + else { *ret = TRUE; hres = S_OK; } @@ -3173,29 +3326,38 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl { dispex_prop_t *prop; HRESULT hres; + DISPID id; - hres = find_prop_name(obj, string_hash(name), name, FALSE, NULL, &prop); + hres = find_prop_name(obj, string_hash(name), name, FALSE, NULL, &id); if(FAILED(hres)) return hres; - if(!prop) + if(hres != S_OK) return DISP_E_UNKNOWNNAME; - memset(desc, 0, sizeof(*desc)); + desc->mask = PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE; + if(obj->builtin_info->prop_get_desc) { + hres = obj->builtin_info->prop_get_desc(obj, id, flags_only, desc); + if(hres != S_FALSE) { + desc->explicit_value = TRUE; + return hres; + } + } + + prop = &obj->props[prop_id_to_idx(id)]; switch(prop->type) { case PROP_BUILTIN: case PROP_JSVAL: - case PROP_EXTERN: - desc->mask |= PROPF_WRITABLE; desc->explicit_value = TRUE; if(!flags_only) { - hres = prop_get(obj, to_disp(obj), prop, &desc->value); + hres = prop_get(obj, to_disp(obj), id, &desc->value); if(FAILED(hres)) return hres; } break; case PROP_ACCESSOR: + desc->mask = PROPF_ENUMERABLE | PROPF_CONFIGURABLE; desc->explicit_getter = desc->explicit_setter = TRUE; if(!flags_only) { desc->getter = prop->u.accessor.getter @@ -3209,7 +3371,45 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl } desc->flags = prop->flags & (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE); - desc->mask |= PROPF_ENUMERABLE | PROPF_CONFIGURABLE; + return S_OK; +} + +static HRESULT define_existing_indexed_prop(jsdisp_t *obj, const WCHAR *name, DISPID id, const property_desc_t *desc) +{ + property_desc_t prop_desc; + HRESULT hres; + jsval_t val; + BOOL eq; + + TRACE("existing indexed prop %s desc flags %x desc mask %x\n", debugstr_w(name), desc->flags, desc->mask); + + if((desc->mask & desc->flags & (PROPF_CONFIGURABLE | PROPF_ENUMERABLE)) != (desc->mask & PROPF_ENUMERABLE)) + return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); + + if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) { + if(obj->builtin_info->prop_get_desc(obj, id, TRUE, &prop_desc) == S_OK && !(prop_desc.flags & PROPF_WRITABLE)) { + if(desc->mask & desc->flags & PROPF_WRITABLE) + return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name); + if(desc->explicit_value) { + hres = obj->builtin_info->prop_get(obj, id, &val); + if(FAILED(hres)) + return hres; + hres = jsval_strict_equal(desc->value, val, &eq); + jsval_release(val); + if(FAILED(hres)) + return hres; + if(!eq) + return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name); + } + }else if(desc->explicit_value) { + hres = obj->builtin_info->prop_put(obj, id, desc->value); + if(FAILED(hres)) + return hres; + } + }else if(desc->explicit_getter || desc->explicit_setter) { + return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); + } + return S_OK; } @@ -3217,16 +3417,40 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t { dispex_prop_t *prop; HRESULT hres; + DISPID id; - hres = find_prop_name(obj, string_hash(name), name, FALSE, NULL, &prop); + hres = find_prop_name(obj, string_hash(name), name, FALSE, NULL, &id); if(FAILED(hres)) return hres; - if((!prop || prop->type == PROP_DELETED || prop->type == PROP_PROTREF) && !obj->extensible) + if(hres == S_OK) { + if(is_indexed_prop_id(id)) { + if(obj->builtin_info->prop_define) { + hres = obj->builtin_info->prop_define(obj, id, desc); + if(hres != S_FALSE) + return hres; + } + return define_existing_indexed_prop(obj, name, id, desc); + } + + prop = &obj->props[prop_id_to_idx(id)]; + if((prop->type == PROP_DELETED || prop->type == PROP_PROTREF) && !obj->extensible) + return throw_error(obj->ctx, JS_E_OBJECT_NONEXTENSIBLE, name); + }else if(!obj->extensible) { return throw_error(obj->ctx, JS_E_OBJECT_NONEXTENSIBLE, name); + }else if(id) { + prop = &obj->props[prop_id_to_idx(id)]; + }else { + if(!(prop = alloc_prop(obj, name, PROP_DELETED, 0))) + return E_OUTOFMEMORY; + id = prop_to_id(obj, prop); + } - if(!prop && !(prop = alloc_prop(obj, name, PROP_DELETED, 0))) - return E_OUTOFMEMORY; + if(obj->builtin_info->prop_define) { + hres = obj->builtin_info->prop_define(obj, id, desc); + if(hres != S_FALSE) + return hres; + } if(prop->type == PROP_DELETED || prop->type == PROP_PROTREF) { prop->flags = desc->flags; @@ -3293,16 +3517,16 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t } } if(desc->explicit_value) { - if(prop->type == PROP_JSVAL) - jsval_release(prop->u.val); - else { - if(prop->type == PROP_EXTERN && obj->builtin_info->prop_delete) { - hres = obj->builtin_info->prop_delete(obj, prop->u.id); - if(FAILED(hres)) - return hres; - } - prop->type = PROP_JSVAL; - } + DWORD flags = prop->flags; + BOOL tmp; + + prop->flags |= PROPF_CONFIGURABLE; + hres = delete_prop(obj, prop_to_id(obj, prop), &tmp); + prop->flags = flags; + if(FAILED(hres)) + return hres; + + prop->type = PROP_JSVAL; hres = jsval_copy(desc->value, &prop->u.val); if(FAILED(hres)) { prop->u.val = jsval_undefined(); @@ -3382,7 +3606,7 @@ HRESULT jsdisp_change_prototype(jsdisp_t *obj, jsdisp_t *proto) static void set_prop_flags(jsdisp_t *obj, dispex_prop_t *prop, UINT32 flags) { - if(prop->type == PROP_EXTERN && obj->builtin_info->prop_config) { + if(prop->type == PROP_EXTERN) { HRESULT hres = obj->builtin_info->prop_config(obj, prop->u.id, flags); if(hres != S_OK) return; @@ -3428,12 +3652,22 @@ BOOL jsdisp_is_frozen(jsdisp_t *obj, BOOL sealed) HRESULT jsdisp_get_prop_name(jsdisp_t *obj, DISPID id, jsstr_t **r) { - dispex_prop_t *prop = get_prop(obj, id); + const WCHAR *name; + WCHAR buf[11]; - if(!prop) + switch(prop_kind(obj, id)) { + case DISPEX_PROP: + name = obj->props[prop_id_to_idx(id)].name; + break; + case INDEXED_PROP: + swprintf(buf, ARRAY_SIZE(buf), L"%u", indexed_prop_id_to_idx(id)); + name = buf; + break; + default: return DISP_E_MEMBERNOTFOUND; + } - *r = jsstr_alloc(prop->name); + *r = jsstr_alloc(name); return *r ? S_OK : E_OUTOFMEMORY; } @@ -3447,16 +3681,10 @@ static inline HostObject *HostObject_from_jsdisp(jsdisp_t *jsdisp) return CONTAINING_RECORD(jsdisp, HostObject, jsdisp); } -static ULONG HostObject_addref(jsdisp_t *jsdisp) -{ - HostObject *This = HostObject_from_jsdisp(jsdisp); - return IWineJSDispatchHost_AddRef(This->host_iface); -} - -static ULONG HostObject_release(jsdisp_t *jsdisp) +static IWineJSDispatchHost *HostObject_get_host_disp(jsdisp_t *jsdisp) { HostObject *This = HostObject_from_jsdisp(jsdisp); - return IWineJSDispatchHost_Release(This->host_iface); + return This->host_iface; } static HRESULT HostObject_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, unsigned flags, struct property_info *desc) @@ -3466,18 +3694,25 @@ static HRESULT HostObject_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, unsig return IWineJSDispatchHost_LookupProperty(This->host_iface, name, flags, desc); } -static HRESULT HostObject_prop_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) +static HRESULT HostObject_prop_get(jsdisp_t *jsdisp, DISPID id, jsval_t *r) { + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; HostObject *This = HostObject_from_jsdisp(jsdisp); EXCEPINFO ei = { 0 }; VARIANT v; HRESULT hres; - V_VT(&v) = VT_EMPTY; - hres = IWineJSDispatchHost_GetProperty(This->host_iface, idx, jsdisp->ctx->lcid, &v, &ei, - &jsdisp->ctx->jscaller->IServiceProvider_iface); - if(hres == DISP_E_EXCEPTION) - handle_dispatch_exception(jsdisp->ctx, &ei); + hres = IWineJSDispatchHost_OverrideProperty(This->host_iface, prop->name, NULL, &v); + if(hres == S_FALSE) { + if(prop->type != PROP_EXTERN) + return S_FALSE; + + V_VT(&v) = VT_EMPTY; + hres = IWineJSDispatchHost_GetProperty(This->host_iface, prop->u.id, jsdisp->ctx->lcid, &v, &ei, + &jsdisp->ctx->jscaller->IServiceProvider_iface); + if(hres == DISP_E_EXCEPTION) + handle_dispatch_exception(jsdisp->ctx, &ei); + } if(FAILED(hres)) return hres; @@ -3486,37 +3721,109 @@ static HRESULT HostObject_prop_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) return hres; } -static HRESULT HostObject_prop_put(jsdisp_t *jsdisp, unsigned idx, jsval_t v) +static HRESULT HostObject_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t v) { + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; HostObject *This = HostObject_from_jsdisp(jsdisp); EXCEPINFO ei = { 0 }; VARIANT var; HRESULT hres; + if(prop->type != PROP_EXTERN) + return S_FALSE; + + if(!(prop->flags & PROPF_WRITABLE)) + return S_OK; + hres = jsval_to_variant(v, &var); if(FAILED(hres)) return hres; - hres = IWineJSDispatchHost_SetProperty(This->host_iface, idx, jsdisp->ctx->lcid, &var, &ei, + hres = IWineJSDispatchHost_SetProperty(This->host_iface, prop->u.id, jsdisp->ctx->lcid, &var, &ei, &jsdisp->ctx->jscaller->IServiceProvider_iface); if(hres == DISP_E_EXCEPTION) handle_dispatch_exception(jsdisp->ctx, &ei); VariantClear(&var); - return hres; + if(hres != S_FALSE) + return hres; + + prop->type = PROP_JSVAL; + prop->flags = PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE; + prop->u.val = jsval_undefined(); + return jsval_copy(v, &prop->u.val); } -static HRESULT HostObject_next_prop(jsdisp_t *jsdisp, unsigned id, struct property_info *desc) +static HRESULT HostObject_prop_delete(jsdisp_t *jsdisp, DISPID id) { + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; HostObject *This = HostObject_from_jsdisp(jsdisp); + HRESULT hres; + + hres = IWineJSDispatchHost_OverrideProperty(This->host_iface, prop->name, NULL, NULL); + if(hres != S_FALSE) + return hres; + + if(prop->type != PROP_EXTERN || !(prop->flags & PROPF_CONFIGURABLE)) + return S_FALSE; + + hres = IWineJSDispatchHost_DeleteProperty(This->host_iface, prop->u.id); + if(SUCCEEDED(hres)) + prop->type = PROP_DELETED; + return hres; +} + +static HRESULT HostObject_prop_get_desc(jsdisp_t *jsdisp, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; + + if(prop->type != PROP_EXTERN) + return S_FALSE; + + if(!flags_only) { + HRESULT hres = HostObject_prop_get(jsdisp, id, &desc->value); + if(hres != S_OK) + return hres; + } - return IWineJSDispatchHost_NextProperty(This->host_iface, id, desc); + desc->flags = prop->flags & (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE); + return S_OK; } -static HRESULT HostObject_prop_delete(jsdisp_t *jsdisp, unsigned id) +static HRESULT HostObject_prop_define(jsdisp_t *jsdisp, DISPID id, const property_desc_t *desc) { + dispex_prop_t *prop = &jsdisp->props[prop_id_to_idx(id)]; HostObject *This = HostObject_from_jsdisp(jsdisp); + struct property_info info; + EXCEPINFO ei = { 0 }; + HRESULT hres; + VARIANT var; + + /* Only defining values can be overridden */ + if(!desc->explicit_value) + return S_FALSE; + + hres = IWineJSDispatchHost_OverrideProperty(This->host_iface, prop->name, &info, NULL); + if(hres != S_OK) + return hres; + if(info.prototype_id) + return S_FALSE; + + hres = jsval_to_variant(desc->value, &var); + if(FAILED(hres)) + return hres; - return IWineJSDispatchHost_DeleteProperty(This->host_iface, id); + hres = IWineJSDispatchHost_SetProperty(This->host_iface, info.id, jsdisp->ctx->lcid, &var, &ei, + &jsdisp->ctx->jscaller->IServiceProvider_iface); + if(hres == DISP_E_EXCEPTION) + handle_dispatch_exception(jsdisp->ctx, &ei); + VariantClear(&var); + if(hres == S_OK) { + release_prop(prop); + prop->type = PROP_EXTERN; + prop->u.id = info.id; + prop->flags = info.flags & PROPF_ALL; + } + return hres; } static HRESULT HostObject_prop_config(jsdisp_t *jsdisp, unsigned id, unsigned flags) @@ -3526,6 +3833,13 @@ static HRESULT HostObject_prop_config(jsdisp_t *jsdisp, unsigned id, unsigned fl return IWineJSDispatchHost_ConfigureProperty(This->host_iface, id, flags); } +static HRESULT HostObject_fill_props(jsdisp_t *jsdisp) +{ + HostObject *This = HostObject_from_jsdisp(jsdisp); + + return IWineJSDispatchHost_FillProperties(This->host_iface); +} + static HRESULT HostObject_to_string(jsdisp_t *jsdisp, jsstr_t **ret) { HostObject *This = HostObject_from_jsdisp(jsdisp); @@ -3542,16 +3856,17 @@ static HRESULT HostObject_to_string(jsdisp_t *jsdisp, jsstr_t **ret) } static const builtin_info_t HostObject_info = { - .class = JSCLASS_HOST, - .addref = HostObject_addref, - .release = HostObject_release, - .lookup_prop = HostObject_lookup_prop, - .prop_get = HostObject_prop_get, - .prop_put = HostObject_prop_put, - .next_prop = HostObject_next_prop, - .prop_delete = HostObject_prop_delete, - .prop_config = HostObject_prop_config, - .to_string = HostObject_to_string, + .class = JSCLASS_HOST, + .get_host_disp = HostObject_get_host_disp, + .lookup_prop = HostObject_lookup_prop, + .prop_get = HostObject_prop_get, + .prop_put = HostObject_prop_put, + .prop_delete = HostObject_prop_delete, + .prop_get_desc = HostObject_prop_get_desc, + .prop_define = HostObject_prop_define, + .prop_config = HostObject_prop_config, + .fill_props = HostObject_fill_props, + .to_string = HostObject_to_string, }; HRESULT init_host_object(script_ctx_t *ctx, IWineJSDispatchHost *host_iface, IWineJSDispatch *prototype_iface, @@ -3561,6 +3876,9 @@ HRESULT init_host_object(script_ctx_t *ctx, IWineJSDispatchHost *host_iface, IWi jsdisp_t *prototype; HRESULT hres; + if(!cc_api.note_edge) + init_cc_api(host_iface); + if(!(host_obj = calloc(1, sizeof(*host_obj)))) return E_OUTOFMEMORY; @@ -3577,6 +3895,8 @@ HRESULT init_host_object(script_ctx_t *ctx, IWineJSDispatchHost *host_iface, IWi host_obj->host_iface = host_iface; if(flags & HOSTOBJ_CONSTRUCTOR) host_obj->jsdisp.is_constructor = TRUE; + if(flags & HOSTOBJ_VOLATILE_PROPS) + host_obj->jsdisp.has_volatile_props = TRUE; *ret = &host_obj->jsdisp.IWineJSDispatch_iface; return S_OK; } @@ -3584,15 +3904,33 @@ HRESULT init_host_object(script_ctx_t *ctx, IWineJSDispatchHost *host_iface, IWi IWineJSDispatchHost *get_host_dispatch(IDispatch *disp) { IWineJSDispatchHost *ret; - HostObject *host_obj; jsdisp_t *jsdisp; - if(!(jsdisp = to_jsdisp(disp))) - return NULL; - if(jsdisp->builtin_info != &HostObject_info) + if(!(jsdisp = to_jsdisp(disp)) || !jsdisp->builtin_info->get_host_disp) return NULL; - host_obj = HostObject_from_jsdisp(jsdisp); - IWineJSDispatchHost_GetOuterDispatch(host_obj->host_iface, &ret); + IWineJSDispatchHost_GetOuterDispatch(jsdisp->builtin_info->get_host_disp(jsdisp), &ret); return ret; } + +HRESULT fill_globals(script_ctx_t *ctx, IWineJSDispatchHost *script_global) +{ + jsdisp_t *global = ctx->global; + DISPID id = DISPID_STARTENUM; + struct property_info desc; + HRESULT hres; + + for(;;) { + hres = jsdisp_next_prop(global, id, JSDISP_ENUM_OWN, &id); + if(hres == S_FALSE) + break; + if(FAILED(hres)) + return hres; + + hres = IWineJSDispatchHost_LookupProperty(script_global, global->props[prop_id_to_idx(id)].name, fdexNameCaseSensitive, &desc); + if(FAILED(hres)) + return hres; + } + + return S_OK; +} diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index c95fcace84ab..7fe34421b089 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -142,12 +142,24 @@ static HRESULT stack_pop_object(script_ctx_t *ctx, IDispatch **r) static inline HRESULT stack_pop_int(script_ctx_t *ctx, INT *r) { - return to_int32(ctx, stack_pop(ctx), r); + jsval_t v; + HRESULT hres; + + v = stack_pop(ctx); + hres = to_int32(ctx, v, r); + jsval_release(v); + return hres; } static inline HRESULT stack_pop_uint(script_ctx_t *ctx, UINT32 *r) { - return to_uint32(ctx, stack_pop(ctx), r); + jsval_t v; + HRESULT hres; + + v = stack_pop(ctx); + hres = to_uint32(ctx, v, r); + jsval_release(v); + return hres; } static inline unsigned local_off(call_frame_t *frame, int ref) @@ -478,36 +490,51 @@ static void scope_destructor(jsdisp_t *dispex) IDispatch_Release(scope->obj); } -static HRESULT scope_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, unsigned flags, struct property_info *desc) +static unsigned scope_indexed_len(jsdisp_t *dispex) { - scope_chain_t *scope = scope_from_dispex(jsdisp); - - return jsdisp_index_lookup(&scope->dispex, name, scope->detached_vars->argc, desc); + return scope_from_dispex(dispex)->detached_vars->argc; } -static HRESULT scope_prop_get(jsdisp_t *dispex, unsigned idx, jsval_t *r) +static HRESULT scope_prop_get(jsdisp_t *dispex, DISPID id, jsval_t *r) { - scope_chain_t *scope = scope_from_dispex(dispex); - - return jsval_copy(scope->detached_vars->var[idx], r); + if(!is_indexed_prop_id(id)) + return S_FALSE; + return jsval_copy(scope_from_dispex(dispex)->detached_vars->var[indexed_prop_id_to_idx(id)], r); } -static HRESULT scope_prop_put(jsdisp_t *dispex, unsigned idx, jsval_t val) +static HRESULT scope_prop_put(jsdisp_t *dispex, DISPID id, jsval_t val) { scope_chain_t *scope = scope_from_dispex(dispex); jsval_t copy, *ref; HRESULT hres; + if(!is_indexed_prop_id(id)) + return S_FALSE; + hres = jsval_copy(val, ©); if(FAILED(hres)) return hres; - ref = &scope->detached_vars->var[idx]; + ref = &scope->detached_vars->var[indexed_prop_id_to_idx(id)]; jsval_release(*ref); *ref = copy; return S_OK; } +static HRESULT scope_prop_get_desc(jsdisp_t *dispex, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + if(!flags_only) { + HRESULT hres = scope_prop_get(dispex, id, &desc->value); + if(hres != S_OK) + return hres; + }else if(!is_indexed_prop_id(id)) { + return S_FALSE; + } + + desc->flags = PROPF_ENUMERABLE | PROPF_WRITABLE; + return S_OK; +} + static HRESULT scope_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) { scope_chain_t *scope = scope_from_dispex(dispex); @@ -543,13 +570,36 @@ static HRESULT scope_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, return scope->obj && (jsobj = to_jsdisp(scope->obj)) ? gc_process_linked_obj(gc_ctx, op, dispex, jsobj, (void**)&scope->obj) : S_OK; } +static void scope_cc_traverse(jsdisp_t *dispex, nsCycleCollectionTraversalCallback *cb) +{ + scope_chain_t *scope = scope_from_dispex(dispex); + note_edge_t note_edge = cc_api.note_edge; + + if(scope->detached_vars) { + struct vars_buffer *vars = scope->detached_vars; + unsigned i, cnt = vars->argc; + + for(i = 0; i < cnt; i++) + if(is_object_instance(vars->var[i])) + note_edge(get_edge_obj(get_object(vars->var[i])), "var", cb); + } + + if(scope->next) + note_edge((IUnknown*)&scope->next->dispex.IWineJSDispatch_iface, "next", cb); + + if(scope->obj) + note_edge(get_edge_obj(scope->obj), "obj", cb); +} + static const builtin_info_t scope_info = { - JSCLASS_NONE, - .destructor = scope_destructor, - .lookup_prop = scope_lookup_prop, - .prop_get = scope_prop_get, - .prop_put = scope_prop_put, - .gc_traverse = scope_gc_traverse + .class = JSCLASS_NONE, + .destructor = scope_destructor, + .indexed_len = scope_indexed_len, + .prop_get = scope_prop_get, + .prop_put = scope_prop_put, + .prop_get_desc = scope_prop_get_desc, + .gc_traverse = scope_gc_traverse, + .cc_traverse = scope_cc_traverse }; static HRESULT scope_push(script_ctx_t *ctx, scope_chain_t *scope, IDispatch *obj, scope_chain_t **ret) @@ -1840,7 +1890,7 @@ static HRESULT interp_carray_set(script_ctx_t *ctx) array = stack_top(ctx); assert(is_object_instance(array)); - hres = jsdisp_propput_idx(to_jsdisp(get_object(array)), index, value); + hres = jsdisp_propput_idx(as_jsdisp(get_object(array)), index, value); jsval_release(value); return hres; } @@ -1887,7 +1937,7 @@ static HRESULT interp_obj_prop(script_ctx_t *ctx) jsdisp_t *func; assert(is_object_instance(val)); - func = to_jsdisp(get_object(val)); + func = as_jsdisp(get_object(val)); desc.mask = desc.flags; if(type == PROPERTY_DEFINITION_GETTER) { diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c index 1f57f6b5173e..fa841aa30600 100644 --- a/dlls/jscript/enumerator.c +++ b/dlls/jscript/enumerator.c @@ -91,7 +91,25 @@ static void Enumerator_destructor(jsdisp_t *dispex) static HRESULT Enumerator_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) { - return gc_process_linked_val(gc_ctx, op, dispex, &enumerator_from_jsdisp(dispex)->item); + EnumeratorInstance *This = enumerator_from_jsdisp(dispex); + + if(op == GC_TRAVERSE_UNLINK) { + IEnumVARIANT *enumvar = This->enumvar; + if(enumvar) { + This->enumvar = NULL; + IEnumVARIANT_Release(enumvar); + } + } + return gc_process_linked_val(gc_ctx, op, dispex, &This->item); +} + +static void Enumerator_cc_traverse(jsdisp_t *dispex, nsCycleCollectionTraversalCallback *cb) +{ + EnumeratorInstance *This = enumerator_from_jsdisp(dispex); + if(This->enumvar) + cc_api.note_edge((IUnknown*)This->enumvar, "enumvar", cb); + if(is_object_instance(This->item)) + cc_api.note_edge(get_edge_obj(get_object(This->item)), "item", cb); } static HRESULT Enumerator_atEnd(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, @@ -189,7 +207,8 @@ static const builtin_info_t Enumerator_info = { static const builtin_info_t EnumeratorInst_info = { .class = JSCLASS_ENUMERATOR, .destructor = Enumerator_destructor, - .gc_traverse = Enumerator_gc_traverse + .gc_traverse = Enumerator_gc_traverse, + .cc_traverse = Enumerator_cc_traverse }; static HRESULT alloc_enumerator(script_ctx_t *ctx, jsdisp_t *object_prototype, EnumeratorInstance **ret) diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 3ff40a1e1e7b..681dd0c64348 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -495,6 +495,9 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_OBJECT_NONEXTENSIBLE: case JS_E_NONCONFIGURABLE_REDEFINED: case JS_E_NONWRITABLE_MODIFIED: + case JS_E_TYPEDARRAY_BAD_CTOR_ARG: + case JS_E_NOT_TYPEDARRAY: + case JS_E_TYPEDARRAY_INVALID_SOURCE: case JS_E_NOT_DATAVIEW: case JS_E_DATAVIEW_NO_ARGUMENT: case JS_E_WRONG_THIS: @@ -509,6 +512,8 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_FRACTION_DIGITS_OUT_OF_RANGE: case JS_E_PRECISION_OUT_OF_RANGE: case JS_E_INVALID_LENGTH: + case JS_E_TYPEDARRAY_INVALID_OFFSLEN: + case JS_E_TYPEDARRAY_INVALID_SUBARRAY: case JS_E_DATAVIEW_INVALID_ACCESS: case JS_E_DATAVIEW_INVALID_OFFSET: constr = ctx->range_error_constr; diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 5330bbae21f4..cc4927ef786b 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -40,6 +40,7 @@ struct _function_vtbl_t { function_code_t* (*get_code)(FunctionInstance*); void (*destructor)(FunctionInstance*); HRESULT (*gc_traverse)(struct gc_ctx*,enum gc_traverse_op,FunctionInstance*); + void (*cc_traverse)(FunctionInstance*,nsCycleCollectionTraversalCallback*); }; typedef struct { @@ -67,7 +68,7 @@ typedef struct { FunctionInstance function; const WCHAR *name; UINT32 id; - UINT32 iid; + INT32 prototype_id; UINT32 flags; } HostFunction; @@ -81,6 +82,7 @@ typedef struct { jsval_t *buf; scope_chain_t *scope; unsigned argc; + BYTE readonly_flags[]; } ArgumentsInstance; static HRESULT create_bind_function(script_ctx_t*,FunctionInstance*,jsval_t,unsigned,jsval_t*,jsdisp_t**r); @@ -90,6 +92,10 @@ static HRESULT no_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, Fun return S_OK; } +static void no_cc_traverse(FunctionInstance *function, nsCycleCollectionTraversalCallback *cb) +{ +} + static inline FunctionInstance *function_from_jsdisp(jsdisp_t *jsdisp) { return CONTAINING_RECORD(jsdisp, FunctionInstance, dispex); @@ -130,18 +136,6 @@ static void Arguments_destructor(jsdisp_t *jsdisp) scope_release(arguments->scope); } -static HRESULT Arguments_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, unsigned flags, struct property_info *desc) -{ - ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); - return jsdisp_index_lookup(&arguments->jsdisp, name, arguments->argc, desc); -} - -static HRESULT Arguments_next_prop(jsdisp_t *jsdisp, unsigned id, struct property_info *desc) -{ - ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); - return jsdisp_next_index(&arguments->jsdisp, arguments->argc, id, desc); -} - static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned idx) { if(arguments->buf) @@ -151,23 +145,39 @@ static jsval_t *get_argument_ref(ArgumentsInstance *arguments, unsigned idx) return arguments->scope->detached_vars->var + idx; } -static HRESULT Arguments_prop_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) +static unsigned Arguments_indexed_len(jsdisp_t *jsdisp) +{ + return arguments_from_jsdisp(jsdisp)->argc; +} + +static HRESULT Arguments_prop_get(jsdisp_t *jsdisp, DISPID id, jsval_t *r) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); - TRACE("%p[%u]\n", arguments, idx); + if(!is_indexed_prop_id(id)) + return S_FALSE; + + TRACE("%p[%u]\n", arguments, indexed_prop_id_to_idx(id)); - return jsval_copy(*get_argument_ref(arguments, idx), r); + return jsval_copy(*get_argument_ref(arguments, indexed_prop_id_to_idx(id)), r); } -static HRESULT Arguments_prop_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) +static HRESULT Arguments_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); jsval_t copy, *ref; + unsigned idx; HRESULT hres; + if(!is_indexed_prop_id(id)) + return S_FALSE; + idx = indexed_prop_id_to_idx(id); + TRACE("%p[%u] = %s\n", arguments, idx, debugstr_jsval(val)); + if(arguments->readonly_flags[idx / 8] & (1u << idx % 8)) + return S_OK; + hres = jsval_copy(val, ©); if(FAILED(hres)) return hres; @@ -178,6 +188,54 @@ static HRESULT Arguments_prop_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) return S_OK; } +static HRESULT Arguments_prop_get_desc(jsdisp_t *jsdisp, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + unsigned idx; + + if(!is_indexed_prop_id(id)) + return S_FALSE; + idx = indexed_prop_id_to_idx(id); + + if(!flags_only) { + HRESULT hres = Arguments_prop_get(jsdisp, id, &desc->value); + if(hres != S_OK) + return hres; + } + + desc->flags = PROPF_ENUMERABLE; + if(!(arguments->readonly_flags[idx / 8] & (1u << idx % 8))) + desc->flags |= PROPF_WRITABLE; + + return S_OK; +} + +static HRESULT Arguments_prop_define(jsdisp_t *jsdisp, DISPID id, const property_desc_t *desc) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + unsigned idx; + HRESULT hres; + + if(!is_indexed_prop_id(id)) + return S_FALSE; + idx = indexed_prop_id_to_idx(id); + + /* Need to keep track of props made read-only when going from writable to non-writable */ + if((desc->mask & PROPF_WRITABLE) && !(desc->flags & PROPF_WRITABLE) && !(arguments->readonly_flags[idx / 8] & (1u << idx % 8)) && + ((desc->mask & desc->flags & (PROPF_CONFIGURABLE | PROPF_ENUMERABLE)) == (desc->mask & PROPF_ENUMERABLE))) { + if(desc->explicit_value) { + hres = Arguments_prop_put(jsdisp, id, desc->value); + if(FAILED(hres)) + return hres; + } + arguments->readonly_flags[idx / 8] |= 1u << idx % 8; + return S_OK; + } + + /* Delegate the rest to the generic prop define */ + return S_FALSE; +} + static HRESULT Arguments_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *jsdisp) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); @@ -201,6 +259,22 @@ static HRESULT Arguments_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op return S_OK; } +static void Arguments_cc_traverse(jsdisp_t *jsdisp, nsCycleCollectionTraversalCallback *cb) +{ + ArgumentsInstance *arguments = arguments_from_jsdisp(jsdisp); + note_edge_t note_edge = cc_api.note_edge; + unsigned i; + + if(arguments->buf) { + for(i = 0; i < arguments->argc; i++) + if(is_object_instance(arguments->buf[i])) + note_edge(get_edge_obj(get_object(arguments->buf[i])), "buf", cb); + } + + if(arguments->scope) + note_edge((IUnknown*)&arguments->scope->dispex.IWineJSDispatch_iface, "scope", cb); +} + static HRESULT Arguments_get_caller(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { ArgumentsInstance *arguments = arguments_from_jsdisp(jsthis); @@ -233,27 +307,31 @@ static const builtin_prop_t Arguments_props[] = { }; static const builtin_info_t Arguments_info = { - .class = JSCLASS_ARGUMENTS, - .call = Arguments_value, - .props_cnt = ARRAY_SIZE(Arguments_props), - .props = Arguments_props, - .destructor = Arguments_destructor, - .lookup_prop = Arguments_lookup_prop, - .next_prop = Arguments_next_prop, - .prop_get = Arguments_prop_get, - .prop_put = Arguments_prop_put, - .gc_traverse = Arguments_gc_traverse + .class = JSCLASS_ARGUMENTS, + .call = Arguments_value, + .props_cnt = ARRAY_SIZE(Arguments_props), + .props = Arguments_props, + .destructor = Arguments_destructor, + .indexed_len = Arguments_indexed_len, + .prop_get = Arguments_prop_get, + .prop_put = Arguments_prop_put, + .prop_get_desc = Arguments_prop_get_desc, + .prop_define = Arguments_prop_define, + .gc_traverse = Arguments_gc_traverse, + .cc_traverse = Arguments_cc_traverse }; static const builtin_info_t Arguments_ES5_info = { - .class = JSCLASS_ARGUMENTS, - .call = Arguments_value, - .destructor = Arguments_destructor, - .lookup_prop = Arguments_lookup_prop, - .next_prop = Arguments_next_prop, - .prop_get = Arguments_prop_get, - .prop_put = Arguments_prop_put, - .gc_traverse = Arguments_gc_traverse + .class = JSCLASS_ARGUMENTS, + .call = Arguments_value, + .destructor = Arguments_destructor, + .indexed_len = Arguments_indexed_len, + .prop_get = Arguments_prop_get, + .prop_put = Arguments_prop_put, + .prop_get_desc = Arguments_prop_get_desc, + .prop_define = Arguments_prop_define, + .gc_traverse = Arguments_gc_traverse, + .cc_traverse = Arguments_cc_traverse }; HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame) @@ -261,7 +339,7 @@ HRESULT setup_arguments_object(script_ctx_t *ctx, call_frame_t *frame) ArgumentsInstance *args; HRESULT hres; - args = calloc(1, sizeof(*args)); + args = calloc(1, FIELD_OFFSET(ArgumentsInstance, readonly_flags[(frame->argc + 7) / 8])); if(!args) return E_OUTOFMEMORY; @@ -674,6 +752,12 @@ static HRESULT Function_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op o return function->vtbl->gc_traverse(gc_ctx, op, function); } +static void Function_cc_traverse(jsdisp_t *dispex, nsCycleCollectionTraversalCallback *cb) +{ + FunctionInstance *function = function_from_jsdisp(dispex); + return function->vtbl->cc_traverse(function, cb); +} + static const builtin_prop_t Function_props[] = { {L"apply", Function_apply, PROPF_METHOD|2}, {L"arguments", NULL, PROPF_HTML, Function_get_arguments}, @@ -690,7 +774,8 @@ static const builtin_info_t Function_info = { .props_cnt = ARRAY_SIZE(Function_props), .props = Function_props, .destructor = Function_destructor, - .gc_traverse = Function_gc_traverse + .gc_traverse = Function_gc_traverse, + .cc_traverse = Function_cc_traverse }; static const builtin_prop_t FunctionInst_props[] = { @@ -705,11 +790,12 @@ static const builtin_info_t FunctionInst_info = { .props_cnt = ARRAY_SIZE(FunctionInst_props), .props = FunctionInst_props, .destructor = Function_destructor, - .gc_traverse = Function_gc_traverse + .gc_traverse = Function_gc_traverse, + .cc_traverse = Function_cc_traverse }; static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_info, const function_vtbl_t *vtbl, size_t size, - DWORD flags, BOOL funcprot, jsdisp_t *prototype, void **ret) + DWORD flags, jsdisp_t *prototype, void **ret) { FunctionInstance *function; HRESULT hres; @@ -718,7 +804,7 @@ static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_ if(!function) return E_OUTOFMEMORY; - if(funcprot) + if(prototype) hres = init_dispex(&function->dispex, ctx, builtin_info, prototype); else if(builtin_info) hres = init_dispex_from_constr(&function->dispex, ctx, builtin_info, ctx->function_constr); @@ -767,7 +853,8 @@ static const function_vtbl_t NativeFunctionVtbl = { NativeFunction_toString, NativeFunction_get_code, NativeFunction_destructor, - no_gc_traverse + no_gc_traverse, + no_cc_traverse }; HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc, const WCHAR *name, @@ -779,7 +866,7 @@ HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc, if(!ctx->function_constr) return E_UNEXPECTED; - hres = create_function(ctx, builtin_info, &NativeFunctionVtbl, sizeof(NativeFunction), flags, FALSE, NULL, (void**)&function); + hres = create_function(ctx, builtin_info, &NativeFunctionVtbl, sizeof(NativeFunction), flags, NULL, (void**)&function); if(FAILED(hres)) return hres; @@ -869,7 +956,8 @@ static const builtin_info_t InterpretedFunction_info = { .props_cnt = ARRAY_SIZE(InterpretedFunction_props), .props = InterpretedFunction_props, .destructor = Function_destructor, - .gc_traverse = Function_gc_traverse + .gc_traverse = Function_gc_traverse, + .cc_traverse = Function_cc_traverse }; static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, @@ -942,12 +1030,20 @@ static HRESULT InterpretedFunction_gc_traverse(struct gc_ctx *gc_ctx, enum gc_tr (void**)&function->scope_chain); } +static void InterpretedFunction_cc_traverse(FunctionInstance *func, nsCycleCollectionTraversalCallback *cb) +{ + InterpretedFunction *function = (InterpretedFunction*)func; + if(function->scope_chain) + cc_api.note_edge((IUnknown*)&function->scope_chain->dispex.IWineJSDispatch_iface, "scope_chain", cb); +} + static const function_vtbl_t InterpretedFunctionVtbl = { InterpretedFunction_call, InterpretedFunction_toString, InterpretedFunction_get_code, InterpretedFunction_destructor, - InterpretedFunction_gc_traverse + InterpretedFunction_gc_traverse, + InterpretedFunction_cc_traverse }; HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_code_t *func_code, @@ -957,7 +1053,7 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod HRESULT hres; hres = create_function(ctx, &InterpretedFunction_info, &InterpretedFunctionVtbl, sizeof(InterpretedFunction), - PROPF_CONSTR, FALSE, NULL, (void**)&function); + PROPF_CONSTR, NULL, (void**)&function); if(FAILED(hres)) return hres; @@ -975,11 +1071,19 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod return S_OK; } +static const builtin_prop_t HostFunction_props[] = { + {L"arguments", NULL, 0, Function_get_arguments}, + {L"caller", NULL, 0, Function_get_caller}, +}; + static const builtin_info_t HostFunction_info = { .class = JSCLASS_FUNCTION, .call = Function_value, .destructor = Function_destructor, - .gc_traverse = Function_gc_traverse + .props_cnt = ARRAY_SIZE(HostFunction_props), + .props = HostFunction_props, + .gc_traverse = Function_gc_traverse, + .cc_traverse = Function_cc_traverse }; static HRESULT HostFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, @@ -1023,7 +1127,7 @@ static HRESULT HostFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsva if(SUCCEEDED(hres)) { V_VT(&retv) = VT_EMPTY; - hres = IWineJSDispatchHost_CallFunction(obj, function->id, function->iid, function->flags, &dp, + hres = IWineJSDispatchHost_CallFunction(obj, function->id, function->prototype_id, function->flags, &dp, r ? &retv : NULL, &ei, &ctx->jscaller->IServiceProvider_iface); if(hres == DISP_E_EXCEPTION) handle_dispatch_exception(ctx, &ei); @@ -1056,17 +1160,13 @@ static void HostFunction_destructor(FunctionInstance *func) { } -static HRESULT HostFunction_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, FunctionInstance *func) -{ - return S_OK; -} - static const function_vtbl_t HostFunctionVtbl = { HostFunction_call, HostFunction_toString, HostFunction_get_code, HostFunction_destructor, - HostFunction_gc_traverse + no_gc_traverse, + no_cc_traverse }; HRESULT create_host_function(script_ctx_t *ctx, const struct property_info *desc, DWORD flags, jsdisp_t **ret) @@ -1078,28 +1178,22 @@ HRESULT create_host_function(script_ctx_t *ctx, const struct property_info *desc return E_UNEXPECTED; hres = create_function(ctx, &HostFunction_info, &HostFunctionVtbl, sizeof(HostFunction), PROPF_METHOD, - FALSE, NULL, (void**)&function); + NULL, (void**)&function); if(FAILED(hres)) return hres; function->name = desc->name; function->id = desc->id; - function->iid = desc->iid; + function->prototype_id = desc->prototype_id; function->flags = flags; *ret = &function->function.dispex; return S_OK; } -static ULONG HostConstructor_addref(jsdisp_t *jsdisp) -{ - HostConstructor *constr = (HostConstructor*)jsdisp; - return IWineJSDispatchHost_AddRef(constr->host_iface); -} - -static ULONG HostConstructor_release(jsdisp_t *jsdisp) +static IWineJSDispatchHost *HostConstructor_get_host_disp(jsdisp_t *jsdisp) { HostConstructor *constr = (HostConstructor*)jsdisp; - return IWineJSDispatchHost_Release(constr->host_iface); + return constr->host_iface; } static HRESULT HostConstructor_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, unsigned flags, struct property_info *desc) @@ -1111,13 +1205,15 @@ static HRESULT HostConstructor_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, } static const builtin_info_t HostConstructor_info = { - .class = JSCLASS_FUNCTION, - .addref = HostConstructor_addref, - .release = HostConstructor_release, - .call = Function_value, - .destructor = Function_destructor, - .gc_traverse = Function_gc_traverse, - .lookup_prop = HostConstructor_lookup_prop, + .class = JSCLASS_FUNCTION, + .call = Function_value, + .destructor = Function_destructor, + .props_cnt = ARRAY_SIZE(HostFunction_props), + .props = HostFunction_props, + .get_host_disp = HostConstructor_get_host_disp, + .gc_traverse = Function_gc_traverse, + .cc_traverse = Function_cc_traverse, + .lookup_prop = HostConstructor_lookup_prop, }; static HRESULT HostConstructor_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, @@ -1142,8 +1238,8 @@ static HRESULT HostConstructor_call(script_ctx_t *ctx, FunctionInstance *func, j if(SUCCEEDED(hres)) { V_VT(&ret) = VT_EMPTY; - hres = IWineJSDispatchHost_Construct(function->host_iface, ctx->lcid, flags, &dp, &ret, &ei, - &ctx->jscaller->IServiceProvider_iface); + hres = IWineJSDispatchHost_Construct(function->host_iface, ctx->lcid, flags, &dp, r ? &ret : NULL, + &ei, &ctx->jscaller->IServiceProvider_iface); if(hres == DISP_E_EXCEPTION) handle_dispatch_exception(ctx, &ei); if(SUCCEEDED(hres) && r) { @@ -1174,17 +1270,13 @@ static void HostConstructor_destructor(FunctionInstance *func) { } -static HRESULT HostConstructor_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, FunctionInstance *func) -{ - return S_OK; -} - static const function_vtbl_t HostConstructorVtbl = { HostConstructor_call, HostConstructor_toString, HostConstructor_get_code, HostConstructor_destructor, - HostConstructor_gc_traverse + no_gc_traverse, + no_cc_traverse }; HRESULT init_host_constructor(script_ctx_t *ctx, IWineJSDispatchHost *host_constr, IWineJSDispatch *prototype, @@ -1194,7 +1286,7 @@ HRESULT init_host_constructor(script_ctx_t *ctx, IWineJSDispatchHost *host_const HRESULT hres; hres = create_function(ctx, &HostConstructor_info, &HostConstructorVtbl, sizeof(*function), PROPF_METHOD, - FALSE, NULL, (void**)&function); + NULL, (void**)&function); if(FAILED(hres)) return hres; function->host_iface = host_constr; @@ -1232,7 +1324,8 @@ static const builtin_info_t BindFunction_info = { .props_cnt = ARRAY_SIZE(BindFunction_props), .props = BindFunction_props, .destructor = Function_destructor, - .gc_traverse = Function_gc_traverse + .gc_traverse = Function_gc_traverse, + .cc_traverse = Function_cc_traverse }; static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, @@ -1307,12 +1400,30 @@ static HRESULT BindFunction_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_ return gc_process_linked_val(gc_ctx, op, &function->function.dispex, &function->this); } +static void BindFunction_cc_traverse(FunctionInstance *func, nsCycleCollectionTraversalCallback *cb) +{ + BindFunction *function = (BindFunction*)func; + note_edge_t note_edge = cc_api.note_edge; + unsigned i; + + for(i = 0; i < function->argc; i++) + if(is_object_instance(function->args[i])) + note_edge(get_edge_obj(get_object(function->args[i])), "arg", cb); + + if(function->target) + note_edge(jsdisp_get_edge_obj(&function->target->dispex), "target", cb); + + if(is_object_instance(function->this)) + note_edge(get_edge_obj(get_object(function->this)), "this", cb); +} + static const function_vtbl_t BindFunctionVtbl = { BindFunction_call, BindFunction_toString, BindFunction_get_code, BindFunction_destructor, - BindFunction_gc_traverse + BindFunction_gc_traverse, + BindFunction_cc_traverse }; static HRESULT create_bind_function(script_ctx_t *ctx, FunctionInstance *target, jsval_t bound_this, unsigned argc, @@ -1322,7 +1433,7 @@ static HRESULT create_bind_function(script_ctx_t *ctx, FunctionInstance *target, HRESULT hres; hres = create_function(ctx, &BindFunction_info, &BindFunctionVtbl, FIELD_OFFSET(BindFunction, args[argc]), PROPF_METHOD, - FALSE, NULL, (void**)&function); + NULL, (void**)&function); if(FAILED(hres)) return hres; @@ -1479,7 +1590,7 @@ HRESULT init_function_constr(script_ctx_t *ctx, jsdisp_t *object_prototype) HRESULT hres; hres = create_function(ctx, &Function_info, &NativeFunctionVtbl, sizeof(NativeFunction), PROPF_CONSTR, - TRUE, object_prototype, (void**)&prot); + object_prototype, (void**)&prot); if(FAILED(hres)) return hres; @@ -1487,7 +1598,7 @@ HRESULT init_function_constr(script_ctx_t *ctx, jsdisp_t *object_prototype) prot->name = L"prototype"; hres = create_function(ctx, &FunctionInst_info, &NativeFunctionVtbl, sizeof(NativeFunction), PROPF_CONSTR|1, - TRUE, &prot->function.dispex, (void**)&constr); + &prot->function.dispex, (void**)&constr); if(SUCCEEDED(hres)) { constr->proc = FunctionConstr_value; constr->name = L"Function"; diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index c42109b41434..18c647d597ac 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -912,6 +912,17 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface, WARN("object does not implement IDispatch\n"); return hres; } + + if(!cc_api.note_edge && This->ctx->html_mode) { + IWineJSDispatchHost *host; + + /* Init CC API to get rid of cycles in IE8 and below as well */ + hres = IDispatch_QueryInterface(disp, &IID_IWineJSDispatchHost, (void**)&host); + if(SUCCEEDED(hres) && host) { + init_cc_api(host); + IWineJSDispatchHost_Release(host); + } + } } item = malloc(sizeof(*item)); @@ -1465,12 +1476,39 @@ static HRESULT WINAPI WineJScript_InitHostConstructor(IWineJScript *iface, IWine return init_host_constructor(This->ctx, constr, prototype, ret); } +static HRESULT WINAPI WineJScript_CreateObject(IWineJScript *iface, IWineJSDispatch **ret) +{ + JScript *This = impl_from_IWineJScript(iface); + jsdisp_t *jsdisp; + HRESULT hres; + + hres = create_object(This->ctx, NULL, &jsdisp); + if(SUCCEEDED(hres)) + *ret = &jsdisp->IWineJSDispatch_iface; + return hres; +} + +static HRESULT WINAPI WineJScript_CreateArrayBuffer(IWineJScript *iface, DWORD size, IWineJSDispatch **arraybuf, void **data) +{ + JScript *This = impl_from_IWineJScript(iface); + return create_arraybuffer(This->ctx, size, arraybuf, data); +} + +static HRESULT WINAPI WineJScript_FillGlobals(IWineJScript *iface, IWineJSDispatchHost *script_global) +{ + JScript *This = impl_from_IWineJScript(iface); + return fill_globals(This->ctx, script_global); +} + static const IWineJScriptVtbl WineJScriptVtbl = { WineJScript_QueryInterface, WineJScript_AddRef, WineJScript_Release, WineJScript_InitHostObject, WineJScript_InitHostConstructor, + WineJScript_CreateObject, + WineJScript_CreateArrayBuffer, + WineJScript_FillGlobals, }; HRESULT create_jscript_object(BOOL is_encode, REFIID riid, void **ppv) diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index e9207c231d8f..1d651dccd206 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -28,12 +28,12 @@ #include "ole2.h" #include "dispex.h" #include "activscp.h" -#include "jsdisp.h" #include "resource.h" #include "wine/list.h" #include "wine/rbtree.h" +#include "jsdisp.h" /* * This is Wine jscript extension for ES5 compatible mode. Native IE9+ implements @@ -73,6 +73,7 @@ heap_pool_t *heap_pool_mark(heap_pool_t*); typedef struct jsdisp_t jsdisp_t; +extern struct jshost_cc_api cc_api; extern HINSTANCE jscript_hinstance ; HRESULT get_dispatch_typeinfo(ITypeInfo**); @@ -113,12 +114,28 @@ typedef enum { JSCLASS_JSON, JSCLASS_ARRAYBUFFER, JSCLASS_DATAVIEW, + JSCLASS_INT8ARRAY, + JSCLASS_INT16ARRAY, + JSCLASS_INT32ARRAY, + JSCLASS_UINT8ARRAY, + JSCLASS_UINT8CLAMPEDARRAY, + JSCLASS_UINT16ARRAY, + JSCLASS_UINT32ARRAY, + JSCLASS_FLOAT32ARRAY, + JSCLASS_FLOAT64ARRAY, JSCLASS_MAP, JSCLASS_SET, JSCLASS_WEAKMAP, JSCLASS_HOST, + + FIRST_TYPEDARRAY_JSCLASS = JSCLASS_INT8ARRAY, + LAST_TYPEDARRAY_JSCLASS = JSCLASS_FLOAT64ARRAY, + FIRST_VIEW_JSCLASS = JSCLASS_DATAVIEW, + LAST_VIEW_JSCLASS = JSCLASS_FLOAT64ARRAY, } jsclass_t; +enum { NUM_TYPEDARRAY_TYPES = LAST_TYPEDARRAY_JSCLASS - FIRST_TYPEDARRAY_JSCLASS + 1 }; + jsdisp_t *iface_to_jsdisp(IDispatch*); typedef HRESULT (*builtin_invoke_t)(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); @@ -180,17 +197,20 @@ typedef struct { DWORD props_cnt; const builtin_prop_t *props; void (*destructor)(jsdisp_t*); - ULONG (*addref)(jsdisp_t*); - ULONG (*release)(jsdisp_t*); + IWineJSDispatchHost *(*get_host_disp)(jsdisp_t*); void (*on_put)(jsdisp_t*,const WCHAR*); + unsigned (*indexed_len)(jsdisp_t*); HRESULT (*lookup_prop)(jsdisp_t*,const WCHAR*,unsigned,struct property_info*); - HRESULT (*next_prop)(jsdisp_t*,unsigned,struct property_info*); - HRESULT (*prop_get)(jsdisp_t*,unsigned,jsval_t*); - HRESULT (*prop_put)(jsdisp_t*,unsigned,jsval_t); - HRESULT (*prop_delete)(jsdisp_t*,unsigned); + HRESULT (*prop_get)(jsdisp_t*,DISPID,jsval_t*); + HRESULT (*prop_put)(jsdisp_t*,DISPID,jsval_t); + HRESULT (*prop_delete)(jsdisp_t*,DISPID); + HRESULT (*prop_get_desc)(jsdisp_t*,DISPID,BOOL,property_desc_t*); + HRESULT (*prop_define)(jsdisp_t*,DISPID,const property_desc_t*); HRESULT (*prop_config)(jsdisp_t*,unsigned,unsigned); + HRESULT (*fill_props)(jsdisp_t*); HRESULT (*to_string)(jsdisp_t*,jsstr_t**); HRESULT (*gc_traverse)(struct gc_ctx*,enum gc_traverse_op,jsdisp_t*); + void (*cc_traverse)(jsdisp_t*,nsCycleCollectionTraversalCallback*); } builtin_info_t; struct jsdisp_t { @@ -198,10 +218,12 @@ struct jsdisp_t { LONG ref; - BOOLEAN has_weak_refs; - BOOLEAN extensible; - BOOLEAN gc_marked; - BOOLEAN is_constructor; + BOOLEAN has_volatile_props : 1; + BOOLEAN is_constructor : 1; + BOOLEAN has_weak_refs : 1; + BOOLEAN props_filled : 1; + BOOLEAN extensible : 1; + BOOLEAN gc_marked : 1; DWORD buf_size; DWORD prop_cnt; @@ -224,6 +246,26 @@ static inline IDispatchEx *to_dispex(jsdisp_t *jsdisp) return (IDispatchEx *)&jsdisp->IWineJSDispatch_iface; } +static inline BOOL is_dispex_prop_id(DISPID id) +{ + return id > 0; +} + +static inline BOOL is_indexed_prop_id(DISPID id) +{ + return id < 0; +} + +static inline unsigned indexed_prop_id_to_idx(DISPID id) +{ + return (unsigned)id - 0x80000000u; +} + +static inline DISPID indexed_prop_idx_to_id(unsigned idx) +{ + return idx + 0x80000000u; +} + jsdisp_t *as_jsdisp(IDispatch*); jsdisp_t *to_jsdisp(IDispatch*); IWineJSDispatchHost *get_host_dispatch(IDispatch*); @@ -242,6 +284,8 @@ HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); HRESULT init_host_object(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,UINT32,IWineJSDispatch**); HRESULT init_host_constructor(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,IWineJSDispatch**); +HRESULT fill_globals(script_ctx_t*,IWineJSDispatchHost*); +void init_cc_api(IWineJSDispatchHost*); HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*); HRESULT disp_call_name(script_ctx_t*,IDispatch*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*); @@ -262,8 +306,6 @@ HRESULT jsdisp_get_id(jsdisp_t*,const WCHAR*,DWORD,DISPID*); HRESULT jsdisp_get_idx_id(jsdisp_t*,DWORD,DISPID*); HRESULT disp_delete(IDispatch*,DISPID,BOOL*); HRESULT disp_delete_name(script_ctx_t*,IDispatch*,jsstr_t*,BOOL*); -HRESULT jsdisp_index_lookup(jsdisp_t*,const WCHAR*,unsigned,struct property_info*); -HRESULT jsdisp_next_index(jsdisp_t*,unsigned,unsigned,struct property_info*); HRESULT jsdisp_delete_idx(jsdisp_t*,DWORD); HRESULT jsdisp_get_own_property(jsdisp_t*,const WCHAR*,BOOL,property_desc_t*); HRESULT jsdisp_define_property(jsdisp_t*,const WCHAR*,property_desc_t*); @@ -292,6 +334,7 @@ void handle_dispatch_exception(script_ctx_t *ctx, EXCEPINFO *ei); HRESULT create_object(script_ctx_t*,jsdisp_t*,jsdisp_t**); HRESULT create_math(script_ctx_t*,jsdisp_t**); HRESULT create_array(script_ctx_t*,DWORD,jsdisp_t**); +HRESULT create_arraybuffer(script_ctx_t*,DWORD,IWineJSDispatch**,void**); HRESULT create_regexp(script_ctx_t*,jsstr_t*,DWORD,jsdisp_t**); HRESULT create_regexp_var(script_ctx_t*,jsval_t,jsval_t*,jsdisp_t**); HRESULT create_string(script_ctx_t*,jsstr_t*,jsdisp_t**); @@ -429,11 +472,12 @@ struct _script_ctx_t { jsdisp_t *vbarray_constr; jsdisp_t *arraybuf_constr; jsdisp_t *dataview_constr; + jsdisp_t *typedarr_constr[LAST_TYPEDARRAY_JSCLASS - FIRST_TYPEDARRAY_JSCLASS + 1]; jsdisp_t *map_prototype; jsdisp_t *set_prototype; jsdisp_t *weakmap_prototype; }; - jsdisp_t *global_objects[25]; + jsdisp_t *global_objects[25 + LAST_TYPEDARRAY_JSCLASS - FIRST_TYPEDARRAY_JSCLASS + 1]; }; }; C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, weakmap_prototype) == RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, global_objects)); @@ -487,6 +531,7 @@ HRESULT regexp_string_match(script_ctx_t*,jsdisp_t*,jsstr_t*,jsval_t*); BOOL bool_obj_value(jsdisp_t*); unsigned array_get_length(jsdisp_t*); +HRESULT typed_array_get_random_values(IDispatch*); HRESULT localize_number(script_ctx_t*,DOUBLE,BOOL,jsstr_t**); BOOL is_builtin_eval_func(jsdisp_t*); @@ -516,6 +561,21 @@ static inline HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_ return disp_call_value_with_caller(ctx, disp, vthis, flags, argc, argv, r, &ctx->jscaller->IServiceProvider_iface); } +static inline IUnknown *jsdisp_get_edge_obj(jsdisp_t *jsdisp) +{ + if(jsdisp->builtin_info->get_host_disp) + return (IUnknown*)jsdisp->builtin_info->get_host_disp(jsdisp); + return (IUnknown*)&jsdisp->IWineJSDispatch_iface; +} + +static inline IUnknown *get_edge_obj(IDispatch *disp) +{ + jsdisp_t *jsdisp = to_jsdisp(disp); + if(jsdisp) + return jsdisp_get_edge_obj(jsdisp); + return (IUnknown*)disp; +} + #define MAKE_JSERROR(code) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_CONTROL, code) #define JS_E_TO_PRIMITIVE MAKE_JSERROR(IDS_TO_PRIMITIVE) @@ -570,6 +630,11 @@ static inline HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_ #define JS_E_OBJECT_NONEXTENSIBLE MAKE_JSERROR(IDS_OBJECT_NONEXTENSIBLE) #define JS_E_NONCONFIGURABLE_REDEFINED MAKE_JSERROR(IDS_NONCONFIGURABLE_REDEFINED) #define JS_E_NONWRITABLE_MODIFIED MAKE_JSERROR(IDS_NONWRITABLE_MODIFIED) +#define JS_E_TYPEDARRAY_BAD_CTOR_ARG MAKE_JSERROR(IDS_TYPEDARRAY_BAD_CTOR_ARG) +#define JS_E_NOT_TYPEDARRAY MAKE_JSERROR(IDS_NOT_TYPEDARRAY) +#define JS_E_TYPEDARRAY_INVALID_OFFSLEN MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_OFFSLEN) +#define JS_E_TYPEDARRAY_INVALID_SUBARRAY MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_SUBARRAY) +#define JS_E_TYPEDARRAY_INVALID_SOURCE MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_SOURCE) #define JS_E_NOT_DATAVIEW MAKE_JSERROR(IDS_NOT_DATAVIEW) #define JS_E_DATAVIEW_NO_ARGUMENT MAKE_JSERROR(IDS_DATAVIEW_NO_ARGUMENT) #define JS_E_DATAVIEW_INVALID_ACCESS MAKE_JSERROR(IDS_DATAVIEW_INVALID_ACCESS) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index 438aaad4c358..7d11a7e09329 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -77,6 +77,11 @@ STRINGTABLE IDS_OBJECT_NONEXTENSIBLE "Cannot define property '|': object is not extensible" IDS_NONCONFIGURABLE_REDEFINED "Cannot redefine non-configurable property '|'" IDS_NONWRITABLE_MODIFIED "Cannot modify non-writable property '|'" + IDS_NOT_TYPEDARRAY "'this' is not a typed array object" + IDS_TYPEDARRAY_BAD_CTOR_ARG "Typed array constructor argument is invalid" + IDS_TYPEDARRAY_INVALID_OFFSLEN "Invalid offset/length when creating typed array" + IDS_TYPEDARRAY_INVALID_SUBARRAY "Invalid begin/end value in typed array subarray method" + IDS_TYPEDARRAY_INVALID_SOURCE "Invalid source in typed array set" IDS_NOT_DATAVIEW "'this' is not a DataView object" IDS_DATAVIEW_NO_ARGUMENT "Required argument offset or value in DataView method is not specified" IDS_DATAVIEW_INVALID_ACCESS "DataView operation access beyond specified buffer length" diff --git a/dlls/jscript/jscript_main.c b/dlls/jscript/jscript_main.c index 6ccab3620510..ccaa12761c25 100644 --- a/dlls/jscript/jscript_main.c +++ b/dlls/jscript/jscript_main.c @@ -27,7 +27,6 @@ #include "mshtmhst.h" #include "rpcproxy.h" #include "jscript_classes.h" -#include "jsdisp.h" #include "wine/debug.h" @@ -208,6 +207,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) if (lpv) break; if (dispatch_typeinfo) ITypeInfo_Release(dispatch_typeinfo); if(jscript_tls != TLS_OUT_OF_INDEXES) TlsFree(jscript_tls); + list_remove(&cc_api.entry); free_strings(); break; } diff --git a/dlls/jscript/jsdisp.idl b/dlls/jscript/jsdisp.idl index 5f1384bce782..1024582a839b 100644 --- a/dlls/jscript/jsdisp.idl +++ b/dlls/jscript/jsdisp.idl @@ -27,7 +27,7 @@ struct property_info UINT32 flags; const WCHAR *name; UINT32 index; - UINT32 iid; + INT32 prototype_id; }; const unsigned int PROPF_METHOD = 0x0100; @@ -39,7 +39,37 @@ const unsigned int PROPF_CONFIGURABLE = 0x1000; const unsigned int PROPF_PUBLIC_MASK = PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE; -const unsigned int HOSTOBJ_CONSTRUCTOR = 0x0001; +const unsigned int HOSTOBJ_CONSTRUCTOR = 0x0001; +const unsigned int HOSTOBJ_VOLATILE_PROPS = 0x0002; + +cpp_quote("DEFINE_GUID(IID_nsCycleCollectionISupports, 0xc61eac14,0x5f7a,0x4481,0x96,0x5e,0x7e,0xaa,0x6e,0xff,0xa8,0x5f);") +cpp_quote("DEFINE_GUID(IID_nsXPCOMCycleCollectionParticipant, 0x9674489b,0x1f6f,0x4550,0xa7,0x30, 0xcc,0xae,0xdd,0x10,0x4c,0xf9);") + +typedef struct { + void *vtbl; + int ref_flags; + void *callbacks; +} ExternalCycleCollectionParticipant; + +typedef struct nsCycleCollectionTraversalCallback nsCycleCollectionTraversalCallback; + +typedef struct { + HRESULT (__stdcall *traverse)(void*,void*,nsCycleCollectionTraversalCallback*); + HRESULT (__stdcall *unlink)(void*); + void (__stdcall *delete_cycle_collectable)(void*); +} CCObjCallback; + +typedef void (__cdecl *note_edge_t)(IUnknown*,const char*,nsCycleCollectionTraversalCallback*); + +struct jshost_cc_api +{ + ExternalCycleCollectionParticipant participant; + BOOL (__cdecl *is_full_cc)(void); + void (__cdecl *collect)(void); + void (__cdecl *describe_node)(ULONG ref, const char *obj_name, nsCycleCollectionTraversalCallback *cb); + note_edge_t note_edge; + struct list entry; +}; interface IWineJSDispatchHost; @@ -51,8 +81,12 @@ interface IWineJSDispatchHost; interface IWineJSDispatch : IDispatchEx { void Free(); + void Traverse(nsCycleCollectionTraversalCallback *cb); + void Unlink(); HRESULT GetPropertyFlags(DISPID id, UINT32 *ret); + HRESULT UpdateProperty(struct property_info *desc); HRESULT GetScriptGlobal(IWineJSDispatchHost **ret); + HRESULT GetRandomValues(IDispatch *typedarr); } [ @@ -64,15 +98,17 @@ interface IWineJSDispatchHost : IDispatchEx { HRESULT GetJSDispatch(IWineJSDispatch **ret); HRESULT LookupProperty(const WCHAR *name, DWORD flags, struct property_info *desc); - HRESULT NextProperty(DISPID id, struct property_info *desc); + HRESULT OverrideProperty(const WCHAR *name, struct property_info *get_desc, VARIANT *get_value); HRESULT GetProperty(DISPID id, LCID lcid, VARIANT *r, EXCEPINFO *ei, IServiceProvider *caller); HRESULT SetProperty(DISPID id, LCID lcid, VARIANT *v, EXCEPINFO *ei, IServiceProvider *caller); HRESULT DeleteProperty(DISPID id); HRESULT ConfigureProperty(DISPID id, UINT32 flags); - HRESULT CallFunction(DISPID id, UINT32 iid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); + HRESULT CallFunction(DISPID id, INT32 prototype_id, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); HRESULT Construct(LCID lcid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); + HRESULT FillProperties(); HRESULT GetOuterDispatch(IWineJSDispatchHost **ret); HRESULT ToString(BSTR *str); + void InitCC(struct jshost_cc_api *cc_api, const CCObjCallback *callback); } [ @@ -84,4 +120,7 @@ interface IWineJScript : IUnknown { HRESULT InitHostObject(IWineJSDispatchHost *host_obj, IWineJSDispatch *prototype, UINT32 flags, IWineJSDispatch **ret); HRESULT InitHostConstructor(IWineJSDispatchHost *constr, IWineJSDispatch *prototype, IWineJSDispatch **ret); + HRESULT CreateObject(IWineJSDispatch **ret); + HRESULT CreateArrayBuffer(DWORD size, IWineJSDispatch **ret, void **data); + HRESULT FillGlobals(IWineJSDispatchHost *script_global); } diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c index 9018687aba26..093bd5bf386e 100644 --- a/dlls/jscript/json.c +++ b/dlls/jscript/json.c @@ -707,7 +707,7 @@ static HRESULT stringify_array(stringify_ctx_t *ctx, jsdisp_t *obj) } } - _itow(i, name, ARRAY_SIZE(name)); + _itow_s(i, name, ARRAY_SIZE(name), 10); hres = stringify(ctx, obj, name); if(FAILED(hres)) return hres; diff --git a/dlls/jscript/jsregexp.c b/dlls/jscript/jsregexp.c index 979f994ee550..1daaa0eac037 100644 --- a/dlls/jscript/jsregexp.c +++ b/dlls/jscript/jsregexp.c @@ -560,6 +560,13 @@ static HRESULT RegExp_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, return gc_process_linked_val(gc_ctx, op, dispex, ®exp_from_jsdisp(dispex)->last_index_val); } +static void RegExp_cc_traverse(jsdisp_t *dispex, nsCycleCollectionTraversalCallback *cb) +{ + RegExpInstance *This = regexp_from_jsdisp(dispex); + if(is_object_instance(This->last_index_val)) + cc_api.note_edge(get_edge_obj(get_object(This->last_index_val)), "last_index_val", cb); +} + static const builtin_prop_t RegExp_props[] = { {L"exec", RegExp_exec, PROPF_METHOD|1}, {L"global", NULL,0, RegExp_get_global}, @@ -577,7 +584,8 @@ static const builtin_info_t RegExp_info = { .props_cnt = ARRAY_SIZE(RegExp_props), .props = RegExp_props, .destructor = RegExp_destructor, - .gc_traverse = RegExp_gc_traverse + .gc_traverse = RegExp_gc_traverse, + .cc_traverse = RegExp_cc_traverse }; static const builtin_prop_t RegExpInst_props[] = { @@ -594,7 +602,8 @@ static const builtin_info_t RegExpInst_info = { .props_cnt = ARRAY_SIZE(RegExpInst_props), .props = RegExpInst_props, .destructor = RegExp_destructor, - .gc_traverse = RegExp_gc_traverse + .gc_traverse = RegExp_gc_traverse, + .cc_traverse = RegExp_cc_traverse }; static HRESULT alloc_regexp(script_ctx_t *ctx, jsstr_t *str, jsdisp_t *object_prototype, RegExpInstance **ret) diff --git a/dlls/jscript/jsutils.c b/dlls/jscript/jsutils.c index cb139977a840..1d6fa06a993f 100644 --- a/dlls/jscript/jsutils.c +++ b/dlls/jscript/jsutils.c @@ -293,13 +293,8 @@ HRESULT variant_to_jsval(script_ctx_t *ctx, VARIANT *var, jsval_t *r) hres = IWineJSDispatchHost_GetJSDispatch(disp_host, &jsdisp_iface); IWineJSDispatchHost_Release(disp_host); if(SUCCEEDED(hres)) { - jsdisp_t *jsdisp = to_jsdisp((IDispatch *)jsdisp_iface); - if(jsdisp->ctx == ctx) { - *r = jsval_obj(jsdisp); - return S_OK; - }else { - jsdisp_release(jsdisp); - } + *r = jsval_obj(as_jsdisp((IDispatch *)jsdisp_iface)); + return S_OK; } } } diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index feeff5c294af..99e04215ff4c 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -53,6 +53,15 @@ static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns L"[object Object]", L"[object ArrayBuffer]", L"[object Object]", + L"[object Int8Array]", + L"[object Int16Array]", + L"[object Int32Array]", + L"[object Uint8Array]", + L"[object Uint8ClampedArray]", + L"[object Uint16Array]", + L"[object Uint32Array]", + L"[object Float32Array]", + L"[object Float64Array]", L"[object Object]", L"[object Object]", L"[object Object]", diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index 640cc01cff9f..d694abc07cd9 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -75,6 +75,11 @@ #define IDS_OBJECT_NONEXTENSIBLE 0x13D5 #define IDS_NONCONFIGURABLE_REDEFINED 0x13D6 #define IDS_NONWRITABLE_MODIFIED 0x13D7 +#define IDS_TYPEDARRAY_BAD_CTOR_ARG 0x13DA +#define IDS_NOT_TYPEDARRAY 0x13DB +#define IDS_TYPEDARRAY_INVALID_OFFSLEN 0x13DC +#define IDS_TYPEDARRAY_INVALID_SUBARRAY 0x13DD +#define IDS_TYPEDARRAY_INVALID_SOURCE 0x13DE #define IDS_NOT_DATAVIEW 0x13DF #define IDS_DATAVIEW_NO_ARGUMENT 0x13E0 #define IDS_DATAVIEW_INVALID_ACCESS 0x13E1 diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index c114e3fd6e22..16535cc46eb5 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -385,6 +385,20 @@ static HRESULT Map_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, js return S_OK; } +static void Map_cc_traverse(jsdisp_t *dispex, nsCycleCollectionTraversalCallback *cb) +{ + note_edge_t note_edge = cc_api.note_edge; + MapInstance *map = (MapInstance*)dispex; + struct jsval_map_entry *entry; + + LIST_FOR_EACH_ENTRY(entry, &map->entries, struct jsval_map_entry, list_entry) { + if(is_object_instance(entry->key)) + note_edge(get_edge_obj(get_object(entry->key)), "key", cb); + if(is_object_instance(entry->value)) + note_edge(get_edge_obj(get_object(entry->value)), "value", cb); + } +} + static const builtin_prop_t Map_prototype_props[] = { {L"clear", Map_clear, PROPF_METHOD}, {L"delete" , Map_delete, PROPF_METHOD|1}, @@ -412,6 +426,7 @@ static const builtin_info_t Map_info = { .props = Map_props, .destructor = Map_destructor, .gc_traverse = Map_gc_traverse, + .cc_traverse = Map_cc_traverse }; static HRESULT Map_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, @@ -565,6 +580,7 @@ static const builtin_info_t Set_info = { .props = Map_props, .destructor = Map_destructor, .gc_traverse = Map_gc_traverse, + .cc_traverse = Map_cc_traverse }; static HRESULT Set_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, @@ -832,6 +848,19 @@ static HRESULT WeakMap_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op return S_OK; } +static void WeakMap_cc_traverse(jsdisp_t *dispex, nsCycleCollectionTraversalCallback *cb) +{ + WeakMapInstance *weakmap = (WeakMapInstance*)dispex; + note_edge_t note_edge = cc_api.note_edge; + struct weakmap_entry *entry; + + /* FIXME: WeakMaps need special handling (see above), but we can't do that with this API. + This will possibly leak objects that need the CC until the WeakMap has no more refs to it. */ + RB_FOR_EACH_ENTRY(entry, &weakmap->map, struct weakmap_entry, entry) + if(is_object_instance(entry->value)) + note_edge(get_edge_obj(get_object(entry->value)), "value", cb); +} + static const builtin_prop_t WeakMap_prototype_props[] = { {L"clear", WeakMap_clear, PROPF_METHOD}, {L"delete", WeakMap_delete, PROPF_METHOD|1}, @@ -852,6 +881,7 @@ static const builtin_info_t WeakMap_info = { .call = WeakMap_value, .destructor = WeakMap_destructor, .gc_traverse = WeakMap_gc_traverse, + .cc_traverse = WeakMap_cc_traverse }; static HRESULT WeakMap_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 968b74f9602a..f02af5b65175 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -1501,7 +1501,7 @@ static void String_destructor(jsdisp_t *dispex) jsstr_release(This->str); } -static HRESULT String_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, unsigned flags, struct property_info *desc) +static unsigned String_indexed_len(jsdisp_t *jsdisp) { StringInstance *string = string_from_jsdisp(jsdisp); @@ -1512,36 +1512,48 @@ static HRESULT String_lookup_prop(jsdisp_t *jsdisp, const WCHAR *name, unsigned * properly. */ if(string->dispex.ctx->version < 2) - return DISP_E_UNKNOWNNAME; + return 0; - return jsdisp_index_lookup(&string->dispex, name, jsstr_length(string->str), desc); + return jsstr_length(string->str); } -static HRESULT String_next_prop(jsdisp_t *jsdisp, unsigned id, struct property_info *desc) +static HRESULT String_prop_get(jsdisp_t *jsdisp, DISPID id, jsval_t *r) { StringInstance *string = string_from_jsdisp(jsdisp); + jsstr_t *ret; - if(string->dispex.ctx->version < 2) + if(!is_indexed_prop_id(id)) return S_FALSE; - return jsdisp_next_index(&string->dispex, jsstr_length(string->str), id, desc); -} - -static HRESULT String_prop_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) -{ - StringInstance *string = string_from_jsdisp(jsdisp); - jsstr_t *ret; - - ret = jsstr_substr(string->str, idx, 1); + ret = jsstr_substr(string->str, indexed_prop_id_to_idx(id), 1); if(!ret) return E_OUTOFMEMORY; - TRACE("%p[%u] = %s\n", string, idx, debugstr_jsstr(ret)); + TRACE("%p[%u] = %s\n", string, indexed_prop_id_to_idx(id), debugstr_jsstr(ret)); *r = jsval_string(ret); return S_OK; } +static HRESULT String_prop_put(jsdisp_t *jsdisp, DISPID id, jsval_t val) +{ + return is_indexed_prop_id(id) ? S_OK : S_FALSE; +} + +static HRESULT String_prop_get_desc(jsdisp_t *jsdisp, DISPID id, BOOL flags_only, property_desc_t *desc) +{ + if(!flags_only) { + HRESULT hres = String_prop_get(jsdisp, id, &desc->value); + if(hres != S_OK) + return hres; + }else if(!is_indexed_prop_id(id)) { + return S_FALSE; + } + + desc->flags = PROPF_ENUMERABLE; + return S_OK; +} + static const builtin_prop_t String_props[] = { {L"anchor", String_anchor, PROPF_METHOD|1}, {L"big", String_big, PROPF_METHOD}, @@ -1591,13 +1603,14 @@ static const builtin_prop_t StringInst_props[] = { }; static const builtin_info_t StringInst_info = { - .class = JSCLASS_STRING, - .props_cnt = ARRAY_SIZE(StringInst_props), - .props = StringInst_props, - .destructor = String_destructor, - .lookup_prop = String_lookup_prop, - .next_prop = String_next_prop, - .prop_get = String_prop_get, + .class = JSCLASS_STRING, + .props_cnt = ARRAY_SIZE(StringInst_props), + .props = StringInst_props, + .destructor = String_destructor, + .indexed_len = String_indexed_len, + .prop_get = String_prop_get, + .prop_put = String_prop_put, + .prop_get_desc = String_prop_get_desc, }; /* ECMA-262 3rd Edition 15.5.3.2 */ diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index 255418a6744a..aea7cac63dc3 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -1965,7 +1965,8 @@ ok(isNaN(tmp), "Math.tan(-Infinity) is not NaN"); "{\n \"prop1\": true,\n \"prop2\": {\n \"prop\": \"string\"\n }\n}"], [[{ },undefined," "], "{}"], [[[,2,undefined,3,{ },]],"[null,2,null,3,{},null]"], - [[[,2,undefined,3,{prop:0},],undefined," "],"[\n null,\n 2,\n null,\n 3,\n {\n \"prop\": 0\n },\n null\n]"] + [[[,2,undefined,3,{prop:0},],undefined," "],"[\n null,\n 2,\n null,\n 3,\n {\n \"prop\": 0\n },\n null\n]"], + [[[0,0,0,0,0,0,0,0,0,0,0,0]], "[0,0,0,0,0,0,0,0,0,0,0,0]"] ]; var i, s, v, t; diff --git a/dlls/jscript/tests/run.c b/dlls/jscript/tests/run.c index 106fd8c99d45..5d555b05eb0f 100644 --- a/dlls/jscript/tests/run.c +++ b/dlls/jscript/tests/run.c @@ -3720,6 +3720,49 @@ static void test_members(void) IActiveScript_Release(script); } +static void test_enum(void) +{ + DISPID id = DISPID_STARTENUM; + IActiveScriptParse *parser; + IActiveScript *engine; + IDispatchEx *dispex; + IDispatch *disp; + HRESULT hres; + + engine = create_script(); + + hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser); + ok(hres == S_OK, "Could not get IActiveScriptParse: %08lx\n", hres); + + hres = IActiveScriptParse_InitNew(parser); + ok(hres == S_OK, "InitNew failed: %08lx\n", hres); + IActiveScriptParse_Release(parser); + + hres = IActiveScript_SetScriptSite(engine, &ActiveScriptSite); + ok(hres == S_OK, "SetScriptSite failed: %08lx\n", hres); + + hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED); + ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08lx\n", hres); + + hres = IActiveScript_GetScriptDispatch(engine, NULL, &disp); + ok(hres == S_OK, "GetScriptDispatch failed: %08lx\n", hres); + ok(disp != NULL, "script disp == NULL\n"); + + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres); + IDispatch_Release(disp); + + hres = IDispatchEx_GetNextDispID(dispex, 0, id, &id); + ok(hres == S_FALSE, "GetNextDispID returned: %08lx\n", hres); + + id = DISPID_STARTENUM; + hres = IDispatchEx_GetNextDispID(dispex, fdexEnumAll, id, &id); + ok(hres == S_FALSE, "GetNextDispID returned: %08lx\n", hres); + + IDispatchEx_Release(dispex); + close_script(engine); +} + static void test_destructors(void) { static const WCHAR cyclic_refs[] = L"(function() {\n" @@ -4379,6 +4422,7 @@ static BOOL run_tests(void) test_script_exprs(); test_invokeex(); test_members(); + test_enum(); test_destructors(); test_eval(); test_error_reports(); diff --git a/dlls/kerberos/unixlib.c b/dlls/kerberos/unixlib.c index a7cb8b1da7af..2c538738e913 100644 --- a/dlls/kerberos/unixlib.c +++ b/dlls/kerberos/unixlib.c @@ -1353,6 +1353,8 @@ static NTSTATUS wow64_unseal_message( void *args ) struct { UINT64 context; + PTR32 stream; + ULONG stream_length; PTR32 data; ULONG data_length; PTR32 token; @@ -1362,6 +1364,8 @@ static NTSTATUS wow64_unseal_message( void *args ) struct unseal_message_params params = { params32->context, + ULongToPtr(params32->stream), + params32->stream_length, ULongToPtr(params32->data), params32->data_length, ULongToPtr(params32->token), diff --git a/dlls/kernel32/debugger.c b/dlls/kernel32/debugger.c index 6ccce02a8f3f..a1317464e67a 100644 --- a/dlls/kernel32/debugger.c +++ b/dlls/kernel32/debugger.c @@ -52,6 +52,7 @@ void WINAPI DECLSPEC_HOTPATCH OutputDebugStringA( LPCSTR str ) static HANDLE DBWinMutex = NULL; static BOOL mutex_inited = FALSE; BOOL caught_by_dbg = TRUE; + DWORD last_error = GetLastError(); if (!str) str = ""; WARN( "%s\n", debugstr_a(str) ); @@ -131,6 +132,7 @@ void WINAPI DECLSPEC_HOTPATCH OutputDebugStringA( LPCSTR str ) CloseHandle( mapping ); } } + SetLastError( last_error ); } diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c index 1ec2f5cce0da..2738f233fcbc 100644 --- a/dlls/kernel32/heap.c +++ b/dlls/kernel32/heap.c @@ -41,6 +41,21 @@ WINE_DEFAULT_DEBUG_CHANNEL(globalmem); +#ifndef _WIN64 +static BOOL __wine_needs_override_large_address_aware(void) +{ + static int needs_override = -1; + + if (needs_override == -1) + { + char str[16]; + + needs_override = __wine_get_unix_env( "WINE_LARGE_ADDRESS_AWARE", str, sizeof(str) ) /* on by default */ + || atoi(str) == 1; + } + return needs_override; +} +#endif /*********************************************************************** * HeapCreate (KERNEL32.@) @@ -424,6 +439,7 @@ VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ) OSVERSIONINFOW osver; #ifndef _WIN64 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( GetModuleHandleW(0) ); + static int force_large_address_aware = -1; #endif /* Because GlobalMemoryStatus is identical to GlobalMemoryStatusEX save @@ -450,6 +466,8 @@ VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ) lpBuffer->dwAvailVirtual = memstatus.ullAvailVirtual; #ifndef _WIN64 + if (force_large_address_aware == -1) + force_large_address_aware = __wine_needs_override_large_address_aware(); if ( osver.dwMajorVersion >= 5 || osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) { lpBuffer->dwTotalPhys = min( memstatus.ullTotalPhys, MAXDWORD ); @@ -463,7 +481,8 @@ VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ) /* values are limited to 2Gb unless the app has the IMAGE_FILE_LARGE_ADDRESS_AWARE flag */ /* page file sizes are not limited (Adobe Illustrator 8 depends on this) */ - if (!(nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)) + if (!(nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) && + !force_large_address_aware) { if (lpBuffer->dwTotalPhys > MAXLONG) lpBuffer->dwTotalPhys = MAXLONG; if (lpBuffer->dwAvailPhys > MAXLONG) lpBuffer->dwAvailPhys = MAXLONG; diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 6fb4ae8c2bed..9174055c92dc 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -376,6 +376,7 @@ # @ stub DisableThreadProfiling @ stdcall DisassociateCurrentThreadFromCallback(ptr) NTDLL.TpDisassociateCallback @ stdcall DiscardVirtualMemory(ptr long) kernelbase.DiscardVirtualMemory +@ stdcall -import DeleteSynchronizationBarrier(ptr) @ stdcall DeleteTimerQueue(long) @ stdcall -import DeleteTimerQueueEx(long long) @ stdcall -import DeleteTimerQueueTimer(long long long) @@ -424,6 +425,7 @@ @ stdcall -import EnumResourceTypesExA(long ptr long long long) @ stdcall -import EnumResourceTypesExW(long ptr long long long) @ stdcall EnumResourceTypesW(long ptr long) +@ stdcall -import EnterSynchronizationBarrier(ptr long) @ stdcall EnumSystemCodePagesA(ptr long) @ stdcall -import EnumSystemCodePagesW(ptr long) @ stdcall -import EnumSystemFirmwareTables(long ptr long) @@ -622,7 +624,7 @@ @ stdcall -import GetConsoleProcessList(ptr long) @ stdcall -import GetConsoleScreenBufferInfo(long ptr) @ stdcall -import GetConsoleScreenBufferInfoEx(long ptr) -# @ stub GetConsoleSelectionInfo +@ stdcall -import GetConsoleSelectionInfo(ptr) @ stdcall -import GetConsoleTitleA(ptr long) @ stdcall -import GetConsoleTitleW(ptr long) @ stdcall -import GetConsoleWindow() @@ -659,6 +661,8 @@ @ stdcall -import GetDiskFreeSpaceExA (str ptr ptr ptr) @ stdcall -import GetDiskFreeSpaceExW (wstr ptr ptr ptr) @ stdcall -import GetDiskFreeSpaceW(wstr ptr ptr ptr ptr) +@ stdcall -import GetDiskSpaceInformationA(str ptr) +@ stdcall -import GetDiskSpaceInformationW(wstr ptr) @ stdcall GetDllDirectoryA(long ptr) @ stdcall GetDllDirectoryW(long ptr) @ stdcall -import GetDriveTypeA(str) @@ -777,7 +781,8 @@ @ stdcall -import GetUserPreferredUILanguages(long ptr ptr ptr) @ stdcall GetPackageFamilyName(long ptr ptr) kernelbase.GetPackageFamilyName @ stdcall GetPackageFullName(long ptr ptr) kernelbase.GetPackageFullName -@ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) kernelbase.GetPackagesByPackageFamily +@ stdcall -import GetPackagePath(ptr long ptr ptr) +@ stdcall -import GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) @ stdcall GetPackagePathByFullName(wstr ptr wstr) kernelbase.GetPackagePathByFullName @ stdcall -import GetPhysicallyInstalledSystemMemory(ptr) @ stdcall -import GetPriorityClass(long) @@ -974,6 +979,7 @@ @ stdcall -import InitializeCriticalSectionAndSpinCount(ptr long) @ stdcall -import InitializeCriticalSectionEx(ptr long long) @ stdcall -import InitializeProcThreadAttributeList(ptr long long ptr) +@ stdcall -import InitializeSynchronizationBarrier(ptr long long) @ stdcall InitializeSListHead(ptr) NTDLL.RtlInitializeSListHead @ stdcall InitializeSRWLock(ptr) NTDLL.RtlInitializeSRWLock @ stdcall -arch=i386 InterlockedCompareExchange (ptr long long) @@ -1168,6 +1174,7 @@ @ stdcall -import PeekConsoleInputW(ptr ptr long ptr) @ stdcall -import PeekNamedPipe(long ptr long ptr ptr ptr) @ stdcall -import PostQueuedCompletionStatus(long long ptr ptr) +@ stdcall -import PackageFullNameFromId(ptr ptr ptr) @ stdcall -import PackageIdFromFullName(wstr long ptr ptr) @ stdcall PowerClearRequest(long long) @ stdcall PowerCreateRequest(ptr) @@ -1324,7 +1331,7 @@ @ cdecl -arch=!i386 RtlDeleteFunctionTable(ptr) NTDLL.RtlDeleteFunctionTable @ stdcall RtlFillMemory(ptr long long) NTDLL.RtlFillMemory @ cdecl -arch=!i386 RtlInstallFunctionTableCallback(long long long ptr ptr ptr) NTDLL.RtlInstallFunctionTableCallback -@ stdcall -arch=!i386 RtlLookupFunctionEntry(long ptr ptr) NTDLL.RtlLookupFunctionEntry +@ stdcall -arch=!i386 RtlLookupFunctionEntry(long ptr ptr) RtlLookupFunctionEntry @ stdcall RtlMoveMemory(ptr ptr long) NTDLL.RtlMoveMemory @ stdcall RtlPcToFileHeader(ptr ptr) NTDLL.RtlPcToFileHeader @ stdcall -arch=arm,x86_64 -norelay RtlRaiseException(ptr) NTDLL.RtlRaiseException @@ -1626,10 +1633,12 @@ @ stdcall WakeAllConditionVariable(ptr) NTDLL.RtlWakeAllConditionVariable @ stdcall WakeConditionVariable(ptr) NTDLL.RtlWakeConditionVariable @ stdcall -import WerGetFlags(ptr ptr) +@ stdcall -import WerRegisterCustomMetadata(wstr wstr) @ stdcall -import WerRegisterFile(wstr long long) @ stdcall -import WerRegisterMemoryBlock(ptr long) @ stdcall -import WerRegisterRuntimeExceptionModule(wstr ptr) @ stdcall -import WerSetFlags(long) +@ stdcall -import WerUnregisterCustomMetadata(wstr) @ stdcall -import WerUnregisterFile(wstr) @ stdcall -import WerUnregisterMemoryBlock(ptr) @ stdcall -import WerUnregisterRuntimeExceptionModule(wstr ptr) diff --git a/dlls/kernel32/tests/debugger.c b/dlls/kernel32/tests/debugger.c index 0782b8f21ebf..fa2450c8496a 100644 --- a/dlls/kernel32/tests/debugger.c +++ b/dlls/kernel32/tests/debugger.c @@ -2420,6 +2420,73 @@ static void test_kill_on_exit(const char *argv0) heap_free(cmd); } +static void test_OutputDebugString(void) +{ + static void (WINAPI *pOutputDebugStringA)(const char *); + + pOutputDebugStringA = (void *)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "OutputDebugStringA"); + ok(!!pOutputDebugStringA, "got NULL"); + SetLastError(0xdeadbeef); + pOutputDebugStringA("test"); + ok(GetLastError() == 0xdeadbeef, "got %ld.\n", GetLastError()); + + pOutputDebugStringA = (void *)GetProcAddress(GetModuleHandleW(L"kernelbase.dll"), "OutputDebugStringA"); + ok(!!pOutputDebugStringA, "got NULL"); + SetLastError(0xdeadbeef); + pOutputDebugStringA("test"); + ok(GetLastError() == 0xdeadbeef, "got %ld.\n", GetLastError()); + + SetLastError(0xdeadbeef); + OutputDebugStringW(L"test"); + ok(GetLastError() == 0xdeadbeef, "got %ld.\n", GetLastError()); +} + +static LONG WINAPI test_unhandled_exception_filter_topfilter( EXCEPTION_POINTERS *ep ) +{ + static int depth; + EXCEPTION_RECORD *rec = ep->ExceptionRecord; + LONG ret; + + ++depth; + if (depth > 1) return EXCEPTION_CONTINUE_SEARCH; + + ret = UnhandledExceptionFilter( ep ); + ok( depth == 2, "got %d.\n", depth ); + --depth; + ok( ret == EXCEPTION_EXECUTE_HANDLER, "got %#lx.\n", ret ); + rec->ExceptionFlags = EXCEPTION_NESTED_CALL; + ret = UnhandledExceptionFilter( ep ); + ok( depth == 1, "got %d.\n", depth ); + depth = 1; + ok( ret == EXCEPTION_CONTINUE_SEARCH, "got %#lx.\n", ret ); + --depth; + rec->ExceptionFlags = 0; + return EXCEPTION_CONTINUE_SEARCH; +} + +static void test_unhandled_exception_filter(void) +{ + EXCEPTION_RECORD rec = { .ExceptionCode = 0xbeef }; + EXCEPTION_POINTERS ep = { .ExceptionRecord = &rec }; + LPTOP_LEVEL_EXCEPTION_FILTER old; + LONG ret; + + old = SetUnhandledExceptionFilter( test_unhandled_exception_filter_topfilter ); + ret = UnhandledExceptionFilter( &ep ); + ok( ret == EXCEPTION_EXECUTE_HANDLER, "got %ld.\n", ret ); + + SetUnhandledExceptionFilter( NULL ); + + rec.ExceptionFlags = EXCEPTION_NESTED_CALL; + ret = UnhandledExceptionFilter( &ep ); + ok( ret == EXCEPTION_CONTINUE_SEARCH, "got %#lx.\n", ret ); + rec.ExceptionFlags &= ~EXCEPTION_NESTED_CALL; + ret = UnhandledExceptionFilter( &ep ); + ok( ret == EXCEPTION_EXECUTE_HANDLER, "got %#lx.\n", ret ); + + SetUnhandledExceptionFilter( old ); +} + START_TEST(debugger) { HMODULE hdll; @@ -2485,5 +2552,7 @@ START_TEST(debugger) test_debug_children(myARGV[0], DEBUG_ONLY_THIS_PROCESS, FALSE, TRUE); test_debugger(myARGV[0]); test_kill_on_exit(myARGV[0]); + test_OutputDebugString(); + test_unhandled_exception_filter(); } } diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index c57edebb3165..f2b20c18fc50 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -38,6 +38,7 @@ #undef DeleteFile /* needed for FILE_DISPOSITION_INFO */ static HANDLE (WINAPI *pFindFirstFileExA)(LPCSTR,FINDEX_INFO_LEVELS,LPVOID,FINDEX_SEARCH_OPS,LPVOID,DWORD); +static BOOL (WINAPI *pGetOverlappedResultEx)(HANDLE, OVERLAPPED *, DWORD *, DWORD, BOOL); static BOOL (WINAPI *pReplaceFileW)(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPVOID, LPVOID); static UINT (WINAPI *pGetSystemWindowsDirectoryA)(LPSTR, UINT); static BOOL (WINAPI *pGetVolumeNameForVolumeMountPointA)(LPCSTR, LPSTR, DWORD); @@ -93,6 +94,7 @@ static void InitFunctionPointers(void) pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); pFindFirstFileExA=(void*)GetProcAddress(hkernel32, "FindFirstFileExA"); + pGetOverlappedResultEx =(void*)GetProcAddress(hkernel32, "GetOverlappedResultEx"); pReplaceFileW=(void*)GetProcAddress(hkernel32, "ReplaceFileW"); pGetSystemWindowsDirectoryA=(void*)GetProcAddress(hkernel32, "GetSystemWindowsDirectoryA"); pGetVolumeNameForVolumeMountPointA = (void *) GetProcAddress(hkernel32, "GetVolumeNameForVolumeMountPointA"); @@ -2286,6 +2288,9 @@ static void test_LockFile(void) OVERLAPPED overlapped; int limited_LockFile; int limited_UnLockFile; + LARGE_INTEGER count, offset; + IO_STATUS_BLOCK iosb; + NTSTATUS status; BOOL ret; handle = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, @@ -2304,6 +2309,17 @@ static void test_LockFile(void) ok( 0, "couldn't open file \"%s\" (err=%ld)\n", filename, GetLastError() ); goto cleanup; } + + count.QuadPart = 0; + offset.QuadPart = 0; + status = NtUnlockFile( handle, NULL, &count, &offset, NULL ); + ok( status == STATUS_ACCESS_VIOLATION, "got %#lx.\n", status ); + memset( &iosb, 0xcc, sizeof(iosb) ); + status = NtUnlockFile( handle, &iosb, &count, &offset, NULL ); + todo_wine_if(NT_ERROR(status)) ok( status == STATUS_RANGE_NOT_LOCKED, "got %#lx.\n", status ); + ok( iosb.Status == status, "got %lu.\n", iosb.Status); + ok( !iosb.Information, "got %Iu.\n", iosb.Information); + ok( WriteFile( handle, sillytext, strlen(sillytext), &written, NULL ), "write failed\n" ); ok( LockFile( handle, 0, 0, 0, 0 ), "LockFile failed\n" ); @@ -2327,6 +2343,16 @@ static void test_LockFile(void) ok( !UnlockFile( handle, 10, 0, 20, 0 ), "UnlockFile 10,20 again succeeded\n" ); ok( UnlockFile( handle, 5, 0, 5, 0 ), "UnlockFile 5,5 failed\n" ); + ret = LockFile( handle, 5, 0, 5, 0 ); + ok( ret, "got error %lu.\n", GetLastError() ); + count.QuadPart = 5; + offset.QuadPart = 5; + memset( &iosb, 0xcc, sizeof(iosb) ); + status = NtUnlockFile( handle, &iosb, &count, &offset, NULL ); + ok( !status, "got %#lx.\n", status ); + ok( iosb.Status == status, "got %lu.\n", iosb.Status); + ok( !iosb.Information, "got %Iu.\n", iosb.Information); + overlapped.Offset = 100; overlapped.OffsetHigh = 0; overlapped.hEvent = 0; @@ -3730,8 +3756,93 @@ static void test_OpenFile(void) static void test_overlapped(void) { + static const struct + { + BOOL ex, alertable, wait, queue_apc; + BOOL pass_file_handle, pass_event_handle, set_event; + } + tests[] = + { + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, + { TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, + { TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE }, + { FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE }, + { TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE }, + { TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE }, + { TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE }, + { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE }, + { FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE }, + { TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE }, + { TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE }, + { FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE }, + { TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE }, + { TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE }, + { TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE }, + { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE }, + { FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE }, + { TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE }, + { TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE }, + { FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE }, + { TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE }, + { TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE }, + { TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE }, + { TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE }, + { FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE }, + { TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE }, + { TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE }, + { FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE }, + { TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE }, + { TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE }, + { TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE }, + { TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE }, + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE }, + { TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE }, + { TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE }, + { FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE }, + { TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE }, + { TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE }, + { TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE }, + { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE }, + { FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE }, + { TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE }, + { TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE }, + { FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE }, + { TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE }, + { TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE }, + { TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE }, + { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE }, + { FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE }, + { TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE }, + { TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE }, + { FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE }, + { TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE }, + { TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE }, + { TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE }, + { TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE }, + { FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE }, + { TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE }, + { TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE }, + { FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE }, + { TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE }, + { TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE }, + { TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE }, + { TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, + }; + static const NTSTATUS test_status[] = + { + STATUS_SUCCESS, STATUS_PENDING, STATUS_UNEXPECTED_IO_ERROR, + }; + static const ULONG_PTR test_file_bits[] = + { + 0, 1, 2, 3, 0xdeadbeef, + }; + OVERLAPPED ov; - DWORD r, result; + DWORD r, result, err; + HANDLE event; + unsigned int i, status_idx, file_bits_idx; + NTSTATUS iosb_status; + ULONG_PTR file_bits, event_bits; /* GetOverlappedResult crashes if the 2nd or 3rd param are NULL */ if (0) /* tested: WinXP */ @@ -3786,10 +3897,13 @@ static void test_overlapped(void) "wrong error %lu\n", GetLastError() ); ok( r == FALSE, "should return false\n"); + SetLastError( 0xdeadbeef ); r = GetOverlappedResult( 0, &ov, &result, TRUE ); ok( r == TRUE, "should return TRUE\n" ); ok( result == 0xabcd, "wrong result %lu\n", result ); ok( ov.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %08Ix\n", ov.Internal ); + err = GetLastError(); + ok( err == ERROR_IO_PENDING || broken( err == 0xdeadbeef ) /* Before Win10 1809 */, "got %lu.\n", GetLastError() ); ResetEvent( ov.hEvent ); @@ -3803,6 +3917,154 @@ static void test_overlapped(void) r = CloseHandle( ov.hEvent ); ok( r == TRUE, "close handle failed\n"); + + if (!pGetOverlappedResultEx) + { + win_skip( "GetOverlappedResultEx is not available, skipping tests.\n" ); + return; + } + + event = CreateEventW( NULL, FALSE, FALSE, NULL ); + + user_apc_ran = FALSE; + QueueUserAPC( user_apc, GetCurrentThread(), 0 ); + SetEvent( event ); + r = WaitForSingleObjectEx( event, INFINITE, TRUE ); + todo_wine ok( r == WAIT_IO_COMPLETION, "got %lu.\n", r ); + if (!r) SleepEx( 0, TRUE ); + ok( user_apc_ran, "APC was not run.\n" ); + + user_apc_ran = FALSE; + SetEvent( event ); + QueueUserAPC( user_apc, GetCurrentThread(), 0 ); + r = WaitForSingleObjectEx( event, 2, TRUE ); + todo_wine ok( r == WAIT_IO_COMPLETION, "got %lu.\n", r ); + if (!r) SleepEx( 0, TRUE ); + ok( user_apc_ran, "APC was not run.\n" ); + + user_apc_ran = FALSE; + SetEvent( event ); + QueueUserAPC( user_apc, GetCurrentThread(), 0 ); + r = WaitForSingleObjectEx( event, 0, TRUE ); + todo_wine ok( r == WAIT_IO_COMPLETION, "got %lu.\n", r ); + if (!r) SleepEx( 0, TRUE ); + ok( user_apc_ran, "APC was not run.\n" ); + + for (event_bits = 0; event_bits < 2; ++event_bits) + for (file_bits_idx = 0; file_bits_idx < ARRAY_SIZE(test_file_bits); ++file_bits_idx) + { + file_bits = test_file_bits[file_bits_idx]; + for (status_idx = 0; status_idx < ARRAY_SIZE(test_status); ++status_idx) + { + iosb_status = test_status[status_idx]; + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + BOOL will_wait, wait_fails, wait_alerts, wait_timeouts; + DWORD err; + HANDLE file; + + ov.Internal = iosb_status; + ov.InternalHigh = 0xabcd; + ov.hEvent = (tests[i].pass_event_handle ? event : NULL); + file = (tests[i].pass_file_handle ? event : NULL); + ov.hEvent = (HANDLE)((ULONG_PTR)ov.hEvent | event_bits); + file = (HANDLE)((ULONG_PTR)file | file_bits); + will_wait = tests[i].wait + && (iosb_status == STATUS_PENDING || (tests[i].ex && !(file_bits & 1))); + wait_fails = will_wait && WaitForSingleObject( ov.hEvent ? ov.hEvent : file, 0 ) == WAIT_FAILED; + wait_alerts = will_wait && tests[i].ex && tests[i].alertable && tests[i].queue_apc; + wait_timeouts = will_wait && !wait_fails && !wait_alerts && !tests[i].set_event && !(tests[i].ex && file_bits & 1); + if (will_wait && !tests[i].ex && wait_timeouts) + { + /* This would wait forever. */ + continue; + } + + winetest_push_context( "status %#lx, file_bits %Iu, event_bits %Iu, test %u", + iosb_status, file_bits, event_bits, i ); + + if (tests[i].set_event) + SetEvent( event ); + else + ResetEvent( event ); + + if (tests[i].queue_apc) + QueueUserAPC( user_apc, GetCurrentThread(), 0 ); + + result = 0xdeadbeef; + SetLastError( 0xdeadbeef ); + if (tests[i].ex) + r = pGetOverlappedResultEx( file, &ov, &result, tests[i].wait ? 2 : 0, tests[i].alertable ); + else + r = GetOverlappedResult( file, &ov, &result, tests[i].wait ); + err = GetLastError(); + if (will_wait) + { + if (wait_fails) + { + ok( !r, "got %lu.\n", r ); + ok( err == ERROR_INVALID_HANDLE, "got %lu.\n", err ); + ok( result == 0xdeadbeef, "wrong result %lu\n", result ); + } + else if (wait_alerts) + { + /* todo comes from WaitForSingleObjectEx() with signaled event and queued APC not preferring + * user APC (which is tested above for clarity) */ + todo_wine_if(tests[i].set_event) ok( err == WAIT_IO_COMPLETION, "got %lu.\n", err ); + if (err == WAIT_IO_COMPLETION) + { + ok( !r, "got %lu.\n", r ); + ok( result == 0xdeadbeef, "wrong result %lu\n", result ); + } + } + else if (wait_timeouts) + { + ok( !r, "got %lu.\n", r ); + ok( err == WAIT_TIMEOUT, "got %lu.\n", err ); + ok( result == 0xdeadbeef, "wrong result %lu\n", result ); + } + else + { + ok( r == (iosb_status == STATUS_SUCCESS || iosb_status == STATUS_PENDING), + "got %lu.\n", r ); + ok( err == RtlNtStatusToDosError( iosb_status ) || broken( r && err == 0xdeadbeef ) /* Before Win10 1809 */, + "got %lu.\n", err ); + ok( result == 0xabcd, "wrong result %lu\n", result ); + } + } + else if (iosb_status == STATUS_PENDING) + { + ok( !r, "got %lu.\n", r ); + ok( err == ERROR_IO_INCOMPLETE, "got %lu.\n", err ); + ok( result == 0xdeadbeef, "wrong result %lu\n", result ); + } + else + { + ok( r == (iosb_status == STATUS_SUCCESS || iosb_status == STATUS_PENDING), + "got %lu.\n", r ); + ok( err == RtlNtStatusToDosError( iosb_status ) || broken( r && err == 0xdeadbeef ) /* Before Win10 1809 */, + "got %lu.\n", err ); + ok( result == 0xabcd, "wrong result %lu\n", result ); + } + + r = WaitForSingleObject( event, 0 ); + if (!tests[i].set_event || (will_wait && !wait_fails && !wait_alerts)) + { + ok( r == WAIT_TIMEOUT, "got %#lx.\n", r ); + } + else + { + todo_wine_if(will_wait && !wait_fails && wait_alerts && tests[i].set_event) + ok( r == WAIT_OBJECT_0, "got %#lx.\n", r ); + } + + winetest_pop_context(); + if (tests[i].queue_apc) + SleepEx( 0, TRUE ); + } + } + } + CloseHandle( event ); } static void test_RemoveDirectory(void) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index c62eb4491924..b7daabb7ad5b 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -38,9 +38,13 @@ #define HEAP_VALIDATE_ALL 0x20000000 #define HEAP_VALIDATE_PARAMS 0x40000000 +#define REGION_ALIGN 0x10000 +#define INITIAL_COMMIT_ALIGN (0x400 * sizeof(void *)) #define BLOCK_ALIGN (2 * sizeof(void *) - 1) #define ALIGN_BLOCK_SIZE(x) (((x) + BLOCK_ALIGN) & ~BLOCK_ALIGN) +#define ROUND_SIZE(size, mask) ((((SIZE_T)(size) + (mask)) & ~(SIZE_T)(mask))) + /* use function pointers to avoid warnings for invalid parameter tests */ static LPVOID (WINAPI *pHeapAlloc)(HANDLE,DWORD,SIZE_T); static LPVOID (WINAPI *pHeapReAlloc)(HANDLE,DWORD,LPVOID,SIZE_T); @@ -571,8 +575,7 @@ static void test_HeapCreate(void) ok( entries[0].cbData <= 0x1000 /* sizeof(*heap) */, "got cbData %#lx\n", entries[0].cbData ); ok( entries[0].cbOverhead == 0, "got cbOverhead %#x\n", entries[0].cbOverhead ); ok( entries[0].iRegionIndex == 0, "got iRegionIndex %d\n", entries[0].iRegionIndex ); - todo_wine - ok( entries[0].Region.dwCommittedSize == 0x400 * sizeof(void *), + todo_wine ok( entries[0].Region.dwCommittedSize == 0x400 * sizeof(void *), "got Region.dwCommittedSize %#lx\n", entries[0].Region.dwCommittedSize ); ok( entries[0].Region.dwUnCommittedSize == 0x10000 - entries[0].Region.dwCommittedSize || entries[0].Region.dwUnCommittedSize == 0x10000 * sizeof(void *) - entries[0].Region.dwCommittedSize /* win7 */, @@ -747,6 +750,9 @@ static void test_HeapCreate(void) while ((ret = HeapWalk( heap, &entry ))) entries[count++] = entry; ok( GetLastError() == ERROR_NO_MORE_ITEMS, "got error %lu\n", GetLastError() ); ok( count == 4, "got count %lu\n", count ); + todo_wine ok( entries->Region.dwCommittedSize == INITIAL_COMMIT_ALIGN, "got %#lx.\n", entries->Region.dwCommittedSize ); + ok( entries->Region.dwUnCommittedSize == REGION_ALIGN - entries->Region.dwCommittedSize, "got %#lx.\n", + entries->Region.dwUnCommittedSize ); ok( !memcmp( entries + 16, entries, 1 * sizeof(entry) ), "entries differ\n" ); ok( memcmp( entries + 17, entries + 2, 2 * sizeof(entry) ), "entries differ\n" ); @@ -1544,7 +1550,7 @@ static void test_GlobalAlloc(void) ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); tmp_mem = pGlobalFree( mem ); ok( !tmp_mem, "GlobalFree failed, error %lu\n", GetLastError() ); - if (sizeof(void *) != 8) /* crashes on 64-bit */ + if (0) /* crashes on Windows */ { SetLastError( 0xdeadbeef ); tmp_mem = pGlobalFree( mem ); @@ -1587,7 +1593,7 @@ static void test_GlobalAlloc(void) tmp_mem = GlobalReAlloc( mem, 0, GMEM_MOVEABLE ); ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); - if (sizeof(void *) != 8) /* crashes on 64-bit */ + if (0) /* crashes on Windows */ { SetLastError( 0xdeadbeef ); tmp_mem = GlobalHandle( mem ); @@ -1621,7 +1627,7 @@ static void test_GlobalAlloc(void) tmp_mem = GlobalReAlloc( invalid_mem, 0, GMEM_MOVEABLE ); ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); - if (sizeof(void *) != 8) /* crashes on 64-bit */ + if (0) /* crashes on Windows */ { SetLastError( 0xdeadbeef ); tmp_mem = GlobalHandle( invalid_mem ); @@ -2334,7 +2340,7 @@ static void test_LocalAlloc(void) tmp_mem = LocalReAlloc( mem, 0, LMEM_MOVEABLE ); ok( !tmp_mem, "LocalReAlloc succeeded\n" ); ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); - if (sizeof(void *) != 8) /* crashes on 64-bit */ + if (0) /* crashes on Windows */ { SetLastError( 0xdeadbeef ); tmp_mem = LocalHandle( mem ); @@ -2367,7 +2373,7 @@ static void test_LocalAlloc(void) tmp_mem = LocalReAlloc( invalid_mem, 0, LMEM_MOVEABLE ); ok( !tmp_mem, "LocalReAlloc succeeded\n" ); ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); - if (sizeof(void *) != 8) /* crashes on 64-bit */ + if (0) /* crashes on Windows */ { SetLastError( 0xdeadbeef ); tmp_mem = LocalHandle( invalid_mem ); @@ -3456,6 +3462,48 @@ static void test_heap_layout( HANDLE handle, DWORD global_flag, DWORD heap_flags } } +static void test_heap_tail_zeroing( DWORD heap_flags ) +{ + static const ULONG_PTR large_block_min_size = 65536 * (2 * sizeof(void *)); + HANDLE heap = GetProcessHeap(); + size_t size, size_aligned; + ULONG_PTR v, expected; + char *p1, *p2; + + if (heap_flags & HEAP_PAGE_ALLOCS) + { + /* This behaves differently, no support yet. */ + skip( "Skipping test with HEAP_PAGE_ALLOCS.\n" ); + return; + } + + for (size = 1; size <= 1048576 * 2; size *= 2) + { + winetest_push_context( "heap_flags %#lx, size %Iu", heap_flags, size ); + p1 = pHeapAlloc( heap, 0, size + 1 ); + ok( !!p1, "got NULL.\n" ); + size_aligned = ROUND_SIZE(size + 1, sizeof(void *) - 1); + /* This and read access below is going to make valgrind or ASAN unhappy but the purpose of this test is + * to specifically check what happens with the tail bytes following the allocation. */ + if (!(heap_flags & (HEAP_VALIDATE_PARAMS | HEAP_VALIDATE_ALL))) + memset( p1, 0xcc, size_aligned ); + pHeapFree( heap, 0, p1 ); + + /* We are not guarenteed to get the same pointer here but that often happens, especially when the test + * is run first, and spoling the data before that adds certainity to the results. */ + p2 = pHeapAlloc( heap, HEAP_ZERO_MEMORY, size + 1 ); + ok( !!p2, "got NULL.\n" ); + v = 0; + memcpy( &v, p2 + size, size_aligned - size ); + expected = 0; + if (size_aligned - size > 1 && size + 1 < large_block_min_size && heap_flags & HEAP_TAIL_CHECKING_ENABLED) + memset( (char *)&expected + 1, 0xab, size_aligned - size - 1 ); + ok( v == expected, "got %#Ix, expected %#Ix.\n", v, expected ); + pHeapFree( heap, 0, p2 ); + winetest_pop_context(); + } +} + static void test_child_heap( const char *arg ) { char buffer[32]; @@ -3535,6 +3583,7 @@ static void test_child_heap( const char *arg ) ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); test_heap_checks( heap_flags ); + test_heap_tail_zeroing( heap_flags ); } static void test_GetPhysicallyInstalledSystemMemory(void) @@ -3645,12 +3694,13 @@ static void test_GlobalMemoryStatus(void) #undef IS_WITHIN_RANGE } -static void get_valloc_info( void *mem, char **base, SIZE_T *alloc_size ) +static void get_valloc_info( void *mem, char **base, SIZE_T *alloc_size, SIZE_T *commit_size ) { MEMORY_BASIC_INFORMATION info, info2; SIZE_T size; char *p; + *commit_size = 0; size = VirtualQuery( mem, &info, sizeof(info) ); ok( size == sizeof(info), "got %Iu.\n", size ); @@ -3663,6 +3713,7 @@ static void get_valloc_info( void *mem, char **base, SIZE_T *alloc_size ) if (info2.AllocationBase != info.AllocationBase) break; ok( info2.State == MEM_RESERVE || info2.State == MEM_COMMIT, "got %#lx.\n", info2.State ); + if (info2.State == MEM_COMMIT) *commit_size += info2.RegionSize; p += info2.RegionSize; } @@ -3670,32 +3721,39 @@ static void get_valloc_info( void *mem, char **base, SIZE_T *alloc_size ) *alloc_size = p - *base; } -static void test_heap_size( SIZE_T initial_size ) +static void test_heap_size( SIZE_T initial_commit_size ) { - static const SIZE_T default_heap_size = 0x10000, init_grow_size = 0x100000, max_grow_size = 0xfd0000; + static const SIZE_T init_grow_size = 0x100000, max_grow_size = 0xfd0000, test_alloc_size = 0x60000; BOOL initial_subheap = TRUE, max_size_reached = FALSE; - SIZE_T alloc_size, current_subheap_size; + SIZE_T alloc_size, committed_size, current_subheap_size, expected, commit_size, initial_committed_size; char *base, *current_base; + BOOL subheap_changed; unsigned int i; HANDLE heap; void *p; - winetest_push_context( "init size %#Ix", initial_size ); - heap = HeapCreate( HEAP_NO_SERIALIZE, initial_size, 0 ); - get_valloc_info( heap, ¤t_base, &alloc_size ); + winetest_push_context( "init size %#Ix", initial_commit_size ); + heap = HeapCreate( HEAP_NO_SERIALIZE, initial_commit_size, 0 ); + get_valloc_info( heap, ¤t_base, &alloc_size, &committed_size ); - ok( alloc_size == initial_size + default_heap_size || broken( (initial_size && alloc_size == initial_size) - || (!initial_size && (alloc_size == default_heap_size * sizeof(void*))) ) /* Win7 */, - "got %#Ix.\n", alloc_size ); + commit_size = ROUND_SIZE( initial_commit_size, INITIAL_COMMIT_ALIGN - 1 ); + expected = ROUND_SIZE( commit_size + 1, REGION_ALIGN - 1 ); + + ok( alloc_size == expected, "got %#Ix, expected %#Ix.\n", alloc_size, expected ); + expected = max( commit_size, INITIAL_COMMIT_ALIGN ); + todo_wine_if( (!initial_commit_size || (initial_commit_size & (REGION_ALIGN - 1))) + && !(initial_commit_size > REGION_ALIGN - INITIAL_COMMIT_ALIGN && initial_commit_size < REGION_ALIGN)) + ok( committed_size == expected, "got commit size %#Ix, expected %#Ix.\n", committed_size, expected ); current_subheap_size = alloc_size; + initial_committed_size = committed_size; + commit_size = 0; for (i = 0; i < 100; ++i) { - winetest_push_context( "i %u, current_subheap_size %#Ix", i, current_subheap_size ); - p = HeapAlloc( heap, 0, 0x60000 ); - get_valloc_info( p, &base, &alloc_size ); - if (base != current_base) + p = HeapAlloc( heap, 0, test_alloc_size ); + get_valloc_info( p, &base, &alloc_size, &committed_size ); + if ((subheap_changed = (base != current_base))) { current_base = base; if (initial_subheap) @@ -3709,8 +3767,18 @@ static void test_heap_size( SIZE_T initial_size ) if (current_subheap_size == max_grow_size) max_size_reached = TRUE; } + commit_size = 0x1000; + initial_committed_size = 0; } + + winetest_push_context( "i %u, current_subheap_size %#Ix, subheap_changed %d", i, current_subheap_size, + subheap_changed ); + commit_size += test_alloc_size + 0x1000; ok( alloc_size == current_subheap_size, "got %#Ix.\n", alloc_size ); + expected = max( initial_committed_size, commit_size ); + todo_wine_if(commit_size != 0x5b0000 && expected != initial_commit_size) + ok( committed_size == expected, "got %#Ix, expected %#Ix, commit_size %#Ix, initial_committed_size %#Ix. p %p.\n", + committed_size, expected, commit_size, initial_committed_size, p ); winetest_pop_context(); } ok( max_size_reached, "Did not reach maximum subheap size.\n" ); @@ -3722,10 +3790,24 @@ static void test_heap_size( SIZE_T initial_size ) static void test_heap_sizes(void) { unsigned int i; - SIZE_T size, round_size = 0x400 * sizeof(void*); + SIZE_T size, commit_size, round_size = 0x400 * sizeof(void*); char *base; test_heap_size( 0 ); + test_heap_size( 1 ); + test_heap_size( 0x100 ); + test_heap_size( 0xf00 ); + test_heap_size( 0xfff ); + test_heap_size( 0x1000 ); + test_heap_size( 0xe000 ); + test_heap_size( 0xe001 ); + test_heap_size( 0xf000 ); + test_heap_size( 0xf001 ); + test_heap_size( 0xffff ); + test_heap_size( 0x10000 ); + test_heap_size( 0x20fff ); + test_heap_size( 0x30000 ); + test_heap_size( 0x30001 ); test_heap_size( 0x80000 ); test_heap_size( 0x150000 ); @@ -3733,7 +3815,7 @@ static void test_heap_sizes(void) { HANDLE heap = HeapCreate( 0, i * 0x100, i * 0x100 ); ok( heap != NULL, "%x: creation failed\n", i * 0x100 ); - get_valloc_info( heap, &base, &size ); + get_valloc_info( heap, &base, &size, &commit_size ); ok( size == ((i * 0x100 + round_size - 1) & ~(round_size - 1)), "%x: wrong size %Ix\n", i * 0x100, size ); HeapDestroy( heap ); @@ -3760,6 +3842,7 @@ START_TEST(heap) test_GetPhysicallyInstalledSystemMemory(); test_GlobalMemoryStatus(); + test_heap_tail_zeroing( 0 ); if (pRtlGetNtGlobalFlags) { diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 0871ae3b57f0..fa14bc53836c 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -68,7 +68,7 @@ static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG_PTR, S static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG); static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *); static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR); -static NTSTATUS (WINAPI *pLdrLoadDll)(LPCWSTR,DWORD,const UNICODE_STRING *,HMODULE*); +static NTSTATUS (WINAPI *pLdrLoadDll)(LPCWSTR,DWORD *,const UNICODE_STRING *,HMODULE*); static NTSTATUS (WINAPI *pLdrUnloadDll)(HMODULE); static void (WINAPI *pRtlInitUnicodeString)(PUNICODE_STRING,LPCWSTR); static void (WINAPI *pRtlAcquirePebLock)(void); @@ -2121,8 +2121,8 @@ static DWORD WINAPI tls_thread_fn(void* tlsidx_v) static void test_import_resolution(void) { - char temp_path[MAX_PATH]; - char dll_name[MAX_PATH]; + WCHAR temp_path[MAX_PATH]; + WCHAR dll_name[MAX_PATH]; DWORD dummy; void *expect, *tmp; char *str; @@ -2131,6 +2131,7 @@ static void test_import_resolution(void) HMODULE mod, mod2; NTSTATUS status; LARGE_INTEGER offset; + UNICODE_STRING name; struct imports { IMAGE_IMPORT_DESCRIPTOR descr[2]; @@ -2186,7 +2187,7 @@ static void test_import_resolution(void) static const UCHAR entry_point_code[] = { 0x00 }; #endif - for (test = 0; test < 7; test++) + for (test = 0; test < 8; test++) { #define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data)) #ifdef _WIN64 @@ -2255,10 +2256,10 @@ static void test_import_resolution(void) nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = data.rel.reloc.SizeOfBlock; nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = DATA_RVA(&data.rel); - GetTempPathA(MAX_PATH, temp_path); - GetTempFileNameA(temp_path, "ldr", 0, dll_name); + GetTempPathW(MAX_PATH, temp_path); + GetTempFileNameW(temp_path, L"ldr", 0, dll_name); - hfile = CreateFileA(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0); + hfile = CreateFileW(dll_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0); ok( hfile != INVALID_HANDLE_VALUE, "creation failed\n" ); memset( §ion, 0, sizeof(section) ); @@ -2282,7 +2283,7 @@ static void test_import_resolution(void) switch (test) { case 0: /* normal load */ - mod = LoadLibraryA( dll_name ); + mod = LoadLibraryW( dll_name ); ok( mod != NULL, "failed to load err %lu\n", GetLastError() ); if (!mod) break; ptr = (struct imports *)((char *)mod + page_size); @@ -2296,8 +2297,20 @@ static void test_import_resolution(void) check_tls_index(mod, ptr->tls_index != 9999); FreeLibrary( mod ); break; + case 7: case 1: /* load with DONT_RESOLVE_DLL_REFERENCES doesn't resolve imports */ - mod = LoadLibraryExA( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES ); + if (test == 7) + { + DWORD load_flags = LDR_DONT_RESOLVE_REFS; + + pRtlInitUnicodeString( &name, dll_name ); + status = pLdrLoadDll( NULL, &load_flags, &name, &mod ); + ok( !status, "got %#lx.\n", status ); + } + else + { + mod = LoadLibraryExW( dll_name, 0, DONT_RESOLVE_DLL_REFERENCES ); + } ok( mod != NULL, "failed to load err %lu\n", GetLastError() ); if (!mod) break; ptr = (struct imports *)((char *)mod + page_size); @@ -2305,7 +2318,7 @@ static void test_import_resolution(void) (void *)ptr->thunks[0].u1.Function, data.module, data.function.name ); ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index ); - mod2 = LoadLibraryA( dll_name ); + mod2 = LoadLibraryW( dll_name ); ok( mod2 == mod, "loaded twice %p / %p\n", mod, mod2 ); ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n", (void *)ptr->thunks[0].u1.Function, data.module, data.function.name ); @@ -2315,7 +2328,7 @@ static void test_import_resolution(void) FreeLibrary( mod ); break; case 2: /* load without IMAGE_FILE_DLL doesn't resolve imports */ - mod = LoadLibraryA( dll_name ); + mod = LoadLibraryW( dll_name ); ok( mod != NULL, "failed to load err %lu\n", GetLastError() ); if (!mod) break; ptr = (struct imports *)((char *)mod + page_size); @@ -2326,7 +2339,7 @@ static void test_import_resolution(void) FreeLibrary( mod ); break; case 3: /* load with tls init function */ - mod = LoadLibraryA( dll_name ); + mod = LoadLibraryW( dll_name ); ok( mod != NULL, "failed to load err %lu\n", GetLastError() ); if (!mod) break; ptr = (struct imports *)((char *)mod + page_size); @@ -2354,7 +2367,7 @@ static void test_import_resolution(void) case 4: /* map with ntdll */ case 5: /* map with ntdll, without IMAGE_FILE_DLL */ case 6: /* map with ntdll, without IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE */ - hfile = CreateFileA(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + hfile = CreateFileW(dll_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); ok( hfile != INVALID_HANDLE_VALUE, "CreateFile failed err %lu\n", GetLastError() ); mapping = CreateFileMappingA( hfile, NULL, SEC_IMAGE | PAGE_READONLY, 0, 0, NULL ); CloseHandle( hfile ); @@ -2406,7 +2419,7 @@ static void test_import_resolution(void) if (tmp) VirtualFree( tmp, 0, MEM_RELEASE ); break; } - DeleteFileA( dll_name ); + DeleteFileW( dll_name ); winetest_pop_context(); #undef DATA_RVA } @@ -4542,10 +4555,27 @@ static void test_wow64_redirection(void) char buffer[MAX_PATH]; static const char *dlls[] = {"wlanapi.dll", "dxgi.dll", "dwrite.dll"}; unsigned i; + HMODULE mod, mod_fixed, kernelbase; + IMAGE_NT_HEADERS *nt; + WORD machine; if (!is_wow64) return; + kernelbase = GetModuleHandleW(L"kernelbase.dll"); + nt = RtlImageNtHeader(kernelbase); + machine = nt->FileHeader.Machine; + + ok(!GetModuleHandleA("rasapi32.dll"), "rasapi32.dll is already loaded.\n"); + + mod = LoadLibraryExW(L"c:\\windows\\system32\\rasapi32.dll", 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE); + mod_fixed = (HMODULE)((ULONG_PTR)mod & ~(ULONG_PTR)3); + ok(!!mod_fixed, "got NULL.\n" ); + nt = RtlImageNtHeader(mod_fixed); + ok(!!nt, "got NULL.\n"); + ok(nt->FileHeader.Machine == machine, "got wrong machine.\n"); + FreeLibrary(mod); + /* Disable FS redirection, then test loading system libraries (pick ones that shouldn't * already be loaded in this process). */ @@ -4558,6 +4588,34 @@ static void test_wow64_redirection(void) test_wow64_redirection_for_dll(buffer, TRUE); } + mod = LoadLibraryExW(L"c:\\windows\\system32\\kernelbase.dll", 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE); + ok(!!mod, "got NULL.\n" ); + ok(mod == kernelbase, "got different modules.\n"); + FreeLibrary(mod); + + mod = LoadLibraryExW(L"c:\\windows\\system32\\kernelbase.dll", 0, LOAD_LIBRARY_AS_DATAFILE); + ok(!!mod, "got NULL.\n" ); + ok(mod == kernelbase, "got different modules.\n"); + FreeLibrary(mod); + + ok(!GetModuleHandleA("rasapi32.dll"), "rasapi32.dll is already loaded.\n"); + mod = LoadLibraryExW(L"c:\\windows\\system32\\rasapi32.dll", 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE); + mod_fixed = (HMODULE)((ULONG_PTR)mod & ~(ULONG_PTR)3); + ok(!!mod_fixed, "got NULL.\n" ); + nt = RtlImageNtHeader(mod_fixed); + ok(!!nt, "got NULL.\n"); + ok(nt->FileHeader.Machine != machine, "got 32 bit dll.\n"); + FreeLibrary(mod); + + ok(!GetModuleHandleA("rasapi32.dll"), "rasapi32.dll is already loaded.\n"); + mod = LoadLibraryExW(L"c:\\windows\\system32\\rasapi32.dll", 0, LOAD_LIBRARY_AS_DATAFILE); + mod_fixed = (HMODULE)((ULONG_PTR)mod & ~(ULONG_PTR)3); + ok(!!mod_fixed, "got NULL.\n" ); + nt = RtlImageNtHeader(mod_fixed); + ok(!!nt, "got NULL.\n"); + ok(nt->FileHeader.Machine != machine, "got 32 bit dll.\n"); + FreeLibrary(mod); + ok(pWow64RevertWow64FsRedirection(OldValue), "Re-enabling FS redirection failed\n"); /* and results don't depend whether redirection is enabled or not */ for (i = 0; i < ARRAY_SIZE(dlls); i++) diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c index 60fa7d99a8a2..c0cb9aeeded1 100644 --- a/dlls/kernel32/tests/locale.c +++ b/dlls/kernel32/tests/locale.c @@ -2841,6 +2841,24 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f ok(!ret, "%s func_ptr should fail with srclen = 0\n", func_name); ok(GetLastError() == ERROR_INVALID_PARAMETER, "%s unexpected error code %ld\n", func_name, GetLastError()); + + /* test for characters which don't get mapped to their + halfwidth counterparts on LCMAP_HALFWIDTH */ + for (i = 0x2190; i <= 0x21ff; ++i) + buf[i - 0x2190] = buf2[i - 0x2190] = i; + + buf[0x70] = buf2[0x70] = 0x25cb; + ret = func_ptr(LCMAP_HALFWIDTH, buf, 0x71, buf2, 0x71); + ok(ret == 0x71, "%s ret %#x, expected value 0x71\n", func_name, ret); + ok(!memcmp(buf, buf2, sizeof(WCHAR) * 0x71), "in- and output must be equal\n"); + + /* test the other way around */ + for (i = 0xffe9; i <= 0xffee; ++i) + buf[i - 0xffe9] = buf2[i - 0xffe9] = i; + + ret = func_ptr(LCMAP_FULLWIDTH, buf, 0x6, buf2, 0x6); + ok(ret == 0x6, "%s ret %#x, expected value 0x6\n", func_name, ret); + ok(!memcmp(buf, buf2, sizeof(WCHAR) * 0x6), "in- and output must be equal\n"); } static INT LCMapStringW_wrapper(DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen) diff --git a/dlls/kernel32/tests/module.c b/dlls/kernel32/tests/module.c index 0619ce5f7473..680f2379fdfd 100644 --- a/dlls/kernel32/tests/module.c +++ b/dlls/kernel32/tests/module.c @@ -44,6 +44,8 @@ static NTSTATUS (WINAPI *pLdrSetDllDirectory)(UNICODE_STRING*); static NTSTATUS (WINAPI *pLdrGetDllHandle)( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base ); static NTSTATUS (WINAPI *pLdrGetDllHandleEx)( ULONG flags, LPCWSTR load_path, ULONG *dll_characteristics, const UNICODE_STRING *name, HMODULE *base ); +static NTSTATUS (WINAPI *pLdrGetDllPath)(LPCWSTR,ULONG,LPWSTR*,LPWSTR*); +static NTSTATUS (WINAPI *pLdrLoadDll)(LPCWSTR,DWORD *,const UNICODE_STRING *,HMODULE*); static NTSTATUS (WINAPI *pLdrGetDllFullName)( HMODULE module, UNICODE_STRING *name ); static BOOL (WINAPI *pIsApiSetImplemented)(LPCSTR); @@ -519,9 +521,13 @@ static void test_LoadLibraryEx_search_flags(void) { { 1, 1, 2 }, 0, 2 }, }; char *p, path[MAX_PATH], buf[MAX_PATH], curdir[MAX_PATH]; - WCHAR bufW[MAX_PATH]; + WCHAR bufW[MAX_PATH], pathW[MAX_PATH]; DLL_DIRECTORY_COOKIE cookies[4]; + WCHAR *load_path, *dummy; unsigned int i, j, k; + UNICODE_STRING name; + DWORD load_flags; + NTSTATUS status; BOOL ret; HMODULE mod; @@ -550,6 +556,12 @@ static void test_LoadLibraryEx_search_flags(void) ok( mod != NULL, "LoadLibrary failed err %lu\n", GetLastError() ); FreeLibrary( mod ); + RtlInitUnicodeString( &name, L"1\\winetestdll.dll" ); + status = pLdrLoadDll( NULL, NULL, &name, &mod ); + ok( !status, "got %#lx.\n", status ); + ok( !!mod, "got NULL.\n" ); + FreeLibrary( mod ); + SetLastError( 0xdeadbeef ); sprintf( path, "%c:1\\winetestdll.dll", buf[0] ); mod = LoadLibraryA( path ); @@ -563,10 +575,46 @@ static void test_LoadLibraryEx_search_flags(void) ok( !mod, "LoadLibrary succeeded\n" ); ok( GetLastError() == ERROR_MOD_NOT_FOUND, "wrong error %lu\n", GetLastError() ); + RtlInitUnicodeString( &name, L"1\\winetestdll.dll" ); + mod = (void *)0xdeadbeef; + status = pLdrLoadDll( (void *)(ULONG_PTR)(LOAD_LIBRARY_SEARCH_SYSTEM32 | 1), NULL, &name, &mod ); + ok( status == STATUS_DLL_NOT_FOUND, "got %#lx.\n", status ); + ok( mod == (HMODULE)0xdeadbeef, "got %p.\n", mod ); + + load_flags = LOAD_LIBRARY_SEARCH_SYSTEM32; + mod = (void *)0xdeadbeef; + if (0) + { + /* crashes on Windows. */ + pLdrLoadDll( NULL, (void *)(ULONG_PTR)load_flags, &name, &mod ); + } + status = pLdrLoadDll( NULL, &load_flags, &name, &mod ); + ok( !status, "got %#lx.\n", status ); + FreeLibrary( mod ); + + status = pLdrGetDllPath( name.Buffer, LOAD_LIBRARY_SEARCH_SYSTEM32, &load_path, &dummy ); + ok( !status, "got %#lx.\n", status ); + mod = (void *)0xdeadbeef; + status = pLdrLoadDll( load_path, NULL, &name, &mod ); + ok( status == STATUS_DLL_NOT_FOUND, "got %#lx.\n", status ); + ok( mod == (HMODULE)0xdeadbeef, "got %p.\n", mod ); + RtlReleasePath( load_path ); + + mod = (void *)0xdeadbeef; + status = pLdrLoadDll( L".", NULL, &name, &mod ); + ok( !status, "got %#lx.\n", status ); + FreeLibrary( mod ); + SetLastError( 0xdeadbeef ); mod = LoadLibraryExA( path, 0, LOAD_LIBRARY_SEARCH_SYSTEM32 ); ok( mod != NULL, "LoadLibrary failed err %lu\n", GetLastError() ); FreeLibrary( mod ); + + MultiByteToWideChar( CP_ACP, 0, path, -1, pathW, ARRAY_SIZE(pathW) ); + RtlInitUnicodeString( &name, pathW ); + status = pLdrLoadDll( (void *)(LOAD_LIBRARY_SEARCH_SYSTEM32 | 1), NULL, &name, &mod ); + ok( !status, "got %#lx.\n", status ); + FreeLibrary( mod ); } strcpy( p, "\\1" ); @@ -614,6 +662,12 @@ static void test_LoadLibraryEx_search_flags(void) ok( !mod, "LoadLibrary succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + RtlInitUnicodeString( &name, L"winetestdll.dll" ); + mod = (void *)0xdeadbeef; + status = pLdrLoadDll( (void *)(LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_WITH_ALTERED_SEARCH_PATH | 1), NULL, &name, &mod ); + ok( status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status ); + ok( mod == (HMODULE)0xdeadbeef, "got %p.\n", mod ); + SetLastError( 0xdeadbeef ); mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_WITH_ALTERED_SEARCH_PATH ); ok( !mod, "LoadLibrary succeeded\n" ); @@ -673,6 +727,12 @@ static void test_LoadLibraryEx_search_flags(void) ok( !mod, "LoadLibrary succeeded\n" ); ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError() ); + RtlInitUnicodeString( &name, L"foo\\winetestdll.dll" ); + mod = (void *)0xdeadbeef; + status = pLdrLoadDll( (void *)(LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | 1), NULL, &name, &mod ); + ok( status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status ); + ok( mod == (HMODULE)0xdeadbeef, "got %p.\n", mod ); + SetLastError( 0xdeadbeef ); mod = LoadLibraryExA( "\\windows\\winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR ); ok( !mod, "LoadLibrary succeeded\n" ); @@ -716,6 +776,37 @@ static void test_LoadLibraryEx_search_flags(void) } FreeLibrary( mod ); + mod = LoadLibraryExA( "winetestdll.dll", 0, LOAD_LIBRARY_SEARCH_USER_DIRS ); + if (tests[j].expect) + { + ok( mod != NULL, "%u: LoadLibrary failed err %lu\n", j, GetLastError() ); + GetModuleFileNameA( mod, path, MAX_PATH ); + sprintf( p, "\\%u\\winetestdll.dll", tests[j].expect ); + ok( !lstrcmpiA( path, buf ), "%u: wrong module %s expected %s\n", j, path, buf ); + } + else + { + ok( !mod, "%u: LoadLibrary succeeded\n", j ); + ok( GetLastError() == ERROR_MOD_NOT_FOUND || broken(GetLastError() == ERROR_NOT_ENOUGH_MEMORY), + "%u: wrong error %lu\n", j, GetLastError() ); + } + FreeLibrary( mod ); + + mod = NULL; + RtlInitUnicodeString( &name, L"winetestdll.dll" ); + status = pLdrLoadDll( (void *)(ULONG_PTR)(LOAD_LIBRARY_SEARCH_USER_DIRS | 1), NULL, &name, &mod ); + if (tests[j].expect) + { + ok( !status, "got %#lx.\n", status ); + ok( !!mod, "got NULL.\n" ); + } + else + { + ok( status == STATUS_DLL_NOT_FOUND, "got %#lx.\n", status ); + ok( !mod, "got %p.\n", mod ); + } + FreeLibrary( mod ); + for (k = 0; tests[j].add_dirs[k]; k++) pRemoveDllDirectory( cookies[k] ); } @@ -968,6 +1059,8 @@ static void init_pointers(void) MAKEFUNC(LdrSetDllDirectory); MAKEFUNC(LdrGetDllHandle); MAKEFUNC(LdrGetDllHandleEx); + MAKEFUNC(LdrGetDllPath); + MAKEFUNC(LdrLoadDll); MAKEFUNC(LdrGetDllFullName); MAKEFUNC(RtlHashUnicodeString); mod = GetModuleHandleA( "kernelbase.dll" ); @@ -1708,7 +1801,10 @@ static void test_tls_links(void) TEB *teb = NtCurrentTeb(), *thread_teb; THREAD_BASIC_INFORMATION tbi; NTSTATUS status; + ULONG i, count; HANDLE thread; + SIZE_T size; + void **ptr; ok(!!teb->ThreadLocalStoragePointer, "got NULL.\n"); @@ -1728,6 +1824,26 @@ static void test_tls_links(void) ResumeThread(thread); WaitForSingleObject(test_tls_links_started, INFINITE); + if (!is_old_loader_struct()) + { + ptr = teb->ThreadLocalStoragePointer; + count = (ULONG_PTR)ptr[-2]; + size = HeapSize(GetProcessHeap(), 0, ptr - 2); + ok(size == (count + 2) * sizeof(void *), "got count %lu, size %Iu.\n", count, size); + + for (i = 0; i < count; ++i) + { + if (!ptr[i]) continue; + size = HeapSize(GetProcessHeap(), 0, (void **)ptr[i] - 2); + ok(size && size < 100000, "got %Iu.\n", size); + } + + ptr = thread_teb->ThreadLocalStoragePointer; + count = (ULONG_PTR)ptr[-2]; + size = HeapSize(GetProcessHeap(), 0, ptr - 2); + ok(size == (count + 2) * sizeof(void *), "got count %lu, size %Iu.\n", count, size); + } + ok(!!thread_teb->ThreadLocalStoragePointer, "got NULL.\n"); ok(!teb->TlsLinks.Flink, "got %p.\n", teb->TlsLinks.Flink); ok(!teb->TlsLinks.Blink, "got %p.\n", teb->TlsLinks.Blink); @@ -1852,6 +1968,98 @@ static void test_hash_links(void) } } +#define check_dll_path(a, b) check_dll_path_( __LINE__, a, b ) +static void check_dll_path_( unsigned int line, HMODULE h, const char *expected ) +{ + char path[MAX_PATH]; + DWORD ret; + + *path = 0; + ret = GetModuleFileNameA( h, path, MAX_PATH); + ok_(__FILE__, line)( ret && ret < MAX_PATH, "Got %lu.\n", ret ); + ok_(__FILE__, line)( !stricmp( path, expected ), "Got %s.\n", debugstr_a(path) ); +} + +static void test_known_dlls_load(void) +{ + static const char apiset_dll[] = "ext-ms-win-base-psapi-l1-1-0.dll"; + char system_path[MAX_PATH], local_path[MAX_PATH]; + static const char dll[] = "psapi.dll"; + HMODULE hlocal, hsystem, hapiset, h; + BOOL ret; + + if (GetModuleHandleA( dll ) || GetModuleHandleA( apiset_dll )) + { + skip( "%s is already loaded, skipping test.\n", dll ); + return; + } + + hapiset = LoadLibraryA( apiset_dll ); + if (!hapiset) + { + win_skip( "%s is not available.\n", apiset_dll ); + return; + } + FreeLibrary( hapiset ); + + GetSystemDirectoryA( system_path, sizeof(system_path) ); + strcat( system_path, "\\" ); + strcat( system_path, dll ); + + GetCurrentDirectoryA( sizeof(local_path), local_path ); + strcat( local_path, "\\" ); + strcat( local_path, dll ); + + /* Known dll is always found in system dir, regardless of its presence in the application dir. */ + ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_USER_DIRS ); + ok( ret, "SetDefaultDllDirectories failed err %lu\n", GetLastError() ); + h = LoadLibraryA( dll ); + ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_DEFAULT_DIRS ); + ok( ret, "SetDefaultDllDirectories failed err %lu\n", GetLastError() ); + ok( !!h, "Got NULL.\n" ); + check_dll_path( h, system_path ); + hapiset = GetModuleHandleA( apiset_dll ); + ok( hapiset == h, "Got %p, %p.\n", hapiset, h ); + FreeLibrary( h ); + + h = LoadLibraryExA( dll, 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); + ok( !!h, "Got NULL.\n" ); + check_dll_path( h, system_path ); + hapiset = GetModuleHandleA( apiset_dll ); + ok( hapiset == h, "Got %p, %p.\n", hapiset, h ); + FreeLibrary( h ); + + /* Put dll to the current directory. */ + create_test_dll( dll ); + + h = LoadLibraryExA( dll, 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); + ok( !!h, "Got NULL.\n" ); + check_dll_path( h, system_path ); + hapiset = GetModuleHandleA( apiset_dll ); + ok( hapiset == h, "Got %p, %p.\n", hapiset, h ); + FreeLibrary( h ); + + /* Local version can still be loaded if dll name contains path. */ + hlocal = LoadLibraryA( local_path ); + ok( !!hlocal, "Got NULL.\n" ); + check_dll_path( hlocal, local_path ); + + /* dll without path will match the loaded one. */ + hsystem = LoadLibraryA( dll ); + ok( hsystem == hlocal, "Got %p, %p.\n", hsystem, hlocal ); + h = GetModuleHandleA( dll ); + ok( h == hlocal, "Got %p, %p.\n", h, hlocal ); + + /* apiset dll won't match the one loaded not from system dir. */ + hapiset = GetModuleHandleA( apiset_dll ); + ok( !hapiset, "Got %p.\n", hapiset ); + + FreeLibrary( hsystem ); + FreeLibrary( hlocal ); + + DeleteFileA( dll ); +} + START_TEST(module) { WCHAR filenameW[MAX_PATH]; @@ -1891,4 +2099,5 @@ START_TEST(module) test_tls_links(); test_base_address_index_tree(); test_hash_links(); + test_known_dlls_load(); } diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 8e168622c17b..3a0307d7597f 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -2933,18 +2933,38 @@ static void test_CompletionPort(void) job = pCreateJobObjectW(NULL, NULL); ok(job != NULL, "CreateJobObject error %lu\n", GetLastError()); - create_process("wait", &pi2); - ret = pAssignProcessToJobObject(job, pi2.hProcess); - ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); + port_info.CompletionKey = job; + port_info.CompletionPort = NULL; + ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); + ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_PARAMETER) /* Before Win8 */, + "got ret %d, error %lu\n", ret, GetLastError()); port = pCreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); ok(port != NULL, "CreateIoCompletionPort error %lu\n", GetLastError()); - port_info.CompletionKey = job; port_info.CompletionPort = port; ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); ok(ret, "SetInformationJobObject error %lu\n", GetLastError()); + ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got ret %d, error %lu\n", ret, GetLastError()); + + port_info.CompletionKey = NULL; + port_info.CompletionPort = NULL; + ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); + ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_PARAMETER) /* Before Win8 */, + "got ret %d, error %lu\n", ret, GetLastError()); + + create_process("wait", &pi2); + ret = pAssignProcessToJobObject(job, pi2.hProcess); + ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); + + port_info.CompletionKey = job; + port_info.CompletionPort = port; + ret = pSetInformationJobObject(job, JobObjectAssociateCompletionPortInformation, &port_info, sizeof(port_info)); + ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_PARAMETER), + "got ret %d, error %lu\n" /* Before Win8 */, ret, GetLastError()); + create_process("wait", &pi); ret = pAssignProcessToJobObject(job, pi.hProcess); @@ -4211,8 +4231,12 @@ static void test_process_info(HANDLE hproc) break; case ProcessCookie: if (is_current) + { ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER /* before win8 */, "for info %lu got %08lx (ret_len %lu)\n", i, status, ret_len); + if (!status) + ok( *(ULONG *)buf, "got 0.\n" ); + } else ok(status == STATUS_INVALID_PARAMETER /* before win8 */ || status == STATUS_ACCESS_DENIED, "for info %lu got %08lx (ret_len %lu)\n", i, status, ret_len); @@ -4792,6 +4816,7 @@ static void test_dead_process(void) static void test_nested_jobs_child(unsigned int index) { + JOBOBJECT_BASIC_ACCOUNTING_INFORMATION job_info; JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info; HANDLE job, job_parent, job_other, port; PROCESS_INFORMATION pi; @@ -4831,6 +4856,15 @@ static void test_nested_jobs_child(unsigned int index) ret = pAssignProcessToJobObject(job, pi.hProcess); ok(ret, "AssignProcessToJobObject error %lu\n", GetLastError()); + ret = pQueryInformationJobObject(NULL, JobObjectBasicAccountingInformation, &job_info, + sizeof(job_info), NULL); + ok(ret, "got error %lu.\n", GetLastError()); + + ret = pQueryInformationJobObject(INVALID_HANDLE_VALUE, JobObjectBasicAccountingInformation, &job_info, + sizeof(job_info), NULL); + ok(!ret, "got ret %d.\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got error %lu.\n", GetLastError()); + out = FALSE; ret = pIsProcessInJob(pi.hProcess, NULL, &out); ok(ret, "IsProcessInJob error %lu\n", GetLastError()); diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 49420e4519f6..5c1fffd666a9 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -58,6 +58,7 @@ static BOOLEAN (WINAPI *pTryAcquireSRWLockShared)(PSRWLOCK); static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG_PTR, SIZE_T *, ULONG, ULONG); static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG); +static NTSTATUS (WINAPI *pNtQuerySystemTime)(LARGE_INTEGER *); static NTSTATUS (WINAPI *pNtWaitForSingleObject)(HANDLE, BOOLEAN, const LARGE_INTEGER *); static NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*); static PSLIST_ENTRY (__fastcall *pRtlInterlockedPushListSList)(PSLIST_HEADER list, PSLIST_ENTRY first, @@ -67,6 +68,10 @@ static PSLIST_ENTRY (WINAPI *pRtlInterlockedPushListSListEx)(PSLIST_HEADER list, static NTSTATUS (WINAPI *pNtQueueApcThread)(HANDLE,PNTAPCFUNC,ULONG_PTR,ULONG_PTR,ULONG_PTR); static NTSTATUS (WINAPI *pNtTestAlert)(void); +BOOL (WINAPI *pInitializeSynchronizationBarrier)(SYNCHRONIZATION_BARRIER *,LONG, LONG); +BOOL (WINAPI *pDeleteSynchronizationBarrier)(SYNCHRONIZATION_BARRIER *); +BOOL (WINAPI *pEnterSynchronizationBarrier)(SYNCHRONIZATION_BARRIER*, DWORD); + #ifdef __i386__ #include "pshpack1.h" @@ -228,8 +233,23 @@ static void test_temporary_objects(void) ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); } +static HANDLE mutex, mutex2, mutices[2]; + +static DWORD WINAPI mutex_thread( void *param ) +{ + DWORD expect = (DWORD)(DWORD_PTR)param; + DWORD ret; + + ret = WaitForSingleObject( mutex, 0 ); + ok(ret == expect, "expected %lu, got %lu\n", expect, ret); + + if (!ret) ReleaseMutex( mutex ); + return 0; +} + static void test_mutex(void) { + HANDLE thread; DWORD wait_ret; BOOL ret; HANDLE hCreated; @@ -269,7 +289,8 @@ static void test_mutex(void) SetLastError(0xdeadbeef); hOpened = OpenMutexA(GENERIC_READ | GENERIC_WRITE, FALSE, "WineTestMutex"); ok(hOpened != NULL, "OpenMutex failed with error %ld\n", GetLastError()); - wait_ret = WaitForSingleObject(hOpened, INFINITE); + wait_ret = WaitForSingleObject(hOpened, 0); +todo_wine_if(getenv("WINEESYNC")) /* XFAIL: validation is not implemented */ ok(wait_ret == WAIT_FAILED, "WaitForSingleObject succeeded\n"); CloseHandle(hOpened); @@ -300,6 +321,7 @@ static void test_mutex(void) SetLastError(0xdeadbeef); ret = ReleaseMutex(hCreated); +todo_wine_if(getenv("WINEESYNC")) /* XFAIL: due to the above */ ok(!ret && (GetLastError() == ERROR_NOT_OWNER), "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %ld\n", GetLastError()); @@ -338,6 +360,85 @@ static void test_mutex(void) CloseHandle(hOpened); CloseHandle(hCreated); + + mutex = CreateMutexA( NULL, FALSE, NULL ); + ok(!!mutex, "got error %lu\n", GetLastError()); + + ret = ReleaseMutex( mutex ); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_NOT_OWNER, "got error %lu\n", GetLastError()); + + for (i = 0; i < 100; i++) + { + ret = WaitForSingleObject( mutex, 0 ); + ok(ret == 0, "got %u\n", ret); + } + + for (i = 0; i < 100; i++) + { + ret = ReleaseMutex( mutex ); + ok(ret, "got error %lu\n", GetLastError()); + } + + ret = ReleaseMutex( mutex ); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_NOT_OWNER, "got error %lu\n", GetLastError()); + + thread = CreateThread( NULL, 0, mutex_thread, (void *)0, 0, NULL ); + ret = WaitForSingleObject( thread, 2000 ); + ok(ret == 0, "wait failed: %u\n", ret); + + WaitForSingleObject( mutex, 0 ); + + thread = CreateThread( NULL, 0, mutex_thread, (void *)WAIT_TIMEOUT, 0, NULL ); + ret = WaitForSingleObject( thread, 2000 ); + ok(ret == 0, "wait failed: %u\n", ret); + + ret = ReleaseMutex( mutex ); + ok(ret, "got error %lu\n", GetLastError()); + + thread = CreateThread( NULL, 0, mutex_thread, (void *)0, 0, NULL ); + ret = WaitForSingleObject( thread, 2000 ); + ok(ret == 0, "wait failed: %u\n", ret); + + mutex2 = CreateMutexA( NULL, TRUE, NULL ); + ok(!!mutex2, "got error %lu\n", GetLastError()); + + ret = ReleaseMutex( mutex2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ReleaseMutex( mutex2 ); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_NOT_OWNER, "got error %lu\n", GetLastError()); + + mutices[0] = mutex; + mutices[1] = mutex2; + + ret = WaitForMultipleObjects( 2, mutices, FALSE, 0 ); + ok(ret == 0, "got %u\n", ret); + + ret = ReleaseMutex( mutex ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ReleaseMutex( mutex2 ); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_NOT_OWNER, "got error %lu\n", GetLastError()); + + ret = WaitForMultipleObjects( 2, mutices, TRUE, 0 ); + ok(ret == 0, "got %u\n", ret); + + ret = ReleaseMutex( mutex ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ReleaseMutex( mutex2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = CloseHandle( mutex ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = CloseHandle( mutex2 ); + ok(ret, "got error %lu\n", GetLastError()); + } static void test_slist(void) @@ -513,12 +614,13 @@ static void test_slist(void) static void test_event(void) { - HANDLE handle, handle2; + HANDLE handle, handle2, handles[2]; SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd; ACL acl; DWORD ret; BOOL val; + int i; /* no sd */ handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event"); @@ -622,11 +724,130 @@ static void test_event(void) ok( ret, "QueryMemoryResourceNotification failed err %lu\n", GetLastError() ); ok( val == FALSE || val == TRUE, "wrong value %u\n", val ); CloseHandle( handle ); + + handle = CreateEventA( NULL, TRUE, FALSE, NULL ); + ok(!!handle, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject( handle, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ret = SetEvent( handle ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = SetEvent( handle ); + ok(ret, "got error %lu\n", GetLastError()); + + for (i = 0; i < 100; i++) + { + ret = WaitForSingleObject( handle, 0 ); + ok(ret == 0, "got %lu\n", ret); + } + + ret = ResetEvent( handle ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ResetEvent( handle ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject( handle, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + handle2 = CreateEventA( NULL, FALSE, TRUE, NULL ); + ok(!!handle2, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ret = SetEvent( handle2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = SetEvent( handle2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ResetEvent( handle2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ResetEvent( handle2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + handles[0] = handle; + handles[1] = handle2; + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + SetEvent( handle ); + SetEvent( handle2 ); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ResetEvent( handle ); + SetEvent( handle2 ); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 1, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + SetEvent( handle ); + SetEvent( handle2 ); + + ret = WaitForMultipleObjects( 2, handles, TRUE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, TRUE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + SetEvent( handle2 ); + ResetEvent( handle ); + + ret = WaitForMultipleObjects( 2, handles, TRUE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == 0, "got %lu\n", ret); + + handles[0] = handle2; + handles[1] = handle; + SetEvent( handle ); + SetEvent( handle2 ); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 1, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 1, "got %lu\n", ret); + + ret = CloseHandle( handle ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = CloseHandle( handle2 ); + ok(ret, "got error %lu\n", GetLastError()); } static void test_semaphore(void) { - HANDLE handle, handle2; + HANDLE handle, handle2, handles[2]; + DWORD ret; + LONG prev; + int i; /* test case sensitivity */ @@ -668,6 +889,99 @@ static void test_semaphore(void) ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); CloseHandle( handle ); + + handle = CreateSemaphoreA( NULL, 0, 5, NULL ); + ok(!!handle, "CreateSemaphore failed: %lu\n", GetLastError()); + + ret = WaitForSingleObject( handle, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ret = ReleaseSemaphore( handle, 1, &prev ); + ok(ret, "got error %lu\n", GetLastError()); + ok(prev == 0, "got prev %ld\n", prev); + + ret = ReleaseSemaphore( handle, 1, &prev ); + ok(ret, "got error %lu\n", GetLastError()); + ok(prev == 1, "got prev %ld\n", prev); + + ret = ReleaseSemaphore( handle, 5, &prev ); + ok(!ret, "got %ld\n", ret); + ok(GetLastError() == ERROR_TOO_MANY_POSTS, "got error %lu\n", GetLastError()); + ok(prev == 1, "got prev %ld\n", prev); + + ret = ReleaseSemaphore( handle, 2, &prev ); + ok(ret, "got error %lu\n", GetLastError()); + ok(prev == 2, "got prev %ld\n", prev); + + ret = ReleaseSemaphore( handle, 1, &prev ); + ok(ret, "got error %lu\n", GetLastError()); + ok(prev == 4, "got prev %ld\n", prev); + + for (i = 0; i < 5; i++) + { + ret = WaitForSingleObject( handle, 0 ); + ok(ret == 0, "got %lu\n", ret); + } + + ret = WaitForSingleObject( handle, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + handle2 = CreateSemaphoreA( NULL, 3, 5, NULL ); + ok(!!handle2, "CreateSemaphore failed: %lu\n", GetLastError()); + + ret = ReleaseSemaphore( handle2, 1, &prev ); + ok(ret, "got error %lu\n", GetLastError()); + ok(prev == 3, "got prev %ld\n", prev); + + for (i = 0; i < 4; i++) + { + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == 0, "got %lu\n", ret); + } + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + handles[0] = handle; + handles[1] = handle2; + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ReleaseSemaphore( handle, 1, NULL ); + ReleaseSemaphore( handle2, 1, NULL ); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 1, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ReleaseSemaphore( handle, 1, NULL ); + ReleaseSemaphore( handle2, 1, NULL ); + + ret = WaitForMultipleObjects( 2, handles, TRUE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ReleaseSemaphore( handle, 1, NULL ); + + ret = WaitForMultipleObjects( 2, handles, TRUE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ret = WaitForSingleObject( handle, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = CloseHandle( handle ); + ok(ret, "got error %lu\n", ret); + + ret = CloseHandle( handle2 ); + ok(ret, "got error %lu\n", ret); } static void test_waitable_timer(void) @@ -1222,11 +1536,15 @@ static HANDLE modify_handle(HANDLE handle, DWORD modify) return ULongToHandle(tmp); } +#define TIMEOUT_INFINITE (((LONGLONG)0x7fffffff) << 32 | 0xffffffff) + static void test_WaitForSingleObject(void) { HANDLE signaled, nonsignaled, invalid; + LARGE_INTEGER ntnow, ntthen; LARGE_INTEGER timeout; NTSTATUS status; + DWORD now, then; DWORD ret; signaled = CreateEventW(NULL, TRUE, TRUE, NULL); @@ -1311,6 +1629,68 @@ static void test_WaitForSingleObject(void) status = pNtWaitForSingleObject(GetCurrentThread(), FALSE, &timeout); ok(status == STATUS_TIMEOUT, "expected STATUS_TIMEOUT, got %08lx\n", status); + ret = WaitForSingleObject( signaled, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForSingleObject( nonsignaled, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + /* test that a timed wait actually does wait */ + now = GetTickCount(); + ret = WaitForSingleObject( nonsignaled, 100 ); + then = GetTickCount(); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + ok(abs((then - now) - 100) < 5, "got %lu ms\n", then - now); + + now = GetTickCount(); + ret = WaitForSingleObject( signaled, 100 ); + then = GetTickCount(); + ok(ret == 0, "got %lu\n", ret); + ok(abs(then - now) < 5, "got %lu ms\n", then - now); + + ret = WaitForSingleObject( signaled, INFINITE ); + ok(ret == 0, "got %lu\n", ret); + + /* test NT timeouts */ + pNtQuerySystemTime( &ntnow ); + timeout.QuadPart = ntnow.QuadPart + 100 * 10000; + status = pNtWaitForSingleObject( nonsignaled, FALSE, &timeout ); + pNtQuerySystemTime( &ntthen ); + ok(status == STATUS_TIMEOUT, "got %#lx\n", status); + ok(abs(((ntthen.QuadPart - ntnow.QuadPart) / 10000) - 100) < 5, "got %s ns\n", + wine_dbgstr_longlong((ntthen.QuadPart - ntnow.QuadPart) * 100)); + + pNtQuerySystemTime( &ntnow ); + timeout.QuadPart = -100 * 10000; + status = pNtWaitForSingleObject( nonsignaled, FALSE, &timeout ); + pNtQuerySystemTime( &ntthen ); + ok(status == STATUS_TIMEOUT, "got %#lx\n", status); + ok(abs(((ntthen.QuadPart - ntnow.QuadPart) / 10000) - 100) < 5, "got %s ns\n", + wine_dbgstr_longlong((ntthen.QuadPart - ntnow.QuadPart) * 100)); + + status = pNtWaitForSingleObject( signaled, FALSE, NULL ); + ok(status == 0, "got %#lx\n", status); + + timeout.QuadPart = TIMEOUT_INFINITE; + status = pNtWaitForSingleObject( signaled, FALSE, &timeout ); + ok(status == 0, "got %#lx\n", status); + + pNtQuerySystemTime( &ntnow ); + timeout.QuadPart = ntnow.QuadPart; + status = pNtWaitForSingleObject( nonsignaled, FALSE, &timeout ); + pNtQuerySystemTime( &ntthen ); + ok(status == STATUS_TIMEOUT, "got %#lx\n", status); + ok(abs((ntthen.QuadPart - ntnow.QuadPart) / 10000) < 5, "got %s ns\n", + wine_dbgstr_longlong((ntthen.QuadPart - ntnow.QuadPart) * 100)); + + pNtQuerySystemTime( &ntnow ); + timeout.QuadPart = ntnow.QuadPart - 100 * 10000; + status = pNtWaitForSingleObject( nonsignaled, FALSE, &timeout ); + pNtQuerySystemTime( &ntthen ); + ok(status == STATUS_TIMEOUT, "got %#lx\n", status); + ok(abs((ntthen.QuadPart - ntnow.QuadPart) / 10000) < 5, "got %s ns\n", + wine_dbgstr_longlong((ntthen.QuadPart - ntnow.QuadPart) * 100)); + CloseHandle(signaled); CloseHandle(nonsignaled); } @@ -2733,17 +3113,17 @@ static void test_apc_deadlock(void) CloseHandle(pi.hProcess); } -static jmp_buf bad_cs_jmpbuf; +static jmp_buf call_exception_jmpbuf; +static DWORD call_exception_number_parameters; +static DWORD call_exception_flags; -static LONG WINAPI bad_cs_handler( EXCEPTION_POINTERS *eptr ) +static LONG WINAPI call_exception_handler( EXCEPTION_POINTERS *eptr ) { EXCEPTION_RECORD *rec = eptr->ExceptionRecord; - ok(!rec->NumberParameters, "got %lu.\n", rec->NumberParameters); - ok(rec->ExceptionFlags == EXCEPTION_NONCONTINUABLE - || rec->ExceptionFlags == (EXCEPTION_NONCONTINUABLE | EXCEPTION_SOFTWARE_ORIGINATE), - "got %#lx.\n", rec->ExceptionFlags); - longjmp(bad_cs_jmpbuf, rec->ExceptionCode); + call_exception_number_parameters = rec->NumberParameters; + call_exception_flags = rec->ExceptionFlags; + longjmp(call_exception_jmpbuf, rec->ExceptionCode); return EXCEPTION_CONTINUE_SEARCH; } @@ -2823,11 +3203,16 @@ static void test_crit_section(void) cs.LockSemaphore = (HANDLE)0xdeadbeef; cs.LockCount = 0; - vectored_handler = AddVectoredExceptionHandler(TRUE, bad_cs_handler); - if (!(exc_code = setjmp(bad_cs_jmpbuf))) + vectored_handler = AddVectoredExceptionHandler(TRUE, call_exception_handler); + if (!(exc_code = setjmp(call_exception_jmpbuf))) EnterCriticalSection(&cs); ok(cs.LockCount, "got %ld.\n", cs.LockCount); ok(exc_code == STATUS_INVALID_HANDLE, "got %#x.\n", exc_code); + ok(!call_exception_number_parameters, "got %lu.\n", call_exception_number_parameters); + ok(call_exception_flags == EXCEPTION_NONCONTINUABLE + || call_exception_flags == (EXCEPTION_NONCONTINUABLE | EXCEPTION_SOFTWARE_ORIGINATE), + "got %#lx.\n", call_exception_flags); + RemoveVectoredExceptionHandler(vectored_handler); cs.LockSemaphore = old; DeleteCriticalSection(&cs); @@ -2904,6 +3289,343 @@ static void test_QueueUserAPC(void) ok(apc_count == 1, "APC count %u\n", apc_count); } +static int zigzag_state, zigzag_count[2], zigzag_stop; + +static DWORD CALLBACK zigzag_event0(void *arg) +{ + HANDLE *events = arg; + + while (!zigzag_stop) + { + WaitForSingleObject(events[0], INFINITE); + ResetEvent(events[0]); + ok(zigzag_state == 0, "got wrong state %d\n", zigzag_state); + zigzag_state++; + SetEvent(events[1]); + zigzag_count[0]++; + } + trace("thread 0 got done\n"); + return 0; +} + +static DWORD CALLBACK zigzag_event1(void *arg) +{ + HANDLE *events = arg; + + while (!zigzag_stop) + { + WaitForSingleObject(events[1], INFINITE); + ResetEvent(events[1]); + ok(zigzag_state == 1, "got wrong state %d\n", zigzag_state); + zigzag_state--; + SetEvent(events[0]); + zigzag_count[1]++; + } + trace("thread 1 got done\n"); + return 0; +} + +static void test_zigzag_event(void) +{ + /* The basic idea is to test SetEvent/Wait back and forth between two + * threads. Each thread clears their own event, sets some common data, + * signals the other's, then waits on their own. We make sure the common + * data is always in the right state. We also print performance data. */ + + HANDLE threads[2], events[2]; + BOOL ret; + + events[0] = CreateEventA(NULL, FALSE, FALSE, NULL); + events[1] = CreateEventA(NULL, FALSE, FALSE, NULL); + + threads[0] = CreateThread(NULL, 0, zigzag_event0, events, 0, NULL); + threads[1] = CreateThread(NULL, 0, zigzag_event1, events, 0, NULL); + + zigzag_state = 0; + zigzag_count[0] = zigzag_count[1] = 0; + zigzag_stop = 0; + + trace("starting zigzag test (events)\n"); + SetEvent(events[0]); + Sleep(2000); + zigzag_stop = 1; + ret = WaitForMultipleObjects(2, threads, FALSE, INFINITE); + trace("%d\n", ret); + ok(ret == 0 || ret == 1, "wait failed: %u\n", ret); + + ok(zigzag_count[0] == zigzag_count[1] || zigzag_count[0] == zigzag_count[1] + 1, + "count did not match: %d != %d\n", zigzag_count[0], zigzag_count[1]); + + /* signal the other thread to finish, if it didn't already + * (in theory they both would at the same time, but there's a slight race on teardown if we get + * thread 1 SetEvent -> thread 0 ResetEvent -> thread 0 Wait -> thread 1 exits */ + zigzag_state = 1-ret; + SetEvent(events[1-ret]); + ret = WaitForSingleObject(threads[1-ret], 1000); + ok(!ret, "wait failed: %u\n", ret); + + trace("count: %d\n", zigzag_count[0]); +} + +struct test_barrier_thread_param +{ + RTL_BARRIER *barrier; + ULONG flags; + LONG thread_count; + BOOL wait_skipped; + volatile LONG *count; + volatile LONG *true_ret_count; +}; + +static DWORD WINAPI test_barrier_thread(void *param) +{ + struct test_barrier_thread_param *p = param; + + InterlockedIncrement( p->count ); + if (pEnterSynchronizationBarrier( p->barrier, p->flags )) + InterlockedIncrement( p->true_ret_count ); + if (!p->wait_skipped) + ok( *p->count == p->thread_count, "got %ld.\n", *p->count ); + return 0; +} + +static DWORD WINAPI test_barrier_delete_thread(void *param) +{ + struct test_barrier_thread_param *p = param; + + pDeleteSynchronizationBarrier( p->barrier ); + if (!(p->flags & SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE)) + { + ok( *p->count == p->thread_count, "got %ld.\n", *p->count ); + } + else + { + /* No wait was performed. */ + ok( *p->count <= p->thread_count, "got %ld.\n", *p->count ); + } + + return 0; +} + +static void test_barrier(void) +{ + static const DWORD test_flags[] = + { + SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE, + 0, + SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY, + }; + static const DWORD valid_flags = SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY | SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY + | SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE; + struct test_barrier_thread_param p, p2; + volatile LONG count, true_ret_count; + HANDLE threads[8], delete_thread; + SYNCHRONIZATION_BARRIER barrier; + void *vectored_handler; + unsigned int i, test; + DWORD flags, ret; + int exc_code; + BOOL bval; + + if (!pInitializeSynchronizationBarrier) + { + win_skip("InitializeSynchronizationBarrier is not available.\n"); + return; + } + + SetLastError( 0xdeadbeef ); + bval = pInitializeSynchronizationBarrier( &barrier, 1, -1 ); + ok( bval == TRUE, "got %#x.\n", bval ); + ok( GetLastError() == 0xdeadbeef, "got %lu.\n", GetLastError() ); + + vectored_handler = AddVectoredExceptionHandler(TRUE, call_exception_handler); + + SetLastError( 0xdeadbeef ); + bval = 0xdeadbeef; + if (!(exc_code = setjmp(call_exception_jmpbuf))) + bval = pInitializeSynchronizationBarrier( NULL, 1, -1 ); + if (exc_code == STATUS_ACCESS_VIOLATION) + { + /* Crashes before Win10 1607; the other behaviour details are also different. */ + RemoveVectoredExceptionHandler(vectored_handler); + win_skip( "Old synchronization barriers implementation, skipping tests.\n" ); + return; + } + ok( !bval && GetLastError() == ERROR_INVALID_PARAMETER, "got bval %d, error %lu.\n", bval, GetLastError() ); + + SetLastError( 0xdeadbeef ); + bval = pInitializeSynchronizationBarrier( &barrier, -2, -1 ); + ok( !bval && GetLastError() == ERROR_INVALID_PARAMETER, "got bval %d, error %lu.\n", bval, GetLastError() ); + + SetLastError( 0xdeadbeef ); + bval = pInitializeSynchronizationBarrier( &barrier, 1, -2 ); + ok( !bval && GetLastError() == ERROR_INVALID_PARAMETER, "got bval %d, error %lu.\n", bval, GetLastError() ); + + SetLastError( 0xdeadbeef ); + bval = pInitializeSynchronizationBarrier( &barrier, 0, -1 ); + ok( !bval && GetLastError() == ERROR_INVALID_PARAMETER, "got bval %d, error %lu.\n", bval, GetLastError() ); + + SetLastError( 0xdeadbeef ); + bval = pInitializeSynchronizationBarrier( &barrier, 1, INT_MAX ); + ok( bval == TRUE, "got %#x.\n", bval ); + ok( GetLastError() == 0xdeadbeef, "got %lu.\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + bval = pInitializeSynchronizationBarrier( &barrier, INT_MAX, 0 ); + ok( bval == TRUE, "got %#x.\n", bval ); + ok( GetLastError() == 0xdeadbeef, "got %lu.\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + bval = pInitializeSynchronizationBarrier( &barrier, 1, INT_MAX ); + ok( bval == TRUE, "got %#x.\n", bval ); + ok( GetLastError() == 0xdeadbeef, "got %lu.\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + bval = pInitializeSynchronizationBarrier( &barrier, 1, -1 ); + ok( bval == TRUE, "got %#x.\n", bval ); + ok( GetLastError() == 0xdeadbeef, "got %lu.\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + bval = pEnterSynchronizationBarrier( &barrier, 0 ); + ok( bval == TRUE, "got %#x.\n", bval ); + ok( GetLastError() == 0xdeadbeef, "got %lu.\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + bval = pEnterSynchronizationBarrier( &barrier, 0 ); + ok( bval == TRUE, "got %#x.\n", bval ); + ok( GetLastError() == 0xdeadbeef, "got %lu.\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + bval = pDeleteSynchronizationBarrier( &barrier ); + ok( bval == TRUE, "got %#x.\n", bval ); + ok( GetLastError() == 0xdeadbeef, "got %lu.\n", GetLastError() ); + + for (i = 0; i < 32; ++i) + { + flags = 1u << i; + + if (!(exc_code = setjmp(call_exception_jmpbuf))) + { + bval = pEnterSynchronizationBarrier( &barrier, flags ); + if (flags & ~valid_flags) + { + ok( 0, "expected exception.\n" ); + } + else + { + ok( bval == TRUE, "got %#x.\n", bval ); + ok( GetLastError() == 0xdeadbeef, "got %lu.\n", GetLastError() ); + } + } + if (flags & ~valid_flags) + ok(exc_code == STATUS_INVALID_PARAMETER, "got %#x.\n", exc_code); + else + ok(!exc_code, "got %#x.\n", exc_code); + } + bval = pEnterSynchronizationBarrier( &barrier, valid_flags ); + ok( bval == TRUE, "got %#x.\n", bval ); + RemoveVectoredExceptionHandler(vectored_handler); + + /* Previously completed barrier. */ + p.barrier = &barrier; + p.flags = 0; + p.thread_count = ARRAY_SIZE(threads) + 1; + p.count = &count; + p.true_ret_count = &true_ret_count; + p.wait_skipped = TRUE; + count = 0; + true_ret_count = 0; + for (i = 0; i < ARRAY_SIZE(threads); ++i) + threads[i] = CreateThread( NULL, 0, test_barrier_thread, &p, 0, NULL ); + InterlockedIncrement( p.count ); + if (pEnterSynchronizationBarrier( p.barrier, p.flags )) + InterlockedIncrement( p.true_ret_count ); + for (i = 0; i < ARRAY_SIZE(threads); ++i) + { + WaitForSingleObject( threads[i], INFINITE ); + CloseHandle( threads[i] ); + } + ok( true_ret_count == p.thread_count, "got %ld.\n", true_ret_count ); + + /* Normal case. */ + bval = pInitializeSynchronizationBarrier( &barrier, p.thread_count, INT_MAX ); + ok( bval == TRUE, "got %#x.\n", bval ); + /* DeleteSynchronizationBarrier doesn't seem to do anything unless there are threads already waiting on the barrier + * without SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE flag (and then it will wait for those to finish). */ + bval = pDeleteSynchronizationBarrier( &barrier ); + ok( bval == TRUE, "got %#x.\n", bval ); + p.flags = 0; + p.wait_skipped = FALSE; + count = 0; + true_ret_count = 0; + for (i = 0; i < ARRAY_SIZE(threads); ++i) + threads[i] = CreateThread( NULL, 0, test_barrier_thread, &p, 0, NULL ); + InterlockedIncrement( p.count ); + if (pEnterSynchronizationBarrier( p.barrier, p.flags )) + InterlockedIncrement( p.true_ret_count ); + /* DeleteSynchronizationBarrier (without SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE flag passed to EnterSynchronizationBarrier) + * will wait for the waiters to be actually woken before returning. Without calling DeleteSynchronizationBarrier or + * when setting SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE flag here the test will randomly fire an exception or hang + * (because InitializeSynchronizationBarrier will break the not yet woken waiters wake up. */ + pDeleteSynchronizationBarrier( &barrier ); + pInitializeSynchronizationBarrier( &barrier, p.thread_count, -1 ); + /* p.count is incremented before barrier wait, check at once. */ + ok( *p.count == p.thread_count, "got %ld.\n", *p.count ); + for (i = 0; i < ARRAY_SIZE(threads); ++i) + { + WaitForSingleObject( threads[i], INFINITE ); + CloseHandle( threads[i] ); + } + /* Only check after all the threads are finished and thus guaranteed to exit EnterSynchronizationBarrier() + * and increment true_ret_count. */ + ok( true_ret_count == 1, "got %ld.\n", true_ret_count ); + + /* Test wait in DeleteSynchronizationBarrier(). */ + for (test = 0; test < ARRAY_SIZE(test_flags); ++test) + { + winetest_push_context( "flags %#lx", test_flags[test] ); + p.thread_count = ARRAY_SIZE(threads); + bval = pInitializeSynchronizationBarrier( &barrier, p.thread_count, -1 ); + ok( bval == TRUE, "got %#x.\n", bval ); + true_ret_count = 0; + p.wait_skipped = FALSE; + count = 0; + true_ret_count = 0; + p.flags = test_flags[test]; + threads[0] = CreateThread( NULL, 0, test_barrier_thread, &p, 0, NULL ); + /* Now try to make sure the thread has entered barrier wait before spawning test_barrier_delete_thread. */ + while (!ReadAcquire( p.count )) + Sleep(1); + Sleep(16); + + delete_thread = CreateThread( NULL, 0, test_barrier_delete_thread, &p, 0, NULL ); + ret = WaitForSingleObject( delete_thread, 100 ); + if (!(p.flags & SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE)) + ok( ret == WAIT_TIMEOUT, "got %#lx.\n", ret ); + else + ok( !ret, "got %#lx.\n", ret ); + + /* If barrier waiters joined without SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE after RtlDeleteBarrier started the + * wait, all the barrier waiting threads and RtlDeleteBarrier will hang forever on Windows for some reason. + * So create the rest of the waiters with the flag. */ + p2 = p; + p2.flags = SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE; + for (i = 1; i < ARRAY_SIZE(threads); ++i) + threads[i] = CreateThread( NULL, 0, test_barrier_thread, &p2, 0, NULL ); + + WaitForSingleObject( delete_thread, INFINITE ); + CloseHandle( delete_thread ); + for (i = 0; i < ARRAY_SIZE(threads); ++i) + { + WaitForSingleObject( threads[i], INFINITE ); + CloseHandle( threads[i] ); + } + ok( *p.count == p.thread_count, "got %ld.\n", *p.count ); + ok( true_ret_count == 1, "got %ld.\n", true_ret_count ); + winetest_pop_context(); + } +} + START_TEST(sync) { char **argv; @@ -2928,8 +3650,12 @@ START_TEST(sync) pReleaseSRWLockShared = (void *)GetProcAddress(hdll, "ReleaseSRWLockShared"); pTryAcquireSRWLockExclusive = (void *)GetProcAddress(hdll, "TryAcquireSRWLockExclusive"); pTryAcquireSRWLockShared = (void *)GetProcAddress(hdll, "TryAcquireSRWLockShared"); + pInitializeSynchronizationBarrier = (void *)GetProcAddress(hdll, "InitializeSynchronizationBarrier"); + pDeleteSynchronizationBarrier = (void *)GetProcAddress(hdll, "DeleteSynchronizationBarrier"); + pEnterSynchronizationBarrier = (void *)GetProcAddress(hdll, "EnterSynchronizationBarrier"); pNtAllocateVirtualMemory = (void *)GetProcAddress(hntdll, "NtAllocateVirtualMemory"); pNtFreeVirtualMemory = (void *)GetProcAddress(hntdll, "NtFreeVirtualMemory"); + pNtQuerySystemTime = (void *)GetProcAddress(hntdll, "NtQuerySystemTime"); pNtWaitForSingleObject = (void *)GetProcAddress(hntdll, "NtWaitForSingleObject"); pNtWaitForMultipleObjects = (void *)GetProcAddress(hntdll, "NtWaitForMultipleObjects"); pRtlInterlockedPushListSList = (void *)GetProcAddress(hntdll, "RtlInterlockedPushListSList"); @@ -2974,5 +3700,7 @@ START_TEST(sync) test_srwlock_example(); test_alertable_wait(); test_apc_deadlock(); + test_zigzag_event(); test_crit_section(); + test_barrier(); } diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c index d7bf445b3452..49dae0f52963 100644 --- a/dlls/kernel32/tests/version.c +++ b/dlls/kernel32/tests/version.c @@ -25,9 +25,12 @@ #include "winternl.h" #include "appmodel.h" +static LONG (WINAPI * pGetPackagePath)(const PACKAGE_ID *, const UINT32, UINT32 *, WCHAR *); +static LONG (WINAPI * pGetPackagesByPackageFamily)(const WCHAR *, UINT32 *, WCHAR **, UINT32 *, WCHAR *); static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); static UINT (WINAPI * pEnumSystemFirmwareTables)(DWORD, void *, DWORD); static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); +static LONG (WINAPI * pPackageFullNameFromId)(const PACKAGE_ID *, UINT32 *, WCHAR *); static LONG (WINAPI * pPackageIdFromFullName)(const WCHAR *, UINT32, UINT32 *, BYTE *); static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, void *, ULONG, ULONG *); static NTSTATUS (WINAPI * pRtlGetVersion)(RTL_OSVERSIONINFOEXW *); @@ -46,9 +49,12 @@ static void init_function_pointers(void) hmod = GetModuleHandleA("kernel32.dll"); + GET_PROC(GetPackagePath); + GET_PROC(GetPackagesByPackageFamily); GET_PROC(GetProductInfo); GET_PROC(EnumSystemFirmwareTables); GET_PROC(GetSystemFirmwareTable); + GET_PROC(PackageFullNameFromId); GET_PROC(PackageIdFromFullName); hmod = GetModuleHandleA("ntdll.dll"); @@ -827,9 +833,11 @@ static void test_PackageIdFromFullName(void) { 0, PROCESSOR_ARCHITECTURE_INTEL, {{.Major = 1, .Minor = 2, .Build = 3, .Revision = 4}}, - (WCHAR *)L"TestPackage", NULL, + (WCHAR *)L"TestPackage", (WCHAR *)L"TestResource", (WCHAR *)L"TestResourceId", (WCHAR *)L"0abcdefghjkme" }; + static const WCHAR test_package_fullname[] = + L"TestPackage_1.2.3.4_x86_TestResourceId_0abcdefghjkme"; UINT32 size, expected_size; PACKAGE_ID test_id; WCHAR fullname[512]; @@ -942,6 +950,22 @@ static void test_PackageIdFromFullName(void) size = sizeof(id_buffer); ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_0abcdefghjkme", 0, &size, id_buffer); ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + + ret = pPackageFullNameFromId(&test_package_id, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + size = sizeof(fullname); + ret = pPackageFullNameFromId(&test_package_id, &size, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + size = 0; + ret = pPackageFullNameFromId(&test_package_id, &size, NULL); + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); + ok(size == lstrlenW(test_package_fullname) + 1, "Got unexpected size %u.\n", size); + + ret = pPackageFullNameFromId(&test_package_id, &size, fullname); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!lstrcmpW(fullname, test_package_fullname), "Got unexpected fullname %s.\n", debugstr_w(fullname)); } #define TEST_VERSION_WIN7 1 @@ -1101,6 +1125,187 @@ static void test_pe_os_version(void) } } + +static void test_package_info(void) +{ + static const WCHAR package_family_msvc140[] = L"Microsoft.VCLibs.140.00_8wekyb3d8bbwe"; + UINT32 count, length, curr_length, size, path_length, total_length; + WCHAR buffer[2048], path[MAX_PATH]; + PACKAGE_ID *id, saved_id; + WCHAR *full_names[32]; + BYTE id_buffer[512]; + DWORD arch, attrib; + BOOL arch_found; + SYSTEM_INFO si; + unsigned int i; + LONG ret; + + if (!pGetPackagesByPackageFamily) + { + win_skip("GetPackagesByPackageFamily not available.\n"); + return; + } + + GetSystemInfo(&si); + arch = si.wProcessorArchitecture; + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_8wekyb3d8bbwe", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_iekyb3d8bbwe", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0xdeadbeef; + length = 0xdeadbeef; + ret = pGetPackagesByPackageFamily(L"Unknown", &count, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == 0xdeadbeef, "Got unexpected count %u.\n", count); + ok(length == 0xdeadbeef, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown", &count, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_8wekyb3d8bbwe_b", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + length = 0; + ret = pGetPackagesByPackageFamily(package_family_msvc140, NULL, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + + count = ARRAY_SIZE(full_names); + length = ARRAY_SIZE(buffer); + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); + ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); + + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, full_names, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); + ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); + + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); + ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); + + length = 0; + ret = pGetPackagePath(NULL, 0, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, NULL); + if (!ret && !count && !length) + { + win_skip("Package VCLibs.140.00 is not installed.\n"); + return; + } + + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); + ok(count >= 1, "Got unexpected count %u.\n", count); + ok(length > 1, "Got unexpected length %u.\n", length); + + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, full_names, &length, buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(count >= 1, "Got unexpected count %u.\n", count); + ok(length > 1, "Got unexpected length %u.\n", length); + + total_length = length; + id = (PACKAGE_ID *)id_buffer; + curr_length = 0; + arch_found = FALSE; + for (i = 0; i < count; ++i) + { + curr_length += lstrlenW(full_names[i]) + 1; + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(full_names[i], 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + + if (id->processorArchitecture == arch) + arch_found = TRUE; + + path_length = 0; + ret = pGetPackagePath(id, 0, &path_length, NULL); + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); + ok(path_length > 1, "Got unexpected path_length %u.\n", path_length); + + length = path_length; + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(length == path_length, "Got unexpected length %u.\n", length); + attrib = GetFileAttributesW(path); + ok(attrib != INVALID_FILE_ATTRIBUTES && attrib & FILE_ATTRIBUTE_DIRECTORY, + "Got unexpected attrib %#x, GetLastError() %u.\n", attrib, GetLastError()); + } + ok(curr_length == total_length, "Got unexpected length %u.\n", length); + ok(arch_found, "Did not find package for current arch.\n"); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(full_names[0], 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + saved_id = *id; + + id->publisherId = NULL; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->name = NULL; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->publisher = NULL; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->processorArchitecture = ~0u; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->name[0] = L'X'; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %u.\n", ret); +} + START_TEST(version) { char **argv; @@ -1128,4 +1333,5 @@ START_TEST(version) test_pe_os_version(); test_SystemFirmwareTable(); test_PackageIdFromFullName(); + test_package_info(); } diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c index cfbfcac09503..41eb79b75af6 100644 --- a/dlls/kernel32/tests/virtual.c +++ b/dlls/kernel32/tests/virtual.c @@ -1735,7 +1735,7 @@ static void test_write_watch(void) MEMORY_BASIC_INFORMATION info; HANDLE readpipe, writepipe, file; OVERLAPPED overlapped, *overlapped2; - void *results[64]; + void *results[2048]; ULONG_PTR count; ULONG i, pagesize; BOOL success; @@ -1775,6 +1775,7 @@ static void test_write_watch(void) SetLastError( 0xdeadbeef ); ret = pGetWriteWatch( 0, GetModuleHandleW(NULL), size, results, &count, &pagesize ); + ok(ret, "failed.\n"); if (ret) { ok( ret == ~0u, "GetWriteWatch succeeded %lu\n", ret ); @@ -1798,6 +1799,7 @@ static void test_write_watch(void) ok( results[0] == base + pagesize, "wrong result %p\n", results[0] ); count = 64; + results[0] = (void *)0xdeadbeef; ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); ok( count == 1, "wrong count %Iu\n", count ); @@ -2207,6 +2209,16 @@ static void test_write_watch(void) base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_NOACCESS ); ok( base != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); + + ret = pResetWriteWatch( base, size ); + ok( !ret, "pResetWriteWatch failed %lu\n", GetLastError() ); + + base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_NOACCESS ); ok( base != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); @@ -2226,20 +2238,160 @@ static void test_write_watch(void) ok( old_prot == PAGE_READWRITE, "wrong old prot %lx\n", old_prot ); count = 64; - ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ret = pGetWriteWatch( /*0*/WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); ok( count == 1, "wrong count %Iu\n", count ); ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] ); + ret = pResetWriteWatch( base, size ); + ret = pResetWriteWatch( base + 6*pagesize, size - 6 * pagesize ); + ok( !ret, "pResetWriteWatch failed %lu\n", GetLastError() ); + + count = 64; + results[0] = (void *)0xdeadbeef; + ret = pGetWriteWatch( /*0*/WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); + ok( results[0] == (void *)0xdeadbeef, "wrong result %p\n", results[0] ); + + ret = VirtualFree( base + pagesize, pagesize, MEM_DECOMMIT ); + ok( ret, "VirtualFree failed %lu\n", GetLastError() ); + + ret = VirtualProtect( base + 2*pagesize, pagesize, PAGE_READWRITE, &old_prot ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); + ok( old_prot == PAGE_NOACCESS, "wrong old prot %lx\n", old_prot ); + + count = 64; + results[0] = (void *)0xdeadbeef; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); + ok( results[0] == (void *)0xdeadbeef, "wrong result %p\n", results[0] ); + + base[2*pagesize + 200] = 3; + count = 64; + results[0] = (void *)0xdeadbeef; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1, "wrong count %Iu\n", count ); + ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] ); + + base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_NOACCESS ); + ok( !!base, "VirtualFree failed %lu\n", GetLastError() ); + + ret = VirtualProtect( base, 6*pagesize, PAGE_READWRITE, &old_prot ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); + ok( old_prot == PAGE_NOACCESS, "wrong old prot %lx\n", old_prot ); + + base[3*pagesize + 200] = 3; + base[5*pagesize + 200] = 3; + ret = VirtualFree( base, size, MEM_DECOMMIT ); ok( ret, "VirtualFree failed %lu\n", GetLastError() ); count = 64; ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); - ok( count == 1 || broken(count == 0), /* win98 */ - "wrong count %Iu\n", count ); - if (count) ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] ); + ok( !count, "wrong count %Iu\n", count ); + + base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_READWRITE ); + ok(!!base, "VirtualAlloc failed.\n"); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( !count, "wrong count %Iu\n", count ); + + /* Looks like VirtualProtect latches write watch state somewhere, so if pages are decommitted after, + * (which normally clears write watch state), a page from range which previously had protection change + * is still reported as dirty. */ + base[3*pagesize + 200] = 3; + ret = VirtualProtect( base, 6*pagesize, PAGE_READWRITE, &old_prot ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %lx\n", old_prot ); + + base[5*pagesize + 200] = 3; + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 2, "wrong c ount %Iu\n", count ); + ok( results[0] == base + 3*pagesize && results[1] == base + 5*pagesize, "wrong result %p\n", results[0] ); + + ret = VirtualFree( base, size, MEM_DECOMMIT ); + ok( ret, "VirtualFree failed %lu\n", GetLastError() ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + todo_wine ok( count == 1, "wrong count %Iu\n", count ); + ok( results[0] == base + 3*pagesize, "wrong result %p\n", results[0] ); + + base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_READWRITE ); + ok(!!base, "VirtualAlloc failed.\n"); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + todo_wine ok( count == 1, "wrong count %Iu\n", count ); + ok( results[0] == base + 3*pagesize, "wrong result %p\n", results[0] ); + + base[4*pagesize + 200] = 4; + base[2*pagesize + 200] = 4; + base[6*pagesize + 200] = 4; + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + todo_wine ok( count == 4, "wrong count %Iu\n", count ); + ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] ); + todo_wine ok( results[1] == base + 3*pagesize, "wrong result %p\n", results[0] ); + todo_wine ok( results[2] == base + 4*pagesize, "wrong result %p\n", results[0] ); + todo_wine ok( results[3] == base + 6*pagesize, "wrong result %p\n", results[0] ); + + VirtualFree( base, 0, MEM_RELEASE ); + + /* Test longer range */ + size = 2048 * pagesize; + base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE ); + ok( base != NULL, "VirtualAlloc failed %lu\n", GetLastError() ); + + count = 2048; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); + + count = 2048; + for (i = 0; i < count; i += 2) + ++base[i * pagesize]; + + ret = VirtualProtect( base, size / 2, PAGE_READONLY, &old_prot ); + ok( ret, "VirtualProtect failed error %lu\n", GetLastError() ); + + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1024, "wrong count %Iu\n", count ); + + for (i = 0; i < count; ++i) + { + ok( results[i] == base + i * 2 * pagesize, "wrong result %p\n", results[i] ); + if (results[i] != base + i * 2 * pagesize) + break; + } + + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 1024, "wrong count %Iu\n", count ); + + for (i = 0; i < count; ++i) + { + ok( results[i] == base + i * 2 * pagesize, "wrong result %p\n", results[i] ); + if (results[i] != base + i * 2 * pagesize) + break; + } + + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); + ok( count == 0, "wrong count %Iu\n", count ); VirtualFree( base, 0, MEM_RELEASE ); } diff --git a/dlls/kernel32/tests/volume.c b/dlls/kernel32/tests/volume.c index 24a9a2e7124a..70ab7339c7ad 100644 --- a/dlls/kernel32/tests/volume.c +++ b/dlls/kernel32/tests/volume.c @@ -60,6 +60,7 @@ static BOOL (WINAPI *pGetVolumePathNamesForVolumeNameA)(LPCSTR, LPSTR, DWORD, LP static BOOL (WINAPI *pGetVolumePathNamesForVolumeNameW)(LPCWSTR, LPWSTR, DWORD, LPDWORD); static BOOL (WINAPI *pCreateSymbolicLinkA)(const char *, const char *, DWORD); static BOOL (WINAPI *pGetVolumeInformationByHandleW)(HANDLE, WCHAR *, DWORD, DWORD *, DWORD *, DWORD *, WCHAR *, DWORD); +static HRESULT (WINAPI *pGetDiskSpaceInformationA)(LPCSTR, DISK_SPACE_INFORMATION *); /* ############################### */ @@ -594,6 +595,7 @@ static void test_disk_extents(void) DWORD size; HANDLE handle; static DWORD data[16]; + VOLUME_DISK_EXTENTS *d; handle = CreateFileA( "\\\\.\\c:", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); if (handle == INVALID_HANDLE_VALUE) @@ -610,8 +612,18 @@ static void test_disk_extents(void) CloseHandle( handle ); return; } + size = 0xdeadbeef; + ret = DeviceIoControl( handle, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, data, + sizeof(data), &data, sizeof(*d) - 4, &size, NULL ); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "got ret %d, error %lu.\n", ret, GetLastError()); + ok(size == 0xdeadbeef, "expected 32, got %lu\n", size); + ret = DeviceIoControl( handle, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, data, + sizeof(data), &data, sizeof(*d), &size, NULL ); ok(ret, "DeviceIoControl failed %lu\n", GetLastError()); ok(size == 32, "expected 32, got %lu\n", size); + d = (VOLUME_DISK_EXTENTS *)data; + ok(d->NumberOfDiskExtents == 1, "got %lu.\n", d->NumberOfDiskExtents); + ok(d->Extents[0].ExtentLength.QuadPart > 0, "got %lu.\n", d->NumberOfDiskExtents); CloseHandle( handle ); } @@ -1736,6 +1748,96 @@ static void test_mountmgr_query_points(void) free(output); } +#define check_disk_space_information(a) check_disk_space_information_(__LINE__, a) +static void check_disk_space_information_(unsigned int line, const DISK_SPACE_INFORMATION *info) +{ + ULONGLONG expected; + + expected = info->ActualAvailableAllocationUnits + info->ActualPoolUnavailableAllocationUnits + + info->UsedAllocationUnits + info->TotalReservedAllocationUnits; + ok_(__FILE__,line)(info->ActualTotalAllocationUnits == expected, + "ActualTotalAllocationUnits expected 0x%s, got 0x%s\n", wine_dbgstr_longlong(expected), + wine_dbgstr_longlong(info->ActualTotalAllocationUnits)); + expected = info->ActualTotalAllocationUnits - info->UsedAllocationUnits - info->TotalReservedAllocationUnits; + ok_(__FILE__,line)(info->ActualAvailableAllocationUnits == expected, + "ActualAvailableAllocationUnits expected 0x%s, got 0x%s\n", + wine_dbgstr_longlong(expected), wine_dbgstr_longlong(info->ActualAvailableAllocationUnits)); + ok_(__FILE__,line)(info->ActualPoolUnavailableAllocationUnits == 0, + "ActualPoolUnavailableAllocationUnits expected zero, got 0x%s\n", + wine_dbgstr_longlong(info->ActualPoolUnavailableAllocationUnits)); + expected = info->CallerAvailableAllocationUnits + info->CallerPoolUnavailableAllocationUnits + + info->UsedAllocationUnits + info->TotalReservedAllocationUnits; + ok_(__FILE__,line)(info->CallerTotalAllocationUnits == expected, + "CallerTotalAllocationUnits expected 0x%s, got 0x%s\n", wine_dbgstr_longlong(expected), + wine_dbgstr_longlong(info->CallerTotalAllocationUnits)); + ok_(__FILE__,line)((LONGLONG)info->CallerAvailableAllocationUnits > 0, + "CallerAvailableAllocationUnits expected positive, got 0x%s\n", + wine_dbgstr_longlong(info->CallerAvailableAllocationUnits)); + ok_(__FILE__,line)(info->CallerPoolUnavailableAllocationUnits == 0, + "CallerPoolUnavailableAllocationUnits expected zero, got 0x%s\n", + wine_dbgstr_longlong(info->CallerPoolUnavailableAllocationUnits)); + ok_(__FILE__,line)((LONGLONG)info->UsedAllocationUnits > 0, "UsedAllocationUnits expected positive, got 0x%s\n", + wine_dbgstr_longlong(info->UsedAllocationUnits)); + ok_(__FILE__,line)((LONGLONG)info->TotalReservedAllocationUnits >= 0, + "TotalReservedAllocationUnits expected >= 0, got 0x%s\n", + wine_dbgstr_longlong(info->TotalReservedAllocationUnits)); + ok_(__FILE__,line)(info->VolumeStorageReserveAllocationUnits <= info->TotalReservedAllocationUnits, + "VolumeStorageReserveAllocationUnits expected <= 0x%s, got 0x%s\n", + wine_dbgstr_longlong(info->TotalReservedAllocationUnits), + wine_dbgstr_longlong(info->VolumeStorageReserveAllocationUnits)); + ok_(__FILE__,line)(info->AvailableCommittedAllocationUnits == 0 + /* in win10 can be (0 - UsedAllocationUnits - TotalReservedAllocationUnits) */ + || broken((LONGLONG)info->AvailableCommittedAllocationUnits < 0), + "AvailableCommittedAllocationUnits expected zero, got 0x%s\n", + wine_dbgstr_longlong(info->AvailableCommittedAllocationUnits)); + ok_(__FILE__,line)(info->PoolAvailableAllocationUnits == 0, + "PoolAvailableAllocationUnits expected zero, got 0x%s\n", + wine_dbgstr_longlong(info->PoolAvailableAllocationUnits)); + + /* Assume file system is NTFS */ + ok_(__FILE__,line)(info->BytesPerSector == 512, "BytesPerSector expected 512, got %ld\n",info->BytesPerSector); + ok_(__FILE__,line)(info->SectorsPerAllocationUnit == 8, "SectorsPerAllocationUnit expected 8, got %ld\n",info->SectorsPerAllocationUnit); +} + +static void test_GetDiskSpaceInformationA(void) +{ + DISK_SPACE_INFORMATION info; + HRESULT hr; + + /* GetDiskSpaceInformation() is supported on Windows 10 build 1809 and later */ + if (!pGetDiskSpaceInformationA) + { + win_skip("GetDiskSpaceInformationA is not present.\n"); + return; + } + + memset(&info,0,sizeof(info)); + + hr = pGetDiskSpaceInformationA("Q:\\", &info); + todo_wine + ok(hr == HRESULT_FROM_NT(ERROR_BAD_NET_RESP | ERROR_SEVERITY_WARNING | ERROR_SEVERITY_INFORMATIONAL), + "unexpected 0x%08lx\n", hr); + + hr = pGetDiskSpaceInformationA("", &info); + ok(hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "unexpected 0x%08lx\n", hr); + + hr = pGetDiskSpaceInformationA(NULL, NULL); + ok(hr == HRESULT_FROM_NT(ERROR_INVALID_DATA | ERROR_SEVERITY_WARNING | ERROR_SEVERITY_INFORMATIONAL), + "unexpected 0x%08lx\n", hr); + + hr = pGetDiskSpaceInformationA(NULL, &info); + ok(hr == S_OK, "failed 0x%08lx\n", hr); + check_disk_space_information(&info); + + hr = pGetDiskSpaceInformationA("C:\\", &info); + ok(hr == S_OK, "failed 0x%08lx\n", hr); + check_disk_space_information(&info); + + hr = pGetDiskSpaceInformationA("\\\\?\\C:\\", &info); + ok(hr == S_OK, "failed 0x%08lx\n", hr); + check_disk_space_information(&info); +} + START_TEST(volume) { hdll = GetModuleHandleA("kernel32.dll"); @@ -1748,6 +1850,7 @@ START_TEST(volume) pGetVolumePathNamesForVolumeNameW = (void *) GetProcAddress(hdll, "GetVolumePathNamesForVolumeNameW"); pCreateSymbolicLinkA = (void *) GetProcAddress(hdll, "CreateSymbolicLinkA"); pGetVolumeInformationByHandleW = (void *) GetProcAddress(hdll, "GetVolumeInformationByHandleW"); + pGetDiskSpaceInformationA = (void *) GetProcAddress(hdll, "GetDiskSpaceInformationA"); test_query_dos_deviceA(); test_dos_devices(); @@ -1768,4 +1871,5 @@ START_TEST(volume) test_mounted_folder(); test_GetVolumeInformationByHandle(); test_mountmgr_query_points(); + test_GetDiskSpaceInformationA(); } diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c index 7f1a3f5b2fbd..2ecc3bb5ed84 100644 --- a/dlls/kernel32/thread.c +++ b/dlls/kernel32/thread.c @@ -55,6 +55,15 @@ __ASM_FASTCALL_FUNC( BaseThreadInitThunk, 12, "call *%edx\n\t" "movl %eax,(%esp)\n\t" "call " __ASM_STDCALL( "RtlExitUserThread", 4 )) +#elif defined(__x86_64__) && defined(__WINE_PE_BUILD) && !defined(__arm64ec__) +__ASM_GLOBAL_FUNC( BaseThreadInitThunk, + "subq $0x28,%rsp\n\t" + ".seh_stackalloc 0x28\n\t" + ".seh_endprologue\n\t" + "movq %r8,%rcx\n\t" + "call *%rdx\n\t" + "movl %eax,%ecx\n\t" + "call " __ASM_NAME( "RtlExitUserThread" )) #else void __fastcall BaseThreadInitThunk( DWORD unknown, LPTHREAD_START_ROUTINE entry, void *arg ) { diff --git a/dlls/kernel32/version.rc b/dlls/kernel32/version.rc index f91262dfa8ee..b4630e40032c 100644 --- a/dlls/kernel32/version.rc +++ b/dlls/kernel32/version.rc @@ -26,9 +26,9 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT #define WINE_FILENAME_STR "kernel32.dll" /* these values come from Windows 10 Version 2009 */ -#define WINE_FILEVERSION 10,0,19043,1466 -#define WINE_FILEVERSION_STR "10.0.19043.1466" -#define WINE_PRODUCTVERSION 10,0,19043,1466 -#define WINE_PRODUCTVERSION_STR "10.0.19043.1466" +#define WINE_FILEVERSION 10,0,19045,5796 +#define WINE_FILEVERSION_STR "10.0.19045.5796" +#define WINE_PRODUCTVERSION 10,0,19045,5796 +#define WINE_PRODUCTVERSION_STR "10.0.19045.5796" #include "wine/wine_common_ver.rc" diff --git a/dlls/kernel32/virtual.c b/dlls/kernel32/virtual.c index 0314b362e86c..59332e30f725 100644 --- a/dlls/kernel32/virtual.c +++ b/dlls/kernel32/virtual.c @@ -35,6 +35,7 @@ #include "psapi.h" #include "wine/exception.h" #include "wine/debug.h" +#include "wine/asm.h" #include "kernel_private.h" @@ -293,7 +294,8 @@ LPWSTR WINAPI lstrcatW( LPWSTR dst, LPCWSTR src ) * lstrcpyA (KERNEL32.@) * lstrcpy (KERNEL32.@) */ -LPSTR WINAPI lstrcpyA( LPSTR dst, LPCSTR src ) +#if defined(__x86_64__) && !defined(__arm64ec__) +LPSTR WINAPI lstrcpyA_impl( LPSTR dst, LPCSTR src ) { __TRY { @@ -309,6 +311,42 @@ LPSTR WINAPI lstrcpyA( LPSTR dst, LPCSTR src ) return dst; } +__ASM_GLOBAL_FUNC( lstrcpyA, + ".byte 0x48, 0x8d, 0xa4, 0x24, 0x00, 0x00, 0x00, 0x00\n\t" + "pushq %rbp\n\t" + __ASM_SEH(".seh_pushreg %rbp\n\t") + __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") + __ASM_CFI(".cfi_rel_offset %rbp,0\n\t") + "movq %rsp,%rbp\n\t" + __ASM_SEH(".seh_setframe %rbp,0\n\t") + __ASM_CFI(".cfi_def_cfa_register %rbp\n\t") + __ASM_SEH(".seh_endprologue\n\t") + "subq $0x20,%rsp\n\t" + "andq $~15,%rsp\n\t" + "call " __ASM_NAME("lstrcpyA_impl") "\n\t" + "leaq 0(%rbp),%rsp\n\t" + __ASM_CFI(".cfi_def_cfa_register %rsp\n\t") + "popq %rbp\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") + __ASM_CFI(".cfi_same_value %rbp\n\t") + "ret" ) +#else /* defined(__x86_64__) && !defined(__arm64ec__) */ +LPSTR WINAPI lstrcpyA( LPSTR dst, LPCSTR src ) +{ + __TRY + { + /* this is how Windows does it */ + memmove( dst, src, strlen(src)+1 ); + } + __EXCEPT( badptr_handler ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return NULL; + } + __ENDTRY + return dst; +} +#endif /*********************************************************************** * lstrcpyW (KERNEL32.@) diff --git a/dlls/kernelbase/console.c b/dlls/kernelbase/console.c index 97c5462c42fb..84ae027b1177 100644 --- a/dlls/kernelbase/console.c +++ b/dlls/kernelbase/console.c @@ -1068,6 +1068,14 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleScreenBufferInfoEx( HANDLE handle, } +BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleSelectionInfo(CONSOLE_SELECTION_INFO *info) +{ + FIXME("stub (%p)\n", info); + info->dwFlags = CONSOLE_NO_SELECTION; + return TRUE; +} + + /****************************************************************************** * GetConsoleTitleA (kernelbase.@) */ diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index cbefc0c87334..30b04285823c 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -181,6 +181,7 @@ static LONG WINAPI debug_exception_handler( EXCEPTION_POINTERS *eptr ) */ void WINAPI DECLSPEC_HOTPATCH OutputDebugStringA( LPCSTR str ) { + DWORD last_error = GetLastError(); static HANDLE DBWinMutex = NULL; static BOOL mutex_inited = FALSE; BOOL caught_by_dbg = TRUE; @@ -263,6 +264,7 @@ void WINAPI DECLSPEC_HOTPATCH OutputDebugStringA( LPCSTR str ) CloseHandle( mapping ); } } + SetLastError( last_error ); } static LONG WINAPI debug_exception_handler_wide( EXCEPTION_POINTERS *eptr ) @@ -627,7 +629,7 @@ static BOOL start_debugger( EXCEPTION_POINTERS *epointers, HANDLE event ) startup.cb = sizeof(startup); startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = SW_SHOWNORMAL; - ret = CreateProcessW( NULL, cmdline, NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, env, NULL, &startup, &info ); + ret = CreateProcessW( NULL, cmdline, NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW, env, NULL, &startup, &info ); FreeEnvironmentStringsW( env ); if (ret) @@ -662,6 +664,8 @@ static BOOL start_debugger_atomic( EXCEPTION_POINTERS *epointers ) { static HANDLE once; + if (!ERR_ON(seh)) return FALSE; + if (once == 0) { OBJECT_ATTRIBUTES attr; @@ -735,6 +739,7 @@ static BOOL check_resource_write( void *addr ) LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS *epointers ) { const EXCEPTION_RECORD *rec = epointers->ExceptionRecord; + BOOL nested; if (rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && rec->NumberParameters >= 2) { @@ -755,7 +760,8 @@ LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS *epointers ) TerminateProcess( GetCurrentProcess(), 1 ); } - if (top_filter) + nested = rec->ExceptionFlags & EXCEPTION_NESTED_CALL; + if (top_filter && !nested) { LONG ret = top_filter( epointers ); if (ret != EXCEPTION_CONTINUE_SEARCH) return ret; @@ -763,7 +769,7 @@ LONG WINAPI UnhandledExceptionFilter( EXCEPTION_POINTERS *epointers ) if ((GetErrorMode() & SEM_NOGPFAULTERRORBOX) || !start_debugger_atomic( epointers ) || !NtCurrentTeb()->Peb->BeingDebugged) - return EXCEPTION_EXECUTE_HANDLER; + return nested ? EXCEPTION_CONTINUE_SEARCH : EXCEPTION_EXECUTE_HANDLER; } return EXCEPTION_CONTINUE_SEARCH; } @@ -779,6 +785,16 @@ HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerGetFlags( HANDLE process, DWORD *flags } +/*********************************************************************** + * WerRegisterCustomMetadata (kernelbase.@) + */ +HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerRegisterCustomMetadata( const WCHAR *key, const WCHAR *value ) +{ + FIXME( "(%s, %s) stub\n", debugstr_w(key), debugstr_w(value) ); + return S_OK; +} + + /*********************************************************************** * WerRegisterFile (kernelbase.@) */ @@ -820,6 +836,16 @@ HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerSetFlags( DWORD flags ) } +/*********************************************************************** + * WerUnregisterCustomMetadata (kernelbase.@) + */ +HRESULT WINAPI /* DECLSPEC_HOTPATCH */ WerUnregisterCustomMetadata( const WCHAR *key ) +{ + FIXME( "(%s) stub\n", debugstr_w(key)); + return S_OK; +} + + /*********************************************************************** * WerUnregisterFile (kernelbase.@) */ @@ -1446,6 +1472,29 @@ DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameExA( HANDLE process, HMODULE mod } +static NTSTATUS get_process_image_file_name( HANDLE process, BYTE *buffer, size_t buffer_size, + void **dynamic_buffer, UNICODE_STRING **result ) +{ + NTSTATUS status; + DWORD needed; + + /* FIXME: Use ProcessImageFileName for the PROCESS_NAME_NATIVE case */ + status = NtQueryInformationProcess( process, ProcessImageFileNameWin32, buffer, + sizeof(buffer) - sizeof(WCHAR), &needed ); + if (status == STATUS_INFO_LENGTH_MISMATCH) + { + *dynamic_buffer = HeapAlloc( GetProcessHeap(), 0, needed + sizeof(WCHAR) ); + status = NtQueryInformationProcess( process, ProcessImageFileNameWin32, *dynamic_buffer, + needed, &needed ); + if (status) HeapFree( GetProcessHeap(), 0, *dynamic_buffer ); + *result = *dynamic_buffer; + } + else + *result = (UNICODE_STRING *)buffer; + return status; +} + + /*********************************************************************** * GetModuleFileNameExW (kernelbase.@) * K32GetModuleFileNameExW (kernelbase.@) @@ -1458,29 +1507,47 @@ DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameExW( HANDLE process, HMODULE mod if (!size) return 0; - if (!IsWow64Process( process, &wow64 )) return 0; - - if (is_win64 && wow64) + if (module) { - LDR_DATA_TABLE_ENTRY32 ldr_module32; + if (!IsWow64Process( process, &wow64 )) return 0; - if (get_ldr_module32( process, module, &ldr_module32 )) + if (is_win64 && wow64) { - len = ldr_module32.FullDllName.Length / sizeof(WCHAR); - if (ReadProcessMemory( process, (void *)(DWORD_PTR)ldr_module32.FullDllName.Buffer, - name, min( len, size ) * sizeof(WCHAR), NULL )) - found = TRUE; + LDR_DATA_TABLE_ENTRY32 ldr_module32; + + if (get_ldr_module32( process, module, &ldr_module32 )) + { + len = ldr_module32.FullDllName.Length / sizeof(WCHAR); + if (ReadProcessMemory( process, (void *)(DWORD_PTR)ldr_module32.FullDllName.Buffer, + name, min( len, size ) * sizeof(WCHAR), NULL )) + found = TRUE; + } + } + if (!found) + { + LDR_DATA_TABLE_ENTRY ldr_module; + + if (!get_ldr_module(process, module, &ldr_module)) return 0; + len = ldr_module.FullDllName.Length / sizeof(WCHAR); + if (!ReadProcessMemory( process, ldr_module.FullDllName.Buffer, + name, min( len, size ) * sizeof(WCHAR), NULL )) + return 0; } } - if (!found) + else { - LDR_DATA_TABLE_ENTRY ldr_module; + BYTE buffer[sizeof(UNICODE_STRING) + MAX_PATH*sizeof(WCHAR)]; /* this buffer should be enough */ + void *dynamic_buffer = NULL; + UNICODE_STRING *result; + NTSTATUS status; - if (!get_ldr_module(process, module, &ldr_module)) return 0; - len = ldr_module.FullDllName.Length / sizeof(WCHAR); - if (!ReadProcessMemory( process, ldr_module.FullDllName.Buffer, - name, min( len, size ) * sizeof(WCHAR), NULL )) - return 0; + status = get_process_image_file_name( process, buffer, sizeof(buffer), &dynamic_buffer, &result ); + if (set_ntstatus( status )) + { + len = result->Length / sizeof(WCHAR); + memcpy( name, result->Buffer, min( len, size - 1 ) * sizeof(WCHAR) ); + HeapFree( GetProcessHeap(), 0, dynamic_buffer ); + } } if (len < size) @@ -1691,7 +1758,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetWsChangesEx( HANDLE process, PSAPI_WS_WATCH_INF BOOL WINAPI /* DECLSPEC_HOTPATCH */ InitializeProcessForWsWatch( HANDLE process ) { FIXME( "(process=%p): stub\n", process ); - return TRUE; + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; } @@ -1744,25 +1812,12 @@ BOOL WINAPI DECLSPEC_HOTPATCH QueryFullProcessImageNameW( HANDLE process, DWORD WCHAR *name, DWORD *size ) { BYTE buffer[sizeof(UNICODE_STRING) + MAX_PATH*sizeof(WCHAR)]; /* this buffer should be enough */ - UNICODE_STRING *dynamic_buffer = NULL; - UNICODE_STRING *result = NULL; + void *dynamic_buffer = NULL; + UNICODE_STRING *result; NTSTATUS status; - DWORD needed; - - /* FIXME: Use ProcessImageFileName for the PROCESS_NAME_NATIVE case */ - status = NtQueryInformationProcess( process, ProcessImageFileNameWin32, buffer, - sizeof(buffer) - sizeof(WCHAR), &needed ); - if (status == STATUS_INFO_LENGTH_MISMATCH) - { - dynamic_buffer = HeapAlloc( GetProcessHeap(), 0, needed + sizeof(WCHAR) ); - status = NtQueryInformationProcess( process, ProcessImageFileNameWin32, dynamic_buffer, - needed, &needed ); - result = dynamic_buffer; - } - else - result = (UNICODE_STRING *)buffer; - if (status) goto cleanup; + status = get_process_image_file_name( process, buffer, sizeof(buffer), &dynamic_buffer, &result ); + if (status) return set_ntstatus( status ); if (flags & PROCESS_NAME_NATIVE && result->Length > 2 * sizeof(WCHAR)) { diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index f0dedfe3b14f..6287fcd95c3f 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -3254,36 +3254,25 @@ DWORD WINAPI DECLSPEC_HOTPATCH GetFileType( HANDLE file ) */ BOOL WINAPI DECLSPEC_HOTPATCH GetOverlappedResult( HANDLE file, LPOVERLAPPED overlapped, LPDWORD result, BOOL wait ) -{ - return GetOverlappedResultEx( file, overlapped, result, wait ? INFINITE : 0, FALSE ); -} - - -/*********************************************************************** - * GetOverlappedResultEx (kernelbase.@) - */ -BOOL WINAPI DECLSPEC_HOTPATCH GetOverlappedResultEx( HANDLE file, OVERLAPPED *overlapped, - DWORD *result, DWORD timeout, BOOL alertable ) { NTSTATUS status; DWORD ret; - TRACE( "(%p %p %p %lu %d)\n", file, overlapped, result, timeout, alertable ); + TRACE( "(%p %p %p %d)\n", file, overlapped, result, wait ); /* Paired with the write-release in set_async_iosb() in ntdll; see the * latter for details. */ status = ReadAcquire( (LONG *)&overlapped->Internal ); if (status == STATUS_PENDING) { - if (!timeout) + if (!wait) { SetLastError( ERROR_IO_INCOMPLETE ); return FALSE; } - ret = WaitForSingleObjectEx( overlapped->hEvent ? overlapped->hEvent : file, timeout, alertable ); - if (ret == WAIT_FAILED) - return FALSE; - else if (ret) + ret = WaitForSingleObject( overlapped->hEvent ? overlapped->hEvent : file, INFINITE ); + if (ret == WAIT_FAILED) return FALSE; + if (ret) { SetLastError( ret ); return FALSE; @@ -3292,11 +3281,55 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetOverlappedResultEx( HANDLE file, OVERLAPPED *ov /* We don't need to give this load acquire semantics; the wait above * already guarantees that the IOSB and output buffer are filled. */ status = overlapped->Internal; - if (status == STATUS_PENDING) status = STATUS_SUCCESS; } *result = overlapped->InternalHigh; - return set_ntstatus( status ); + SetLastError( RtlNtStatusToDosError( status )); + return !status || status == STATUS_PENDING; +} + + +/*********************************************************************** + * GetOverlappedResultEx (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH GetOverlappedResultEx( HANDLE file, OVERLAPPED *overlapped, + DWORD *result, DWORD timeout, BOOL alertable ) +{ + NTSTATUS status = STATUS_PENDING; + BOOL compat_mode; + DWORD ret; + + TRACE( "(%p %p %p %lu %d)\n", file, overlapped, result, timeout, alertable ); + + compat_mode = (ULONG_PTR)file & 1; + if (compat_mode || !timeout) + { + /* Paired with the write-release in set_async_iosb() in ntdll; see the + * latter for details. */ + status = ReadAcquire( (LONG *)&overlapped->Internal ); + } + + if (timeout && status == STATUS_PENDING) + { + ret = WaitForSingleObjectEx( overlapped->hEvent ? overlapped->hEvent : file, timeout, alertable ); + if (ret == WAIT_FAILED) return FALSE; + if (ret && !(compat_mode && ret == WAIT_TIMEOUT)) + { + SetLastError( ret ); + return FALSE; + } + /* We don't need to give this load acquire semantics; the wait above + * already guarantees that the IOSB and output buffer are filled. */ + status = overlapped->Internal; + } + else if (status == STATUS_PENDING) + { + SetLastError( ERROR_IO_INCOMPLETE ); + return FALSE; + } + *result = overlapped->InternalHigh; + SetLastError( RtlNtStatusToDosError( status )); + return !status || status == STATUS_PENDING; } @@ -3864,12 +3897,13 @@ BOOL WINAPI DECLSPEC_HOTPATCH UnlockFile( HANDLE file, DWORD offset_low, DWORD o DWORD count_low, DWORD count_high ) { LARGE_INTEGER count, offset; + IO_STATUS_BLOCK io; count.u.LowPart = count_low; count.u.HighPart = count_high; offset.u.LowPart = offset_low; offset.u.HighPart = offset_high; - return set_ntstatus( NtUnlockFile( file, NULL, &offset, &count, NULL )); + return set_ntstatus( NtUnlockFile( file, &io, &offset, &count, NULL )); } diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 27f45edcedf0..14c4e19cb43f 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -162,8 +162,10 @@ @ stdcall CompareStringW(long long wstr long wstr long) @ stdcall ConnectNamedPipe(long ptr) @ stdcall ContinueDebugEvent(long long long) +@ stdcall ConvertAuxiliaryCounterToPerformanceCounter(int64 ptr ptr) @ stdcall ConvertDefaultLocale(long) @ stdcall ConvertFiberToThread() +@ stdcall ConvertPerformanceCounterToAuxiliaryCounter(int64 ptr ptr) @ stdcall ConvertThreadToFiber(ptr) @ stdcall ConvertThreadToFiberEx(ptr long) @ stdcall ConvertToAutoInheritPrivateObjectSecurity(ptr ptr ptr ptr long ptr) @@ -260,7 +262,7 @@ # @ stub DeleteStateAtomValue # @ stub DeleteStateContainer # @ stub DeleteStateContainerValue -# @ stub DeleteSynchronizationBarrier +@ stdcall DeleteSynchronizationBarrier(ptr) @ stdcall DeleteTimerQueueEx(long long) @ stdcall DeleteTimerQueueTimer(long long long) @ stdcall DeleteVolumeMountPointW(wstr) @@ -293,7 +295,7 @@ @ stdcall EncodeSystemPointer(ptr) ntdll.RtlEncodeSystemPointer # @ stub EnterCriticalPolicySectionInternal @ stdcall EnterCriticalSection(ptr) ntdll.RtlEnterCriticalSection -# @ stub EnterSynchronizationBarrier +@ stdcall EnterSynchronizationBarrier(ptr long) @ stdcall EnumCalendarInfoExEx(ptr wstr long wstr long long) @ stdcall EnumCalendarInfoExW(ptr long long long) @ stdcall EnumCalendarInfoW(ptr long long long) @@ -338,7 +340,7 @@ @ stdcall EventSetInformation(int64 long ptr long) ntdll.EtwEventSetInformation @ stdcall EventUnregister(int64) ntdll.EtwEventUnregister @ stdcall EventWrite(int64 ptr long ptr) ntdll.EtwEventWrite -# @ stub EventWriteEx +@ stdcall EventWriteEx(int64 ptr int64 long ptr ptr long ptr) ntdll.EtwEventWriteEx @ stdcall EventWriteString(int64 long int64 ptr) ntdll.EtwEventWriteString @ stdcall EventWriteTransfer(int64 ptr ptr ptr long ptr) ntdll.EtwEventWriteTransfer @ stdcall ExitProcess(long) ntdll.RtlExitUserProcess @@ -472,6 +474,7 @@ @ stdcall GetConsoleProcessList(ptr long) @ stdcall GetConsoleScreenBufferInfo(long ptr) @ stdcall GetConsoleScreenBufferInfoEx(long ptr) +@ stdcall GetConsoleSelectionInfo(ptr) @ stdcall GetConsoleTitleA(ptr long) @ stdcall GetConsoleTitleW(ptr long) @ stdcall GetConsoleWindow() @@ -512,6 +515,8 @@ @ stdcall GetDiskFreeSpaceExA(str ptr ptr ptr) @ stdcall GetDiskFreeSpaceExW(wstr ptr ptr ptr) @ stdcall GetDiskFreeSpaceW(wstr ptr ptr ptr ptr) +@ stdcall GetDiskSpaceInformationA(str ptr) +@ stdcall GetDiskSpaceInformationW(wstr ptr) @ stdcall GetDriveTypeA(str) @ stdcall GetDriveTypeW(wstr) # @ stub GetDurationFormatEx @@ -563,7 +568,7 @@ @ stdcall GetGeoInfoEx(ptr long ptr long) @ stdcall GetHandleInformation(long ptr) # @ stub GetHivePath -# @ stub GetIntegratedDisplaySize +@ stdcall GetIntegratedDisplaySize(ptr) # @ stub GetIsEdpEnabled @ stdcall GetKernelObjectSecurity(long long ptr long ptr) @ stdcall GetLargePageMinimum() @@ -630,7 +635,7 @@ # @ stub GetPackageInfo # @ stub GetPackageInstallTime # @ stub GetPackageOSMaxVersionTested -# @ stub GetPackagePath +@ stdcall GetPackagePath(ptr long ptr ptr) @ stdcall GetPackagePathByFullName(wstr ptr wstr) # @ stub GetPackagePathOnVolume # @ stub GetPackageProperty @@ -845,7 +850,7 @@ @ stdcall InitializeSRWLock(ptr) ntdll.RtlInitializeSRWLock @ stdcall InitializeSecurityDescriptor(ptr long) @ stdcall InitializeSid(ptr ptr long) -# @ stub InitializeSynchronizationBarrier +@ stdcall InitializeSynchronizationBarrier(ptr long long) # @ stub InstallELAMCertificateInfo @ stdcall -arch=i386 InterlockedCompareExchange(ptr long long) @ stdcall -arch=i386 -ret64 InterlockedCompareExchange64(ptr int64 int64) ntdll.RtlInterlockedCompareExchange64 @@ -1045,7 +1050,7 @@ # @ stub PackageFamilyNameFromFullName # @ stub PackageFamilyNameFromId # @ stub PackageFamilyNameFromProductId -# @ stub PackageFullNameFromId +@ stdcall PackageFullNameFromId(ptr ptr ptr) # @ stub PackageFullNameFromProductId @ stdcall PackageIdFromFullName(wstr long ptr ptr) # @ stub PackageIdFromProductId @@ -1749,10 +1754,12 @@ @ stdcall WakeByAddressSingle(ptr) ntdll.RtlWakeAddressSingle @ stdcall WakeConditionVariable(ptr) ntdll.RtlWakeConditionVariable @ stdcall WerGetFlags(ptr ptr) +@ stdcall WerRegisterCustomMetadata(wstr wstr) @ stdcall WerRegisterFile(wstr long long) @ stdcall WerRegisterMemoryBlock(ptr long) @ stdcall WerRegisterRuntimeExceptionModule(wstr ptr) @ stdcall WerSetFlags(long) +@ stdcall WerUnregisterCustomMetadata(wstr) @ stdcall WerUnregisterFile(wstr) @ stdcall WerUnregisterMemoryBlock(ptr) @ stdcall WerUnregisterRuntimeExceptionModule(wstr ptr) diff --git a/dlls/kernelbase/loader.c b/dlls/kernelbase/loader.c index 7afbe0460ebb..f4ccd0269689 100644 --- a/dlls/kernelbase/loader.c +++ b/dlls/kernelbase/loader.c @@ -152,23 +152,33 @@ static BOOL load_library_as_datafile( LPCWSTR load_path, DWORD flags, LPCWSTR na static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags ) { const DWORD unsupported_flags = LOAD_IGNORE_CODE_AUTHZ_LEVEL | LOAD_LIBRARY_REQUIRE_SIGNED_TARGET; + const ULONG load_library_search_flags = LOAD_WITH_ALTERED_SEARCH_PATH | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR + | LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS + | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; NTSTATUS status; HMODULE module; WCHAR *load_path, *dummy; + DWORD load_flags = 0, search_flags; + + TRACE("%s %#lx.\n", libname ? debugstr_w(libname->Buffer) : "", flags); if (flags & unsupported_flags) FIXME( "unsupported flag(s) used %#08lx\n", flags ); - if (!set_ntstatus( LdrGetDllPath( libname->Buffer, flags, &load_path, &dummy ))) return 0; + search_flags = flags & load_library_search_flags; + if (flags & DONT_RESOLVE_DLL_REFERENCES) + load_flags |= LDR_DONT_RESOLVE_REFS; if (flags & (LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE)) { + if (!set_ntstatus( LdrGetDllPath( libname->Buffer, flags, &load_path, &dummy ))) return 0; if (LdrGetDllHandleEx( 0, load_path, NULL, libname, &module )) load_library_as_datafile( load_path, flags, libname->Buffer, &module ); + RtlReleasePath( load_path ); } else { - status = LdrLoadDll( load_path, flags, libname, &module ); + status = LdrLoadDll( (void *)((ULONG_PTR)search_flags | 1), &load_flags, libname, &module ); if (!set_ntstatus( status )) { module = 0; @@ -176,8 +186,6 @@ static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags ) SetLastError( ERROR_DLL_NOT_FOUND ); } } - - RtlReleasePath( load_path ); return module; } @@ -301,7 +309,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameW( HMODULE module, LPWSTR filena UNICODE_STRING name; NTSTATUS status; - if (!module && ((win16_tib = NtCurrentTeb()->Tib.SubSystemTib)) && win16_tib->exe_name) + if (!module && (0 && (win16_tib = NtCurrentTeb()->Tib.SubSystemTib)) && win16_tib->exe_name) { len = min( size, win16_tib->exe_name->Length / sizeof(WCHAR) ); memcpy( filename, win16_tib->exe_name->Buffer, len * sizeof(WCHAR) ); @@ -533,9 +541,16 @@ HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryW( LPCWSTR name ) HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExA( LPCSTR name, HANDLE file, DWORD flags ) { WCHAR *nameW; + HMODULE module; + + /* A new allocation is necessary due to TP Shell Service + * calling LoadLibraryExA from an LdrLoadDll hook */ + if (!(nameW = file_name_AtoW( name, TRUE ))) return 0; + + module = LoadLibraryExW( nameW, file, flags ); - if (!(nameW = file_name_AtoW( name, FALSE ))) return 0; - return LoadLibraryExW( nameW, file, flags ); + HeapFree( GetProcessHeap(), 0, nameW ); + return module; } @@ -552,8 +567,16 @@ HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExW( LPCWSTR name, HANDLE file, DWOR SetLastError( ERROR_INVALID_PARAMETER ); return 0; } + + /* HACK: allow webservices.dll to be shipped together with remote debugger tools. */ + if (flags == LOAD_LIBRARY_SEARCH_SYSTEM32 && !file && !wcscmp( name, L"webservices.dll" )) + { + FIXME( "HACK: ignoring LOAD_LIBRARY_SEARCH_SYSTEM32 for webservices.dll\n" ); + flags = 0; + } + RtlInitUnicodeString( &str, name ); - if (str.Buffer[str.Length/sizeof(WCHAR) - 1] != ' ') return load_library( &str, flags ); + if (str.Length && str.Buffer[str.Length/sizeof(WCHAR) - 1] != ' ') return load_library( &str, flags ); /* library name has trailing spaces */ RtlCreateUnicodeString( &str, name ); diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c index 60173ba65130..fe834c6188dd 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -570,3 +570,9 @@ HRESULT WINAPI GetAcceptLanguagesW(WCHAR *langbuf, DWORD *buflen) *buflen = 0; return E_NOT_SUFFICIENT_BUFFER; } + +HRESULT WINAPI GetIntegratedDisplaySize( double *sz_inches ) +{ + FIXME( "%p stub.\n", sz_inches ); + return E_NOTIMPL; +} diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 0be178f6ab76..e102345119ab 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -121,11 +121,17 @@ BOOL WINAPI DECLSPEC_HOTPATCH FlushViewOfFile( const void *base, SIZE_T size ) return set_ntstatus( status ); } - /**************************************************************************** * FlushInstructionCache (kernelbase.@) */ +#if defined(__i386__) || defined(__x86_64__) BOOL WINAPI DECLSPEC_HOTPATCH FlushInstructionCache( HANDLE process, LPCVOID addr, SIZE_T size ) +{ + /* X86 processors have coherent instruction and data caches, no need to do anything */ + return TRUE; +} +#else +static BOOL flush_instruction_cache( HANDLE process, LPCVOID addr, SIZE_T size ) { CROSS_PROCESS_WORK_LIST *list; @@ -137,6 +143,28 @@ BOOL WINAPI DECLSPEC_HOTPATCH FlushInstructionCache( HANDLE process, LPCVOID add return set_ntstatus( NtFlushInstructionCache( process, addr, size )); } +#ifdef __arm64ec__ +/* Wrapper that preserves RDX/X0 */ +BOOL WINAPI __attribute__((naked)) FlushInstructionCache( HANDLE process, LPCVOID addr, SIZE_T size ) +{ + asm( ".seh_proc \"#FlushInstructionCache\"\n\t" + "stp x29, x30, [sp, #-32]!\n\t" + "str x1, [sp, #16]\n\t" + ".seh_save_fplr_x 32\n\t" + ".seh_endprologue\n\t" + "bl \"#flush_instruction_cache\"\n\t" + "ldr x1, [sp, #16]\n\t" + "ldp x29, x30, [sp], #32\n\t" + "ret\n\t" + ".seh_endproc" ); +} +#else +BOOL WINAPI DECLSPEC_HOTPATCH FlushInstructionCache( HANDLE process, LPCVOID addr, SIZE_T size ) +{ + return flush_instruction_cache( process, addr, size ); +} +#endif +#endif /*********************************************************************** * GetLargePageMinimum (kernelbase.@) diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c index a737294e6553..eea31159daaa 100644 --- a/dlls/kernelbase/path.c +++ b/dlls/kernelbase/path.c @@ -4733,6 +4733,7 @@ BOOL WINAPI UrlIsA(const char *url, URLIS Urlis) return scheme_is_opaque( base.nScheme ); case URLIS_FILEURL: + if (strlen(url) < 5) return FALSE; return (CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, url, 5, "file:", 5) == CSTR_EQUAL); case URLIS_DIRECTORY: diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index df3447a90149..8a0b7489a3f2 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -26,12 +26,14 @@ #include "windef.h" #include "winbase.h" #include "winnls.h" +#include "winver.h" #include "wincontypes.h" #include "winternl.h" #include "kernelbase.h" #include "wine/debug.h" #include "wine/condrv.h" +#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(process); @@ -502,6 +504,171 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalA( HANDLE token, const char * return ret; } +static char *get_product_name( const WCHAR *app_name ) +{ + WCHAR full_path[MAX_PATH]; + char *product_name, *ret; + DWORD *translation; + char buf[100]; + void *block; + UINT size; + + if (!GetLongPathNameW( app_name, full_path, MAX_PATH )) lstrcpynW( full_path, app_name, MAX_PATH ); + if (!GetFullPathNameW( full_path, MAX_PATH, full_path, NULL )) lstrcpynW( full_path, app_name, MAX_PATH ); + + size = GetFileVersionInfoSizeExW(0, full_path, NULL); + if (!size) + return NULL; + + block = HeapAlloc( GetProcessHeap(), 0, size ); + + if (!GetFileVersionInfoExW(0, full_path, 0, size, block)) + { + HeapFree( GetProcessHeap(), 0, block ); + return NULL; + } + + if (!VerQueryValueA(block, "\\VarFileInfo\\Translation", (void **) &translation, &size) || size != 4) + { + HeapFree( GetProcessHeap(), 0, block ); + return NULL; + } + + sprintf(buf, "\\StringFileInfo\\%08lx\\ProductName", MAKELONG(HIWORD(*translation), LOWORD(*translation))); + + if (!VerQueryValueA(block, buf, (void **) &product_name, &size)) + { + HeapFree( GetProcessHeap(), 0, block ); + return NULL; + } + + + ret = HeapAlloc( GetProcessHeap(), 0, strlen( product_name ) + 1 ); + strcpy( ret, product_name ); + HeapFree( GetProcessHeap(), 0, block ); + return ret; +} + +static int battleye_launcher_redirect_hack( const WCHAR *app_name, WCHAR *new_name, DWORD new_name_len, + WCHAR **orig_app_name, const char *product_name ) +{ + static const WCHAR belauncherW[] = L"c:\\windows\\system32\\belauncher.exe"; + unsigned int len; + + if (GetEnvironmentVariableW(L"PROTON_ORIG_LAUNCHER_NAME", NULL, 0)) + { + /* run from builtin belauncher. */ + return 0; + } + + /* We detect the BattlEye launcher executable through the product name property, as the executable name varies */ + if (!product_name || strcmp( product_name, "BattlEye Launcher" )) + return 0; + + TRACE( "Detected launch of a BattlEye Launcher, redirecting to Proton version.\n" ); + + if (new_name_len < wcslen( belauncherW ) + 1) + { + ERR( "Game executable path doesn't fit in buffer.\n" ); + return 0; + } + + len = (wcslen( app_name ) + 1) * sizeof(*app_name); + if (!(*orig_app_name = HeapAlloc( GetProcessHeap(), 0, len ))) + { + ERR( "No memory.\n" ); + return 0; + } + memcpy( *orig_app_name, app_name, len ); + wcscpy( new_name, belauncherW ); + return 1; +} + +static const WCHAR *hack_append_command_line( const WCHAR *cmd ) +{ + static const struct + { + const WCHAR *exe_name; + const WCHAR *append; + const char *steamgameid; + } + options[] = + { + {L"Click&Fight.exe", L" --disable_direct_composition=1"}, + {L"Willful.exe", L" --disable_direct_composition=1"}, + {L"Banyu Lintar Angin - Little Storm -.exe", L" --disable_direct_composition=1"}, + {L"Super\\Super.exe", L" --disable_direct_composition=1"}, + {L"A Raven Monologue.exe", L" --use-angle=d3d9"}, + {L"antenna\\antenna.exe", L" --use-angle=d3d9"}, + {L"Bloody Walls\\game.exe", L" --disable_direct_composition=1"}, + {L"Insanitys Blade\\nw.exe", L" --use-gl=swiftshader"}, + {L"Warhammer2.exe", L" --in-process-gpu"}, + {L"SummerIslands.exe", L" --in-process-gpu"}, + {L"Paradox Launcher.exe", L" --use-angle=gl"}, + {L"Montaro\\nw.exe", L" --use-gl=swiftshader"}, + {L"Aisling and the Tavern of Elves\\nw.exe", L" --use-gl=swiftshader"}, + {L"Snares of Ruin 2\\SoR2.exe", L" --use-gl=swiftshader"}, + {L"OlympiaRising.exe", L" --use-gl=swiftshader"}, + {L"nw.exe.exe", L" --use-angle=d3d9"}, + {L"DC Universe Online\\LaunchPad.exe", L" --use-gl=swiftshader"}, + {L"PlanetSide 2\\LaunchPad.exe", L" --use-gl=swiftshader"}, + {L"PaladinLias\\Game.exe", L" --use-gl=desktop"}, + {L"EverQuest 2\\LaunchPad.exe", L" --use-gl=swiftshader"}, + {L"Everquest F2P\\LaunchPad.exe", L" --use-gl=swiftshader"}, + {L"Red Tie Runner.exe", L" --use-angle=gl"}, + {L"UnrealCEFSubProcess.exe", L" --use-gl=swiftshader", "2316580"}, + {L"UnrealCEFSubProcess.exe", L" --use-angle=d3d9", "2684500"}, + }; + unsigned int i; + char sgi[64]; + + if (!cmd) return NULL; + + for (i = 0; i < ARRAY_SIZE(options); ++i) + { + if (wcsstr( cmd, options[i].exe_name )) + { + if (options[i].steamgameid && !(GetEnvironmentVariableA( "SteamGameId", sgi, sizeof(sgi) ) + && !strcmp( sgi, options[i].steamgameid ))) + continue; + FIXME( "HACK: appending %s to command line.\n", debugstr_w(options[i].append) ); + return options[i].append; + } + } + return NULL; +} + +static void sync_env_var_to_unix( WCHAR *env, const char *name ) +{ + UNICODE_STRING us_name, us_value; + WCHAR valuew[256]; + WCHAR namew[64]; + char value[256]; + NTSTATUS status; + int len; + + MultiByteToWideChar( CP_ACP, 0, name, -1, namew, ARRAY_SIZE(namew) ); + RtlInitUnicodeString( &us_name, namew ); + us_value.Length = 0; + us_value.MaximumLength = sizeof(valuew) - sizeof(WCHAR); + us_value.Buffer = valuew; + + status = RtlQueryEnvironmentVariable_U( env, &us_name, &us_value ); + if (status && status != STATUS_VARIABLE_NOT_FOUND) + { + ERR( "status %#lx.\n", status ); + return; + } + if (!status) + { + len = us_value.Length / sizeof(WCHAR); + valuew[len] = 0; + WideCharToMultiByte( CP_ACP, 0, valuew, len + 1, value, sizeof(value), NULL, NULL ); + __wine_set_unix_env( name, value ); + TRACE( "set %s to %s.\n", debugstr_a(name), debugstr_a(value) ); + } else __wine_set_unix_env( name, NULL ); +} + /********************************************************************** * CreateProcessInternalW (kernelbase.@) */ @@ -514,17 +681,19 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR { const struct proc_thread_attr *handle_list = NULL, *job_list = NULL; WCHAR name[MAX_PATH]; - WCHAR *p, *tidy_cmdline = cmd_line; + WCHAR *p, *tidy_cmdline = cmd_line, *orig_app_name = NULL; RTL_USER_PROCESS_PARAMETERS *params = NULL; RTL_USER_PROCESS_INFORMATION rtl_info; HANDLE parent = 0, debug = 0; + char *product_name = NULL; + const WCHAR *append; ULONG nt_flags = 0; USHORT machine = 0; NTSTATUS status; /* Process the AppName and/or CmdLine to get module name and path */ - TRACE( "app %s cmdline %s\n", debugstr_w(app_name), debugstr_w(cmd_line) ); + TRACE( "app %s cmdline %s, inherit %d, flags %#lx, env %p (%s)\n", debugstr_w(app_name), debugstr_w(cmd_line), inherit, flags, env, debugstr_w(env) ); if (new_token) FIXME( "No support for returning created process token\n" ); @@ -536,13 +705,46 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR return FALSE; swprintf( tidy_cmdline, lstrlenW(app_name) + 3, L"\"%s\"", app_name ); } + else if ((append = hack_append_command_line( app_name ))) + { + tidy_cmdline = RtlAllocateHeap( GetProcessHeap(), 0, + sizeof(WCHAR) * (lstrlenW(cmd_line) + lstrlenW(append) + 1) ); + lstrcpyW(tidy_cmdline, cmd_line); + lstrcatW(tidy_cmdline, append); + } } else { - if (!(tidy_cmdline = get_file_name( cmd_line, name, ARRAY_SIZE(name) ))) return FALSE; + WCHAR *cmdline_new = NULL; + + if ((append = hack_append_command_line( cmd_line ))) + { + cmdline_new = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(WCHAR) + * (lstrlenW(cmd_line) + lstrlenW(append) + 1) ); + lstrcpyW(cmdline_new, cmd_line); + lstrcatW(cmdline_new, append); + } + + tidy_cmdline = get_file_name( cmdline_new ? cmdline_new : cmd_line, name, ARRAY_SIZE(name) ); + + if (!tidy_cmdline) + { + HeapFree( GetProcessHeap(), 0, cmdline_new ); + return FALSE; + } + + if (cmdline_new) + { + if (cmdline_new == tidy_cmdline) cmd_line = NULL; + else HeapFree( GetProcessHeap(), 0, cmdline_new ); + } app_name = name; } + product_name = get_product_name( app_name ); + if (battleye_launcher_redirect_hack( app_name, name, ARRAY_SIZE(name), &orig_app_name, product_name )) + app_name = name; + /* Warn if unsupported features are used */ if (flags & (IDLE_PRIORITY_CLASS | HIGH_PRIORITY_CLASS | REALTIME_PRIORITY_CLASS | @@ -564,10 +766,53 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR if (!(params = create_process_params( app_name, tidy_cmdline, cur_dir, env, flags, startup_info ))) { + HeapFree( GetProcessHeap(), 0, orig_app_name ); status = STATUS_NO_MEMORY; goto done; } + /* Set PROTON_EAC_LAUNCHER_PROCESS when launching the EAC launcher to let ntdll know to load the native EAC client library. + - We don't do this check in ntdll itself because it's harder to get the product name there + - we don't overwrite WINEDLLOVERRIDES because it's fetched from the unix environment */ + { + UNICODE_STRING name, value; + + WCHAR *new_env = RtlAllocateHeap( GetProcessHeap(), 0, params->EnvironmentSize ); + memcpy(new_env, params->Environment, params->EnvironmentSize); + + RtlDestroyProcessParameters( params ); + + if (product_name && !strcmp( product_name, "Easy Anti-Cheat Bootstrapper (EOS)" )) + { + /* EOS EAC bootstrapper will start the game process directly without using WINAPI, so env vars set on the + * PE side will be lost. Preserve some critical ones. */ + sync_env_var_to_unix( new_env, "UPLAY_ARGUMENTS" ); + sync_env_var_to_unix( new_env, "UPC_GAME_STARTER_RUNNING" ); + } + + RtlInitUnicodeString( &name, L"PROTON_EAC_LAUNCHER_PROCESS" ); + RtlInitUnicodeString( &value, L"1" ); + RtlSetEnvironmentVariable( &new_env, &name, + product_name && !strcmp( product_name, "EasyAntiCheat Launcher" ) ? &value : NULL ); + + if (orig_app_name) + { + RtlInitUnicodeString( &name, L"PROTON_ORIG_LAUNCHER_NAME" ); + RtlInitUnicodeString( &value, orig_app_name ); + RtlSetEnvironmentVariable( &new_env, &name, &value ); + } + + HeapFree( GetProcessHeap(), 0, orig_app_name ); + params = create_process_params( app_name, tidy_cmdline, cur_dir, new_env, flags | CREATE_UNICODE_ENVIRONMENT, startup_info ); + + RtlFreeHeap(GetProcessHeap(), 0, new_env); + if (!params) + { + status = STATUS_NO_MEMORY; + goto done; + } + } + if (flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) { if ((status = DbgUiConnectToDbg())) goto done; @@ -676,6 +921,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR done: RtlDestroyProcessParameters( params ); if (tidy_cmdline != cmd_line) HeapFree( GetProcessHeap(), 0, tidy_cmdline ); + HeapFree( GetProcessHeap(), 0, product_name ); return set_ntstatus( status ); } @@ -1100,6 +1346,21 @@ HANDLE WINAPI DECLSPEC_HOTPATCH OpenProcess( DWORD access, BOOL inherit, DWORD i attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; + /* PROTON HACK: + * On Windows, the Steam client puts its process ID into the registry + * at: + * + * [HKCU\Software\Valve\Steam\ActiveProcess] + * PID=dword:00000008 + * + * Games get that pid from the registry and then query it with + * OpenProcess to ensure Steam is running. Since we aren't running the + * Windows Steam in Wine, instead we hack this magic number into the + * registry and then substitute the game's process itself in its place + * so it can query a valid process. + */ + if (id == 0xfffe) id = GetCurrentProcessId(); + cid.UniqueProcess = ULongToHandle(id); cid.UniqueThread = 0; @@ -1531,6 +1792,59 @@ LPSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsA(void) return ret; } +static void hack_shrink_environment( WCHAR *env, SIZE_T len ) +{ + static int enabled = -1; + static const char *skip[] = + { + "SteamGenericControllers=", + "STEAM_RUNTIME_LIBRARY_PATH=", + "SDL_GAMECONTROLLER_IGNORE_DEVICES=", + "SDL_GAMECONTROLLERCONFIG=", + "LD_LIBRARY_PATH=", + "ORIG_LD_LIBRARY_PATH=", + "LS_COLORS=", + "BASH_FUNC_", + "XDG_DATA_DIRS=", + }; + SIZE_T l; + unsigned int i, j; + + if (enabled == -1) + { + WCHAR str[40]; + + *str = 0; + if (GetEnvironmentVariableW( L"WINE_SHRINK_ENV", str, sizeof(str)) ) + enabled = *str != '0'; + else if (GetEnvironmentVariableW( L"SteamGameId", str, sizeof(str)) ) + enabled = !wcscmp( str, L"431590" ); + else + enabled = 0; + + if (enabled) + ERR( "HACK: shrinking environment size.\n" ); + } + + if (!enabled) return; + + while (*env) + { + for (i = 0; i < ARRAY_SIZE(skip); ++i) + { + j = 0; + while (skip[i][j] && skip[i][j] == env[j]) + ++j; + if (!skip[i][j]) break; + } + l = lstrlenW( env ); + len -= (l + 1) * sizeof(WCHAR); + if (i == ARRAY_SIZE(skip)) + env += l + 1; + else + memmove( env, env + l + 1, len ); + } +} /*********************************************************************** * GetEnvironmentStringsW (kernelbase.@) @@ -1543,7 +1857,10 @@ LPWSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsW(void) RtlAcquirePebLock(); len = get_env_length( NtCurrentTeb()->Peb->ProcessParameters->Environment ) * sizeof(WCHAR); if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) + { memcpy( ret, NtCurrentTeb()->Peb->ProcessParameters->Environment, len ); + hack_shrink_environment( ret, len ); + } RtlReleasePebLock(); return ret; } diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 6b9041e17b93..7e9c2db72fb0 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -112,20 +112,15 @@ static BOOL is_classes_root( const UNICODE_STRING *name ) return (len >= classes_root_len - 1 && !wcsnicmp( name->Buffer, classes_root, min( len, classes_root_len ) )); } -static BOOL is_classes_wow6432node( HKEY key ) +static KEY_NAME_INFORMATION *get_key_name( HKEY key, char *buffer, DWORD len ) { - char buffer[256], *buf_ptr = buffer; + char *buf_ptr = buffer; KEY_NAME_INFORMATION *info = (KEY_NAME_INFORMATION *)buffer; - DWORD len = sizeof(buffer); - UNICODE_STRING name; NTSTATUS status; - BOOL ret = FALSE; - /* Obtain the name of the root key */ - status = NtQueryKey( key, KeyNameInformation, info, len, &len ); - if (status && status != STATUS_BUFFER_OVERFLOW) return FALSE; + status = NtQueryKey( key, KeyNameInformation, buf_ptr, len, &len ); + if (status && status != STATUS_BUFFER_OVERFLOW) return NULL; - /* Retry with a dynamically allocated buffer */ while (status == STATUS_BUFFER_OVERFLOW) { if (buf_ptr != buffer) heap_free( buf_ptr ); @@ -133,9 +128,22 @@ static BOOL is_classes_wow6432node( HKEY key ) info = (KEY_NAME_INFORMATION *)buf_ptr; status = NtQueryKey( key, KeyNameInformation, info, len, &len ); } + if (!status) return (KEY_NAME_INFORMATION *)buf_ptr; + if (buf_ptr != buffer) heap_free( buf_ptr ); + return NULL; +} + +static BOOL is_classes_wow6432node( HKEY key ) +{ + KEY_NAME_INFORMATION *info; + char buffer[256]; + UNICODE_STRING name; + BOOL ret = FALSE; + + if (!(info = get_key_name( key, buffer, sizeof(buffer) ))) return FALSE; /* Check if the key ends in Wow6432Node and if the root is the Classes key*/ - if (!status && info->NameLength / sizeof(WCHAR) >= 11) + if (info->NameLength / sizeof(WCHAR) >= 11) { name.Buffer = info->Name + info->NameLength / sizeof(WCHAR) - 11; name.Length = 11 * sizeof(WCHAR); @@ -146,9 +154,39 @@ static BOOL is_classes_wow6432node( HKEY key ) ret = is_classes_root( &name ); } } + if ((char *)info != buffer) heap_free( info ); - if (buf_ptr != buffer) heap_free( buf_ptr ); + return ret; +} +static BOOL is_wow6432_shared( HANDLE key ) +{ + static const WCHAR users_root[] = L"\\Registry\\User\\"; + const DWORD users_root_len = ARRAY_SIZE( users_root ) - 1; + static const WCHAR software[] = L"\\Software"; + const DWORD software_len = ARRAY_SIZE( software ) - 1; + KEY_NAME_INFORMATION *info; + char buffer[256]; + BOOL ret = FALSE; + WCHAR *name; + DWORD len; + + info = get_key_name( key, buffer, sizeof(buffer) ); + len = info->NameLength / sizeof(WCHAR); + if (len <= users_root_len) goto done; + name = info->Name; + if (wcsnicmp( name, users_root, users_root_len )) goto done; + name += users_root_len; + len -= users_root_len; + while (len && *name != '\\') + { + ++name; + --len; + } + if (len != software_len) goto done; + ret = !wcsnicmp( name, software, software_len ); +done: + if ((char *)info != buffer) heap_free( info ); return ret; } @@ -166,6 +204,11 @@ static HANDLE open_wow6432node( HANDLE key ) attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED | KEY_WOW64_64KEY, &attr, 0 )) return key; + if (is_wow6432_shared( key )) + { + NtClose( ret ); + return key; + } return ret; } diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c index f03a6c3150a6..d1e82328893b 100644 --- a/dlls/kernelbase/sync.c +++ b/dlls/kernelbase/sync.c @@ -271,6 +271,38 @@ BOOL WINAPI QueryIdleProcessorCycleTimeEx( USHORT group_id, ULONG *size, ULONG64 } +/*********************************************************************** + * ConvertAuxiliaryCounterToPerformanceCounter (kernelbase.@) + */ +HRESULT WINAPI ConvertAuxiliaryCounterToPerformanceCounter( ULONGLONG from, ULONGLONG *to, ULONGLONG *error ) +{ + NTSTATUS status; + + TRACE( "%#I64x, %p, %p.\n", from, to, error ); + + if ((status = NtConvertBetweenAuxiliaryCounterAndPerformanceCounter( 0, &from, to, error )) == STATUS_NOT_SUPPORTED) + return E_NOTIMPL; + + return HRESULT_FROM_NT(status); +} + + +/*********************************************************************** + * ConvertAuxiliaryCounterToPerformanceCounter (kernelbase.@) + */ +HRESULT WINAPI ConvertPerformanceCounterToAuxiliaryCounter( ULONGLONG from, ULONGLONG *to, ULONGLONG *error ) +{ + NTSTATUS status; + + TRACE( "%#I64x, %p, %p.\n", from, to, error ); + + if ((status = NtConvertBetweenAuxiliaryCounterAndPerformanceCounter( 1, &from, to, error )) == STATUS_NOT_SUPPORTED) + return E_NOTIMPL; + + return HRESULT_FROM_NT(status); +} + + /*********************************************************************** * Waits ***********************************************************************/ @@ -310,7 +342,11 @@ DWORD WINAPI DECLSPEC_HOTPATCH SignalObjectAndWait( HANDLE signal, HANDLE wait, DWORD timeout, BOOL alertable ) { NTSTATUS status; +#ifdef __i386__ + DECLSPEC_ALIGN(4) LARGE_INTEGER time; +#else LARGE_INTEGER time; +#endif TRACE( "%p %p %ld %d\n", signal, wait, timeout, alertable ); @@ -723,7 +759,7 @@ HANDLE WINAPI DECLSPEC_HOTPATCH OpenMutexW( DWORD access, BOOL inherit, LPCWSTR { HANDLE ret; UNICODE_STRING nameW; - OBJECT_ATTRIBUTES attr; + DECLSPEC_ALIGN(32) OBJECT_ATTRIBUTES attr; if (!is_version_nt()) access = MUTEX_ALL_ACCESS; @@ -1763,3 +1799,50 @@ __ASM_STDCALL_FUNC(InterlockedDecrement, 4, "ret $4") #endif /* __i386__ */ + + +/*********************************************************************** + * Synchronization barrier functions + ***********************************************************************/ + + +/*********************************************************************** + * InitializeSynchronizationBarrier (kernelbase.@) + */ +BOOL WINAPI InitializeSynchronizationBarrier( SYNCHRONIZATION_BARRIER *barrier, LONG thread_count, LONG spin_count ) +{ + if (thread_count <= 0 || spin_count < -1) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + return set_ntstatus( RtlInitBarrier( barrier, thread_count, spin_count )); +} + + +/*********************************************************************** + * DeleteSynchronizationBarrier (kernelbase.@) + */ +BOOL WINAPI DeleteSynchronizationBarrier( SYNCHRONIZATION_BARRIER *barrier ) +{ + RtlDeleteBarrier( barrier ); + return TRUE; +} + + +/*********************************************************************** + * EnterSynchronizationBarrier (kernelbase.@) + */ +BOOL WINAPI EnterSynchronizationBarrier( SYNCHRONIZATION_BARRIER *barrier, DWORD flags ) +{ + static const DWORD valid_flags = SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY | SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY + | SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE; + static unsigned int once; + + if (flags & ~valid_flags) RtlRaiseStatus( STATUS_INVALID_PARAMETER ); + + if (flags & ~SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE && !once++) + FIXME( "flags %#lx are not implemented.\n", flags ); + + return RtlBarrier( barrier, flags & SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE ? 0 : 0x10000 ); +} diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index d9529ee085cf..17b414128b21 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -37,10 +37,12 @@ #include "winnls.h" #include "winternl.h" #include "winerror.h" +#include "winreg.h" #include "appmodel.h" #include "kernelbase.h" #include "wine/debug.h" +#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(ver); @@ -154,11 +156,13 @@ static const struct }, /* Windows 10 */ { - { 10, 0, 19043 }, + { 10, 0, 19045 }, {0x8e0f7a12,0xbfb3,0x4fe8,{0xb9,0xa5,0x48,0xfd,0x50,0xa1,0x5a,0x9a}} } }; +static const WCHAR packages_key_name[] = L"Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows" + L"\\CurrentVersion\\AppModel\\PackageRepository\\Packages"; /****************************************************************************** * init_current_version @@ -776,6 +780,32 @@ DWORD WINAPI GetFileVersionInfoSizeExW( DWORD flags, LPCWSTR filename, LPDWORD r if ((hModule = LoadLibraryExW( filename, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE ))) { HRSRC hRsrc = NULL; + + static const char builtin_signature[] = "Wine builtin DLL"; + HMODULE mod = (HMODULE)((ULONG_PTR)hModule & ~(ULONG_PTR)3); + char *signature = (char *)((IMAGE_DOS_HEADER *)mod + 1); + WCHAR exe_name[MAX_PATH]; + IMAGE_NT_HEADERS *nt; + DWORD exe_name_len; + + if ((exe_name_len = GetModuleFileNameW( NULL, exe_name, ARRAY_SIZE(exe_name) )) + && ((exe_name_len >= 16 + && (!memcmp( exe_name + exe_name_len - 16, L"vcredist_x64.exe", 16 * sizeof(*exe_name) ) + || !memcmp( exe_name + exe_name_len - 16, L"vcredist_x86.exe", 16 * sizeof(*exe_name) ))) + || (exe_name_len >= 17 + && (!memcmp( exe_name + exe_name_len - 17, L"vc_redist.x64.exe", 17 * sizeof(*exe_name) ) + || !memcmp( exe_name + exe_name_len - 17, L"vc_redist.x86.exe", 17 * sizeof(*exe_name) ) + || !memcmp( exe_name + exe_name_len - 17, L"VC_redist.x64.exe", 17 * sizeof(*exe_name) ) + || !memcmp( exe_name + exe_name_len - 17, L"VC_redist.x86.exe", 17 * sizeof(*exe_name) )))) + && (nt = RtlImageNtHeader( mod )) && (char *)nt - signature >= sizeof(builtin_signature) + && !memcmp( signature, builtin_signature, sizeof(builtin_signature) )) + { + ERR("HACK: not exposing version info.\n"); + FreeLibrary( hModule ); + SetLastError( ERROR_RESOURCE_NAME_NOT_FOUND ); + return 0; + } + if (!(flags & FILE_VER_GET_LOCALISED)) { LANGID english = MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ); @@ -1610,22 +1640,6 @@ LONG WINAPI /* DECLSPEC_HOTPATCH */ GetPackageFamilyName( HANDLE process, UINT32 return APPMODEL_ERROR_NO_PACKAGE; } -/*********************************************************************** - * GetPackagesByPackageFamily (kernelbase.@) - */ -LONG WINAPI DECLSPEC_HOTPATCH GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, - WCHAR *full_names, UINT32 *buffer_len, WCHAR *buffer) -{ - FIXME( "(%s %p %p %p %p): stub\n", debugstr_w(family_name), count, full_names, buffer_len, buffer ); - - if (!count || !buffer_len) - return ERROR_INVALID_PARAMETER; - - *count = 0; - *buffer_len = 0; - return ERROR_SUCCESS; -} - /*********************************************************************** * GetPackagePathByFullName (kernelbase.@) */ @@ -1664,6 +1678,16 @@ static UINT32 processor_arch_from_string(const WCHAR *str, unsigned int len) return ~0u; } +const WCHAR *string_from_processor_arch(UINT32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(arch_names); ++i) + if (code == arch_names[i].code) + return arch_names[i].name; + return NULL; +} + /*********************************************************************** * PackageIdFromFullName (kernelbase.@) */ @@ -1752,3 +1776,229 @@ LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 * return ERROR_SUCCESS; } + + +/*********************************************************************** + * PackageFullNameFromId (kernelbase.@) + */ +LONG WINAPI PackageFullNameFromId(const PACKAGE_ID *package_id, UINT32 *length, WCHAR *full_name) +{ + WCHAR ver_str[5 * 4 + 3 + 1]; + const WCHAR *arch_str; + UINT32 have_length; + + TRACE("package_id %p, length %p, full_name %p.\n", package_id, length, full_name); + + if (!package_id || !length) + return ERROR_INVALID_PARAMETER; + if (!full_name && *length) + return ERROR_INVALID_PARAMETER; + if (!package_id->name || !package_id->resourceId || !package_id->publisherId + || !(arch_str = string_from_processor_arch(package_id->processorArchitecture))) + return ERROR_INVALID_PARAMETER; + + swprintf(ver_str, ARRAY_SIZE(ver_str), L"%u.%u.%u.%u", package_id->version.Major, + package_id->version.Minor, package_id->version.Build, package_id->version.Revision); + have_length = *length; + *length = lstrlenW(package_id->name) + 1 + lstrlenW(ver_str) + 1 + lstrlenW(arch_str) + 1 + + lstrlenW(package_id->resourceId) + 1 + lstrlenW(package_id->publisherId) + 1; + + if (have_length < *length) + return ERROR_INSUFFICIENT_BUFFER; + + swprintf(full_name, *length, L"%s_%s_%s_%s_%s", package_id->name, ver_str, arch_str, package_id->resourceId, package_id->publisherId); + return ERROR_SUCCESS; +} + + +/*********************************************************************** + * GetPackagesByPackageFamily (kernelbase.@) + */ +LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, + UINT32 *buffer_length, WCHAR *buffer) +{ + UINT32 curr_count, curr_length, package_id_buf_size, size; + unsigned int i, name_len, publisher_id_len; + DWORD subkey_count, max_key_len, length; + const WCHAR *publisher_id; + WCHAR *package_name; + BOOL short_buffer; + PACKAGE_ID *id; + HKEY key; + + TRACE("family_name %s, count %p, full_names %p, buffer_length %p, buffer %p.\n", + debugstr_w(family_name), count, full_names, buffer_length, buffer); + + if (!buffer_length || !count || !family_name) + return ERROR_INVALID_PARAMETER; + + if ((*buffer_length || *count) && (!full_names || !buffer)) + return ERROR_INVALID_PARAMETER; + + if (!(publisher_id = wcschr(family_name, L'_'))) + return ERROR_INVALID_PARAMETER; + + name_len = publisher_id - family_name; + ++publisher_id; + publisher_id_len = lstrlenW(publisher_id); + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, packages_key_name, 0, KEY_READ, &key)) + { + ERR("Key open failed.\n"); + *count = 0; + *buffer_length = 0; + return ERROR_SUCCESS; + } + if (RegQueryInfoKeyW(key, NULL, NULL, NULL, &subkey_count, &max_key_len, NULL, NULL, NULL, NULL, NULL, NULL)) + { + ERR("Query key info failed.\n"); + RegCloseKey(key); + *count = 0; + *buffer_length = 0; + return ERROR_SUCCESS; + } + + if (!(package_name = heap_alloc((max_key_len + 1) * sizeof(*package_name)))) + { + ERR("No memory.\n"); + RegCloseKey(key); + return ERROR_OUTOFMEMORY; + } + + package_id_buf_size = sizeof(*id) + (max_key_len + 1) * sizeof(WCHAR); + if (!(id = heap_alloc(package_id_buf_size))) + { + ERR("No memory.\n"); + heap_free(package_name); + RegCloseKey(key); + return ERROR_OUTOFMEMORY; + } + + curr_count = curr_length = 0; + for (i = 0; i < subkey_count; ++i) + { + length = max_key_len + 1; + if (RegEnumKeyExW(key, i, package_name, &length, NULL, NULL, NULL, NULL)) + { + ERR("Error enumerating key %u.\n", i); + continue; + } + + size = package_id_buf_size; + if (PackageIdFromFullName(package_name, 0, &size, (BYTE *)id)) + { + ERR("Error getting package id from full name.\n"); + continue; + } + + if (lstrlenW(id->name) != name_len) + continue; + if (wcsnicmp(family_name, id->name, name_len)) + continue; + + if (lstrlenW(id->publisherId) != publisher_id_len) + continue; + if (wcsnicmp(publisher_id, id->publisherId, publisher_id_len)) + continue; + if (curr_length + length < *buffer_length) + { + memcpy(buffer + curr_length, package_name, (length + 1) * sizeof(*package_name)); + if (curr_count < *count) + full_names[curr_count] = buffer + curr_length; + } + curr_length += length + 1; + ++curr_count; + } + + heap_free(id); + heap_free(package_name); + RegCloseKey(key); + + short_buffer = curr_length > *buffer_length || curr_count > *count; + *count = curr_count; + *buffer_length = curr_length; + + return short_buffer ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS; +} + + +/*********************************************************************** + * GetPackagePath (kernelbase.@) + */ +LONG WINAPI GetPackagePath(const PACKAGE_ID *package_id, const UINT32 reserved, UINT32 *length, WCHAR *path) +{ + WCHAR *key_name = NULL, *expanded_path = NULL; + UINT32 required_length, have_length; + unsigned int offset; + HKEY key = NULL; + DWORD size; + LONG ret; + + TRACE("package_id %p, reserved %u, length %p, path %p.\n", package_id, reserved, length, path); + + if (!length) + return ERROR_INVALID_PARAMETER; + if (!path && *length) + return ERROR_INVALID_PARAMETER; + + required_length = 0; + if ((ret = PackageFullNameFromId(package_id, &required_length, NULL)) != ERROR_INSUFFICIENT_BUFFER) + return ret; + + offset = lstrlenW(packages_key_name) + 1; + if (!(key_name = heap_alloc((offset + required_length) * sizeof(WCHAR)))) + { + ERR("No memory."); + return ERROR_OUTOFMEMORY; + } + + if ((ret = PackageFullNameFromId(package_id, &required_length, key_name + offset))) + goto done; + + memcpy(key_name, packages_key_name, (offset - 1) * sizeof(WCHAR)); + key_name[offset - 1] = L'\\'; + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ, &key)) + { + WARN("Key %s not found.\n", debugstr_w(key_name)); + ret = ERROR_NOT_FOUND; + goto done; + } + if (RegGetValueW(key, NULL, L"Path", RRF_RT_REG_SZ, NULL, NULL, &size)) + { + WARN("Path value not found in %s.\n", debugstr_w(key_name)); + ret = ERROR_NOT_FOUND; + goto done; + } + if (!(expanded_path = heap_alloc(size))) + { + ERR("No memory."); + ret = ERROR_OUTOFMEMORY; + goto done; + } + if (RegGetValueW(key, NULL, L"Path", RRF_RT_REG_SZ, NULL, expanded_path, &size)) + { + WARN("Could not get Path value from %s.\n", debugstr_w(key_name)); + ret = ERROR_NOT_FOUND; + goto done; + } + + have_length = *length; + *length = lstrlenW(expanded_path) + 1; + if (have_length >= *length) + { + memcpy(path, expanded_path, *length * sizeof(*path)); + ret = ERROR_SUCCESS; + } + else + { + ret = ERROR_INSUFFICIENT_BUFFER; + } + +done: + if (key) + RegCloseKey(key); + heap_free(expanded_path); + heap_free(key_name); + return ret; +} diff --git a/dlls/kernelbase/volume.c b/dlls/kernelbase/volume.c index d48952285256..b7025ce91c1d 100644 --- a/dlls/kernelbase/volume.c +++ b/dlls/kernelbase/volume.c @@ -736,6 +736,43 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_se } +/*********************************************************************** + * GetDiskSpaceInformationW (kernelbase.@) + */ +HRESULT WINAPI GetDiskSpaceInformationW( LPCWSTR root, DISK_SPACE_INFORMATION *info ) +{ + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE handle; + + TRACE( "%s,%p\n", debugstr_w(root), info ); + + if (!info) + return HRESULT_FROM_NT( ERROR_INVALID_DATA | ERROR_SEVERITY_WARNING | ERROR_SEVERITY_INFORMATIONAL ); + + if (!open_device_root( root, &handle )) return HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ); + + status = NtQueryVolumeInformationFile( handle, &io, (FILE_FS_FULL_SIZE_INFORMATION_EX *)info, sizeof(*info), + FileFsFullSizeInformationEx ); + NtClose( handle ); + if (!set_ntstatus( status )) return status; + + return S_OK; +} + + +/*********************************************************************** + * GetDiskSpaceInformationA (kernelbase.@) + */ +HRESULT WINAPI GetDiskSpaceInformationA( LPCSTR root, DISK_SPACE_INFORMATION *info ) +{ + WCHAR *rootW = NULL; + + if (root && !(rootW = file_name_AtoW( root, FALSE ))) return FALSE; + return GetDiskSpaceInformationW( rootW, info ); +} + + static BOOL is_dos_path( const UNICODE_STRING *path ) { static const WCHAR global_prefix[4] = {'\\','?','?','\\'}; diff --git a/dlls/krnl386.exe16/file.c b/dlls/krnl386.exe16/file.c index 5eab05598835..01cf4ac657aa 100644 --- a/dlls/krnl386.exe16/file.c +++ b/dlls/krnl386.exe16/file.c @@ -643,7 +643,7 @@ UINT16 WINAPI GetSystemDirectory16( LPSTR path, UINT16 count ) UINT16 len; len = GetWindowsDirectory16(windir, sizeof(windir) - sizeof(system16) + 1) + sizeof(system16); - if (count >= len) + if (path && count >= len) { lstrcpyA(path, windir); lstrcatA(path, system16); diff --git a/dlls/mf/evr.c b/dlls/mf/evr.c index eb366ea599af..f09cf43f8bf4 100644 --- a/dlls/mf/evr.c +++ b/dlls/mf/evr.c @@ -64,6 +64,7 @@ struct video_stream LONG refcount; unsigned int id; unsigned int flags; + unsigned int preroll_count; struct video_renderer *parent; IMFMediaEventQueue *event_queue; IMFVideoSampleAllocator *allocator; @@ -426,9 +427,16 @@ static HRESULT WINAPI video_stream_sink_ProcessSample(IMFStreamSink *iface, IMFS if (stream->flags & EVR_STREAM_PREROLLING) { - IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamSinkPrerolled, &GUID_NULL, S_OK, NULL); - stream->flags &= ~EVR_STREAM_PREROLLING; - stream->flags |= EVR_STREAM_PREROLLED; + if (stream->preroll_count--) + IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamSinkRequestSample, + &GUID_NULL, S_OK, NULL); + else + { + IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamSinkPrerolled, + &GUID_NULL, S_OK, NULL); + stream->flags &= ~EVR_STREAM_PREROLLING; + stream->flags |= EVR_STREAM_PREROLLED; + } } } @@ -1534,6 +1542,7 @@ static HRESULT WINAPI video_renderer_preroll_NotifyPreroll(IMFMediaSinkPreroll * IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL); stream->flags |= EVR_STREAM_PREROLLING; + stream->preroll_count = 3; } LeaveCriticalSection(&stream->cs); } diff --git a/dlls/mf/mf.rgs b/dlls/mf/mf.rgs index f06576baccb6..f127df763212 100644 --- a/dlls/mf/mf.rgs +++ b/dlls/mf/mf.rgs @@ -12,14 +12,6 @@ HKLM { val '{477ec299-1421-4bdd-971f-7ccb933f21ad}' = s 'File Scheme Handler' } - 'http:' - { - val '{9ec4b4f9-3029-45ad-947b-344de2a249e2}' = s 'Urlmon Scheme Handler' - } - 'https:' - { - val '{9ec4b4f9-3029-45ad-947b-344de2a249e2}' = s 'Urlmon Scheme Handler' - } } } } diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index de599139736a..4d54afc1d316 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -1195,6 +1195,10 @@ static HRESULT sample_grabber_set_state(struct sample_grabber *grabber, enum sin if (state == SINK_STATE_RUNNING && grabber->state != SINK_STATE_RUNNING) { + /* Unpause at a position is a seek operation which drops everything pending. */ + if (grabber->state == SINK_STATE_PAUSED && offset != PRESENTATION_CURRENT_POSITION) + grabber->sample_count = MAX_SAMPLE_QUEUE_LENGTH; + /* Every transition to running state sends a bunch requests to build up initial queue. */ for (i = 0; i < grabber->sample_count; ++i) { diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c index 84824f954dd3..cdafd606f656 100644 --- a/dlls/mf/sar.c +++ b/dlls/mf/sar.c @@ -636,7 +636,7 @@ static HRESULT WINAPI audio_renderer_clock_sink_OnClockStart(IMFClockStateSink * EnterCriticalSection(&renderer->cs); if (renderer->audio_client) { - if (renderer->state == STREAM_STATE_STOPPED) + if (renderer->state != STREAM_STATE_RUNNING) { if (FAILED(hr = IAudioClient_Start(renderer->audio_client))) WARN("Failed to start audio client, hr %#lx.\n", hr); @@ -1339,6 +1339,7 @@ static HRESULT stream_queue_sample(struct audio_renderer *renderer, IMFSample *s { struct queued_object *object; DWORD sample_len, sample_frames; + MFTIME time, clocktime, systime; HRESULT hr; if (FAILED(hr = IMFSample_GetTotalLength(sample, &sample_len))) @@ -1346,15 +1347,33 @@ static HRESULT stream_queue_sample(struct audio_renderer *renderer, IMFSample *s sample_frames = sample_len / renderer->frame_size; - if (!(object = calloc(1, sizeof(*object)))) - return E_OUTOFMEMORY; + if (FAILED(hr = IMFSample_GetSampleTime(sample, &time))) + { + WARN("Failed to get sample time, hr %#lx.\n", hr); + return hr; + } - object->type = OBJECT_TYPE_SAMPLE; - object->u.sample.sample = sample; - IMFSample_AddRef(object->u.sample.sample); + if (!renderer->clock) + clocktime = time; + else if (FAILED(hr = IMFPresentationClock_GetCorrelatedTime(renderer->clock, 0, &clocktime, &systime))) + { + WARN("Failed to get clock time, hr %#lx.\n", hr); + return hr; + } - list_add_tail(&renderer->queue, &object->entry); - renderer->queued_frames += sample_frames; + if (time < clocktime) + FIXME("Dropping sample %p, time %I64u, clocktime %I64u, systime %I64u.\n", sample, time, clocktime, systime); + else + { + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->type = OBJECT_TYPE_SAMPLE; + object->u.sample.sample = sample; + IMFSample_AddRef(object->u.sample.sample); + list_add_tail(&renderer->queue, &object->entry); + renderer->queued_frames += sample_frames; + } return S_OK; } @@ -1458,6 +1477,8 @@ static HRESULT WINAPI audio_renderer_stream_Flush(IMFStreamSink *iface) } } renderer->queued_frames = 0; + if (FAILED(hr = IAudioClient_Reset(renderer->audio_client))) + WARN("Failed to reset audio client, hr %#lx.\n", hr); LeaveCriticalSection(&renderer->cs); return hr; @@ -1503,6 +1524,7 @@ static HRESULT check_media_type(IMFMediaType *type, IMFMediaType *current) { static const GUID *required_attrs[] = { + &MF_MT_SUBTYPE, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &MF_MT_AUDIO_NUM_CHANNELS, &MF_MT_AUDIO_BITS_PER_SAMPLE, diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 483ea6f904f7..11903eaa1089 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -19,6 +19,7 @@ #include #include #include +#include #define COBJMACROS @@ -56,7 +57,6 @@ struct session_op IUnknown IUnknown_iface; LONG refcount; enum session_command command; - BOOL submitted; union { struct @@ -92,21 +92,38 @@ struct queued_topology enum session_state { SESSION_STATE_STOPPED = 0, - SESSION_STATE_STARTING_SOURCES, - SESSION_STATE_PREROLLING_SINKS, - SESSION_STATE_STARTING_SINKS, - SESSION_STATE_RESTARTING_SOURCES, SESSION_STATE_STARTED, - SESSION_STATE_PAUSING_SINKS, - SESSION_STATE_PAUSING_SOURCES, SESSION_STATE_PAUSED, - SESSION_STATE_STOPPING_SINKS, - SESSION_STATE_STOPPING_SOURCES, - SESSION_STATE_FINALIZING_SINKS, SESSION_STATE_CLOSED, SESSION_STATE_SHUT_DOWN, }; +enum command_state +{ + COMMAND_STATE_COMPLETE = 0, + /* Command submitted but hasn't started execution. + * invariant: the submitted command is always the head of session->commands. */ + COMMAND_STATE_SUBMITTED, + /* STOPPED | PAUSED | STARTED -> STARTED transition */ + COMMAND_STATE_RESTARTING_SOURCES, /* -> COMMAND_STATE_STARTING_SOURCES */ + COMMAND_STATE_STARTING_SOURCES, /* -> COMMAND_STATE_PREROLLING_SINKS | COMMAND_STATE_STARTING_SINKS */ + COMMAND_STATE_PREROLLING_SINKS, /* -> COMMAND_STATE_STARTING_SINKS */ + COMMAND_STATE_STARTING_SINKS, /* -> SESSION_STATE_STARTED */ + /* STARTED -> PAUSED transition */ + COMMAND_STATE_PAUSING_SINKS, /* -> COMMAND_STATE_PAUSING_SOURCES */ + COMMAND_STATE_PAUSING_SOURCES, /* -> SESSION_STATE_PAUSED */ + /* STARTED -> STOPPED transition when presentation ends */ + COMMAND_STATE_ENDING_STREAMS, /* -> COMMAND_STATE_ENDING_SINKS */ + COMMAND_STATE_ENDING_SINKS, /* -> SESSION_STATE_STOPPED */ + /* STARTED | PAUSED -> STOPPED transition */ + COMMAND_STATE_STOPPING_SINKS, /* -> COMMAND_STATE_STOPPING_SOURCES */ + COMMAND_STATE_STOPPING_SOURCES, /* -> SESSION_STATE_STOPPED */ + /* STARTED | PAUSED | STOPPED -> CLOSED transition */ + COMMAND_STATE_CLOSING_SINKS, /* -> COMMAND_STATE_CLOSING_SOURCES */ + COMMAND_STATE_CLOSING_SOURCES, /* -> COMMAND_STATE_FINALIZING_SINKS */ + COMMAND_STATE_FINALIZING_SINKS, /* -> SESSION_STATE_CLOSED */ +}; + enum object_state { OBJ_STATE_STOPPED = 0, @@ -129,7 +146,6 @@ struct media_source IMFMediaSource *source; IUnknown *object; }; - IMFMediaShutdownNotify *shutdown_notify; IMFPresentationDescriptor *pd; enum object_state state; unsigned int flags; @@ -159,6 +175,7 @@ struct transform_stream struct list samples; unsigned int requests; unsigned int min_buffer_size; + IMFSample *allocated_sample; BOOL draining; }; @@ -217,11 +234,11 @@ enum presentation_flags { SESSION_FLAG_SOURCES_SUBSCRIBED = 0x1, SESSION_FLAG_PRESENTATION_CLOCK_SET = 0x2, - SESSION_FLAG_FINALIZE_SINKS = 0x4, SESSION_FLAG_NEEDS_PREROLL = 0x8, - SESSION_FLAG_END_OF_PRESENTATION = 0x10, + SESSION_FLAG_SOURCE_SHUTDOWN = 0x10, SESSION_FLAG_PENDING_RATE_CHANGE = 0x20, - SESSION_FLAG_PENDING_COMMAND = 0x40, + SESSION_FLAG_RESTARTING = 0x40, + SESSION_FLAG_SINKS_SUBSCRIBED = 0x80, }; struct media_session @@ -233,11 +250,9 @@ struct media_session IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface; IMFAsyncCallback commands_callback; IMFAsyncCallback sa_ready_callback; - IMFAsyncCallback shutdown_callback; IMFAsyncCallback events_callback; IMFAsyncCallback sink_finalizer_callback; LONG refcount; - BOOL source_shutdown_handled; IMFMediaEventQueue *event_queue; IMFPresentationClock *clock; IMFPresentationTimeSource *system_time_source; @@ -260,10 +275,13 @@ struct media_session /* Latest SetRate() arguments. */ BOOL thin; float rate; + + BOOL thin_committed; } presentation; struct list topologies; struct list commands; enum session_state state; + enum command_state command_state; DWORD caps; CRITICAL_SECTION cs; }; @@ -283,11 +301,6 @@ static struct media_session *impl_from_sa_ready_callback_IMFAsyncCallback(IMFAsy return CONTAINING_RECORD(iface, struct media_session, sa_ready_callback); } -static struct media_session *impl_from_shutdown_callback_IMFAsyncCallback(IMFAsyncCallback *iface) -{ - return CONTAINING_RECORD(iface, struct media_session, shutdown_callback); -} - static struct media_session *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface) { return CONTAINING_RECORD(iface, struct media_session, events_callback); @@ -473,10 +486,12 @@ static HRESULT session_submit_command(struct media_session *session, struct sess EnterCriticalSection(&session->cs); if (SUCCEEDED(hr = session_is_shut_down(session))) { - if (list_empty(&session->commands) && !(session->presentation.flags & SESSION_FLAG_PENDING_COMMAND)) + if (list_empty(&session->commands) && session->command_state == COMMAND_STATE_COMPLETE) { hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface); - op->submitted = SUCCEEDED(hr); + /* Since session->commands is empty, whether `op` is added to head or tail, it will + * always be at the head of this list, thus the invariant holds. */ + if (SUCCEEDED(hr)) session->command_state = COMMAND_STATE_SUBMITTED; } if (op->command == SESSION_CMD_SHUTDOWN) list_add_head(&session->commands, &op->entry); @@ -520,7 +535,7 @@ static void session_set_topo_status(struct media_session *session, HRESULT statu IMFMediaEvent *event; PROPVARIANT param; - if (topo_status == MF_TOPOSTATUS_INVALID) + if (topo_status == MF_TOPOSTATUS_INVALID || status == MF_E_SHUTDOWN) return; if (list_empty(&session->topologies)) @@ -762,6 +777,12 @@ static void transform_stream_drop_events(struct transform_stream *stream) { IMFMediaEvent *event; + if (stream->allocated_sample) + { + IMFSample_Release(stream->allocated_sample); + stream->allocated_sample = NULL; + } + while (SUCCEEDED(transform_stream_pop_event(stream, &event))) IMFMediaEvent_Release(event); } @@ -840,7 +861,7 @@ static void session_shutdown_current_topology(struct media_session *session) WARN("Failed to shut down activation object for the sink, hr %#lx.\n", hr); IMFActivate_Release(activate); } - else if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) + if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) { if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink))) { @@ -860,14 +881,11 @@ static void session_shutdown_current_topology(struct media_session *session) static void session_clear_command_list(struct media_session *session) { struct session_op *op, *op2; - + /* Checking this flag is unnecessary if this function is only called + * from the callback or upon release, but do it for consistency and + * in case a call from elsewhere is added. */ LIST_FOR_EACH_ENTRY_SAFE(op, op2, &session->commands, struct session_op, entry) { - /* Checking this flag is unnecessary if this function is only called - * from the callback or upon release, but do it for consistency and - * in case a call from elsewhere is added. */ - if (op->submitted) - continue; list_remove(&op->entry); IUnknown_Release(&op->IUnknown_iface); } @@ -966,14 +984,14 @@ static void session_command_complete(struct media_session *session) struct list *e; HRESULT hr; - session->presentation.flags &= ~SESSION_FLAG_PENDING_COMMAND; + session->command_state = COMMAND_STATE_COMPLETE; /* Submit next command. */ if ((e = list_head(&session->commands))) { op = LIST_ENTRY(e, struct session_op, entry); hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, &op->IUnknown_iface); - op->submitted = SUCCEEDED(hr); + if (SUCCEEDED(hr)) session->command_state = COMMAND_STATE_SUBMITTED; } } @@ -1006,73 +1024,162 @@ static HRESULT session_subscribe_sources(struct media_session *session) return hr; } -static void session_flush_nodes(struct media_session *session) +static HRESULT session_subscribe_sinks(struct media_session *session) { struct topo_node *node; + HRESULT hr = S_OK; + + if (session->presentation.flags & SESSION_FLAG_SINKS_SUBSCRIBED) + return hr; LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) { - if (node->type == MF_TOPOLOGY_OUTPUT_NODE) - IMFStreamSink_Flush(node->object.sink_stream); - else if (node->type == MF_TOPOLOGY_TRANSFORM_NODE) + if (node->type != MF_TOPOLOGY_OUTPUT_NODE) + continue; + + if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback, + node->object.object))) + { + WARN("Failed to subscribe to stream sink events, hr %#lx.\n", hr); + } + } + + session->presentation.flags |= SESSION_FLAG_SINKS_SUBSCRIBED; + return hr; +} + +static void session_flush_transforms(struct media_session *session) +{ + struct topo_node *node; + UINT i; + + LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) + { + if (node->type == MF_TOPOLOGY_TRANSFORM_NODE) + { IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0); + for (i = 0; i < node->u.transform.output_count; i++) + node->u.transform.outputs[i].requests = 0; /* these requests might have been flushed */ + } } } -static void session_purge_pending_commands(struct media_session *session) +static void session_request_sample(struct media_session *session, IMFStreamSink *sink_stream); + +static void session_flush_sinks(struct media_session *session) { - struct session_op *op, *op2; + struct topo_node *node; - /* Purge all commands which are no longer valid after a forced source shutdown. - * Calling Stop() in this case is not required in native Windows. */ - LIST_FOR_EACH_ENTRY_SAFE(op, op2, &session->commands, struct session_op, entry) + LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) { - if (op->command == SESSION_CMD_SET_TOPOLOGY) - break; - if (op->command == SESSION_CMD_CLEAR_TOPOLOGIES || op->command == SESSION_CMD_CLOSE - || op->command == SESSION_CMD_SHUTDOWN) - continue; - /* Once a command is submitted, the callback becomes responsible - * for removal from the list and release of the ref. */ - if (op->submitted) - continue; - list_remove(&op->entry); - IUnknown_Release(&op->IUnknown_iface); + if (node->type == MF_TOPOLOGY_OUTPUT_NODE) + { + if (node->u.sink.requests) + { + node->u.sink.requests--; + session_request_sample(session, node->object.sink_stream); + } + IMFStreamSink_Flush(node->object.sink_stream); + } } } -static void session_reset(struct media_session *session) +static void session_flush_nodes(struct media_session *session) { - /* Media sessions in native Windows are not consistently usable after a - * forced source shutdown, but we try to clean up as well as possible. */ - session->state = SESSION_STATE_STOPPED; - session_clear_presentation(session); - session_purge_pending_commands(session); - session_command_complete(session); + struct topo_node *node; + + LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) + { + if (node->type == MF_TOPOLOGY_OUTPUT_NODE) + IMFStreamSink_Flush(node->object.sink_stream); + else if (node->type == MF_TOPOLOGY_TRANSFORM_NODE) + IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_COMMAND_FLUSH, 0); + } } -static void session_handle_start_error(struct media_session *session, HRESULT hr) +static void session_handle_source_shutdown(struct media_session *session); + +static void session_reset_transforms(struct media_session *session, BOOL drop) { - if (hr == MF_E_SHUTDOWN) + struct topo_node *topo_node; + UINT i; + + LIST_FOR_EACH_ENTRY(topo_node, &session->presentation.nodes, struct topo_node, entry) { - session_reset(session); - hr = MF_E_INVALIDREQUEST; + if (topo_node->type != MF_TOPOLOGY_TRANSFORM_NODE) + continue; + + for (i = 0; i < topo_node->u.transform.input_count; i++) + { + struct transform_stream *stream = &topo_node->u.transform.inputs[i]; + stream->draining = FALSE; + if (drop) + transform_stream_drop_events(stream); + } + + if (!drop) + continue; + + for (i = 0; i < topo_node->u.transform.output_count; ++i) + { + struct transform_stream *stream = &topo_node->u.transform.outputs[i]; + transform_stream_drop_events(stream); + stream->requests = 0; + } } - session_command_complete_with_event(session, MESessionStarted, hr, NULL); } static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position) { struct media_source *source; - struct topo_node *topo_node; MFTIME duration; HRESULT hr; - UINT i; switch (session->state) { - case SESSION_STATE_STOPPED: + case SESSION_STATE_PAUSED: + case SESSION_STATE_STARTED: + if (!IsEqualGUID(time_format, &GUID_NULL) || start_position->vt != VT_EMPTY) + { + session->command_state = COMMAND_STATE_RESTARTING_SOURCES; + + /* We are seeking to a new position, check for invalid positions */ + LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) + { + hr = IMFPresentationDescriptor_GetUINT64(source->pd, &MF_PD_DURATION, (UINT64 *)&duration); + if (SUCCEEDED(hr) && IsEqualGUID(time_format, &GUID_NULL) + && start_position->vt == VT_I8 && start_position->hVal.QuadPart > duration) + { + WARN("Start position %s out of range, hr %#lx.\n", wine_dbgstr_longlong(start_position->hVal.QuadPart), hr); + session_command_complete_with_event(session, MESessionStarted, MF_E_INVALID_POSITION, NULL); + return; + } + } + + /* Stop sources */ + LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) + { + if (FAILED(hr = IMFMediaSource_Stop(source->source))) + { + WARN("Failed to stop media source %p, hr %#lx.\n", source->source, hr); + if (hr == MF_E_SHUTDOWN) + return session_handle_source_shutdown(session); + session_command_complete_with_event(session, MESessionStarted, hr, NULL); + return; + } + } + session->presentation.time_format = *time_format; + session->presentation.start_position.vt = VT_EMPTY; + PropVariantCopy(&session->presentation.start_position, start_position); + + break; + } + else if (session->state == SESSION_STATE_STARTED) + return session_command_complete_with_event(session, MESessionStarted, S_OK, NULL); + + /* fallthrough; we're resuming from the current position */ + case SESSION_STATE_STOPPED: /* Start request with no current topology. */ if (session->presentation.topo_status == MF_TOPOSTATUS_INVALID) { @@ -1080,8 +1187,7 @@ static void session_start(struct media_session *session, const GUID *time_format break; } - /* fallthrough */ - case SESSION_STATE_PAUSED: + session->command_state = COMMAND_STATE_STARTING_SOURCES; session->presentation.time_format = *time_format; session->presentation.start_position.vt = VT_EMPTY; @@ -1089,67 +1195,28 @@ static void session_start(struct media_session *session, const GUID *time_format if (FAILED(hr = session_subscribe_sources(session))) { - session_handle_start_error(session, hr); - return; + if (hr == MF_E_SHUTDOWN) + return session_handle_source_shutdown(session); + return session_command_complete_with_event(session, MESessionStarted, hr, NULL); } + session_reset_transforms(session, FALSE); + LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position))) { WARN("Failed to start media source %p, hr %#lx.\n", source->source, hr); - session_handle_start_error(session, hr); - return; + if (hr == MF_E_SHUTDOWN) + return session_handle_source_shutdown(session); + return session_command_complete_with_event(session, MESessionStarted, hr, NULL); } } - LIST_FOR_EACH_ENTRY(topo_node, &session->presentation.nodes, struct topo_node, entry) - { - if (topo_node->type == MF_TOPOLOGY_TRANSFORM_NODE) - { - for (i = 0; i < topo_node->u.transform.input_count; i++) - { - struct transform_stream *stream = &topo_node->u.transform.inputs[i]; - stream->draining = FALSE; - } - } - } - - session->state = SESSION_STATE_STARTING_SOURCES; break; - case SESSION_STATE_STARTED: - /* Check for invalid positions */ - LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) - { - hr = IMFPresentationDescriptor_GetUINT64(source->pd, &MF_PD_DURATION, (UINT64 *)&duration); - if (SUCCEEDED(hr) && IsEqualGUID(time_format, &GUID_NULL) - && start_position->vt == VT_I8 && start_position->hVal.QuadPart > duration) - { - WARN("Start position %s out of range, hr %#lx.\n", wine_dbgstr_longlong(start_position->hVal.QuadPart), hr); - session_command_complete_with_event(session, MESessionStarted, MF_E_INVALID_POSITION, NULL); - return; - } - } - - /* Stop sources */ - LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) - { - if (FAILED(hr = IMFMediaSource_Stop(source->source))) - { - WARN("Failed to stop media source %p, hr %#lx.\n", source->source, hr); - session_command_complete_with_event(session, MESessionStarted, hr, NULL); - return; - } - } - session->presentation.time_format = *time_format; - session->presentation.start_position.vt = VT_EMPTY; - PropVariantCopy(&session->presentation.start_position, start_position); - - /* SESSION_STATE_STARTED -> SESSION_STATE_RESTARTING_SOURCES -> SESSION_STATE_STARTED */ - session->state = SESSION_STATE_RESTARTING_SOURCES; - break; - default: + case SESSION_STATE_CLOSED: + case SESSION_STATE_SHUT_DOWN: session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL); break; } @@ -1189,12 +1256,12 @@ static void session_set_started(struct media_session *session) session_command_complete(session); } -static void session_set_paused(struct media_session *session, unsigned int state, HRESULT status) +static void session_set_paused(struct media_session *session, HRESULT status) { /* Failed event status could indicate a failure during normal transition to paused state, or an attempt to pause from invalid initial state. To finalize failed transition in the former case, state is still forced to PAUSED, otherwise previous state is retained. */ - if (state != ~0u) session->state = state; + session->state = SESSION_STATE_PAUSED; if (SUCCEEDED(status)) session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE); session_command_complete_with_event(session, MESessionPaused, status, NULL); @@ -1210,7 +1277,6 @@ static void session_set_closed(struct media_session *session, HRESULT status) static void session_pause(struct media_session *session) { - unsigned int state = ~0u; HRESULT hr; switch (session->state) @@ -1218,21 +1284,22 @@ static void session_pause(struct media_session *session) case SESSION_STATE_STARTED: /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */ - if (SUCCEEDED(hr = IMFPresentationClock_Pause(session->clock))) - session->state = SESSION_STATE_PAUSING_SINKS; - state = SESSION_STATE_PAUSED; + session->command_state = COMMAND_STATE_PAUSING_SINKS; + hr = IMFPresentationClock_Pause(session->clock); - break; + if (FAILED(hr)) + session_set_paused(session, hr); + break; case SESSION_STATE_STOPPED: - hr = MF_E_SESSION_PAUSEWHILESTOPPED; + session_command_complete_with_event(session, MESessionPaused, MF_E_SESSION_PAUSEWHILESTOPPED, NULL); + break; + case SESSION_STATE_PAUSED: + case SESSION_STATE_CLOSED: + case SESSION_STATE_SHUT_DOWN: + session_command_complete_with_event(session, MESessionPaused, MF_E_INVALIDREQUEST, NULL); break; - default: - hr = MF_E_INVALIDREQUEST; } - - if (FAILED(hr)) - session_set_paused(session, state, hr); } static void session_clear_end_of_presentation(struct media_session *session) @@ -1240,7 +1307,6 @@ static void session_clear_end_of_presentation(struct media_session *session) struct media_source *source; struct topo_node *node; - session->presentation.flags &= ~SESSION_FLAG_END_OF_PRESENTATION; LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { source->flags &= ~SOURCE_FLAG_END_OF_PRESENTATION; @@ -1252,13 +1318,11 @@ static void session_clear_end_of_presentation(struct media_session *session) session->presentation.topo_status = MF_TOPOSTATUS_READY; } -static void session_set_stopped(struct media_session *session, HRESULT status) +static void session_set_stopped(struct media_session *session, MediaEventType event_type, HRESULT status) { - MediaEventType event_type; IMFMediaEvent *event; session->state = SESSION_STATE_STOPPED; - event_type = session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION ? MESessionEnded : MESessionStopped; if (SUCCEEDED(MFCreateMediaEvent(event_type, &GUID_NULL, status, NULL, &event))) { @@ -1282,15 +1346,16 @@ static void session_stop(struct media_session *session) /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */ IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time); if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock))) - session->state = SESSION_STATE_STOPPING_SINKS; + session->command_state = COMMAND_STATE_STOPPING_SINKS; else - session_set_stopped(session, hr); + session_set_stopped(session, MESessionStopped, hr); break; case SESSION_STATE_STOPPED: hr = S_OK; /* fallthrough */ - default: + case SESSION_STATE_CLOSED: + case SESSION_STATE_SHUT_DOWN: session_command_complete_with_event(session, MESessionStopped, hr, NULL); break; } @@ -1303,8 +1368,7 @@ static HRESULT session_finalize_sinks(struct media_session *session) struct media_sink *sink; HRESULT hr = S_OK; - session->presentation.flags &= ~SESSION_FLAG_FINALIZE_SINKS; - session->state = SESSION_STATE_FINALIZING_SINKS; + session->command_state = COMMAND_STATE_FINALIZING_SINKS; LIST_FOR_EACH_ENTRY(sink, &session->presentation.sinks, struct media_sink, entry) { @@ -1334,16 +1398,15 @@ static void session_close(struct media_session *session) switch (session->state) { case SESSION_STATE_STOPPED: - case SESSION_STATE_RESTARTING_SOURCES: hr = session_finalize_sinks(session); break; case SESSION_STATE_STARTED: case SESSION_STATE_PAUSED: - session->presentation.flags |= SESSION_FLAG_FINALIZE_SINKS; if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock))) - session->state = SESSION_STATE_STOPPING_SINKS; + session->command_state = COMMAND_STATE_CLOSING_SINKS; break; - default: + case SESSION_STATE_CLOSED: + case SESSION_STATE_SHUT_DOWN: hr = MF_E_INVALIDREQUEST; break; } @@ -1453,12 +1516,6 @@ static void session_set_presentation_clock(struct media_session *session) struct topo_node *node; HRESULT hr; - LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) - { - if (node->type == MF_TOPOLOGY_TRANSFORM_NODE) - IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); - } - if (!(session->presentation.flags & SESSION_FLAG_PRESENTATION_CLOCK_SET)) { /* Attempt to get time source from the sinks. */ @@ -1480,18 +1537,6 @@ static void session_set_presentation_clock(struct media_session *session) if (FAILED(hr)) WARN("Failed to set time source, hr %#lx.\n", hr); - LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) - { - if (node->type != MF_TOPOLOGY_OUTPUT_NODE) - continue; - - if (FAILED(hr = IMFStreamSink_BeginGetEvent(node->object.sink_stream, &session->events_callback, - node->object.object))) - { - WARN("Failed to subscribe to stream sink events, hr %#lx.\n", hr); - } - } - /* Set clock for all topology nodes. */ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { @@ -1535,7 +1580,7 @@ static void session_set_rate(struct media_session *session, BOOL thin, float rat if (SUCCEEDED(hr)) hr = IMFRateControl_GetRate(session->clock_rate_control, NULL, &clock_rate); - if (SUCCEEDED(hr) && (rate != clock_rate) && SUCCEEDED(hr = session_subscribe_sources(session))) + if (SUCCEEDED(hr) && (rate != clock_rate || thin != session->presentation.thin_committed) && SUCCEEDED(hr = session_subscribe_sources(session))) { LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { @@ -1548,6 +1593,7 @@ static void session_set_rate(struct media_session *session, BOOL thin, float rat { session->presentation.flags |= SESSION_FLAG_PENDING_RATE_CHANGE; session->presentation.rate = rate; + session->presentation.thin = thin; return; } } @@ -1572,7 +1618,9 @@ static void session_complete_rate_change(struct media_session *session) session->presentation.flags &= ~SESSION_FLAG_PENDING_RATE_CHANGE; session_set_presentation_clock(session); - hr = IMFRateControl_SetRate(session->clock_rate_control, session->presentation.thin, + session->presentation.thin_committed = session->presentation.thin; + + hr = IMFRateControl_SetRate(session->clock_rate_control, FALSE, session->presentation.rate); param.vt = VT_R4; @@ -1598,11 +1646,6 @@ static struct media_source *session_get_media_source(struct media_session *sessi static void session_release_media_source(struct media_source *source) { - if (source->shutdown_notify) - { - IMFMediaShutdownNotify_set_notification_callback(source->shutdown_notify, NULL, NULL); - IMFMediaShutdownNotify_Release(source->shutdown_notify); - } if (source->source) IMFMediaSource_Release(source->source); if (source->pd) @@ -1624,21 +1667,6 @@ static HRESULT session_add_media_source(struct media_session *session, IMFTopolo media_source->source = source; IMFMediaSource_AddRef(media_source->source); - if (SUCCEEDED(hr = IMFMediaSource_QueryInterface(media_source->source, - &IID_IMFMediaShutdownNotify, (void **)&media_source->shutdown_notify))) - { - hr = IMFMediaShutdownNotify_set_notification_callback(media_source->shutdown_notify, - &session->shutdown_callback, (IUnknown *)media_source->source); - if (hr == MF_E_SHUTDOWN) - { - session_release_media_source(media_source); - return hr; - } - } - - if (FAILED(hr)) - TRACE("Session is not robust to unexpected shutdown, hr %#lx.\n", hr); - hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, &IID_IMFPresentationDescriptor, (void **)&media_source->pd); @@ -1879,7 +1907,7 @@ static HRESULT session_append_node(struct media_session *session, IMFTopologyNod &IID_IMFVideoSampleAllocator, (void **)&topo_node->u.sink.allocator))) { if (FAILED(hr = IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator, - 2, media_type))) + 4, media_type))) { WARN("Failed to initialize sample allocator for the stream, hr %#lx.\n", hr); } @@ -2005,9 +2033,8 @@ static HRESULT session_set_current_topology(struct media_session *session, IMFTo return hr; } - session->source_shutdown_handled = FALSE; - - session_collect_nodes(session); + if (FAILED(hr = session_collect_nodes(session))) + return hr; LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) { @@ -2085,10 +2112,14 @@ static void session_set_topology(struct media_session *session, DWORD flags, IMF { hr = session_bind_output_nodes(topology); + IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE); + if (SUCCEEDED(hr)) hr = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */); if (SUCCEEDED(hr)) hr = session_init_media_types(resolved_topology); + else + WARN("failed to load topology %p, hr %#lx.\n", topology, hr); if (SUCCEEDED(hr)) { @@ -2118,7 +2149,7 @@ static void session_set_topology(struct media_session *session, DWORD flags, IMF session_raise_topology_set(session, topology, hr); /* With no current topology set it right away, otherwise queue. */ - if (topology) + if (SUCCEEDED(hr) && topology) { struct queued_topology *queued_topology; @@ -2791,39 +2822,49 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, EnterCriticalSection(&session->cs); - if (session->presentation.flags & SESSION_FLAG_PENDING_COMMAND) - { - WARN("session %p command is in progress, waiting for it to complete.\n", session); - LeaveCriticalSection(&session->cs); - return S_OK; - } - + assert( session->command_state == COMMAND_STATE_SUBMITTED ); list_remove(&op->entry); - session->presentation.flags |= SESSION_FLAG_PENDING_COMMAND; switch (op->command) { case SESSION_CMD_CLEAR_TOPOLOGIES: + session->presentation.flags &= ~SESSION_FLAG_SOURCE_SHUTDOWN; session_clear_topologies(session); break; case SESSION_CMD_SET_TOPOLOGY: + session->presentation.flags &= ~SESSION_FLAG_SOURCE_SHUTDOWN; session_set_topology(session, op->set_topology.flags, op->set_topology.topology); session_command_complete(session); break; case SESSION_CMD_START: - session_start(session, &op->start.time_format, &op->start.start_position); + if (session->presentation.flags & SESSION_FLAG_SOURCE_SHUTDOWN) + session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL); + else + session_start(session, &op->start.time_format, &op->start.start_position); break; case SESSION_CMD_PAUSE: - session_pause(session); + if (session->presentation.flags & SESSION_FLAG_SOURCE_SHUTDOWN) + session_command_complete_with_event(session, MESessionPaused, MF_E_SHUTDOWN, NULL); + else + session_pause(session); break; case SESSION_CMD_STOP: - session_stop(session); + if (session->presentation.flags & SESSION_FLAG_SOURCE_SHUTDOWN) + session_command_complete_with_event(session, MESessionStopped, MF_E_SHUTDOWN, NULL); + else + session_stop(session); break; case SESSION_CMD_CLOSE: - session_close(session); + if (session->presentation.flags & SESSION_FLAG_SOURCE_SHUTDOWN) + session_command_complete_with_event(session, MESessionClosed, MF_E_SHUTDOWN, NULL); + else + session_close(session); break; case SESSION_CMD_SET_RATE: - session_set_rate(session, op->set_rate.thin, op->set_rate.rate); + if (session->presentation.flags & SESSION_FLAG_SOURCE_SHUTDOWN) + session_command_complete_with_event(session, MESessionRateChanged, MF_E_SHUTDOWN, NULL); + else + session_set_rate(session, op->set_rate.thin, op->set_rate.rate); break; case SESSION_CMD_SHUTDOWN: session_clear_command_list(session); @@ -2914,105 +2955,52 @@ static const IMFAsyncCallbackVtbl session_sa_ready_callback_vtbl = static void session_handle_source_shutdown(struct media_session *session) { - BOOL finalize_sinks; - EnterCriticalSection(&session->cs); - /* Shutdown may be notified via a dedicated callback or by Begin/EndGetEvent() failure. */ - if (session->source_shutdown_handled) + switch (session->command_state) { - LeaveCriticalSection(&session->cs); - return; - } - session->source_shutdown_handled = TRUE; - - finalize_sinks = session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS; - - /* When stopping the session, MESessionStopped is sent without waiting - * for MESourceStopped, so we need do nothing in that case. */ - switch (session->state) - { - case SESSION_STATE_STARTING_SOURCES: - case SESSION_STATE_RESTARTING_SOURCES: - case SESSION_STATE_PREROLLING_SINKS: - case SESSION_STATE_STARTING_SINKS: - IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStarted, &GUID_NULL, - MF_E_INVALIDREQUEST, NULL); + case COMMAND_STATE_STARTING_SOURCES: + case COMMAND_STATE_RESTARTING_SOURCES: + case COMMAND_STATE_PREROLLING_SINKS: + case COMMAND_STATE_STARTING_SINKS: + session_clear_presentation(session); + session->state = SESSION_STATE_STOPPED; + session_command_complete_with_event(session, MESessionStarted, MF_E_INVALIDREQUEST, NULL); break; - case SESSION_STATE_STOPPING_SINKS: - case SESSION_STATE_STOPPING_SOURCES: - if (!finalize_sinks) - IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionStopped, &GUID_NULL, - MF_E_INVALIDREQUEST, NULL); + case COMMAND_STATE_PAUSING_SINKS: + case COMMAND_STATE_PAUSING_SOURCES: + session_clear_presentation(session); + session->state = SESSION_STATE_STOPPED; + session_command_complete_with_event(session, MESessionPaused, MF_E_SHUTDOWN, NULL); break; - default: + case COMMAND_STATE_ENDING_STREAMS: + case COMMAND_STATE_ENDING_SINKS: + case COMMAND_STATE_STOPPING_SINKS: + case COMMAND_STATE_STOPPING_SOURCES: + session_clear_presentation(session); + session->state = SESSION_STATE_STOPPED; + session_command_complete_with_event(session, MESessionStopped, MF_E_SHUTDOWN, NULL); + break; + case COMMAND_STATE_CLOSING_SINKS: + case COMMAND_STATE_CLOSING_SOURCES: + case COMMAND_STATE_FINALIZING_SINKS: + session_clear_presentation(session); + session->state = SESSION_STATE_CLOSED; + session_command_complete_with_event(session, MESessionClosed, MF_E_SHUTDOWN, NULL); + break; + case COMMAND_STATE_COMPLETE: + if (session->state == SESSION_STATE_STARTED || session->state == SESSION_STATE_PAUSED) + session_set_stopped(session, MESessionStopped, MF_E_SHUTDOWN); + break; + case COMMAND_STATE_SUBMITTED: break; } - if (session->state != SESSION_STATE_CLOSED) - { - if (finalize_sinks) - session_finalize_sinks(session); - else - session_reset(session); - } + session->presentation.flags |= SESSION_FLAG_SOURCE_SHUTDOWN; LeaveCriticalSection(&session->cs); } -static HRESULT WINAPI session_shutdown_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IMFAsyncCallback) - || IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFAsyncCallback_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI session_shutdown_callback_AddRef(IMFAsyncCallback *iface) -{ - struct media_session *session = impl_from_shutdown_callback_IMFAsyncCallback(iface); - return IMFMediaSession_AddRef(&session->IMFMediaSession_iface); -} - -static ULONG WINAPI session_shutdown_callback_Release(IMFAsyncCallback *iface) -{ - struct media_session *session = impl_from_shutdown_callback_IMFAsyncCallback(iface); - return IMFMediaSession_Release(&session->IMFMediaSession_iface); -} - -static HRESULT WINAPI session_shutdown_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) -{ - return E_NOTIMPL; -} - -static HRESULT WINAPI session_shutdown_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) -{ - struct media_session *session = impl_from_shutdown_callback_IMFAsyncCallback(iface); - IMFMediaSource *source = (IMFMediaSource *)IMFAsyncResult_GetStateNoAddRef(result); - - TRACE("Source %p was shut down.\n", source); - - session_handle_source_shutdown(session); - - return S_OK; -} - -static const IMFAsyncCallbackVtbl session_shutdown_callback_vtbl = -{ - session_shutdown_callback_QueryInterface, - session_shutdown_callback_AddRef, - session_shutdown_callback_Release, - session_shutdown_callback_GetParameters, - session_shutdown_callback_Invoke, -}; - static HRESULT WINAPI session_events_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFAsyncCallback) || @@ -3198,6 +3186,7 @@ static void session_set_source_object_state(struct media_session *session, IUnkn struct media_source *src; struct media_sink *sink; enum object_state state; + struct topo_node *node; BOOL changed = FALSE; DWORD i, count; HRESULT hr; @@ -3235,25 +3224,26 @@ static void session_set_source_object_state(struct media_session *session, IUnkn if (!changed) return; - switch (session->state) + switch (session->command_state) { - case SESSION_STATE_STARTING_SOURCES: + case COMMAND_STATE_STARTING_SOURCES: if (!session_is_source_nodes_state(session, OBJ_STATE_STARTED)) break; session_set_topo_status(session, S_OK, MF_TOPOSTATUS_STARTED_SOURCE); - session_set_presentation_clock(session); - - /* If sinks are already started, start session immediately. This can happen when doing a - * seek from SESSION_STATE_STARTED */ - if (session_is_output_nodes_state(session, OBJ_STATE_STARTED) - && SUCCEEDED(session_start_clock(session))) + if (event_type == MESourceStarted || event_type == MEStreamStarted) { - session_set_started(session); - return; + LIST_FOR_EACH_ENTRY(node, &session->presentation.nodes, struct topo_node, entry) + { + if (node->type == MF_TOPOLOGY_TRANSFORM_NODE) + IMFTransform_ProcessMessage(node->object.transform, MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0); + } } + session_subscribe_sinks(session); + session_set_presentation_clock(session); + if ((session->presentation.flags & SESSION_FLAG_NEEDS_PREROLL) && session_is_output_nodes_state(session, OBJ_STATE_STOPPED)) { MFTIME preroll_time = 0; @@ -3286,17 +3276,42 @@ static void session_set_source_object_state(struct media_session *session, IUnkn } } } - session->state = SESSION_STATE_PREROLLING_SINKS; + session->command_state = COMMAND_STATE_PREROLLING_SINKS; + } + else + { + if (session->presentation.flags & SESSION_FLAG_RESTARTING) + { + session->presentation.flags &= ~SESSION_FLAG_RESTARTING; + session_flush_sinks(session); + } + + if (SUCCEEDED(hr = session_start_clock(session))) + { + /* If sinks are already started, start session immediately. This can happen when doing a + * seek from SESSION_STATE_STARTED (i.e. a seek without pause/stop) */ + if (session_is_output_nodes_state(session, OBJ_STATE_STARTED)) + session_set_started(session); + else + session->command_state = COMMAND_STATE_STARTING_SINKS; + } + else + { + WARN("Failed to start session clock %p, hr %#lx.\n", session, hr); + session_command_complete_with_event(session, MESessionStarted, hr, NULL); + } } - else if (SUCCEEDED(session_start_clock(session))) - session->state = SESSION_STATE_STARTING_SINKS; break; - case SESSION_STATE_RESTARTING_SOURCES: + case COMMAND_STATE_RESTARTING_SOURCES: if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED)) break; - session_flush_nodes(session); + session->presentation.flags |= SESSION_FLAG_RESTARTING; + session_reset_transforms(session, TRUE); + session_flush_transforms(session); + session->state = SESSION_STATE_STOPPED; + session->command_state = COMMAND_STATE_STARTING_SOURCES; /* Start sources */ LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) @@ -3305,33 +3320,46 @@ static void session_set_source_object_state(struct media_session *session, IUnkn &session->presentation.time_format, &session->presentation.start_position))) { WARN("Failed to start media source %p, hr %#lx.\n", source->source, hr); - session_command_complete_with_event(session, MESessionStarted, hr, NULL); - return; + if (hr == MF_E_SHUTDOWN) + return session_handle_source_shutdown(session); + return session_command_complete_with_event(session, MESessionStarted, hr, NULL); } } - session->state = SESSION_STATE_STARTING_SOURCES; break; - case SESSION_STATE_PAUSING_SOURCES: + case COMMAND_STATE_PAUSING_SOURCES: if (!session_is_source_nodes_state(session, OBJ_STATE_PAUSED)) break; - session_set_paused(session, SESSION_STATE_PAUSED, S_OK); + session_set_paused(session, S_OK); break; - case SESSION_STATE_STOPPING_SOURCES: + case COMMAND_STATE_STOPPING_SOURCES: if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED)) break; session_flush_nodes(session); session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE); + session_set_stopped(session, MESessionStopped, S_OK); + break; + case COMMAND_STATE_CLOSING_SOURCES: + if (!session_is_source_nodes_state(session, OBJ_STATE_STOPPED)) + break; - if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS) - session_finalize_sinks(session); - else - session_set_stopped(session, S_OK); - + session_flush_nodes(session); + session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE); + session_finalize_sinks(session); + break; + case COMMAND_STATE_SUBMITTED: + case COMMAND_STATE_COMPLETE: + case COMMAND_STATE_PREROLLING_SINKS: + case COMMAND_STATE_STARTING_SINKS: + case COMMAND_STATE_PAUSING_SINKS: + case COMMAND_STATE_STOPPING_SINKS: + case COMMAND_STATE_ENDING_STREAMS: + case COMMAND_STATE_ENDING_SINKS: + case COMMAND_STATE_CLOSING_SINKS: + case COMMAND_STATE_FINALIZING_SINKS: + WARN("Ignoring source state change in command state %#x\n", session->command_state); break; - default: - ; } } @@ -3349,26 +3377,26 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre if (!(changed = session_set_node_object_state(session, (IUnknown *)stream, MF_TOPOLOGY_OUTPUT_NODE, state))) return; - switch (session->state) + switch (session->command_state) { - case SESSION_STATE_PREROLLING_SINKS: + case COMMAND_STATE_PREROLLING_SINKS: if (!session_is_output_nodes_state(session, OBJ_STATE_PREROLLED)) break; if (SUCCEEDED(session_start_clock(session))) - session->state = SESSION_STATE_STARTING_SINKS; + session->command_state = COMMAND_STATE_STARTING_SINKS; break; - case SESSION_STATE_STARTING_SINKS: + case COMMAND_STATE_STARTING_SINKS: if (!session_is_output_nodes_state(session, OBJ_STATE_STARTED)) break; session_set_started(session); break; - case SESSION_STATE_PAUSING_SINKS: + case COMMAND_STATE_PAUSING_SINKS: if (!session_is_output_nodes_state(session, OBJ_STATE_PAUSED)) break; - session->state = SESSION_STATE_PAUSING_SOURCES; + session->command_state = COMMAND_STATE_PAUSING_SOURCES; LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { @@ -3377,48 +3405,77 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre } if (FAILED(hr)) - session_set_paused(session, SESSION_STATE_PAUSED, hr); + session_set_paused(session, hr); break; - case SESSION_STATE_STOPPING_SINKS: + case COMMAND_STATE_ENDING_SINKS: if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED)) break; - session->state = SESSION_STATE_STOPPING_SOURCES; + LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) + IMFMediaSource_Stop(source->source); + + session_set_stopped(session, MESessionEnded, S_OK); + break; + case COMMAND_STATE_STOPPING_SINKS: + if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED)) + break; + + session->command_state = COMMAND_STATE_STOPPING_SOURCES; LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) - { - if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION) - IMFMediaSource_Stop(source->source); - else if (FAILED(hr = IMFMediaSource_Stop(source->source))) + if (FAILED(hr = IMFMediaSource_Stop(source->source))) break; - } - if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION) - session_set_stopped(session, hr); - else if (FAILED(hr)) - { - if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS) - session_set_closed(session, hr); - else - session_set_stopped(session, hr); - } + if (FAILED(hr)) + session_set_stopped(session, MESessionStopped, hr); + break; + case COMMAND_STATE_CLOSING_SINKS: + if (!session_is_output_nodes_state(session, OBJ_STATE_STOPPED)) + break; + + session->command_state = COMMAND_STATE_CLOSING_SOURCES; + + LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) + if (FAILED(hr = IMFMediaSource_Stop(source->source))) + break; + if (FAILED(hr)) + session_set_closed(session, hr); + break; + case COMMAND_STATE_SUBMITTED: + case COMMAND_STATE_COMPLETE: + case COMMAND_STATE_RESTARTING_SOURCES: + case COMMAND_STATE_STARTING_SOURCES: + case COMMAND_STATE_PAUSING_SOURCES: + case COMMAND_STATE_ENDING_STREAMS: + case COMMAND_STATE_STOPPING_SOURCES: + case COMMAND_STATE_CLOSING_SOURCES: + case COMMAND_STATE_FINALIZING_SINKS: + WARN("Ignoring sink state change in command state %#x\n", session->command_state); break; - default: - ; } } static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform, DWORD output, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample) { + struct transform_stream *stream = &transform->u.transform.outputs[output]; + DWORD buffer_size, sample_size, input; IMFMediaBuffer *buffer = NULL; struct topo_node *topo_node; - unsigned int buffer_size; - DWORD input; HRESULT hr; + buffer_size = max(stream_info->cbSize, stream->min_buffer_size); + if ((*sample = stream->allocated_sample)) + { + stream->allocated_sample = NULL; + if (SUCCEEDED(IMFSample_GetTotalLength(*sample, &sample_size)) && sample_size >= buffer_size) + return S_OK; + IMFSample_Release(*sample); + *sample = NULL; + } + if (!(topo_node = session_get_topo_node_output(session, transform, output, &input))) { WARN("Failed to node %p/%lu output.\n", transform, output); @@ -3431,8 +3488,6 @@ static HRESULT transform_get_external_output_sample(const struct media_session * } else { - buffer_size = max(stream_info->cbSize, transform->u.transform.outputs[output].min_buffer_size); - hr = MFCreateAlignedMemoryBuffer(buffer_size, stream_info->cbAlignment, &buffer); if (SUCCEEDED(hr)) hr = MFCreateSample(sample); @@ -3650,6 +3705,11 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, if (FAILED(hr = transform_stream_push_sample(stream, buffers[i].pSample))) WARN("Failed to queue output sample, hr %#lx\n", hr); } + else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && !stream->allocated_sample) + { + stream->allocated_sample = buffers[i].pSample; + buffers[i].pSample = NULL; + } } done: @@ -3690,13 +3750,32 @@ static HRESULT transform_node_push_sample(const struct media_session *session, s struct transform_stream *stream = &topo_node->u.transform.inputs[input]; UINT id = transform_node_get_stream_id(topo_node, FALSE, input); IMFTransform *transform = topo_node->object.transform; + MFTIME pts, clocktime; + IMFMediaType *type; + GUID major_type; + const char *sgi; HRESULT hr; if (sample) { - hr = IMFTransform_ProcessInput(transform, id, sample, 0); - if (hr == MF_E_NOTACCEPTING) - hr = transform_stream_push_sample(stream, sample); + /* HACK: VRChat (438100) requires audio packets that are late to be dropped prior to being passed to an MFT */ + if((sgi = getenv("SteamGameId")) && !strcmp(sgi, "438100") && + SUCCEEDED(IMFTransform_GetOutputCurrentType(transform, id, &type)) && + SUCCEEDED(IMFMediaType_GetMajorType(type, &major_type)) && + IsEqualGUID(&major_type, &MFMediaType_Audio) && + SUCCEEDED(IMFSample_GetSampleTime(sample, &pts)) && pts != MINLONGLONG && + SUCCEEDED(IMFPresentationClock_GetTime(session->clock, &clocktime)) && + clocktime > pts) + { + hr = S_OK; + FIXME("dropping audio sample clocktime %I64d pts %I64d jitter: %I64d\n", clocktime, pts, clocktime - pts); + } + else + { + hr = IMFTransform_ProcessInput(transform, id, sample, 0); + if (hr == MF_E_NOTACCEPTING) + hr = transform_stream_push_sample(stream, sample); + } } else { @@ -3755,15 +3834,27 @@ static HRESULT transform_node_handle_format_change(struct media_session *session static HRESULT session_handle_format_change(struct media_session *session, struct topo_node *topo_node, UINT input, IMFMediaType *media_type) { + IMFMediaTypeHandler *handler; HRESULT hr; switch (topo_node->type) { case MF_TOPOLOGY_OUTPUT_NODE: - if (!topo_node->u.sink.allocator) - return S_OK; - if (SUCCEEDED(hr = IMFVideoSampleAllocator_UninitializeSampleAllocator(topo_node->u.sink.allocator))) - hr = IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator, 4, media_type); + /* For H.264, the sink's input media type must be set to the aligned frame size + * before MESessionStarted is sent. The decoder sends MF_E_TRANSFORM_STREAM_CHANGE + * to trigger a refresh of its output type once the aligned frame size is known. + * This occurs before any call to ProcessOutput() can succeed on the transform. + * Satisfactory is known to use the sink frame size. */ + if (FAILED(hr = topology_node_get_type_handler(topo_node->node, 0, FALSE, &handler))) + WARN("Failed to get type handler, hr %#lx.\n", hr); + else if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, media_type))) + WARN("Failed to set type, hr %#lx.\n", hr); + + if (SUCCEEDED(hr) && topo_node->u.sink.allocator) + { + if (SUCCEEDED(hr = IMFVideoSampleAllocator_UninitializeSampleAllocator(topo_node->u.sink.allocator))) + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node->u.sink.allocator, 4, media_type); + } return hr; case MF_TOPOLOGY_TRANSFORM_NODE: @@ -4127,14 +4218,14 @@ static void session_nodes_unset_mask(struct media_session *session, MF_TOPOLOGY_ static void session_raise_end_of_presentation(struct media_session *session) { - if (!(session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM))) + if (!session_nodes_is_mask_set(session, MF_TOPOLOGY_SOURCESTREAM_NODE, TOPO_NODE_END_OF_STREAM)) return; - if (!(session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)) + if (session->command_state == COMMAND_STATE_COMPLETE) { if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION)) { - session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION | SESSION_FLAG_PENDING_COMMAND; + session->command_state = COMMAND_STATE_ENDING_STREAMS; IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL); } } @@ -4177,6 +4268,7 @@ static void session_handle_end_of_presentation(struct media_session *session, IM static void session_sink_stream_marker(struct media_session *session, IMFStreamSink *stream_sink) { struct topo_node *node; + HRESULT hr; if (!(node = session_get_node_object(session, (IUnknown *)stream_sink, MF_TOPOLOGY_OUTPUT_NODE)) || node->flags & TOPO_NODE_END_OF_STREAM) @@ -4186,12 +4278,17 @@ static void session_sink_stream_marker(struct media_session *session, IMFStreamS node->flags |= TOPO_NODE_END_OF_STREAM; - if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION && + if (session->command_state == COMMAND_STATE_ENDING_STREAMS && session_nodes_is_mask_set(session, MF_TOPOLOGY_OUTPUT_NODE, TOPO_NODE_END_OF_STREAM)) { session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED); session_set_caps(session, session->caps & ~MFSESSIONCAP_PAUSE); - session_stop(session); + + IMFPresentationClock_GetTime(session->clock, &session->presentation.clock_stop_time); + if (SUCCEEDED(hr = IMFPresentationClock_Stop(session->clock))) + session->command_state = COMMAND_STATE_ENDING_SINKS; + else + session_set_stopped(session, MESessionEnded, hr); } } @@ -4234,7 +4331,7 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event))) { - if (hr == MF_E_SHUTDOWN) + if (hr == MF_E_SHUTDOWN && session_get_media_source(session, (IMFMediaSource *)event_source)) { session_handle_source_shutdown(session); } @@ -4430,6 +4527,16 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM } break; + + case MEError: + /* Wine-specific extension */ + EnterCriticalSection(&session->cs); + if (SUCCEEDED(IMFMediaEvent_GetStatus(event, &hr)) && hr == MF_E_SHUTDOWN && + session_get_media_source(session, (IMFMediaSource *)event_source)) + session_handle_source_shutdown(session); + LeaveCriticalSection(&session->cs); + break; + default: ; } @@ -4440,7 +4547,7 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source))) { - if (hr == MF_E_SHUTDOWN) + if (hr == MF_E_SHUTDOWN && session_get_media_source(session, (IMFMediaSource *)event_source)) { session_handle_source_shutdown(session); } @@ -4713,6 +4820,17 @@ static ULONG WINAPI session_rate_control_Release(IMFRateControl *iface) return IMFMediaSession_Release(&session->IMFMediaSession_iface); } +static BOOL allow_rate_zero(void) +{ + static int allow = -1; + if (allow == -1) + { + const char *sgi = getenv("SteamGameId"); + allow = sgi && !strcmp(sgi, "2111630") /* JR East Train Simulator */ ; + } + return allow; +} + static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate) { struct media_session *session = impl_session_from_IMFRateControl(iface); @@ -4721,6 +4839,13 @@ static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL t TRACE("%p, %d, %f.\n", iface, thin, rate); + if (!rate && !allow_rate_zero()) + { + /* The Anacrusis fails to play its video if we succeed here */ + ERR("Scrubbing not implemented!\n"); + return E_NOTIMPL; + } + if (FAILED(hr = create_session_op(SESSION_CMD_SET_RATE, &op))) return hr; @@ -4737,7 +4862,10 @@ static HRESULT WINAPI session_rate_control_GetRate(IMFRateControl *iface, BOOL * TRACE("%p, %p, %p.\n", iface, thin, rate); - return IMFRateControl_GetRate(session->clock_rate_control, thin, rate); + if (thin) + *thin = session->presentation.thin_committed; + + return IMFRateControl_GetRate(session->clock_rate_control, NULL, rate); } static const IMFRateControlVtbl session_rate_control_vtbl = @@ -4816,7 +4944,6 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses object->IMFTopologyNodeAttributeEditor_iface.lpVtbl = &node_attribute_editor_vtbl; object->commands_callback.lpVtbl = &session_commands_callback_vtbl; object->sa_ready_callback.lpVtbl = &session_sa_ready_callback_vtbl; - object->shutdown_callback.lpVtbl = &session_shutdown_callback_vtbl; object->events_callback.lpVtbl = &session_events_callback_vtbl; object->sink_finalizer_callback.lpVtbl = &session_sink_finalizer_callback_vtbl; object->refcount = 1; @@ -4886,6 +5013,8 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses goto failed; } + session_clear_presentation(object); + *session = &object->IMFMediaSession_iface; return S_OK; diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 73526802b635..b669c7c894ec 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -275,11 +275,11 @@ static void init_sink_node(IMFStreamSink *stream_sink, MF_CONNECT_METHOD method, } } -DEFINE_EXPECT(test_source_BeginGetEvent); -DEFINE_EXPECT(test_source_QueueEvent); -DEFINE_EXPECT(test_source_Start); +DEFINE_EXPECT(test_stub_source_BeginGetEvent); +DEFINE_EXPECT(test_stub_source_QueueEvent); +DEFINE_EXPECT(test_stub_source_Start); -struct test_source +struct test_stub_source { IMFMediaSource IMFMediaSource_iface; LONG refcount; @@ -287,12 +287,12 @@ struct test_source IMFPresentationDescriptor *pd; }; -static struct test_source *impl_from_IMFMediaSource(IMFMediaSource *iface) +static struct test_stub_source *impl_from_IMFMediaSource(IMFMediaSource *iface) { - return CONTAINING_RECORD(iface, struct test_source, IMFMediaSource_iface); + return CONTAINING_RECORD(iface, struct test_stub_source, IMFMediaSource_iface); } -static HRESULT WINAPI test_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) +static HRESULT WINAPI test_stub_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) { if (IsEqualIID(riid, &IID_IMFMediaSource) || IsEqualIID(riid, &IID_IMFMediaEventGenerator) @@ -310,15 +310,15 @@ static HRESULT WINAPI test_source_QueryInterface(IMFMediaSource *iface, REFIID r return S_OK; } -static ULONG WINAPI test_source_AddRef(IMFMediaSource *iface) +static ULONG WINAPI test_stub_source_AddRef(IMFMediaSource *iface) { - struct test_source *source = impl_from_IMFMediaSource(iface); + struct test_stub_source *source = impl_from_IMFMediaSource(iface); return InterlockedIncrement(&source->refcount); } -static ULONG WINAPI test_source_Release(IMFMediaSource *iface) +static ULONG WINAPI test_stub_source_Release(IMFMediaSource *iface) { - struct test_source *source = impl_from_IMFMediaSource(iface); + struct test_stub_source *source = impl_from_IMFMediaSource(iface); ULONG refcount = InterlockedDecrement(&source->refcount); if (!refcount) @@ -330,92 +330,92 @@ static ULONG WINAPI test_source_Release(IMFMediaSource *iface) return refcount; } -static HRESULT WINAPI test_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) +static HRESULT WINAPI test_stub_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) { ok(0, "Unexpected call.\n"); return E_NOTIMPL; } -static HRESULT WINAPI test_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) +static HRESULT WINAPI test_stub_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) { - struct test_source *source = impl_from_IMFMediaSource(iface); - CHECK_EXPECT(test_source_BeginGetEvent); + struct test_stub_source *source = impl_from_IMFMediaSource(iface); + CHECK_EXPECT(test_stub_source_BeginGetEvent); return source->begin_get_event_res; } -static HRESULT WINAPI test_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) +static HRESULT WINAPI test_stub_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) { ok(0, "Unexpected call.\n"); return E_NOTIMPL; } -static HRESULT WINAPI test_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, +static HRESULT WINAPI test_stub_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) { - CHECK_EXPECT(test_source_QueueEvent); + CHECK_EXPECT(test_stub_source_QueueEvent); return E_NOTIMPL; } -static HRESULT WINAPI test_source_GetCharacteristics(IMFMediaSource *iface, DWORD *flags) +static HRESULT WINAPI test_stub_source_GetCharacteristics(IMFMediaSource *iface, DWORD *flags) { *flags = 0; return S_OK; } -static HRESULT WINAPI test_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **pd) +static HRESULT WINAPI test_stub_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **pd) { - struct test_source *source = impl_from_IMFMediaSource(iface); + struct test_stub_source *source = impl_from_IMFMediaSource(iface); return IMFPresentationDescriptor_Clone(source->pd, pd); } -static HRESULT WINAPI test_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *pd, const GUID *time_format, +static HRESULT WINAPI test_stub_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *pd, const GUID *time_format, const PROPVARIANT *start_position) { - CHECK_EXPECT(test_source_Start); + CHECK_EXPECT(test_stub_source_Start); return E_NOTIMPL; } -static HRESULT WINAPI test_source_Stop(IMFMediaSource *iface) +static HRESULT WINAPI test_stub_source_Stop(IMFMediaSource *iface) { ok(0, "Unexpected call.\n"); return E_NOTIMPL; } -static HRESULT WINAPI test_source_Pause(IMFMediaSource *iface) +static HRESULT WINAPI test_stub_source_Pause(IMFMediaSource *iface) { ok(0, "Unexpected call.\n"); return E_NOTIMPL; } -static HRESULT WINAPI test_source_Shutdown(IMFMediaSource *iface) +static HRESULT WINAPI test_stub_source_Shutdown(IMFMediaSource *iface) { ok(0, "Unexpected call.\n"); return E_NOTIMPL; } -static const IMFMediaSourceVtbl test_source_vtbl = -{ - test_source_QueryInterface, - test_source_AddRef, - test_source_Release, - test_source_GetEvent, - test_source_BeginGetEvent, - test_source_EndGetEvent, - test_source_QueueEvent, - test_source_GetCharacteristics, - test_source_CreatePresentationDescriptor, - test_source_Start, - test_source_Stop, - test_source_Pause, - test_source_Shutdown, +static const IMFMediaSourceVtbl test_stub_source_vtbl = +{ + test_stub_source_QueryInterface, + test_stub_source_AddRef, + test_stub_source_Release, + test_stub_source_GetEvent, + test_stub_source_BeginGetEvent, + test_stub_source_EndGetEvent, + test_stub_source_QueueEvent, + test_stub_source_GetCharacteristics, + test_stub_source_CreatePresentationDescriptor, + test_stub_source_Start, + test_stub_source_Stop, + test_stub_source_Pause, + test_stub_source_Shutdown, }; -static IMFMediaSource *create_test_source(IMFPresentationDescriptor *pd) +static IMFMediaSource *create_test_stub_source(IMFPresentationDescriptor *pd) { - struct test_source *source; + struct test_stub_source *source; source = calloc(1, sizeof(*source)); - source->IMFMediaSource_iface.lpVtbl = &test_source_vtbl; + source->IMFMediaSource_iface.lpVtbl = &test_stub_source_vtbl; source->refcount = 1; source->begin_get_event_res = E_NOTIMPL; IMFPresentationDescriptor_AddRef((source->pd = pd)); @@ -1458,11 +1458,37 @@ static const IMFMediaStreamVtbl test_media_stream_vtbl = test_media_stream_RequestSample, }; +static struct test_media_stream *create_test_stream(DWORD stream_index, IMFMediaSource *source) +{ + struct test_media_stream *stream; + IMFPresentationDescriptor *pd; + BOOL selected; + HRESULT hr; + + stream = calloc(1, sizeof(*stream)); + stream->IMFMediaStream_iface.lpVtbl = &test_media_stream_vtbl; + stream->refcount = 1; + hr = MFCreateEventQueue(&stream->event_queue); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + stream->source = source; + IMFMediaSource_AddRef(stream->source); + stream->is_new = TRUE; + + IMFMediaSource_CreatePresentationDescriptor(source, &pd); + IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, stream_index, &selected, &stream->sd); + IMFPresentationDescriptor_Release(pd); + + return stream; +} + #define TEST_SOURCE_NUM_STREAMS 3 -struct test_seek_source +struct test_source { IMFMediaSource IMFMediaSource_iface; + IMFGetService IMFGetService_iface; + IMFRateSupport IMFRateSupport_iface; + IMFRateControl IMFRateControl_iface; IMFMediaEventQueue *event_queue; IMFPresentationDescriptor *pd; struct test_media_stream *streams[TEST_SOURCE_NUM_STREAMS]; @@ -1470,22 +1496,33 @@ struct test_seek_source unsigned stream_count; CRITICAL_SECTION cs; BOOL seekable; + BOOL thinnable; + BOOL thin; + float rate; LONG refcount; }; -static struct test_seek_source *impl_test_seek_source_from_IMFMediaSource(IMFMediaSource *iface) +static struct test_source *impl_test_source_from_IMFMediaSource(IMFMediaSource *iface) { - return CONTAINING_RECORD(iface, struct test_seek_source, IMFMediaSource_iface); + return CONTAINING_RECORD(iface, struct test_source, IMFMediaSource_iface); } -static HRESULT WINAPI test_seek_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) +static HRESULT WINAPI test_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) { + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); + if (IsEqualIID(riid, &IID_IMFMediaSource) || IsEqualIID(riid, &IID_IMFMediaEventGenerator) || IsEqualIID(riid, &IID_IUnknown)) { *out = iface; } + else if (IsEqualIID(riid, &IID_IMFGetService)) + { + IMFGetService_AddRef(&source->IMFGetService_iface); + *out = &source->IMFGetService_iface; + return S_OK; + } else { *out = NULL; @@ -1496,15 +1533,15 @@ static HRESULT WINAPI test_seek_source_QueryInterface(IMFMediaSource *iface, REF return S_OK; } -static ULONG WINAPI test_seek_source_AddRef(IMFMediaSource *iface) +static ULONG WINAPI test_source_AddRef(IMFMediaSource *iface) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); return InterlockedIncrement(&source->refcount); } -static ULONG WINAPI test_seek_source_Release(IMFMediaSource *iface) +static ULONG WINAPI test_source_Release(IMFMediaSource *iface) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); ULONG refcount = InterlockedDecrement(&source->refcount); if (!refcount) @@ -1516,34 +1553,34 @@ static ULONG WINAPI test_seek_source_Release(IMFMediaSource *iface) return refcount; } -static HRESULT WINAPI test_seek_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) +static HRESULT WINAPI test_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event); } -static HRESULT WINAPI test_seek_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) +static HRESULT WINAPI test_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state); } -static HRESULT WINAPI test_seek_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) +static HRESULT WINAPI test_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event); } -static HRESULT WINAPI test_seek_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, +static HRESULT WINAPI test_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value); } -static HRESULT WINAPI test_seek_source_GetCharacteristics(IMFMediaSource *iface, DWORD *flags) +static HRESULT WINAPI test_source_GetCharacteristics(IMFMediaSource *iface, DWORD *flags) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); if (source->seekable) *flags = MFMEDIASOURCE_CAN_PAUSE | MFMEDIASOURCE_CAN_SEEK; @@ -1552,9 +1589,9 @@ static HRESULT WINAPI test_seek_source_GetCharacteristics(IMFMediaSource *iface, return S_OK; } -static HRESULT WINAPI test_seek_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **pd) +static HRESULT WINAPI test_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **pd) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); IMFStreamDescriptor *sds[ARRAY_SIZE(source->streams)]; IMFMediaType *media_type; HRESULT hr = S_OK; @@ -1616,10 +1653,10 @@ static BOOL is_stream_selected(IMFPresentationDescriptor *pd, DWORD index) return selected; } -static HRESULT WINAPI test_seek_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *pd, const GUID *time_format, +static HRESULT WINAPI test_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *pd, const GUID *time_format, const PROPVARIANT *start_position) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); MediaEventType event_type; PROPVARIANT var; HRESULT hr; @@ -1670,9 +1707,9 @@ static HRESULT WINAPI test_seek_source_Start(IMFMediaSource *iface, IMFPresentat return S_OK; } -static HRESULT WINAPI test_seek_source_Stop(IMFMediaSource *iface) +static HRESULT WINAPI test_source_Stop(IMFMediaSource *iface) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); MediaEventType event_type; HRESULT hr; int i; @@ -1703,9 +1740,9 @@ static HRESULT WINAPI test_seek_source_Stop(IMFMediaSource *iface) return S_OK; } -static HRESULT WINAPI test_seek_source_Pause(IMFMediaSource *iface) +static HRESULT WINAPI test_source_Pause(IMFMediaSource *iface) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); MediaEventType event_type; HRESULT hr; int i; @@ -1735,9 +1772,9 @@ static HRESULT WINAPI test_seek_source_Pause(IMFMediaSource *iface) return S_OK; } -static HRESULT WINAPI test_seek_source_Shutdown(IMFMediaSource *iface) +static HRESULT WINAPI test_source_Shutdown(IMFMediaSource *iface) { - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + struct test_source *source = impl_test_source_from_IMFMediaSource(iface); HRESULT hr; add_object_state(&actual_object_state_record, SOURCE_SHUTDOWN); @@ -1748,23 +1785,213 @@ static HRESULT WINAPI test_seek_source_Shutdown(IMFMediaSource *iface) return S_OK; } -static const IMFMediaSourceVtbl test_seek_source_vtbl = -{ - test_seek_source_QueryInterface, - test_seek_source_AddRef, - test_seek_source_Release, - test_seek_source_GetEvent, - test_seek_source_BeginGetEvent, - test_seek_source_EndGetEvent, - test_seek_source_QueueEvent, - test_seek_source_GetCharacteristics, - test_seek_source_CreatePresentationDescriptor, - test_seek_source_Start, - test_seek_source_Stop, - test_seek_source_Pause, - test_seek_source_Shutdown, +static const IMFMediaSourceVtbl test_source_vtbl = +{ + test_source_QueryInterface, + test_source_AddRef, + test_source_Release, + test_source_GetEvent, + test_source_BeginGetEvent, + test_source_EndGetEvent, + test_source_QueueEvent, + test_source_GetCharacteristics, + test_source_CreatePresentationDescriptor, + test_source_Start, + test_source_Stop, + test_source_Pause, + test_source_Shutdown, +}; + +static struct test_source *impl_test_source_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct test_source, IMFGetService_iface); +} + +static HRESULT WINAPI test_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct test_source *source = impl_test_source_from_IMFGetService(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI test_source_get_service_AddRef(IMFGetService *iface) +{ + struct test_source *source = impl_test_source_from_IMFGetService(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI test_source_get_service_Release(IMFGetService *iface) +{ + struct test_source *source = impl_test_source_from_IMFGetService(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI test_source_get_service_GetService(IMFGetService *iface, REFGUID service, + REFIID riid, void **obj) +{ + struct test_source *source = impl_test_source_from_IMFGetService(iface); + + if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE)) + { + if (IsEqualIID(riid, &IID_IMFRateSupport)) + { + IMFRateSupport_AddRef(&source->IMFRateSupport_iface); + *obj = &source->IMFRateSupport_iface; + return S_OK; + } + if (IsEqualIID(riid, &IID_IMFRateControl)) + { + IMFRateControl_AddRef(&source->IMFRateControl_iface); + *obj = &source->IMFRateControl_iface; + return S_OK; + } + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static const IMFGetServiceVtbl test_source_get_service_vtbl = +{ + test_source_get_service_QueryInterface, + test_source_get_service_AddRef, + test_source_get_service_Release, + test_source_get_service_GetService, +}; + +static struct test_source *impl_test_source_from_IMFRateSupport(IMFRateSupport *iface) +{ + return CONTAINING_RECORD(iface, struct test_source, IMFRateSupport_iface); +} + +static HRESULT WINAPI test_source_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj) +{ + struct test_source *source = impl_test_source_from_IMFRateSupport(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI test_source_rate_support_AddRef(IMFRateSupport *iface) +{ + struct test_source *source = impl_test_source_from_IMFRateSupport(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI test_source_rate_support_Release(IMFRateSupport *iface) +{ + struct test_source *source = impl_test_source_from_IMFRateSupport(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI test_source_rate_support_GetSlowestRate(IMFRateSupport *iface, + MFRATE_DIRECTION direction, BOOL thin, float *rate) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_source_rate_support_GetFastestRate(IMFRateSupport *iface, + MFRATE_DIRECTION direction, BOOL thin, float *rate) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, + float rate, float *nearest_rate) +{ + if (nearest_rate) *nearest_rate = rate; + return S_OK; +} + +static const IMFRateSupportVtbl test_source_rate_support_vtbl = +{ + test_source_rate_support_QueryInterface, + test_source_rate_support_AddRef, + test_source_rate_support_Release, + test_source_rate_support_GetSlowestRate, + test_source_rate_support_GetFastestRate, + test_source_rate_support_IsRateSupported, +}; + +static struct test_source *impl_test_source_from_IMFRateControl(IMFRateControl *iface) +{ + return CONTAINING_RECORD(iface, struct test_source, IMFRateControl_iface); +} + +static HRESULT WINAPI test_source_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj) +{ + struct test_source *source = impl_test_source_from_IMFRateControl(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI test_source_rate_control_AddRef(IMFRateControl *iface) +{ + struct test_source *source = impl_test_source_from_IMFRateControl(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI test_source_rate_control_Release(IMFRateControl *iface) +{ + struct test_source *source = impl_test_source_from_IMFRateControl(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI test_source_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate) +{ + struct test_source *source = impl_test_source_from_IMFRateControl(iface); + HRESULT hr; + if (thin && !source->thinnable) + return MF_E_THINNING_UNSUPPORTED; + EnterCriticalSection(&source->cs); + source->thin = thin; + source->rate = rate; + LeaveCriticalSection(&source->cs); + hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + return S_OK; +} + +static HRESULT WINAPI test_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate) +{ + struct test_source *source = impl_test_source_from_IMFRateControl(iface); + EnterCriticalSection(&source->cs); + *rate = source->rate; + if (thin) + *thin = source->thin; + LeaveCriticalSection(&source->cs); + return S_OK; +} + +static const IMFRateControlVtbl test_source_rate_control_vtbl = +{ + test_source_rate_control_QueryInterface, + test_source_rate_control_AddRef, + test_source_rate_control_Release, + test_source_rate_control_SetRate, + test_source_rate_control_GetRate, }; +static IMFMediaSource *create_test_source(BOOL seekable) +{ + struct test_source *source; + int i; + + source = calloc(1, sizeof(*source)); + source->IMFMediaSource_iface.lpVtbl = &test_source_vtbl; + source->IMFGetService_iface.lpVtbl = &test_source_get_service_vtbl; + source->IMFRateSupport_iface.lpVtbl = &test_source_rate_support_vtbl; + source->IMFRateControl_iface.lpVtbl = &test_source_rate_control_vtbl; + source->refcount = 1; + source->stream_count = 1; + source->seekable = seekable; + source->thinnable = FALSE; + source->thin = FALSE; + source->rate = 1.0; + MFCreateEventQueue(&source->event_queue); + InitializeCriticalSection(&source->cs); + for (i = 0; i < source->stream_count; ++i) + source->streams[i] = create_test_stream(i, &source->IMFMediaSource_iface); + + return &source->IMFMediaSource_iface; +} + static HRESULT WINAPI test_seek_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFClockStateSink) || @@ -1831,47 +2058,6 @@ static const IMFClockStateSinkVtbl test_seek_clock_sink_vtbl = test_seek_clock_sink_OnClockSetRate, }; -static struct test_media_stream *create_test_stream(DWORD stream_index, IMFMediaSource *source) -{ - struct test_media_stream *stream; - IMFPresentationDescriptor *pd; - BOOL selected; - HRESULT hr; - - stream = calloc(1, sizeof(*stream)); - stream->IMFMediaStream_iface.lpVtbl = &test_media_stream_vtbl; - stream->refcount = 1; - hr = MFCreateEventQueue(&stream->event_queue); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - stream->source = source; - IMFMediaSource_AddRef(stream->source); - stream->is_new = TRUE; - - IMFMediaSource_CreatePresentationDescriptor(source, &pd); - IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, stream_index, &selected, &stream->sd); - IMFPresentationDescriptor_Release(pd); - - return stream; -} - -static IMFMediaSource *create_test_seek_source(BOOL seekable) -{ - struct test_seek_source *source; - int i; - - source = calloc(1, sizeof(*source)); - source->IMFMediaSource_iface.lpVtbl = &test_seek_source_vtbl; - source->refcount = 1; - source->stream_count = 1; - source->seekable = seekable; - MFCreateEventQueue(&source->event_queue); - InitializeCriticalSection(&source->cs); - for (i = 0; i < source->stream_count; ++i) - source->streams[i] = create_test_stream(i, &source->IMFMediaSource_iface); - - return &source->IMFMediaSource_iface; -} - static void test_media_session_events(void) { static const media_type_desc audio_float_44100 = @@ -1898,7 +2084,7 @@ static void test_media_session_events(void) struct test_stream_sink stream_sink = test_stream_sink; struct test_media_sink media_sink = test_media_sink; struct test_handler handler = test_handler; - struct test_source *source_impl; + struct test_stub_source *source_impl; IMFAsyncCallback *callback, *callback2; IMFMediaType *input_type, *output_type; IMFTopologyNode *src_node, *sink_node; @@ -2066,7 +2252,7 @@ static void test_media_session_events(void) hr = IMFMediaSession_SetTopology(session, 0, topology); ok(hr == MF_E_TOPO_MISSING_SOURCE, "Unexpected hr %#lx.\n", hr); - source = create_test_source(pd); + source = create_test_stub_source(pd); init_source_node(source, -1, src_node, pd, sd); hr = IMFMediaSession_SetTopology(session, 0, topology); @@ -2294,9 +2480,9 @@ static void test_media_session_events(void) source_impl->begin_get_event_res = 0x80001234; - SET_EXPECT(test_source_BeginGetEvent); - SET_EXPECT(test_source_QueueEvent); - SET_EXPECT(test_source_Start); + SET_EXPECT(test_stub_source_BeginGetEvent); + SET_EXPECT(test_stub_source_QueueEvent); + SET_EXPECT(test_stub_source_Start); propvar.vt = VT_EMPTY; hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); @@ -2307,8 +2493,8 @@ static void test_media_session_events(void) ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); PropVariantClear(&propvar); - CHECK_CALLED(test_source_BeginGetEvent); - CHECK_NOT_CALLED(test_source_Start); + CHECK_CALLED(test_stub_source_BeginGetEvent); + CHECK_NOT_CALLED(test_stub_source_Start); hr = IMFMediaSession_ClearTopologies(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -2320,9 +2506,9 @@ static void test_media_session_events(void) source_impl->begin_get_event_res = E_NOTIMPL; - CLEAR_CALLED(test_source_BeginGetEvent); - CLEAR_CALLED(test_source_QueueEvent); - CLEAR_CALLED(test_source_Start); + CLEAR_CALLED(test_stub_source_BeginGetEvent); + CLEAR_CALLED(test_stub_source_QueueEvent); + CLEAR_CALLED(test_stub_source_Start); /* sometimes briefly leaking */ IMFMediaSession_Release(session); @@ -2343,9 +2529,9 @@ static void test_media_session_events(void) source_impl = impl_from_IMFMediaSource(source); source_impl->begin_get_event_res = S_OK; - SET_EXPECT(test_source_BeginGetEvent); - SET_EXPECT(test_source_QueueEvent); - SET_EXPECT(test_source_Start); + SET_EXPECT(test_stub_source_BeginGetEvent); + SET_EXPECT(test_stub_source_QueueEvent); + SET_EXPECT(test_stub_source_Start); propvar.vt = VT_EMPTY; hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); @@ -2356,8 +2542,8 @@ static void test_media_session_events(void) ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); PropVariantClear(&propvar); - CHECK_CALLED(test_source_BeginGetEvent); - CHECK_CALLED(test_source_Start); + CHECK_CALLED(test_stub_source_BeginGetEvent); + CHECK_CALLED(test_stub_source_Start); hr = IMFMediaSession_ClearTopologies(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -2369,9 +2555,9 @@ static void test_media_session_events(void) source_impl->begin_get_event_res = E_NOTIMPL; - CLEAR_CALLED(test_source_BeginGetEvent); - CLEAR_CALLED(test_source_QueueEvent); - CLEAR_CALLED(test_source_Start); + CLEAR_CALLED(test_stub_source_BeginGetEvent); + CLEAR_CALLED(test_stub_source_QueueEvent); + CLEAR_CALLED(test_stub_source_Start); /* sometimes briefly leaking */ IMFMediaSession_Release(session); @@ -6285,7 +6471,7 @@ static void test_media_session_Start(void) IMFSampleGrabberSinkCallback_Release(&grabber_callback->IMFSampleGrabberSinkCallback_iface); /* Unseekable media source */ - source = create_test_seek_source(FALSE); + source = create_test_source(FALSE); hr = IMFMediaSource_GetCharacteristics(source, &caps); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok((caps & MFMEDIASOURCE_CAN_SEEK) == 0, "Got unexpected caps %#lx.\n", caps); @@ -6356,7 +6542,7 @@ static void test_media_session_Start(void) { winetest_push_context("Test %d", initial_state); - source = create_test_seek_source(TRUE); + source = create_test_source(TRUE); callback = create_test_callback(TRUE); grabber_callback = impl_from_IMFSampleGrabberSinkCallback(create_test_grabber_callback()); @@ -6407,7 +6593,6 @@ static void test_media_session_Start(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event(session, callback, MESessionStarted, 5000, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine_if(initial_state == SOURCE_PAUSED) compare_object_states(&actual_object_state_record, &expected_object_state_records[initial_state]); hr = IMFMediaSession_Stop(session); @@ -6453,6 +6638,7 @@ static void test_media_session_source_shutdown(void) HRESULT hr; enum { + TEST_TOPOLOGY, TEST_START, TEST_RESTART, TEST_PAUSE, @@ -6465,7 +6651,7 @@ static void test_media_session_source_shutdown(void) /* These tests don't cover asynchronous shutdown, which is difficult to consistently test. */ - for (shutdown_point = TEST_START; shutdown_point <= TEST_CLOSE; ++shutdown_point) + for (shutdown_point = TEST_TOPOLOGY; shutdown_point <= TEST_CLOSE; ++shutdown_point) { winetest_push_context("Test %d", shutdown_point); @@ -6489,6 +6675,8 @@ static void test_media_session_source_shutdown(void) hr = MFCreateMediaSession(NULL, &session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); topology = create_test_topology(source, sink_activate, &duration); + if (shutdown_point == TEST_TOPOLOGY) + IMFMediaSource_Shutdown(source); hr = IMFMediaSession_SetTopology(session, 0, topology); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFTopology_Release(topology); @@ -6501,7 +6689,7 @@ static void test_media_session_source_shutdown(void) IMFMediaSource_Shutdown(source); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event(session, callback, MESessionStarted, 5000, &propvar); - ok(hr == (shutdown_point == TEST_START ? MF_E_INVALIDREQUEST : S_OK), "Unexpected hr %#lx.\n", hr); + ok(hr == (shutdown_point <= TEST_START ? MF_E_INVALIDREQUEST : S_OK), "Unexpected hr %#lx.\n", hr); switch (shutdown_point) { @@ -6799,6 +6987,148 @@ static void test_media_session_Close(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); } +static void test_media_session_thinning(void) +{ + media_type_desc video_rgb32_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + }; + IMFRateControl *rate_control, *source_rate_control; + IMFMediaSession *session; + IMFAsyncCallback *callback; + IMFMediaSource *source; + IMFTopology *topology; + IMFMediaType *output_type; + IMFActivate *sink_activate; + struct test_source *source_impl; + struct test_grabber_callback *grabber_callback; + PROPVARIANT propvar; + HRESULT hr; + float rate; + BOOL thin; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr); + + callback = create_test_callback(TRUE); + + source = create_test_source(FALSE); + source_impl = impl_test_source_from_IMFMediaSource(source); + + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr); + + hr = MFGetService((IUnknown *)session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, (void **)&rate_control); + ok(hr == S_OK, "Failed to get rate control interface, hr %#lx.\n", hr); + hr = MFGetService((IUnknown *) source, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, (void **)&source_rate_control); + ok(hr == S_OK, "Failed to get rate control interface, hr %#lx.\n", hr); + + grabber_callback = impl_from_IMFSampleGrabberSinkCallback(create_test_grabber_callback()); + hr = MFCreateMediaType(&output_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(output_type, video_rgb32_desc, -1); + hr = MFCreateSampleGrabberSinkActivate(output_type, &grabber_callback->IMFSampleGrabberSinkCallback_iface, &sink_activate); + ok(hr == S_OK, "Failed to create grabber sink, hr %#lx.\n", hr); + IMFMediaType_Release(output_type); + + topology = create_test_topology(source, sink_activate, NULL); + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopology_Release(topology); + IMFSampleGrabberSinkCallback_Release(&grabber_callback->IMFSampleGrabberSinkCallback_iface); + IMFActivate_Release(sink_activate); + + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 5000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* thinning unsupported, try enable thinning */ + + source_impl->thinnable = FALSE; + + hr = IMFRateControl_SetRate(rate_control, TRUE, 2.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionRateChanged, 1000, &propvar); + ok(hr == MF_E_THINNING_UNSUPPORTED, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + PropVariantClear(&propvar); + + hr = IMFRateControl_GetRate(rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(thin == FALSE, "got thin %d\n", !!thin); + ok(rate == 1.0, "got rate %f\n", rate); + + hr = IMFRateControl_GetRate(source_rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(thin == FALSE, "got source thin %d\n", !!thin); + ok(rate == 1.0, "got source rate %f\n", rate); + + /* thinning supported, enable thinning */ + + source_impl->thinnable = TRUE; + + hr = IMFRateControl_SetRate(rate_control, TRUE, 2.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionRateChanged, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_R4, "got vt %u\n", propvar.vt); + ok(propvar.fltVal == 2.0, "got fltVal %f\n", propvar.fltVal); + PropVariantClear(&propvar); + + hr = IMFRateControl_GetRate(rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(thin == TRUE, "got thin %d\n", !!thin); + ok(rate == 2.0, "got rate %f\n", rate); + + hr = IMFRateControl_GetRate(source_rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(thin == TRUE, "got source thin %d\n", !!thin); + ok(rate == 2.0, "got source rate %f\n", rate); + + /* disable thinning */ + + hr = IMFRateControl_SetRate(rate_control, FALSE, 3.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionRateChanged, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_R4, "got vt %u\n", propvar.vt); + ok(propvar.fltVal == 3.0, "got fltVal %f\n", propvar.fltVal); + PropVariantClear(&propvar); + + hr = IMFRateControl_GetRate(rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(thin == FALSE, "got thin %d\n", !!thin); + ok(rate == 3.0, "got rate %f\n", rate); + + hr = IMFRateControl_GetRate(source_rate_control, &thin, &rate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(thin == FALSE, "got source thin %d\n", !!thin); + ok(rate == 3.0, "got source rate %f\n", rate); + + hr = IMFMediaSession_Stop(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Close(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSource_Shutdown(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFAsyncCallback_Release(callback); + IMFMediaSource_Release(source); + IMFRateControl_Release(rate_control); + IMFRateControl_Release(source_rate_control); + IMFMediaSession_Release(session); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); +} + START_TEST(mf) { init_functions(); @@ -6835,4 +7165,5 @@ START_TEST(mf) test_MFEnumDeviceSources(); test_media_session_Close(); test_media_session_source_shutdown(); + test_media_session_thinning(); } diff --git a/dlls/mf/tests/mf_test.h b/dlls/mf/tests/mf_test.h index a4f330efbcb7..f6f281939f7b 100644 --- a/dlls/mf/tests/mf_test.h +++ b/dlls/mf/tests/mf_test.h @@ -101,6 +101,7 @@ struct buffer_desc RECT compare_rect; dump_cb dump; SIZE size; + BOOL todo_data; }; struct sample_desc @@ -115,6 +116,7 @@ struct sample_desc BOOL todo_length; BOOL todo_duration; BOOL todo_time; + BOOL todo_data; }; #define check_mf_sample_collection(a, b, c) check_mf_sample_collection_(__FILE__, __LINE__, a, b, c, FALSE) diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index 4b2e83d7ee40..9070098a60a9 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -2268,7 +2268,7 @@ static void test_topology_loader(void) ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * 4 * 44100), ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 4 * 8), - ATTR_UINT32(MF_MT_AUDIO_CHANNEL_MASK, 3), + ATTR_UINT32(MF_MT_AUDIO_CHANNEL_MASK, 3, .todo = TRUE), ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), }; static const media_type_desc video_i420_1280 = @@ -2457,14 +2457,12 @@ static void test_topology_loader(void) .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, .current_input = &audio_mp3_44100, .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, - .flags = LOADER_TODO, }, { /* MP3 -> PCM, need both decoder and converter */ .input_type = &audio_mp3_44100, .output_type = &audio_float_48000, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, .current_input = &audio_mp3_44100, .decoded_type = &audio_float_44100_stereo, .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, .converter_class = CLSID_CResamplerMediaObject, - .flags = LOADER_TODO, }, { @@ -2776,7 +2774,6 @@ todo_wine { hr = IMFTopology_GetNodeCount(full_topology, &node_count); ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - todo_wine_if(IsEqualGUID(&test->decoder_class, &CLSID_CMP3DecMediaObject)) ok(node_count == count, "Unexpected node count %u.\n", node_count); hr = IMFTopologyNode_GetTopoNodeID(src_node, &node_id); diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index e828f719ffd2..5dc8df6ac5a4 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -728,6 +728,7 @@ static void check_mft_set_input_type_(int line, IMFTransform *transform, const s init_media_type(media_type, attributes, -1); hr = IMFTransform_SetInputType(transform, 0, media_type, MFT_SET_TYPE_TEST_ONLY); + todo_wine_if(todo) ok_(__FILE__, line)(hr == expect_hr, "SetInputType returned %#lx.\n", hr); hr = IMFTransform_SetInputType(transform, 0, media_type, 0); todo_wine_if(todo) @@ -1344,7 +1345,7 @@ static DWORD check_mf_media_buffer_(const char *file, int line, IMFMediaBuffer * if (*expect_data) { if (*expect_data_len < length) - todo_wine_if(expect->todo_length) + todo_wine_if(expect->todo_length || expect->todo_data) ok_(file, line)(0, "missing %#lx bytes\n", length - *expect_data_len); else if (!expect->compare) diff = compare_bytes(data, &length, NULL, NULL, *expect_data); @@ -1429,6 +1430,7 @@ static DWORD check_mf_sample_(const char *file, int line, IMFSample *sample, con todo_wine_if(expect->todo_length) ok_(file, line)(total_length == expect_length, "got total length %#lx\n", total_length); + todo_wine_if(expect->todo_data) ok_(file, line)(!*expect_data || *expect_data_len >= expect_length, "missing %#lx data\n", expect_length - *expect_data_len); @@ -2881,6 +2883,135 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de CoUninitialize(); } +static void test_aac_decoder_user_data(void) +{ + /* https://wiki.multimedia.cx/index.php/MPEG-4_Audio */ + static const BYTE aac_raw_codec_data[] = {0x12, 0x08}; /* short form of 1 channel 44.1 Khz */ + static const BYTE aac_raw_codec_data_long[] = {0x17, 0x80, 0x56, 0x22, 0x08}; /* long form of 1 channel 44.1 Khz */ + static const BYTE aac_raw_codec_data_48khz[] = {0x11, 0x90}; /* short form of 1 channel 48 Khz */ + static const struct attribute_desc raw_aac_input_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_RAW_AAC1, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_BLOB(MF_MT_USER_DATA, aac_raw_codec_data, sizeof(aac_raw_codec_data), .required = TRUE), + {0}, + }; + static const struct attribute_desc raw_aac_input_type_desc_long[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_RAW_AAC1, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_BLOB(MF_MT_USER_DATA, aac_raw_codec_data_long, sizeof(aac_raw_codec_data_long), .required = TRUE), + {0}, + }; + static const struct attribute_desc raw_aac_input_type_desc_48khz[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_RAW_AAC1, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_BLOB(MF_MT_USER_DATA, aac_raw_codec_data_48khz, sizeof(aac_raw_codec_data_48khz), .required = TRUE), + {0}, + }; + static const struct attribute_desc raw_aac_input_type_desc_mismatch[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_RAW_AAC1, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_BLOB(MF_MT_USER_DATA, aac_raw_codec_data_48khz, sizeof(aac_raw_codec_data_48khz), .required = TRUE), + {0}, + }; + static const struct attribute_desc aac_input_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE), + ATTR_BLOB(MF_MT_USER_DATA, test_aac_codec_data, sizeof(test_aac_codec_data), .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 12000), + ATTR_UINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 41), + ATTR_UINT32(MF_MT_AAC_PAYLOAD_TYPE, 0), + {0}, + }; + + static struct { + const char *name; + const struct attribute_desc *desc; + HRESULT exp_result; + BOOL todo; + BOOL todo_short; + } tests[] = { + { "aac", aac_input_type_desc, S_OK, FALSE, TRUE }, + { "raw aac", raw_aac_input_type_desc, S_OK }, + { "raw aac long", raw_aac_input_type_desc_long, S_OK, FALSE, TRUE }, + { "raw aac 48Khz", raw_aac_input_type_desc_48khz, S_OK }, + { "raw aac mismatch", raw_aac_input_type_desc_mismatch, MF_E_INVALIDMEDIATYPE, TRUE }, + }; + + const struct attribute_desc *input_type_desc; + struct attribute_desc input_desc[64]; + unsigned int user_data_index = ~0u; + IMFTransform *transform; + ULONG ret, i, j; + HRESULT hr; + + winetest_push_context("aacdec user_data"); + hr = CoInitialize(NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + + if (FAILED(hr = CoCreateInstance(&CLSID_MSAACDecMFT, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform))) + { + win_skip("AAC decoder transform is not available.\n"); + goto failed; + } + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + winetest_push_context("%s", tests[i].name); + user_data_index = ~0u; + input_type_desc = tests[i].desc; + for (j = 0; j < ARRAY_SIZE(input_desc); j++) + { + input_desc[j] = input_type_desc[j]; + if (!input_desc[j].key) + break; + if (IsEqualGUID(input_desc[j].key, &MF_MT_USER_DATA)) + user_data_index = j; + } + + ok(user_data_index != ~0u, "Could not find MF_MT_USER_DATA.\n"); + ok(i < ARRAY_SIZE(input_desc), "Too many attributes.\n"); + + /* confirm standard input result */ + check_mft_set_input_type_(__LINE__, transform, input_desc, tests[i].exp_result, tests[i].todo); + + if (tests[i].exp_result == S_OK) + { + /* confirm shorter fails */ + input_desc[user_data_index].value.blob.cbSize = input_type_desc[user_data_index].value.blob.cbSize - 1; + check_mft_set_input_type_(__LINE__, transform, input_desc, MF_E_INVALIDMEDIATYPE, tests[i].todo_short); + + /* confirm longer is OK */ + input_desc[user_data_index].value.blob.cbSize = input_type_desc[user_data_index].value.blob.cbSize + 1; + check_mft_set_input_type(transform, input_desc, S_OK); + } + winetest_pop_context(); + } + + ret = IMFTransform_Release(transform); + ok(!ret, "got %lu.\n", ret); + +failed: + winetest_pop_context(); + CoUninitialize(); +} + static void test_aac_decoder(void) { static const BYTE aac_raw_codec_data[] = {0x12, 0x08}; @@ -6280,21 +6411,12 @@ static void test_wmv_decoder(void) .attributes = output_sample_attributes, .sample_time = 0, .sample_duration = 333333, .buffer_count = 1, .buffers = &output_buffer_desc_nv12, - .todo_duration = TRUE, - }; - const struct sample_desc output_sample_desc_nv12_todo_time = - { - .attributes = output_sample_attributes, - .sample_time = 0, .sample_duration = 333333, - .buffer_count = 1, .buffers = &output_buffer_desc_nv12, - .todo_time = TRUE, .todo_duration = TRUE, }; const struct sample_desc output_sample_desc_rgb = { .attributes = output_sample_attributes, .sample_time = 0, .sample_duration = 333333, .buffer_count = 1, .buffers = &output_buffer_desc_rgb, - .todo_time = TRUE, .todo_duration = TRUE, }; const struct transform_desc @@ -6306,6 +6428,7 @@ static void test_wmv_decoder(void) const struct sample_desc *output_sample_desc; const WCHAR *result_bitmap; ULONG delta; + BOOL new_transform; BOOL todo; } transform_tests[] = @@ -6327,7 +6450,7 @@ static void test_wmv_decoder(void) .expect_output_type_desc = expect_output_type_desc, .expect_input_info = &expect_input_info, .expect_output_info = &expect_output_info, - .output_sample_desc = &output_sample_desc_nv12_todo_time, + .output_sample_desc = &output_sample_desc_nv12, .result_bitmap = L"nv12frame.bmp", .delta = 0, }, @@ -6365,6 +6488,52 @@ static void test_wmv_decoder(void) .delta = 5, }, + { + /* WMV1 -> RGB (w/ new transform) */ + .output_type_desc = output_type_desc_rgb, + .expect_output_type_desc = expect_output_type_desc_rgb, + .expect_input_info = &expect_input_info_rgb, + .expect_output_info = &expect_output_info_rgb, + .output_sample_desc = &output_sample_desc_rgb, + .result_bitmap = L"rgb32frame.bmp", + .delta = 5, + .new_transform = TRUE, + }, + + { + /* WMV1 -> RGB (negative stride, but reusing MFT w/ positive stride) */ + .output_type_desc = output_type_desc_rgb_negative_stride, + .expect_output_type_desc = expect_output_type_desc_rgb_negative_stride, + .expect_input_info = &expect_input_info_rgb, + .expect_output_info = &expect_output_info_rgb, + .output_sample_desc = &output_sample_desc_rgb, + .result_bitmap = L"rgb32frame.bmp", + .delta = 5, + }, + + { + /* WMV1 -> RGB (negative stride w/ new transform) */ + .output_type_desc = output_type_desc_rgb_negative_stride, + .expect_output_type_desc = expect_output_type_desc_rgb_negative_stride, + .expect_input_info = &expect_input_info_rgb, + .expect_output_info = &expect_output_info_rgb, + .output_sample_desc = &output_sample_desc_rgb, + .result_bitmap = L"rgb32frame-flip.bmp", + .delta = 5, + .new_transform = TRUE, + }, + + { + /* WMV1 -> RGB (positive stride w/ new transform) */ + .output_type_desc = output_type_desc_rgb_positive_stride, + .expect_output_type_desc = expect_output_type_desc_rgb, + .expect_input_info = &expect_input_info_rgb, + .expect_output_info = &expect_output_info_rgb, + .output_sample_desc = &output_sample_desc_rgb, + .result_bitmap = L"rgb32frame.bmp", + .delta = 5, + .new_transform = TRUE, + }, }; MFT_REGISTER_TYPE_INFO output_type = {MFMediaType_Video, MFVideoFormat_NV12}; @@ -6470,10 +6639,23 @@ static void test_wmv_decoder(void) ok(hr == MF_E_NO_MORE_TYPES, "GetOutputAvailableType returned %#lx\n", hr); ok(i == ARRAY_SIZE(expect_available_outputs), "%lu input media types\n", i); + check_mft_set_output_type(transform, output_type_desc_rgb, S_OK); + for (j = 0; j < ARRAY_SIZE(transform_tests); j++) { winetest_push_context("transform #%lu", j); + if (transform_tests[j].new_transform) + { + ret = IMFTransform_Release(transform); + ok(ret == 0, "Release returned %lu\n", ret); + + if (FAILED(hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform))) + goto failed; + check_mft_set_input_type(transform, input_type_desc, S_OK); + } + check_mft_set_output_type_required(transform, transform_tests[j].output_type_desc); check_mft_set_output_type(transform, transform_tests[j].output_type_desc, S_OK); check_mft_get_output_current_type_(__LINE__, transform, transform_tests[j].expect_output_type_desc, FALSE, TRUE); @@ -6535,6 +6717,7 @@ static void test_wmv_decoder(void) ret = check_mf_sample_collection(output_samples, transform_tests[j].output_sample_desc, transform_tests[j].result_bitmap); + todo_wine_if(transform_tests[j].todo) ok(ret <= transform_tests[j].delta, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); @@ -8416,9 +8599,18 @@ static void test_video_processor(BOOL use_2d_buffer) hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = IMFTransform_GetOutputStatus(transform, &flags); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputStatus returned %#lx.\n", hr); + hr = IMFTransform_SetOutputType(transform, 0, media_type, 0); ok(hr == S_OK, "Failed to set output type, hr %#lx.\n", hr); + flags = 0xdeadbeef; + hr = IMFTransform_GetOutputStatus(transform, &flags); + ok(hr == S_OK, "GetOutputStatus returned %#lx.\n", hr); + todo_wine + ok(flags == 0, "Unexpected output status %#lx.\n", flags); + hr = MFCalculateImageSize(&MFVideoFormat_IYUV, 16, 16, (UINT32 *)&input_info.cbSize); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = MFCalculateImageSize(&MFVideoFormat_RGB32, 16, 16, (UINT32 *)&output_info.cbSize); @@ -8440,6 +8632,11 @@ static void test_video_processor(BOOL use_2d_buffer) todo_wine ok(hr == S_OK, "Failed to push a sample, hr %#lx.\n", hr); + flags = 0xdeadbeef; + hr = IMFTransform_GetOutputStatus(transform, &flags); + ok(hr == S_OK, "GetOutputStatus returned %#lx.\n", hr); + ok(flags == MFT_OUTPUT_STATUS_SAMPLE_READY, "Unexpected output status %#lx.\n", flags); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); todo_wine ok(hr == MF_E_NOTACCEPTING, "Unexpected hr %#lx.\n", hr); @@ -8471,6 +8668,12 @@ static void test_video_processor(BOOL use_2d_buffer) { hr = check_mft_process_output(transform, output_sample, &output_status); ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "Unexpected hr %#lx.\n", hr); + + flags = 0xdeadbeef; + hr = IMFTransform_GetOutputStatus(transform, &flags); + ok(hr == S_OK, "GetOutputStatus returned %#lx.\n", hr); + todo_wine + ok(flags == 0, "Unexpected output status %#lx.\n", flags); } ref = IMFTransform_Release(transform); @@ -8922,8 +9125,9 @@ static void test_mp3_decoder(void) const struct buffer_desc output_buffer_desc[] = { - {.length = 0x9c0, .compare = compare_pcm16}, + {.length = 0x9c0, .compare = compare_pcm16, .todo_length = TRUE}, {.length = mp3dec_block_size, .compare = compare_pcm16}, + {.length = mp3dec_block_size, .compare = compare_pcm16, .todo_data = TRUE}, }; const struct attribute_desc output_sample_attributes[] = { @@ -8937,16 +9141,19 @@ static void test_mp3_decoder(void) .attributes = output_sample_attributes + 0, .sample_time = 0, .sample_duration = 282993, .buffer_count = 1, .buffers = output_buffer_desc + 0, + .todo_length = TRUE, .todo_duration = TRUE, }, { .attributes = output_sample_attributes + 0, .sample_time = 282993, .sample_duration = 522449, .buffer_count = 1, .buffers = output_buffer_desc + 1, .repeat_count = 18, + .todo_time = TRUE, }, { .attributes = output_sample_attributes + 1, /* not MFT_OUTPUT_DATA_BUFFER_INCOMPLETE */ .sample_time = 10209524, .sample_duration = 522449, - .buffer_count = 1, .buffers = output_buffer_desc + 1, + .buffer_count = 1, .buffers = output_buffer_desc + 2, + .todo_time = TRUE, .todo_data = TRUE, }, }; @@ -9000,9 +9207,7 @@ static void test_mp3_decoder(void) ok(ret == 0, "Release returned %lu\n", ret); winetest_pop_context(); } - todo_wine ok(hr == MF_E_NO_MORE_TYPES, "GetInputAvailableType returned %#lx\n", hr); - todo_wine ok(i == ARRAY_SIZE(expect_available_inputs), "%lu input media types\n", i); /* setting output media type first doesn't work */ @@ -9097,6 +9302,7 @@ static void test_mp3_decoder(void) else { ret = check_mf_sample_collection(output_samples, output_sample_desc, L"mp3decdata.bin"); + todo_wine ok(ret == 0, "got %lu%% diff\n", ret); } IMFCollection_Release(output_samples); @@ -10235,6 +10441,7 @@ START_TEST(transform) test_sample_copier_output_processing(); test_aac_encoder(); test_aac_decoder(); + test_aac_decoder_user_data(); test_wma_encoder(); test_wma_decoder(); test_wma_decoder_dmo_input_type(); diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 73f70e62bc66..a1b201fd4d24 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -383,7 +383,10 @@ static HRESULT get_first_supported_media_type(IMFMediaTypeHandler *handler, IMFM for (i = 0; SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, i, &media_type)); i++) { - if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, media_type, NULL))) + /* HACK: Force initialize media type here, this is now something the topology laoder should do + * according to conformance tests but it should hopefully going to solve uninitialized audio + * renderer issues. */ + if (SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, media_type))) { *type = media_type; return hr; diff --git a/dlls/mfmediaengine/Makefile.in b/dlls/mfmediaengine/Makefile.in index 5b593814ef68..cc8e69f72cb8 100644 --- a/dlls/mfmediaengine/Makefile.in +++ b/dlls/mfmediaengine/Makefile.in @@ -1,5 +1,5 @@ MODULE = mfmediaengine.dll -IMPORTS = oleaut32 ole32 mfplat mf mfuuid dxguid uuid +IMPORTS = oleaut32 ole32 mfplat mf mfuuid uuid EXTRADLLFLAGS = -Wb,--prefer-native diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 27249f09fa68..bfbe652226c2 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -28,7 +28,9 @@ #include "mfmediaengine.h" #include "mferror.h" #include "dxgi.h" +#include "initguid.h" #include "d3d11.h" +#include "wincodec.h" #include "mmdeviceapi.h" #include "audiosessiontypes.h" @@ -153,6 +155,7 @@ struct media_engine double default_playback_rate; double volume; double duration; + double next_seek; MF_MEDIA_ENGINE_NETWORK network_state; MF_MEDIA_ENGINE_ERR error_code; HRESULT extended_code; @@ -181,6 +184,7 @@ struct media_engine BYTE *buffer; UINT buffer_size; DXGI_FORMAT output_format; + BOOL format_mismatch; struct { @@ -811,55 +815,44 @@ static unsigned int get_gcd(unsigned int a, unsigned int b) return a; } -static void media_engine_get_frame_size(struct media_engine *engine, IMFTopology *topology) +static void media_engine_get_frame_size(struct media_engine *engine) { IMFMediaTypeHandler *handler; IMFMediaType *media_type; - IMFStreamDescriptor *sd; - IMFTopologyNode *node; - unsigned int gcd; - UINT64 size; - HRESULT hr; engine->video_frame.size.cx = 0; engine->video_frame.size.cy = 0; engine->video_frame.ratio.cx = 1; engine->video_frame.ratio.cy = 1; - if (FAILED(IMFTopology_GetNodeByID(topology, engine->video_frame.node_id, &node))) - return; - - hr = IMFTopologyNode_GetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR, - &IID_IMFStreamDescriptor, (void **)&sd); - IMFTopologyNode_Release(node); - if (FAILED(hr)) - return; - - hr = IMFStreamDescriptor_GetMediaTypeHandler(sd, &handler); - IMFStreamDescriptor_Release(sd); - if (FAILED(hr)) - return; - - hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, &media_type); - IMFMediaTypeHandler_Release(handler); - if (FAILED(hr)) + if (engine->presentation.frame_sink && + SUCCEEDED(video_frame_sink_query_iface(engine->presentation.frame_sink, &IID_IMFMediaTypeHandler, (void**)&handler))) { - WARN("Failed to get current media type %#lx.\n", hr); - return; - } - - IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &size); - - engine->video_frame.size.cx = size >> 32; - engine->video_frame.size.cy = size; + if (SUCCEEDED(IMFMediaTypeHandler_GetCurrentMediaType(handler, &media_type))) + { + UINT64 size; + HRESULT hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &size); + if (SUCCEEDED(hr)) + { + unsigned int gcd; + engine->video_frame.size.cx = size >> 32; + engine->video_frame.size.cy = size; + + if ((gcd = get_gcd(engine->video_frame.size.cx, engine->video_frame.size.cy))) + { + engine->video_frame.ratio.cx = engine->video_frame.size.cx / gcd; + engine->video_frame.ratio.cy = engine->video_frame.size.cy / gcd; + } + } + else + { + WARN("Failed to get frame size %#lx.\n", hr); + } - if ((gcd = get_gcd(engine->video_frame.size.cx, engine->video_frame.size.cy))) - { - engine->video_frame.ratio.cx = engine->video_frame.size.cx / gcd; - engine->video_frame.ratio.cy = engine->video_frame.size.cy / gcd; + IMFMediaType_Release(media_type); + } + IMFMediaTypeHandler_Release(handler); } - - IMFMediaType_Release(media_type); } static void media_engine_apply_volume(const struct media_engine *engine) @@ -911,6 +904,8 @@ static HRESULT WINAPI media_engine_callback_GetParameters(IMFAsyncCallback *ifac return E_NOTIMPL; } +static HRESULT media_engine_set_current_time(struct media_engine *engine, double seektime); + static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { struct media_engine *engine = impl_from_session_events_IMFAsyncCallback(iface); @@ -941,32 +936,19 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface case MESessionTopologyStatus: { UINT32 topo_status = 0; - IMFTopology *topology; PROPVARIANT value; IMFMediaEvent_GetUINT32(event, &MF_EVENT_TOPOLOGY_STATUS, &topo_status); if (topo_status != MF_TOPOSTATUS_READY) break; - value.vt = VT_EMPTY; - if (FAILED(IMFMediaEvent_GetValue(event, &value))) - break; - - if (value.vt != VT_UNKNOWN) - { - PropVariantClear(&value); - break; - } - - topology = (IMFTopology *)value.punkVal; - EnterCriticalSection(&engine->cs); media_engine_apply_volume(engine); engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_METADATA; - media_engine_get_frame_size(engine, topology); + media_engine_get_frame_size(engine); IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE, 0, 0); IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA, 0, 0); @@ -989,6 +971,8 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface media_engine_set_flag(engine, FLAGS_ENGINE_SEEKING | FLAGS_ENGINE_IS_ENDED, FALSE); IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_SEEKED, 0, 0); IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, 0, 0); + if (isfinite(engine->next_seek)) + media_engine_set_current_time(engine, engine->next_seek); } LeaveCriticalSection(&engine->cs); IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_PLAYING, 0, 0); @@ -1183,6 +1167,23 @@ static HRESULT media_engine_create_video_renderer(struct media_engine *engine, I return E_FAIL; } + switch (output_format) + { + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + /* IMFMediaSession doesn't support output to these formats unless the decoder supports + * MFVideoFormat_P010 output, which would allow inclusion of a suitable converter. + * The Windows H.264 decoder doesn't suppport MFVideoFormat_P010 output, and Media + * Engine apparently performs a format conversion. + * Create an 8-bit output and ensure the sampled texture is copied via a pixel shader. */ + output_format = DXGI_FORMAT_B8G8R8A8_UNORM; + engine->video_frame.format_mismatch = TRUE; + break; + default: + break; + } + memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); if (!(subtype.Data1 = MFMapDXGIFormatToDX9Format(output_format))) { @@ -1865,6 +1866,14 @@ static HRESULT media_engine_set_current_time(struct media_engine *engine, double if (FAILED(hr) || !(caps & MFSESSIONCAP_SEEK)) return hr; + if (engine->flags & FLAGS_ENGINE_SEEKING) + { + engine->next_seek = seektime; + return S_OK; + } + + engine->next_seek = NAN; + position.vt = VT_I8; position.hVal.QuadPart = min(max(0, seektime), engine->duration) * 10000000; @@ -2416,11 +2425,39 @@ static void media_engine_adjust_destination_for_ratio(const struct media_engine } } +static HRESULT get_d3d11_resource_from_sample(IMFSample *sample, ID3D11Texture2D **resource, UINT *subresource) +{ + IMFDXGIBuffer *dxgi_buffer; + IMFMediaBuffer *buffer; + HRESULT hr; + + *resource = NULL; + *subresource = 0; + + if (FAILED(hr = IMFSample_GetBufferByIndex(sample, 0, &buffer))) + return hr; + + if (SUCCEEDED(hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer))) + { + IMFDXGIBuffer_GetSubresourceIndex(dxgi_buffer, subresource); + hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_ID3D11Texture2D, (void **)resource); + IMFDXGIBuffer_Release(dxgi_buffer); + } + + IMFMediaBuffer_Release(buffer); + return hr; +} + static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext *context, struct media_engine *engine) { D3D11_TEXTURE2D_DESC surface_desc; + D3D11_TEXTURE2D_DESC src_desc; IMFMediaBuffer *media_buffer; + ID3D11Texture2D *src_texture; + ID3D11Device *device; IMFSample *sample; + UINT subresource; + HRESULT hr; if (!video_frame_sink_get_sample(engine->presentation.frame_sink, &sample)) return; @@ -2438,7 +2475,23 @@ static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext *context surface_desc.Width = 0; } - if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(sample, &media_buffer))) + if (SUCCEEDED(hr = get_d3d11_resource_from_sample(sample, &src_texture, &subresource))) + { + + ID3D11Texture2D_GetDesc(src_texture, &src_desc); + + if (SUCCEEDED(hr = media_engine_lock_d3d_device(engine, &device))) + { + ID3D11Device_GetImmediateContext(device, &context); + ID3D11DeviceContext_CopyResource(context, (ID3D11Resource *)engine->video_frame.d3d11.source, (ID3D11Resource *)src_texture); + ID3D11DeviceContext_Release(context); + media_engine_unlock_d3d_device(engine, device); + } + + ID3D11Texture2D_Release(src_texture); + } + + if (FAILED(hr) && SUCCEEDED(IMFSample_ConvertToContiguousBuffer(sample, &media_buffer))) { BYTE *buffer; DWORD buffer_size; @@ -2458,29 +2511,6 @@ static void media_engine_update_d3d11_frame_surface(ID3D11DeviceContext *context IMFSample_Release(sample); } -static HRESULT get_d3d11_resource_from_sample(IMFSample *sample, ID3D11Texture2D **resource, UINT *subresource) -{ - IMFDXGIBuffer *dxgi_buffer; - IMFMediaBuffer *buffer; - HRESULT hr; - - *resource = NULL; - *subresource = 0; - - if (FAILED(hr = IMFSample_GetBufferByIndex(sample, 0, &buffer))) - return hr; - - if (SUCCEEDED(hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFDXGIBuffer, (void **)&dxgi_buffer))) - { - IMFDXGIBuffer_GetSubresourceIndex(dxgi_buffer, subresource); - hr = IMFDXGIBuffer_GetResource(dxgi_buffer, &IID_ID3D11Texture2D, (void **)resource); - IMFDXGIBuffer_Release(dxgi_buffer); - } - - IMFMediaBuffer_Release(buffer); - return hr; -} - static HRESULT media_engine_transfer_d3d11(struct media_engine *engine, ID3D11Texture2D *dst_texture, const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color) { @@ -2693,12 +2723,127 @@ static HRESULT media_engine_transfer_to_d3d11_texture(struct media_engine *engin return hr; } +static HRESULT media_engine_transfer_wic(struct media_engine *engine, IWICBitmap *bitmap, + const MFVideoNormalizedRect *src_mf_rect, const RECT *dst_rect, const MFARGB *color) +{ + UINT frame_width, frame_height, dst_width, dst_height, dst_size, src_stride, dst_stride, format_size; + RECT src_rect = {0}, dst_rect_default = {0}; + DWORD max_length, current_length; + IMFMediaBuffer *media_buffer; + IWICBitmapLock *lock = NULL; + WICPixelFormatGUID format; + IMFSample *sample; + WICRect wic_rect; + BYTE *dst, *src; + HRESULT hr; + + frame_width = engine->video_frame.size.cx; + frame_height = engine->video_frame.size.cy; + + if (src_mf_rect) + { + src_rect.left = src_mf_rect->left * frame_width + 0.5f; + src_rect.top = src_mf_rect->top * frame_height + 0.5f; + src_rect.right = src_mf_rect->right * frame_width + 0.5f; + src_rect.bottom = src_mf_rect->bottom * frame_height + 0.5f; + } + else + { + src_rect.right = frame_width; + src_rect.bottom = frame_height; + } + + if (FAILED(hr = IWICBitmap_GetPixelFormat(bitmap, &format)) + || FAILED(hr = IWICBitmap_GetSize(bitmap, &dst_width, &dst_height))) + return hr; + + if (!dst_rect) + { + dst_rect = &dst_rect_default; + dst_rect_default.right = dst_width; + dst_rect_default.bottom = dst_height; + } + + if (!video_frame_sink_get_sample(engine->presentation.frame_sink, &sample)) + return MF_E_UNEXPECTED; + hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer); + IMFSample_Release(sample); + if (FAILED(hr)) + return hr; + + if (dst_rect->left + src_rect.right - src_rect.left > dst_width + || dst_rect->top + src_rect.bottom - src_rect.top > dst_height) + { + hr = MF_E_UNEXPECTED; + goto done; + } + if (dst_rect->right - dst_rect->left != src_rect.right - src_rect.left + || dst_rect->bottom - dst_rect->top != src_rect.bottom - src_rect.top) + { + FIXME("Scaling/letterboxing is not implemented.\n"); + goto done; + } + + if (!IsEqualGUID(&format, &GUID_WICPixelFormat32bppBGR) && !IsEqualGUID(&format, &GUID_WICPixelFormat32bppBGRA)) + { + FIXME("Unsupported format %s.\n", wine_dbgstr_guid(&format)); + goto done; + } + if (engine->video_frame.output_format != DXGI_FORMAT_B8G8R8A8_UNORM + && engine->video_frame.output_format != DXGI_FORMAT_B8G8R8X8_UNORM) + { + FIXME("Unsupported format %#x.\n", engine->video_frame.output_format); + goto done; + } + if (engine->video_frame.output_format == DXGI_FORMAT_B8G8R8A8_UNORM + && IsEqualGUID(&format, &GUID_WICPixelFormat32bppBGR)) + { + WARN("Dropping alpha channel.\n"); + } + format_size = 4; + + wic_rect.X = dst_rect->left; + wic_rect.Y = dst_rect->top; + wic_rect.Width = dst_rect->right - dst_rect->left; + wic_rect.Height = dst_rect->bottom - dst_rect->top; + if (FAILED(hr = IWICBitmap_Lock(bitmap, &wic_rect, WICBitmapLockWrite, &lock))) + goto done; + + if (FAILED(hr = IWICBitmapLock_GetStride(lock, &dst_stride)) + || FAILED(hr = IWICBitmapLock_GetDataPointer(lock, &dst_size, &dst))) + goto done; + + if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &src, &max_length, ¤t_length))) + goto done; + + if (current_length < frame_width * frame_height * format_size) + { + WARN("Unexpected source length %lu.\n", current_length); + hr = MF_E_UNEXPECTED; + goto done; + } + + src_stride = frame_width * format_size; + src += src_rect.top * src_stride + src_rect.left * format_size; + MFCopyImage(dst, dst_stride, src, src_stride, dst_stride, wic_rect.Height); + + IMFMediaBuffer_Unlock(media_buffer); + +done: + if (lock) + IWICBitmapLock_Release(lock); + IMFMediaBuffer_Release(media_buffer); + + return hr; +} + static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, IUnknown *surface, const MFVideoNormalizedRect *src_rect, const RECT *dst_rect, const MFARGB *color) { struct media_engine *engine = impl_from_IMFMediaEngineEx(iface); ID3D11Texture2D *texture; HRESULT hr = E_NOINTERFACE; + IWICBitmap *bitmap; TRACE("%p, %p, %s, %s, %p.\n", iface, surface, src_rect ? wine_dbg_sprintf("(%f,%f)-(%f,%f)", src_rect->left, src_rect->top, src_rect->right, src_rect->bottom) : "(null)", @@ -2708,10 +2853,18 @@ static HRESULT WINAPI media_engine_TransferVideoFrame(IMFMediaEngineEx *iface, I if (SUCCEEDED(IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture))) { - if (!engine->device_manager || FAILED(hr = media_engine_transfer_d3d11(engine, texture, src_rect, dst_rect, color))) + if (!engine->device_manager + || engine->video_frame.format_mismatch + || FAILED(hr = media_engine_transfer_d3d11(engine, texture, src_rect, dst_rect, color))) hr = media_engine_transfer_to_d3d11_texture(engine, texture, src_rect, dst_rect, color); ID3D11Texture2D_Release(texture); } + /* Windows does not allow transfer to IWICBitmap if a device manager was set. */ + else if (!engine->device_manager && SUCCEEDED(IUnknown_QueryInterface(surface, &IID_IWICBitmap, (void **)&bitmap))) + { + hr = media_engine_transfer_wic(engine, bitmap, src_rect, dst_rect, color); + IWICBitmap_Release(bitmap); + } else { FIXME("Unsupported destination type.\n"); @@ -3378,6 +3531,7 @@ static HRESULT init_media_engine(DWORD flags, IMFAttributes *attributes, struct engine->playback_rate = 1.0; engine->volume = 1.0; engine->duration = NAN; + engine->next_seek = NAN; engine->video_frame.pts = MINLONGLONG; InitializeCriticalSection(&engine->cs); diff --git a/dlls/mfmediaengine/tests/Makefile.in b/dlls/mfmediaengine/tests/Makefile.in index e123952956db..f703371cda2c 100644 --- a/dlls/mfmediaengine/tests/Makefile.in +++ b/dlls/mfmediaengine/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mfmediaengine.dll -IMPORTS = ole32 mf mfplat oleaut32 mfuuid uuid +IMPORTS = ole32 mf mfplat oleaut32 mfuuid uuid dxguid SOURCES = \ mfmediaengine.c \ diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 34b3519d063e..ed389da920f2 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -33,6 +33,7 @@ #include "initguid.h" #include "mmdeviceapi.h" #include "audiosessiontypes.h" +#include "wincodec.h" #include "wine/test.h" @@ -1272,9 +1273,11 @@ static void test_TransferVideoFrame(void) ID3D11Texture2D *texture = NULL, *rb_texture; D3D11_MAPPED_SUBRESOURCE map_desc; IMFMediaEngineEx *media_engine = NULL; + IWICImagingFactory *factory = NULL; IMFDXGIDeviceManager *manager; ID3D11DeviceContext *context; D3D11_TEXTURE2D_DESC desc; + IWICBitmap *bitmap = NULL; IMFByteStream *stream; ID3D11Device *device; RECT dst_rect; @@ -1317,6 +1320,13 @@ static void test_TransferVideoFrame(void) hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &texture); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICImagingFactory, (void **)&factory); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICImagingFactory_CreateBitmap(factory, desc.Width, desc.Height, &GUID_WICPixelFormat32bppBGR, + WICBitmapCacheOnLoad, &bitmap); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + url = SysAllocString(L"i420-64x64.avi"); hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine, stream, url); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -1373,6 +1383,10 @@ static void test_TransferVideoFrame(void) ID3D11DeviceContext_Release(context); ID3D11Texture2D_Release(rb_texture); + hr = IMFMediaEngineEx_TransferVideoFrame(notify->media_engine, (IUnknown *)bitmap, NULL, &dst_rect, NULL); + /* not supported if a DXGI device manager was provided */ + ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr); + done: if (media_engine) { @@ -1380,6 +1394,10 @@ static void test_TransferVideoFrame(void) IMFMediaEngineEx_Release(media_engine); } + if (bitmap) + IWICBitmap_Release(bitmap); + if (factory) + IWICImagingFactory_Release(factory); if (texture) ID3D11Texture2D_Release(texture); if (device) @@ -1388,6 +1406,98 @@ static void test_TransferVideoFrame(void) IMFMediaEngineNotify_Release(¬ify->IMFMediaEngineNotify_iface); } +static void test_TransferVideoFrame_wic(void) +{ + struct test_transfer_notify *notify; + UINT lock_buffer_size, lock_buffer_stride; + IMFMediaEngineEx *media_engine = NULL; + IWICImagingFactory *factory = NULL; + IWICBitmap *bitmap = NULL; + IMFByteStream *stream; + IWICBitmapLock *lock; + WICRect wicrc = {0}; + BYTE *lock_buffer; + RECT dst_rect; + LONGLONG pts; + HRESULT hr; + DWORD res; + BSTR url; + + stream = load_resource(L"i420-64x64.avi", L"video/avi"); + + notify = create_transfer_notify(); + + create_media_engine(¬ify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_B8G8R8X8_UNORM, + &IID_IMFMediaEngineEx, (void **)&media_engine); + + if (!(notify->media_engine = media_engine)) + goto done; + + wicrc.Width = 64; + wicrc.Height = 64; + + hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICImagingFactory, (void **)&factory); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICImagingFactory_CreateBitmap(factory, wicrc.Width, wicrc.Height, &GUID_WICPixelFormat32bppBGR, + WICBitmapCacheOnLoad, &bitmap); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + url = SysAllocString(L"i420-64x64.avi"); + hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine, stream, url); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + SysFreeString(url); + IMFByteStream_Release(stream); + + res = WaitForSingleObject(notify->frame_ready_event, 5000); + ok(!res, "Unexpected res %#lx.\n", res); + + if (FAILED(notify->error)) + { + win_skip("Media engine reported error %#lx, skipping tests.\n", notify->error); + goto done; + } + + /* FIXME: Wine first video frame is often full of garbage, wait for another update */ + res = WaitForSingleObject(notify->ready_event, 500); + /* It's also missing the MF_MEDIA_ENGINE_EVENT_TIMEUPDATE notifications */ + todo_wine + ok(!res, "Unexpected res %#lx.\n", res); + + SetRect(&dst_rect, 0, 0, wicrc.Width, wicrc.Height); + IMFMediaEngineEx_OnVideoStreamTick(notify->media_engine, &pts); + hr = IMFMediaEngineEx_TransferVideoFrame(notify->media_engine, (IUnknown *)bitmap, NULL, &dst_rect, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IWICBitmap_Lock(bitmap, &wicrc, WICBitmapLockRead, &lock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICBitmapLock_GetStride(lock, &lock_buffer_stride); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICBitmapLock_GetDataPointer(lock, &lock_buffer_size, &lock_buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!lock_buffer, "got null lock_buffer\n"); + ok(lock_buffer_size == 16384, "got lock_buffer_size %u\n", lock_buffer_size); + ok(lock_buffer_stride == wicrc.Width * 4, "got lock_buffer_stride %u\n", lock_buffer_stride); + res = check_rgb32_data(L"rgb32frame.bmp", lock_buffer, lock_buffer_stride * wicrc.Height, &dst_rect); + ok(res == 0, "Unexpected %lu%% diff\n", res); + + IWICBitmapLock_Release(lock); + +done: + if (media_engine) + { + IMFMediaEngineEx_Shutdown(media_engine); + IMFMediaEngineEx_Release(media_engine); + } + + if (bitmap) + IWICBitmap_Release(bitmap); + if (factory) + IWICImagingFactory_Release(factory); + + IMFMediaEngineNotify_Release(¬ify->IMFMediaEngineNotify_iface); +} + struct test_transform { IMFTransform IMFTransform_iface; @@ -2712,6 +2822,7 @@ START_TEST(mfmediaengine) test_SetSourceFromByteStream(); test_audio_configuration(); test_TransferVideoFrame(); + test_TransferVideoFrame_wic(); test_effect(); test_GetDuration(); test_GetSeekable(); diff --git a/dlls/mfmediaengine/video_frame_sink.c b/dlls/mfmediaengine/video_frame_sink.c index 23d8e19e71e5..a79cd5f86446 100644 --- a/dlls/mfmediaengine/video_frame_sink.c +++ b/dlls/mfmediaengine/video_frame_sink.c @@ -1012,11 +1012,9 @@ static HRESULT video_frame_sink_set_state(struct video_frame_sink *sink, enum si video_frame_sink_set_flag(sink, FLAGS_FIRST_FRAME, FALSE); } - if (state == SINK_STATE_RUNNING && sink->state != SINK_STATE_RUNNING) - { - video_frame_sink_sample_queue_flush(sink); + if (state == SINK_STATE_RUNNING && (sink->state == SINK_STATE_STOPPED || sink->state == SINK_STATE_PAUSED || + (sink->state == SINK_STATE_RUNNING && offset != PRESENTATION_CURRENT_POSITION))) video_frame_sink_stream_request_sample(sink); - } if (state != sink->state || state != SINK_STATE_PAUSED) { diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 65fab78d427d..6a8d43f30019 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -58,6 +58,7 @@ struct buffer unsigned int locks; MF2DBuffer_LockFlags lock_flags; p_copy_image_func copy_image; + BOOL performance_hack_enabled; } _2d; struct { @@ -290,10 +291,14 @@ static HRESULT WINAPI memory_1d_2d_buffer_QueryInterface(IMFMediaBuffer *iface, return S_OK; } +static HRESULT memory_2d_buffer_lock(struct buffer *buffer, BYTE **scanline0, LONG *pitch, + BYTE **buffer_start, DWORD *buffer_length); + static HRESULT WINAPI memory_1d_2d_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, DWORD *current_length) { struct buffer *buffer = impl_from_IMFMediaBuffer(iface); HRESULT hr = S_OK; + const char *sgi; TRACE("%p, %p, %p, %p.\n", iface, data, max_length, current_length); @@ -305,8 +310,25 @@ static HRESULT WINAPI memory_1d_2d_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat EnterCriticalSection(&buffer->cs); - if (!buffer->_2d.linear_buffer && buffer->_2d.locks) + if (buffer->_2d.performance_hack_enabled + || (!buffer->_2d.linear_buffer && buffer->_2d.width == buffer->_2d.pitch + && (sgi = getenv("SteamGameId")) && (!strcmp(sgi, "418370") || !strcmp(sgi, "287700") || !strcmp(sgi, "462780")))) + { + BYTE *scanline; + LONG pitch; + + /* width and pitch are the same, so this avoids a potentially expensive copy + * this is a HACK as it does not match Windows behaviour (Windows will copy the buffer) + * this fixes performance regressions for Resident Evil 7 Biohazard (418370), + * Metal Gear Solid V (287700) and Darksiders Warmastered Edition (462780). + */ + hr = memory_2d_buffer_lock(buffer, &scanline, &pitch, data, NULL); + buffer->_2d.performance_hack_enabled = TRUE; + } + else if (!buffer->_2d.linear_buffer && buffer->_2d.locks) + { hr = MF_E_INVALIDREQUEST; + } else if (!buffer->_2d.linear_buffer) { if (!(buffer->_2d.linear_buffer = malloc(buffer->_2d.plane_size))) @@ -323,10 +345,14 @@ static HRESULT WINAPI memory_1d_2d_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat } } - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr) && buffer->_2d.linear_buffer) { ++buffer->_2d.locks; *data = buffer->_2d.linear_buffer; + } + + if (SUCCEEDED(hr)) + { if (max_length) *max_length = buffer->_2d.plane_size; if (current_length) @@ -341,12 +367,20 @@ static HRESULT WINAPI memory_1d_2d_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat static HRESULT WINAPI memory_1d_2d_buffer_Unlock(IMFMediaBuffer *iface) { struct buffer *buffer = impl_from_IMFMediaBuffer(iface); + HRESULT hr = S_OK; TRACE("%p.\n", iface); EnterCriticalSection(&buffer->cs); - if (buffer->_2d.linear_buffer && !--buffer->_2d.locks) + if (buffer->_2d.performance_hack_enabled) + { + if (buffer->_2d.locks) + --buffer->_2d.locks; + else + hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED); + } + else if (buffer->_2d.linear_buffer && !--buffer->_2d.locks) { int pitch = buffer->_2d.pitch; @@ -361,7 +395,7 @@ static HRESULT WINAPI memory_1d_2d_buffer_Unlock(IMFMediaBuffer *iface) LeaveCriticalSection(&buffer->cs); - return S_OK; + return hr; } static const IMFMediaBufferVtbl memory_1d_2d_buffer_vtbl = @@ -1004,6 +1038,7 @@ static void dxgi_surface_buffer_unmap(struct buffer *buffer, MF2DBuffer_LockFlag { ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL); + ID3D11DeviceContext_Flush(immediate_context); } ID3D11DeviceContext_Release(immediate_context); @@ -1352,7 +1387,6 @@ static HRESULT memory_buffer_init(struct buffer *buffer, DWORD max_length, DWORD if (!(buffer->data = _aligned_malloc(max_length, alignment))) return E_OUTOFMEMORY; - memset(buffer->data, 0, max_length); buffer->IMFMediaBuffer_iface.lpVtbl = vtbl; buffer->refcount = 1; diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 4ed607686f18..0a7c294294e4 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -43,6 +43,7 @@ #include "strsafe.h" #undef INITGUID #include "evr.h" +#include "wine/mfinternal.h" /* mfd3d12 guids are not included in mfuuid */ #define INITGUID #undef EXTERN_GUID @@ -6207,14 +6208,18 @@ static HRESULT resolver_create_bytestream_handler(IMFByteStream *stream, DWORD f static HRESULT resolver_get_bytestream_url_hint(IMFByteStream *stream, WCHAR const **url) { - static const unsigned char asfmagic[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c}; - static const unsigned char wavmagic[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '}; - static const unsigned char wavmask[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; - static const unsigned char isommagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00}; - static const unsigned char mp4_magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', 'S', 'N', 'V',0x00,0x00,0x00,0x00}; - static const unsigned char mp42magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00}; - static const unsigned char mp4vmagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', '4', 'V', ' ',0x00,0x00,0x00,0x00}; - static const unsigned char mp4mask[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00}; + static const unsigned char asfmagic[] = {0x30,0x26,0xb2,0x75,0x8e,0x66,0xcf,0x11,0xa6,0xd9,0x00,0xaa,0x00,0x62,0xce,0x6c}; + static const unsigned char wavmagic[] = { 'R', 'I', 'F', 'F',0x00,0x00,0x00,0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' '}; + static const unsigned char wavmask[] = {0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; + static const unsigned char isommagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm',0x00,0x00,0x00,0x00}; + static const unsigned char mp4_magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', 'S', 'N', 'V',0x00,0x00,0x00,0x00}; + static const unsigned char mp42magic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',0x00,0x00,0x00,0x00}; + static const unsigned char mp4vmagic[] = {0x00,0x00,0x00,0x00, 'f', 't', 'y', 'p', 'M', '4', 'V', ' ',0x00,0x00,0x00,0x00}; + static const unsigned char mp4mask[] = {0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00}; + static const unsigned char mp3magic[] = {0xff,0xf2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + static const unsigned char mp3mask[] = {0xff,0xf6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + static const unsigned char idv2_3_magic[] = {'I','D','3',0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + static const unsigned char idv2_3_mask[] = {0xff,0xff,0xff,0xff,0x00,0x1f,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00}; static const struct stream_content_url_hint { const unsigned char *magic; @@ -6229,6 +6234,8 @@ static HRESULT resolver_get_bytestream_url_hint(IMFByteStream *stream, WCHAR con { mp42magic, L".mp4", mp4mask }, { mp4_magic, L".mp4", mp4mask }, { mp4vmagic, L".m4v", mp4mask }, + { mp3magic, L".mp3", mp3mask }, + { idv2_3_magic, L".mp3", idv2_3_mask }, }; unsigned char buffer[4 * sizeof(unsigned int)], pattern[4 * sizeof(unsigned int)]; IMFAttributes *attributes; @@ -6292,10 +6299,9 @@ static HRESULT resolver_get_bytestream_url_hint(IMFByteStream *stream, WCHAR con return S_OK; } -static HRESULT resolver_create_gstreamer_handler(IMFByteStreamHandler **handler) +static HRESULT resolver_create_default_handler(IMFByteStreamHandler **handler) { - static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; - return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler); + return CoCreateInstance(&CLSID_MPEG4ByteStreamHandlerPlugin, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler); } static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHAR *url, DWORD flags, @@ -6331,12 +6337,14 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA this handler for all possible types. */ + TRACE( "url_ext %s mimeW %s\n", debugstr_w(url_ext), debugstr_w(mimeW) ); + if (url_ext || mimeW) { hr = resolver_create_bytestream_handler(stream, flags, mimeW, url_ext, handler); if (FAILED(hr)) - hr = resolver_create_gstreamer_handler(handler); + hr = resolver_create_default_handler(handler); } CoTaskMemFree(mimeW); @@ -6354,7 +6362,7 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA hr = resolver_create_bytestream_handler(stream, flags, NULL, url_ext, handler); if (FAILED(hr)) - hr = resolver_create_gstreamer_handler(handler); + hr = resolver_create_default_handler(handler); return hr; } @@ -6673,7 +6681,10 @@ static HRESULT WINAPI source_resolver_BeginCreateObjectFromURL(IMFSourceResolver (IMFAsyncCallback *)&resolver->url_callback, (IUnknown *)result); if (SUCCEEDED(hr) && inner_cookie) + { resolver_create_cancel_object((IUnknown *)handler, OBJECT_FROM_URL, inner_cookie, cancel_cookie); + IUnknown_Release(inner_cookie); + } IRtwqAsyncResult_Release(result); @@ -6719,7 +6730,10 @@ static HRESULT WINAPI source_resolver_BeginCreateObjectFromByteStream(IMFSourceR /* Cancel object wraps underlying handler cancel cookie with context necessary to call CancelObjectCreate(). */ if (SUCCEEDED(hr) && inner_cookie) + { resolver_create_cancel_object((IUnknown *)handler, OBJECT_FROM_BYTESTREAM, inner_cookie, cancel_cookie); + IUnknown_Release(inner_cookie); + } IRtwqAsyncResult_Release(result); @@ -9210,9 +9224,16 @@ static const IMFDXGIDeviceManagerVtbl dxgi_device_manager_vtbl = HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **manager) { struct dxgi_device_manager *object; + const char *do_not_create = getenv("WINE_DO_NOT_CREATE_DXGI_DEVICE_MANAGER"); TRACE("%p, %p.\n", token, manager); + if (do_not_create && do_not_create[0] != '\0') + { + FIXME("stubbing out\n"); + return E_NOTIMPL; + } + if (!token || !manager) return E_POINTER; diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 916ab77408d3..ed68a3e4ff3b 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3005,11 +3005,7 @@ HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *mediatype, WAVE return E_INVALIDARG; if (FAILED(hr = IMFMediaType_GetBlobSize(mediatype, &MF_MT_USER_DATA, &user_size))) - { - if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float)) - return hr; user_size = 0; - } if (media_type_get_uint32(mediatype, &MF_MT_AUDIO_NUM_CHANNELS) > 2 && SUCCEEDED(IMFMediaType_GetItem(mediatype, &MF_MT_AUDIO_CHANNEL_MASK, NULL))) diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c index 4d75924b939f..60d78dc8bf08 100644 --- a/dlls/mfplat/sample.c +++ b/dlls/mfplat/sample.c @@ -791,6 +791,65 @@ static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_lengt return S_OK; } +static HRESULT copy_2d_buffer_from_contiguous(IMFMediaBuffer *src, IMF2DBuffer *dst, DWORD *current_length) +{ + HRESULT hr, hr2; + BYTE *ptr; + + hr = IMFMediaBuffer_Lock(src, &ptr, NULL, current_length); + + if (SUCCEEDED(hr)) + { + hr = IMF2DBuffer_ContiguousCopyFrom(dst, ptr, *current_length); + + hr2 = IMFMediaBuffer_Unlock(src); + if (FAILED(hr2)) + WARN("Unlocking source buffer %p failed with hr %#lx.\n", src, hr2); + if (FAILED(hr2) && SUCCEEDED(hr)) + hr = hr2; + } + + return hr; +} + +static HRESULT copy_2d_buffer(IMFMediaBuffer *src, IMFMediaBuffer *dst) +{ + IMF2DBuffer2 *src2d2 = NULL, *dst2d2 = NULL; + IMF2DBuffer *dst2 = NULL; + HRESULT hr; + DWORD current_length; + + hr = IMFMediaBuffer_QueryInterface(src, &IID_IMF2DBuffer2, (void **)&src2d2); + + if (SUCCEEDED(hr)) + hr = IMFMediaBuffer_QueryInterface(dst, &IID_IMF2DBuffer2, (void **)&dst2d2); + + if (SUCCEEDED(hr)) + hr = IMF2DBuffer2_Copy2DTo(src2d2, dst2d2); + + if (src2d2) + IMF2DBuffer2_Release(src2d2); + + if (dst2d2) + IMF2DBuffer2_Release(dst2d2); + + if (SUCCEEDED(hr)) + return hr; + + hr = IMFMediaBuffer_QueryInterface(dst, &IID_IMF2DBuffer, (void **)&dst2); + + if (SUCCEEDED(hr)) + hr = copy_2d_buffer_from_contiguous(src, dst2, ¤t_length); + + if (SUCCEEDED(hr)) + IMFMediaBuffer_SetCurrentLength(dst, current_length); + + if (dst2) + IMF2DBuffer_Release(dst2); + + return hr; +} + static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer) { struct sample *sample = impl_from_IMFSample(iface); @@ -805,6 +864,15 @@ static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buff EnterCriticalSection(&sample->attributes.cs); + if (sample->buffer_count == 1) + { + if (SUCCEEDED(hr = copy_2d_buffer(sample->buffers[0], buffer))) + { + LeaveCriticalSection(&sample->attributes.cs); + return hr; + } + } + total_length = sample_get_total_length(sample); dst_current_length = 0; diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index ac21a7283e83..506aec0ae29a 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -42,6 +42,7 @@ #include "evr.h" #include "mfmediaengine.h" #include "codecapi.h" +#include "rtworkq.h" #include "wine/test.h" @@ -102,6 +103,8 @@ DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_wvp2,MAKEFOURCC('w','v','p','2')); DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_X264,MAKEFOURCC('X','2','6','4')); DEFINE_MEDIATYPE_GUID(MEDIASUBTYPE_x264,MAKEFOURCC('x','2','6','4')); +DEFINE_GUID(MF_XVP_PLAYBACK_MODE, 0x3c5d293f, 0xad67, 0x4e29, 0xaf, 0x12, 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9); + static BOOL is_win8_plus; #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__) @@ -219,6 +222,39 @@ static void check_attributes_(const char *file, int line, IMFAttributes *attribu } } +#define check_platform_lock_count(a) check_platform_lock_count_(__LINE__, a) +static void check_platform_lock_count_(unsigned int line, unsigned int expected) +{ + int i, count = 0; + BOOL unexpected; + DWORD queue; + HRESULT hr; + + for (;;) + { + if (FAILED(hr = MFAllocateWorkQueue(&queue))) + { + unexpected = hr != MF_E_SHUTDOWN; + break; + } + MFUnlockWorkQueue(queue); + + hr = MFUnlockPlatform(); + if ((unexpected = FAILED(hr))) + break; + + ++count; + } + + for (i = 0; i < count; ++i) + MFLockPlatform(); + + if (unexpected) + count = -1; + + ok_(__FILE__, line)(count == expected, "Unexpected lock count %d.\n", count); +} + struct d3d9_surface_readback { IDirect3DSurface9 *surface, *readback_surface; @@ -509,6 +545,11 @@ static HRESULT (WINAPI *pMFLockDXGIDeviceManager)(UINT *token, IMFDXGIDeviceMana static HRESULT (WINAPI *pMFUnlockDXGIDeviceManager)(void); static HRESULT (WINAPI *pMFInitVideoFormat_RGB)(MFVIDEOFORMAT *format, DWORD width, DWORD height, DWORD d3dformat); +static HRESULT (WINAPI *pRtwqStartup)(void); +static HRESULT (WINAPI *pRtwqShutdown)(void); +static HRESULT (WINAPI *pRtwqLockPlatform)(void); +static HRESULT (WINAPI *pRtwqUnlockPlatform)(void); + static HWND create_window(void) { RECT r = {0, 0, 640, 480}; @@ -1719,6 +1760,14 @@ static void init_functions(void) mod = GetModuleHandleA("ole32.dll"); X(CoGetApartmentType); + + if ((mod = LoadLibraryA("rtworkq.dll"))) + { + X(RtwqStartup); + X(RtwqShutdown); + X(RtwqUnlockPlatform); + X(RtwqLockPlatform); + } #undef X is_win8_plus = pMFPutWaitingWorkItem != NULL; @@ -3825,6 +3874,8 @@ static void test_MFCreateAsyncResult(void) static void test_startup(void) { + struct test_callback *callback; + IMFAsyncResult *result; DWORD queue; HRESULT hr; @@ -3834,10 +3885,7 @@ static void test_startup(void) hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); - hr = MFAllocateWorkQueue(&queue); - ok(hr == S_OK, "Failed to allocate a queue, hr %#lx.\n", hr); - hr = MFUnlockWorkQueue(queue); - ok(hr == S_OK, "Failed to unlock the queue, hr %#lx.\n", hr); + check_platform_lock_count(1); hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); @@ -3852,10 +3900,7 @@ static void test_startup(void) hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); - hr = MFAllocateWorkQueue(&queue); - ok(hr == S_OK, "Failed to allocate a queue, hr %#lx.\n", hr); - hr = MFUnlockWorkQueue(queue); - ok(hr == S_OK, "Failed to unlock the queue, hr %#lx.\n", hr); + check_platform_lock_count(1); hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); @@ -3864,10 +3909,7 @@ static void test_startup(void) hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); - hr = MFAllocateWorkQueue(&queue); - ok(hr == S_OK, "Failed to allocate a queue, hr %#lx.\n", hr); - hr = MFUnlockWorkQueue(queue); - ok(hr == S_OK, "Failed to unlock the queue, hr %#lx.\n", hr); + check_platform_lock_count(1); /* Unlocking implies shutdown. */ hr = MFUnlockPlatform(); @@ -3879,13 +3921,250 @@ static void test_startup(void) hr = MFLockPlatform(); ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + check_platform_lock_count(1); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + if (!pRtwqStartup) + { + win_skip("RtwqStartup() not found.\n"); + return; + } + + /* Rtwq equivalence */ + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + hr = pRtwqStartup(); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + hr = pRtwqShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + check_platform_lock_count(1); + + /* Matching MFStartup() with RtwqShutdown() causes shutdown. */ + hr = pRtwqShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + hr = MFAllocateWorkQueue(&queue); - ok(hr == S_OK, "Failed to allocate a queue, hr %#lx.\n", hr); - hr = MFUnlockWorkQueue(queue); - ok(hr == S_OK, "Failed to unlock the queue, hr %#lx.\n", hr); + ok(hr == MF_E_SHUTDOWN, "Failed to allocate a queue, hr %#lx.\n", hr); hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + /* RtwqStartup() enables MF functions */ + hr = pRtwqStartup(); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + check_platform_lock_count(1); + + callback = create_test_callback(NULL); + + /* MF platform lock is the Rtwq lock */ + hr = pRtwqUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock platform, hr %#lx.\n", hr); + + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Failed to allocate a queue, hr %#lx.\n", hr); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + check_platform_lock_count(1); + + hr = pRtwqLockPlatform(); + ok(hr == S_OK, "Failed to lock platform, hr %#lx.\n", hr); + check_platform_lock_count(2); + + IMFAsyncResult_Release(result); + + hr = pRtwqShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); +} + +void test_startup_counts(void) +{ + IMFAsyncResult *result, *result2, *callback_result; + struct test_callback *callback; + MFWORKITEM_KEY key, key2; + DWORD res, queue; + LONG refcount; + HRESULT hr; + + hr = MFLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = MFUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + + callback = create_test_callback(&test_async_callback_result_vtbl); + + /* Create async results without startup. */ + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result2); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + IMFAsyncResult_Release(result); + IMFAsyncResult_Release(result2); + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + /* Before startup the platform lock count does not track the maximum AsyncResult count. */ + check_platform_lock_count(1); + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + /* Startup only locks once. */ + check_platform_lock_count(1); + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + /* Platform locked by the AsyncResult object. */ + check_platform_lock_count(2); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result2); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + check_platform_lock_count(3); + + IMFAsyncResult_Release(result); + IMFAsyncResult_Release(result2); + /* Platform lock count for AsyncResult objects does not decrease + * unless the platform is in shutdown state. */ + check_platform_lock_count(3); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + /* Platform lock count tracks the maximum AsyncResult count plus one for startup. */ + check_platform_lock_count(3); + IMFAsyncResult_Release(result); + + hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &callback->IMFAsyncCallback_iface, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + res = wait_async_callback_result(&callback->IMFAsyncCallback_iface, 100, &callback_result); + ok(res == 0, "got %#lx\n", res); + refcount = IMFAsyncResult_Release(callback_result); + /* Release of an internal lock occurs in a worker thread. */ + flaky_wine + ok(!refcount, "Unexpected refcount %ld.\n", refcount); + check_platform_lock_count(3); + + hr = MFLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + hr = MFLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + check_platform_lock_count(5); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + /* Platform is in shutdown state if either the lock count or the startup count is <= 0. */ + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + /* Platform can be unlocked after shutdown. */ + hr = MFUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + /* Platform locks for AsyncResult objects were released on shutdown, but the explicit lock was not. */ + check_platform_lock_count(2); + hr = MFUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + check_platform_lock_count(1); + + hr = MFUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + /* Zero lock count. */ + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = MFUnlockPlatform(); + ok(hr == S_OK, "Failed to unlock, %#lx.\n", hr); + /* Negative lock count. */ + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + hr = MFLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + hr = MFLockPlatform(); + ok(hr == S_OK, "Failed to lock, %#lx.\n", hr); + check_platform_lock_count(1); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + check_platform_lock_count(2); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + /* Release an AsyncResult object after shutdown. Lock count tracks the AsyncResult count. + * It's not possible to show if unlock occurs immedately or on the next startup. */ + IMFAsyncResult_Release(result); + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + check_platform_lock_count(1); + + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + check_platform_lock_count(2); + /* Release an AsyncResult object after shutdown and startup */ + IMFAsyncResult_Release(result); + check_platform_lock_count(2); + + hr = MFScheduleWorkItem(&callback->IMFAsyncCallback_iface, NULL, -5000, &key); + ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); + /* The AsyncResult created for the item locks the platform */ + check_platform_lock_count(2); + + hr = MFScheduleWorkItem(&callback->IMFAsyncCallback_iface, NULL, -5000, &key2); + ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); + check_platform_lock_count(3); + + /* Platform locks for scheduled items are not released */ + hr = MFCancelWorkItem(key); + ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr); + hr = MFCancelWorkItem(key2); + ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr); + check_platform_lock_count(3); + + hr = MFScheduleWorkItem(&callback->IMFAsyncCallback_iface, NULL, -5000, &key); + ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); + check_platform_lock_count(3); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + hr = MFAllocateWorkQueue(&queue); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + hr = MFCancelWorkItem(key); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + res = wait_async_callback_result(&callback->IMFAsyncCallback_iface, 0, &result); + ok(res == WAIT_TIMEOUT, "got res %#lx\n", res); + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + /* Shutdown while a scheduled item is pending leaks the internal AsyncResult. */ + check_platform_lock_count(2); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); } static void test_allocate_queue(void) @@ -4135,8 +4414,6 @@ static void test_scheduled_items(void) hr = MFCancelWorkItem(key2); ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr); - IMFAsyncResult_Release(result); - hr = MFScheduleWorkItem(&callback->IMFAsyncCallback_iface, NULL, -5000, &key); ok(hr == S_OK, "Failed to schedule item, hr %#lx.\n", hr); @@ -4146,6 +4423,12 @@ static void test_scheduled_items(void) hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + Sleep(20); + /* A callback invocation with RTWQ_E_OPERATION_CANCELLED may have been pending + * when MFShutdown() was called. Release depends upon its execution. */ + refcount = IMFAsyncResult_Release(result); + ok(refcount == 0, "Unexpected refcount %lu.\n", refcount); + IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); } @@ -4340,12 +4623,26 @@ static void test_event_queue(void) hr = IMFMediaEventQueue_EndGetEvent(queue, result, &event); ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + /* Shutdown behavior. */ + hr = MFCreateMediaEvent(MEError, &GUID_NULL, E_FAIL, NULL, &event); + ok(hr == S_OK, "Failed to create event object, hr %#lx.\n", hr); + hr = IMFMediaEventQueue_QueueEvent(queue, event); + ok(hr == S_OK, "Failed to queue event, hr %#lx.\n", hr); + IMFMediaEvent_Release(event); + hr = IMFMediaEventQueue_Shutdown(queue); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + event = (void *)0xdeadbeef; + hr = IMFMediaEventQueue_GetEvent(queue, 0, &event); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + ok(event == (void *)0xdeadbeef, "Unexpected event %p.\n", event); + event = (void *)0xdeadbeef; hr = IMFMediaEventQueue_GetEvent(queue, MF_EVENT_FLAG_NO_WAIT, &event); ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + ok(event == (void *)0xdeadbeef, "Unexpected event %p.\n", event); + hr = MFCreateMediaEvent(MEError, &GUID_NULL, E_FAIL, NULL, &event); ok(hr == S_OK, "Failed to create event object, hr %#lx.\n", hr); @@ -4391,6 +4688,34 @@ static void test_event_queue(void) ok(ret == 1 || broken(ret == 2) /* Vista */, "Unexpected refcount %ld, expected 1.\n", ret); IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); + IMFAsyncCallback_Release(&callback2->IMFAsyncCallback_iface); + + + callback = create_test_callback(&test_async_callback_result_vtbl); + + hr = MFCreateEventQueue(&queue); + ok(hr == S_OK, "Failed to create event queue, hr %#lx.\n", hr); + hr = IMFMediaEventQueue_BeginGetEvent(queue, &callback->IMFAsyncCallback_iface, NULL); + ok(hr == S_OK, "Failed to Begin*, hr %#lx.\n", hr); + hr = IMFMediaEventQueue_QueueEventParamVar(queue, MEError, &GUID_NULL, E_FAIL, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaEventQueue_Shutdown(queue); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + + ret = WaitForSingleObject(callback->event, 500); + ok(ret == WAIT_OBJECT_0, "Unexpected return value %#lx.\n", ret); + result = callback->result; + callback->result = NULL; + + event = (void *)0xdeadbeef; + hr = IMFMediaEventQueue_EndGetEvent(queue, result, &event); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + ok(event == (void *)0xdeadbeef, "Unexpected event %p.\n", event); + IMFAsyncResult_Release(result); + + IMFMediaEventQueue_Release(queue); + IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); + hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); @@ -5648,11 +5973,15 @@ static void test_MFCreateWaveFormatExFromMFMediaType(void) { const GUID *subtype; WORD format_tag; + UINT32 size; + WORD size_field; } wave_fmt_tests[] = { - { &MFAudioFormat_PCM, WAVE_FORMAT_PCM, }, - { &MFAudioFormat_Float, WAVE_FORMAT_IEEE_FLOAT, }, + { &MFAudioFormat_PCM, WAVE_FORMAT_PCM, sizeof(WAVEFORMATEX), 0, }, + { &MFAudioFormat_Float, WAVE_FORMAT_IEEE_FLOAT, sizeof(WAVEFORMATEX), 0, }, + { &MFAudioFormat_MP3, WAVE_FORMAT_MPEGLAYER3, sizeof(WAVEFORMATEX), 0, }, + { &DUMMY_GUID3, WAVE_FORMAT_EXTENSIBLE, sizeof(WAVEFORMATEXTENSIBLE), 22, }, }; WAVEFORMATEXTENSIBLE *format_ext; IMFMediaType *mediatype; @@ -5680,20 +6009,21 @@ static void test_MFCreateWaveFormatExFromMFMediaType(void) for (i = 0; i < ARRAY_SIZE(wave_fmt_tests); ++i) { + winetest_push_context("test %d", i); hr = IMFMediaType_SetGUID(mediatype, &MF_MT_SUBTYPE, wave_fmt_tests[i].subtype); ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); hr = MFCreateWaveFormatExFromMFMediaType(mediatype, &format, &size, MFWaveFormatExConvertFlag_Normal); ok(hr == S_OK, "Failed to create format, hr %#lx.\n", hr); ok(format != NULL, "Expected format structure.\n"); - ok(size == sizeof(*format), "Unexpected size %u.\n", size); + ok(size == wave_fmt_tests[i].size, "Unexpected size %u.\n", size); ok(format->wFormatTag == wave_fmt_tests[i].format_tag, "Expected tag %u, got %u.\n", wave_fmt_tests[i].format_tag, format->wFormatTag); ok(format->nChannels == 0, "Unexpected number of channels, %u.\n", format->nChannels); ok(format->nSamplesPerSec == 0, "Unexpected sample rate, %lu.\n", format->nSamplesPerSec); ok(format->nAvgBytesPerSec == 0, "Unexpected average data rate rate, %lu.\n", format->nAvgBytesPerSec); ok(format->nBlockAlign == 0, "Unexpected alignment, %u.\n", format->nBlockAlign); ok(format->wBitsPerSample == 0, "Unexpected sample size, %u.\n", format->wBitsPerSample); - ok(format->cbSize == 0, "Unexpected size field, %u.\n", format->cbSize); + ok(format->cbSize == wave_fmt_tests[i].size_field, "Unexpected size field, %u.\n", format->cbSize); CoTaskMemFree(format); hr = MFCreateWaveFormatExFromMFMediaType(mediatype, (WAVEFORMATEX **)&format_ext, &size, @@ -5714,8 +6044,9 @@ static void test_MFCreateWaveFormatExFromMFMediaType(void) hr = MFCreateWaveFormatExFromMFMediaType(mediatype, &format, &size, MFWaveFormatExConvertFlag_ForceExtensible + 1); ok(hr == S_OK, "Failed to create format, hr %#lx.\n", hr); - ok(size == sizeof(*format), "Unexpected size %u.\n", size); + ok(size == wave_fmt_tests[i].size, "Unexpected size %u.\n", size); CoTaskMemFree(format); + winetest_pop_context(); } IMFMediaType_Release(mediatype); @@ -6437,6 +6768,208 @@ static void test_dxgi_device_manager(void) IMFDXGIDeviceManager_Release(manager2); } +static IMFSample *create_dxgi_sample(ID3D11Device *device, UINT32 color, UINT bind_flags) +{ + D3D11_TEXTURE2D_DESC desc = { + .Width = 1, + .Height = 1, + .MipLevels = 1, + .ArraySize = 1, + .Format = DXGI_FORMAT_B8G8R8A8_UNORM, + .SampleDesc = { + .Count = 1, + .Quality = 0, + }, + .Usage = D3D11_USAGE_DEFAULT, + .BindFlags = bind_flags, + .CPUAccessFlags = 0, + .MiscFlags = 0, + }; + D3D11_SUBRESOURCE_DATA data = { + .pSysMem = &color, + .SysMemPitch = 4, + .SysMemSlicePitch = 4, + }; + IMFSample *sample; + ID3D11Texture2D *texture; + IMFMediaBuffer *buffer; + HRESULT hr; + + hr = ID3D11Device_CreateTexture2D(device, &desc, &data, &texture); + ok(hr == S_OK, "Failed to create d3d11 texture, hr %#lx.\n", hr); + + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *) texture, 0, FALSE, &buffer); + ok(hr == S_OK, "Failed to create dxgi surface buffer, hr %#lx.\n", hr); + + hr = IMFMediaBuffer_SetCurrentLength(buffer, 4); + ok(hr == S_OK, "Failed to set media buffer length, hr %#lx.\n", hr); + + hr = MFCreateSample(&sample); + ok(hr == S_OK, "Failed create sample, hr %#lx.\n", hr); + + hr = IMFSample_AddBuffer(sample, buffer); + ok(hr == S_OK, "Failed add buffer to sample, hr %#lx.\n", hr); + + hr = IMFSample_SetSampleTime(sample, 0); + ok(hr == S_OK, "Failed to set sample time, hr %#lx.\n", hr); + + hr = IMFSample_SetSampleDuration(sample, 10000000/60); + ok(hr == S_OK, "Failed to set sample duration, hr %#lx.\n", hr); + + IMFMediaBuffer_Release(buffer); + ID3D11Texture2D_Release(texture); + + return sample; +} + +static IMFSample *test_xvp_process_sample(IMFTransform *xvp, IMFSample *in_sample, IMFSample *out_sample) +{ + IMFMediaBuffer *out_buffer; + HRESULT hr; + MFT_OUTPUT_DATA_BUFFER out = { + .dwStreamID = 0, + .pSample = out_sample, + .dwStatus = 0, + .pEvents = NULL, + }; + DWORD status; + BYTE *out_data; + DWORD out_length; + + hr = IMFTransform_ProcessInput(xvp, 0, in_sample, 0); + ok(hr == S_OK, "Failed to process input, hr %#lx.\n", hr); + + hr = IMFTransform_ProcessOutput(xvp, 0, 1, &out, &status); + ok(hr == S_OK, "Failed to process output, hr %#lx.\n", hr); + + hr = IMFSample_ConvertToContiguousBuffer(out.pSample, &out_buffer); + ok(hr == S_OK, "Failed to convert sample to contiguous buffer, hr %#lx.\n", hr); + + hr = IMFMediaBuffer_Lock(out_buffer, &out_data, &out_length, NULL); + ok(hr == S_OK, "Failed to lock buffer, hr %#lx.\n", hr); + + ok(out_length == 4, "Output sample length should be 4.\n"); + ok(*(UINT32 *) out_data == 0xdeadbeef, "Output sample should be populated with input data.\n"); + + hr = IMFMediaBuffer_Unlock(out_buffer); + ok(hr == S_OK, "Failed to unlock buffer, hr %#lx.\n", hr); + + IMFMediaBuffer_Release(out_buffer); + + if (out.pEvents) IMFCollection_Release(out.pEvents); + + return out.pSample; +} + +static void test_xvp_playback_mode(void) +{ + HRESULT hr; + UINT reset_token; + MFT_OUTPUT_STREAM_INFO out_info; + IMFDXGIDeviceManager *manager; + ID3D11Device *device; + IMFTransform *xvp; + IMFAttributes *xvp_attrs; + IMFSample *in_sample, *out_sample, *got_out_sample; + IMFMediaType *type; + + if (!pMFCreateDXGIDeviceManager) + { + win_skip("MFCreateDXGIDeviceManager not found.\n"); + return; + } + + if (!pMFCreateDXGISurfaceBuffer) + { + win_skip("MFCreateDXGISurfaceBuffer() is not available.\n"); + return; + } + + hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, + NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL); + if (FAILED(hr)) + { + skip("Failed to create D3D11 device object.\n"); + return; + } + + hr = pMFCreateDXGIDeviceManager(&reset_token, &manager); + ok(hr == S_OK, "Failed to create device manager, hr %#lx.\n", hr); + + hr = IMFDXGIDeviceManager_ResetDevice(manager, (IUnknown *) device, reset_token); + ok(hr == S_OK, "Failed to reset device manager, hr %#lx.\n", hr); + + hr = CoCreateInstance(&CLSID_VideoProcessorMFT, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **) &xvp); + ok(hr == S_OK, "Failed to create video processor MFT, hr %#lx.\n", hr); + + hr = IMFTransform_ProcessMessage(xvp, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR) manager); + if (hr == E_NOINTERFACE) + { + win_skip("D3D11 manager does not support video processing.\n"); + goto end; + } + ok(hr == S_OK, "Failed to set D3D manager, hr %#lx.\n", hr); + + hr = IMFTransform_GetAttributes(xvp, &xvp_attrs); + ok(hr == S_OK, "Failed to get video processor attributes\n"); + + hr = MFCreateMediaType(&type); + ok(hr == S_OK, "Failed create media type, hr %#lx.\n", hr); + + hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Failed to set major type, hr %#lx.\n", hr); + + hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFVideoFormat_ARGB32); + ok(hr == S_OK, "Failed to set subtype, hr %#lx.\n", hr); + + hr = IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, ((UINT64) 1 << 32) | 1); + ok(hr == S_OK, "Failed to frame size, hr %#lx.\n", hr); + + hr = IMFTransform_SetInputType(xvp, 0, type, 0); + ok(hr == S_OK, "Failed to set input type, hr %#lx.\n", hr); + + hr = IMFTransform_SetOutputType(xvp, 0, type, 0); + ok(hr == S_OK, "Failed to set output type, hr %#lx.\n", hr); + + hr = IMFTransform_GetOutputStreamInfo(xvp, 0, &out_info); + ok(hr == S_OK, "Failed to get output stream info, hr %#lx.\n", hr); + + ok(out_info.cbSize == 4, "Output size should be 4.\n"); + + in_sample = create_dxgi_sample(device, 0xdeadbeef, 0); + + if ((out_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) || (out_info.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)) + { + got_out_sample = test_xvp_process_sample(xvp, in_sample, NULL); + IMFSample_Release(got_out_sample); + } + else + { + win_skip("Video processor MFT can't provide output samples.\n"); + } + + hr = IMFTransform_ProcessMessage(xvp, MFT_MESSAGE_NOTIFY_END_STREAMING, 0); + ok(hr == S_OK, "Failed to end streaming, hr %#lx.\n", hr); + + hr = IMFAttributes_SetUINT32(xvp_attrs, &MF_XVP_PLAYBACK_MODE, TRUE); + ok(hr == S_OK, "Failed to set MF_XVP_PLAYBACK_MODE, hr %#lx.\n", hr); + + out_sample = create_dxgi_sample(device, 0, D3D11_BIND_RENDER_TARGET); + got_out_sample = test_xvp_process_sample(xvp, in_sample, out_sample); + + ok(got_out_sample == out_sample, "Video processor should use caller-provided sample.\n"); + + if (got_out_sample != out_sample) IMFSample_Release(got_out_sample); + IMFSample_Release(in_sample); + IMFSample_Release(out_sample); + IMFMediaType_Release(type); + IMFAttributes_Release(xvp_attrs); +end: + IMFTransform_Release(xvp); + IMFDXGIDeviceManager_Release(manager); + ID3D11Device_Release(device); +} + static void test_MFCreateTransformActivate(void) { IMFActivate *activate; @@ -7931,7 +8464,6 @@ static void test_MFInitMediaTypeFromWaveFormatEx(void) hr = IMFMediaType_DeleteItem(mediatype, &MF_MT_USER_DATA); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = MFCreateWaveFormatExFromMFMediaType(mediatype, (WAVEFORMATEX **)&wfx, &size, 0); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr == S_OK) { @@ -8203,6 +8735,18 @@ static void test_MFInitAMMediaTypeFromMFMediaType(void) ok(IsEqualGUID(&am_type.formattype, &FORMAT_MPEG2Video), "got %s.\n", debugstr_guid(&am_type.formattype)); ok(am_type.cbFormat == sizeof(MPEG2VIDEOINFO), "got %lu\n", am_type.cbFormat); CoTaskMemFree(am_type.pbFormat); + IMFMediaType_DeleteAllItems(media_type); + + /* test audio with NULL mapping */ + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_MP3); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, 2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFInitAMMediaTypeFromMFMediaType(media_type, GUID_NULL, &am_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_DeleteAllItems(media_type); /* test WAVEFORMATEX mapping */ @@ -13193,6 +13737,43 @@ static void test_2dbuffer_copy(void) ID3D11Device_Release(device); } +static void test_undefined_queue_id(void) +{ + struct test_callback *callback; + IMFAsyncResult *result; + HRESULT hr; + DWORD res; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr); + + callback = create_test_callback(&test_async_callback_result_vtbl); + + hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_UNDEFINED, &callback->IMFAsyncCallback_iface, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + res = wait_async_callback_result(&callback->IMFAsyncCallback_iface, 100, &result); + ok(res == 0, "got %#lx\n", res); + IMFAsyncResult_Release(result); + + hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK, &callback->IMFAsyncCallback_iface, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + res = wait_async_callback_result(&callback->IMFAsyncCallback_iface, 100, &result); + ok(res == 0, "got %#lx\n", res); + IMFAsyncResult_Release(result); + + hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK & (MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK - 1), + &callback->IMFAsyncCallback_iface, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + res = wait_async_callback_result(&callback->IMFAsyncCallback_iface, 100, &result); + ok(res == 0, "got %#lx\n", res); + IMFAsyncResult_Release(result); + + IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); +} + START_TEST(mfplat) { char **argv; @@ -13216,6 +13797,7 @@ START_TEST(mfplat) CoInitialize(NULL); test_startup(); + test_startup_counts(); test_register(); test_media_type(); test_MFCreateMediaEvent(); @@ -13287,6 +13869,8 @@ START_TEST(mfplat) test_MFInitMediaTypeFromAMMediaType(); test_MFCreatePathFromURL(); test_2dbuffer_copy(); + test_undefined_queue_id(); + test_xvp_playback_mode(); CoUninitialize(); } diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 4d223f1de6ec..ba58e0b007e8 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -89,7 +89,6 @@ struct media_stream IMFMediaStream *stream; IMFMediaType *current; struct list transforms; - IMFVideoSampleAllocatorEx *allocator; IMFTransform *transform_service; DWORD id; unsigned int index; @@ -176,6 +175,9 @@ struct source_reader CONDITION_VARIABLE sample_event; CONDITION_VARIABLE state_event; CONDITION_VARIABLE stop_event; + + BOOL flag_eos_for_all_streams; + DWORD next_stream_eos_index; }; static inline struct source_reader *impl_from_IMFSourceReaderEx(IMFSourceReaderEx *iface) @@ -232,8 +234,6 @@ static void media_stream_destroy(struct media_stream *stream) IMFMediaStream_Release(stream->stream); if (stream->current) IMFMediaType_Release(stream->current); - if (stream->allocator) - IMFVideoSampleAllocatorEx_Release(stream->allocator); } static ULONG source_reader_release(struct source_reader *reader) @@ -429,39 +429,6 @@ static void source_reader_response_ready(struct source_reader *reader, struct st stream->requests--; } -static void source_reader_copy_sample_buffer(IMFSample *src, IMFSample *dst) -{ - IMFMediaBuffer *buffer; - LONGLONG time; - DWORD flags; - HRESULT hr; - - IMFSample_CopyAllItems(src, (IMFAttributes *)dst); - - IMFSample_SetSampleDuration(dst, 0); - IMFSample_SetSampleTime(dst, 0); - IMFSample_SetSampleFlags(dst, 0); - - if (SUCCEEDED(IMFSample_GetSampleDuration(src, &time))) - IMFSample_SetSampleDuration(dst, time); - - if (SUCCEEDED(IMFSample_GetSampleTime(src, &time))) - IMFSample_SetSampleTime(dst, time); - - if (SUCCEEDED(IMFSample_GetSampleFlags(src, &flags))) - IMFSample_SetSampleFlags(dst, flags); - - if (SUCCEEDED(IMFSample_ConvertToContiguousBuffer(src, NULL))) - { - if (SUCCEEDED(IMFSample_GetBufferByIndex(dst, 0, &buffer))) - { - if (FAILED(hr = IMFSample_CopyToBuffer(src, buffer))) - WARN("Failed to copy a buffer, hr %#lx.\n", hr); - IMFMediaBuffer_Release(buffer); - } - } -} - static HRESULT source_reader_queue_response(struct source_reader *reader, struct media_stream *stream, HRESULT status, DWORD stream_flags, LONGLONG timestamp, IMFSample *sample) { @@ -680,26 +647,31 @@ static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallbac return source_reader_release(reader); } -static HRESULT source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO *info, IMFSample **out) +static HRESULT source_reader_allocate_stream_sample(IMFTransform *transform, MFT_OUTPUT_STREAM_INFO *info, IMFSample **out) { + IMFMediaType *media_type; IMFMediaBuffer *buffer; IMFSample *sample; HRESULT hr; *out = NULL; - if (FAILED(hr = MFCreateSample(&sample))) + if (SUCCEEDED(hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type))) + { + hr = MFCreateMediaBufferFromMediaType(media_type, 10000000, info->cbSize, info->cbAlignment, &buffer); + IMFMediaType_Release(media_type); + } + if (FAILED(hr) && FAILED(hr = MFCreateAlignedMemoryBuffer(info->cbSize, info->cbAlignment, &buffer))) return hr; - if (SUCCEEDED(hr = MFCreateAlignedMemoryBuffer(info->cbSize, info->cbAlignment, &buffer))) + + if (SUCCEEDED(hr = MFCreateSample(&sample))) { if (SUCCEEDED(hr = IMFSample_AddBuffer(sample, buffer))) - { *out = sample; - IMFSample_AddRef(sample); - } - IMFMediaBuffer_Release(buffer); + else + IMFSample_Release(sample); } - IMFSample_Release(sample); + IMFMediaBuffer_Release(buffer); return hr; } @@ -716,14 +688,13 @@ static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const /* update a media type with additional attributes reported by upstream element */ /* also present in mf/topology_loader.c pipeline */ -static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type) +static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type, BOOL advanced) { HRESULT hr = S_OK; /* propagate common video attributes */ media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_SIZE, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_RATE, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_DEFAULT_STRIDE, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_ROTATION, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FIXED_SIZE_SAMPLES, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_PIXEL_ASPECT_RATIO, &hr); @@ -738,6 +709,9 @@ static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMedi media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_LIGHTING, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_NOMINAL_RANGE, &hr); + if (!advanced) + media_type_try_copy_attr(media_type, upstream_type, &MF_MT_DEFAULT_STRIDE, &hr); + /* propagate common audio attributes */ media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_NUM_CHANNELS, &hr); media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &hr); @@ -885,7 +859,7 @@ static HRESULT source_reader_pull_transform_samples(struct source_reader *reader IMFMediaType *media_type; if (!(stream_info.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)) - && FAILED(hr = source_reader_allocate_stream_sample(&stream_info, &out_buffer.pSample))) + && FAILED(hr = source_reader_allocate_stream_sample(entry->transform, &stream_info, &out_buffer.pSample))) break; if (SUCCEEDED(hr = IMFTransform_ProcessOutput(entry->transform, 0, 1, &out_buffer, &status))) @@ -1219,8 +1193,6 @@ static struct stream_response * media_stream_detach_response(struct source_reade static struct stream_response *media_stream_pop_response(struct source_reader *reader, struct media_stream *stream) { struct stream_response *response; - IMFSample *sample; - HRESULT hr; LIST_FOR_EACH_ENTRY(response, &reader->responses, struct stream_response, entry) { @@ -1229,26 +1201,6 @@ static struct stream_response *media_stream_pop_response(struct source_reader *r if (!stream) stream = &reader->streams[response->stream_index]; - if (response->sample && stream->allocator) - { - /* Return allocation error to the caller, while keeping original response sample in for later. */ - if (SUCCEEDED(hr = IMFVideoSampleAllocatorEx_AllocateSample(stream->allocator, &sample))) - { - source_reader_copy_sample_buffer(response->sample, sample); - IMFSample_Release(response->sample); - response->sample = sample; - } - else - { - if (!(response = calloc(1, sizeof(*response)))) - return NULL; - - response->status = hr; - response->stream_flags = MF_SOURCE_READERF_ERROR; - return response; - } - } - return media_stream_detach_response(reader, response); } @@ -1397,9 +1349,11 @@ static HRESULT source_reader_get_next_selected_stream(struct source_reader *read } /* If all selected streams reached EOS, use first selected. */ - if (first_selected != ~0u) + if (first_selected != ~0u && min_ts == MAXLONGLONG) { - if (min_ts == MAXLONGLONG) + if (reader->flag_eos_for_all_streams) + *stream_index = reader->next_stream_eos_index++ % reader->stream_count; + else *stream_index = first_selected; } @@ -1571,7 +1525,8 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb case SOURCE_READER_ASYNC_SAMPLE_READY: EnterCriticalSection(&reader->cs); - response = media_stream_pop_response(reader, NULL); + stream = &reader->streams[command->u.sample.stream_index]; + response = media_stream_pop_response(reader, stream); LeaveCriticalSection(&reader->cs); if (response) @@ -1661,7 +1616,6 @@ static ULONG WINAPI src_reader_Release(IMFSourceReaderEx *iface) { struct source_reader *reader = impl_from_IMFSourceReaderEx(iface); ULONG refcount = InterlockedDecrement(&reader->public_refcount); - unsigned int i; TRACE("%p, refcount %lu.\n", iface, refcount); @@ -1681,23 +1635,6 @@ static ULONG WINAPI src_reader_Release(IMFSourceReaderEx *iface) LeaveCriticalSection(&reader->cs); } - for (i = 0; i < reader->stream_count; ++i) - { - struct media_stream *stream = &reader->streams[i]; - IMFVideoSampleAllocatorCallback *callback; - - if (!stream->allocator) - continue; - - if (SUCCEEDED(IMFVideoSampleAllocatorEx_QueryInterface(stream->allocator, &IID_IMFVideoSampleAllocatorCallback, - (void **)&callback))) - { - IMFVideoSampleAllocatorCallback_SetCallback(callback, NULL); - IMFVideoSampleAllocatorCallback_Release(callback); - } - } - - MFUnlockWorkQueue(reader->queue); source_reader_release(reader); } @@ -1948,85 +1885,66 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea return type_set ? S_OK : S_FALSE; } -static HRESULT source_reader_create_sample_allocator_attributes(const struct source_reader *reader, - IMFAttributes **attributes) +static BOOL source_reader_allow_video_processor(struct source_reader *reader, BOOL *advanced) { - UINT32 shared = 0, shared_without_mutex = 0; - HRESULT hr; - - if (FAILED(hr = MFCreateAttributes(attributes, 1))) - return hr; + UINT32 value; - IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &shared); - IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &shared_without_mutex); + *advanced = FALSE; + if (!reader->attributes) + return FALSE; - if (shared_without_mutex) - hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, TRUE); - else if (shared) - hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED, TRUE); + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, &value))) + *advanced = value; + if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, &value))) + return value || *advanced; - return hr; + return *advanced; } -static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader, unsigned int index) +static void mediatype_set_uint32(IMFMediaType *mediatype, const GUID *attr, unsigned int value, HRESULT *hr) { - struct media_stream *stream = &reader->streams[index]; - IMFAttributes *attributes = NULL; - GUID major = { 0 }; - HRESULT hr; - - IMFMediaType_GetMajorType(stream->current, &major); - if (!IsEqualGUID(&major, &MFMediaType_Video)) - return S_OK; - - if (!(reader->flags & SOURCE_READER_HAS_DEVICE_MANAGER)) - return S_OK; - - if (!stream->allocator) - { - if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&stream->allocator))) - { - WARN("Failed to create sample allocator, hr %#lx.\n", hr); - return hr; - } - } + if (SUCCEEDED(*hr)) + *hr = IMFMediaType_SetUINT32(mediatype, attr, value); +} - IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream->allocator); - if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(stream->allocator, reader->device_manager))) - { - WARN("Failed to set device manager, hr %#lx.\n", hr); - return hr; - } +static void mediatype_get_stride_and_sample_size(IMFMediaType *mediatype, LONG *stride, DWORD *sample_size, HRESULT *hr) +{ + UINT64 frame_size; + GUID subtype; - if (FAILED(hr = source_reader_create_sample_allocator_attributes(reader, &attributes))) - WARN("Failed to create allocator attributes, hr %#lx.\n", hr); + if (SUCCEEDED(*hr)) + *hr = IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &subtype); - if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream->allocator, 2, 8, - attributes, stream->current))) - { - WARN("Failed to initialize sample allocator, hr %#lx.\n", hr); - } + if (SUCCEEDED(*hr)) + *hr = IMFMediaType_GetUINT64(mediatype, &MF_MT_FRAME_SIZE, &frame_size); - if (attributes) - IMFAttributes_Release(attributes); + if (SUCCEEDED(*hr)) + *hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, frame_size >> 32, stride); - return hr; + if (SUCCEEDED(*hr)) + *hr = MFGetPlaneSize(subtype.Data1, frame_size >> 32, frame_size & 0xffffffff, sample_size); } -static BOOL source_reader_allow_video_processor(struct source_reader *reader, BOOL *advanced) +static HRESULT set_default_video_attributes(struct source_reader *reader, IMFMediaType *output_type) { - UINT32 value; + DWORD sample_size; + BOOL compressed; + LONG stride; + HRESULT hr; - *advanced = FALSE; - if (!reader->attributes) - return FALSE; + if (FAILED(hr = IMFMediaType_IsCompressedFormat(output_type, &compressed))) + return hr; - if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, &value))) - *advanced = value; - if (SUCCEEDED(IMFAttributes_GetUINT32(reader->attributes, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, &value))) - return value || *advanced; + if (!compressed) + { + mediatype_get_stride_and_sample_size(output_type, &stride, &sample_size, &hr); - return *advanced; + mediatype_set_uint32(output_type, &MF_MT_COMPRESSED, compressed, &hr); + mediatype_set_uint32(output_type, &MF_MT_DEFAULT_STRIDE, abs(stride), &hr); + mediatype_set_uint32(output_type, &MF_MT_SAMPLE_SIZE, sample_size, &hr); + } + + return hr; } static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL decoder, BOOL allow_processor, @@ -2059,12 +1977,21 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL list_init(&entry->entry); entry->category = category; - if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio) - && SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &entry->min_buffer_size))) + if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Audio)) { UINT32 bytes_per_second; - if (SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second))) + /* decoders require to have MF_MT_AUDIO_BITS_PER_SAMPLE attribute set, but the source reader doesn't */ + if (FAILED(IMFMediaType_GetItem(output_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, NULL))) + { + if (IsEqualGUID(&out_type.guidSubtype, &MFAudioFormat_PCM)) + IMFMediaType_SetUINT32(output_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, 16); + else if (IsEqualGUID(&out_type.guidSubtype, &MFAudioFormat_Float)) + IMFMediaType_SetUINT32(output_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, 32); + } + + if (SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &entry->min_buffer_size)) + && SUCCEEDED(IMFMediaType_GetUINT32(output_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second))) entry->min_buffer_size = max(entry->min_buffer_size, bytes_per_second); } @@ -2078,6 +2005,15 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL out_type.guidSubtype = MFVideoFormat_RGB32; } + if (IsEqualGUID(&out_type.guidMajorType, &MFMediaType_Video) && IsEqualGUID(&out_type.guidSubtype, &MFVideoFormat_IYUV) + && IsEqualGUID(&category, &MFT_CATEGORY_VIDEO_DECODER)) + { + /* The WMV video decoder isn't registered for MFVideoFormat_IYUV, but selecting it as an output format still succeeds, + * the host decoders usually support IYUV as well, so fixup the subtype for MFTEnumEx. + */ + WARN("Fixing up MFVideoFormat_IYUV subtype for the video processor\n"); + out_type.guidSubtype = MFVideoFormat_NV12; + } count = 0; if (SUCCEEDED(hr = MFTEnumEx(category, 0, &in_type, allow_processor ? NULL : &out_type, &activates, &count))) @@ -2120,7 +2056,11 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)) && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type))) { - if (SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type)) + BOOL enable_advanced; + + source_reader_allow_video_processor(reader, &enable_advanced); + + if ((SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type, enable_advanced))) && FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0)) && FAILED(hr = set_matching_transform_output_type(transform, output_type)) && allow_processor && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type))) @@ -2128,7 +2068,8 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL struct transform_entry *converter; if (SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, media_type, 0)) - && SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type)) + && SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type, enable_advanced)) + && (enable_advanced || SUCCEEDED(hr = set_default_video_attributes(reader, output_type))) && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, media_type, output_type, &converter))) list_add_tail(&entry->entry, &converter->entry); @@ -2239,6 +2180,7 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReaderEx *iface, D IMFMediaType *type) { struct source_reader *reader = impl_from_IMFSourceReaderEx(iface); + IMFMediaType *output_type; HRESULT hr; TRACE("%p, %#lx, %p, %p.\n", iface, index, reserved, type); @@ -2258,18 +2200,25 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReaderEx *iface, D if (index >= reader->stream_count) return MF_E_INVALIDSTREAMNUMBER; + if (FAILED(hr = MFCreateMediaType(&output_type))) + return hr; + if (FAILED(IMFMediaType_CopyAllItems(type, (IMFAttributes *)output_type))) + { + IMFMediaType_Release(output_type); + return hr; + } + /* FIXME: setting the output type while streaming should trigger a flush */ EnterCriticalSection(&reader->cs); - hr = source_reader_set_compatible_media_type(reader, index, type); + hr = source_reader_set_compatible_media_type(reader, index, output_type); if (hr == S_FALSE) - hr = source_reader_create_decoder_for_stream(reader, index, type); - if (SUCCEEDED(hr)) - hr = source_reader_setup_sample_allocator(reader, index); + hr = source_reader_create_decoder_for_stream(reader, index, output_type); LeaveCriticalSection(&reader->cs); + IMFMediaType_Release(output_type); return hr; } @@ -2492,8 +2441,19 @@ static HRESULT WINAPI src_reader_Flush(IMFSourceReaderEx *iface, DWORD index) struct source_reader *reader = impl_from_IMFSourceReaderEx(iface); HRESULT hr; + const char *sgi; + TRACE("%p, %#lx.\n", iface, index); + sgi = getenv("SteamGameId"); + if (sgi && strcmp(sgi, "1293160") == 0) + { + /* In The Medium flushes sometimes lead to the callback + calling objects that have already been destroyed. */ + WARN("ignoring flush\n"); + return S_OK; + } + EnterCriticalSection(&reader->cs); if (reader->async_callback) @@ -2752,6 +2712,8 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri unsigned int i; HRESULT hr; + const char *sgi; + object = calloc(1, sizeof(*object)); if (!object) return E_OUTOFMEMORY; @@ -2873,6 +2835,16 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri } } + if (object->stream_count > 1 && (sgi = getenv("SteamGameId")) && strcmp(sgi, "462780") == 0) + { + /* Darksiders Warmastered Edition ends media sampling only when MF_SOURCE_READERF_ENDOFSTREAM + * is returned for all streams. If audio and video end simultaneously then ENDOFSTREAM is + * flagged only for stream 0, therefore the game depends on a slight time difference which + * usually does not occur for the fourth splash video. */ + WARN("HACK: enabled flagging ENDOFSTREAM for all streams.\n"); + object->flag_eos_for_all_streams = TRUE; + } + if (FAILED(hr = MFLockSharedWorkQueue(L"", 0, NULL, &object->queue))) WARN("Failed to acquired shared queue, hr %#lx.\n", hr); diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index b6981479a1b6..2e75e5089b2c 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1807,6 +1807,8 @@ static void test_source_reader_transforms(BOOL enable_processing, BOOL enable_ad ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), ATTR_UINT32(MF_MT_COMPRESSED, 0, .todo = TRUE), ATTR_UINT32(MF_MT_INTERLACE_MODE, 2, .todo_value = TRUE), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 96, .not_present = TRUE), + {0}, }; IMFStreamDescriptor *video_stream; IMFSourceReaderEx *reader_ex; @@ -2644,11 +2646,11 @@ static HRESULT WINAPI test_decoder_ProcessOutput(IMFTransform *iface, DWORD flag hr = IMFSample_GetBufferByIndex(data->pSample, 0, &buffer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine check_interface(buffer, &IID_IMF2DBuffer2, TRUE); - todo_wine check_interface(buffer, &IID_IMFGetService, TRUE); + check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + check_interface(buffer, &IID_IMFGetService, TRUE); check_interface(buffer, &IID_IMFDXGIBuffer, FALSE); hr = MFGetService((IUnknown *)buffer, &MR_BUFFER_SERVICE, &IID_IDirect3DSurface9, (void **)&unknown); - todo_wine ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); + ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); IMFMediaBuffer_Release(buffer); } diff --git a/dlls/mfsrcsnk/factory.c b/dlls/mfsrcsnk/factory.c index c0a02d5fa9de..d8fe4268feb2 100644 --- a/dlls/mfsrcsnk/factory.c +++ b/dlls/mfsrcsnk/factory.c @@ -33,6 +33,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out) return IClassFactory_QueryInterface(&avi_byte_stream_plugin_factory, riid, out); if (IsEqualGUID(clsid, &CLSID_WAVByteStreamPlugin)) return IClassFactory_QueryInterface(&wav_byte_stream_plugin_factory, riid, out); + if (IsEqualGUID(clsid, &CLSID_MP3ByteStreamPlugin)) + return IClassFactory_QueryInterface(&mp3_byte_stream_plugin_factory, riid, out); if (IsEqualGUID(clsid, &CLSID_MFWAVESinkClassFactory)) return IClassFactory_QueryInterface(wave_sink_class_factory, riid, out); diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c index ac5f013d9cd5..8eef19c31928 100644 --- a/dlls/mfsrcsnk/media_source.c +++ b/dlls/mfsrcsnk/media_source.c @@ -26,6 +26,49 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +#define DEFINE_MF_ASYNC_PARAMS(type) \ + static struct type *type ## _from_IUnknown(IUnknown *iface) \ + { \ + return CONTAINING_RECORD(iface, struct type, IUnknown_iface); \ + } \ + static HRESULT WINAPI type ## _QueryInterface(IUnknown *iface, REFIID iid, void **out) \ + { \ + if (IsEqualIID(iid, &IID_IUnknown)) \ + { \ + IUnknown_AddRef(iface); \ + *out = iface; \ + return S_OK; \ + } \ + *out = NULL; \ + return E_NOINTERFACE; \ + } \ + static ULONG WINAPI type ## _AddRef(IUnknown *iface) \ + { \ + struct type *object = type ## _from_IUnknown(iface); \ + return InterlockedIncrement(&object->refcount); \ + } \ + static ULONG WINAPI type ## _Release(IUnknown *iface) \ + { \ + struct type *object = type ## _from_IUnknown(iface); \ + ULONG ref = InterlockedDecrement(&object->refcount); \ + if (!ref) type ## _ ## destroy(object); \ + return ref; \ + } \ + static const IUnknownVtbl type ## _vtbl = \ + { \ + type ## _QueryInterface, \ + type ## _AddRef, \ + type ## _Release, \ + }; \ + static struct type *type ## _alloc(void) \ + { \ + struct type *object; \ + if (!(object = calloc(1, sizeof(*object)))) return NULL; \ + object->IUnknown_iface.lpVtbl = &type ## _vtbl; \ + object->refcount = 1; \ + return object; \ + } + #define DEFINE_MF_ASYNC_CALLBACK_(type, name, impl_from, pfx, mem, expr) \ static struct type *impl_from(IMFAsyncCallback *iface) \ { \ @@ -80,7 +123,7 @@ struct object_entry static void object_entry_destroy(struct object_entry *entry) { - if (entry->object) IUnknown_AddRef( entry->object ); + if (entry->object) IUnknown_Release( entry->object ); free(entry); } @@ -137,70 +180,52 @@ struct async_start_params PROPVARIANT position; }; -static struct async_start_params *async_start_params_from_IUnknown(IUnknown *iface) -{ - return CONTAINING_RECORD(iface, struct async_start_params, IUnknown_iface); -} - -static HRESULT WINAPI async_start_params_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +static void async_start_params_destroy(struct async_start_params *params) { - struct async_start_params *params = async_start_params_from_IUnknown(iface); - - if (IsEqualIID(riid, &IID_IUnknown)) - { - IUnknown_AddRef(¶ms->IUnknown_iface); - *obj = ¶ms->IUnknown_iface; - return S_OK; - } - - WARN("Unsupported interface %s\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; + IMFPresentationDescriptor_Release(params->descriptor); + PropVariantClear(¶ms->position); + free(params); } -static ULONG WINAPI async_start_params_AddRef(IUnknown *iface) -{ - struct async_start_params *params = async_start_params_from_IUnknown(iface); - return InterlockedIncrement(¶ms->refcount); -} +DEFINE_MF_ASYNC_PARAMS(async_start_params); -static ULONG WINAPI async_start_params_Release(IUnknown *iface) +static HRESULT async_start_params_create(IMFPresentationDescriptor *descriptor, const GUID *time_format, + const PROPVARIANT *position, IUnknown **out) { - struct async_start_params *params = async_start_params_from_IUnknown(iface); - ULONG refcount = InterlockedDecrement(¶ms->refcount); + struct async_start_params *params; - if (!refcount) - { - IMFPresentationDescriptor_Release(params->descriptor); - PropVariantClear(¶ms->position); - free(params); - } + if (!(params = async_start_params_alloc())) return E_OUTOFMEMORY; + params->descriptor = descriptor; + IMFPresentationDescriptor_AddRef(descriptor); + params->format = *time_format; + PropVariantCopy(¶ms->position, position); - return refcount; + *out = ¶ms->IUnknown_iface; + return S_OK; } -static const IUnknownVtbl async_start_params_vtbl = +struct async_set_rate_params { - async_start_params_QueryInterface, - async_start_params_AddRef, - async_start_params_Release, + IUnknown IUnknown_iface; + LONG refcount; + float rate; + BOOL thin; }; -static HRESULT async_start_params_create(IMFPresentationDescriptor *descriptor, const GUID *time_format, - const PROPVARIANT *position, IUnknown **out) +static void async_set_rate_params_destroy(struct async_set_rate_params *params) { - struct async_start_params *params; + free(params); +} - if (!(params = calloc(1, sizeof(*params)))) - return E_OUTOFMEMORY; +DEFINE_MF_ASYNC_PARAMS(async_set_rate_params); - params->IUnknown_iface.lpVtbl = &async_start_params_vtbl; - params->refcount = 1; +static HRESULT async_set_rate_params_create(float rate, BOOL thin, IUnknown **out) +{ + struct async_set_rate_params *params; - params->descriptor = descriptor; - IMFPresentationDescriptor_AddRef(descriptor); - params->format = *time_format; - PropVariantCopy(¶ms->position, position); + if (!(params = async_set_rate_params_alloc())) return E_OUTOFMEMORY; + params->rate = rate; + params->thin = thin; *out = ¶ms->IUnknown_iface; return S_OK; @@ -210,6 +235,7 @@ struct media_stream { IMFMediaStream IMFMediaStream_iface; IMFAsyncCallback async_request_iface; + IMFAsyncCallback async_request_thin_iface; LONG refcount; IMFMediaSource *source; @@ -220,6 +246,8 @@ struct media_stream BOOL active; BOOL eos; + BOOL thin; + BOOL pending_thin; }; struct media_source @@ -233,17 +261,21 @@ struct media_source IMFAsyncCallback async_stop_iface; IMFAsyncCallback async_pause_iface; IMFAsyncCallback async_read_iface; + IMFAsyncCallback async_set_rate_iface; LONG refcount; CRITICAL_SECTION cs; + IMFAsyncResult *shutdown_result; IMFMediaEventQueue *queue; IMFByteStream *stream; WCHAR *url; float rate; + BOOL thin; struct winedmo_demuxer winedmo_demuxer; struct winedmo_stream winedmo_stream; UINT64 file_size; + UINT64 position; INT64 duration; UINT stream_count; WCHAR mime_type[256]; @@ -266,13 +298,34 @@ static struct media_source *media_source_from_IMFMediaSource(IMFMediaSource *ifa return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface); } +static void queue_media_event_value(IMFMediaEventQueue *queue, MediaEventType type, const PROPVARIANT *value) +{ + HRESULT hr; + if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(queue, type, &GUID_NULL, S_OK, value))) + ERR("Failed to queue event of type %#lx to queue %p, hr %#lx\n", type, queue, hr); +} + +static void media_stream_set_thin(struct media_stream *stream, BOOL thin) +{ + if (stream->thin != thin) + { + PROPVARIANT param = {.vt = VT_INT, .iVal = thin}; + stream->thin = thin; + queue_media_event_value(stream->queue, MEStreamThinMode, ¶m); + } +} + static void media_stream_send_sample(struct media_stream *stream, IMFSample *sample, IUnknown *token) { HRESULT hr = S_OK; if (!token || SUCCEEDED(hr = IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token))) + { + /* thinning stays enabled until a sample is sent, always a keyframe as it was enabled */ + if (!stream->pending_thin) media_stream_set_thin(stream, FALSE); hr = IMFMediaEventQueue_QueueEventParamUnk(stream->queue, MEMediaSample, &GUID_NULL, S_OK, (IUnknown *)sample); + } if (FAILED(hr)) ERR("Failed to send stream %p sample, hr %#lx\n", stream, hr); } @@ -289,6 +342,17 @@ static struct media_stream *media_stream_from_index(struct media_source *source, return NULL; } +static BOOL media_stream_accepts_sample(struct media_stream *stream, IMFSample *sample, BOOL thin) +{ + BOOL thinning = thin || stream->thin; + UINT32 keyframe; + + if (thinning && SUCCEEDED(IMFSample_GetUINT32(sample, &MFSampleExtension_CleanPoint, &keyframe))) + return keyframe; + + return !thinning; +} + static HRESULT media_source_send_sample(struct media_source *source, UINT index, IMFSample *sample) { struct media_stream *stream; @@ -298,17 +362,24 @@ static HRESULT media_source_send_sample(struct media_source *source, UINT index, if (!(stream = media_stream_from_index(source, index)) || !stream->active) return S_FALSE; - if (SUCCEEDED(hr = object_queue_pop(&stream->tokens, &token))) + if (list_empty(&stream->tokens)) { - media_stream_send_sample(stream, sample, token); - if (token) IUnknown_Release(token); - return S_OK; + if (FAILED(hr = object_queue_push(&stream->samples, (IUnknown *)sample))) + return hr; + return S_FALSE; } - if (FAILED(hr = object_queue_push(&stream->samples, (IUnknown *)sample))) - return hr; + if (!media_stream_accepts_sample(stream, sample, stream->pending_thin)) + { + /* thinning stays disabled until a sample is skipped */ + if (stream->pending_thin) media_stream_set_thin(stream, TRUE); + return S_FALSE; + } - return S_FALSE; + object_queue_pop(&stream->tokens, &token); + media_stream_send_sample(stream, sample, token); + if (token) IUnknown_Release(token); + return S_OK; } static void queue_media_event_object(IMFMediaEventQueue *queue, MediaEventType type, IUnknown *object) @@ -318,13 +389,6 @@ static void queue_media_event_object(IMFMediaEventQueue *queue, MediaEventType t ERR("Failed to queue event of type %#lx to queue %p, hr %#lx\n", type, queue, hr); } -static void queue_media_event_value(IMFMediaEventQueue *queue, MediaEventType type, const PROPVARIANT *value) -{ - HRESULT hr; - if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(queue, type, &GUID_NULL, S_OK, value))) - ERR("Failed to queue event of type %#lx to queue %p, hr %#lx\n", type, queue, hr); -} - static void queue_media_source_read(struct media_source *source) { HRESULT hr; @@ -800,22 +864,50 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM return hr; } -static HRESULT media_stream_async_request(struct media_stream *stream, IMFAsyncResult *result) +static HRESULT media_stream_pop_sample(struct media_stream *stream, IMFSample **pSample) +{ + HRESULT hr; + + while (SUCCEEDED(hr = object_queue_pop(&stream->samples, (IUnknown **)pSample)) + && !media_stream_accepts_sample(stream, *pSample, stream->pending_thin)) + { + /* thinning stays disabled until a sample is skipped */ + if (stream->pending_thin) media_stream_set_thin(stream, TRUE); + IMFSample_Release(*pSample); + } + + return hr; +} + +static HRESULT media_source_request_stream_sample(struct media_source *source, struct media_stream *stream, IUnknown *token) { - struct media_source *source = media_source_from_IMFMediaSource(stream->source); - IUnknown *token = IMFAsyncResult_GetStateNoAddRef(result); IMFSample *sample; HRESULT hr = S_OK; - EnterCriticalSection(&source->cs); - if (source->state == SOURCE_SHUTDOWN) - hr = MF_E_SHUTDOWN; - else if (source->state == SOURCE_RUNNING && SUCCEEDED(hr = object_queue_pop(&stream->samples, (IUnknown **)&sample))) + return MF_E_SHUTDOWN; + + if (source->state == SOURCE_RUNNING && SUCCEEDED(hr = media_stream_pop_sample(stream, &sample))) + { media_stream_send_sample(stream, sample, token); - else if (SUCCEEDED(hr = object_queue_push(&stream->tokens, token)) && source->state == SOURCE_RUNNING) + IMFSample_Release(sample); + return S_OK; + } + + if (SUCCEEDED(hr = object_queue_push(&stream->tokens, token)) && source->state == SOURCE_RUNNING) queue_media_source_read(source); + return hr; +} + +static HRESULT media_stream_async_request(struct media_stream *stream, IMFAsyncResult *result) +{ + struct media_source *source = media_source_from_IMFMediaSource(stream->source); + IUnknown *token = IMFAsyncResult_GetStateNoAddRef(result); + HRESULT hr = S_OK; + EnterCriticalSection(&source->cs); + stream->pending_thin = FALSE; + hr = media_source_request_stream_sample(source, stream, token); LeaveCriticalSection(&source->cs); return hr; @@ -823,6 +915,22 @@ static HRESULT media_stream_async_request(struct media_stream *stream, IMFAsyncR DEFINE_MF_ASYNC_CALLBACK(media_stream, async_request, IMFMediaStream_iface) +static HRESULT media_stream_async_request_thin(struct media_stream *stream, IMFAsyncResult *result) +{ + struct media_source *source = media_source_from_IMFMediaSource(stream->source); + IUnknown *token = IMFAsyncResult_GetStateNoAddRef(result); + HRESULT hr = S_OK; + + EnterCriticalSection(&source->cs); + stream->pending_thin = TRUE; + hr = media_source_request_stream_sample(source, stream, token); + LeaveCriticalSection(&source->cs); + + return hr; +} + +DEFINE_MF_ASYNC_CALLBACK(media_stream, async_request_thin, IMFMediaStream_iface) + static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) { struct media_stream *stream = media_stream_from_IMFMediaStream(iface); @@ -839,6 +947,8 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown hr = MF_E_MEDIA_SOURCE_WRONGSTATE; else if (stream->eos) hr = MF_E_END_OF_STREAM; + else if (source->thin) + hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &stream->async_request_thin_iface, token); else hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &stream->async_request_iface, token); @@ -873,6 +983,7 @@ static HRESULT media_stream_create(IMFMediaSource *source, IMFStreamDescriptor * object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl; object->async_request_iface.lpVtbl = &media_stream_async_request_vtbl; + object->async_request_thin_iface.lpVtbl = &media_stream_async_request_thin_vtbl; object->refcount = 1; if (FAILED(hr = MFCreateEventQueue(&object->queue))) @@ -1035,26 +1146,46 @@ static ULONG WINAPI media_source_IMFRateControl_Release(IMFRateControl *iface) return IMFMediaSource_Release(&source->IMFMediaSource_iface); } +static HRESULT media_source_async_set_rate(struct media_source *source, IMFAsyncResult *result) +{ + struct async_set_rate_params *params; + IUnknown *state; + + if (!(state = IMFAsyncResult_GetStateNoAddRef(result))) return E_INVALIDARG; + params = async_set_rate_params_from_IUnknown(state); + + EnterCriticalSection(&source->cs); + source->rate = params->rate; + source->thin = params->thin; + LeaveCriticalSection(&source->cs); + + queue_media_event_value(source->queue, MESourceRateChanged, NULL); + return S_OK; +} + +DEFINE_MF_ASYNC_CALLBACK(media_source, async_set_rate, IMFMediaSource_iface) + static HRESULT WINAPI media_source_IMFRateControl_SetRate(IMFRateControl *iface, BOOL thin, float rate) { struct media_source *source = media_source_from_IMFRateControl(iface); + IUnknown *params; HRESULT hr; FIXME("source %p, thin %d, rate %f, stub!\n", source, thin, rate); if (rate < 0.0f) return MF_E_REVERSE_UNSUPPORTED; - if (thin) - return MF_E_THINNING_UNSUPPORTED; if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL))) return hr; - EnterCriticalSection(&source->cs); - source->rate = rate; - LeaveCriticalSection(&source->cs); + if (FAILED(hr = async_set_rate_params_create(rate, thin, ¶ms))) + return hr; + + hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &source->async_set_rate_iface, params); + IUnknown_Release(params); - return IMFMediaEventQueue_QueueEventParamVar(source->queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL); + return hr; } static HRESULT WINAPI media_source_IMFRateControl_GetRate(IMFRateControl *iface, BOOL *thin, float *rate) @@ -1063,11 +1194,10 @@ static HRESULT WINAPI media_source_IMFRateControl_GetRate(IMFRateControl *iface, TRACE("source %p, thin %p, rate %p\n", source, thin, rate); - if (thin) - *thin = FALSE; - EnterCriticalSection(&source->cs); *rate = source->rate; + if (thin) + *thin = source->thin; LeaveCriticalSection(&source->cs); return S_OK; @@ -1132,6 +1262,8 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface) free(source->stream_map); free(source->streams); + if (source->shutdown_result) + IMFAsyncResult_Release(source->shutdown_result); IMFMediaEventQueue_Release(source->queue); IMFByteStream_Release(source->stream); free(source->url); @@ -1331,16 +1463,25 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) } source->state = SOURCE_SHUTDOWN; + IMFMediaEventQueue_QueueEventParamVar(source->queue, MEError, &GUID_NULL, MF_E_SHUTDOWN, NULL); IMFMediaEventQueue_Shutdown(source->queue); IMFByteStream_Close(source->stream); while (source->stream_count--) { struct media_stream *stream = source->streams[source->stream_count]; + IMFMediaEventQueue_QueueEventParamVar(stream->queue, MEError, &GUID_NULL, MF_E_SHUTDOWN, NULL); IMFMediaEventQueue_Shutdown(stream->queue); IMFMediaStream_Release(&stream->IMFMediaStream_iface); } + if (source->shutdown_result) + { + MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, source->shutdown_result); + IMFAsyncResult_Release(source->shutdown_result); + source->shutdown_result = NULL; + } + LeaveCriticalSection(&source->cs); return S_OK; @@ -1385,8 +1526,44 @@ static HRESULT media_type_from_winedmo_format( GUID major, union winedmo_format if (IsEqualGUID( &major, &MFMediaType_Video )) return media_type_from_mf_video_format( &format->video, media_type ); + if (IsEqualGUID( &major, &MFMediaType_Audio )) - return MFCreateAudioMediaType( &format->audio, (IMFAudioMediaType **)media_type ); + { + const char *sgi = getenv("SteamGameId"); + WAVEFORMATEXTENSIBLE *audio = (WAVEFORMATEXTENSIBLE *)&format->audio; + + /* Warhammer 40,000: Dakka Squadron depends on the input format belonging to a specific set of formats. + * Append transcoded audio info to the user data so it can be restored, and create a fake AAC media + * type instead. If decoding support is added, PCM will work without a hack. */ + if (sgi && !strcmp(sgi, "1253190") && format->audio.wFormatTag == WAVE_FORMAT_EXTENSIBLE + && IsEqualGUID(&audio->SubFormat, &MFAudioFormat_Vorbis)) + { + size_t config_data_size = format->audio.cbSize + sizeof(WAVEFORMATEX) - sizeof(WAVEFORMATEXTENSIBLE); + size_t data_size = config_data_size + sizeof(WAVEFORMATEXTENSIBLE); + HEAACWAVEFORMAT *hwf; + HRESULT hr; + + if (!(hwf = malloc(offsetof(HEAACWAVEFORMAT, pbAudioSpecificConfig[data_size])))) + return E_OUTOFMEMORY; + + hwf->wfInfo.wfx = audio->Format; + hwf->wfInfo.wfx.wFormatTag = WAVE_FORMAT_MPEG_HEAAC; + hwf->wfInfo.wfx.cbSize = sizeof(HEAACWAVEINFO) + data_size - sizeof(WAVEFORMATEX); + hwf->wfInfo.wPayloadType = 0; + hwf->wfInfo.wAudioProfileLevelIndication = 0; + hwf->wfInfo.wStructType = 0; + hwf->wfInfo.wReserved1 = 0; + hwf->wfInfo.dwReserved2 = 0; + memcpy(hwf->pbAudioSpecificConfig, (BYTE *)(audio + 1), config_data_size); + memcpy(&hwf->pbAudioSpecificConfig[config_data_size], audio, sizeof(*audio)); + + hr = MFCreateAudioMediaType((WAVEFORMATEX *)hwf, (IMFAudioMediaType **)media_type); + free(hwf); + return hr; + } + + return MFCreateAudioMediaType(&format->audio, (IMFAudioMediaType **)media_type); + } FIXME( "Unsupported major type %s\n", debugstr_guid( &major ) ); return E_NOTIMPL; @@ -1420,10 +1597,12 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea if (wcscmp(source->mime_type, L"video/mp4")) { - for (i = stream_count - 1; i >= 0; i--) + for (i = 0; i < stream_count; i++) { - TRACE("mapping source %p stream %u to demuxer stream %u\n", source, i, i); - source->stream_map[i] = i; + if (FAILED(get_stream_media_type(source->winedmo_demuxer, i, &major, NULL))) + continue; + TRACE("mapping source %p stream %u to demuxer stream %u\n", source, n, i); + source->stream_map[n++] = i; } return; } @@ -1515,11 +1694,11 @@ static void media_source_init_descriptors(struct media_source *source) NTSTATUS status; GUID major; - if (FAILED(status = winedmo_demuxer_stream_lang(source->winedmo_demuxer, source->stream_map[i], buffer, ARRAY_SIZE(buffer))) + if ((status = winedmo_demuxer_stream_lang(source->winedmo_demuxer, source->stream_map[i], buffer, ARRAY_SIZE(buffer))) || (!wcscmp(source->mime_type, L"video/mp4") && FAILED(normalize_mp4_language_code(source, buffer))) || FAILED(IMFStreamDescriptor_SetString(stream->descriptor, &MF_SD_LANGUAGE, buffer))) WARN("Failed to set stream descriptor language, status %#lx\n", status); - if (FAILED(status = winedmo_demuxer_stream_name(source->winedmo_demuxer, source->stream_map[i], buffer, ARRAY_SIZE(buffer))) + if ((status = winedmo_demuxer_stream_name(source->winedmo_demuxer, source->stream_map[i], buffer, ARRAY_SIZE(buffer))) || FAILED(IMFStreamDescriptor_SetString(stream->descriptor, &MF_SD_STREAM_NAME, buffer))) WARN("Failed to set stream descriptor name, status %#lx\n", status); @@ -1597,16 +1776,26 @@ static NTSTATUS CDECL media_source_seek_cb( struct winedmo_stream *stream, UINT6 if (FAILED(IMFByteStream_Seek(source->stream, msoBegin, *pos, 0, pos))) return STATUS_UNSUCCESSFUL; + + source->position = *pos; return STATUS_SUCCESS; } static NTSTATUS CDECL media_source_read_cb(struct winedmo_stream *stream, BYTE *buffer, ULONG *size) { struct media_source *source = CONTAINING_RECORD(stream, struct media_source, winedmo_stream); + UINT64 position; + TRACE("stream %p, buffer %p, size %p\n", stream, buffer, size); + if (SUCCEEDED(IMFByteStream_GetCurrentPosition(source->stream, &position)) && position != source->position + && FAILED(IMFByteStream_SetCurrentPosition(source->stream, source->position))) + WARN("Failed to set current position\n"); + if (FAILED(IMFByteStream_Read(source->stream, buffer, *size, size))) return STATUS_UNSUCCESSFUL; + + source->position += *size; return STATUS_SUCCESS; } @@ -1657,7 +1846,7 @@ static HRESULT media_source_async_create(struct media_source *source, IMFAsyncRe GUID major; if (FAILED(hr = get_stream_media_type(source->winedmo_demuxer, source->stream_map[i], &major, &media_type))) - goto done; + continue; if (SUCCEEDED(hr = stream_descriptor_create(i + 1, media_type, &descriptor))) { if (SUCCEEDED(hr = media_stream_create(&source->IMFMediaSource_iface, descriptor, &source->streams[i]))) @@ -1716,6 +1905,7 @@ static HRESULT media_source_create(const WCHAR *url, IMFByteStream *stream, IMFM source->async_stop_iface.lpVtbl = &media_source_async_stop_vtbl; source->async_pause_iface.lpVtbl = &media_source_async_pause_vtbl; source->async_read_iface.lpVtbl = &media_source_async_read_vtbl; + source->async_set_rate_iface.lpVtbl = &media_source_async_set_rate_vtbl; source->refcount = 1; if (FAILED(hr = MFCreateEventQueue(&source->queue))) @@ -1899,7 +2089,7 @@ static BOOL use_gst_byte_stream_handler(void) RRF_RT_REG_DWORD, NULL, &result, &size )) return !result; - return TRUE; + return FALSE; } static HRESULT WINAPI asf_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, @@ -2005,3 +2195,29 @@ static const IClassFactoryVtbl wav_byte_stream_plugin_factory_vtbl = }; IClassFactory wav_byte_stream_plugin_factory = {&wav_byte_stream_plugin_factory_vtbl}; + +static HRESULT WINAPI mp3_byte_stream_plugin_factory_CreateInstance(IClassFactory *iface, + IUnknown *outer, REFIID riid, void **out) +{ + NTSTATUS status; + + if ((status = winedmo_demuxer_check("audio/mp3")) || use_gst_byte_stream_handler()) + { + static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618,0x5e5a,0x468a,{0x9f,0x15,0xd8,0x27,0xa9,0xa0,0x81,0x62}}; + if (status) WARN("Unsupported demuxer, status %#lx.\n", status); + return CoCreateInstance(&CLSID_GStreamerByteStreamHandler, outer, CLSCTX_INPROC_SERVER, riid, out); + } + + return byte_stream_plugin_create(outer, riid, out); +} + +static const IClassFactoryVtbl mp3_byte_stream_plugin_factory_vtbl = +{ + class_factory_QueryInterface, + class_factory_AddRef, + class_factory_Release, + mp3_byte_stream_plugin_factory_CreateInstance, + class_factory_LockServer, +}; + +IClassFactory mp3_byte_stream_plugin_factory = {&mp3_byte_stream_plugin_factory_vtbl}; diff --git a/dlls/mfsrcsnk/media_source.h b/dlls/mfsrcsnk/media_source.h index 1e6c90ea7d5b..7703e7634ec0 100644 --- a/dlls/mfsrcsnk/media_source.h +++ b/dlls/mfsrcsnk/media_source.h @@ -24,3 +24,4 @@ extern IClassFactory asf_byte_stream_plugin_factory; extern IClassFactory avi_byte_stream_plugin_factory; extern IClassFactory mpeg4_byte_stream_plugin_factory; extern IClassFactory wav_byte_stream_plugin_factory; +extern IClassFactory mp3_byte_stream_plugin_factory; diff --git a/dlls/mfsrcsnk/mfsrcsnk.idl b/dlls/mfsrcsnk/mfsrcsnk.idl index 10b41769060c..e6473b355e92 100644 --- a/dlls/mfsrcsnk/mfsrcsnk.idl +++ b/dlls/mfsrcsnk/mfsrcsnk.idl @@ -38,3 +38,10 @@ coclass MFWAVESinkClassFactory { } uuid(42c9b9f5-16fc-47ef-af22-da05f7c842e3) ] coclass WAVByteStreamPlugin {} + +[ + helpstring("MP3 Byte Stream Handler"), + threading(both), + uuid(a82e50ba-8e92-41eb-9df2-433f50ec2993) +] +coclass MP3ByteStreamPlugin {} diff --git a/dlls/mfsrcsnk/mfsrcsnk.rgs b/dlls/mfsrcsnk/mfsrcsnk.rgs index c8272189273b..dcdcb165db12 100644 --- a/dlls/mfsrcsnk/mfsrcsnk.rgs +++ b/dlls/mfsrcsnk/mfsrcsnk.rgs @@ -37,6 +37,19 @@ HKLM { val '{42c9b9f5-16fc-47ef-af22-da05f7c842e3}' = s 'WAV Byte Stream Handler' } + + '.mp3' + { + val '{a82e50ba-8e92-41eb-9df2-433f50ec2993}' = s 'MP3 Byte Stream Handler' + } + 'audio/mp3' + { + val '{a82e50ba-8e92-41eb-9df2-433f50ec2993}' = s 'MP3 Byte Stream Handler' + } + 'audio/x-mp3' + { + val '{a82e50ba-8e92-41eb-9df2-433f50ec2993}' = s 'MP3 Byte Stream Handler' + } } } } diff --git a/dlls/mfsrcsnk/tests/Makefile.in b/dlls/mfsrcsnk/tests/Makefile.in index 55a842562662..89889d6f723c 100644 --- a/dlls/mfsrcsnk/tests/Makefile.in +++ b/dlls/mfsrcsnk/tests/Makefile.in @@ -2,4 +2,5 @@ TESTDLL = mfsrcsnk.dll IMPORTS = ole32 mfsrcsnk mfplat mf uuid mfuuid SOURCES = \ - mfsrcsnk.c + mfsrcsnk.c \ + resource.rc diff --git a/dlls/mfsrcsnk/tests/mfsrcsnk.c b/dlls/mfsrcsnk/tests/mfsrcsnk.c index 1aba4094c629..03d206a5f556 100644 --- a/dlls/mfsrcsnk/tests/mfsrcsnk.c +++ b/dlls/mfsrcsnk/tests/mfsrcsnk.c @@ -26,9 +26,31 @@ #include "mfapi.h" #include "mfidl.h" #include "mferror.h" +#include "wine/mfinternal.h" #include "wine/test.h" +static const char *debugstr_time(LONGLONG time) +{ + ULONGLONG abstime = time >= 0 ? time : -time; + unsigned int i = 0, j = 0; + char buffer[23], rev[23]; + + while (abstime || i <= 8) + { + buffer[i++] = '0' + (abstime % 10); + abstime /= 10; + if (i == 7) buffer[i++] = '.'; + } + if (time < 0) buffer[i++] = '-'; + + while (i--) rev[j++] = buffer[i]; + while (rev[j-1] == '0' && rev[j-2] != '.') --j; + rev[j] = 0; + + return wine_dbg_sprintf("%s", rev); +} + #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) { @@ -204,6 +226,604 @@ static void test_wave_sink(void) IMFByteStream_Release(bytestream); } +struct source_create_callback +{ + IMFAsyncCallback iface; + LONG refcount; + + IMFByteStreamHandler *handler; + HRESULT hr; + MF_OBJECT_TYPE type; + IUnknown *object; + HANDLE event; +}; + +struct source_create_callback *source_create_callback_from_iface(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct source_create_callback, iface); +} + +static HRESULT WINAPI source_create_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI source_create_callback_AddRef(IMFAsyncCallback *iface) +{ + struct source_create_callback *callback = source_create_callback_from_iface(iface); + return InterlockedIncrement(&callback->refcount); +} + +static ULONG WINAPI source_create_callback_Release(IMFAsyncCallback *iface) +{ + struct source_create_callback *callback = source_create_callback_from_iface(iface); + ULONG refcount = InterlockedDecrement(&callback->refcount); + if (refcount == 0) + { + if (callback->object) + IUnknown_Release(callback->object); + IMFByteStreamHandler_Release(callback->handler); + CloseHandle(callback->event); + free(callback); + } + return refcount; +} + +static HRESULT WINAPI source_create_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI source_create_callback_stream_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct source_create_callback *callback = source_create_callback_from_iface(iface); + callback->hr = IMFByteStreamHandler_EndCreateObject(callback->handler, result, &callback->type, + &callback->object); + SetEvent(callback->event); + return callback->hr; +} + +static const IMFAsyncCallbackVtbl source_create_callback_vtbl = +{ + &source_create_callback_QueryInterface, + &source_create_callback_AddRef, + &source_create_callback_Release, + &source_create_callback_GetParameters, + &source_create_callback_stream_Invoke, +}; + +static HRESULT create_source(const GUID *guid_handler, IMFByteStream *stream, IMFMediaSource **source) +{ + HRESULT hr; + IMFByteStreamHandler *handler; + struct source_create_callback *callback; + + if (!(callback = calloc(1, sizeof *callback))) + return E_OUTOFMEMORY; + hr = CoCreateInstance(guid_handler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)&handler); + if (FAILED(hr)) + { + free(callback); + return hr; + } + callback->iface.lpVtbl = &source_create_callback_vtbl; + callback->refcount = 1; + callback->handler = handler; + callback->object = NULL; + callback->type = MF_OBJECT_INVALID; + callback->hr = E_PENDING; + callback->event = CreateEventW(NULL, FALSE, FALSE, NULL); + + hr = IMFByteStreamHandler_BeginCreateObject(callback->handler, stream, NULL, + MF_RESOLUTION_MEDIASOURCE, NULL, NULL, &callback->iface, NULL); + if (FAILED(hr)) + goto done; + + WaitForSingleObject(callback->event, INFINITE); + if (FAILED(hr = callback->hr)) + goto done; + if (callback->type != MF_OBJECT_MEDIASOURCE) + { + hr = E_UNEXPECTED; + goto done; + } + + hr = S_OK; + *source = (IMFMediaSource *)callback->object; + callback->object = NULL; + +done: + IMFAsyncCallback_Release(&callback->iface); + return hr; +} + +static IMFByteStream *create_byte_stream(const BYTE *data, ULONG data_len) +{ + IMFByteStream *stream; + HRESULT hr; + + hr = MFCreateTempFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, &stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFByteStream_Write(stream, data, data_len, &data_len); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFByteStream_SetCurrentPosition(stream, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + return stream; +} + +static IMFByteStream *create_resource_byte_stream(const WCHAR *name) +{ + const BYTE *resource_data; + ULONG resource_len; + HRSRC resource; + + resource = FindResourceW(NULL, name, (const WCHAR *)RT_RCDATA); + ok(resource != 0, "FindResourceW %s failed, error %lu\n", debugstr_w(name), GetLastError()); + resource_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); + resource_len = SizeofResource(GetModuleHandleW(NULL), resource); + + return create_byte_stream(resource_data, resource_len); +} + +struct test_callback +{ + IMFAsyncCallback IMFAsyncCallback_iface; + LONG refcount; + + HANDLE event; + IMFMediaEvent *media_event; + BOOL check_media_event; +}; + +static struct test_callback *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct test_callback, IMFAsyncCallback_iface); +} + +static HRESULT WINAPI testcallback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI testcallback_AddRef(IMFAsyncCallback *iface) +{ + struct test_callback *callback = impl_from_IMFAsyncCallback(iface); + return InterlockedIncrement(&callback->refcount); +} + +static ULONG WINAPI testcallback_Release(IMFAsyncCallback *iface) +{ + struct test_callback *callback = impl_from_IMFAsyncCallback(iface); + ULONG refcount = InterlockedDecrement(&callback->refcount); + + if (!refcount) + { + if (callback->media_event) + IMFMediaEvent_Release(callback->media_event); + CloseHandle(callback->event); + free(callback); + } + + return refcount; +} + +static HRESULT WINAPI testcallback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + ok(flags != NULL && queue != NULL, "Unexpected arguments.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI testcallback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct test_callback *callback = CONTAINING_RECORD(iface, struct test_callback, IMFAsyncCallback_iface); + IUnknown *object; + HRESULT hr; + + ok(result != NULL, "Unexpected result object.\n"); + ok(!callback->media_event, "Event already present.\n"); + + if (callback->check_media_event) + { + hr = IMFAsyncResult_GetObject(result, &object); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = IMFAsyncResult_GetState(result, &object); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + callback->media_event = (void *)0xdeadbeef; + hr = IMFMediaEventGenerator_EndGetEvent((IMFMediaEventGenerator *)object, + result, &callback->media_event); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IUnknown_Release(object); + } + + SetEvent(callback->event); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl testcallbackvtbl = +{ + testcallback_QueryInterface, + testcallback_AddRef, + testcallback_Release, + testcallback_GetParameters, + testcallback_Invoke, +}; + +static IMFAsyncCallback *create_test_callback(BOOL check_media_event) +{ + struct test_callback *callback; + + if (!(callback = calloc(1, sizeof(*callback)))) + return NULL; + + callback->refcount = 1; + callback->check_media_event = check_media_event; + callback->IMFAsyncCallback_iface.lpVtbl = &testcallbackvtbl; + callback->event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!callback->event, "CreateEventW failed, error %lu\n", GetLastError()); + + return &callback->IMFAsyncCallback_iface; +} + +#define next_media_event(a, b, c, d) next_media_event_(__LINE__, (IMFMediaEventGenerator *)a, b, c, d) +static DWORD next_media_event_(int line, IMFMediaEventGenerator *source, IMFAsyncCallback *callback, DWORD timeout, + IMFMediaEvent **event) +{ + struct test_callback *impl = impl_from_IMFAsyncCallback(callback); + HRESULT hr; + DWORD ret; + + hr = IMFMediaEventGenerator_BeginGetEvent(source, &impl->IMFAsyncCallback_iface, (IUnknown *)source); + ok_(__FILE__, line)(hr == S_OK || hr == MF_S_MULTIPLE_BEGIN || hr == MF_E_MULTIPLE_SUBSCRIBERS, "Unexpected hr %#lx.\n", hr); + ret = WaitForSingleObject(impl->event, timeout); + *event = impl->media_event; + impl->media_event = NULL; + + return ret; +} + +#define wait_media_event(a, b, c, d, e) wait_media_event_(__LINE__, (IMFMediaEventGenerator *)a, b, c, d, e) +static HRESULT wait_media_event_(int line, IMFMediaEventGenerator *source, IMFAsyncCallback *callback, + MediaEventType expect_type, DWORD timeout, PROPVARIANT *value) +{ + IMFMediaEvent *event = NULL; + MediaEventType type; + HRESULT hr, status; + DWORD ret; + GUID guid; + + do + { + if (event) IMFMediaEvent_Release(event); + ret = next_media_event_(line, source, callback, timeout, &event); + if (ret) return MF_E_NO_EVENTS_AVAILABLE; + hr = IMFMediaEvent_GetType(event, &type); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok_(__FILE__, line)(type == expect_type, "got %#lx.\n", type); + } while (type != expect_type); + + hr = IMFMediaEvent_GetExtendedType(event, &guid); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok_(__FILE__, line)(IsEqualGUID(&guid, &GUID_NULL), "got extended type %s\n", debugstr_guid(&guid)); + + hr = IMFMediaEvent_GetValue(event, value); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaEvent_GetStatus(event, &status); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFMediaEvent_Release(event); + return status; +} + +static void test_sample_times_at_rate(IMFMediaSource *source, FLOAT rate, BOOL thin) +{ + static LONGLONG expect_times[] = + { + 0, 333666, + 1668333, 333666, + 2002000, 333666, + 2335666, 333666, + 2669333, 333666, + }; + static LONGLONG expect_times_thin[ARRAY_SIZE(expect_times)] = + { + 0, 333666, + 1668333, 333666, + 3336666, 333666, + 5005000, 333666, + 6673333, 333666, + }; + IMFAsyncCallback *callback, *source_callback; + IMFRateControl *rate_control; + IMFPresentationDescriptor *pd; + IMFMediaStream *stream; + IMFMediaEvent *event; + PROPVARIANT value; + LONGLONG time; + HRESULT hr; + DWORD ret; + + winetest_push_context("%f/%u", rate, thin); + + hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + value.vt = VT_EMPTY; + hr = IMFMediaSource_Start(source, pd, &GUID_NULL, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFPresentationDescriptor_Release(pd); + + callback = create_test_callback(TRUE); + source_callback = create_test_callback(TRUE); + if (!winetest_platform_is_wine) + { + hr = wait_media_event(source, source_callback, thin ? MENewStream : MEUpdatedStream, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + else + { + ret = next_media_event(source, source_callback, 100, &event); + ok(ret == 0, "Unexpected ret %#lx.\n", ret); + hr = IMFMediaEvent_GetType(event, &ret); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(!thin) + ok(ret == (thin ? MENewStream : MEUpdatedStream), "Unexpected type %#lx.\n", ret); + hr = IMFMediaEvent_GetValue(event, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaEvent_Release(event); + } + ok(value.vt == VT_UNKNOWN, "got vt %u\n", value.vt); + stream = (IMFMediaStream *)value.punkVal; + IMFMediaStream_AddRef(stream); + PropVariantClear(&value); + + hr = wait_media_event(stream, callback, MEStreamStarted, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_I8, "got vt %u\n", value.vt); + hr = wait_media_event(source, source_callback, MESourceStarted, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_I8, "got vt %u\n", value.vt); + + winetest_push_context("sample 0"); + + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_UNKNOWN, "got vt %u\n", value.vt); + hr = IMFSample_GetSampleTime((IMFSample *)value.punkVal, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(time == expect_times[0], "Unexpected time %s.\n", debugstr_time(time)); + hr = IMFSample_GetSampleDuration((IMFSample *)value.punkVal, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(time == expect_times[1], "Unexpected time %s.\n", debugstr_time(time)); + hr = IMFSample_GetSampleFlags((IMFSample *)value.punkVal, &ret); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(ret == 0, "Unexpected flags %#lx.\n", ret); + PropVariantClear(&value); + + winetest_pop_context(); + + hr = MFGetService((IUnknown *)source, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, (void **)&rate_control); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFRateControl_SetRate(rate_control, thin, rate); + todo_wine_if(thin && hr == MF_E_THINNING_UNSUPPORTED) + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = wait_media_event(source, source_callback, MESourceRateChanged, 100, &value); + todo_wine_if(thin) + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(value.vt == VT_R4, "got vt %u\n", value.vt); + ret = next_media_event(source, source_callback, 100, &event); + ok(ret == WAIT_TIMEOUT, "Unexpected ret %#lx.\n", ret); + + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (!winetest_platform_is_wine) + { + hr = wait_media_event(stream, callback, MEStreamThinMode, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_INT, "got vt %u\n", value.vt); + ok(value.iVal == thin, "Unexpected thin %d\n", value.iVal); + } + + winetest_push_context("sample 1"); + + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_UNKNOWN, "got vt %u\n", value.vt); + hr = IMFSample_GetSampleTime((IMFSample *)value.punkVal, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(time == expect_times[2], "Unexpected time %s.\n", debugstr_time(time)); + hr = IMFSample_GetSampleDuration((IMFSample *)value.punkVal, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(time == expect_times[3], "Unexpected time %s.\n", debugstr_time(time)); + hr = IMFSample_GetSampleFlags((IMFSample *)value.punkVal, &ret); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(ret == 0, "Unexpected flags %#lx.\n", ret); + PropVariantClear(&value); + + winetest_pop_context(); + + for (int i = 2; i < ARRAY_SIZE(expect_times) / 2; i++) + { + winetest_push_context("sample %u", i); + + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_UNKNOWN, "got vt %u\n", value.vt); + hr = IMFSample_GetSampleTime((IMFSample *)value.punkVal, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(time == (thin ? expect_times_thin[2 * i] : expect_times[2 * i]), "Unexpected time %s.\n", debugstr_time(time)); + hr = IMFSample_GetSampleDuration((IMFSample *)value.punkVal, &time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(time == (thin ? expect_times_thin[2 * i + 1] : expect_times[2 * i + 1]), "Unexpected time %s.\n", debugstr_time(time)); + hr = IMFSample_GetSampleFlags((IMFSample *)value.punkVal, &ret); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(ret == 0, "Unexpected flags %#lx.\n", ret); + PropVariantClear(&value); + + winetest_pop_context(); + } + + /* change rate after sample requests */ + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFRateControl_SetRate(rate_control, !thin, rate+0.5); + todo_wine_if(!thin && hr == MF_E_THINNING_UNSUPPORTED) + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* rate change event is available immediately */ + hr = wait_media_event(source, source_callback, MESourceRateChanged, 100, &value); + todo_wine_if(!thin && hr == MF_E_NO_EVENTS_AVAILABLE) + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&value); + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&value); + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&value); + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&value); + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&value); + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&value); + + /* thin mode only changes when a new sample is requested */ + hr = wait_media_event(stream, callback, MEStreamThinMode, 1000, &value); + ok(MF_E_NO_EVENTS_AVAILABLE == hr, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (!thin) + { + /* next sample is already a keyframe. thin mode only changes after some samples get skipped */ + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&value); + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + if (!winetest_platform_is_wine) + { + hr = wait_media_event(stream, callback, MEStreamThinMode, 1000, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&value); + + /* switch back to previous mode */ + hr = IMFRateControl_SetRate(rate_control, thin, rate+0.5); + todo_wine_if(thin && hr == MF_E_THINNING_UNSUPPORTED) + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(source, source_callback, MESourceRateChanged, 100, &value); + todo_wine_if(thin && hr == MF_E_NO_EVENTS_AVAILABLE) + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaStream_RequestSample(stream, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (!winetest_platform_is_wine) + { + hr = wait_media_event(stream, callback, MEStreamThinMode, 1000, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + if (thin && !winetest_platform_is_wine) + { + hr = wait_media_event(stream, callback, MEEndOfStream, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(source, source_callback, MEEndOfPresentation, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + else + { + hr = wait_media_event(stream, callback, MEMediaSample, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&value); + } + + hr = IMFMediaSource_Stop(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(source, source_callback, MESourceStopped, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_EMPTY, "got vt %u\n", value.vt); + hr = wait_media_event(stream, callback, MEStreamStopped, 100, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_EMPTY, "got vt %u\n", value.vt); + + IMFMediaStream_Release(stream); + IMFAsyncCallback_Release(callback); + IMFAsyncCallback_Release(source_callback); + IMFRateControl_Release(rate_control); + + winetest_pop_context(); +} + +static void test_thinning(void) +{ + IMFMediaSource *source; + IMFByteStream *stream; + HRESULT hr; + + stream = create_resource_byte_stream(L"test_thinning.avi"); + hr = create_source(&CLSID_AVIByteStreamPlugin, stream, &source); + IMFByteStream_Release(stream); + + if (FAILED(hr)) + { + win_skip("Failed to create MPEG4 source: %#lx.\n", hr); + return; + } + + test_sample_times_at_rate(source, 2.0, TRUE); + test_sample_times_at_rate(source, 3.0, FALSE); + + hr = IMFMediaSource_Shutdown(source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaSource_Release(source); +} + START_TEST(mfsrcsnk) { HRESULT hr; @@ -212,6 +832,7 @@ START_TEST(mfsrcsnk) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); test_wave_sink(); + test_thinning(); hr = MFShutdown(); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); diff --git a/dlls/mfsrcsnk/tests/resource.rc b/dlls/mfsrcsnk/tests/resource.rc new file mode 100644 index 000000000000..7b3a6532f0a3 --- /dev/null +++ b/dlls/mfsrcsnk/tests/resource.rc @@ -0,0 +1,31 @@ +/* + * Resources for mfsrcsnk test suite. + * + * Copyright 2025 Charlotte Pabst for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "windef.h" + +/* Generated with: + gst-launch-1.0 videotestsrc num-buffers=60 pattern=smpte100 ! \ + video/x-raw,format=I420,width=64,height=64,framerate=30000/1001 ! \ + videoflip method=clockwise ! videoconvert ! \ + x264enc key-int-max=5 ! qtmux ! filesink location=tmp.mp4 && \ + ffmpeg -i tmp.mp4 dlls/mfsrcsnk/tests/test_thinning.avi + */ +/* @makedep: test_thinning.avi */ +test_thinning.avi RCDATA test_thinning.avi diff --git a/dlls/mfsrcsnk/tests/test_thinning.avi b/dlls/mfsrcsnk/tests/test_thinning.avi new file mode 100644 index 000000000000..acc35cce915e Binary files /dev/null and b/dlls/mfsrcsnk/tests/test_thinning.avi differ diff --git a/dlls/mlang/mlang.c b/dlls/mlang/mlang.c index 3ff3c8b34bbe..650af2f74239 100644 --- a/dlls/mlang/mlang.c +++ b/dlls/mlang/mlang.c @@ -1327,6 +1327,10 @@ static INT CALLBACK map_font_enum_proc(const LOGFONTW *lf, const TEXTMETRICW *nt UINT charset; struct map_font_enum_data *data = (struct map_font_enum_data *)lParam; + if ((data->charset == GB2312_CHARSET || data->charset == SHIFTJIS_CHARSET) + && wcscmp(lf->lfFaceName, L"Microsoft YaHei") != 0) + return 1; + data->src_lf.lfCharSet = lf->lfCharSet; wcscpy(data->src_lf.lfFaceName, lf->lfFaceName); diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index d29969b80c54..07390b165274 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -1064,7 +1064,8 @@ static HRESULT WINAPI client_GetSharedModeEnginePeriod(IAudioClient3 *iface, return hr; *default_period_frames = def_period * format->nSamplesPerSec / (REFERENCE_TIME)10000000; - *min_period_frames = min_period * format->nSamplesPerSec / (REFERENCE_TIME)10000000; + *min_period_frames = (min_period * format->nSamplesPerSec + 10000000 - 1) / (REFERENCE_TIME)10000000; + *default_period_frames = max( *default_period_frames, *min_period_frames ); *max_period_frames = *default_period_frames; *unit_period_frames = 1; diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c index b1993573dd9f..7d56715f62df 100644 --- a/dlls/mmdevapi/devenum.c +++ b/dlls/mmdevapi/devenum.c @@ -44,6 +44,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); +#define WINE_REG_PROP_MAGIC 0xbeef +struct reg_prop_serialized { + VARTYPE vt; + WORD unk; /* Uninitialized memory on native, we store a magic value here. */ + ULONG elems; + BYTE data[]; +}; + static HKEY key_render; static HKEY key_capture; @@ -154,6 +162,143 @@ static HRESULT MMDevPropStore_OpenPropKey(const GUID *guid, DWORD flow, HKEY *pr return S_OK; } +static BOOL is_vector_vt(VARTYPE vt) +{ + return !!(vt & VT_VECTOR); +} + +static unsigned int get_vt_elem_size(VARTYPE vt) +{ + switch (vt & VT_TYPEMASK) + { + case VT_BOOL: + return sizeof(VARIANT_BOOL); + + case VT_CLSID: + return sizeof(GUID); + + default: + return 0; + } +} + +static BOOL is_valid_serialized_reg_prop(BYTE *data, DWORD data_size) +{ + struct reg_prop_serialized *reg_prop; + unsigned int elem_size; + + if (data_size <= sizeof(*reg_prop)) + return FALSE; + + reg_prop = (struct reg_prop_serialized *)data; + if (reg_prop->unk != WINE_REG_PROP_MAGIC) + return FALSE; + + if (((reg_prop->vt & VT_TYPEMASK) > VT_CLSID)) + return FALSE; + + if (!!(reg_prop->vt & ~VT_TYPEMASK) && !is_vector_vt(reg_prop->vt)) + return FALSE; + + if (!reg_prop->elems || ((reg_prop->elems > 1) && !is_vector_vt(reg_prop->vt))) + return FALSE; + + elem_size = get_vt_elem_size(reg_prop->vt); + if (elem_size && (((elem_size * reg_prop->elems) + sizeof(*reg_prop)) > data_size)) + return FALSE; + + return TRUE; +} + +static void deserialize_reg_prop(BYTE *data, DWORD data_size, PROPVARIANT *pv) +{ + struct reg_prop_serialized *reg_prop = (struct reg_prop_serialized *)data; + unsigned int elems_size; + + switch (reg_prop->vt) + { + case VT_BOOL: + pv->vt = reg_prop->vt; + pv->boolVal = ((VARIANT_BOOL *)reg_prop->data)[0]; + break; + + case VT_BOOL | VT_VECTOR: + pv->vt = reg_prop->vt; + pv->cabool.cElems = reg_prop->elems; + elems_size = sizeof(*pv->cabool.pElems) * reg_prop->elems; + pv->cabool.pElems = CoTaskMemAlloc(elems_size); + memcpy(pv->cabool.pElems, reg_prop->data, elems_size); + break; + + case VT_CLSID: + pv->vt = reg_prop->vt; + pv->puuid = CoTaskMemAlloc(sizeof(*pv->puuid)); + *pv->puuid = ((GUID *)reg_prop->data)[0]; + break; + + case VT_CLSID | VT_VECTOR: + pv->vt = reg_prop->vt; + pv->cauuid.cElems = reg_prop->elems; + elems_size = sizeof(*pv->cauuid.pElems) * reg_prop->elems; + pv->cauuid.pElems = CoTaskMemAlloc(elems_size); + memcpy(pv->cauuid.pElems, reg_prop->data, elems_size); + break; + + default: + break; + } +} + +static HRESULT serialize_reg_prop(HKEY reg_key, const WCHAR *prop_id, PROPVARIANT *pv) +{ + const struct reg_prop_serialized reg_prop_init = { pv->vt, WINE_REG_PROP_MAGIC }; + struct reg_prop_serialized *reg_prop = NULL; + unsigned int size = sizeof(reg_prop_init); + unsigned int elems_size = 0, elem_count = 1; + void *elems_val = NULL; + LONG ret; + + switch (pv->vt) + { + case VT_BOOL: + elems_size = get_vt_elem_size(pv->vt); + elems_val = &pv->boolVal; + break; + + case VT_BOOL | VT_VECTOR: + elem_count = pv->cabool.cElems; + elems_size = elem_count * get_vt_elem_size(pv->vt); + elems_val = pv->cabool.pElems; + break; + + case VT_CLSID: + elems_size = get_vt_elem_size(pv->vt); + elems_val = pv->puuid; + break; + + case VT_CLSID | VT_VECTOR: + elem_count = pv->cauuid.cElems; + elems_size = elem_count * get_vt_elem_size(pv->vt); + elems_val = pv->cauuid.pElems; + break; + + default: + assert(0); + break; + } + + size += elems_size; + if (!(reg_prop = malloc(size))) + return E_OUTOFMEMORY; + + *reg_prop = reg_prop_init; + reg_prop->elems = elem_count; + memcpy(reg_prop->data, elems_val, elems_size); + ret = RegSetValueExW(reg_key, prop_id, 0, REG_BINARY, (BYTE *)reg_prop, size); + free(reg_prop); + return !ret ? S_OK : E_FAIL; +} + static HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, PROPVARIANT *pv) { WCHAR buffer[80]; @@ -198,13 +343,27 @@ static HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow, REFPROPERT } case REG_BINARY: { - pv->vt = VT_BLOB; - pv->blob.cbSize = size; - pv->blob.pBlobData = CoTaskMemAlloc(size); - if (!pv->blob.pBlobData) + BYTE *data = CoTaskMemAlloc(size); + + if (!data) + { hr = E_OUTOFMEMORY; + break; + } + + RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_BINARY, NULL, data, &size); + if (is_valid_serialized_reg_prop(data, size)) + { + TRACE("do_deserialize().\n"); + deserialize_reg_prop(data, size, pv); + CoTaskMemFree(data); + } else - RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_BINARY, NULL, (BYTE*)pv->blob.pBlobData, &size); + { + pv->vt = VT_BLOB; + pv->blob.cbSize = size; + pv->blob.pBlobData = data; + } break; } default: @@ -237,6 +396,17 @@ static HRESULT MMDevice_SetPropValue(const GUID *devguid, DWORD flow, REFPROPERT ret = RegSetValueExW(regkey, buffer, 0, REG_DWORD, (const BYTE*)&pv->ulVal, sizeof(DWORD)); break; } + + case VT_BOOL: + case VT_BOOL | VT_VECTOR: + case VT_CLSID: + case VT_CLSID | VT_VECTOR: + { + hr = serialize_reg_prop(regkey, buffer, (PROPVARIANT *)pv); + ret = 0; + break; + } + case VT_BLOB: { ret = RegSetValueExW(regkey, buffer, 0, REG_BINARY, pv->blob.pBlobData, pv->blob.cbSize); @@ -416,6 +586,8 @@ static MMDevice *MMDevice_Create(const WCHAR *name, GUID *id, EDataFlow flow, DW pv.pwszVal = guidstr; MMDevice_SetPropValue(id, flow, &deviceinterface_key, &pv); + set_driver_prop_value(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_ContainerId); + if (FAILED(set_driver_prop_value(id, flow, &PKEY_AudioEndpoint_FormFactor))) { pv.vt = VT_UI4; @@ -516,6 +688,7 @@ static HRESULT set_format(MMDevice *dev) HRESULT hr; IAudioClient *client; WAVEFORMATEX *fmt; + WAVEFORMATEXTENSIBLE *fmtex; PROPVARIANT pv = { VT_EMPTY }; hr = AudioClient_Create(&dev->devguid, &dev->IMMDevice_iface, &client); @@ -530,6 +703,24 @@ static HRESULT set_format(MMDevice *dev) IAudioClient_Release(client); + /* for most devices, native Windows only allows PCM formats for + * DeviceFormat. GetMixFormat often returns float. */ + if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ + fmtex = (WAVEFORMATEXTENSIBLE *)fmt; + if(IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){ + fmt->wBitsPerSample = 16; + fmt->nBlockAlign = fmt->wBitsPerSample * fmt->nChannels / 8; + fmt->nAvgBytesPerSec = fmt->nSamplesPerSec * fmt->nBlockAlign; + fmtex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + fmtex->Samples.wValidBitsPerSample = fmt->wBitsPerSample; + } + }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT){ + fmt->wFormatTag = WAVE_FORMAT_PCM; + fmt->wBitsPerSample = 16; + fmt->nBlockAlign = fmt->wBitsPerSample * fmt->nChannels / 8; + fmt->nAvgBytesPerSec = fmt->nSamplesPerSec * fmt->nBlockAlign; + } + pv.vt = VT_BLOB; pv.blob.cbSize = sizeof(WAVEFORMATEX) + fmt->cbSize; pv.blob.pBlobData = (BYTE*)fmt; diff --git a/dlls/mmdevapi/tests/Makefile.in b/dlls/mmdevapi/tests/Makefile.in index d7408be1bbf3..dc515833ce19 100644 --- a/dlls/mmdevapi/tests/Makefile.in +++ b/dlls/mmdevapi/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mmdevapi.dll -IMPORTS = ole32 version user32 advapi32 winmm +IMPORTS = ole32 version user32 advapi32 winmm oleaut32 propsys SOURCES = \ capture.c \ diff --git a/dlls/mmdevapi/tests/propstore.c b/dlls/mmdevapi/tests/propstore.c index b333a556567c..26d75a9822d5 100644 --- a/dlls/mmdevapi/tests/propstore.c +++ b/dlls/mmdevapi/tests/propstore.c @@ -31,6 +31,7 @@ #include "ks.h" #include "ksmedia.h" #include "mmreg.h" +#include "propvarutil.h" static BOOL (WINAPI *pIsWow64Process)(HANDLE, BOOL *); @@ -133,19 +134,150 @@ static void test_getat(IPropertyStore *store) ok(found_desc, "DEVPKEY_Device_DeviceDesc not found\n"); } +static const VARIANT_BOOL vt_bool_vals[] = { VARIANT_TRUE, VARIANT_FALSE }; +static const GUID vt_clsid_vals[] = { { 1 }, { 2 } }; +static const BYTE vt_blob_val[] = { 1, 2, 3, 4, 5, 6 }; +static const WCHAR vt_bstr_val[] = L"Test1"; + +static ULONG set_propvariant_for_vt(PROPVARIANT *pv, VARTYPE vt, const void *val, DWORD size) +{ + ULONG elems = 1; + + PropVariantInit(pv); + pv->vt = vt; + switch (vt) + { + case VT_BOOL: + pv->boolVal = ((const VARIANT_BOOL *)val)[0]; + break; + + case VT_BOOL | VT_VECTOR: + pv->cabool.cElems = size / sizeof(*pv->cabool.pElems); + pv->cabool.pElems = CoTaskMemAlloc(size); + memcpy(pv->cabool.pElems, val, size); + elems = pv->cabool.cElems; + break; + + case VT_CLSID: + pv->puuid = CoTaskMemAlloc(sizeof(*pv->puuid)); + *pv->puuid = ((const GUID *)val)[0]; + break; + + case VT_CLSID | VT_VECTOR: + pv->cauuid.cElems = size / sizeof(*pv->cauuid.pElems); + pv->cauuid.pElems = CoTaskMemAlloc(size); + memcpy(pv->cauuid.pElems, val, size); + elems = pv->cauuid.cElems; + break; + + case VT_BSTR: + pv->bstrVal = SysAllocString((const WCHAR *)val); + break; + + case VT_BLOB: + pv->blob.cbSize = size; + pv->blob.pBlobData = CoTaskMemAlloc(size); + memcpy(pv->blob.pBlobData, val, size); + break; + } + + return elems; +} + +static BOOL compare_propvariant(PROPVARIANT *pv, PROPVARIANT *pv2) +{ + unsigned int i; + + if (pv->vt != pv2->vt) + return FALSE; + + switch (pv->vt) + { + case VT_BSTR: + case VT_CLSID: + return !PropVariantCompareEx(pv, pv2, 0, 0); + + case VT_BOOL: + return pv->boolVal == pv2->boolVal; + + case VT_BOOL | VT_VECTOR: + if (pv->cabool.cElems != pv2->cabool.cElems) + return FALSE; + + for (i = 0; i < pv->cabool.cElems; i++) + { + if (pv->cabool.pElems[i] != pv2->cabool.pElems[i]) + return FALSE; + } + return TRUE; + + case VT_CLSID | VT_VECTOR: + if (pv->cauuid.cElems != pv2->cauuid.cElems) + return FALSE; + + for (i = 0; i < pv->cauuid.cElems; i++) + { + if (memcmp(&pv->cauuid.pElems[i], &pv2->cauuid.pElems[i], sizeof(*pv->cauuid.pElems))) + return FALSE; + } + return TRUE; + + case VT_BLOB: + if (pv->blob.cbSize != pv2->blob.cbSize) + return FALSE; + + return !memcmp(pv->blob.pBlobData, pv2->blob.pBlobData, pv->blob.cbSize); + } + + return FALSE; +} + +struct reg_serialized { + VARTYPE vt; + WORD unk; /* Seems like mostly uninitialized memory... */ + ULONG elems; + BYTE data[]; +}; + static void test_setvalue_on_wow64(IPropertyStore *store) { - PROPVARIANT pv; + static const struct + { + VARTYPE vt; + const void *data; + DWORD data_size; + + HRESULT expected_hr; + DWORD expected_reg_type; + DWORD expected_size; + BOOL todo_hr; + BOOL todo_data; + } propvar_tests[] = + { + { VT_BOOL, vt_bool_vals, sizeof(vt_bool_vals) / 2, S_OK, REG_BINARY, 0xa }, + { VT_BOOL | VT_VECTOR, vt_bool_vals, sizeof(vt_bool_vals), S_OK, REG_BINARY, 0xc }, + { VT_CLSID, vt_clsid_vals, sizeof(vt_clsid_vals) / 2, S_OK, REG_BINARY, 0x18 }, + { VT_CLSID | VT_VECTOR, vt_clsid_vals, sizeof(vt_clsid_vals), S_OK, REG_BINARY, 0x28 }, + { VT_BSTR, vt_bstr_val, sizeof(vt_bstr_val), S_OK, REG_BINARY, 0x14, TRUE, TRUE }, + { VT_BLOB, vt_blob_val, sizeof(vt_blob_val), S_OK, REG_BINARY, 0xe, .todo_data = TRUE }, + }; + PROPVARIANT pv, pv2; HRESULT hr; LONG ret; WCHAR *guidW; HKEY root, props, devkey; DWORD type, regval, size; + unsigned int i; + BYTE buf[256]; static const PROPERTYKEY PKEY_Bogus = { {0x1da5d803, 0xd492, 0x4edd, {0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x00}}, 0x7f }; + static const PROPERTYKEY PKEY_Bogus2 = { + {0x1da5d803, 0xd492, 0x4edd, {0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x00}}, 0x80 + }; static const WCHAR bogusW[] = L"{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F00},127"; + static const WCHAR bogus2W[] = L"{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F00},128"; PropVariantInit(&pv); @@ -189,6 +321,47 @@ static void test_setvalue_on_wow64(IPropertyStore *store) ok(type == REG_DWORD, "Got wrong value type: %lu\n", type); ok(regval == 0xAB, "Got wrong value: 0x%lx\n", regval); + for (i = 0; i < ARRAY_SIZE(propvar_tests); i++) + { + struct reg_serialized *reg_val; + ULONG expected_elems; + + winetest_push_context("Test %u", i); + + expected_elems = set_propvariant_for_vt(&pv, propvar_tests[i].vt, propvar_tests[i].data, propvar_tests[i].data_size); + hr = IPropertyStore_SetValue(store, &PKEY_Bogus2, &pv); + todo_wine_if(propvar_tests[i].todo_hr) ok(hr == propvar_tests[i].expected_hr, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + { + winetest_pop_context(); + PropVariantClear(&pv); + continue; + } + + ret = RegQueryValueExW(props, bogus2W, NULL, &type, NULL, &size); + ok(ret == ERROR_SUCCESS, "Couldn't get bogus propertykey value: %lu.\n", ret); + ok(type == propvar_tests[i].expected_reg_type, "Unexpected registry value type %lu.\n", type); + todo_wine_if(propvar_tests[i].todo_data) ok(size >= propvar_tests[i].expected_size, "Unexpected registry value size 0x%lx.\n", size); + + ret = RegQueryValueExW(props, bogus2W, NULL, &type, buf, &size); + ok(ret == ERROR_SUCCESS, "Couldn't get bogus propertykey value: %lu.\n", ret); + reg_val = (struct reg_serialized *)buf; + todo_wine_if(propvar_tests[i].todo_data) + ok(reg_val->vt == propvar_tests[i].vt, "Unexpected vt: %#x.\n", reg_val->vt); + todo_wine_if(propvar_tests[i].todo_data) + ok(reg_val->elems == expected_elems, "Unexpected elems: %lu.\n", reg_val->elems); + todo_wine_if(propvar_tests[i].todo_data) + ok(!memcmp(reg_val->data, propvar_tests[i].data, propvar_tests[i].data_size), "Unexpected data.\n"); + + hr = IPropertyStore_GetValue(store, &PKEY_Bogus2, &pv2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(compare_propvariant(&pv, &pv2), "Propvariant mismatch.\n"); + + PropVariantClear(&pv); + PropVariantClear(&pv2); + winetest_pop_context(); + } + RegCloseKey(props); RegCloseKey(devkey); RegCloseKey(root); diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c index 236a4ff71c80..38e28e1ee7d4 100644 --- a/dlls/mmdevapi/tests/render.c +++ b/dlls/mmdevapi/tests/render.c @@ -182,9 +182,6 @@ static void test_audioclient(void) handle = CreateEventW(NULL, FALSE, FALSE, NULL); - hr = IAudioClient_QueryInterface(ac, &IID_IUnknown, NULL); - ok(hr == E_POINTER, "QueryInterface(NULL) returned %08lx\n", hr); - unk = (void*)(LONG_PTR)0x12345678; hr = IAudioClient_QueryInterface(ac, &IID_NULL, (void**)&unk); ok(hr == E_NOINTERFACE, "QueryInterface(IID_NULL) returned %08lx\n", hr); @@ -197,7 +194,6 @@ static void test_audioclient(void) ref = IUnknown_Release(unk); ok(ref == 1, "Released count is %lu\n", ref); } - hr = IAudioClient_QueryInterface(ac, &IID_IAudioClient, (void**)&unk); ok(hr == S_OK, "QueryInterface(IID_IAudioClient) returned %08lx\n", hr); if (unk) @@ -372,6 +368,20 @@ static void test_audioclient(void) hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&ac); ok(hr == S_OK, "Activation failed with %08lx\n", hr); + + hr = IAudioClient_QueryInterface(ac, &IID_IAudioClient3, (void**)&ac3); + ok(hr == S_OK, "Failed to query IAudioClient3 interface: %08lx\n", hr); + + hr = IAudioClient3_InitializeSharedAudioStream( + ac3, AUDCLNT_SHAREMODE_SHARED, min_period, pwfx, NULL); + ok(hr == S_OK, "InitializeSharedAudioStream returns %08lx\n", hr); + + IAudioClient3_Release(ac3); + IAudioClient_Release(ac); + + hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, + NULL, (void**)&ac); + ok(hr == S_OK, "Activation failed with %08lx\n", hr); } else win_skip("IAudioClient3 is not present\n"); diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c index 271f2c86d77b..d0308a3c993b 100644 --- a/dlls/mountmgr.sys/device.c +++ b/dlls/mountmgr.sys/device.c @@ -1848,11 +1848,30 @@ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp ) break; case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: { - DWORD len = min( 32, irpsp->Parameters.DeviceIoControl.OutputBufferLength ); + struct size_info size_info = { 0, 0, 0, 0, 0 }; + struct get_volume_size_info_params params = { dev->unix_mount, &size_info }; + VOLUME_DISK_EXTENTS info = { 0 }; - FIXME( "returning zero-filled buffer for IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS\n" ); - memset( irp->AssociatedIrp.SystemBuffer, 0, len ); - irp->IoStatus.Information = len; + if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(info)) + { + TRACE( "len %lu is too small.\n", irpsp->Parameters.DeviceIoControl.OutputBufferLength ); + status = STATUS_INVALID_PARAMETER; + break; + } + FIXME( "IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS semi-stub.\n" ); + + info.NumberOfDiskExtents = 1; + info.Extents[0].DiskNumber = dev->devnum.DeviceNumber; + info.Extents[0].StartingOffset.QuadPart = 0; + + if ((status = MOUNTMGR_CALL( get_volume_size_info, ¶ms )) == STATUS_SUCCESS) + { + info.Extents[0].ExtentLength.QuadPart = size_info.total_allocation_units + * size_info.sectors_per_allocation_unit + * size_info.bytes_per_sector; + } + memcpy( irp->AssociatedIrp.SystemBuffer, &info, sizeof(info) ); + irp->IoStatus.Information = sizeof(info); status = STATUS_SUCCESS; break; } diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c index 8d42fb36bad4..77c2b795ef59 100644 --- a/dlls/mountmgr.sys/mountmgr.c +++ b/dlls/mountmgr.sys/mountmgr.c @@ -609,6 +609,27 @@ static DWORD WINAPI run_loop_thread( void *arg ) return MOUNTMGR_CALL( run_loop, ¶ms ); } +static DWORD WINAPI registry_flush_thread( void *arg ) +{ + UNICODE_STRING name = RTL_CONSTANT_STRING( L"\\Registry" ); + OBJECT_ATTRIBUTES attr; + HANDLE root; + + InitializeObjectAttributes( &attr, &name, 0, 0, NULL ); + if (NtOpenKeyEx( &root, MAXIMUM_ALLOWED, &attr, 0 )) + { + ERR( "Failed opening root registry key.\n" ); + return 0; + } + + for (;;) + { + Sleep( 30000 ); + if (NtFlushKey( root )) ERR( "Failed flushing registry.\n" ); + } + + return 0; +} /* main entry point for the mount point manager driver */ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) @@ -652,6 +673,7 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) thread = CreateThread( NULL, 0, device_op_thread, NULL, 0, NULL ); CloseHandle( CreateThread( NULL, 0, run_loop_thread, thread, 0, NULL )); + CloseHandle( CreateThread( NULL, 0, registry_flush_thread, thread, 0, NULL )); #ifdef _WIN64 /* create a symlink so that the Wine port overrides key can be edited with 32-bit reg or regedit */ diff --git a/dlls/mp3dmod/Makefile.in b/dlls/mp3dmod/Makefile.in index ff2f2f241162..254174d4d319 100644 --- a/dlls/mp3dmod/Makefile.in +++ b/dlls/mp3dmod/Makefile.in @@ -1,5 +1,5 @@ MODULE = mp3dmod.dll -IMPORTS = $(MPG123_PE_LIBS) dmoguids msdmo ole32 uuid wmcodecdspuuid kernelbase +IMPORTS = $(MPG123_PE_LIBS) dmoguids mfplat mfuuid msdmo ole32 uuid wmcodecdspuuid kernelbase EXTRAINCL = $(MPG123_PE_CFLAGS) EXTRADEFS = -DMPG123_NO_LARGENAME diff --git a/dlls/mp3dmod/mp3dmod.c b/dlls/mp3dmod/mp3dmod.c index 842be5889dab..bf518f38f39c 100644 --- a/dlls/mp3dmod/mp3dmod.c +++ b/dlls/mp3dmod/mp3dmod.c @@ -30,6 +30,9 @@ #include "dmo.h" #include "rpcproxy.h" #include "wmcodecdsp.h" +#include "mfapi.h" +#include "mferror.h" +#include "mftransform.h" #include "wine/debug.h" #include "initguid.h" @@ -44,6 +47,7 @@ struct mp3_decoder { IUnknown IUnknown_inner; IMediaObject IMediaObject_iface; + IMFTransform IMFTransform_iface; IUnknown *outer; LONG ref; mpg123_handle *mh; @@ -53,6 +57,8 @@ struct mp3_decoder IMediaBuffer *buffer; REFERENCE_TIME timestamp; + + BOOL draining; }; static inline struct mp3_decoder *impl_from_IUnknown(IUnknown *iface) @@ -70,6 +76,8 @@ static HRESULT WINAPI Unknown_QueryInterface(IUnknown *iface, REFIID iid, void * *obj = &This->IUnknown_inner; else if (IsEqualGUID(iid, &IID_IMediaObject)) *obj = &This->IMediaObject_iface; + else if (IsEqualGUID(iid, &IID_IMFTransform)) + *obj = &This->IMFTransform_iface; else { FIXME("no interface for %s\n", debugstr_guid(iid)); @@ -171,6 +179,9 @@ static HRESULT WINAPI MediaObject_GetInputType(IMediaObject *iface, DWORD index, { TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); + if (index) + return DMO_E_INVALIDSTREAMINDEX; + if (type_index) return DMO_E_NO_MORE_ITEMS; @@ -192,6 +203,9 @@ static HRESULT WINAPI MediaObject_GetOutputType(IMediaObject *iface, DWORD index TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); + if (index) + return DMO_E_INVALIDSTREAMINDEX; + if (!dmo->intype_set) return DMO_E_TYPE_NOT_SET; @@ -222,9 +236,13 @@ static HRESULT WINAPI MediaObject_GetOutputType(IMediaObject *iface, DWORD index static HRESULT WINAPI MediaObject_SetInputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) { struct mp3_decoder *dmo = impl_from_IMediaObject(iface); + const WAVEFORMATEX *format; TRACE("iface %p, index %lu, type %p, flags %#lx.\n", iface, index, type, flags); + if (index) + return DMO_E_INVALIDSTREAMINDEX; + if (flags & DMO_SET_TYPEF_CLEAR) { if (dmo->intype_set) @@ -238,6 +256,11 @@ static HRESULT WINAPI MediaObject_SetInputType(IMediaObject *iface, DWORD index, || !IsEqualGUID(&type->formattype, &WMFORMAT_WaveFormatEx)) return DMO_E_TYPE_NOT_ACCEPTED; + format = (WAVEFORMATEX *) type->pbFormat; + + if (!format->nChannels) + return DMO_E_TYPE_NOT_ACCEPTED; + if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) { if (dmo->intype_set) @@ -252,12 +275,18 @@ static HRESULT WINAPI MediaObject_SetInputType(IMediaObject *iface, DWORD index, static HRESULT WINAPI MediaObject_SetOutputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) { struct mp3_decoder *This = impl_from_IMediaObject(iface); - WAVEFORMATEX *format; + WAVEFORMATEX *format, *in_format; long enc; int err; TRACE("(%p)->(%ld, %p, %#lx)\n", iface, index, type, flags); + if (index) + return DMO_E_INVALIDSTREAMINDEX; + + if (!This->intype_set) + return DMO_E_TYPE_NOT_SET; + if (flags & DMO_SET_TYPEF_CLEAR) { MoFreeMediaType(&This->outtype); @@ -274,12 +303,28 @@ static HRESULT WINAPI MediaObject_SetOutputType(IMediaObject *iface, DWORD index enc = MPG123_ENC_UNSIGNED_8; else if (format->wBitsPerSample == 16) enc = MPG123_ENC_SIGNED_16; + else if (format->wBitsPerSample == 32) + enc = MPG123_ENC_FLOAT_32; else { ERR("Cannot decode to bit depth %u.\n", format->wBitsPerSample); return DMO_E_TYPE_NOT_ACCEPTED; } + if (format->nChannels * format->wBitsPerSample/8 != format->nBlockAlign + || format->nSamplesPerSec * format->nBlockAlign != format->nAvgBytesPerSec) + return E_INVALIDARG; + + in_format = (WAVEFORMATEX *)This->intype.pbFormat; + + if (format->nSamplesPerSec != in_format->nSamplesPerSec && + format->nSamplesPerSec*2 != in_format->nSamplesPerSec && + format->nSamplesPerSec*4 != in_format->nSamplesPerSec) + { + ERR("Cannot decode to %lu samples per second (input %lu).\n", format->nSamplesPerSec, in_format->nSamplesPerSec); + return DMO_E_TYPE_NOT_ACCEPTED; + } + if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) { err = mpg123_format(This->mh, format->nSamplesPerSec, format->nChannels, enc); @@ -289,6 +334,8 @@ static HRESULT WINAPI MediaObject_SetOutputType(IMediaObject *iface, DWORD index format->nChannels, format->nSamplesPerSec, format->wBitsPerSample); return DMO_E_TYPE_NOT_ACCEPTED; } + if (This->outtype_set) + MoFreeMediaType(&This->outtype); MoCopyMediaType(&This->outtype, type); This->outtype_set = TRUE; } @@ -298,16 +345,34 @@ static HRESULT WINAPI MediaObject_SetOutputType(IMediaObject *iface, DWORD index static HRESULT WINAPI MediaObject_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) { - FIXME("(%p)->(%ld, %p) stub!\n", iface, index, type); + struct mp3_decoder *dmo = impl_from_IMediaObject(iface); + TRACE("(%p)->(%ld, %p)\n", iface, index, type); - return E_NOTIMPL; + if (index) + return DMO_E_INVALIDSTREAMINDEX; + + if (!dmo->intype_set) + return DMO_E_TYPE_NOT_SET; + + MoCopyMediaType(type, &dmo->intype); + + return S_OK; } static HRESULT WINAPI MediaObject_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) { - FIXME("(%p)->(%ld, %p) stub!\n", iface, index, type); + struct mp3_decoder *dmo = impl_from_IMediaObject(iface); + TRACE("(%p)->(%ld, %p)\n", iface, index, type); - return E_NOTIMPL; + if (index) + return DMO_E_INVALIDSTREAMINDEX; + + if (!dmo->outtype_set) + return DMO_E_TYPE_NOT_SET; + + MoCopyMediaType(type, &dmo->outtype); + + return S_OK; } static HRESULT WINAPI MediaObject_GetInputSizeInfo(IMediaObject *iface, @@ -317,6 +382,9 @@ static HRESULT WINAPI MediaObject_GetInputSizeInfo(IMediaObject *iface, TRACE("iface %p, index %lu, size %p, lookahead %p, alignment %p.\n", iface, index, size, lookahead, alignment); + if (index) + return DMO_E_INVALIDSTREAMINDEX; + if (!dmo->intype_set || !dmo->outtype_set) return DMO_E_TYPE_NOT_SET; @@ -331,6 +399,9 @@ static HRESULT WINAPI MediaObject_GetOutputSizeInfo(IMediaObject *iface, DWORD i TRACE("iface %p, index %lu, size %p, alignment %p.\n", iface, index, size, alignment); + if (index) + return DMO_E_INVALIDSTREAMINDEX; + if (!dmo->intype_set || !dmo->outtype_set) return DMO_E_TYPE_NOT_SET; @@ -380,16 +451,16 @@ static HRESULT WINAPI MediaObject_Discontinuity(IMediaObject *iface, DWORD index static HRESULT WINAPI MediaObject_AllocateStreamingResources(IMediaObject *iface) { - FIXME("(%p)->() stub!\n", iface); + TRACE("(%p)->()\n", iface); - return E_NOTIMPL; + return S_OK; } static HRESULT WINAPI MediaObject_FreeStreamingResources(IMediaObject *iface) { - FIXME("(%p)->() stub!\n", iface); + TRACE("(%p)->()\n", iface); - return E_NOTIMPL; + return S_OK; } static HRESULT WINAPI MediaObject_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags) @@ -411,6 +482,9 @@ static HRESULT WINAPI MediaObject_ProcessInput(IMediaObject *iface, DWORD index, TRACE("(%p)->(%ld, %p, %#lx, %s, %s)\n", iface, index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); + if (index) + return DMO_E_INVALIDSTREAMINDEX; + if (This->buffer) { ERR("Already have a buffer.\n"); @@ -568,6 +642,534 @@ static const IMediaObjectVtbl MediaObject_vtbl = { MediaObject_Lock, }; +static HRESULT convert_dmo_to_mf_error(HRESULT dmo_error) +{ + switch (dmo_error) + { + case DMO_E_INVALIDSTREAMINDEX: + return MF_E_INVALIDSTREAMNUMBER; + + case DMO_E_INVALIDTYPE: + case DMO_E_TYPE_NOT_ACCEPTED: + return MF_E_INVALIDMEDIATYPE; + + case DMO_E_TYPE_NOT_SET: + return MF_E_TRANSFORM_TYPE_NOT_SET; + + case DMO_E_NOTACCEPTING: + return MF_E_NOTACCEPTING; + + case DMO_E_NO_MORE_ITEMS: + return MF_E_NO_MORE_TYPES; + } + + return dmo_error; +} + +static inline struct mp3_decoder *impl_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct mp3_decoder, IMFTransform_iface); +} + +static HRESULT WINAPI MFTransform_QueryInterface(IMFTransform *iface, REFIID iid, void **obj) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + return IUnknown_QueryInterface(decoder->outer, iid, obj); +} + +static ULONG WINAPI MFTransform_AddRef(IMFTransform *iface) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + return IUnknown_AddRef(decoder->outer); +} + +static ULONG WINAPI MFTransform_Release(IMFTransform *iface) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + return IUnknown_Release(decoder->outer); +} + +static HRESULT WINAPI MFTransform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, + DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", + iface, input_minimum, input_maximum, output_minimum, output_maximum); + IMediaObject_GetStreamCount(&decoder->IMediaObject_iface, input_minimum, output_minimum); + *input_maximum = *input_minimum; + *output_maximum = *output_minimum; + return S_OK; +} + +static HRESULT WINAPI MFTransform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); + IMediaObject_GetStreamCount(&decoder->IMediaObject_iface, inputs, outputs); + return S_OK; +} + +static HRESULT WINAPI MFTransform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, + DWORD output_size, DWORD *outputs) +{ + FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p stub!\n", iface, + input_size, inputs, output_size, outputs); + + return E_NOTIMPL; +} + +static HRESULT WINAPI MFTransform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + HRESULT hr; + + TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); + + memset(info, 0, sizeof(*info)); + + /* Doc says: If not implemented, assume zero latency. */ + if (FAILED(hr = IMediaObject_GetInputMaxLatency(&decoder->IMediaObject_iface, id, &info->hnsMaxLatency)) && hr != E_NOTIMPL) + return convert_dmo_to_mf_error(hr); + + if (FAILED(hr = IMediaObject_GetInputStreamInfo(&decoder->IMediaObject_iface, id, &info->dwFlags))) + return convert_dmo_to_mf_error(hr); + + if (FAILED(hr = IMediaObject_GetInputSizeInfo(&decoder->IMediaObject_iface, id, &info->cbSize, &info->cbMaxLookahead, &info->cbAlignment))) + return convert_dmo_to_mf_error(hr); + + return S_OK; +} + +static HRESULT WINAPI MFTransform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + HRESULT hr; + + TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); + + memset(info, 0, sizeof(*info)); + + if (FAILED(hr = IMediaObject_GetOutputStreamInfo(&decoder->IMediaObject_iface, id, &info->dwFlags))) + return convert_dmo_to_mf_error(hr); + + if (FAILED(hr = IMediaObject_GetOutputSizeInfo(&decoder->IMediaObject_iface, id, &info->cbSize, &info->cbAlignment))) + return convert_dmo_to_mf_error(hr); + + return S_OK; +} + +static HRESULT WINAPI MFTransform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + TRACE("iface %p, attributes %p.\n", iface, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI MFTransform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI MFTransform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI MFTransform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + TRACE("iface %p, id %#lx.\n", iface, id); + return E_NOTIMPL; +} + +static HRESULT WINAPI MFTransform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids); + return E_NOTIMPL; +} + +static HRESULT WINAPI MFTransform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + DMO_MEDIA_TYPE pt; + HRESULT hr; + + TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + + if (FAILED(hr = IMediaObject_GetInputType(&decoder->IMediaObject_iface, id, index, &pt))) + return convert_dmo_to_mf_error(hr); + + if (FAILED(hr = MFCreateMediaType(type))) + return hr; + + return MFInitMediaTypeFromAMMediaType(*type, (AM_MEDIA_TYPE*)&pt); +} + +static HRESULT WINAPI MFTransform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + UINT32 bps, block_align, num_channels; + const WAVEFORMATEX *input_format; + HRESULT hr; + + TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + + if (id) + return MF_E_INVALIDSTREAMNUMBER; + + if (!decoder->intype_set) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + input_format = (WAVEFORMATEX *)decoder->intype.pbFormat; + + if (index >= 6 || (input_format->nChannels != 2 && index >= 3)) + return MF_E_NO_MORE_TYPES; + + if (FAILED(hr = MFCreateMediaType(type))) + return hr; + + if (FAILED(hr = IMFMediaType_SetGUID(*type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio))) + goto fail; + + if (FAILED(hr = IMFMediaType_SetGUID(*type, &MF_MT_SUBTYPE, index % 3 ? &MFAudioFormat_PCM : &MFAudioFormat_Float))) + goto fail; + + if (index % 3 == 0) + bps = 32; + else if (index % 3 == 1) + bps = 16; + else + bps = 8; + + num_channels = index / 3 ? 1 : input_format->nChannels; + block_align = bps/8 * num_channels; + + if (FAILED(hr = IMFMediaType_SetUINT32(*type, &MF_MT_AUDIO_BITS_PER_SAMPLE, bps))) + goto fail; + + if (FAILED(hr = IMFMediaType_SetUINT32(*type, &MF_MT_AUDIO_NUM_CHANNELS, num_channels))) + goto fail; + + if (FAILED(hr = IMFMediaType_SetUINT32(*type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, input_format->nSamplesPerSec))) + goto fail; + + if (FAILED(hr = IMFMediaType_SetUINT32(*type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, input_format->nSamplesPerSec * block_align))) + goto fail; + + if (FAILED(hr = IMFMediaType_SetUINT32(*type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_align))) + goto fail; + + if (FAILED(hr = IMFMediaType_SetUINT32(*type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) + goto fail; + + return S_OK; + +fail: + IMFMediaType_Release(*type); + return hr; +} + +static HRESULT WINAPI MFTransform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + DMO_MEDIA_TYPE mt; + HRESULT hr; + + TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + + if (!type) + flags |= DMO_SET_TYPEF_CLEAR; + else if (FAILED(hr = MFInitAMMediaTypeFromMFMediaType(type, GUID_NULL, (AM_MEDIA_TYPE*)&mt))) + return hr; + + hr = IMediaObject_SetInputType(&decoder->IMediaObject_iface, id, &mt, flags); + + if (hr == S_FALSE) + return MF_E_INVALIDMEDIATYPE; + else if (FAILED(hr)) + return convert_dmo_to_mf_error(hr); + + return S_OK; +} + +static HRESULT WINAPI MFTransform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + DMO_MEDIA_TYPE mt; + HRESULT hr; + + TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + + if (!type) + flags |= DMO_SET_TYPEF_CLEAR; + else if (FAILED(hr = MFInitAMMediaTypeFromMFMediaType(type, GUID_NULL, (AM_MEDIA_TYPE*)&mt))) + return hr; + + hr = IMediaObject_SetOutputType(&decoder->IMediaObject_iface, id, &mt, flags); + + if (hr == S_FALSE) + return MF_E_INVALIDMEDIATYPE; + else if (FAILED(hr)) + return convert_dmo_to_mf_error(hr); + + return S_OK; +} + +static HRESULT WINAPI MFTransform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **out) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + DMO_MEDIA_TYPE mt; + HRESULT hr; + + TRACE("iface %p, id %#lx, out %p.\n", iface, id, out); + + if (FAILED(hr = IMediaObject_GetInputCurrentType(&decoder->IMediaObject_iface, id, &mt))) + return convert_dmo_to_mf_error(hr); + + if (FAILED(hr = MFCreateMediaType(out))) + return hr; + + return MFInitMediaTypeFromAMMediaType(*out, (AM_MEDIA_TYPE*)&mt); +} + +static HRESULT WINAPI MFTransform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **out) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + DMO_MEDIA_TYPE mt; + HRESULT hr; + + TRACE("iface %p, id %#lx, out %p.\n", iface, id, out); + + if (FAILED(hr = IMediaObject_GetOutputCurrentType(&decoder->IMediaObject_iface, id, &mt))) + return convert_dmo_to_mf_error(hr); + + if (FAILED(hr = MFCreateMediaType(out))) + return hr; + + return MFInitMediaTypeFromAMMediaType(*out, (AM_MEDIA_TYPE*)&mt); +} + +static HRESULT WINAPI MFTransform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + + FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); + + return E_NOTIMPL; +} + +static HRESULT WINAPI MFTransform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + FIXME("iface %p, flags %p stub!\n", iface, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI MFTransform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + FIXME("iface %p, lower %I64d, upper %I64d stub!\n", iface, lower, upper); + return E_NOTIMPL; +} + +static HRESULT WINAPI MFTransform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); + return E_NOTIMPL; +} + +static HRESULT WINAPI MFTransform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + HRESULT hr; + + TRACE("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); + + switch(message) + { + case MFT_MESSAGE_COMMAND_FLUSH: + if (FAILED(hr = IMediaObject_Flush(&decoder->IMediaObject_iface))) + return convert_dmo_to_mf_error(hr); + break; + + case MFT_MESSAGE_COMMAND_DRAIN: + decoder->draining = TRUE; + break; + + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + case MFT_MESSAGE_NOTIFY_START_OF_STREAM: + if (FAILED(hr = IMediaObject_AllocateStreamingResources(&decoder->IMediaObject_iface))) + return convert_dmo_to_mf_error(hr); + break; + + case MFT_MESSAGE_NOTIFY_END_OF_STREAM: + case MFT_MESSAGE_NOTIFY_END_STREAMING: + if (FAILED(hr = IMediaObject_FreeStreamingResources(&decoder->IMediaObject_iface))) + return convert_dmo_to_mf_error(hr); + break; + + default: + FIXME("message %#x stub!\n", message); + break; + } + + return S_OK; +} + +static HRESULT WINAPI MFTransform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + LONGLONG sample_time, duration; + IMediaBuffer *dmo_buffer; + IMFMediaBuffer *buffer; + UINT32 discontinuity; + HRESULT hr; + + TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); + + if (decoder->draining) + return MF_E_NOTACCEPTING; + + if (SUCCEEDED(IMFSample_GetUINT32(sample, &MFSampleExtension_Discontinuity, &discontinuity)) && discontinuity) + { + if (FAILED(hr = IMediaObject_Discontinuity(&decoder->IMediaObject_iface, id))) + return convert_dmo_to_mf_error(hr); + } + + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer))) + return hr; + + hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(sample, buffer, 0, &dmo_buffer); + IMFMediaBuffer_Release(buffer); + if (FAILED(hr)) + return hr; + + flags = 0; + + if (SUCCEEDED(IMFSample_GetSampleTime(sample, &sample_time))) + flags |= DMO_INPUT_DATA_BUFFERF_TIME; + + if (SUCCEEDED(IMFSample_GetSampleDuration(sample, &duration))) + flags |= DMO_INPUT_DATA_BUFFERF_TIMELENGTH; + + hr = IMediaObject_ProcessInput(&decoder->IMediaObject_iface, id, dmo_buffer, flags, sample_time, duration); + IMediaBuffer_Release(dmo_buffer); + if (FAILED(hr)) + return convert_dmo_to_mf_error(hr); + + return S_OK; +} + +static HRESULT WINAPI MFTransform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) +{ + struct mp3_decoder *decoder = impl_from_IMFTransform(iface); + DMO_OUTPUT_DATA_BUFFER *dmo_output; + IMFMediaBuffer *buffer; + HRESULT hr; + int i; + + TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); + + if (count > 1) + { + FIXME("Multiple buffers not handled.\n"); + return E_INVALIDARG; + } + + dmo_output = calloc(count, sizeof(*dmo_output)); + if (!dmo_output) + return E_OUTOFMEMORY; + + for (i = 0; i < count; i++) + { + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[i].pSample, &buffer))) + goto fail; + + hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(samples[i].pSample, buffer, 0, &dmo_output[i].pBuffer); + IMFMediaBuffer_Release(buffer); + if (FAILED(hr)) + goto fail; + } + + hr = IMediaObject_ProcessOutput(&decoder->IMediaObject_iface, flags, count, dmo_output, status); + + for (i = 0; i < count; i++) + IMediaBuffer_Release(dmo_output[i].pBuffer); + + if (FAILED(hr)) + { + free(dmo_output); + return convert_dmo_to_mf_error(hr); + } + + for (i = 0; i < count; i++) + { + if (dmo_output[i].dwStatus & DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT) + IMFSample_SetUINT32(samples[i].pSample, &MFSampleExtension_CleanPoint, 1); + + if (dmo_output[i].dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIME) + IMFSample_SetSampleTime(samples[i].pSample, dmo_output[i].rtTimestamp); + + if (dmo_output[i].dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH) + IMFSample_SetSampleDuration(samples[i].pSample, dmo_output[i].rtTimelength); + + if (dmo_output[i].dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE) + samples[i].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE; + } + + free(dmo_output); + + if (hr == S_FALSE) + { + decoder->draining = FALSE; + return MF_E_TRANSFORM_NEED_MORE_INPUT; + } + + return S_OK; + +fail: + for (i = 0; i < count; i++) + { + if (dmo_output[i].pBuffer) + IMediaBuffer_Release(dmo_output[i].pBuffer); + } + free(dmo_output); + + return hr; +} + +static const IMFTransformVtbl IMFTransform_vtbl = +{ + MFTransform_QueryInterface, + MFTransform_AddRef, + MFTransform_Release, + MFTransform_GetStreamLimits, + MFTransform_GetStreamCount, + MFTransform_GetStreamIDs, + MFTransform_GetInputStreamInfo, + MFTransform_GetOutputStreamInfo, + MFTransform_GetAttributes, + MFTransform_GetInputStreamAttributes, + MFTransform_GetOutputStreamAttributes, + MFTransform_DeleteInputStream, + MFTransform_AddInputStreams, + MFTransform_GetInputAvailableType, + MFTransform_GetOutputAvailableType, + MFTransform_SetInputType, + MFTransform_SetOutputType, + MFTransform_GetInputCurrentType, + MFTransform_GetOutputCurrentType, + MFTransform_GetInputStatus, + MFTransform_GetOutputStatus, + MFTransform_SetOutputBounds, + MFTransform_ProcessEvent, + MFTransform_ProcessMessage, + MFTransform_ProcessInput, + MFTransform_ProcessOutput, +}; + static HRESULT create_mp3_decoder(IUnknown *outer, REFIID iid, void **obj) { struct mp3_decoder *This; @@ -579,6 +1181,7 @@ static HRESULT create_mp3_decoder(IUnknown *outer, REFIID iid, void **obj) This->IUnknown_inner.lpVtbl = &Unknown_vtbl; This->IMediaObject_iface.lpVtbl = &MediaObject_vtbl; + This->IMFTransform_iface.lpVtbl = &IMFTransform_vtbl; This->ref = 1; This->outer = outer ? outer : &This->IUnknown_inner; @@ -667,6 +1270,7 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **obj) */ HRESULT WINAPI DllRegisterServer(void) { + MFT_REGISTER_TYPE_INFO mf_in, mf_out; DMO_PARTIAL_MEDIATYPE in, out; HRESULT hr; @@ -674,9 +1278,16 @@ HRESULT WINAPI DllRegisterServer(void) in.subtype = WMMEDIASUBTYPE_MP3; out.type = WMMEDIATYPE_Audio; out.subtype = WMMEDIASUBTYPE_PCM; + mf_in.guidMajorType = MFMediaType_Audio; + mf_in.guidSubtype = MFAudioFormat_MP3; + mf_out.guidMajorType = MFMediaType_Audio; + mf_out.guidSubtype = MFAudioFormat_PCM; hr = DMORegister(L"MP3 Decoder DMO", &CLSID_CMP3DecMediaObject, &DMOCATEGORY_AUDIO_DECODER, 0, 1, &in, 1, &out); if (FAILED(hr)) return hr; + hr = MFTRegister(CLSID_CMP3DecMediaObject, MFT_CATEGORY_AUDIO_DECODER, (LPWSTR) L"MP3 Decoder MFT", + 0, 1, &mf_in, 1, &mf_out, NULL); + if (FAILED(hr)) return hr; return __wine_register_resources(); } @@ -690,6 +1301,8 @@ HRESULT WINAPI DllUnregisterServer(void) hr = DMOUnregister(&CLSID_CMP3DecMediaObject, &DMOCATEGORY_AUDIO_DECODER); if (FAILED(hr)) return hr; + hr = MFTUnregister(CLSID_CMP3DecMediaObject); + if (FAILED(hr)) return hr; return __wine_unregister_resources(); } diff --git a/dlls/mp3dmod/tests/mp3dmod.c b/dlls/mp3dmod/tests/mp3dmod.c index 7d213fcd18a0..655224da7caa 100644 --- a/dlls/mp3dmod/tests/mp3dmod.c +++ b/dlls/mp3dmod/tests/mp3dmod.c @@ -40,6 +40,49 @@ static REFERENCE_TIME samplelen(DWORD samples, int rate) return (REFERENCE_TIME) 10000000 * samples / rate; } +#define check_member_(line, val, exp, fmt, member) \ + ok_ (__FILE__, line)((val).member == (exp).member, "Got " #member " " fmt ", expected " fmt ".\n", (val).member, (exp).member) +#define check_member(val, exp, fmt, member) check_member_(__LINE__, val, exp, fmt, member) + +#define check_wave_format(a, b) check_wave_format_(__LINE__, a, b) +static void check_wave_format_(int line, WAVEFORMATEX *info, const WAVEFORMATEX *expected) +{ + check_member_(line, *info, *expected, "%#x", wFormatTag); + check_member_(line, *info, *expected, "%u", nChannels); + check_member_(line, *info, *expected, "%lu", nSamplesPerSec); + check_member_(line, *info, *expected, "%lu", nAvgBytesPerSec); + check_member_(line, *info, *expected, "%u", nBlockAlign); + check_member_(line, *info, *expected, "%u", wBitsPerSample); + check_member_(line, *info, *expected, "%u", cbSize); +} + +#define check_dmo_media_type(a, b) check_dmo_media_type_(__LINE__, a, b) +static void check_dmo_media_type_(int line, DMO_MEDIA_TYPE *media_type, const DMO_MEDIA_TYPE *expected) +{ + ok_(__FILE__, line)(IsEqualGUID(&media_type->majortype, &expected->majortype), + "Got unexpected majortype %s, expected %s.\n", + debugstr_guid(&media_type->majortype), debugstr_guid(&expected->majortype)); + ok_(__FILE__, line)(IsEqualGUID(&media_type->subtype, &expected->subtype), + "Got unexpected subtype %s, expected %s.\n", + debugstr_guid(&media_type->subtype), debugstr_guid(&expected->subtype)); + ok_(__FILE__, line)(IsEqualGUID(&media_type->formattype, &expected->formattype), + "Got unexpected formattype %s.\n", + debugstr_guid(&media_type->formattype)); + ok_(__FILE__, line)(media_type->pUnk == NULL, "Got unexpected pUnk %p.\n", media_type->pUnk); + check_member_(line, *media_type, *expected, "%lu", cbFormat); + + if (expected->pbFormat) + { + ok_(__FILE__, line)(!!media_type->pbFormat, "Got NULL pbFormat.\n"); + if (!media_type->pbFormat) + return; + + if (IsEqualGUID(&media_type->formattype, &FORMAT_WaveFormatEx) + && IsEqualGUID(&expected->formattype, &FORMAT_WaveFormatEx)) + check_wave_format((WAVEFORMATEX *)media_type->pbFormat, (WAVEFORMATEX *)expected->pbFormat); + } +} + struct test_buffer { IMediaBuffer IMediaBuffer_iface; @@ -171,6 +214,8 @@ static void test_convert(void) for (i = 0; i < 5; i++) memcpy(inbuf.data + 96 * i, mp3hdr, 4); inbuf.len = 96 * 5; + hr = IMediaObject_ProcessInput(dmo, 1, &inbuf.IMediaBuffer_iface, 0, 0, 0); + ok(hr == DMO_E_INVALIDSTREAMINDEX, "got %#lx\n", hr); hr = IMediaObject_ProcessInput(dmo, 0, &inbuf.IMediaBuffer_iface, 0, 0, 0); ok(hr == S_OK, "got %#lx\n", hr); ok(inbuf.refcount == 2, "Got refcount %ld.\n", inbuf.refcount); @@ -425,6 +470,11 @@ static void test_stream_info(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(!flags, "Got flags %#lx.\n", flags); + hr = IMediaObject_GetInputSizeInfo(dmo, 1, &size, &lookahead, &alignment); + ok(hr == DMO_E_INVALIDSTREAMINDEX, "Got hr %#lx.\n", hr); + hr = IMediaObject_GetOutputSizeInfo(dmo, 1, &size, &alignment); + ok(hr == DMO_E_INVALIDSTREAMINDEX, "Got hr %#lx.\n", hr); + hr = IMediaObject_GetInputSizeInfo(dmo, 0, &size, &lookahead, &alignment); ok(hr == DMO_E_TYPE_NOT_SET, "Got hr %#lx.\n", hr); hr = IMediaObject_GetOutputSizeInfo(dmo, 0, &size, &alignment); @@ -524,6 +574,8 @@ static void test_media_types(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); memset(&mt, 0xcc, sizeof(DMO_MEDIA_TYPE)); + hr = IMediaObject_GetInputType(dmo, 1, 0, &mt); + ok(hr == DMO_E_INVALIDSTREAMINDEX, "Got hr %#lx.\n", hr); hr = IMediaObject_GetInputType(dmo, 0, 0, &mt); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(IsEqualGUID(&mt.majortype, &MEDIATYPE_Audio), "Got major type %s.\n", wine_dbgstr_guid(&mt.majortype)); @@ -541,12 +593,28 @@ static void test_media_types(void) ok(hr == DMO_E_NO_MORE_ITEMS, "Got hr %#lx.\n", hr); memset(&mt, 0xcc, sizeof(DMO_MEDIA_TYPE)); + hr = IMediaObject_GetOutputType(dmo, 1, 0, &mt); + ok(hr == DMO_E_INVALIDSTREAMINDEX, "Got hr %#lx.\n", hr); hr = IMediaObject_GetOutputType(dmo, 0, 0, &mt); ok(hr == DMO_E_TYPE_NOT_SET, "Got hr %#lx.\n", hr); + hr = IMediaObject_SetOutputType(dmo, 0, &output_mt, DMO_SET_TYPEF_TEST_ONLY); + ok(hr == DMO_E_TYPE_NOT_SET, "Got hr %#lx.\n", hr); + + hr = IMediaObject_GetInputCurrentType(dmo, 1, &mt); + ok(hr == DMO_E_INVALIDSTREAMINDEX, "Got hr %#lx.\n", hr); + + hr = IMediaObject_GetInputCurrentType(dmo, 0, &mt); + ok(hr == DMO_E_TYPE_NOT_SET, "Got hr %#lx.\n", hr); + + hr = IMediaObject_SetInputType(dmo, 1, &input_mt, DMO_SET_TYPEF_TEST_ONLY); + ok(hr == DMO_E_INVALIDSTREAMINDEX, "Got hr %#lx.\n", hr); hr = IMediaObject_SetInputType(dmo, 0, &input_mt, DMO_SET_TYPEF_TEST_ONLY); ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaObject_GetInputCurrentType(dmo, 0, &mt); + ok(hr == DMO_E_TYPE_NOT_SET, "Got hr %#lx.\n", hr); + input_mt.majortype = GUID_NULL; hr = IMediaObject_SetInputType(dmo, 0, &input_mt, DMO_SET_TYPEF_TEST_ONLY); ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "Got hr %#lx.\n", hr); @@ -574,6 +642,12 @@ static void test_media_types(void) hr = IMediaObject_SetInputType(dmo, 0, &input_mt, 0); ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaObject_GetInputCurrentType(dmo, 0, &mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + check_dmo_media_type(&mt, &input_mt); + MoFreeMediaType(&mt); + for (i = 0; i < 4; ++i) { memset(&mt, 0xcc, sizeof(DMO_MEDIA_TYPE)); @@ -606,6 +680,12 @@ static void test_media_types(void) hr = IMediaObject_SetInputType(dmo, 0, &input_mt, 0); ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaObject_GetInputCurrentType(dmo, 0, &mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + check_dmo_media_type(&mt, &input_mt); + MoFreeMediaType(&mt); + for (i = 0; i < 2; ++i) { memset(&mt, 0xcc, sizeof(DMO_MEDIA_TYPE)); @@ -634,9 +714,21 @@ static void test_media_types(void) hr = IMediaObject_GetOutputType(dmo, 0, 2, &mt); ok(hr == DMO_E_NO_MORE_ITEMS, "Got hr %#lx.\n", hr); + hr = IMediaObject_SetOutputType(dmo, 1, &output_mt, DMO_SET_TYPEF_TEST_ONLY); + ok(hr == DMO_E_INVALIDSTREAMINDEX, "Got hr %#lx.\n", hr); + + hr = IMediaObject_GetOutputCurrentType(dmo, 1, &mt); + ok(hr == DMO_E_INVALIDSTREAMINDEX, "Got hr %#lx.\n", hr); + + hr = IMediaObject_GetOutputCurrentType(dmo, 0, &mt); + ok(hr == DMO_E_TYPE_NOT_SET, "Got hr %#lx.\n", hr); + hr = IMediaObject_SetOutputType(dmo, 0, &output_mt, DMO_SET_TYPEF_TEST_ONLY); ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IMediaObject_GetOutputCurrentType(dmo, 0, &mt); + ok(hr == DMO_E_TYPE_NOT_SET, "Got hr %#lx.\n", hr); + output_mt.formattype = GUID_NULL; hr = IMediaObject_SetOutputType(dmo, 0, &output_mt, DMO_SET_TYPEF_TEST_ONLY); ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "Got hr %#lx.\n", hr); @@ -645,6 +737,54 @@ static void test_media_types(void) ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "Got hr %#lx.\n", hr); output_mt.formattype = FORMAT_WaveFormatEx; + hr = IMediaObject_SetOutputType(dmo, 0, &output_mt, 0); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IMediaObject_GetOutputCurrentType(dmo, 0, &mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + check_dmo_media_type(&mt, &output_mt); + MoFreeMediaType(&mt); + + output_format.nSamplesPerSec = 24000; + output_format.nAvgBytesPerSec = 24000; + hr = IMediaObject_SetOutputType(dmo, 0, &output_mt, DMO_SET_TYPEF_TEST_ONLY); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + output_format.nSamplesPerSec = 12000; + output_format.nAvgBytesPerSec = 12000; + hr = IMediaObject_SetOutputType(dmo, 0, &output_mt, DMO_SET_TYPEF_TEST_ONLY); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + output_format.nSamplesPerSec = 6000; + output_format.nAvgBytesPerSec = 6000; + hr = IMediaObject_SetOutputType(dmo, 0, &output_mt, DMO_SET_TYPEF_TEST_ONLY); + ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "Got hr %#lx.\n", hr); + + output_format.nSamplesPerSec = 12000; + output_format.nAvgBytesPerSec = 6000; + hr = IMediaObject_SetOutputType(dmo, 0, &output_mt, DMO_SET_TYPEF_TEST_ONLY); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + + output_format.nSamplesPerSec = 48000; + output_format.nAvgBytesPerSec = 48000; + output_format.nChannels = 2; + hr = IMediaObject_SetOutputType(dmo, 0, &output_mt, DMO_SET_TYPEF_TEST_ONLY); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + + /* Windows accepts 32 bits per sample but does not enumerate it */ + output_format.nChannels = 1; + output_format.wBitsPerSample = 32; + output_format.nBlockAlign = 4; + output_format.nSamplesPerSec = 48000; + output_format.nAvgBytesPerSec = 192000; + hr = IMediaObject_SetOutputType(dmo, 0, &output_mt, DMO_SET_TYPEF_TEST_ONLY); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + mp3fmt.wfx.nChannels = 0; + hr = IMediaObject_SetInputType(dmo, 0, &input_mt, DMO_SET_TYPEF_TEST_ONLY); + ok(hr == DMO_E_TYPE_NOT_ACCEPTED, "Got hr %#lx.\n", hr); + IMediaObject_Release(dmo); } diff --git a/dlls/msado15/connection.c b/dlls/msado15/connection.c index d6ca0c2df397..ea9302e0b817 100644 --- a/dlls/msado15/connection.c +++ b/dlls/msado15/connection.c @@ -269,8 +269,10 @@ static HRESULT WINAPI connection_put_ConnectionTimeout( _Connection *iface, LONG static HRESULT WINAPI connection_get_Version( _Connection *iface, BSTR *str ) { - FIXME( "%p, %p\n", iface, str ); - return E_NOTIMPL; + struct connection *connection = impl_from_Connection( iface ); + TRACE( "%p, %p\n", connection, str ); + *str = SysAllocString( L"2.8" ); + return S_OK; } static HRESULT WINAPI connection_Close( _Connection *iface ) diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c index 76e1bb35b77d..d1e22fa14342 100644 --- a/dlls/msado15/tests/msado15.c +++ b/dlls/msado15/tests/msado15.c @@ -1179,6 +1179,12 @@ if (0) /* Crashes on windows */ ok(hr == E_INVALIDARG, "Unexpected hr 0x%08lx\n", hr); } + str = NULL; + hr = _Connection_get_Version(connection, &str); + ok(hr == S_OK, "Failed to get state, hr 0x%08lx\n", hr); + ok(str != NULL, "got %p\n", str); + SysFreeString(str); + state = -1; hr = _Connection_get_State(connection, &state); ok(hr == S_OK, "Failed to get state, hr 0x%08lx\n", hr); diff --git a/dlls/msauddecmft/msauddecmft.c b/dlls/msauddecmft/msauddecmft.c index 813d81387b51..672389564a27 100644 --- a/dlls/msauddecmft/msauddecmft.c +++ b/dlls/msauddecmft/msauddecmft.c @@ -34,6 +34,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmo); #include "initguid.h" DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); +static const GUID CLSID_WineAudioDecoder = {0x480b1517,0xc8e9,0x4eaf,{0xb0,0x06,0xe6,0x30,0x07,0x18,0xd8,0x5d}}; + +static HRESULT WINAPI audio_decoder_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, + REFIID riid, void **out) +{ + static const GUID CLSID_GStreamerAudioDecoder = {0x480b1517,0xc8e9,0x4eae,{0xb0,0x06,0xe6,0x30,0x07,0x18,0xd8,0x5d}}; + return CoCreateInstance(&CLSID_GStreamerAudioDecoder, outer, CLSCTX_INPROC_SERVER, riid, out); +} static HRESULT WINAPI aac_decoder_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **out) @@ -71,6 +79,17 @@ static const IClassFactoryVtbl aac_decoder_factory_vtbl = static IClassFactory aac_decoder_factory = {&aac_decoder_factory_vtbl}; +static const IClassFactoryVtbl audio_decoder_factory_vtbl = +{ + class_factory_QueryInterface, + class_factory_AddRef, + class_factory_Release, + audio_decoder_factory_CreateInstance, + class_factory_LockServer, +}; + +static IClassFactory audio_decoder_factory = {&audio_decoder_factory_vtbl}; + /*********************************************************************** * DllGetClassObject (msauddecmft.@) */ @@ -78,6 +97,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out) { if (IsEqualGUID(clsid, &CLSID_MSAACDecMFT)) return IClassFactory_QueryInterface(&aac_decoder_factory, riid, out); + if (IsEqualGUID(clsid, &CLSID_WineAudioDecoder)) + return IClassFactory_QueryInterface(&audio_decoder_factory, riid, out); *out = NULL; FIXME("Unknown clsid %s.\n", debugstr_guid(clsid)); @@ -100,6 +121,16 @@ HRESULT WINAPI DllRegisterServer(void) {MFMediaType_Audio, MFAudioFormat_Float}, {MFMediaType_Audio, MFAudioFormat_PCM}, }; + MFT_REGISTER_TYPE_INFO audio_decoder_mft_inputs[] = + { + {MFMediaType_Audio, MFAudioFormat_Vorbis}, + {MFMediaType_Audio, MFAudioFormat_Opus}, + }; + MFT_REGISTER_TYPE_INFO audio_decoder_mft_outputs[] = + { + {MFMediaType_Audio, MFAudioFormat_Float}, + {MFMediaType_Audio, MFAudioFormat_PCM}, + }; HRESULT hr; TRACE("\n"); @@ -111,6 +142,11 @@ HRESULT WINAPI DllRegisterServer(void) ARRAY_SIZE(aac_decoder_mft_inputs), aac_decoder_mft_inputs, ARRAY_SIZE(aac_decoder_mft_outputs), aac_decoder_mft_outputs, NULL))) return hr; + if (FAILED(hr = MFTRegister(CLSID_WineAudioDecoder, MFT_CATEGORY_AUDIO_DECODER, + (WCHAR *)L"Wine Audio Decoder", MFT_ENUM_FLAG_SYNCMFT, + ARRAY_SIZE(audio_decoder_mft_inputs), audio_decoder_mft_inputs, + ARRAY_SIZE(audio_decoder_mft_outputs), audio_decoder_mft_outputs, NULL))) + return hr; return S_OK; } @@ -128,6 +164,8 @@ HRESULT WINAPI DllUnregisterServer(void) return hr; if (FAILED(hr = MFTUnregister(CLSID_MSAACDecMFT))) return hr; + if (FAILED(hr = MFTUnregister(CLSID_WineAudioDecoder))) + return hr; return S_OK; } diff --git a/dlls/msauddecmft/msauddecmft.idl b/dlls/msauddecmft/msauddecmft.idl index f1b2a62a2d24..1aba2baf7b13 100644 --- a/dlls/msauddecmft/msauddecmft.idl +++ b/dlls/msauddecmft/msauddecmft.idl @@ -23,3 +23,9 @@ uuid(32d186a7-218f-4c75-8876-dd77273a8999) ] coclass CMSAACDecMFT {} + +[ + threading(both), + uuid(480b1517-c8e9-4eaf-b006-e6300718d85d) +] +coclass WineAudioDecoder {} diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index e1dd00656e94..454a47bec8c8 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -711,7 +711,7 @@ HRESULT ICLRRuntimeInfo_GetRuntimeHost(ICLRRuntimeInfo *iface, RuntimeHost **res #ifdef __i386__ static const WCHAR libmono2_arch_dll[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','-','x','8','6','.','d','l','l',0}; -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__aarch64__) static const WCHAR libmono2_arch_dll[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','-','x','8','6','_','6','4','.','d','l','l',0}; #else static const WCHAR libmono2_arch_dll[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','.','d','l','l',0}; @@ -792,7 +792,8 @@ static BOOL get_mono_path_registry(LPWSTR path) static BOOL get_mono_path_dos(const WCHAR *dir, LPWSTR path) { static const WCHAR unix_prefix[] = {'\\','\\','?','\\','u','n','i','x','\\'}; - static const WCHAR basedir[] = L"\\wine-mono-" WINE_MONO_VERSION; + static const WCHAR basedir[] = L"\\wine-mono"; + static const WCHAR basedir2[] = L"\\wine-mono-" WINE_MONO_VERSION; LPWSTR dos_dir; WCHAR mono_dll_path[MAX_PATH]; DWORD len; @@ -812,6 +813,20 @@ static BOOL get_mono_path_dos(const WCHAR *dir, LPWSTR path) free(dos_dir); + if (!ret) + { + len = lstrlenW( dir ) + lstrlenW( basedir2 ) + 1; + if (!(dos_dir = malloc( len * sizeof(WCHAR) ))) return FALSE; + lstrcpyW( dos_dir, dir ); + lstrcatW( dos_dir, basedir2 ); + + ret = find_mono_dll(dos_dir, mono_dll_path); + if (ret) + lstrcpyW(path, dos_dir); + + free(dos_dir); + } + return ret; } @@ -842,7 +857,7 @@ static BOOL get_mono_path_datadir(LPWSTR path) { static const WCHAR winedatadirW[] = {'W','I','N','E','D','A','T','A','D','I','R',0}; static const WCHAR winebuilddirW[] = {'W','I','N','E','B','U','I','L','D','D','I','R',0}; - static const WCHAR unix_prefix[] = {'\\','?','?','\\','u','n','i','x','\\'}; + static const WCHAR unix_prefix[] = {'\\','?','?','\\','u','n','i','x','\\',0}; static const WCHAR monoW[] = {'\\','m','o','n','o',0}; static const WCHAR dotdotmonoW[] = {'\\','.','.','\\','m','o','n','o',0}; const WCHAR *data_dir, *suffix; @@ -1730,6 +1745,44 @@ static MonoAssembly* mono_assembly_try_load(WCHAR *path) return result; } +static BOOL compile_assembly(const char *source, const char *target, char *target_path, DWORD target_path_len) +{ + static const char *csc = "C:\\windows\\Microsoft.NET\\Framework\\v2.0.50727\\csc.exe"; + char cmdline[2 * MAX_PATH + 74], tmp[MAX_PATH], tmpdir[MAX_PATH], source_path[MAX_PATH]; + STARTUPINFOA si = {.cb = sizeof(STARTUPINFOA)}; + PROCESS_INFORMATION pi; + HANDLE file; + DWORD size; + BOOL ret; + LUID id; + + if (!PathFileExistsA(csc)) return FALSE; + if (!AllocateLocallyUniqueId(&id)) return FALSE; + + GetTempPathA(MAX_PATH, tmp); + if (!GetTempFileNameA(tmp, "assembly", id.LowPart, tmpdir)) return FALSE; + if (!CreateDirectoryA(tmpdir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) return FALSE; + + snprintf(source_path, MAX_PATH, "%s\\source.cs", tmpdir); + snprintf(target_path, target_path_len, "%s\\%s", tmpdir, target); + + file = CreateFileA(source_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) return FALSE; + ret = WriteFile(file, source, strlen(source), &size, NULL); + CloseHandle(file); + if (!ret) return FALSE; + + snprintf(cmdline, ARRAY_SIZE(cmdline), "%s /t:library /out:\"%s\" \"%s\"", csc, target_path, source_path); + ret = CreateProcessA(csc, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + if (!ret) return FALSE; + + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + return PathFileExistsA(target_path); +} + static MonoAssembly* CDECL mono_assembly_preload_hook_fn(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { int flags = 0; @@ -1762,6 +1815,8 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_v2_fn(MonoAssemblyNam static const WCHAR dotdllW[] = {'.','d','l','l',0}; static const WCHAR dotexeW[] = {'.','e','x','e',0}; + const char *sgi = getenv("SteamGameId"); + stringname = mono_stringify_assembly_name(aname); assemblyname = mono_assembly_name_get_name(aname); culture = mono_assembly_name_get_culture(aname); @@ -1818,6 +1873,90 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_v2_fn(MonoAssemblyNam } } + if (!strcmp(assemblyname, "ManagedStarter")) + { + /* HACK for Mount & Blade II: Bannerlord + * + * The launcher executable uses an AssemblyResolve event handler + * to redirect loads of the "ManagedStarter" assembly to + * Bannerlord.exe. Due to Mono issue #11319, the runtime attempts + * to load ManagedStarter before executing the static constructor + * that adds this event handler. We work around this by doing the + * same thing in our own assembly load hook. */ + if (sgi && !strcmp(sgi, "261550")) + { + FIXME("hack, using Bannerlord.exe\n"); + + result = mono_assembly_open("Bannerlord.exe", &stat); + + if (result) + goto done; + else + ERR("Bannerlord.exe failed to load\n"); + } + } + + /* HACK for games which reference a type from a non-existing DLL. + * Native .NET framework normally gets away with it but Mono cannot + * due to some deeply rooted differences. */ + if (sgi) + { + size_t i; + + static const struct { + const char *assembly_name; + const char *module_name; + const char *appid; + const char *source; + } assembly_hacks[] = { + { + "CameraQuakeViewer", + "CameraQuakeViewer.dll", + "527280", /* Nights of Azure */ + "namespace CQViewer { class CQMgr {} }" + }, + { + "UnrealEdCSharp", + "UnrealEdCSharp.dll", + "317940", /* Karmaflow */ + "namespace ContentBrowser { class IContentBrowserBackendInterface {} class Package {} } " + }, + { + "UnrealEdCSharp", + "UnrealEdCSharp.dll", + "321360", /* Primal Carnage: Extinction */ + "namespace ContentBrowser { class IContentBrowserBackendInterface {} class Package {} } " + }, + { + "DockPanel", + "DockPanel.dll", + "46450", /* Grotesque Tactics: Evil Heroes */ + "namespace WeifenLuo.WinFormsUI { class DockPanel {} }" + }, + }; + + for (i = 0; i < ARRAY_SIZE(assembly_hacks); ++i) + { + if (!strcmp(assemblyname, assembly_hacks[i].assembly_name) && + !strcmp(sgi, assembly_hacks[i].appid)) + { + char assembly_path[MAX_PATH]; + + FIXME("HACK: Building %s\n", assembly_hacks[i].module_name); + + if (compile_assembly(assembly_hacks[i].source, assembly_hacks[i].module_name, assembly_path, MAX_PATH)) + result = mono_assembly_open(assembly_path, &stat); + else + ERR("HACK: Failed to build %s\n", assembly_hacks[i].assembly_name); + + if (result) + goto done; + + ERR("HACK: Failed to load %s\n", assembly_hacks[i].assembly_name); + } + } + } + if ((search_flags & ASSEMBLY_SEARCH_GAC) != 0) { stringnameW_size = MultiByteToWideChar(CP_UTF8, 0, stringname, -1, NULL, 0); diff --git a/dlls/mscoree/mscoree_main.c b/dlls/mscoree/mscoree_main.c index 2b9f78a39556..b68f9a509694 100644 --- a/dlls/mscoree/mscoree_main.c +++ b/dlls/mscoree/mscoree_main.c @@ -800,7 +800,7 @@ static BOOL invoke_appwiz(void) return ret; } -static BOOL get_support_msi(LPCWSTR mono_path, LPWSTR msi_path) +static BOOL get_support_msi(LPCWSTR mono_path, LPWSTR msi_path, BOOL ignore_version) { static const WCHAR support_msi_relative[] = {'\\','s','u','p','p','o','r','t','\\','w','i','n','e','m','o','n','o','-','s','u','p','p','o','r','t','.','m','s','i',0}; UINT (WINAPI *pMsiOpenPackageW)(LPCWSTR,ULONG*); @@ -838,7 +838,7 @@ static BOOL get_support_msi(LPCWSTR mono_path, LPWSTR msi_path) if (res == ERROR_SUCCESS) { TRACE("found support msi version %s at %s\n", versionstringbuf, debugstr_w(msi_path)); - if (compare_versions(WINE_MONO_VERSION, versionstringbuf) <= 0) + if (ignore_version || compare_versions(WINE_MONO_VERSION, versionstringbuf) <= 0) { ret = TRUE; } @@ -922,12 +922,12 @@ static BOOL install_wine_mono(void) initresult = CoInitialize(NULL); - ret = get_support_msi(mono_path, support_msi_path); + ret = get_support_msi(mono_path, support_msi_path, FALSE); if (!ret) { /* Try looking outside c:\windows\mono */ ret = (get_mono_path(mono_path, TRUE) && - get_support_msi(mono_path, support_msi_path)); + get_support_msi(mono_path, support_msi_path, TRUE)); } if (ret) diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h index eb7c75bacb98..f5396c5b6030 100644 --- a/dlls/mscoree/mscoree_private.h +++ b/dlls/mscoree/mscoree_private.h @@ -45,7 +45,7 @@ extern HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version); extern HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count); extern HRESULT assembly_get_native_entrypoint(ASSEMBLY *assembly, NativeEntryPointFunc *func); -#define WINE_MONO_VERSION "9.4.0" +#define WINE_MONO_VERSION "10.4.1" /* Mono embedding */ typedef struct _MonoDomain MonoDomain; diff --git a/dlls/msctf/msctf.c b/dlls/msctf/msctf.c index e2dde836b12f..a79a32afc025 100644 --- a/dlls/msctf/msctf.c +++ b/dlls/msctf/msctf.c @@ -67,7 +67,6 @@ static UINT array_size; static struct list AtsList = LIST_INIT(AtsList); static UINT activated = 0; -DWORD tlsIndex = 0; TfClientId processId = 0; ITfCompartmentMgr *globalCompartmentMgr = NULL; @@ -394,23 +393,19 @@ HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp) ActivatedTextService *actsvr; ITfCategoryMgr *catmgr; AtsEntry *entry; - ITfThreadMgrEx *tm = TlsGetValue(tlsIndex); + ITfThreadMgr *tm; ITfClientId *clientid; - if (!tm) return E_UNEXPECTED; + if (FAILED(TF_GetThreadMgr(&tm))) return E_UNEXPECTED; actsvr = malloc(sizeof(ActivatedTextService)); - if (!actsvr) return E_OUTOFMEMORY; + if (!actsvr) goto fail; - ITfThreadMgrEx_QueryInterface(tm, &IID_ITfClientId, (void **)&clientid); + ITfThreadMgr_QueryInterface(tm, &IID_ITfClientId, (void **)&clientid); ITfClientId_GetClientId(clientid, &lp->clsid, &actsvr->tid); ITfClientId_Release(clientid); - if (!actsvr->tid) - { - free(actsvr); - return E_OUTOFMEMORY; - } + if (!actsvr->tid) goto fail; actsvr->pITfTextInputProcessor = NULL; actsvr->LanguageProfile = *lp; @@ -437,20 +432,21 @@ HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp) deactivate_remove_conflicting_ts(&actsvr->LanguageProfile.catid); if (activated > 0) - activate_given_ts(actsvr, tm); + activate_given_ts(actsvr, (ITfThreadMgrEx *)tm); entry = malloc(sizeof(AtsEntry)); - - if (!entry) - { - free(actsvr); - return E_OUTOFMEMORY; - } + if (!entry) goto fail; entry->ats = actsvr; list_add_head(&AtsList, &entry->entry); + ITfThreadMgr_Release(tm); return S_OK; + +fail: + ITfThreadMgr_Release(tm); + free(actsvr); + return E_OUTOFMEMORY; } BOOL get_active_textservice(REFCLSID rclsid, TF_LANGUAGEPROFILE *profile) @@ -554,11 +550,9 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad) switch (fdwReason) { case DLL_PROCESS_ATTACH: - tlsIndex = TlsAlloc(); break; case DLL_PROCESS_DETACH: if (fImpLoad) break; - TlsFree(tlsIndex); break; } return TRUE; @@ -592,20 +586,6 @@ HRESULT WINAPI TF_CreateThreadMgr(ITfThreadMgr **pptim) return ThreadMgr_Constructor(NULL,(IUnknown**)pptim); } -/*********************************************************************** - * TF_GetThreadMgr (MSCTF.@) - */ -HRESULT WINAPI TF_GetThreadMgr(ITfThreadMgr **pptim) -{ - TRACE("\n"); - *pptim = TlsGetValue(tlsIndex); - - if (*pptim) - ITfThreadMgr_AddRef(*pptim); - - return S_OK; -} - /*********************************************************************** * SetInputScope(MSCTF.@) */ diff --git a/dlls/msctf/msctf_internal.h b/dlls/msctf/msctf_internal.h index 24c8c017ff30..e465b985bf2b 100644 --- a/dlls/msctf/msctf_internal.h +++ b/dlls/msctf/msctf_internal.h @@ -36,7 +36,6 @@ #define COOKIE_MAGIC_INPUTPROCESSORPROFILEACTIVATIONSINK 0x00b0 #define COOKIE_MAGIC_ACTIVELANGSINK 0x00c0 -extern DWORD tlsIndex; extern TfClientId processId; extern ITfCompartmentMgr *globalCompartmentMgr; @@ -87,9 +86,9 @@ typedef struct { #define SINK_ENTRY(cursor,type) (LIST_ENTRY(cursor,Sink,entry)->interfaces.p##type) #define SINK_FOR_EACH(cursor,list,type,elem) \ - for ((cursor) = (list)->next, elem = SINK_ENTRY(cursor,type); \ - (cursor) != (list); \ - (cursor) = (cursor)->next, elem = SINK_ENTRY(cursor,type)) + for ((cursor) = (list)->next; \ + (cursor) != (list) && (elem = SINK_ENTRY(cursor, type), 1); \ + (cursor) = (cursor)->next) HRESULT advise_sink(struct list *sink_list, REFIID riid, DWORD cookie_magic, IUnknown *unk, DWORD *cookie); HRESULT unadvise_sink(DWORD cookie); diff --git a/dlls/msctf/threadmgr.c b/dlls/msctf/threadmgr.c index 11c79c030fff..ff2b0b95ff77 100644 --- a/dlls/msctf/threadmgr.c +++ b/dlls/msctf/threadmgr.c @@ -37,6 +37,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(msctf); +static CRITICAL_SECTION ThreadMgrCs; +static CRITICAL_SECTION_DEBUG ThreadMgrCsDebug = +{ + 0, 0, &ThreadMgrCs, + {&ThreadMgrCsDebug.ProcessLocksList, + &ThreadMgrCsDebug.ProcessLocksList }, + 0, 0, {(DWORD_PTR)(__FILE__ ": ThreadMgrCs")} +}; +static CRITICAL_SECTION ThreadMgrCs = {&ThreadMgrCsDebug, -1, 0, 0, 0, 0}; +struct list ThreadMgrList = LIST_INIT(ThreadMgrList); + typedef struct tagPreservedKey { struct list entry; @@ -98,6 +109,9 @@ typedef struct tagACLMulti { struct list ThreadMgrEventSink; struct list UIElementSink; struct list InputProcessorProfileActivationSink; + + DWORD threadId; + struct list entry; } ThreadMgr; typedef struct tagEnumTfDocumentMgr { @@ -110,6 +124,11 @@ typedef struct tagEnumTfDocumentMgr { static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut); +static inline ThreadMgr *impl_from_ITfThreadMgr(ITfThreadMgr *iface) +{ + return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEx_iface); +} + static inline ThreadMgr *impl_from_ITfThreadMgrEx(ITfThreadMgrEx *iface) { return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEx_iface); @@ -155,6 +174,35 @@ static inline EnumTfDocumentMgr *impl_from_IEnumTfDocumentMgrs(IEnumTfDocumentMg return CONTAINING_RECORD(iface, EnumTfDocumentMgr, IEnumTfDocumentMgrs_iface); } +/*********************************************************************** + * TF_GetThreadMgr (MSCTF.@) + */ +HRESULT WINAPI TF_GetThreadMgr(ITfThreadMgr **pptim) +{ + DWORD id = GetCurrentThreadId(); + ThreadMgr *cursor; + + TRACE("%p\n", pptim); + + if (!pptim) + return E_INVALIDARG; + + EnterCriticalSection(&ThreadMgrCs); + LIST_FOR_EACH_ENTRY(cursor, &ThreadMgrList, ThreadMgr, entry) + { + if (cursor->threadId == id) + { + ITfThreadMgrEx_AddRef(&cursor->ITfThreadMgrEx_iface); + *pptim = (ITfThreadMgr *)&cursor->ITfThreadMgrEx_iface; + LeaveCriticalSection(&ThreadMgrCs); + return S_OK; + } + } + LeaveCriticalSection(&ThreadMgrCs); + *pptim = NULL; + return E_FAIL; +} + static void ThreadMgr_Destructor(ThreadMgr *This) { struct list *cursor, *cursor2; @@ -163,7 +211,9 @@ static void ThreadMgr_Destructor(ThreadMgr *This) if (This->focusHook) UnhookWindowsHookEx(This->focusHook); - TlsSetValue(tlsIndex,NULL); + EnterCriticalSection(&ThreadMgrCs); + list_remove(&This->entry); + LeaveCriticalSection(&ThreadMgrCs); TRACE("destroying %p\n", This); if (This->focus) ITfDocumentMgr_Release(This->focus); @@ -386,17 +436,20 @@ static HRESULT WINAPI ThreadMgr_SetFocus(ITfThreadMgrEx *iface, ITfDocumentMgr * static LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lParam) { + ITfThreadMgr *ThreadMgr_iface; ThreadMgr *This; - This = TlsGetValue(tlsIndex); - if (!This) + if (FAILED(TF_GetThreadMgr(&ThreadMgr_iface))) { ERR("Hook proc but no ThreadMgr for this thread. Serious Error\n"); return 0; } + + This = impl_from_ITfThreadMgr(ThreadMgr_iface); if (!This->focusHook) { ERR("Hook proc but no ThreadMgr focus Hook. Serious Error\n"); + ITfThreadMgr_Release(ThreadMgr_iface); return 0; } @@ -417,6 +470,7 @@ static LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lPa } } + ITfThreadMgr_Release(ThreadMgr_iface); return CallNextHookEx(This->focusHook, nCode, wParam, lParam); } @@ -1346,13 +1400,8 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) return CLASS_E_NOAGGREGATION; /* Only 1 ThreadMgr is created per thread */ - This = TlsGetValue(tlsIndex); - if (This) - { - ThreadMgr_AddRef(&This->ITfThreadMgrEx_iface); - *ppOut = (IUnknown*)&This->ITfThreadMgrEx_iface; + if (SUCCEEDED(TF_GetThreadMgr((ITfThreadMgr **)ppOut))) return S_OK; - } This = calloc(1, sizeof(ThreadMgr)); if (This == NULL) @@ -1367,7 +1416,6 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) This->ITfUIElementMgr_iface.lpVtbl = &ThreadMgrUIElementMgrVtbl; This->ITfSourceSingle_iface.lpVtbl = &SourceSingleVtbl; This->refCount = 1; - TlsSetValue(tlsIndex,This); CompartmentMgr_Constructor((IUnknown*)&This->ITfThreadMgrEx_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr); @@ -1384,6 +1432,11 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) list_init(&This->UIElementSink); list_init(&This->InputProcessorProfileActivationSink); + This->threadId = GetCurrentThreadId(); + EnterCriticalSection(&ThreadMgrCs); + list_add_tail(&ThreadMgrList, &This->entry); + LeaveCriticalSection(&ThreadMgrCs); + TRACE("returning %p\n", This); *ppOut = (IUnknown *)&This->ITfThreadMgrEx_iface; return S_OK; diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 77eec0499128..0eb18fe8d3df 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -34,6 +34,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); #define MAX_ARGS 16 +DISPID propput_dispid = DISPID_PROPERTYPUT; static ExternalCycleCollectionParticipant dispex_ccp; static CRITICAL_SECTION cs_dispex_static_data; @@ -800,6 +801,14 @@ HRESULT dispex_define_property(DispatchEx *dispex, const WCHAR *name, DWORD flag dynamic_prop_t *prop; HRESULT hres; + if(flags & PROPF_CONFIGURABLE) { + prop = NULL; + hres = get_dynamic_prop(dispex, name, 0, &prop); + assert(FAILED(hres)); + if(prop) + return hres; + } + hres = alloc_dynamic_prop(dispex, name, NULL, &prop); if(FAILED(hres)) return hres; @@ -1075,7 +1084,7 @@ static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARI } } - hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, func->info->tid, DISPATCH_METHOD, ¶ms, res, ei, caller); + hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, -func->info->tid, DISPATCH_METHOD, ¶ms, res, ei, caller); fail: while(argc--) @@ -1102,7 +1111,7 @@ static HRESULT function_call(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARIA if(FAILED(hres)) return CTL_E_ILLEGALFUNCTIONCALL; - hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, func->info->tid, DISPATCH_METHOD, ¶ms, res, ei, caller); + hres = IWineJSDispatchHost_CallFunction(this_iface, func->info->id, -func->info->tid, DISPATCH_METHOD, ¶ms, res, ei, caller); IWineJSDispatchHost_Release(this_iface); return (hres == E_UNEXPECTED) ? CTL_E_ILLEGALFUNCTIONCALL : hres; } @@ -1179,7 +1188,7 @@ static HRESULT function_get_prop_desc(DispatchEx *dispex, DISPID id, struct prop desc->id = id; desc->flags = 0; desc->name = function_props[idx].name; - desc->iid = 0; + desc->prototype_id = 0; return S_OK; } @@ -1375,6 +1384,11 @@ HRESULT dispex_get_chain_builtin_id(DispatchEx *dispex, const WCHAR *name, DWORD assert(compat_mode >= COMPAT_MODE_IE9); + hres = get_builtin_id(info, name, flags, pid); + if(hres != DISP_E_UNKNOWNNAME) + return hres; + info = info->desc->prototype_info[compat_mode - COMPAT_MODE_IE9]; + for(;;) { hres = get_builtin_id(info, name, flags, pid); if(hres != DISP_E_UNKNOWNNAME) @@ -2187,8 +2201,6 @@ HRESULT dispex_prop_get(DispatchEx *dispex, DISPID id, LCID lcid, VARIANT *r, EX HRESULT dispex_prop_put(DispatchEx *dispex, DISPID id, LCID lcid, VARIANT *v, EXCEPINFO *ei, IServiceProvider *caller) { - static DISPID propput_dispid = DISPID_PROPERTYPUT; - switch(get_dispid_type(id)) { case DISPEXPROP_CUSTOM: { DISPPARAMS dp = { .cArgs = 1, .rgvarg = v, .cNamedArgs = 1, .rgdispidNamedArgs = &propput_dispid }; @@ -2522,7 +2534,7 @@ HRESULT dispex_next_id(DispatchEx *dispex, DISPID id, BOOL enum_all_own_props, D } if(dispex->info->vtbl->next_dispid) { - hres = dispex->info->vtbl->next_dispid(dispex, id, ret); + hres = dispex->info->vtbl->next_dispid(dispex, id, enum_all_own_props, ret); if(hres != S_FALSE) return hres; } @@ -2573,7 +2585,7 @@ HRESULT dispex_index_prop_desc(DispatchEx *dispex, DISPID id, struct property_in desc->flags |= PROPF_ENUMERABLE; desc->name = NULL; desc->index = id - MSHTML_DISPID_CUSTOM_MIN; - desc->iid = 0; + desc->prototype_id = 0; return S_OK; } @@ -2593,18 +2605,18 @@ static HRESULT get_host_property_descriptor(DispatchEx *This, DISPID id, struct desc->flags = PROPF_CONFIGURABLE; desc->name = func->name; if(func->func_disp_idx >= 0) { - desc->iid = func->tid; + desc->prototype_id = This->info->desc->id ? This->info->desc->id : -func->tid; desc->flags |= PROPF_METHOD | PROPF_WRITABLE; }else { if(func->func_disp_idx == -1) desc->flags |= PROPF_ENUMERABLE; if(This->info->is_prototype) { - desc->iid = func->tid; + desc->prototype_id = This->info->desc->id ? This->info->desc->id : -func->tid; if(func->put_vtbl_off) desc->flags |= PROPF_WRITABLE; }else { desc->flags |= PROPF_WRITABLE; - desc->iid = 0; + desc->prototype_id = 0; } } break; @@ -2613,7 +2625,7 @@ static HRESULT get_host_property_descriptor(DispatchEx *This, DISPID id, struct dynamic_prop_t *prop = &This->dynamic_data->props[id - DISPID_DYNPROP_0]; desc->flags = prop->flags & PROPF_PUBLIC_MASK; desc->name = prop->name; - desc->iid = 0; + desc->prototype_id = 0; break; } case DISPEXPROP_CUSTOM: @@ -2639,19 +2651,27 @@ static HRESULT WINAPI JSDispatchHost_LookupProperty(IWineJSDispatchHost *iface, return get_host_property_descriptor(This, id, desc); } -static HRESULT WINAPI JSDispatchHost_NextProperty(IWineJSDispatchHost *iface, DISPID id, struct property_info *desc) +static HRESULT WINAPI JSDispatchHost_OverrideProperty(IWineJSDispatchHost *iface, const WCHAR *name, + struct property_info *get_desc, VARIANT *get_value) { DispatchEx *This = impl_from_IWineJSDispatchHost(iface); - DISPID next; HRESULT hres; + DISPID id; - TRACE("%s (%p)->(%lx)\n", This->info->name, This, id); + if(!This->info->vtbl->override) + return S_FALSE; - hres = dispex_next_id(This, id, TRUE, &next); - if(hres != S_OK) - return hres; + TRACE("%s (%p)->(%s %p)\n", This->info->name, This, debugstr_w(name), get_value); - return get_host_property_descriptor(This, next, desc); + if(get_desc) { + hres = dispex_get_id(This, name, fdexNameCaseSensitive, &id); + if(FAILED(hres)) + return (hres == DISP_E_UNKNOWNNAME) ? S_FALSE : hres; + + return get_host_property_descriptor(This, id, get_desc); + } + + return This->info->vtbl->override(This, name, get_value); } static HRESULT WINAPI JSDispatchHost_GetProperty(IWineJSDispatchHost *iface, DISPID id, LCID lcid, VARIANT *r, @@ -2700,19 +2720,31 @@ static HRESULT WINAPI JSDispatchHost_ConfigureProperty(IWineJSDispatchHost *ifac return S_OK; } -static HRESULT WINAPI JSDispatchHost_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DWORD flags, +static HRESULT WINAPI JSDispatchHost_CallFunction(IWineJSDispatchHost *iface, DISPID id, INT32 prototype_id, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller) { DispatchEx *This = impl_from_IWineJSDispatchHost(iface); + dispex_static_data_t *desc = This->info->desc; func_info_t *func; HRESULT hres; - TRACE("%s (%p)->(%lx %x %lx %p %p %p %p)\n", This->info->name, This, id, iid, flags, dp, ret, ei, caller); + TRACE("%s (%p)->(%lx %d %lx %p %p %p %p)\n", This->info->name, This, id, prototype_id, flags, dp, ret, ei, caller); hres = get_builtin_func(This->info, id, &func); - if(FAILED(hres) || func->tid != iid) + if(FAILED(hres)) return E_UNEXPECTED; + if(prototype_id <= 0) { + if(func->tid != -prototype_id) + return E_UNEXPECTED; + }else if(prototype_id != desc->id) { + while(prototype_id != desc->prototype_id) { + if(!desc->prototype_id) + return E_UNEXPECTED; + desc = object_descriptors[desc->prototype_id]; + } + } + switch(flags) { case DISPATCH_METHOD: assert(func->func_disp_idx >= 0); @@ -2741,6 +2773,40 @@ static HRESULT WINAPI JSDispatchHost_Construct(IWineJSDispatchHost *iface, LCID return dispex_prop_call(This, DISPID_VALUE, lcid, flags, dp, ret, ei, caller); } +static HRESULT WINAPI JSDispatchHost_FillProperties(IWineJSDispatchHost *iface) +{ + DispatchEx *This = impl_from_IWineJSDispatchHost(iface); + DISPID id = DISPID_STARTENUM; + HRESULT hres, retval = S_OK; + struct property_info desc; + + TRACE("%s (%p)->(%lx)\n", This->info->name, This, id); + + if(This->info->vtbl->fill_props) { + retval = This->info->vtbl->fill_props(This); + if(FAILED(retval)) + return retval; + } + + for(;;) { + hres = dispex_next_id(This, id, TRUE, &id); + if(FAILED(hres)) + return hres; + if(hres == S_FALSE) + break; + + hres = get_host_property_descriptor(This, id, &desc); + if(FAILED(hres)) + return hres; + + hres = IWineJSDispatch_UpdateProperty(This->jsdisp, &desc); + if(FAILED(hres)) + return hres; + } + + return retval; +} + static HRESULT WINAPI JSDispatchHost_GetOuterDispatch(IWineJSDispatchHost *iface, IWineJSDispatchHost **ret) { DispatchEx *This = impl_from_IWineJSDispatchHost(iface); @@ -2758,6 +2824,30 @@ static HRESULT WINAPI JSDispatchHost_ToString(IWineJSDispatchHost *iface, BSTR * return dispex_to_string(This, str); } +static BOOL __cdecl is_full_cc(void) +{ + thread_data_t *thread_data = get_thread_data(FALSE); + return thread_data ? thread_data->full_cc_in_progress : FALSE; +} + +static void __cdecl describe_node(ULONG ref, const char *obj_name, nsCycleCollectionTraversalCallback *cb) +{ + nsCycleCollectingAutoRefCnt ccref; + + ccref_init(&ccref, ref); + describe_cc_node(&ccref, obj_name, cb); +} + +static void WINAPI JSDispatchHost_InitCC(IWineJSDispatchHost *iface, struct jshost_cc_api *cc_api, const CCObjCallback *callback) +{ + ccp_init(&cc_api->participant, callback); + cc_api->is_full_cc = is_full_cc; + cc_api->collect = cc_api_collect; + cc_api->describe_node = describe_node; + cc_api->note_edge = (note_edge_t)note_cc_edge; + list_add_tail(&cc_api_list, &cc_api->entry); +} + static IWineJSDispatchHostVtbl JSDispatchHostVtbl = { DispatchEx_QueryInterface, DispatchEx_AddRef, @@ -2776,17 +2866,73 @@ static IWineJSDispatchHostVtbl JSDispatchHostVtbl = { DispatchEx_GetNameSpaceParent, JSDispatchHost_GetJSDispatch, JSDispatchHost_LookupProperty, - JSDispatchHost_NextProperty, + JSDispatchHost_OverrideProperty, JSDispatchHost_GetProperty, JSDispatchHost_SetProperty, JSDispatchHost_DeleteProperty, JSDispatchHost_ConfigureProperty, JSDispatchHost_CallFunction, JSDispatchHost_Construct, + JSDispatchHost_FillProperties, JSDispatchHost_GetOuterDispatch, JSDispatchHost_ToString, + JSDispatchHost_InitCC }; +HRESULT dispex_builtin_props_to_json(DispatchEx *dispex, HTMLInnerWindow *window, VARIANT *ret) +{ + IWineJSDispatchHost *subdispex_iface; + static WCHAR toJSONW[] = L"toJSON"; + func_info_t *func, *end; + IWineJSDispatch *json; + DISPID id, to_json; + HRESULT hres; + VARIANT var; + DISPPARAMS dp = { 0 }, put_dp = { &var, &propput_dispid, 1, 1 }; + + if(!window->jscript) + return E_UNEXPECTED; + + hres = IWineJScript_CreateObject(window->jscript, &json); + if(FAILED(hres)) + return hres; + + for(func = dispex->info->funcs, end = func + dispex->info->func_cnt; func < end; func++) { + if(func->func_disp_idx != -1) + continue; + hres = builtin_propget(dispex, func, &dp, &var, NULL, NULL); + if(SUCCEEDED(hres)) { + hres = IWineJSDispatch_GetDispID(json, func->name, fdexNameEnsure | fdexNameCaseSensitive, &id); + + if(SUCCEEDED(hres) && V_VT(&var) == VT_DISPATCH && + SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IWineJSDispatchHost, (void**)&subdispex_iface))) { + if(subdispex_iface->lpVtbl == &JSDispatchHostVtbl) { + DispatchEx *subdispex = impl_from_IWineJSDispatchHost(subdispex_iface); + + if(SUCCEEDED(get_builtin_id(subdispex->info, toJSONW, fdexNameCaseSensitive, &to_json))) { + VariantClear(&var); + hres = dispex_call_builtin(subdispex, to_json, &dp, &var, NULL, NULL); + } + } + IWineJSDispatchHost_Release(subdispex_iface); + } + if(SUCCEEDED(hres)) + hres = IWineJSDispatch_InvokeEx(json, id, 0, DISPATCH_PROPERTYPUT, &put_dp, NULL, NULL, NULL); + VariantClear(&var); + } + if(FAILED(hres)) { + IWineJSDispatch_Release(json); + return hres; + } + } + + if(ret) { + V_VT(ret) = VT_DISPATCH; + V_DISPATCH(ret) = (IDispatch*)json; + } + return hres; +} + static nsresult NSAPI dispex_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb) { DispatchEx *This = impl_from_IWineJSDispatchHost(p); @@ -2797,6 +2943,9 @@ static nsresult NSAPI dispex_traverse(void *ccp, void *p, nsCycleCollectionTrave if(This->info->vtbl->traverse) This->info->vtbl->traverse(This, cb); + if(This->jsdisp) + IWineJSDispatch_Traverse(This->jsdisp, cb); + if(!This->dynamic_data) return NS_OK; @@ -2852,6 +3001,9 @@ static nsresult NSAPI dispex_unlink(void *p) if(This->info->vtbl->unlink) This->info->vtbl->unlink(This); + if(This->jsdisp) + IWineJSDispatch_Unlink(This->jsdisp); + dispex_props_unlink(This); return NS_OK; } @@ -3002,9 +3154,16 @@ static HRESULT prototype_find_dispid(DispatchEx *dispex, const WCHAR *name, DWOR return hres; } +static HRESULT prototype_fill_props(DispatchEx *dispex) +{ + DISPID dispid; + return dispex_get_id(dispex, L"constructor", 0, &dispid); +} + static const dispex_static_data_vtbl_t prototype_dispex_vtbl = { .destructor = prototype_destructor, .find_dispid = prototype_find_dispid, + .fill_props = prototype_fill_props, }; HRESULT get_prototype(HTMLInnerWindow *script_global, prototype_id_t id, DispatchEx **ret) @@ -3094,6 +3253,12 @@ static HRESULT constructor_find_dispid(DispatchEx *dispex, const WCHAR *name, DW return hres; } +static HRESULT constructor_fill_props(DispatchEx *dispex) +{ + DISPID dispid; + return dispex_get_id(dispex, L"prototype", 0, &dispid); +} + static const char *constructor_get_name(DispatchEx *dispex) { struct constructor *constr = constr_from_DispatchEx(dispex); @@ -3103,6 +3268,7 @@ static const char *constructor_get_name(DispatchEx *dispex) static const dispex_static_data_vtbl_t constructor_dispex_vtbl = { .destructor = constructor_destructor, .find_dispid = constructor_find_dispid, + .fill_props = constructor_fill_props, .get_name = constructor_get_name, }; diff --git a/dlls/mshtml/htmlanchor.c b/dlls/mshtml/htmlanchor.c index 6f328b8173cf..15d2c50cf176 100644 --- a/dlls/mshtml/htmlanchor.c +++ b/dlls/mshtml/htmlanchor.c @@ -49,7 +49,7 @@ static HRESULT navigate_href_new_window(HTMLElement *element, nsAString *href_st IUri *uri; HRESULT hres; - if(!element->node.doc->window->base.outer_window) + if(is_detached_window(element->node.doc->window)) return S_OK; nsAString_GetData(href_str, &href); @@ -114,7 +114,7 @@ static HRESULT navigate_href(HTMLElement *element, nsAString *href_str, nsAStrin const PRUnichar *href; HRESULT hres; - if(!element->node.doc->window->base.outer_window) + if(is_detached_window(element->node.doc->window)) return S_OK; window = get_target_window(element->node.doc->window->base.outer_window, target_str, &use_new_window); diff --git a/dlls/mshtml/htmlcurstyle.c b/dlls/mshtml/htmlcurstyle.c index ffccceb2457f..0fd6707be6b7 100644 --- a/dlls/mshtml/htmlcurstyle.c +++ b/dlls/mshtml/htmlcurstyle.c @@ -1201,6 +1201,7 @@ dispex_static_data_t MSCurrentStyleCSSProperties_dispex = { .disp_tid = DispHTMLCurrentStyle_tid, .iface_tids = MSCurrentStyleCSSProperties_iface_tids, .init_info = MSCurrentStyleCSSProperties_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; HRESULT HTMLCurrentStyle_Create(HTMLElement *elem, IHTMLCurrentStyle **p) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 6ae7ccb36e41..7152c1eeb7fd 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -39,6 +39,20 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); +static const WCHAR *const content_type_from_document_type[] = { + [DOCTYPE_HTML] = L"text/html", + [DOCTYPE_XHTML] = L"application/xhtml+xml", + [DOCTYPE_XML] = L"text/xml", + [DOCTYPE_SVG] = L"image/svg+xml", +}; + +static dispex_static_data_t *const dispex_from_document_type[] = { + [DOCTYPE_HTML] = &HTMLDocument_dispex, + [DOCTYPE_XHTML] = &XMLDocument_dispex, + [DOCTYPE_XML] = &XMLDocument_dispex, + [DOCTYPE_SVG] = &XMLDocument_dispex, +}; + static HRESULT create_document_fragment(nsIDOMNode *nsnode, HTMLDocumentNode *doc_node, HTMLDocumentNode **ret); HRESULT get_doc_elem_by_id(HTMLDocumentNode *doc, const WCHAR *id, HTMLElement **ret) @@ -626,21 +640,20 @@ static HRESULT WINAPI HTMLDocument_get_anchors(IHTMLDocument2 *iface, IHTMLEleme return E_UNEXPECTED; } - if(!This->html_document) { - FIXME("Not implemented for XML document\n"); - return E_NOTIMPL; - } + if(This->doc_type == DOCTYPE_XHTML) + FIXME("Not implemented for XHTML Document, returning empty list\n"); - nsres = nsIDOMHTMLDocument_GetAnchors(This->html_document, &nscoll); - if(NS_FAILED(nsres)) { - ERR("GetAnchors failed: %08lx\n", nsres); - return E_FAIL; + if(This->html_document) { + nsres = nsIDOMHTMLDocument_GetAnchors(This->html_document, &nscoll); + if(NS_FAILED(nsres)) { + ERR("GetAnchors failed: %08lx\n", nsres); + return E_FAIL; + } } - if(nscoll) { - *p = create_collection_from_htmlcol(nscoll, &This->node.event_target.dispex); + *p = create_collection_from_htmlcol(nscoll, &This->node.event_target.dispex); + if(nscoll) nsIDOMHTMLCollection_Release(nscoll); - } return S_OK; } @@ -816,7 +829,7 @@ static HRESULT WINAPI HTMLDocument_get_frames(IHTMLDocument2 *iface, IHTMLFrames /* Not implemented by IE */ return E_NOTIMPL; } - if(!This->window->base.outer_window) + if(is_detached_window(This->window)) return E_FAIL; return IHTMLWindow2_get_frames(&This->window->base.outer_window->base.IHTMLWindow2_iface, p); } @@ -1000,7 +1013,7 @@ static HRESULT WINAPI HTMLDocument_put_URL(IHTMLDocument2 *iface, BSTR v) TRACE("(%p)->(%s)\n", This, debugstr_w(v)); - if(!This->window || !This->window->base.outer_window) { + if(!This->window || is_detached_window(This->window)) { FIXME("No window available\n"); return E_FAIL; } @@ -1015,7 +1028,7 @@ static HRESULT WINAPI HTMLDocument_get_URL(IHTMLDocument2 *iface, BSTR *p) TRACE("(%p)->(%p)\n", iface, p); - if(This->window && !This->window->base.outer_window) { + if(This->window && is_detached_window(This->window)) { WARN("detached document\n"); return E_FAIL; } @@ -1064,7 +1077,7 @@ static HRESULT WINAPI HTMLDocument_get_domain(IHTMLDocument2 *iface, BSTR *p) return E_NOTIMPL; } - if(This->window && (!This->window->base.outer_window || !This->window->base.outer_window->uri)) + if(This->window && (is_detached_window(This->window) || !This->window->base.outer_window->uri)) return E_FAIL; nsAString_Init(&nsstr, NULL); @@ -1094,7 +1107,7 @@ static HRESULT WINAPI HTMLDocument_put_cookie(IHTMLDocument2 *iface, BSTR v) if(!This->window) return S_OK; - if(!This->window->base.outer_window) + if(is_detached_window(This->window)) return E_FAIL; bret = InternetSetCookieExW(This->window->base.outer_window->url, NULL, v, 0, 0); @@ -1118,7 +1131,7 @@ static HRESULT WINAPI HTMLDocument_get_cookie(IHTMLDocument2 *iface, BSTR *p) *p = NULL; return S_OK; } - if(!This->window->base.outer_window) + if(is_detached_window(This->window)) return E_FAIL; size = 0; @@ -1206,7 +1219,10 @@ static HRESULT WINAPI HTMLDocument_get_mimeType(IHTMLDocument2 *iface, BSTR *p) *p = NULL; - if(This->window && !This->window->navigation_start_time) + if(!This->window) + return get_mime_type_display_name(content_type_from_document_type[This->doc_type], p); + + if(!This->window->navigation_start_time) return (*p = SysAllocString(L"")) ? S_OK : E_FAIL; nsAString_InitDepend(&nsstr, NULL); @@ -1367,7 +1383,7 @@ static HRESULT WINAPI HTMLDocument_open(IHTMLDocument2 *iface, BSTR url, VARIANT *pomWindowResult = NULL; - if(!This->window || !This->window->base.outer_window) + if(!This->window || is_detached_window(This->window)) return E_FAIL; if(!This->dom_document) { @@ -2224,7 +2240,7 @@ static HRESULT WINAPI HTMLDocument3_get_documentElement(IHTMLDocument3 *iface, I TRACE("(%p)->(%p)\n", This, p); if(This->window) { - if(!This->window->base.outer_window) + if(is_detached_window(This->window)) return E_FAIL; if(This->window->base.outer_window->readystate == READYSTATE_UNINITIALIZED) { *p = NULL; @@ -4493,7 +4509,7 @@ static void HTMLDocumentNode_on_advise(IUnknown *iface, cp_static_data_t *cp) { HTMLDocumentNode *This = CONTAINING_RECORD((IHTMLDocument2*)iface, HTMLDocumentNode, IHTMLDocument2_iface); - if(This->window && This->window->base.outer_window) + if(This->window && !is_detached_window(This->window)) update_doc_cp_events(This, cp); } @@ -5446,7 +5462,7 @@ static HRESULT HTMLDocumentNode_disp_invoke(DispatchEx *dispex, DISPID id, LCID return S_FALSE; } -static HRESULT HTMLDocumentNode_next_dispid(DispatchEx *dispex, DISPID id, DISPID *pid) +static HRESULT HTMLDocumentNode_next_dispid(DispatchEx *dispex, DISPID id, BOOL enum_all_own_props, DISPID *pid) { DWORD idx = (id == DISPID_STARTENUM) ? 0 : id - MSHTML_DISPID_CUSTOM_MIN + 1; HTMLDocumentNode *This = impl_from_DispatchEx(dispex); @@ -5528,10 +5544,15 @@ static HRESULT HTMLDocumentNode_get_prop_desc(DispatchEx *dispex, DISPID id, str desc->name = This->elem_vars[idx]; desc->id = id; desc->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE | PROPF_ENUMERABLE; - desc->iid = 0; + desc->prototype_id = 0; return S_OK; } +static HRESULT HTMLDocumentNode_fill_props(DispatchEx *dispex) +{ + return S_FALSE; +} + static HTMLInnerWindow *HTMLDocumentNode_get_script_global(DispatchEx *dispex, dispex_static_data_t **dispex_data) { HTMLDocumentNode *This = impl_from_DispatchEx(dispex); @@ -5542,7 +5563,7 @@ static HTMLInnerWindow *HTMLDocumentNode_get_script_global(DispatchEx *dispex, d if(This->node.vtbl != &HTMLDocumentNodeImplVtbl) *dispex_data = &DocumentFragment_dispex; else - *dispex_data = This->document_mode < COMPAT_MODE_IE11 ? &Document_dispex : &HTMLDocument_dispex; + *dispex_data = This->document_mode < COMPAT_MODE_IE11 ? &Document_dispex : dispex_from_document_type[This->doc_type]; return This->script_global; } @@ -5589,7 +5610,7 @@ static HRESULT HTMLDocumentNode_location_hook(DispatchEx *dispex, WORD flags, DI if(!(flags & DISPATCH_PROPERTYPUT) || !This->window) return S_FALSE; - if(!This->window->base.outer_window) + if(is_detached_window(This->window)) return E_FAIL; return IWineJSDispatchHost_InvokeEx(&This->window->event_target.dispex.IWineJSDispatchHost_iface, @@ -5640,6 +5661,7 @@ static const event_target_vtbl_t HTMLDocument_event_target_vtbl = { .invoke = HTMLDocumentNode_invoke, .disp_invoke = HTMLDocumentNode_disp_invoke, .next_dispid = HTMLDocumentNode_next_dispid, + .fill_props = HTMLDocumentNode_fill_props, .get_script_global = HTMLDocumentNode_get_script_global, }, .get_gecko_target = HTMLDocumentNode_get_gecko_target, @@ -5764,6 +5786,7 @@ dispex_static_data_t Document_dispex = { .disp_tid = DispHTMLDocument_tid, .iface_tids = HTMLDocumentNode_iface_tids, .init_info = HTMLDocumentNode_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; dispex_static_data_t HTMLDocument_dispex = { @@ -5773,6 +5796,18 @@ dispex_static_data_t HTMLDocument_dispex = { .disp_tid = DispHTMLDocument_tid, .iface_tids = HTMLDocumentNode_iface_tids, .init_info = HTMLDocumentNode_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS, + .min_compat_mode = COMPAT_MODE_IE11, +}; + +dispex_static_data_t XMLDocument_dispex = { + .id = PROT_XMLDocument, + .prototype_id = PROT_Document, + .vtbl = &HTMLDocument_event_target_vtbl.dispex_vtbl, + .disp_tid = DispHTMLDocument_tid, + .iface_tids = HTMLDocumentNode_iface_tids, + .init_info = HTMLDocumentNode_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS, .min_compat_mode = COMPAT_MODE_IE11, }; @@ -5825,7 +5860,7 @@ static HTMLDocumentNode *alloc_doc_node(HTMLDocumentObj *doc_obj, HTMLInnerWindo } HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLInnerWindow *window, - HTMLInnerWindow *script_global, compat_mode_t parent_mode, HTMLDocumentNode **ret) + HTMLInnerWindow *script_global, document_type_t doc_type, compat_mode_t parent_mode, HTMLDocumentNode **ret) { HTMLDocumentObj *doc_obj = browser->doc; HTMLDocumentNode *doc; @@ -5833,6 +5868,7 @@ HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLI doc = alloc_doc_node(doc_obj, window, script_global); if(!doc) return E_OUTOFMEMORY; + doc->doc_type = doc_type; if(parent_mode >= COMPAT_MODE_IE9) { TRACE("using parent mode %u\n", parent_mode); @@ -5852,7 +5888,7 @@ HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLI doc->html_document = NULL; } - HTMLDOMNode_Init(doc, &doc->node, (nsIDOMNode*)doc->dom_document, &HTMLDocument_dispex); + HTMLDOMNode_Init(doc, &doc->node, (nsIDOMNode*)doc->dom_document, dispex_from_document_type[doc_type]); init_document_mutation(doc); doc_init_events(doc); @@ -5906,6 +5942,7 @@ dispex_static_data_t DocumentFragment_dispex = { .disp_tid = DispHTMLDocument_tid, .iface_tids = DocumentFragment_iface_tids, .init_info = DocumentFragment_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; static HRESULT create_document_fragment(nsIDOMNode *nsnode, HTMLDocumentNode *doc_node, HTMLDocumentNode **ret) diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index fcd8c969a015..a04dfbb70735 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -1129,6 +1129,7 @@ dispex_static_data_t ClientRectList_dispex = { .vtbl = &HTMLRectCollection_dispex_vtbl, .disp_tid = IHTMLRectCollection_tid, .iface_tids = ClientRectList_iface_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; DISPEX_IDISPATCH_IMPL(HTMLElement, IHTMLElement, @@ -7211,6 +7212,7 @@ dispex_static_data_t DOMTokenList_dispex = { .vtbl = &token_list_dispex_vtbl, .disp_tid = IWineDOMTokenList_tid, .iface_tids = DOMTokenList_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS, .min_compat_mode = COMPAT_MODE_IE10, }; @@ -7394,6 +7396,8 @@ static void Element_init_dispex_info(dispex_data_t *info, compat_mode_t mode) DISPID_UNKNOWN }; + HTMLDOMNode_init_dispex_info(info, mode); + dispex_info_add_dispids(info, IHTMLElement2_tid, elem2_dispids); dispex_info_add_dispids(info, IHTMLElement6_tid, elem6_dispids); if(mode >= COMPAT_MODE_IE10) { @@ -7412,6 +7416,7 @@ static void Element_init_dispex_info(dispex_data_t *info, compat_mode_t mode) dispex_static_data_t Element_dispex = { .id = PROT_Element, .prototype_id = PROT_Node, + .vtbl = &HTMLElement_event_target_vtbl.dispex_vtbl, .init_info = Element_init_dispex_info, }; @@ -7468,6 +7473,8 @@ void HTMLElement_Init(HTMLElement *This, HTMLDocumentNode *doc, nsIDOMElement *n HRESULT HTMLElement_Create(HTMLDocumentNode *doc, nsIDOMNode *nsnode, BOOL use_generic, HTMLElement **ret) { + nsIDOMHTMLElement *nshtmlelem; + nsIDOMSVGElement *svg_element; nsIDOMElement *nselem; nsAString tag_name_str; const PRUnichar *tag_name; @@ -7487,17 +7494,32 @@ HRESULT HTMLElement_Create(HTMLDocumentNode *doc, nsIDOMNode *nsnode, BOOL use_g nsAString_GetData(&tag_name_str, &tag_name); + /* Check this first, as Gecko treats svg elements as non-HTML */ + nsres = nsIDOMElement_QueryInterface(nselem, &IID_nsIDOMSVGElement, (void**)&svg_element); + if(NS_SUCCEEDED(nsres)) { + hres = create_svg_element(doc, svg_element, tag_name, &elem); + nsIDOMSVGElement_Release(svg_element); + goto done; + } + + nsres = nsIDOMElement_QueryInterface(nselem, &IID_nsIDOMHTMLElement, (void**)&nshtmlelem); + if(NS_FAILED(nsres)) { + if(!(elem = calloc(1, sizeof(HTMLElement)))) + hres = E_OUTOFMEMORY; + else { + elem->node.vtbl = &HTMLElementImplVtbl; + HTMLElement_Init(elem, doc, nselem, &Element_dispex); + hres = S_OK; + } + goto done; + } + nsIDOMHTMLElement_Release(nshtmlelem); + tag = get_tag_desc(tag_name); if(tag) { hres = tag->constructor(doc, nselem, &elem); }else { - nsIDOMSVGElement *svg_element; - - nsres = nsIDOMElement_QueryInterface(nselem, &IID_nsIDOMSVGElement, (void**)&svg_element); - if(NS_SUCCEEDED(nsres)) { - hres = create_svg_element(doc, svg_element, tag_name, &elem); - nsIDOMSVGElement_Release(svg_element); - }else if(use_generic || dispex_compat_mode(&doc->node.event_target.dispex) >= COMPAT_MODE_IE9) { + if(use_generic || dispex_compat_mode(&doc->node.event_target.dispex) >= COMPAT_MODE_IE9) { hres = HTMLGenericElement_Create(doc, nselem, &elem); }else { elem = calloc(1, sizeof(HTMLElement)); @@ -7511,6 +7533,7 @@ HRESULT HTMLElement_Create(HTMLDocumentNode *doc, nsIDOMNode *nsnode, BOOL use_g } } +done: TRACE("%s ret %p\n", debugstr_w(tag_name), elem); nsIDOMElement_Release(nselem); @@ -8268,6 +8291,7 @@ dispex_static_data_t NamedNodeMap_dispex = { .vtbl = &HTMLAttributeCollection_dispex_vtbl, .disp_tid = DispHTMLAttributeCollection_tid, .iface_tids = NamedNodeMap_iface_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; HRESULT HTMLElement_get_attr_col(HTMLDOMNode *iface, HTMLAttributeCollection **ac) diff --git a/dlls/mshtml/htmlelemcol.c b/dlls/mshtml/htmlelemcol.c index dd7ffeea2222..fe36dd31063e 100644 --- a/dlls/mshtml/htmlelemcol.c +++ b/dlls/mshtml/htmlelemcol.c @@ -579,6 +579,7 @@ dispex_static_data_t HTMLCollection_dispex = { .vtbl = &HTMLElementColection_dispex_vtbl, .disp_tid = DispHTMLElementCollection_tid, .iface_tids = HTMLCollection_iface_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; static void create_all_list(HTMLDOMNode *elem, elem_vector_t *buf) diff --git a/dlls/mshtml/htmlform.c b/dlls/mshtml/htmlform.c index 153133493f67..f5f50f9258fb 100644 --- a/dlls/mshtml/htmlform.c +++ b/dlls/mshtml/htmlform.c @@ -519,7 +519,7 @@ static HRESULT WINAPI HTMLFormElement_submit(IHTMLFormElement *iface) if(This->element.node.doc) { HTMLDocumentNode *doc = This->element.node.doc; - if(doc->window && doc->window->base.outer_window) + if(doc->window && !is_detached_window(doc->window)) this_window = doc->window->base.outer_window; } if(!this_window) { @@ -868,6 +868,31 @@ static HRESULT HTMLFormElement_invoke(DispatchEx *dispex, DISPID id, LCID lcid, return S_OK; } +static HRESULT HTMLFormElement_override(DispatchEx *dispex, const WCHAR *name, VARIANT *get_value) +{ + HTMLFormElement *This = impl_from_DispatchEx(dispex); + IDispatch *ret; + HRESULT hres; + DISPID id; + + if(get_value) { + hres = HTMLFormElement_get_dispid(&This->element.node.event_target.dispex, (WCHAR*)name, 0, &id); + if(FAILED(hres)) + return (hres == DISP_E_UNKNOWNNAME) ? S_FALSE : hres; + hres = htmlform_item(This, id - MSHTML_DISPID_CUSTOM_MIN, &ret); + if(FAILED(hres)) + return hres; + if(ret) { + V_VT(get_value) = VT_DISPATCH; + V_DISPATCH(get_value) = ret; + }else { + V_VT(get_value) = VT_NULL; + } + } + + return S_OK; +} + static HRESULT HTMLFormElement_handle_event(DispatchEx *dispex, DOMEvent *event, BOOL *prevent_default) { HTMLFormElement *This = impl_from_DispatchEx(dispex); @@ -896,7 +921,8 @@ static const event_target_vtbl_t HTMLFormElement_event_target_vtbl = { .unlink = HTMLFormElement_unlink, .get_dispid = HTMLFormElement_get_dispid, .get_prop_desc = dispex_index_prop_desc, - .invoke = HTMLFormElement_invoke + .invoke = HTMLFormElement_invoke, + .override = HTMLFormElement_override, }, HTMLELEMENT_EVENT_TARGET_VTBL_ENTRIES, .handle_event = HTMLFormElement_handle_event @@ -914,6 +940,7 @@ dispex_static_data_t HTMLFormElement_dispex = { .disp_tid = DispHTMLFormElement_tid, .iface_tids = HTMLFormElement_iface_tids, .init_info = HTMLElement_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; HRESULT HTMLFormElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlframe.c b/dlls/mshtml/htmlframe.c index 193be9f63232..09cae4f42ee7 100644 --- a/dlls/mshtml/htmlframe.c +++ b/dlls/mshtml/htmlframe.c @@ -79,7 +79,7 @@ static HRESULT WINAPI HTMLFrameBase_put_src(IHTMLFrameBase *iface, BSTR v) TRACE("(%p)->(%s)\n", This, debugstr_w(v)); - if(!This->content_window || !This->element.node.doc || !This->element.node.doc->window || !This->element.node.doc->window->base.outer_window) { + if(!This->content_window || !This->element.node.doc || !This->element.node.doc->window || is_detached_window(This->element.node.doc->window)) { nsAString nsstr; nsresult nsres; @@ -934,6 +934,7 @@ dispex_static_data_t HTMLFrameElement_dispex = { .disp_tid = DispHTMLFrameElement_tid, .iface_tids = HTMLFrameElement_iface_tids, .init_info = HTMLElement_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; HRESULT HTMLFrameElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -1371,6 +1372,7 @@ dispex_static_data_t HTMLIFrameElement_dispex = { .disp_tid = DispHTMLIFrame_tid, .iface_tids = HTMLIFrameElement_iface_tids, .init_info = HTMLElement_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; HRESULT HTMLIFrame_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index f6a4b992ab62..a194737aa704 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -864,10 +864,11 @@ static HRESULT HTMLImageElementFactory_value(DispatchEx *dispex, LCID lcid, return S_OK; } -static const tid_t HTMLImageElementFactory_iface_tids[] = { - IHTMLImageElementFactory_tid, - 0 -}; +static void HTMLImageElementFactory_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + if(mode < COMPAT_MODE_IE9) + dispex_info_add_interface(info, IHTMLImageElementFactory_tid, NULL); +} static const dispex_static_data_vtbl_t HTMLImageElementFactory_dispex_vtbl = { .query_interface = HTMLImageElementFactory_query_interface, @@ -882,10 +883,10 @@ static dispex_static_data_t HTMLImageElementFactory_dispex = { .constructor_id = PROT_HTMLImageElement, .vtbl = &HTMLImageElementFactory_dispex_vtbl, .disp_tid = IHTMLImageElementFactory_tid, - .iface_tids = HTMLImageElementFactory_iface_tids, + .init_info = HTMLImageElementFactory_init_dispex_info, }; -HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow *window, HTMLImageElementFactory **ret_val) +HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow *window, DispatchEx **ret_val) { HTMLImageElementFactory *ret; @@ -900,6 +901,6 @@ HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow *window, HTMLImageElement init_dispatch(&ret->dispex, &HTMLImageElementFactory_dispex, window, dispex_compat_mode(&window->event_target.dispex)); - *ret_val = ret; + *ret_val = &ret->dispex; return S_OK; } diff --git a/dlls/mshtml/htmlnode.c b/dlls/mshtml/htmlnode.c index c39159d9b43d..196c600a631f 100644 --- a/dlls/mshtml/htmlnode.c +++ b/dlls/mshtml/htmlnode.c @@ -390,6 +390,7 @@ dispex_static_data_t NodeList_dispex = { .disp_tid = DispDOMChildrenCollection_tid, .iface_tids = NodeList_iface_tids, .init_info = HTMLDOMNode_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; HRESULT create_child_collection(nsIDOMNodeList *nslist, DispatchEx *owner, IHTMLDOMChildrenCollection **ret) diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index 2d02589db382..8801e90edeed 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -510,10 +510,11 @@ static HRESULT HTMLOptionElementFactory_value(DispatchEx *dispex, LCID lcid, return S_OK; } -static const tid_t HTMLOptionElementFactory_iface_tids[] = { - IHTMLOptionElementFactory_tid, - 0 -}; +static void HTMLImageElementFactory_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + if(mode < COMPAT_MODE_IE9) + dispex_info_add_interface(info, IHTMLOptionElementFactory_tid, NULL); +} static const dispex_static_data_vtbl_t HTMLOptionElementFactory_dispex_vtbl = { .query_interface = HTMLOptionElementFactory_query_interface, @@ -528,10 +529,10 @@ static dispex_static_data_t HTMLOptionElementFactory_dispex = { .constructor_id = PROT_HTMLOptionElement, .vtbl = &HTMLOptionElementFactory_dispex_vtbl, .disp_tid = IHTMLOptionElementFactory_tid, - .iface_tids = HTMLOptionElementFactory_iface_tids, + .init_info = HTMLImageElementFactory_init_dispex_info, }; -HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow *window, HTMLOptionElementFactory **ret_ptr) +HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow *window, DispatchEx **ret_ptr) { HTMLOptionElementFactory *ret; @@ -546,7 +547,7 @@ HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow *window, HTMLOptionEleme init_dispatch(&ret->dispex, &HTMLOptionElementFactory_dispex, window, dispex_compat_mode(&window->event_target.dispex)); - *ret_ptr = ret; + *ret_ptr = &ret->dispex; return S_OK; } @@ -1304,6 +1305,7 @@ dispex_static_data_t HTMLSelectElement_dispex = { .disp_tid = DispHTMLSelectElement_tid, .iface_tids = HTMLSelectElement_tids, .init_info = HTMLElement_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; HRESULT HTMLSelectElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c index 8fb5679089a9..6f2d842852bc 100644 --- a/dlls/mshtml/htmlstorage.c +++ b/dlls/mshtml/htmlstorage.c @@ -332,7 +332,6 @@ static HRESULT send_storage_event(HTMLStorage *storage, BSTR key, BSTR old_value ctx.url = NULL; - /* FIXME: Events are actually sent to the current window on native, even if we're detached. */ if(!window->base.outer_window) goto done; @@ -1180,7 +1179,7 @@ static HRESULT HTMLStorage_delete(DispatchEx *dispex, DISPID id) return HTMLStorage_removeItem(&This->IHTMLStorage_iface, This->props[idx]); } -static HRESULT HTMLStorage_next_dispid(DispatchEx *dispex, DISPID id, DISPID *pid) +static HRESULT HTMLStorage_next_dispid(DispatchEx *dispex, DISPID id, BOOL enum_all_own_props, DISPID *pid) { DWORD idx = (id == DISPID_STARTENUM) ? 0 : id - MSHTML_DISPID_CUSTOM_MIN + 1; HTMLStorage *This = impl_from_DispatchEx(dispex); @@ -1274,10 +1273,38 @@ static HRESULT HTMLStorage_get_prop_desc(DispatchEx *dispex, DISPID id, struct p desc->name = This->props[id - MSHTML_DISPID_CUSTOM_MIN]; desc->id = id; desc->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE | PROPF_ENUMERABLE; - desc->iid = 0; + desc->prototype_id = 0; return S_OK; } +static HRESULT HTMLStorage_override(DispatchEx *dispex, const WCHAR *name, VARIANT *get_value) +{ + HTMLStorage *This = impl_from_DispatchEx(dispex); + BSTR bstrName; + HRESULT hres; + + if(!(bstrName = SysAllocString(name))) + return E_OUTOFMEMORY; + + if(get_value) { + hres = HTMLStorage_getItem(&This->IHTMLStorage_iface, bstrName, get_value); + if(SUCCEEDED(hres)) + hres = (V_VT(get_value) != VT_NULL) ? S_OK : S_FALSE; + }else { + hres = HTMLStorage_removeItem(&This->IHTMLStorage_iface, bstrName); + if(SUCCEEDED(hres)) + hres = S_OK; + } + + SysFreeString(bstrName); + return hres; +} + +static HRESULT HTMLStorage_fill_props(DispatchEx *dispex) +{ + return S_FALSE; +} + static const dispex_static_data_vtbl_t Storage_dispex_vtbl = { .query_interface = HTMLStorage_query_interface, .destructor = HTMLStorage_destructor, @@ -1288,6 +1315,8 @@ static const dispex_static_data_vtbl_t Storage_dispex_vtbl = { .delete = HTMLStorage_delete, .next_dispid = HTMLStorage_next_dispid, .get_prop_desc = HTMLStorage_get_prop_desc, + .override = HTMLStorage_override, + .fill_props = HTMLStorage_fill_props, }; static const tid_t HTMLStorage_iface_tids[] = { @@ -1299,6 +1328,7 @@ dispex_static_data_t Storage_dispex = { .vtbl = &Storage_dispex_vtbl, .disp_tid = IHTMLStorage_tid, .iface_tids = HTMLStorage_iface_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; static HRESULT build_session_origin(IUri *uri, BSTR hostname, BSTR *ret) diff --git a/dlls/mshtml/htmlstyle.c b/dlls/mshtml/htmlstyle.c index 36d685bf3d19..e800b40ebbf5 100644 --- a/dlls/mshtml/htmlstyle.c +++ b/dlls/mshtml/htmlstyle.c @@ -2889,13 +2889,12 @@ static HRESULT WINAPI HTMLStyle_setAttribute(IHTMLStyle *iface, BSTR strAttribut if(hres == S_OK) { VARIANT ret; - DISPID dispidNamed = DISPID_PROPERTYPUT; DISPPARAMS params; params.cArgs = 1; params.rgvarg = &AttributeValue; params.cNamedArgs = 1; - params.rgdispidNamedArgs = &dispidNamed; + params.rgdispidNamedArgs = &propput_dispid; hres = HTMLStyle_Invoke(iface, dispid, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, &ret, NULL, NULL); @@ -9778,6 +9777,7 @@ dispex_static_data_t MSStyleCSSProperties_dispex = { .disp_tid = DispHTMLStyle_tid, .iface_tids = MSStyleCSSProperties_iface_tids, .init_info = MSStyleCSSProperties_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; static HRESULT get_style_from_elem(HTMLElement *elem, nsIDOMCSSStyleDeclaration **ret) @@ -9922,6 +9922,7 @@ dispex_static_data_t CSSStyleDeclaration_dispex = { .vtbl = &CSSStyleDeclaration_dispex_vtbl, .disp_tid = DispHTMLW3CComputedStyle_tid, .init_info = CSSStyleDeclaration_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; HRESULT create_computed_style(nsIDOMCSSStyleDeclaration *nsstyle, DispatchEx *owner, IHTMLCSSStyleDeclaration **p) diff --git a/dlls/mshtml/htmlstylesheet.c b/dlls/mshtml/htmlstylesheet.c index 4b9cc3f56a65..e463a50fa82d 100644 --- a/dlls/mshtml/htmlstylesheet.c +++ b/dlls/mshtml/htmlstylesheet.c @@ -377,6 +377,7 @@ dispex_static_data_t MSCSSRuleList_dispex = { .vtbl = &MSCSSRuleList_dispex_vtbl, .disp_tid = DispHTMLStyleSheetRulesCollection_tid, .iface_tids = MSCSSRuleList_iface_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; static HRESULT create_style_sheet_rules_collection(nsIDOMCSSRuleList *nslist, DispatchEx *owner, @@ -739,6 +740,7 @@ dispex_static_data_t StyleSheetList_dispex = { .vtbl = &StyleSheetList_dispex_vtbl, .disp_tid = DispHTMLStyleSheetsCollection_tid, .iface_tids = StyleSheetList_iface_tids, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; HRESULT create_style_sheet_collection(nsIDOMStyleSheetList *nslist, HTMLDocumentNode *doc, @@ -950,17 +952,48 @@ static HRESULT WINAPI HTMLStyleSheet_put_cssText(IHTMLStyleSheet *iface, BSTR v) }while(NS_SUCCEEDED(nsres)); if(v && *v) { + UINT32 i, depth, idx; nsAString nsstr; - UINT32 idx; - - /* FIXME: This won't work for multiple rules in the string. */ - nsAString_InitDepend(&nsstr, v); - nsres = nsIDOMCSSStyleSheet_InsertRule(This->nsstylesheet, &nsstr, 0, &idx); - nsAString_Finish(&nsstr); - if(NS_FAILED(nsres)) { - FIXME("InsertRule failed for string %s. Probably multiple rules passed.\n", debugstr_w(v)); - return E_FAIL; + WCHAR *ws; + + depth = 0; + ws = malloc(sizeof(*ws) * (lstrlenW(v) + 1)); + do + { + for (i = 0; v[i]; ++i) + { + ws[i] = v[i]; + if (ws[i] == '{') + ++depth; + else if (ws[i] == '}' && !--depth) + break; + } + if (ws[i]) + ws[++i] = 0; + + v += i; + + for (i = 0; ws[i]; ++i) + if (!iswspace(ws[i])) + break; + + if (!ws[i]) + { + TRACE("Skipping empty part.\n"); + continue; + } + + nsAString_InitDepend(&nsstr, ws); + nsres = nsIDOMCSSStyleSheet_InsertRule(This->nsstylesheet, &nsstr, 0, &idx); + nsAString_Finish(&nsstr); + + if(NS_FAILED(nsres)) + FIXME("InsertRule failed for string %s.\n", debugstr_w(ws)); + else + TRACE("Added rule %s.\n", debugstr_w(ws)); } + while (*v); + free(ws); } return S_OK; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 31255e7cebce..12a41f2d68f2 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -65,6 +65,22 @@ HTMLOuterWindow *mozwindow_to_window(const mozIDOMWindowProxy *mozwindow) return entry ? WINE_RB_ENTRY_VALUE(entry, HTMLOuterWindow, entry) : NULL; } +void __cdecl cc_api_collect(void) +{ + nsIDOMWindowUtils *window_utils = NULL; + HTMLOuterWindow *window; + + /* We can't rely on GetScriptGlobal as this can be initialized before any scripts are set up */ + if(!window_map.root || !(window = WINE_RB_ENTRY_VALUE(window_map.root, HTMLOuterWindow, entry))->browser) + return; + get_nsinterface((nsISupports*)window->browser->content_window->nswindow, &IID_nsIDOMWindowUtils, (void**)&window_utils); + + if(window_utils) { + cycle_collect(window_utils); + nsIDOMWindowUtils_Release(window_utils); + } +} + static HRESULT get_location(HTMLOuterWindow *This, HTMLLocation **ret) { if(!This->location) { @@ -111,6 +127,10 @@ static void detach_inner_window(HTMLInnerWindow *window) HTMLOuterWindow *outer_window = window->base.outer_window; HTMLDocumentNode *doc = window->doc, *doc_iter; + /* Check if already detached */ + if(!list_empty(&window->outer_window_entry)) + return; + while(!list_empty(&window->children)) { HTMLOuterWindow *child = LIST_ENTRY(list_tail(&window->children), HTMLOuterWindow, sibling_entry); @@ -128,6 +148,7 @@ static void detach_inner_window(HTMLInnerWindow *window) LIST_FOR_EACH_ENTRY(doc_iter, &window->documents, HTMLDocumentNode, script_global_entry) doc_iter->script_global = NULL; + list_init(&window->documents); if(doc) detach_document_node(doc); @@ -137,11 +158,13 @@ static void detach_inner_window(HTMLInnerWindow *window) abort_window_bindings(window); release_script_hosts(window); unlink_ref(&window->jscript); - window->base.outer_window = NULL; - if(outer_window && outer_window->base.inner_window == window) { - outer_window->base.inner_window = NULL; - IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); + if(outer_window) { + list_add_tail(&outer_window->detached_inner_windows, &window->outer_window_entry); + if(outer_window->base.inner_window == window) { + outer_window->base.inner_window = NULL; + IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); + } } } @@ -676,18 +699,13 @@ static HRESULT WINAPI HTMLWindow2_get_Image(IHTMLWindow2 *iface, IHTMLImageEleme TRACE("(%p)->(%p)\n", This, p); - if(!window->image_factory) { - HRESULT hres; - - hres = HTMLImageElementFactory_Create(window, &window->image_factory); + if(!window->constructors[CTOR_IMAGE]) { + HRESULT hres = HTMLImageElementFactory_Create(window, &window->constructors[CTOR_IMAGE]); if(FAILED(hres)) return hres; } - *p = &window->image_factory->IHTMLImageElementFactory_iface; - IHTMLImageElementFactory_AddRef(*p); - - return S_OK; + return IWineJSDispatchHost_QueryInterface(&window->constructors[CTOR_IMAGE]->IWineJSDispatchHost_iface, &IID_IHTMLImageElementFactory, (void**)p); } static HRESULT WINAPI HTMLWindow2_get_location(IHTMLWindow2 *iface, IHTMLLocation **p) @@ -1234,18 +1252,13 @@ static HRESULT WINAPI HTMLWindow2_get_Option(IHTMLWindow2 *iface, IHTMLOptionEle TRACE("(%p)->(%p)\n", This, p); - if(!window->option_factory) { - HRESULT hres; - - hres = HTMLOptionElementFactory_Create(window, &window->option_factory); + if(!window->constructors[CTOR_OPTION]) { + HRESULT hres = HTMLOptionElementFactory_Create(window, &window->constructors[CTOR_OPTION]); if(FAILED(hres)) return hres; } - *p = &window->option_factory->IHTMLOptionElementFactory_iface; - IHTMLOptionElementFactory_AddRef(*p); - - return S_OK; + return IWineJSDispatchHost_QueryInterface(&window->constructors[CTOR_OPTION]->IWineJSDispatchHost_iface, &IID_IHTMLOptionElementFactory, (void**)p); } static HRESULT WINAPI HTMLWindow2_focus(IHTMLWindow2 *iface) @@ -1986,8 +1999,28 @@ static HRESULT WINAPI HTMLWindow6_put_XDomainRequest(IHTMLWindow6 *iface, VARIAN static HRESULT WINAPI HTMLWindow6_get_XDomainRequest(IHTMLWindow6 *iface, VARIANT *p) { HTMLWindow *This = impl_from_IHTMLWindow6(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + HTMLInnerWindow *window = This->inner_window; + + TRACE("(%p)->(%p)\n", This, p); + + if(This->outer_window->readystate == READYSTATE_UNINITIALIZED) { + V_VT(p) = VT_EMPTY; + return S_OK; + } + + if(!window->constructors[PROT_XDomainRequest]) { + HRESULT hres; + + hres = HTMLXDomainRequestFactory_Create(window, &window->constructors[PROT_XDomainRequest]); + if(FAILED(hres)) + return hres; + } + + V_VT(p) = VT_DISPATCH; + V_DISPATCH(p) = (IDispatch*)&window->constructors[PROT_XDomainRequest]->IWineJSDispatchHost_iface; + IDispatch_AddRef(V_DISPATCH(p)); + + return S_OK; } static HRESULT WINAPI HTMLWindow6_get_sessionStorage(IHTMLWindow6 *iface, IHTMLStorage **p) @@ -3184,6 +3217,24 @@ static HRESULT WINAPI window_private_get_console(IWineHTMLWindowPrivate *iface, return S_OK; } +static HRESULT WINAPI window_private_get_msCrypto(IWineHTMLWindowPrivate *iface, IDispatch **crypto) +{ + HTMLInnerWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface)->inner_window; + + TRACE("iface %p, crypto %p.\n", iface, crypto); + + if(!This->crypto) { + HRESULT hres = create_crypto(This, &This->crypto); + if(FAILED(hres)) + return hres; + } + + *crypto = (IDispatch*)This->crypto; + if(This->crypto) + IWineMSHTMLCrypto_AddRef(This->crypto); + return S_OK; +} + static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = { window_private_QueryInterface, window_private_AddRef, @@ -3196,6 +3247,7 @@ static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = { window_private_cancelAnimationFrame, window_private_get_console, window_private_matchMedia, + window_private_get_msCrypto, }; static inline HTMLWindow *impl_from_IWineHTMLWindowCompatPrivateVtbl(IWineHTMLWindowCompatPrivate *iface) @@ -3451,12 +3503,17 @@ static HRESULT WINAPI WindowDispEx_LookupProperty(IWineJSDispatchHost *iface, co name, flags, desc); } -static HRESULT WINAPI WindowDispEx_NextProperty(IWineJSDispatchHost *iface, DISPID id, struct property_info *desc) +static HRESULT WINAPI WindowDispEx_OverrideProperty(IWineJSDispatchHost *iface, const WCHAR *name, + struct property_info *get_desc, VARIANT *get_value) +{ + return S_FALSE; +} + +static HRESULT WINAPI WindowDispEx_FillProperties(IWineJSDispatchHost *iface) { HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface); - return IWineJSDispatchHost_NextProperty(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, - id, desc); + return IWineJSDispatchHost_FillProperties(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface); } static HRESULT WINAPI WindowDispEx_GetProperty(IWineJSDispatchHost *iface, DISPID id, LCID lcid, VARIANT *r, @@ -3491,13 +3548,13 @@ static HRESULT WINAPI WindowDispEx_ConfigureProperty(IWineJSDispatchHost *iface, return IWineJSDispatchHost_ConfigureProperty(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, id, flags); } -static HRESULT WINAPI WindowDispEx_CallFunction(IWineJSDispatchHost *iface, DISPID id, UINT32 iid, DWORD flags, DISPPARAMS *dp, - VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT WINAPI WindowDispEx_CallFunction(IWineJSDispatchHost *iface, DISPID id, INT32 prototype_id, DWORD flags, + DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller) { HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface); return IWineJSDispatchHost_CallFunction(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, - id, iid, flags, dp, ret, ei, caller); + id, prototype_id, flags, dp, ret, ei, caller); } static HRESULT WINAPI WindowDispEx_Construct(IWineJSDispatchHost *iface, LCID lcid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, @@ -3525,6 +3582,13 @@ static HRESULT WINAPI WindowDispEx_ToString(IWineJSDispatchHost *iface, BSTR *st return IWineJSDispatchHost_ToString(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, str); } +static void WINAPI WindowDispEx_InitCC(IWineJSDispatchHost *iface, struct jshost_cc_api *cc_api, const CCObjCallback *callback) +{ + HTMLOuterWindow *This = impl_from_IWineJSDispatchHost(iface); + + IWineJSDispatchHost_InitCC(&This->base.inner_window->event_target.dispex.IWineJSDispatchHost_iface, cc_api, callback); +} + static const IWineJSDispatchHostVtbl WindowDispExVtbl = { WindowDispEx_QueryInterface, WindowDispEx_AddRef, @@ -3543,15 +3607,17 @@ static const IWineJSDispatchHostVtbl WindowDispExVtbl = { WindowDispEx_GetNameSpaceParent, WindowDispEx_GetJSDispatch, WindowDispEx_LookupProperty, - WindowDispEx_NextProperty, + WindowDispEx_OverrideProperty, WindowDispEx_GetProperty, WindowDispEx_SetProperty, WindowDispEx_DeleteProperty, WindowDispEx_ConfigureProperty, WindowDispEx_CallFunction, WindowDispEx_Construct, + WindowDispEx_FillProperties, WindowDispEx_GetOuterDispatch, WindowDispEx_ToString, + WindowDispEx_InitCC }; static inline HTMLOuterWindow *impl_from_IEventTarget(IEventTarget *iface) @@ -3700,10 +3766,6 @@ static void HTMLWindow_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCa note_cc_edge((nsISupports*)&This->doc->node.IHTMLDOMNode_iface, "doc", cb); if(This->console) note_cc_edge((nsISupports*)This->console, "console", cb); - if(This->image_factory) - note_cc_edge((nsISupports*)&This->image_factory->IHTMLImageElementFactory_iface, "image_factory", cb); - if(This->option_factory) - note_cc_edge((nsISupports*)&This->option_factory->IHTMLOptionElementFactory_iface, "option_factory", cb); if(This->screen) note_cc_edge((nsISupports*)This->screen, "screen", cb); if(This->history) @@ -3714,6 +3776,8 @@ static void HTMLWindow_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCa note_cc_edge((nsISupports*)This->session_storage, "session_storage", cb); if(This->local_storage) note_cc_edge((nsISupports*)This->local_storage, "local_storage", cb); + if(This->crypto) + note_cc_edge((nsISupports*)This->crypto, "crypto", cb); if(This->dom_window) note_cc_edge((nsISupports*)This->dom_window, "dom_window", cb); traverse_variant(&This->performance, "performance", cb); @@ -3742,16 +3806,6 @@ static void HTMLWindow_unlink(DispatchEx *dispex) release_event_target(&This->event_target); - if(This->image_factory) { - HTMLImageElementFactory *image_factory = This->image_factory; - This->image_factory = NULL; - IHTMLImageElementFactory_Release(&image_factory->IHTMLImageElementFactory_iface); - } - if(This->option_factory) { - HTMLOptionElementFactory *option_factory = This->option_factory; - This->option_factory = NULL; - IHTMLOptionElementFactory_Release(&option_factory->IHTMLOptionElementFactory_iface); - } unlink_ref(&This->screen); if(This->history) { OmHistory *history = This->history; @@ -3769,6 +3823,11 @@ static void HTMLWindow_unlink(DispatchEx *dispex) This->local_storage = NULL; IHTMLStorage_Release(local_storage); } + if(This->crypto) { + IWineMSHTMLCrypto *crypto = This->crypto; + This->crypto = NULL; + IWineMSHTMLCrypto_Release(crypto); + } unlink_variant(&This->performance); unlink_ref(&This->dom_window); } @@ -3778,6 +3837,7 @@ static void HTMLWindow_destructor(DispatchEx *dispex) HTMLInnerWindow *This = impl_from_DispatchEx(dispex); unsigned i; + list_remove(&This->outer_window_entry); VariantClear(&This->performance); for(i = 0; i < This->global_prop_cnt; i++) @@ -3825,23 +3885,44 @@ static HRESULT HTMLWindow_find_dispid(DispatchEx *dispex, const WCHAR *name, DWO if(dispex_compat_mode(dispex) >= COMPAT_MODE_IE9) { const WCHAR **constr_name = bsearch(&name, constructor_names, ARRAYSIZE(constructor_names) , sizeof(constructor_names[0]), cmp_name); + DispatchEx *constr = NULL; + if(constr_name) { prototype_id_t id = constr_name - constructor_names + 1; compat_mode_t compat_mode = dispex_compat_mode(dispex); - DispatchEx *constr; - VARIANT v; if(compat_mode >= object_descriptors[id]->min_compat_mode && (!object_descriptors[id]->max_compat_mode || compat_mode <= object_descriptors[id]->max_compat_mode)) { hres = get_constructor(This, id, &constr); if(FAILED(hres)) return hres; - - V_VT(&v) = VT_DISPATCH; - V_DISPATCH(&v) = (IDispatch *)&constr->IWineJSDispatchHost_iface; - return dispex_define_property(&This->event_target.dispex, name, PROPF_WRITABLE | PROPF_CONFIGURABLE, &v, dispid); + } + }else { + if(!wcscmp(name, L"Image")) { + if(!This->constructors[CTOR_IMAGE]) { + hres = HTMLImageElementFactory_Create(This, &This->constructors[CTOR_IMAGE]); + if(FAILED(hres)) + return hres; + } + constr = This->constructors[CTOR_IMAGE]; + }else if(!wcscmp(name, L"Option")) { + if(!This->constructors[CTOR_OPTION]) { + hres = HTMLOptionElementFactory_Create(This, &This->constructors[CTOR_OPTION]); + if(FAILED(hres)) + return hres; + } + constr = This->constructors[CTOR_OPTION]; } } + + if(constr) { + VARIANT v; + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch *)&constr->IWineJSDispatchHost_iface; + hres = dispex_define_property(&This->event_target.dispex, name, PROPF_WRITABLE | PROPF_CONFIGURABLE, &v, dispid); + if(hres != DISP_E_UNKNOWNNAME) + return hres; + } } hres = get_frame_by_name(This->base.outer_window, name, FALSE, &frame); @@ -4012,12 +4093,13 @@ static HRESULT HTMLWindow_delete(DispatchEx *dispex, DISPID id) return hres; } -static HRESULT HTMLWindow_next_dispid(DispatchEx *dispex, DISPID id, DISPID *pid) +static HRESULT HTMLWindow_next_dispid(DispatchEx *dispex, DISPID id, BOOL enum_all_own_props, DISPID *pid) { DWORD idx = (id == DISPID_STARTENUM) ? 0 : id - MSHTML_DISPID_CUSTOM_MIN + 1; HTMLInnerWindow *This = impl_from_DispatchEx(dispex); - while(idx < This->global_prop_cnt && This->global_props[idx].type != GLOBAL_DISPEXVAR) + while(idx < This->global_prop_cnt && This->global_props[idx].type != GLOBAL_DISPEXVAR && + (!enum_all_own_props || This->global_props[idx].type != GLOBAL_SCRIPTVAR || global_prop_still_exists(This, &This->global_props[idx]) != S_OK)) idx++; if(idx >= This->global_prop_cnt) return S_FALSE; @@ -4040,7 +4122,7 @@ HRESULT HTMLWindow_get_prop_desc(DispatchEx *dispex, DISPID id, struct property_ desc->name = prop->name; desc->id = id; desc->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE; - desc->iid = 0; + desc->prototype_id = 0; switch(prop->type) { case GLOBAL_SCRIPTVAR: { @@ -4058,6 +4140,36 @@ HRESULT HTMLWindow_get_prop_desc(DispatchEx *dispex, DISPID id, struct property_ return hres; } +static HRESULT HTMLWindow_fill_props(DispatchEx *dispex) +{ + HTMLInnerWindow *This = impl_from_DispatchEx(dispex); + DISPID dispid; + HRESULT hres; + unsigned i; + + if(!This->static_props_filled) { + hres = dispex_get_id(&This->event_target.dispex, L"Image", 0, &dispid); + if(SUCCEEDED(hres)) + hres = dispex_get_id(&This->event_target.dispex, L"Option", 0, &dispid); + if(FAILED(hres)) + return hres; + + for(i = 0; i < ARRAYSIZE(constructor_names); i++) { + hres = dispex_get_id(&This->event_target.dispex, constructor_names[i], 0, &dispid); + if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME) + return hres; + } + + This->static_props_filled = TRUE; + } + + hres = IWineJScript_FillGlobals(This->jscript, &This->event_target.dispex.IWineJSDispatchHost_iface); + if(FAILED(hres)) + return hres; + + return S_FALSE; +} + static HTMLInnerWindow *HTMLWindow_get_script_global(DispatchEx *dispex, dispex_static_data_t **dispex_data) { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); @@ -4186,15 +4298,19 @@ static HRESULT IHTMLWindow6_postMessage_hook(DispatchEx *dispex, WORD flags, DIS static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) { - static const dispex_hook_t window2_hooks[] = { - {DISPID_IHTMLWINDOW2_LOCATION, IHTMLWindow2_location_hook}, - {DISPID_UNKNOWN} - }; static const dispex_hook_t window2_ie11_hooks[] = { - {DISPID_IHTMLWINDOW2_LOCATION, IHTMLWindow2_location_hook}, - {DISPID_IHTMLWINDOW2_EXECSCRIPT, NULL}, + {DISPID_IHTMLWINDOW2_EXECSCRIPT}, + + /* IE9+ */ + {DISPID_IHTMLWINDOW2_IMAGE}, + {DISPID_IHTMLWINDOW2_OPTION}, + + /* Common for all modes */ + {DISPID_IHTMLWINDOW2_LOCATION, IHTMLWindow2_location_hook}, {DISPID_UNKNOWN} }; + const dispex_hook_t *const window2_ie9_hooks = window2_ie11_hooks + 1; + const dispex_hook_t *const window2_hooks = window2_ie9_hooks + 2; static const dispex_hook_t window3_hooks[] = { {DISPID_IHTMLWINDOW3_SETTIMEOUT, IHTMLWindow3_setTimeout_hook}, {DISPID_UNKNOWN} @@ -4209,24 +4325,33 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa {DISPID_IHTMLWINDOW4_CREATEPOPUP, NULL}, {DISPID_UNKNOWN} }; - static const dispex_hook_t window6_hooks[] = { + static const dispex_hook_t window6_ie9_hooks[] = { + {DISPID_IHTMLWINDOW6_XDOMAINREQUEST}, + + /* Common for all modes */ {DISPID_IHTMLWINDOW6_POSTMESSAGE, IHTMLWindow6_postMessage_hook}, {DISPID_UNKNOWN} }; + const dispex_hook_t *const window6_hooks = window6_ie9_hooks + 1; + static const dispex_hook_t private_ie10_hooks[] = { + {DISPID_IWINEHTMLWINDOWPRIVATE_MSCRYPTO}, + {DISPID_UNKNOWN} + }; if(compat_mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLWindow7_tid, NULL); else dispex_info_add_interface(info, IWineHTMLWindowCompatPrivate_tid, NULL); if(compat_mode >= COMPAT_MODE_IE10) - dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, NULL); + dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, compat_mode < COMPAT_MODE_IE11 ? private_ie10_hooks : NULL); - dispex_info_add_interface(info, IHTMLWindow6_tid, window6_hooks); + dispex_info_add_interface(info, IHTMLWindow6_tid, compat_mode >= COMPAT_MODE_IE9 ? window6_ie9_hooks : window6_hooks); if(compat_mode < COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLWindow5_tid, NULL); dispex_info_add_interface(info, IHTMLWindow4_tid, compat_mode >= COMPAT_MODE_IE11 ? window4_ie11_hooks : NULL); dispex_info_add_interface(info, IHTMLWindow3_tid, compat_mode >= COMPAT_MODE_IE11 ? window3_ie11_hooks : window3_hooks); - dispex_info_add_interface(info, IHTMLWindow2_tid, compat_mode >= COMPAT_MODE_IE11 ? window2_ie11_hooks : window2_hooks); + dispex_info_add_interface(info, IHTMLWindow2_tid, compat_mode >= COMPAT_MODE_IE11 ? window2_ie11_hooks : + compat_mode >= COMPAT_MODE_IE9 ? window2_ie9_hooks : window2_hooks); EventTarget_init_dispex_info(info, compat_mode); } @@ -4249,6 +4374,7 @@ static const event_target_vtbl_t HTMLWindow_event_target_vtbl = { .delete = HTMLWindow_delete, .next_dispid = HTMLWindow_next_dispid, .get_prop_desc = HTMLWindow_get_prop_desc, + .fill_props = HTMLWindow_fill_props, .get_script_global = HTMLWindow_get_script_global, .get_outer_iface = HTMLWindow_get_outer_iface, }, @@ -4262,6 +4388,7 @@ dispex_static_data_t Window_dispex = { .vtbl = &HTMLWindow_event_target_vtbl.dispex_vtbl, .disp_tid = DispHTMLWindow2_tid, .init_info = HTMLWindow_init_dispex_info, + .js_flags = HOSTOBJ_VOLATILE_PROPS }; static nsresult NSAPI outer_window_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb) @@ -4317,6 +4444,12 @@ static nsresult NSAPI outer_window_unlink(void *p) unlink_ref(&window->window_proxy); wine_rb_remove(&window_map, &window->entry); } + while(!list_empty(&window->detached_inner_windows)) { + HTMLInnerWindow *inner_window = LIST_ENTRY(list_head(&window->detached_inner_windows), HTMLInnerWindow, outer_window_entry); + list_remove(&inner_window->outer_window_entry); + list_init(&inner_window->outer_window_entry); + inner_window->base.outer_window = NULL; + } return NS_OK; } @@ -4395,6 +4528,7 @@ static HRESULT create_inner_window(HTMLOuterWindow *outer_window, IMoniker *mon, list_init(&window->script_hosts); list_init(&window->bindings); list_init(&window->script_queue); + list_init(&window->outer_window_entry); window->base.outer_window = outer_window; window->base.inner_window = window; @@ -4430,6 +4564,7 @@ HRESULT create_outer_window(GeckoBrowser *browser, mozIDOMWindowProxy *mozwindow window->base.inner_window = NULL; window->browser = browser; list_add_head(&browser->outer_windows, &window->browser_entry); + list_init(&window->detached_inner_windows); ccref_init(&window->ccref, 1); mozIDOMWindowProxy_AddRef(mozwindow); @@ -4482,7 +4617,7 @@ HRESULT create_pending_window(HTMLOuterWindow *outer_window, nsChannelBSC *chann if(outer_window->pending_window) { abort_window_bindings(outer_window->pending_window); - outer_window->pending_window->base.outer_window = NULL; + list_add_tail(&outer_window->detached_inner_windows, &outer_window->pending_window->outer_window_entry); IHTMLWindow2_Release(&outer_window->pending_window->base.IHTMLWindow2_iface); } @@ -4519,7 +4654,7 @@ HRESULT update_window_doc(HTMLInnerWindow *window) if(outer_window->parent) parent_mode = outer_window->parent->base.inner_window->doc->document_mode; - hres = create_document_node(nsdoc, outer_window->browser, window, window, parent_mode, &window->doc); + hres = create_document_node(nsdoc, outer_window->browser, window, window, DOCTYPE_HTML, parent_mode, &window->doc); nsIDOMDocument_Release(nsdoc); if(FAILED(hres)) return hres; diff --git a/dlls/mshtml/main.c b/dlls/mshtml/main.c index a45a2c111dc1..1999a878dea0 100644 --- a/dlls/mshtml/main.c +++ b/dlls/mshtml/main.c @@ -64,6 +64,7 @@ static IMultiLanguage2 *mlang; static IInternetSecurityManager *security_manager; static unsigned global_max_compat_mode = COMPAT_MODE_IE11; static struct list compat_config = LIST_INIT(compat_config); +struct list cc_api_list = LIST_INIT(cc_api_list); typedef struct { struct list entry; @@ -377,6 +378,15 @@ static void process_detach(void) close_gecko(); release_typelib(); + while(!list_empty(&cc_api_list)) { + struct jshost_cc_api *entry = LIST_ENTRY(list_head(&cc_api_list), struct jshost_cc_api, entry); + entry->is_full_cc = NULL; + entry->collect = NULL; + entry->describe_node = NULL; + entry->note_edge = NULL; + list_remove(&entry->entry); + } + while(!list_empty(&compat_config)) { config = LIST_ENTRY(list_head(&compat_config), compat_config_t, entry); list_remove(&config->entry); diff --git a/dlls/mshtml/mshtml.inf b/dlls/mshtml/mshtml.inf index 3e05d849fe37..f2c60748c5fe 100644 --- a/dlls/mshtml/mshtml.inf +++ b/dlls/mshtml/mshtml.inf @@ -278,6 +278,7 @@ HKCR,".tiff","Content Type",,"image/tiff" HKCR,"MIME\Database\Content Type\text/plain","CLSID",,"%CLSID_HTMLDocument%" HKCR,"MIME\Database\Content Type\text/plain","Extension",,".txt" HKCR,"MIME\Database\Content Type\text/plain","Encoding",1,07,00,00,00 +HKCR,".log",,,"txtfile" HKCR,".txt",,,"txtfile" HKCR,".txt","Content Type",,"text/plain" diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 95f7a5f49411..be3139656525 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -76,6 +76,7 @@ #define MSHTML_E_INVALID_PROPERTY 0x800a01b6 #define MSHTML_E_INVALID_ACTION 0x800a01bd #define MSHTML_E_NODOC 0x800a025c +#define MSHTML_E_SYNTAX 0x800a03ea #define MSHTML_E_NOT_FUNC 0x800a138a typedef struct HTMLWindow HTMLWindow; @@ -107,6 +108,7 @@ typedef struct ScriptHost ScriptHost; XDIID(DispDOMStorageEvent) \ XDIID(DispDOMUIEvent) \ XDIID(DispDOMDocumentType) \ + XDIID(DispDOMParser) \ XDIID(DispHTMLAnchorElement) \ XDIID(DispHTMLAreaElement) \ XDIID(DispHTMLAttributeCollection) \ @@ -156,6 +158,7 @@ typedef struct ScriptHost ScriptHost; XDIID(DispHTMLW3CComputedStyle) \ XDIID(DispHTMLWindow2) \ XDIID(DispHTMLXMLHttpRequest) \ + XDIID(DispXDomainRequest) \ XDIID(DispSVGCircleElement) \ XDIID(DispSVGSVGElement) \ XDIID(DispSVGTSpanElement) \ @@ -171,6 +174,7 @@ typedef struct ScriptHost ScriptHost; XIID(IDOMStorageEvent) \ XIID(IDOMUIEvent) \ XIID(IDOMDocumentType) \ + XIID(IDOMParser) \ XIID(IDocumentEvent) \ XIID(IDocumentRange) \ XIID(IDocumentSelector) \ @@ -289,6 +293,8 @@ typedef struct ScriptHost ScriptHost; XIID(IHTMLXMLHttpRequest) \ XIID(IHTMLXMLHttpRequest2) \ XIID(IHTMLXMLHttpRequestFactory) \ + XIID(IHTMLXDomainRequest) \ + XIID(IHTMLXDomainRequestFactory) \ XIID(IOmHistory) \ XIID(IOmNavigator) \ XIID(ISVGCircleElement) \ @@ -308,6 +314,8 @@ typedef struct ScriptHost ScriptHost; XIID(IWinePageTransitionEvent) \ XIID(IWineXMLHttpRequestPrivate) \ XIID(IWineMSHTMLConsole) \ + XIID(IWineMSHTMLCrypto) \ + XIID(IWineMSHTMLSubtleCrypto) \ XIID(IWineMSHTMLMediaQueryList) \ XIID(IWineMSHTMLMutationObserver) @@ -351,7 +359,6 @@ typedef struct dispex_dynamic_data_t dispex_dynamic_data_t; #define MSHTML_CUSTOM_DISPID_CNT (MSHTML_DISPID_CUSTOM_MAX-MSHTML_DISPID_CUSTOM_MIN) typedef struct DispatchEx DispatchEx; -typedef struct nsCycleCollectionTraversalCallback nsCycleCollectionTraversalCallback; typedef struct dispex_static_data_t dispex_static_data_t; typedef struct { @@ -397,9 +404,15 @@ typedef struct { /* These are called when the object implements GetMemberName, InvokeEx, DeleteMemberByDispID and GetNextDispID for custom props */ HRESULT (*invoke)(DispatchEx*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); HRESULT (*delete)(DispatchEx*,DISPID); - HRESULT (*next_dispid)(DispatchEx*,DISPID,DISPID*); + HRESULT (*next_dispid)(DispatchEx*,DISPID,BOOL,DISPID*); HRESULT (*get_prop_desc)(DispatchEx*,DISPID,struct property_info*); + /* Used when the object wants to override existing props get/delete operations (by name) */ + HRESULT (*override)(DispatchEx*,const WCHAR*,VARIANT*); + + /* Used when the object has props it has to fill prior to enumeration, or if it's volatile to not cache it (return S_FALSE then) */ + HRESULT (*fill_props)(DispatchEx*); + /* Similar to invoke, but allows overriding all dispids */ HRESULT (*disp_invoke)(DispatchEx*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); @@ -424,8 +437,10 @@ typedef struct { X(ClientRectList) \ X(Comment) \ X(Console) \ + X(Crypto) \ X(CustomEvent) \ X(DOMImplementation) \ + X(DOMParser) \ X(DOMTokenList) \ X(Document) \ X(DocumentFragment) \ @@ -498,10 +513,13 @@ typedef struct { X(StorageEvent) \ X(StyleSheet) \ X(StyleSheetList) \ + X(SubtleCrypto) \ X(Text) \ X(TextRange) \ X(UIEvent) \ X(Window) \ + X(XDomainRequest) \ + X(XMLDocument) \ X(XMLHttpRequest) typedef enum { @@ -510,6 +528,11 @@ typedef enum { ALL_PROTOTYPES #undef X PROT_LAST, + + /* Extra constructors without new prototypes */ + CTOR_IMAGE = PROT_LAST, + CTOR_OPTION, + CTOR_LAST } prototype_id_t; struct dispex_static_data_t { @@ -536,6 +559,8 @@ ALL_PROTOTYPES #undef X extern dispex_static_data_t *object_descriptors[PROT_LAST]; +extern struct list cc_api_list; +extern DISPID propput_dispid; typedef HRESULT (*dispex_hook_invoke_t)(DispatchEx*,WORD,DISPPARAMS*,VARIANT*, EXCEPINFO*,IServiceProvider*); @@ -594,20 +619,6 @@ struct DispatchEx { } \ DISPEX_IDISPATCH_NOUNK_IMPL(prefix, iface_name, dispex) -typedef struct { - void *vtbl; - int ref_flags; - void *callbacks; -} ExternalCycleCollectionParticipant; - -typedef struct { - nsresult (NSAPI *traverse)(void*,void*,nsCycleCollectionTraversalCallback*); - nsresult (NSAPI *unlink)(void*); - void (NSAPI *delete_cycle_collectable)(void*); -} CCObjCallback; - -DEFINE_GUID(IID_nsXPCOMCycleCollectionParticipant, 0x9674489b,0x1f6f,0x4550,0xa7,0x30, 0xcc,0xae,0xdd,0x10,0x4c,0xf9); - extern nsrefcnt (__cdecl *ccref_incr)(nsCycleCollectingAutoRefCnt*,nsISupports*); extern nsrefcnt (__cdecl *ccref_decr)(nsCycleCollectingAutoRefCnt*,nsISupports*,ExternalCycleCollectionParticipant*); extern void (__cdecl *ccref_init)(nsCycleCollectingAutoRefCnt*,nsrefcnt); @@ -624,6 +635,7 @@ HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**); HRESULT get_dispids(tid_t,DWORD*,DISPID**); HRESULT remove_attribute(DispatchEx*,DISPID,VARIANT_BOOL*); HRESULT dispex_get_dynid(DispatchEx*,const WCHAR*,BOOL,DISPID*); +HRESULT dispex_builtin_props_to_json(DispatchEx*,HTMLInnerWindow*,VARIANT*); void release_typelib(void); HRESULT get_class_typeinfo(const CLSID*,ITypeInfo**); const void *dispex_get_vtbl(DispatchEx*); @@ -754,6 +766,7 @@ struct HTMLOuterWindow { struct list sibling_entry; struct wine_rb_entry entry; + struct list detached_inner_windows; }; struct HTMLInnerWindow { @@ -770,16 +783,16 @@ struct HTMLInnerWindow { IHTMLEventObj *event; - HTMLImageElementFactory *image_factory; - HTMLOptionElementFactory *option_factory; IHTMLScreen *screen; OmHistory *history; IOmNavigator *navigator; IHTMLStorage *session_storage; IHTMLStorage *local_storage; IWineMSHTMLConsole *console; + IWineMSHTMLCrypto *crypto; - BOOL performance_initialized; + BOOLEAN static_props_filled; + BOOLEAN performance_initialized; VARIANT performance; unsigned blocking_depth; @@ -800,7 +813,7 @@ struct HTMLInnerWindow { ULONG redirect_count; DispatchEx *prototypes[PROT_LAST]; - DispatchEx *constructors[PROT_LAST]; + DispatchEx *constructors[CTOR_LAST]; ULONGLONG navigation_start_time; ULONGLONG unload_event_start_time; @@ -818,6 +831,8 @@ struct HTMLInnerWindow { ULONGLONG load_event_start_time; ULONGLONG load_event_end_time; ULONGLONG first_paint_time; + + struct list outer_window_entry; }; typedef enum { @@ -1078,6 +1093,15 @@ struct HTMLFrameBase { typedef struct nsDocumentEventListener nsDocumentEventListener; +/* NOTE: Update arrays at top of htmldoc.c if you change this */ +typedef enum { + DOCTYPE_INVALID = -1, + DOCTYPE_HTML, + DOCTYPE_XHTML, + DOCTYPE_XML, + DOCTYPE_SVG, +} document_type_t; + struct HTMLDocumentNode { HTMLDOMNode node; @@ -1133,6 +1157,7 @@ struct HTMLDocumentNode { unsigned int content_ready : 1; unsigned int unload_sent : 1; + document_type_t doc_type; IHTMLDOMImplementation *dom_implementation; IHTMLNamespaceCollection *namespaces; @@ -1159,16 +1184,18 @@ HRESULT HTMLDocument_Create(IUnknown*,REFIID,void**); HRESULT MHTMLDocument_Create(IUnknown*,REFIID,void**); HRESULT HTMLLoadOptions_Create(IUnknown*,REFIID,void**); HRESULT create_document_node(nsIDOMDocument*,GeckoBrowser*,HTMLInnerWindow*,HTMLInnerWindow*, - compat_mode_t,HTMLDocumentNode**); + document_type_t,compat_mode_t,HTMLDocumentNode**); HRESULT create_doctype_node(HTMLDocumentNode*,nsIDOMNode*,HTMLDOMNode**); +HRESULT create_marshaled_doc(HWND,REFIID,void**); HRESULT create_outer_window(GeckoBrowser*,mozIDOMWindowProxy*,HTMLOuterWindow*,HTMLOuterWindow**); HRESULT update_window_doc(HTMLInnerWindow*); HTMLOuterWindow *mozwindow_to_window(const mozIDOMWindowProxy*); void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**); -HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow*,HTMLOptionElementFactory**); -HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow*,HTMLImageElementFactory**); +HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow*,DispatchEx**); +HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow*,DispatchEx**); HRESULT HTMLXMLHttpRequestFactory_Create(HTMLInnerWindow*,DispatchEx**); +HRESULT HTMLXDomainRequestFactory_Create(HTMLInnerWindow*,DispatchEx**); HRESULT create_location(HTMLOuterWindow*,HTMLLocation**); HRESULT create_navigator(HTMLInnerWindow*,IOmNavigator**); HRESULT create_html_screen(HTMLInnerWindow*,IHTMLScreen**); @@ -1202,6 +1229,8 @@ void ConnectionPointContainer_Destroy(ConnectionPointContainer*); HRESULT create_gecko_browser(HTMLDocumentObj*,GeckoBrowser**); void detach_gecko_browser(GeckoBrowser*); +void cycle_collect(nsIDOMWindowUtils*); +void __cdecl cc_api_collect(void); DWORD get_compat_mode_version(compat_mode_t compat_mode); compat_mode_t lock_document_mode(HTMLDocumentNode*); @@ -1270,6 +1299,7 @@ HRESULT nsnode_to_nsstring(nsIDOMNode*,nsAString*); void setup_editor_controller(GeckoBrowser*); nsresult get_nsinterface(nsISupports*,REFIID,void**); nsIWritableVariant *create_nsvariant(void); +nsIDOMParser *create_nsdomparser(HTMLDocumentNode*); nsIXMLHttpRequest *create_nsxhr(nsIDOMWindow *nswindow); nsresult create_nsfile(const PRUnichar*,nsIFile**); char *get_nscategory_entry(const char*,const char*); @@ -1312,6 +1342,11 @@ static inline BOOL is_main_content_window(HTMLOuterWindow *window) return window->browser && window == window->browser->content_window; } +static inline BOOL is_detached_window(HTMLInnerWindow *window) +{ + return !list_empty(&window->outer_window_entry) || !window->base.outer_window; +} + struct HTMLAttributeCollection { DispatchEx dispex; IHTMLAttributeCollection IHTMLAttributeCollection_iface; @@ -1494,6 +1529,7 @@ typedef struct { struct list *pending_xhr_events_tail; struct wine_rb_tree session_storage_map; void *blocking_xhr; + unsigned full_cc_in_progress; unsigned tasks_locked; BOOL timer_blocked; } thread_data_t; @@ -1699,4 +1735,5 @@ IInternetSecurityManager *get_security_manager(void); extern HINSTANCE hInst; void create_console(HTMLInnerWindow *window, IWineMSHTMLConsole **ret); +HRESULT create_crypto(HTMLInnerWindow *window, IWineMSHTMLCrypto **ret); HRESULT create_media_query_list(HTMLInnerWindow *window, BSTR media_query, IDispatch **ret); diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index 5214315c7434..da5c9a59a2fa 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -113,6 +113,62 @@ interface IWineMSHTMLMediaQueryList : IDispatch HRESULT removeListener([in] VARIANT *listener); } +[ + odl, + oleautomation, + dual, + hidden, + uuid(fd55b4b6-2813-4fb4-829d-380099474ab2) +] +interface IWineMSHTMLCrypto : IDispatch +{ + [propget, id(1)] + HRESULT subtle([retval, out] IDispatch **subtle); + [id(2)] + HRESULT getRandomValues([in] VARIANT *typedArray, [retval, out] IDispatch **ret); +} + +[ + odl, + oleautomation, + dual, + hidden, + uuid(fd55b4b6-2813-4fb4-829d-380099474ab3) +] +interface IWineMSHTMLSubtleCrypto : IDispatch +{ + [id(1)] + HRESULT encrypt([in] VARIANT *algorithm, [in] VARIANT *key, [in] VARIANT *data, [retval, out] IDispatch **result); + [id(2)] + HRESULT decrypt([in] VARIANT *algorithm, [in] VARIANT *key, [in] VARIANT *data, [retval, out] IDispatch **result); + [id(3)] + HRESULT sign([in] VARIANT *algorithm, [in] VARIANT *key, [in] VARIANT *data, [retval, out] IDispatch **signature); + [id(4)] + HRESULT verify([in] VARIANT *algorithm, [in] VARIANT *key, [in] VARIANT *signature, [in] VARIANT *data, + [retval, out] IDispatch **result); + [id(5)] + HRESULT digest([in] VARIANT *algorithm, [in] VARIANT *data, [retval, out] IDispatch **digest); + [id(6)] + HRESULT generateKey([in] VARIANT *algorithm, VARIANT_BOOL extractable, [in] VARIANT *keyUsages, + [retval, out] IDispatch **result); + [id(7)] + HRESULT deriveKey([in] VARIANT *algorithm, [in] VARIANT *baseKey, [in] VARIANT *derivedKeyAlgorithm, + VARIANT_BOOL extractable, [in] VARIANT *keyUsages, [retval, out] IDispatch **result); + [id(8)] + HRESULT importKey([in] BSTR format, [in] VARIANT *keyData, [in] VARIANT *algorithm, VARIANT_BOOL extractable, + [in] VARIANT *keyUsages, [retval, out] IDispatch **result); + [id(9)] + HRESULT exportKey([in] BSTR format, [in] VARIANT *key, [retval, out] IDispatch **result); + [id(10)] + HRESULT wrapKey([in] BSTR format, [in] VARIANT *key, [in] VARIANT *wrappingKey, [in] VARIANT *wrapAlgo, + [retval, out] IDispatch **result); + [id(11)] + HRESULT unwrapKey([in] BSTR format, [in] VARIANT *wrappedKey, [in] VARIANT *unwrappingKey, + [in] VARIANT *unwrapAlgo, [in] VARIANT *unwrappedKeyAlgo, VARIANT_BOOL extractable, + [in] VARIANT *keyUsages, [retval, out] IDispatch **result); +} + +const long DISPID_IWINEHTMLWINDOWPRIVATE_MSCRYPTO = 54; [ odl, oleautomation, @@ -130,6 +186,8 @@ interface IWineHTMLWindowPrivate : IDispatch HRESULT console([retval, out] IDispatch **console); [id(53)] HRESULT matchMedia([in] BSTR media_query, [retval, out] IDispatch **media_query_list); + [propget, id(DISPID_IWINEHTMLWINDOWPRIVATE_MSCRYPTO)] + HRESULT msCrypto([retval, out] IDispatch **crypto); } [ diff --git a/dlls/mshtml/mutation.c b/dlls/mshtml/mutation.c index 6cc969cf634c..11e31d38968d 100644 --- a/dlls/mshtml/mutation.c +++ b/dlls/mshtml/mutation.c @@ -438,6 +438,7 @@ compat_mode_t lock_document_mode(HTMLDocumentNode *doc) static void set_document_mode(HTMLDocumentNode *doc, compat_mode_t document_mode, BOOL emulate_mode, BOOL lock) { compat_mode_t max_compat_mode; + const char *sgi; if(doc->document_mode_locked) { WARN("attempting to set document mode %d on locked document %p\n", document_mode, doc); @@ -446,7 +447,7 @@ static void set_document_mode(HTMLDocumentNode *doc, compat_mode_t document_mode TRACE("%p: %d\n", doc, document_mode); - max_compat_mode = doc->window && doc->window->base.outer_window + max_compat_mode = doc->window && !is_detached_window(doc->window) ? get_max_compat_mode(doc->window->base.outer_window->uri) : COMPAT_MODE_IE11; if(max_compat_mode < document_mode) { @@ -455,6 +456,9 @@ static void set_document_mode(HTMLDocumentNode *doc, compat_mode_t document_mode document_mode = max_compat_mode; } + if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "39210"))) + document_mode = COMPAT_MODE_IE11; + doc->document_mode = document_mode; doc->emulate_mode = emulate_mode; if(lock) @@ -1217,7 +1221,7 @@ dispex_static_data_t MutationObserver_dispex = { .vtbl = &mutation_observer_dispex_vtbl, .disp_tid = IWineMSHTMLMutationObserver_tid, .iface_tids = mutation_observer_iface_tids, - .min_compat_mode = COMPAT_MODE_IE11, + .min_compat_mode = COMPAT_MODE_IE11 + 1, /* FIXME HACK: Not exposed as FFXIV Launcher breaks with MutationObserver stub */ }; static HRESULT create_mutation_observer(DispatchEx *owner, IDispatch *callback, diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index 90ca22ea8b1c..19837d247be0 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -578,7 +578,7 @@ static HRESULT WINAPI BindCallbackRedirect_Redirect(IBindCallbackRedirect *iface TRACE("(%p)->(%s %p)\n", This, debugstr_w(url), vbCancel); - if(This->window && This->window->base.outer_window && (browser = This->window->base.outer_window->browser) + if(This->window && !is_detached_window(This->window) && (browser = This->window->base.outer_window->browser) && browser->doc->doc_object_service) { if(is_main_content_window(This->window->base.outer_window)) { hres = IHTMLWindow2_get_name(&This->window->base.IHTMLWindow2_iface, &frame_name); @@ -814,7 +814,8 @@ static void query_http_info(nsChannelBSC *This, IWinInetHttpInfo *wininet_info) { const WCHAR *ptr; DWORD len = 0; - WCHAR *buf; + WCHAR *wbuf; + char *buf; IWinInetHttpInfo_QueryInfo(wininet_info, HTTP_QUERY_RAW_HEADERS_CRLF, NULL, &len, NULL, NULL); if(!len) @@ -830,13 +831,18 @@ static void query_http_info(nsChannelBSC *This, IWinInetHttpInfo *wininet_info) return; } - ptr = wcschr(buf, '\r'); + wbuf = strdupAtoW(buf); + free(buf); + if (!wbuf) + return; + + ptr = wcschr(wbuf, '\r'); if(ptr && ptr[1] == '\n') { ptr += 2; process_response_headers(This, ptr); } - free(buf); + free(wbuf); } HRESULT start_binding(HTMLInnerWindow *inner_window, BSCallback *bscallback, IBindCtx *bctx) @@ -1269,7 +1275,7 @@ static nsresult NSAPI nsAsyncVerifyRedirectCallback_OnRedirectVerifyCallback(nsI ERR("AddRequest failed: %08lx\n", nsres); } - if(This->bsc->is_doc_channel && This->bsc->bsc.window && This->bsc->bsc.window->base.outer_window) { + if(This->bsc->is_doc_channel && This->bsc->bsc.window && !is_detached_window(This->bsc->bsc.window)) { IUri *uri = nsuri_get_uri(This->nschannel->uri); if(uri) { @@ -1445,7 +1451,7 @@ static void handle_navigation_error(nsChannelBSC *This, DWORD result) BSTR unk; HRESULT hres; - if(!This->is_doc_channel || !This->bsc.window || !This->bsc.window->base.outer_window + if(!This->is_doc_channel || !This->bsc.window || is_detached_window(This->bsc.window) || !This->bsc.window->base.outer_window->browser) return; @@ -1644,7 +1650,7 @@ static void handle_extern_mime_navigation(nsChannelBSC *This) VARIANT flags; HRESULT hres; - if(!This->bsc.window || !This->bsc.window->base.outer_window || !This->bsc.window->base.outer_window->browser) + if(!This->bsc.window || is_detached_window(This->bsc.window) || !This->bsc.window->base.outer_window->browser) return; doc_obj = This->bsc.window->base.outer_window->browser->doc; diff --git a/dlls/mshtml/nsembed.c b/dlls/mshtml/nsembed.c index b06c08ff496a..651229bba749 100644 --- a/dlls/mshtml/nsembed.c +++ b/dlls/mshtml/nsembed.c @@ -42,6 +42,7 @@ WINE_DECLARE_DEBUG_CHANNEL(gecko); #define NS_WEBBROWSER_CONTRACTID "@mozilla.org/embedding/browser/nsWebBrowser;1" #define NS_COMMANDPARAMS_CONTRACTID "@mozilla.org/embedcomp/command-params;1" #define NS_HTMLSERIALIZER_CONTRACTID "@mozilla.org/layout/contentserializer;1?mimetype=text/html" +#define NS_DOMPARSER_CONTRACTID "@mozilla.org/xmlextras/domparser;1" #define NS_EDITORCONTROLLER_CONTRACTID "@mozilla.org/editor/editorcontroller;1" #define NS_PREFERENCES_CONTRACTID "@mozilla.org/preferences;1" #define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1" @@ -2173,6 +2174,16 @@ static const nsISupportsWeakReferenceVtbl nsSupportsWeakReferenceVtbl = { nsSupportsWeakReference_GetWeakReference }; +void cycle_collect(nsIDOMWindowUtils *window_utils) +{ + thread_data_t *thread_data = get_thread_data(TRUE); + if(thread_data) { + thread_data->full_cc_in_progress++; + nsIDOMWindowUtils_CycleCollect(window_utils, NULL, 0); + thread_data->full_cc_in_progress--; + } +} + static HRESULT init_browser(GeckoBrowser *browser) { mozIDOMWindowProxy *mozwindow; @@ -2396,7 +2407,7 @@ void detach_gecko_browser(GeckoBrowser *This) /* Force cycle collection */ if(window_utils) { - nsIDOMWindowUtils_CycleCollect(window_utils, NULL, 0); + cycle_collect(window_utils); nsIDOMWindowUtils_Release(window_utils); } } @@ -2415,6 +2426,51 @@ __ASM_GLOBAL_FUNC(call_thiscall_func, #define nsIScriptObjectPrincipal_GetPrincipal(this) ((void* (WINAPI*)(void*,void*))&call_thiscall_func)((this)->lpVtbl->GetPrincipal,this) #endif +nsIDOMParser *create_nsdomparser(HTMLDocumentNode *doc_node) +{ + nsIScriptObjectPrincipal *sop; + HTMLOuterWindow *outer_window; + mozIDOMWindow *inner_window; + nsIGlobalObject *nsglo; + nsIDOMParser *nsparser; + nsIPrincipal *nspri; + nsresult nsres; + + outer_window = doc_node->window && doc_node->window->base.outer_window ? doc_node->window->base.outer_window : doc_node->doc_obj->window; + + nsres = nsIDOMWindow_GetInnerWindow(outer_window->nswindow, &inner_window); + if(NS_FAILED(nsres)) { + ERR("Could not get inner window: %08lx\n", nsres); + return NULL; + } + + nsres = mozIDOMWindow_QueryInterface(inner_window, &IID_nsIGlobalObject, (void**)&nsglo); + mozIDOMWindow_Release(inner_window); + assert(nsres == NS_OK); + + nsres = nsIGlobalObject_QueryInterface(nsglo, &IID_nsIScriptObjectPrincipal, (void**)&sop); + assert(nsres == NS_OK); + + /* The returned principal is *not* AddRef'd */ + nspri = nsIScriptObjectPrincipal_GetPrincipal(sop); + nsIScriptObjectPrincipal_Release(sop); + + nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, + NS_DOMPARSER_CONTRACTID, NULL, &IID_nsIDOMParser, (void**)&nsparser); + if(NS_SUCCEEDED(nsres)) { + nsres = nsIDOMParser_Init(nsparser, nspri, NULL, NULL, nsglo); + if(NS_FAILED(nsres)) + nsIDOMParser_Release(nsparser); + } + nsIGlobalObject_Release(nsglo); + if(NS_FAILED(nsres)) { + ERR("nsIDOMParser_Init failed: %08lx\n", nsres); + return NULL; + } + + return nsparser; +} + nsIXMLHttpRequest *create_nsxhr(nsIDOMWindow *nswindow) { nsIScriptObjectPrincipal *sop; diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index 5d52cf4f17a5..342615a9e67c 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -316,7 +316,7 @@ static nsresult handle_load(HTMLDocumentNode *doc, nsIDOMEvent *event) TRACE("(%p)\n", doc); - if(!doc->window || !doc->window->base.outer_window) + if(!doc->window || is_detached_window(doc->window)) return NS_ERROR_FAILURE; if(doc->doc_obj && doc->doc_obj->doc_node == doc) { doc_obj = doc->doc_obj; @@ -328,7 +328,7 @@ static nsresult handle_load(HTMLDocumentNode *doc, nsIDOMEvent *event) handle_docobj_load(doc_obj); doc->window->dom_complete_time = get_time_stamp(); - if(doc->window->base.outer_window) + if(!is_detached_window(doc->window)) set_ready_state(doc->window->base.outer_window, READYSTATE_COMPLETE); if(doc_obj) { @@ -339,7 +339,7 @@ static nsresult handle_load(HTMLDocumentNode *doc, nsIDOMEvent *event) update_title(doc_obj); - if(doc_obj->doc_object_service && doc->window->base.outer_window && !(doc->window->base.outer_window->load_flags & BINDING_REFRESH)) + if(doc_obj->doc_object_service && !is_detached_window(doc->window) && !(doc->window->base.outer_window->load_flags & BINDING_REFRESH)) IDocObjectService_FireDocumentComplete(doc_obj->doc_object_service, &doc->window->base.outer_window->base.IHTMLWindow2_iface, 0); @@ -441,8 +441,12 @@ static nsresult handle_htmlevent(HTMLDocumentNode *doc, nsIDOMEvent *nsevent) }else { hres = get_node(nsnode, TRUE, &node); nsIDOMNode_Release(nsnode); - if(FAILED(hres) || !node->doc->script_global) + if(FAILED(hres)) + return NS_OK; + if(!node->doc->script_global) { + IHTMLDOMNode_Release(&node->IHTMLDOMNode_iface); return NS_OK; + } target = &node->event_target; } diff --git a/dlls/mshtml/nsiface.idl b/dlls/mshtml/nsiface.idl index 43786b490f54..20664ee4b27d 100644 --- a/dlls/mshtml/nsiface.idl +++ b/dlls/mshtml/nsiface.idl @@ -4369,6 +4369,19 @@ interface nsIScriptObjectPrincipal : nsISupports nsIPrincipal* /* thiscall */ GetPrincipal(); } +[ + object, + uuid(70b9600e-8622-4c93-9ad8-22c28058dc44), + local +] +interface nsIDOMParser : nsISupports +{ + nsresult ParseFromString(const char16_t *str, const char *contentType, nsIDOMDocument **_retval); + nsresult ParseFromBuffer(const uint8_t *buf, uint32_t bufLen, const char *aContentType, nsIDOMDocument **_retval); + nsresult ParseFromStream(nsIInputStream *stream, const char *charset, int32_t contentLength, const char *contentType, nsIDOMDocument **_retval); + nsresult Init(nsIPrincipal *principal, nsIURI *documentURI, nsIURI *baseURI, nsIGlobalObject *scriptObject); +} + [ object, uuid(6f54214c-7175-498d-9d2d-0429e38c2869), @@ -4406,5 +4419,3 @@ interface nsIXMLHttpRequest : nsISupports nsresult GetMozSystem(bool *aMozSystem); nsresult GetResponseBuffer(void *buffer, uint32_t buffer_size, uint32_t *_retval); } - -cpp_quote("DEFINE_GUID(IID_nsCycleCollectionISupports, 0xc61eac14,0x5f7a,0x4481,0x96,0x5e,0x7e,0xaa,0x6e,0xff,0xa8,0x5f);") diff --git a/dlls/mshtml/nsio.c b/dlls/mshtml/nsio.c index a5564e1b6e49..ed8ed949fba9 100644 --- a/dlls/mshtml/nsio.c +++ b/dlls/mshtml/nsio.c @@ -287,6 +287,50 @@ static nsresult before_async_open(nsChannel *channel, GeckoBrowser *container, B return NS_OK; } +static nsresult fire_before_navigate(nsChannel *channel, HTMLOuterWindow *window, BOOL *cancel) +{ + BSTR frame_name = NULL; + OLECHAR *new_url; + BSTR uri_str; + HRESULT hres; + + hres = IUri_GetDisplayUri(channel->uri->uri, &uri_str); + if(FAILED(hres)) + { + ERR("IUri_GetDisplayUri failed, hres %#lx.\n", hres); + return NS_ERROR_FAILURE; + } + if(window->browser->doc->hostui) + { + hres = IDocHostUIHandler_TranslateUrl(window->browser->doc->hostui, 0, uri_str, &new_url); + if(hres == S_OK && new_url) + { + if(wcscmp(uri_str, new_url)) + { + FIXME("TranslateUrl returned new URL %s -> %s.\n", debugstr_w(uri_str), debugstr_w(new_url)); + CoTaskMemFree(new_url); + *cancel = TRUE; + SysFreeString(uri_str); + return NS_OK; + } + CoTaskMemFree(new_url); + } + } + + hres = IHTMLWindow2_get_name(&window->base.IHTMLWindow2_iface, &frame_name); + if (FAILED(hres)) + { + SysFreeString(uri_str); + return NS_ERROR_FAILURE; + } + + hres = IDocObjectService_FireBeforeNavigate2(window->browser->doc->doc_object_service, NULL, uri_str, 0x40, + frame_name, NULL, 0, NULL, TRUE, cancel); + SysFreeString(frame_name); + SysFreeString(uri_str); + return SUCCEEDED(hres) ? NS_OK : NS_ERROR_FAILURE; +} + HRESULT load_nsuri(HTMLOuterWindow *window, nsWineURI *uri, nsIInputStream *post_stream, nsChannelBSC *channelbsc, DWORD flags) { @@ -1104,6 +1148,27 @@ static nsresult NSAPI nsChannel_AsyncOpen(nsIHttpChannel *iface, nsIStreamListen This->content_type = strdupWtoA(window->browser->doc->mime); } } + else if (window->browser && window->frame_element && window->browser->doc + && window->browser->doc->doc_object_service) + { + IUnknown *unk; + if (SUCCEEDED(IHTMLFrameBase_QueryInterface(&window->frame_element->IHTMLFrameBase_iface, + &IID_IHTMLIFrameElement, (void **)&unk))) + { + IUnknown_Release(unk); + nsres = fire_before_navigate(This, window, &cancel); + if(NS_SUCCEEDED(nsres) && cancel) + { + TRACE("canceled.\n"); + nsres = NS_BINDING_ABORTED; + } + else + { + FIXME("fire_before_navigate returned error %#lx.\n", nsres); + nsres = NS_OK; + } + } + } } if(!cancel) diff --git a/dlls/mshtml/olecmd.c b/dlls/mshtml/olecmd.c index 650c44c9d2ba..8d0eafee812c 100644 --- a/dlls/mshtml/olecmd.c +++ b/dlls/mshtml/olecmd.c @@ -490,7 +490,7 @@ static HRESULT exec_refresh(HTMLDocumentNode *doc, DWORD nCmdexecopt, VARIANT *p } } - if(!doc->window || !doc->window->base.outer_window) + if(!doc->window || is_detached_window(doc->window)) return E_UNEXPECTED; return reload_page(doc->window->base.outer_window); diff --git a/dlls/mshtml/oleobj.c b/dlls/mshtml/oleobj.c index 7dffdbeeec29..3b1c65c9a3b7 100644 --- a/dlls/mshtml/oleobj.c +++ b/dlls/mshtml/oleobj.c @@ -3699,16 +3699,99 @@ static const cpc_entry_t HTMLDocumentObj_cpc[] = { {NULL} }; + + +/* TRUE if we create a dedicated thread for all HTML documents */ +static BOOL gecko_main_thread_config; + +static LONG gecko_main_thread; +static HWND gecko_main_thread_hwnd; +static HANDLE gecko_main_thread_event; + +static DWORD WINAPI gecko_main_thread_proc(void *arg) +{ + MSG msg; + + TRACE("\n"); + + CoInitialize(NULL); + + gecko_main_thread_hwnd = get_thread_hwnd(); + if(!gecko_main_thread_hwnd) { + ERR("Could not create thread window\n"); + SetEvent(gecko_main_thread_event); + CoUninitialize(); + return 0; + } + + gecko_main_thread = GetCurrentThreadId(); + SetEvent(gecko_main_thread_event); + + while(GetMessageW(&msg, NULL, 0, 0)) { + DispatchMessageW(&msg); + TranslateMessage(&msg); + } + + CoUninitialize(); + return 0; +} + +static BOOL WINAPI read_thread_config(INIT_ONCE *once, void *param, void **context) +{ + char str[64]; + + if((GetEnvironmentVariableA("SteamGameId", str, sizeof(str)) && (!strcmp(str, "491540") || !strcmp(str,"47890"))) + || (GetEnvironmentVariableA("WINE_GECKO_MAIN_THREAD", str, sizeof(str)) && *str != '0')) + { + FIXME("HACK: Using separated main thread.\n"); + gecko_main_thread_config = TRUE; + } + + return TRUE; +} + static HRESULT create_document_object(BOOL is_mhtml, IUnknown *outer, REFIID riid, void **ppv) { HTMLDocumentObj *doc; HRESULT hres; + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + if(outer && !IsEqualGUID(&IID_IUnknown, riid)) { *ppv = NULL; return E_INVALIDARG; } + /* CXHACK 15579 */ + InitOnceExecuteOnce(&init_once, read_thread_config, NULL, NULL); + if(gecko_main_thread_config && !gecko_main_thread) { + HANDLE thread, event; + + event = CreateEventW(NULL, TRUE, FALSE, NULL); + if(InterlockedCompareExchangePointer(&gecko_main_thread_event, event, NULL)) + CloseHandle(event); + + thread = CreateThread(NULL, 0, gecko_main_thread_proc, NULL, 0, NULL); + if(thread) { + WaitForSingleObject(gecko_main_thread_event, INFINITE); + CloseHandle(thread); + }else { + ERR("Could not create a thread\n"); + } + } + + if(!gecko_main_thread) { + gecko_main_thread = GetCurrentThreadId(); + gecko_main_thread_hwnd = get_thread_hwnd(); + }else if(GetCurrentThreadId() != gecko_main_thread) { + FIXME("HACK: Creating HTMLDocument outside Gecko main thread\n"); + if(!gecko_main_thread_config) { + FIXME("HACK: Dedicated main thread not configured\n"); + FIXME("HACK: Create HKCU\\Software\\Wine\\MSHTML\\MainThreadHack key\n"); + } + return create_marshaled_doc(gecko_main_thread_hwnd, riid, ppv); + } + /* ensure that security manager is initialized */ if(!get_security_manager()) return E_OUTOFMEMORY; diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 6b255d4cd54b..cc530dd193ae 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h" #include "wine/debug.h" @@ -32,6 +33,31 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); +static document_type_t document_type_from_content_type(const WCHAR *content_type) +{ + static const struct { + const WCHAR *content_type; + document_type_t doc_type; + } table[] = { + { L"application/xhtml+xml", DOCTYPE_XHTML }, + { L"application/xml", DOCTYPE_XML }, + { L"image/svg+xml", DOCTYPE_SVG }, + { L"text/html", DOCTYPE_HTML }, + { L"text/xml", DOCTYPE_XML }, + }; + unsigned int i, a = 0, b = ARRAY_SIZE(table); + int c; + + while(a < b) { + i = (a + b) / 2; + c = wcsicmp(table[i].content_type, content_type); + if(!c) return table[i].doc_type; + if(c > 0) b = i; + else a = i + 1; + } + return DOCTYPE_INVALID; +} + typedef struct HTMLPluginsCollection HTMLPluginsCollection; typedef struct HTMLMimeTypesCollection HTMLMimeTypesCollection; @@ -113,6 +139,7 @@ static HRESULT WINAPI HTMLDOMImplementation2_createHTMLDocument(IHTMLDOMImplemen { HTMLDOMImplementation *This = impl_from_IHTMLDOMImplementation2(iface); HTMLDocumentNode *new_document_node; + compat_mode_t compat_mode; nsIDOMDocument *doc; nsAString title_str; nsresult nsres; @@ -131,12 +158,17 @@ static HRESULT WINAPI HTMLDOMImplementation2_createHTMLDocument(IHTMLDOMImplemen return E_FAIL; } + compat_mode = dispex_compat_mode(&This->dispex); hres = create_document_node(doc, This->doc->browser, NULL, This->doc->script_global, - dispex_compat_mode(&This->dispex), &new_document_node); + DOCTYPE_HTML, compat_mode, &new_document_node); nsIDOMDocument_Release(doc); if(FAILED(hres)) return hres; + /* make sure dispex info is initialized for the prototype */ + if(compat_mode >= COMPAT_MODE_IE9) + dispex_compat_mode(&new_document_node->node.event_target.dispex); + *new_document = &new_document_node->IHTMLDocument7_iface; return S_OK; } @@ -263,6 +295,259 @@ void detach_dom_implementation(IHTMLDOMImplementation *iface) dom_implementation->doc = NULL; } +struct dom_parser { + DispatchEx dispex; + IDOMParser IDOMParser_iface; + + HTMLDocumentNode *doc; +}; + +static inline struct dom_parser *impl_from_IDOMParser(IDOMParser *iface) +{ + return CONTAINING_RECORD(iface, struct dom_parser, IDOMParser_iface); +} + +DISPEX_IDISPATCH_IMPL(dom_parser, IDOMParser, impl_from_IDOMParser(iface)->dispex) + +static HRESULT WINAPI dom_parser_parseFromString(IDOMParser *iface, BSTR string, BSTR mimeType, IHTMLDocument2 **ppNode) +{ + struct dom_parser *This = impl_from_IDOMParser(iface); + nsIDOMDocument *nsdoc = NULL; + HTMLDocumentNode *xml_doc; + document_type_t doc_type; + nsAString errns, errtag; + nsIDOMNodeList *nodes; + nsIDOMParser *parser; + nsresult nsres; + HRESULT hres; + + TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(string), debugstr_w(mimeType), ppNode); + + if(!string || !mimeType || (doc_type = document_type_from_content_type(mimeType)) == DOCTYPE_INVALID) + return E_INVALIDARG; + + if(doc_type == DOCTYPE_HTML) { + IHTMLDOMImplementation *impl_iface; + HTMLDOMImplementation *impl; + IHTMLDocument7 *html_doc; + IHTMLElement *html_elem; + HTMLDocumentNode *doc; + + hres = IHTMLDocument5_get_implementation(&This->doc->IHTMLDocument5_iface, &impl_iface); + if(FAILED(hres)) + return hres; + + impl = impl_from_IHTMLDOMImplementation(impl_iface); + hres = HTMLDOMImplementation2_createHTMLDocument(&impl->IHTMLDOMImplementation2_iface, NULL, &html_doc); + HTMLDOMImplementation_Release(impl_iface); + if(FAILED(hres)) + return hres; + doc = CONTAINING_RECORD(html_doc, HTMLDocumentNode, IHTMLDocument7_iface); + + hres = IHTMLDocument3_get_documentElement(&doc->IHTMLDocument3_iface, &html_elem); + if(FAILED(hres)) { + IHTMLDocument7_Release(html_doc); + return hres; + } + + hres = IHTMLElement_put_innerHTML(html_elem, string); + IHTMLElement_Release(html_elem); + if(FAILED(hres)) { + IHTMLDocument7_Release(html_doc); + return hres; + } + + *ppNode = &doc->IHTMLDocument2_iface; + return hres; + } + + if(!(parser = create_nsdomparser(This->doc))) + return E_FAIL; + nsres = nsIDOMParser_ParseFromString(parser, string ? string : L"", + doc_type == DOCTYPE_SVG ? "image/svg+xml" : + doc_type == DOCTYPE_XHTML ? "application/xhtml+xml" : + "text/xml", &nsdoc); + nsIDOMParser_Release(parser); + if(NS_FAILED(nsres) || !nsdoc) { + ERR("ParseFromString failed: 0x%08lx\n", nsres); + return NS_FAILED(nsres) ? map_nsresult(nsres) : E_FAIL; + } + + nsAString_InitDepend(&errns, L"http://www.mozilla.org/newlayout/xml/parsererror.xml"); + nsAString_InitDepend(&errtag, L"parsererror"); + nsres = nsIDOMDocument_GetElementsByTagNameNS(nsdoc, &errns, &errtag, &nodes); + nsAString_Finish(&errtag); + nsAString_Finish(&errns); + if(NS_SUCCEEDED(nsres)) { + UINT32 length; + nsres = nsIDOMNodeList_GetLength(nodes, &length); + nsIDOMNodeList_Release(nodes); + if(NS_SUCCEEDED(nsres) && length) { + nsIDOMDocument_Release(nsdoc); + return MSHTML_E_SYNTAX; + } + } + + hres = create_document_node(nsdoc, This->doc->browser, NULL, This->doc->script_global, doc_type, This->doc->document_mode, &xml_doc); + nsIDOMDocument_Release(nsdoc); + if(FAILED(hres)) + return hres; + + /* make sure dispex info is initialized */ + dispex_compat_mode(&xml_doc->node.event_target.dispex); + *ppNode = &xml_doc->IHTMLDocument2_iface; + return hres; +} + +static const IDOMParserVtbl dom_parser_vtbl = { + dom_parser_QueryInterface, + dom_parser_AddRef, + dom_parser_Release, + dom_parser_GetTypeInfoCount, + dom_parser_GetTypeInfo, + dom_parser_GetIDsOfNames, + dom_parser_Invoke, + dom_parser_parseFromString +}; + +static inline struct dom_parser *dom_parser_from_DispatchEx(DispatchEx *iface) +{ + return CONTAINING_RECORD(iface, struct dom_parser, dispex); +} + +static void *dom_parser_query_interface(DispatchEx *dispex, REFIID riid) +{ + struct dom_parser *This = dom_parser_from_DispatchEx(dispex); + + if(IsEqualGUID(&IID_IDOMParser, riid)) + return &This->IDOMParser_iface; + + return NULL; +} + +static void dom_parser_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCallback *cb) +{ + struct dom_parser *This = dom_parser_from_DispatchEx(dispex); + if(This->doc) + note_cc_edge((nsISupports*)&This->doc->node.IHTMLDOMNode_iface, "doc", cb); +} + +static void dom_parser_unlink(DispatchEx *dispex) +{ + struct dom_parser *This = dom_parser_from_DispatchEx(dispex); + if(This->doc) { + HTMLDocumentNode *doc = This->doc; + This->doc = NULL; + IHTMLDOMNode_Release(&doc->node.IHTMLDOMNode_iface); + } +} + +static void dom_parser_destructor(DispatchEx *dispex) +{ + struct dom_parser *This = dom_parser_from_DispatchEx(dispex); + free(This); +} + +static HRESULT create_dom_parser_ctor(HTMLInnerWindow *script_global, DispatchEx **ret); + +static const dispex_static_data_vtbl_t dom_parser_dispex_vtbl = { + .query_interface = dom_parser_query_interface, + .destructor = dom_parser_destructor, + .traverse = dom_parser_traverse, + .unlink = dom_parser_unlink +}; + +static const tid_t dom_parser_iface_tids[] = { + IDOMParser_tid, + 0 +}; + +dispex_static_data_t DOMParser_dispex = { + .id = PROT_DOMParser, + .init_constructor = create_dom_parser_ctor, + .vtbl = &dom_parser_dispex_vtbl, + .disp_tid = DispDOMParser_tid, + .iface_tids = dom_parser_iface_tids, +}; + +struct dom_parser_ctor { + DispatchEx dispex; +}; + +static inline struct dom_parser_ctor *dom_parser_ctor_from_DispatchEx(DispatchEx *dispex) +{ + return CONTAINING_RECORD(dispex, struct dom_parser_ctor, dispex); +} + +static void dom_parser_ctor_destructor(DispatchEx *dispex) +{ + struct dom_parser_ctor *This = dom_parser_ctor_from_DispatchEx(dispex); + free(This); +} + +static HRESULT dom_parser_ctor_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + struct dom_parser_ctor *This = dom_parser_ctor_from_DispatchEx(dispex); + HTMLInnerWindow *window; + struct dom_parser *ret; + + TRACE("\n"); + + switch(flags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: + break; + default: + FIXME("flags %x not supported\n", flags); + return E_NOTIMPL; + } + + if(!(ret = calloc(1, sizeof(*ret)))) + return E_OUTOFMEMORY; + + window = get_script_global(&This->dispex); + ret->IDOMParser_iface.lpVtbl = &dom_parser_vtbl; + ret->doc = window->doc; + IHTMLDOMNode_AddRef(&ret->doc->node.IHTMLDOMNode_iface); + + init_dispatch(&ret->dispex, &DOMParser_dispex, window, dispex_compat_mode(&This->dispex)); + IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); + + V_VT(res) = VT_DISPATCH; + V_DISPATCH(res) = (IDispatch*)&ret->IDOMParser_iface; + return S_OK; +} + +static const dispex_static_data_vtbl_t dom_parser_ctor_dispex_vtbl = { + .destructor = dom_parser_ctor_destructor, + .value = dom_parser_ctor_value, +}; + +static dispex_static_data_t dom_parser_ctor_dispex = { + .name = "Function", + .constructor_id = PROT_DOMParser, + .vtbl = &dom_parser_ctor_dispex_vtbl, +}; + +static HRESULT create_dom_parser_ctor(HTMLInnerWindow *script_global, DispatchEx **ret) +{ + struct dom_parser *dom_parser; + + if(!(dom_parser = calloc(1, sizeof(*dom_parser)))) + return E_OUTOFMEMORY; + + init_dispatch(&dom_parser->dispex, &dom_parser_ctor_dispex, script_global, + dispex_compat_mode(&script_global->event_target.dispex)); + + *ret = &dom_parser->dispex; + return S_OK; +} + typedef struct { DispatchEx dispex; IHTMLScreen IHTMLScreen_iface; @@ -1439,8 +1724,10 @@ static HRESULT WINAPI HTMLPerformanceTiming_toString(IHTMLPerformanceTiming *ifa static HRESULT WINAPI HTMLPerformanceTiming_toJSON(IHTMLPerformanceTiming *iface, VARIANT *p) { HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return dispex_builtin_props_to_json(&This->dispex, This->window, p); } static const IHTMLPerformanceTimingVtbl HTMLPerformanceTimingVtbl = { @@ -1521,15 +1808,20 @@ static const dispex_static_data_vtbl_t HTMLPerformanceTiming_dispex_vtbl = { .unlink = HTMLPerformanceTiming_unlink }; -static const tid_t PerformanceTiming_iface_tids[] = { - IHTMLPerformanceTiming_tid, - 0 -}; +static void PerformanceTiming_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLPERFORMANCETIMING_TOJSON}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLPerformanceTiming_tid, mode < COMPAT_MODE_IE9 ? hooks : NULL); +} + dispex_static_data_t PerformanceTiming_dispex = { .id = PROT_PerformanceTiming, .vtbl = &HTMLPerformanceTiming_dispex_vtbl, .disp_tid = IHTMLPerformanceTiming_tid, - .iface_tids = PerformanceTiming_iface_tids, + .init_info = PerformanceTiming_init_dispex_info, }; typedef struct { @@ -1579,8 +1871,10 @@ static HRESULT WINAPI HTMLPerformanceNavigation_toString(IHTMLPerformanceNavigat static HRESULT WINAPI HTMLPerformanceNavigation_toJSON(IHTMLPerformanceNavigation *iface, VARIANT *p) { HTMLPerformanceNavigation *This = impl_from_IHTMLPerformanceNavigation(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return dispex_builtin_props_to_json(&This->dispex, This->window, p); } static const IHTMLPerformanceNavigationVtbl HTMLPerformanceNavigationVtbl = { @@ -1642,15 +1936,20 @@ static const dispex_static_data_vtbl_t HTMLPerformanceNavigation_dispex_vtbl = { .unlink = HTMLPerformanceNavigation_unlink }; -static const tid_t PerformanceNavigation_iface_tids[] = { - IHTMLPerformanceNavigation_tid, - 0 -}; +static void PerformanceNavigation_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLPERFORMANCENAVIGATION_TOJSON}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLPerformanceNavigation_tid, mode < COMPAT_MODE_IE9 ? hooks : NULL); +} + dispex_static_data_t PerformanceNavigation_dispex = { .id = PROT_PerformanceNavigation, .vtbl = &HTMLPerformanceNavigation_dispex_vtbl, .disp_tid = IHTMLPerformanceNavigation_tid, - .iface_tids = PerformanceNavigation_iface_tids, + .init_info = PerformanceNavigation_init_dispex_info, }; typedef struct { @@ -1736,8 +2035,10 @@ static HRESULT WINAPI HTMLPerformance_toString(IHTMLPerformance *iface, BSTR *st static HRESULT WINAPI HTMLPerformance_toJSON(IHTMLPerformance *iface, VARIANT *var) { HTMLPerformance *This = impl_from_IHTMLPerformance(iface); - FIXME("(%p)->(%p)\n", This, var); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, var); + + return dispex_builtin_props_to_json(&This->dispex, This->window, var); } static const IHTMLPerformanceVtbl HTMLPerformanceVtbl = { @@ -1805,15 +2106,20 @@ static const dispex_static_data_vtbl_t HTMLPerformance_dispex_vtbl = { .unlink = HTMLPerformance_unlink }; -static const tid_t Performance_iface_tids[] = { - IHTMLPerformance_tid, - 0 -}; +static void Performance_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLPERFORMANCE_TOJSON}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLPerformance_tid, mode < COMPAT_MODE_IE9 ? hooks : NULL); +} + dispex_static_data_t Performance_dispex = { .id = PROT_Performance, .vtbl = &HTMLPerformance_dispex_vtbl, .disp_tid = IHTMLPerformance_tid, - .iface_tids = Performance_iface_tids, + .init_info = Performance_init_dispex_info, }; HRESULT create_performance(HTMLInnerWindow *window, IHTMLPerformance **ret) @@ -2459,3 +2765,325 @@ HRESULT create_media_query_list(HTMLInnerWindow *window, BSTR media_query, IDisp *ret = (IDispatch*)&media_query_list->IWineMSHTMLMediaQueryList_iface; return S_OK; } + +struct crypto_subtle { + DispatchEx dispex; + IWineMSHTMLSubtleCrypto IWineMSHTMLSubtleCrypto_iface; +}; + +static inline struct crypto_subtle *impl_from_IWineMSHTMLSubtleCrypto(IWineMSHTMLSubtleCrypto *iface) +{ + return CONTAINING_RECORD(iface, struct crypto_subtle, IWineMSHTMLSubtleCrypto_iface); +} + +DISPEX_IDISPATCH_IMPL(crypto_subtle, IWineMSHTMLSubtleCrypto, impl_from_IWineMSHTMLSubtleCrypto(iface)->dispex) + +static HRESULT WINAPI crypto_subtle_encrypt(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *key, + VARIANT *data, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p %p)\n", subtle, algorithm, key, data, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_decrypt(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *key, + VARIANT *data, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p %p)\n", subtle, algorithm, key, data, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_sign(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *key, + VARIANT *data, IDispatch **signature) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p %p)\n", subtle, algorithm, key, data, signature); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_verify(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *key, + VARIANT *signature, VARIANT *data, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p %p %p)\n", subtle, algorithm, key, signature, data, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_digest(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *data, + IDispatch **digest) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p)\n", subtle, algorithm, data, digest); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_generateKey(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, + VARIANT_BOOL extractable, VARIANT *keyUsages, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %x %p %p)\n", subtle, algorithm, extractable, keyUsages, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_deriveKey(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *baseKey, + VARIANT *derivedKeyAlgorithm, VARIANT_BOOL extractable, VARIANT *keyUsages, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p %x %p %p)\n", subtle, algorithm, baseKey, derivedKeyAlgorithm, extractable, + keyUsages, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_importKey(IWineMSHTMLSubtleCrypto *iface, BSTR format, VARIANT *keyData, + VARIANT *algorithm, VARIANT_BOOL extractable, VARIANT *keyUsages, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%s %p %p %x %p %p)\n", subtle, debugstr_w(format), keyData, algorithm, extractable, + keyUsages, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_exportKey(IWineMSHTMLSubtleCrypto *iface, BSTR format, VARIANT *key, + IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%s %p %p)\n", subtle, debugstr_w(format), key, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_wrapKey(IWineMSHTMLSubtleCrypto *iface, BSTR format, VARIANT *key, + VARIANT *wrappingKey, VARIANT *wrapAlgo, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%s %p %p %p %p)\n", subtle, debugstr_w(format), key, wrappingKey, wrapAlgo, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_unwrapKey(IWineMSHTMLSubtleCrypto *iface, BSTR format, VARIANT *wrappedKey, + VARIANT *unwrappingKey, VARIANT *unwrapAlgo, VARIANT *unwrappedKeyAlgo, VARIANT_BOOL extractable, + VARIANT *keyUsages, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%s %p %p %p %p %x %p %p)\n", subtle, debugstr_w(format), wrappedKey, unwrappingKey, unwrapAlgo, + unwrappedKeyAlgo, extractable, keyUsages, result); + + return E_NOTIMPL; +} + +static const IWineMSHTMLSubtleCryptoVtbl WineMSHTMLSubtleCryptoVtbl = { + crypto_subtle_QueryInterface, + crypto_subtle_AddRef, + crypto_subtle_Release, + crypto_subtle_GetTypeInfoCount, + crypto_subtle_GetTypeInfo, + crypto_subtle_GetIDsOfNames, + crypto_subtle_Invoke, + crypto_subtle_encrypt, + crypto_subtle_decrypt, + crypto_subtle_sign, + crypto_subtle_verify, + crypto_subtle_digest, + crypto_subtle_generateKey, + crypto_subtle_deriveKey, + crypto_subtle_importKey, + crypto_subtle_exportKey, + crypto_subtle_wrapKey, + crypto_subtle_unwrapKey +}; + +static inline struct crypto_subtle *crypto_subtle_from_DispatchEx(DispatchEx *iface) +{ + return CONTAINING_RECORD(iface, struct crypto_subtle, dispex); +} + +static void *crypto_subtle_query_interface(DispatchEx *dispex, REFIID riid) +{ + struct crypto_subtle *subtle = crypto_subtle_from_DispatchEx(dispex); + + if(IsEqualGUID(&IID_IWineMSHTMLSubtleCrypto, riid)) + return &subtle->IWineMSHTMLSubtleCrypto_iface; + + return NULL; +} + +static void crypto_subtle_destructor(DispatchEx *dispex) +{ + struct crypto_subtle *subtle = crypto_subtle_from_DispatchEx(dispex); + free(subtle); +} + +static const dispex_static_data_vtbl_t crypto_subtle_dispex_vtbl = { + .query_interface = crypto_subtle_query_interface, + .destructor = crypto_subtle_destructor +}; + +static const tid_t crypto_subtle_iface_tids[] = { + IWineMSHTMLSubtleCrypto_tid, + 0 +}; +dispex_static_data_t SubtleCrypto_dispex = { + .id = PROT_SubtleCrypto, + .vtbl = &crypto_subtle_dispex_vtbl, + .disp_tid = IWineMSHTMLSubtleCrypto_tid, + .iface_tids = crypto_subtle_iface_tids, + .min_compat_mode = COMPAT_MODE_IE11, +}; + +struct crypto { + DispatchEx dispex; + IWineMSHTMLCrypto IWineMSHTMLCrypto_iface; + struct crypto_subtle *subtle; +}; + +static inline struct crypto *impl_from_IWineMSHTMLCrypto(IWineMSHTMLCrypto *iface) +{ + return CONTAINING_RECORD(iface, struct crypto, IWineMSHTMLCrypto_iface); +} + +DISPEX_IDISPATCH_IMPL(crypto, IWineMSHTMLCrypto, impl_from_IWineMSHTMLCrypto(iface)->dispex) + +static HRESULT WINAPI crypto_get_subtle(IWineMSHTMLCrypto *iface, IDispatch **subtle) +{ + struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + + TRACE("(%p)->(%p)\n", crypto, subtle); + + *subtle = (IDispatch*)&crypto->subtle->dispex.IWineJSDispatchHost_iface; + IWineMSHTMLSubtleCrypto_AddRef(&crypto->subtle->IWineMSHTMLSubtleCrypto_iface); + return S_OK; +} + +static HRESULT WINAPI crypto_getRandomValues(IWineMSHTMLCrypto *iface, VARIANT *typedArray, IDispatch **ret) +{ + struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + HRESULT hres; + + TRACE("(%p)->(%p %p)\n", crypto, typedArray, ret); + + if(V_VT(typedArray) != VT_DISPATCH || !V_DISPATCH(typedArray)) + return E_INVALIDARG; + + hres = IWineJSDispatch_GetRandomValues(crypto->dispex.jsdisp, V_DISPATCH(typedArray)); + if(SUCCEEDED(hres) && ret) { + *ret = V_DISPATCH(typedArray); + IDispatch_AddRef(*ret); + } + return hres; +} + +static const IWineMSHTMLCryptoVtbl WineMSHTMLCryptoVtbl = { + crypto_QueryInterface, + crypto_AddRef, + crypto_Release, + crypto_GetTypeInfoCount, + crypto_GetTypeInfo, + crypto_GetIDsOfNames, + crypto_Invoke, + crypto_get_subtle, + crypto_getRandomValues +}; + +static inline struct crypto *crypto_from_DispatchEx(DispatchEx *iface) +{ + return CONTAINING_RECORD(iface, struct crypto, dispex); +} + +static void *crypto_query_interface(DispatchEx *dispex, REFIID riid) +{ + struct crypto *This = crypto_from_DispatchEx(dispex); + + if(IsEqualGUID(&IID_IWineMSHTMLCrypto, riid)) + return &This->IWineMSHTMLCrypto_iface; + + return NULL; +} + +static void crypto_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCallback *cb) +{ + struct crypto *This = crypto_from_DispatchEx(dispex); + + if(This->subtle) + note_cc_edge((nsISupports*)&This->subtle->dispex.IWineJSDispatchHost_iface, "subtle", cb); +} + +static void crypto_unlink(DispatchEx *dispex) +{ + struct crypto *This = crypto_from_DispatchEx(dispex); + + if(This->subtle) { + struct crypto_subtle *subtle = This->subtle; + This->subtle = NULL; + IWineJSDispatchHost_Release(&subtle->dispex.IWineJSDispatchHost_iface); + } +} + +static void crypto_destructor(DispatchEx *dispex) +{ + struct crypto *This = crypto_from_DispatchEx(dispex); + free(This); +} + +static const dispex_static_data_vtbl_t crypto_dispex_vtbl = { + .query_interface = crypto_query_interface, + .destructor = crypto_destructor, + .traverse = crypto_traverse, + .unlink = crypto_unlink +}; + +static const tid_t crypto_iface_tids[] = { + IWineMSHTMLCrypto_tid, + 0 +}; +dispex_static_data_t Crypto_dispex = { + .id = PROT_Crypto, + .vtbl = &crypto_dispex_vtbl, + .disp_tid = IWineMSHTMLCrypto_tid, + .iface_tids = crypto_iface_tids, + .min_compat_mode = COMPAT_MODE_IE11, +}; + +HRESULT create_crypto(HTMLInnerWindow *window, IWineMSHTMLCrypto **ret) +{ + compat_mode_t compat_mode = dispex_compat_mode(&window->event_target.dispex); + struct crypto_subtle *subtle; + struct crypto *crypto; + + if(!(crypto = calloc(1, sizeof(*crypto)))) + return E_OUTOFMEMORY; + if(!(subtle = calloc(1, sizeof(*subtle)))) { + free(crypto); + return E_OUTOFMEMORY; + } + + crypto->IWineMSHTMLCrypto_iface.lpVtbl = &WineMSHTMLCryptoVtbl; + crypto->subtle = subtle; + init_dispatch(&crypto->dispex, &Crypto_dispex, window, compat_mode); + + subtle->IWineMSHTMLSubtleCrypto_iface.lpVtbl = &WineMSHTMLSubtleCryptoVtbl; + init_dispatch(&subtle->dispex, &SubtleCrypto_dispex, window, compat_mode); + + *ret = &crypto->IWineMSHTMLCrypto_iface; + return S_OK; +} diff --git a/dlls/mshtml/pluginhost.c b/dlls/mshtml/pluginhost.c index c4a580ea4eb9..03959266f1f2 100644 --- a/dlls/mshtml/pluginhost.c +++ b/dlls/mshtml/pluginhost.c @@ -835,7 +835,7 @@ HRESULT HTMLPluginContainer_get_prop_desc(DispatchEx *dispex, DISPID id, struct desc->id = id; desc->flags = 0; desc->name = plugin_container->props[id - MSHTML_DISPID_CUSTOM_MIN]->name; - desc->iid = 0; + desc->prototype_id = 0; return S_OK; } diff --git a/dlls/mshtml/range.c b/dlls/mshtml/range.c index f10a42a895db..fdd39f65615f 100644 --- a/dlls/mshtml/range.c +++ b/dlls/mshtml/range.c @@ -503,7 +503,7 @@ static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf) if(buf->len) { WCHAR *p; - for(p = buf->buf+buf->len-1; p >= buf->buf && iswspace(*p); p--); + for(p = buf->buf+buf->len-1; p > buf->buf && iswspace(*p); p--); p = wcschr(p, '\r'); if(p) diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 3ad1da8cf3ca..a6ebb4a266d1 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -419,7 +419,7 @@ static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPC if(wcscmp(pstrName, L"window")) return DISP_E_MEMBERNOTFOUND; - if(!This->window || !This->window->base.outer_window) + if(!This->window || is_detached_window(This->window)) return E_FAIL; if(dispex_compat_mode(&This->window->event_target.dispex) >= COMPAT_MODE_IE9) @@ -565,7 +565,7 @@ static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow * TRACE("(%p)->(%p)\n", This, phwnd); - if(!This->window || !This->window->base.outer_window) + if(!This->window || is_detached_window(This->window)) return E_UNEXPECTED; *phwnd = This->window->base.outer_window->browser->doc->hwnd; @@ -1433,7 +1433,7 @@ static ScriptHost *get_script_host(HTMLInnerWindow *window, const GUID *guid) void initialize_script_global(HTMLInnerWindow *script_global) { - if(!script_global->base.outer_window) + if(is_detached_window(script_global)) return; get_script_host(script_global, &CLSID_JScript); } diff --git a/dlls/mshtml/task.c b/dlls/mshtml/task.c index 955567eaabba..e9f4a0e53e3e 100644 --- a/dlls/mshtml/task.c +++ b/dlls/mshtml/task.c @@ -33,6 +33,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); #define WM_PROCESSTASK 0x8008 +#define WM_CREATEDOC 0x8018 #define TIMER_ID 0x3000 typedef struct { @@ -378,6 +379,13 @@ static LRESULT process_timer(void) return 0; } +typedef struct { + IUnknown *unk; + IID iid; + IStream *stream; + HRESULT hres; +} create_doc_params_t; + static LRESULT WINAPI hidden_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { thread_data_t *thread_data; @@ -423,6 +431,20 @@ static LRESULT WINAPI hidden_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPa return 0; case WM_TIMER: return process_timer(); + case WM_CREATEDOC: { + create_doc_params_t *params = (create_doc_params_t*)lParam; + IUnknown *unk; + + TRACE("WM_CREATEDOC %p\n", params); + + params->hres = HTMLDocument_Create(NULL, ¶ms->iid, (void**)&unk); + if(FAILED(params->hres)) + return 0; + + params->hres = CoMarshalInterface(params->stream, ¶ms->iid, unk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + IUnknown_Release(unk); + return 0; + } } if(msg > WM_USER) @@ -465,6 +487,35 @@ HWND get_thread_hwnd(void) return thread_data->thread_hwnd; } +HRESULT create_marshaled_doc(HWND main_thread_hwnd, REFIID riid, void **ppv) +{ + create_doc_params_t params = {NULL, *riid, NULL, E_FAIL}; + LARGE_INTEGER zero; + BOOL res; + HRESULT hres; + + hres = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); + if(FAILED(hres)) + return hres; + + res = SendMessageW(main_thread_hwnd, WM_CREATEDOC, 0, (LPARAM)¶ms); + TRACE("SendMessage ret %x\n", res); + if(FAILED(params.hres)) { + WARN("EM_CREATEDOC failed: %08lx\n", params.hres); + IStream_Release(params.stream); + return hres; + } + + zero.QuadPart = 0; + hres = IStream_Seek(params.stream, zero, STREAM_SEEK_SET, NULL); + if(SUCCEEDED(hres)) + hres = CoUnmarshalInterface(params.stream, riid, ppv); + IStream_Release(params.stream); + if(FAILED(hres)) + WARN("CoUnmarshalInterface failed: %08lx\n", hres); + return hres; +} + thread_data_t *get_thread_data(BOOL create) { thread_data_t *thread_data; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 164f5e2bce40..d01085258210 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -83,6 +83,115 @@ if(window.addEventListener) { document.attachEvent("onunload", function() { ok(false, "unload fired on document"); }); } +sync_test("window own props", function() { + if(!Object.getOwnPropertyNames) + return; + + test_own_props(window, "window", [ + ["ANGLE_instanced_arrays",11], "ActiveXObject", ["AesGcmEncryptResult",11], ["AnimationEvent",10], ["ApplicationCache",10], "Array", ["ArrayBuffer",10], "Attr", + "Audio", ["AudioTrack",10], ["AudioTrackList",10], "BeforeUnloadEvent", ["Blob",10], "BookmarkCollection", "Boolean", "CDATASection", "CSSFontFaceRule", "CSSImportRule", + ["CSSKeyframeRule",10], ["CSSKeyframesRule",10], "CSSMediaRule", "CSSNamespaceRule", "CSSPageRule", "CSSRule", "CSSRuleList", "CSSStyleDeclaration", "CSSStyleRule", + "CSSStyleSheet", "CanvasGradient", "CanvasPattern", "CanvasPixelArray", "CanvasRenderingContext2D", "CharacterData", "ClientRect", "ClientRectList", ["CloseEvent",10], + "CollectGarbage", "Comment", "CompositionEvent", ["Console",10], "ControlRangeCollection", "Coordinates", ["Crypto",11], ["CryptoOperation",11], "CustomEvent", + ["DOMError",10], "DOMException", "DOMImplementation", "DOMParser", ["DOMSettableTokenList",10], ["DOMStringList",10], ["DOMStringMap",11], ["DOMTokenList",10], + "DataTransfer", ["DataView",10], "Date", "Debug", ["DeviceAcceleration",11], ["DeviceMotionEvent",11], ["DeviceOrientationEvent",11], ["DeviceRotationRate",11], + "Document", "DocumentFragment", "DocumentType", "DragEvent", ["EXT_texture_filter_anisotropic",11], "Element", "Enumerator", "Error", ["ErrorEvent",10], "EvalError", + "Event", "EventException", ["File",10], ["FileList",10], ["FileReader",10], ["Float32Array",10], ["Float64Array",10], "FocusEvent", ["FormData",10], "Function", + "Geolocation", ["HTMLAllCollection",11], "HTMLAnchorElement", "HTMLAppletElement", "HTMLAreaElement", "HTMLAreasCollection", "HTMLAudioElement", "HTMLBGSoundElement", + "HTMLBRElement", "HTMLBaseElement", "HTMLBaseFontElement", "HTMLBlockElement", "HTMLBodyElement", "HTMLButtonElement", "HTMLCanvasElement", "HTMLCollection", + "HTMLDDElement", "HTMLDListElement", "HTMLDTElement", ["HTMLDataListElement",10], "HTMLDirectoryElement", "HTMLDivElement", ["HTMLDocument",11], "HTMLElement", + "HTMLEmbedElement", "HTMLFieldSetElement", "HTMLFontElement", "HTMLFormElement", "HTMLFrameElement", "HTMLFrameSetElement", "HTMLHRElement", "HTMLHeadElement", + "HTMLHeadingElement", "HTMLHtmlElement", "HTMLIFrameElement", "HTMLImageElement", "HTMLInputElement", "HTMLIsIndexElement", "HTMLLIElement", "HTMLLabelElement", + "HTMLLegendElement", "HTMLLinkElement", "HTMLMapElement", "HTMLMarqueeElement", "HTMLMediaElement", "HTMLMenuElement", "HTMLMetaElement", "HTMLModElement", + "HTMLNextIdElement", "HTMLOListElement", "HTMLObjectElement", "HTMLOptGroupElement", "HTMLOptionElement", "HTMLParagraphElement", "HTMLParamElement", "HTMLPhraseElement", + "HTMLPreElement", ["HTMLProgressElement",10], "HTMLQuoteElement", "HTMLScriptElement", "HTMLSelectElement", "HTMLSourceElement", "HTMLSpanElement", "HTMLStyleElement", + "HTMLTableCaptionElement", "HTMLTableCellElement", "HTMLTableColElement", "HTMLTableDataCellElement", "HTMLTableElement", "HTMLTableHeaderCellElement", + "HTMLTableRowElement", "HTMLTableSectionElement", "HTMLTextAreaElement", "HTMLTitleElement", ["HTMLTrackElement",10], "HTMLUListElement", "HTMLUnknownElement", + "HTMLVideoElement", "History", ["IDBCursor",10], ["IDBCursorWithValue",10], ["IDBDatabase",10], ["IDBFactory",10], ["IDBIndex",10], ["IDBKeyRange",10], + ["IDBObjectStore",10], ["IDBOpenDBRequest",10], ["IDBRequest",10], ["IDBTransaction",10], ["IDBVersionChangeEvent",10], "Image", "ImageData", "Infinity", + ["Int16Array",10], ["Int32Array",10], ["Int8Array",10], ["Intl",11], "JSON", ["Key",11], ["KeyOperation",11], ["KeyPair",11], "KeyboardEvent", "Location", + "MSBehaviorUrnsCollection", ["MSBlobBuilder",10], ["MSCSSMatrix",10], "MSCSSProperties", "MSCSSRuleList", "MSCompatibleInfo", "MSCompatibleInfoCollection", + "MSCurrentStyleCSSProperties", "MSEventObj", ["MSGesture",10], ["MSGestureEvent",10], ["MSGraphicsTrust",11], ["MSInputMethodContext",11], ["MSManipulationEvent",10], + ["MSMediaKeyError",11], ["MSMediaKeyMessageEvent",11], ["MSMediaKeyNeededEvent",11], ["MSMediaKeySession",11], ["MSMediaKeys",11], "MSMimeTypesCollection", + ["MSNamespaceInfo",0,9], ["MSNamespaceInfoCollection",0,9], "MSPluginsCollection", ["MSPointerEvent",10], ["MSPopupWindow",0,10], ["MSRangeCollection",10], + ["MSSelection",0,10], "MSSiteModeEvent", ["MSStream",10], ["MSStreamReader",10], "MSStyleCSSProperties", ["Map",11], "Math", "MediaError", "MediaList", + ["MediaQueryList",10], ["MediaSource",11], ["MessageChannel",10], "MessageEvent", ["MessagePort",10], ["MimeType",11], ["MimeTypeArray",11], "MouseEvent", + "MouseWheelEvent", "MutationEvent", ["MutationObserver",11], ["MutationRecord",11], "NaN", "NamedNodeMap", "Navigator", "Node", "NodeFilter", "NodeIterator", "NodeList", + "Number", ["OES_element_index_uint",11], ["OES_standard_derivatives",11], ["OES_texture_float",11], ["OES_texture_float_linear",11], "Object", "Option", + ["PageTransitionEvent",11], "Performance", "PerformanceEntry", "PerformanceMark", "PerformanceMeasure", "PerformanceNavigation", ["PerformanceNavigationTiming",11], + "PerformanceResourceTiming", "PerformanceTiming", ["Plugin",11], ["PluginArray",11], ["PointerEvent",11], ["PopStateEvent",10], "Position", "PositionError", + "ProcessingInstruction", ["ProgressEvent",10], "Range", "RangeError", "RangeException", "ReferenceError", "RegExp", "SVGAElement", "SVGAngle", "SVGAnimatedAngle", + "SVGAnimatedBoolean", "SVGAnimatedEnumeration", "SVGAnimatedInteger", "SVGAnimatedLength", "SVGAnimatedLengthList", "SVGAnimatedNumber", "SVGAnimatedNumberList", + "SVGAnimatedPreserveAspectRatio", "SVGAnimatedRect", "SVGAnimatedString", "SVGAnimatedTransformList", "SVGCircleElement", "SVGClipPathElement", + ["SVGComponentTransferFunctionElement",10], "SVGDefsElement", "SVGDescElement", "SVGElement", "SVGElementInstance", "SVGElementInstanceList", "SVGEllipseElement", + "SVGException", ["SVGFEBlendElement",10], ["SVGFEColorMatrixElement",10], ["SVGFEComponentTransferElement",10], ["SVGFECompositeElement",10], + ["SVGFEConvolveMatrixElement",10], ["SVGFEDiffuseLightingElement",10], ["SVGFEDisplacementMapElement",10], ["SVGFEDistantLightElement",10], ["SVGFEFloodElement",10], + ["SVGFEFuncAElement",10], ["SVGFEFuncBElement",10], ["SVGFEFuncGElement",10], ["SVGFEFuncRElement",10], ["SVGFEGaussianBlurElement",10], ["SVGFEImageElement",10], + ["SVGFEMergeElement",10], ["SVGFEMergeNodeElement",10], ["SVGFEMorphologyElement",10], ["SVGFEOffsetElement",10], ["SVGFEPointLightElement",10], + ["SVGFESpecularLightingElement",10], ["SVGFESpotLightElement",10], ["SVGFETileElement",10], ["SVGFETurbulenceElement",10], ["SVGFilterElement",10], "SVGGElement", + "SVGGradientElement", "SVGImageElement", "SVGLength", "SVGLengthList", "SVGLineElement", "SVGLinearGradientElement", "SVGMarkerElement", "SVGMaskElement", "SVGMatrix", + "SVGMetadataElement", "SVGNumber", "SVGNumberList", "SVGPathElement", "SVGPathSeg", "SVGPathSegArcAbs", "SVGPathSegArcRel", "SVGPathSegClosePath", "SVGPathSegCurvetoCubicAbs", + "SVGPathSegCurvetoCubicRel", "SVGPathSegCurvetoCubicSmoothAbs", "SVGPathSegCurvetoCubicSmoothRel", "SVGPathSegCurvetoQuadraticAbs", "SVGPathSegCurvetoQuadraticRel", + "SVGPathSegCurvetoQuadraticSmoothAbs", "SVGPathSegCurvetoQuadraticSmoothRel", "SVGPathSegLinetoAbs", "SVGPathSegLinetoHorizontalAbs", "SVGPathSegLinetoHorizontalRel", + "SVGPathSegLinetoRel", "SVGPathSegLinetoVerticalAbs", "SVGPathSegLinetoVerticalRel", "SVGPathSegList", "SVGPathSegMovetoAbs", "SVGPathSegMovetoRel", "SVGPatternElement", + "SVGPoint", "SVGPointList", "SVGPolygonElement", "SVGPolylineElement", "SVGPreserveAspectRatio", "SVGRadialGradientElement", "SVGRect", "SVGRectElement", "SVGSVGElement", + "SVGScriptElement", "SVGStopElement", "SVGStringList", "SVGStyleElement", "SVGSwitchElement", "SVGSymbolElement", "SVGTSpanElement", "SVGTextContentElement", "SVGTextElement", + "SVGTextPathElement", "SVGTextPositioningElement", "SVGTitleElement", "SVGTransform", "SVGTransformList", "SVGUnitTypes", "SVGUseElement", "SVGViewElement", "SVGZoomAndPan", + "SVGZoomEvent", "Screen", "ScriptEngine", "ScriptEngineBuildVersion", "ScriptEngineMajorVersion", "ScriptEngineMinorVersion", "Selection", ["Set",11], ["SourceBuffer",11], + ["SourceBufferList",11], "Storage", "StorageEvent", "String", "StyleMedia", "StyleSheet", "StyleSheetList", "StyleSheetPageList", ["SubtleCrypto",11], "SyntaxError", "Text", + "TextEvent", "TextMetrics", "TextRange", "TextRangeCollection", ["TextTrack",10], ["TextTrackCue",10], ["TextTrackCueList",10], ["TextTrackList",10], "TimeRanges", + ["TrackEvent",10], ["TransitionEvent",10], "TreeWalker", "TypeError", "UIEvent", "URIError", ["URL",10], ["Uint16Array",10], ["Uint32Array",10], ["Uint8Array",10], + ["Uint8ClampedArray",11], "VBArray", ["ValidityState",10], ["VideoPlaybackQuality",11], ["WEBGL_compressed_texture_s3tc",11], ["WEBGL_debug_renderer_info",11], ["WeakMap",11], + ["WebGLActiveInfo",11], ["WebGLBuffer",11], ["WebGLContextEvent",11], ["WebGLFramebuffer",11], ["WebGLObject",11], ["WebGLProgram",11], ["WebGLRenderbuffer",11], + ["WebGLRenderingContext",11], ["WebGLShader",11], ["WebGLShaderPrecisionFormat",11], ["WebGLTexture",11], ["WebGLUniformLocation",11], ["WebSocket",10], "WheelEvent", "Window", + ["Worker",10], ["XDomainRequest",0,10], ["XMLDocument",11], "XMLHttpRequest", ["XMLHttpRequestEventTarget",10], "XMLSerializer", "async_test", "broken", + "compat_version", "decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent", "escape", "eval", "file_prefix", "format_message", "func_scope_val", "func_scope_val2", + "guard", "isFinite", "isNaN", "next_test", "ok", "pagehide_fired", "pageshow_fired", "parseFloat", "parseInt", "ready_states", "reportSuccess", "run_tests", "svg_ns", + "sync_test", "test_name", "test_own_props", "tests", "todo_wine", "todo_wine_if", "trace", "undefined", "unescape", "win_skip" + ], [ + ["AesGcmEncryptResult",11], ["ANGLE_instanced_arrays",11], ["AnimationEvent",10], ["ApplicationCache",10], ["ArrayBuffer",9,9], "Audio", ["AudioTrack",10], ["AudioTrackList",10], + "BeforeUnloadEvent", ["Blob",10], "BookmarkCollection", "CanvasGradient", "CanvasPattern", "CanvasPixelArray", "CanvasRenderingContext2D", "CDATASection", ["CloseEvent",10], + "CompositionEvent", "ControlRangeCollection", "Coordinates", ["CryptoOperation",11], "CSSFontFaceRule", "CSSImportRule", ["CSSKeyframeRule",10], ["CSSKeyframesRule",10], "CSSMediaRule", + "CSSNamespaceRule", "CSSPageRule", "CSSRuleList", "DataTransfer", ["DataView",9,9], "Debug", ["DeviceAcceleration",11], ["DeviceMotionEvent",11], ["DeviceOrientationEvent",11], + ["DeviceRotationRate",11], ["DOMError",10], "DOMException", ["DOMSettableTokenList",10], ["DOMStringList",10], ["DOMStringMap",11], "DragEvent", ["ErrorEvent",10], "EventException", + ["EXT_texture_filter_anisotropic",11], ["File",10], ["FileList",10], ["FileReader",10], ["Float32Array",9,9], ["Float64Array",9,9], "FocusEvent", ["FormData",10], "Geolocation", "GetObject", + ["HTMLAllCollection",11], "HTMLAppletElement", "HTMLAreasCollection", "HTMLAudioElement", "HTMLBaseElement", "HTMLBaseFontElement", "HTMLBGSoundElement", "HTMLBlockElement", "HTMLBRElement", + "HTMLCanvasElement", ["HTMLDataListElement",10], "HTMLDDElement", "HTMLDirectoryElement", "HTMLDivElement", "HTMLDListElement", "HTMLDTElement", "HTMLFieldSetElement", "HTMLFontElement", + "HTMLFrameSetElement", "HTMLHeadingElement", "HTMLHRElement", "HTMLIsIndexElement", "HTMLLegendElement", "HTMLLIElement", "HTMLMapElement", "HTMLMarqueeElement", "HTMLMediaElement", + "HTMLMenuElement", "HTMLModElement", "HTMLNextIdElement", "HTMLOListElement", "HTMLOptGroupElement", "HTMLParagraphElement", "HTMLParamElement", "HTMLPhraseElement", "HTMLPreElement", + ["HTMLProgressElement",10], "HTMLQuoteElement", "HTMLSourceElement", "HTMLSpanElement", "HTMLTableCaptionElement", "HTMLTableColElement", "HTMLTableHeaderCellElement", + "HTMLTableSectionElement", ["HTMLTrackElement",10], "HTMLUListElement", "HTMLVideoElement", ["IDBCursor",10], ["IDBCursorWithValue",10], ["IDBDatabase",10], ["IDBFactory",10], ["IDBIndex",10], + ["IDBKeyRange",10], ["IDBObjectStore",10], ["IDBOpenDBRequest",10], ["IDBRequest",10], ["IDBTransaction",10], ["IDBVersionChangeEvent",10], "ImageData", ["Int16Array",9,9], ["Int32Array",9,9], + ["Int8Array",9,9], ["Intl",11], ["Key",11], ["KeyOperation",11], ["KeyPair",11], "Location", "MediaError", "MediaList", ["MediaSource",11], ["MessageChannel",10], ["MessagePort",10], + ["MimeType",11], ["MimeTypeArray",9,10], "MouseWheelEvent", "MSBehaviorUrnsCollection", ["MSBlobBuilder",10], "MSCompatibleInfo", "MSCompatibleInfoCollection", ["MSCSSMatrix",10], + ["MSGesture",10], ["MSGestureEvent",10], ["MSGraphicsTrust",11], ["MSInputMethodContext",11], ["MSManipulationEvent",10], ["MSMediaKeyError",11], ["MSMediaKeyMessageEvent",11], + ["MSMediaKeyNeededEvent",11], ["MSMediaKeys",11], ["MSMediaKeySession",11], "MSMimeTypesCollection", ["MSNamespaceInfo",0,9], "MSPluginsCollection", ["MSPointerEvent",10], + ["MSPopupWindow",0,10], ["MSRangeCollection",10], "MSSiteModeEvent", ["MSStream",10], ["MSStreamReader",10], "MutationEvent", ["MutationRecord",11], "NodeFilter", "NodeIterator", + ["OES_element_index_uint",11], ["OES_standard_derivatives",11], ["OES_texture_float",11], ["OES_texture_float_linear",11], "PerformanceEntry", "PerformanceMark", "PerformanceMeasure", + ["PerformanceNavigationTiming",11], "PerformanceResourceTiming", ["Plugin",11], ["PluginArray",9,10], ["PointerEvent",11], ["PopStateEvent",10], "Position", "PositionError", + "ProcessingInstruction", "RangeException", "RegExpError", "Selection", ["SourceBuffer",11], ["SourceBufferList",11], "StyleMedia", "StyleSheetPageList", "SVGAElement", "SVGAngle", + "SVGAnimatedAngle", "SVGAnimatedBoolean", "SVGAnimatedEnumeration", "SVGAnimatedInteger", "SVGAnimatedLength", "SVGAnimatedLengthList", "SVGAnimatedNumber", "SVGAnimatedNumberList", + "SVGAnimatedPreserveAspectRatio", "SVGAnimatedRect", "SVGAnimatedString", "SVGAnimatedTransformList", "SVGClipPathElement", ["SVGComponentTransferFunctionElement",10], "SVGDefsElement", + "SVGDescElement", "SVGElementInstance", "SVGElementInstanceList", "SVGEllipseElement", "SVGException", ["SVGFEBlendElement",10], ["SVGFEColorMatrixElement",10], + ["SVGFEComponentTransferElement",10], ["SVGFECompositeElement",10], ["SVGFEConvolveMatrixElement",10], ["SVGFEDiffuseLightingElement",10], ["SVGFEDisplacementMapElement",10], + ["SVGFEDistantLightElement",10], ["SVGFEFloodElement",10], ["SVGFEFuncAElement",10], ["SVGFEFuncBElement",10], ["SVGFEFuncGElement",10], ["SVGFEFuncRElement",10], + ["SVGFEGaussianBlurElement",10], ["SVGFEImageElement",10], ["SVGFEMergeElement",10], ["SVGFEMergeNodeElement",10], ["SVGFEMorphologyElement",10], ["SVGFEOffsetElement",10], + ["SVGFEPointLightElement",10], ["SVGFESpecularLightingElement",10], ["SVGFESpotLightElement",10], ["SVGFETileElement",10], ["SVGFETurbulenceElement",10], ["SVGFilterElement",10], "SVGGElement", + "SVGGradientElement", "SVGImageElement", "SVGLength", "SVGLengthList", "SVGLinearGradientElement", "SVGLineElement", "SVGMarkerElement", "SVGMaskElement", "SVGMatrix", "SVGMetadataElement", + "SVGNumber", "SVGNumberList", "SVGPathElement", "SVGPathSeg", "SVGPathSegArcAbs", "SVGPathSegArcRel", "SVGPathSegClosePath", "SVGPathSegCurvetoCubicAbs", "SVGPathSegCurvetoCubicRel", + "SVGPathSegCurvetoCubicSmoothAbs", "SVGPathSegCurvetoCubicSmoothRel", "SVGPathSegCurvetoQuadraticAbs", "SVGPathSegCurvetoQuadraticRel", "SVGPathSegCurvetoQuadraticSmoothAbs", + "SVGPathSegCurvetoQuadraticSmoothRel", "SVGPathSegLinetoAbs", "SVGPathSegLinetoHorizontalAbs", "SVGPathSegLinetoHorizontalRel", "SVGPathSegLinetoRel", "SVGPathSegLinetoVerticalAbs", + "SVGPathSegLinetoVerticalRel", "SVGPathSegList", "SVGPathSegMovetoAbs", "SVGPathSegMovetoRel", "SVGPatternElement", "SVGPoint", "SVGPointList", "SVGPolygonElement", "SVGPolylineElement", + "SVGPreserveAspectRatio", "SVGRadialGradientElement", "SVGRect", "SVGRectElement", "SVGScriptElement", "SVGStopElement", "SVGStringList", "SVGStyleElement", "SVGSwitchElement", + "SVGSymbolElement", "SVGTextElement", "SVGTextPathElement", "SVGTitleElement", "SVGTransform", "SVGTransformList", "SVGUnitTypes", "SVGUseElement", "SVGViewElement", "SVGZoomAndPan", + "SVGZoomEvent", "TextEvent", "TextMetrics", "TextRangeCollection", ["TextTrack",10], ["TextTrackCue",10], ["TextTrackCueList",10], ["TextTrackList",10], "TimeRanges", ["TrackEvent",10], + ["TransitionEvent",10], "TreeWalker", ["Uint16Array",9,9], ["Uint32Array",9,9], ["Uint8Array",9,9], ["Uint8ClampedArray",9,10], ["URL",10], ["ValidityState",10], ["VideoPlaybackQuality",11], + ["WebGLActiveInfo",11], ["WebGLBuffer",11], ["WebGLContextEvent",11], ["WebGLFramebuffer",11], ["WebGLObject",11], ["WebGLProgram",11], ["WebGLRenderbuffer",11], ["WebGLRenderingContext",11], + ["WebGLShader",11], ["WebGLShaderPrecisionFormat",11], ["WebGLTexture",11], ["WebGLUniformLocation",11], ["WEBGL_compressed_texture_s3tc",11], ["WEBGL_debug_renderer_info",11], ["WebSocket",10], + "WheelEvent", ["Worker",10], ["XMLHttpRequestEventTarget",10], "XMLSerializer" + ]); +}); + sync_test("performance timing", function() { ok(performance.timing.domInteractive >= performance.timing.domLoading, "domInteractive < domLoading"); ok(performance.timing.domContentLoadedEventStart >= performance.timing.domInteractive, "domContentLoadedEventStart < domInteractive"); @@ -329,10 +438,15 @@ sync_test("builtin_toString", function() { if(v < 11) { test("eventObject", document.createEventObject(), "MSEventObj"); test("selection", document.selection, "MSSelection"); + test("XDomainRequest", new XDomainRequest(), "XDomainRequest"); } if(v >= 9) { test("computedStyle", window.getComputedStyle(e), "CSSStyleDeclaration"); test("doctype", document.doctype, "DocumentType"); + test("domParser", new DOMParser(), "DOMParser"); + test("svgDocument", new DOMParser().parseFromString("foobar", "image/svg+xml"), v < 11 ? "Document" : "XMLDocument"); + test("xhtmlDocument", new DOMParser().parseFromString("foobar", "application/xhtml+xml"), v < 11 ? "Document" : "XMLDocument"); + test("xmlDocument", new DOMParser().parseFromString("foobar", "text/xml"), v < 11 ? "Document" : "XMLDocument"); test("Event", document.createEvent("Event"), "Event"); test("CustomEvent", document.createEvent("CustomEvent"), "CustomEvent"); @@ -346,6 +460,8 @@ sync_test("builtin_toString", function() { test("mediaQueryList", window.matchMedia("(hover:hover)"), "MediaQueryList"); } if(v >= 11) { + test("crypto", window.msCrypto, "Crypto"); + test("crypto.subtle", window.msCrypto.subtle, "SubtleCrypto"); test("MutationObserver", new window.MutationObserver(function() {}), "MutationObserver"); } if(v >= 9) { @@ -387,12 +503,20 @@ sync_test("builtin_obj", function() { window.toString.call(null); ok(false, "expected exception calling window.toString with null context"); }catch(ex) {} + + ok(!Object.hasOwnProperty.call(f, "arguments"), "arguments is a prop of createElement"); + ok(!Object.hasOwnProperty.call(f, "caller"), "caller is a prop of createElement"); + ok(!Object.hasOwnProperty.call(f, "length"), "length is a prop of createElement"); }else { ok(Object.getPrototypeOf(f) === Function.prototype, "unexpected document.createElement prototype"); e = window.toString.call(null); ok(e === "[object Window]", "window.toString with null context = " + e); e = window.toString.call(external.nullDisp); ok(e === "[object Window]", "window.toString with nullDisp context = " + e); + + ok(f.hasOwnProperty("arguments"), "arguments not a prop of createElement"); + ok(f.hasOwnProperty("caller"), "caller not a prop of createElement"); + ok(!f.hasOwnProperty("length"), "length is a prop of createElement"); } e = 0; @@ -694,8 +818,12 @@ sync_test("window_props", function() { test_exposed("performance", true); test_exposed("console", v >= 10); test_exposed("matchMedia", v >= 10); + test_exposed("msCrypto", v >= 11); test_exposed("Document", v >= 9); test_exposed("HTMLDocument", v === 8 || v >= 11, v === 8); + test_exposed("XMLDocument", v >= 11); + test_exposed("DOMParser", v >= 9); + test_exposed("XDomainRequest", v < 11); test_exposed("MutationObserver", v >= 11); test_exposed("PageTransitionEvent", v >= 11); test_exposed("ProgressEvent", v >= 10); @@ -718,6 +846,56 @@ sync_test("domimpl_props", function() { test_exposed("createHTMLDocument", v >= 9); }); +sync_test("perf_props", function() { + var obj = window.performance, name = "Performance"; + var v = document.documentMode; + + function test_exposed(prop, expect) { + if(expect) + ok(prop in obj, prop + " not found in " + name + "."); + else + ok(!(prop in obj), prop + " found in " + name + "."); + } + + test_exposed("navigation", true); + test_exposed("timing", true); + test_exposed("toJSON", v >= 9); + test_exposed("toString", true); + + obj = window.performance.navigation, name = "PerformanceNavigation"; + + test_exposed("redirectCount", true); + test_exposed("type", true); + test_exposed("toJSON", v >= 9); + test_exposed("toString", true); + + obj = window.performance.timing, name = "PerformanceTiming"; + + test_exposed("connectEnd", true); + test_exposed("connectStart", true); + test_exposed("domComplete", true); + test_exposed("domContentLoadedEventEnd", true); + test_exposed("domContentLoadedEventStart", true); + test_exposed("domInteractive", true); + test_exposed("domLoading", true); + test_exposed("domainLookupEnd", true); + test_exposed("domainLookupStart", true); + test_exposed("fetchStart", true); + test_exposed("loadEventEnd", true); + test_exposed("loadEventStart", true); + test_exposed("msFirstPaint", true); + test_exposed("navigationStart", true); + test_exposed("redirectEnd", true); + test_exposed("redirectStart", true); + test_exposed("requestStart", true); + test_exposed("responseEnd", true); + test_exposed("responseStart", true); + test_exposed("unloadEventEnd", true); + test_exposed("unloadEventStart", true); + test_exposed("toJSON", v >= 9); + test_exposed("toString", true); +}); + sync_test("xhr_props", function() { var xhr = new XMLHttpRequest(); @@ -906,6 +1084,22 @@ sync_test("style_props", function() { } }); +sync_test("constructor props", function() { + function test_exposed(constructor, prop, expect) { + if(expect) + ok(prop in window[constructor], prop + " not found in " + constructor + " constructor."); + else + ok(!(prop in window[constructor]), prop + " found in " + constructor + " constructor."); + } + var v = document.documentMode; + + test_exposed("Image", "create", v < 9); + test_exposed("Option", "create", v < 9); + test_exposed("XMLHttpRequest", "create", true); + if(v >= 9) test_exposed("DOMParser", "create", false); + if(v >= 11) test_exposed("MutationObserver", "create", false); +}); + sync_test("createElement_inline_attr", function() { var v = document.documentMode, e, s; @@ -2300,7 +2494,6 @@ async_test("storage events", function() { return; } var s = Object.prototype.toString.call(e); - todo_wine_if(e.target != window && e.target != document). ok(s === "[object StorageEvent]", "Object.toString = " + s); ok(e.key === key, "key = " + e.key + ", expected " + key); ok(e.oldValue === oldValue, "oldValue = " + e.oldValue + ", expected " + oldValue); @@ -3132,6 +3325,13 @@ sync_test("__proto__", function() { ok(e.number === 0xa13b6 - 0x80000000 && e.name === "TypeError", "changing __proto__ on non-extensible object threw exception " + e.number + " (" + e.name + ")"); } + + obj = document.createElement("img"); + obj.__proto__ = ctor.prototype; + document.body.setAttribute.call(obj, "height", "101"); + r = document.body.getAttribute.call(obj, "height"); + ok(r === "101", "getAttribute(height) = " + r); + ok(!("getAttribute" in obj), "getAttribute exposed in obj"); }); sync_test("__defineGetter__", function() { @@ -3317,6 +3517,92 @@ sync_test("__defineSetter__", function() { ok(x.setterVal === 9, "x.setterVal after setting bar = " + x.setterVal); }); +sync_test("Crypto", function() { + var crypto = window.msCrypto, arr, r; + if(!crypto) return; + + ok("subtle" in crypto, "subtle not in crypto"); + ok("getRandomValues" in crypto, "getRandomValues not in crypto"); + ok(!("randomUUID" in crypto), "randomUUID is in crypto"); + + var list = [ "decrypt", "deriveKey", "digest", "encrypt", "exportKey", "generateKey", "importKey", "sign", "unwrapKey", "verify", "wrapKey" ]; + for(var i = 0; i < list.length; i++) + ok(list[i] in crypto.subtle, list[i] + " not in crypto.subtle"); + ok(!("deriveBits" in crypto.subtle), "deriveBits is in crypto.subtle"); + + list = [ + [ "Int8Array", 65536 ], + [ "Uint8Array", 65536 ], + [ "Int16Array", 32768 ], + [ "Uint16Array", 32768 ], + [ "Int32Array", 16384 ], + [ "Uint32Array", 16384 ] + ]; + for(var i = 0; i < list.length; i++) { + var arrType = list[i][0]; + arr = eval(arrType + "(" + list[i][1] + ")"); + + ok(arr[0] === 0, arrType + "[0] = " + arr[0]); + ok(arr[1] === 0, arrType + "[1] = " + arr[1]); + r = crypto.getRandomValues(arr); + ok(r === arr, "getRandomValues returned " + r); + + arr = eval(arrType + "(" + (list[i][1]+1) + ")"); + try { + crypto.getRandomValues(arr); + }catch(ex) { + var n = ex.number >>> 0; + todo_wine. + ok(ex.name === "QuotaExceededError", "getRandomValues(oversized " + arrType + ") threw " + ex.name); + todo_wine. + ok(n === 0, "getRandomValues(oversized " + arrType + ") threw code " + n); + todo_wine. + ok(ex.message === "QuotaExceededError", "getRandomValues(oversized " + arrType + ") threw message " + ex.message); + } + } + + try { + crypto.getRandomValues(null); + ok(false, "getRandomValues(null) did not throw exception"); + }catch(e) { + ok(e.number === 0x70057 - 0x80000000, "getRandomValues(null) threw " + e.number); + } + try { + crypto.getRandomValues(external.nullDisp); + ok(false, "getRandomValues(nullDisp) did not throw exception"); + }catch(e) { + ok(e.number === 0x70057 - 0x80000000, "getRandomValues(nullDisp) threw " + e.number); + } + try { + crypto.getRandomValues([1,2,3]); + ok(false, "getRandomValues([1,2,3]) did not throw exception"); + }catch(e) { + ok(e.number === 0x70057 - 0x80000000, "getRandomValues([1,2,3]) threw " + e.number); + } + arr = Float32Array(2); + try { + crypto.getRandomValues(arr); + ok(false, "getRandomValues(Float32Array) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + todo_wine. + ok(ex.name === "TypeMismatchError", "getRandomValues(Float32Array) threw " + ex.name); + todo_wine. + ok(n === 0, "getRandomValues(Float32Array) threw code " + n); + } + arr = Float64Array(2); + try { + crypto.getRandomValues(arr); + ok(false, "getRandomValues(Float64Array) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + todo_wine. + ok(ex.name === "TypeMismatchError", "getRandomValues(Float64Array) threw " + ex.name); + todo_wine. + ok(n === 0, "getRandomValues(Float64Array) threw code " + n); + } +}); + sync_test("MutationObserver", function() { if (!window.MutationObserver) { return; @@ -3473,6 +3759,7 @@ async_test("postMessage", function() { }); sync_test("form", function() { + var v = document.documentMode; document.body.innerHTML = ""; var form = document.createElement("form"); document.body.appendChild(form); @@ -3484,6 +3771,123 @@ sync_test("form", function() { ok(typeof(form[1]) === "object", "form[1] = " + form[1]); form.innerHTML = ""; ok(form[0] === "test", "form[0] = " + form[0]); + + if(v >= 9) { + var setval; + function getter() { return 42; } + function setter(v) { setval = v + 1; } + + Object.defineProperty(form, "0", { get: getter, set: setter, configurable: true, enumerable: false }); + var desc = Object.getOwnPropertyDescriptor(form, "0"); + ok(desc.value === undefined, "value = " + desc.value); + ok(desc.get === getter, "get = " + desc.get); + ok(desc.set === setter, "set = " + desc.set); + ok(desc.writable === undefined, "writable = " + desc.writable); + ok(desc.enumerable === false, "enumerable = " + desc.enumerable); + ok(desc.configurable === true, "configurable = " + desc.configurable); + ok(form[0] === 42, "form[0] = " + form[0]); + form[0] = 1336; + ok(setval === 1337, "setval = " + setval); + + form.innerHTML = ""; + ok(form.length === 2, "form.length = " + form.length); + ok(typeof(form[0]) === "object", "form[0] = " + form[0]); + form[0] = 32; + ok(setval === 33, "setval = " + setval); + + desc = Object.getOwnPropertyDescriptor(form, "0"); + ok(desc.value === undefined, "[0] value = " + desc.value); + ok(desc.get === getter, "[0] get = " + desc.get); + ok(desc.set === setter, "[0] set = " + desc.set); + ok(desc.writable === undefined, "[0] writable = " + desc.writable); + ok(desc.enumerable === false, "[0] enumerable = " + desc.enumerable); + ok(desc.configurable === true, "[0] configurable = " + desc.configurable); + + desc = Object.getOwnPropertyDescriptor(form, "1"); + ok(typeof(desc.value) === "object", "[1] value = " + desc.value); + ok(desc.get === undefined, "[1] get = " + desc.get); + ok(desc.set === undefined, "[1] set = " + desc.set); + ok(desc.writable === true, "[1] writable = " + desc.writable); + todo_wine. + ok(desc.enumerable === true, "[1] enumerable = " + desc.enumerable); + ok(desc.configurable === true, "[1] configurable = " + desc.configurable); + + form.innerHTML = ""; + desc = Object.getOwnPropertyDescriptor(form, "0"); + ok(desc.value === undefined, "value = " + desc.value); + ok(desc.get === getter, "get = " + desc.get); + ok(desc.set === setter, "set = " + desc.set); + ok(desc.writable === undefined, "writable = " + desc.writable); + ok(desc.enumerable === false, "enumerable = " + desc.enumerable); + ok(desc.configurable === true, "configurable = " + desc.configurable); + ok(form[0] === 42, "form[0] = " + form[0]); + form[0] = 100; + ok(setval === 101, "setval = " + setval); + } +}); + +sync_test("indexed hostobj props", function() { + var v = document.documentMode; + if(v < 9) + return; + function getter() { return 42; } + + function check(obj, value, overridden) { + var name = Object.prototype.toString.call(obj).slice(8, -1); + if(value === null) + ok(typeof(obj[0]) === "object", name + "[0] = " + obj[0]); + else + ok(obj[0] === value, name + "[0] post-del = " + obj[0]); + + Object.defineProperty(obj, "0", { get: getter, set: undefined, configurable: true, enumerable: false }); + var desc = Object.getOwnPropertyDescriptor(obj, "0"); + ok(desc.value === undefined, name + "[0] value = " + desc.value); + ok(desc.get === getter, name + "[0] get = " + desc.get); + ok(desc.set === undefined, name + "[0] set = " + desc.set); + ok(desc.writable === undefined, name + "[0] writable = " + desc.writable); + ok(desc.enumerable === false, name + "[0] enumerable = " + desc.enumerable); + ok(desc.configurable === true, name + "[0] configurable = " + desc.configurable); + + if(!overridden) + ok(obj[0] === 42, name + "[0] = " + obj[0]); + else if(value === null) + ok(typeof(obj[0]) === "object", name + "[0] = " + obj[0]); + else + ok(obj[0] === value, name + "[0] = " + obj[0]); + + delete obj["0"]; + desc = Object.getOwnPropertyDescriptor(obj, "0"); + if(value === null) + ok(typeof(desc.value) === "object", name + "[0] value post-del = " + desc.value); + else + ok(desc.value === value, name + "[0] value post-del = " + desc.value); + ok(desc.get === undefined, name + "[0] get post-del = " + desc.get); + ok(desc.set === undefined, name + "[0] set post-del = " + desc.set); + ok(desc.writable === true, name + "[0] writable post-del = " + desc.writable); + todo_wine. + ok(desc.enumerable === true, name + "[0] enumerable post-del = " + desc.enumerable); + ok(desc.configurable === true, name + "[0] configurable post-del = " + desc.configurable); + if(value === null) + ok(typeof(obj[0]) === "object", name + "[0] post-del = " + obj[0]); + else + ok(obj[0] === value, name + "[0] post-del = " + obj[0]); + ok(obj.hasOwnProperty("0"), "0 not a prop of " + name); + } + + document.body.innerHTML = ""; + var e = document.createElement("select"); + e.innerHTML = '