mirror of
https://abf.rosa.ru/djam/wine2.git
synced 2025-02-23 16:42:54 +00:00
5740 lines
201 KiB
Diff
5740 lines
201 KiB
Diff
From b3ae6362eae622e747cf8ad1ee076898e3536597 Mon Sep 17 00:00:00 2001
|
|
From: Nick Sarnie <commendsarnex@gmail.com>
|
|
Date: Wed, 23 Aug 2017 20:13:00 -0400
|
|
Subject: [PATCH] Wine D3D9
|
|
|
|
Signed-off-by: Nick Sarnie <commendsarnex@gmail.com>
|
|
---
|
|
configure.ac | 188 ++++
|
|
dlls/d3d9-nine/Makefile.in | 15 +
|
|
dlls/d3d9-nine/d3d9-nine.spec | 14 +
|
|
dlls/d3d9-nine/d3d9_main.c | 173 ++++
|
|
dlls/d3d9-nine/d3dadapter9.c | 853 ++++++++++++++++++
|
|
dlls/d3d9-nine/d3dadapter9.h | 32 +
|
|
dlls/d3d9-nine/device_wrap.c | 500 +++++++++++
|
|
dlls/d3d9-nine/device_wrap.h | 26 +
|
|
dlls/d3d9-nine/dri3.c | 1426 ++++++++++++++++++++++++++++++
|
|
dlls/d3d9-nine/dri3.h | 91 ++
|
|
dlls/d3d9-nine/present.c | 1748 +++++++++++++++++++++++++++++++++++++
|
|
dlls/d3d9-nine/present.h | 40 +
|
|
dlls/d3d9-nine/shader_validator.c | 88 ++
|
|
dlls/d3d9-nine/shader_validator.h | 29 +
|
|
dlls/d3d9-nine/version.rc | 26 +
|
|
dlls/d3d9-nine/wndproc.c | 277 ++++++
|
|
dlls/d3d9-nine/wndproc.h | 41 +
|
|
17 files changed, 5567 insertions(+)
|
|
create mode 100644 dlls/d3d9-nine/Makefile.in
|
|
create mode 100644 dlls/d3d9-nine/d3d9-nine.spec
|
|
create mode 100644 dlls/d3d9-nine/d3d9_main.c
|
|
create mode 100644 dlls/d3d9-nine/d3dadapter9.c
|
|
create mode 100644 dlls/d3d9-nine/d3dadapter9.h
|
|
create mode 100644 dlls/d3d9-nine/device_wrap.c
|
|
create mode 100644 dlls/d3d9-nine/device_wrap.h
|
|
create mode 100644 dlls/d3d9-nine/dri3.c
|
|
create mode 100644 dlls/d3d9-nine/dri3.h
|
|
create mode 100644 dlls/d3d9-nine/present.c
|
|
create mode 100644 dlls/d3d9-nine/present.h
|
|
create mode 100644 dlls/d3d9-nine/shader_validator.c
|
|
create mode 100644 dlls/d3d9-nine/shader_validator.h
|
|
create mode 100644 dlls/d3d9-nine/version.rc
|
|
create mode 100644 dlls/d3d9-nine/wndproc.c
|
|
create mode 100644 dlls/d3d9-nine/wndproc.h
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index fd05212057..6b96bdd209 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -66,6 +66,14 @@ AC_ARG_WITH(openal, AS_HELP_STRING([--without-openal],[do not use OpenAL]),
|
|
AC_ARG_WITH(opencl, AS_HELP_STRING([--without-opencl],[do not use OpenCL]),
|
|
[if test "x$withval" = "xno"; then ac_cv_header_CL_cl_h=no; ac_cv_header_OpenCL_opencl_h=no; fi])
|
|
AC_ARG_WITH(opengl, AS_HELP_STRING([--without-opengl],[do not use OpenGL]))
|
|
+AC_ARG_WITH(d3d9-nine, AS_HELP_STRING([--without-d3d9-nine],[do not build d3d9-nine.dll (Gallium Nine support)]),
|
|
+ [], [with_d3d9_nine=auto])
|
|
+AC_ARG_WITH(d3d9-nine-module, AS_HELP_STRING([--with-d3d9-nine-module],
|
|
+ [Gallium Nine module location. Can be 'manual' (path to be filled in a register), 'auto' (default. use pkgconfig to detect the location) or a path]),
|
|
+ [], [with_d3d9_nine_module=auto])
|
|
+AC_ARG_WITH(d3d9-nine-headers-path, AS_HELP_STRING([--with-d3d9-nine-headers-path],
|
|
+ [Gallium Nine headers location. Can be 'auto' (default. use pkgconfig to detect the location) or a path]),
|
|
+ [], [with_d3d9_nine_headers_path=auto])
|
|
AC_ARG_WITH(osmesa, AS_HELP_STRING([--without-osmesa],[do not use the OSMesa library]))
|
|
AC_ARG_WITH(oss, AS_HELP_STRING([--without-oss],[do not use the OSS sound support]))
|
|
AC_ARG_WITH(pcap, AS_HELP_STRING([--without-pcap],[do not use the Packet Capture library]),
|
|
@@ -390,6 +398,8 @@ AC_CHECK_LIB(ossaudio,_oss_ioctl)
|
|
|
|
AC_SUBST(OPENGL_LIBS,"")
|
|
|
|
+AC_SUBST(D3D9NINE_LIBS,"")
|
|
+
|
|
dnl **** Check for header files ****
|
|
|
|
AC_SYS_LARGEFILE()
|
|
@@ -1247,6 +1257,183 @@ OpenGL and Direct3D won't be supported.])
|
|
WINE_NOTICE_WITH(va,[test "x$ac_cv_lib_soname_va" = "x" -o "x$ac_cv_lib_soname_va_x11" = "x" -o "x$ac_cv_lib_soname_va_drm" = "x"],
|
|
[libva ${notice_platform}development files not found, GPU video acceleration won't be supported.])
|
|
|
|
+ dnl Check for d3d9-nine support
|
|
+ if test "x$with_d3d9_nine" = "xauto" && (test "x$with_d3d9_nine_module" = "xauto" || test "x$with_d3d9_nine_headers_path" = "xauto")
|
|
+ then
|
|
+ AC_MSG_CHECKING([whether d3dadapter9 package (Gallium Nine) is present])
|
|
+ D3DADAPTER9_MODULEDIR=`$PKG_CONFIG --variable=moduledir d3dadapter9 2>/dev/null`
|
|
+ D3DADAPTER9_LEGACY_MODULEDIR=`$PKG_CONFIG --variable=moduledir d3d 2>/dev/null`
|
|
+ if test "x$D3DADAPTER9_MODULEDIR" = "x" -a "x$D3DADAPTER9_LEGACY_MODULEDIR" = "x"
|
|
+ then
|
|
+ AC_MSG_RESULT([no, disabling support])
|
|
+ with_d3d9_nine=no
|
|
+ else
|
|
+ AC_MSG_RESULT([yes])
|
|
+ fi
|
|
+ fi
|
|
+
|
|
+ if test "x$with_d3d9_nine" != "xno"
|
|
+ then
|
|
+ AC_MSG_NOTICE([Checking for d3dadapter9 library dependencies])
|
|
+ D3D9NINE_LIBS=""
|
|
+ D3D9NINE_MISSING_LIBS=""
|
|
+ AC_CHECK_LIB(xcb,xcb_request_check,[AC_SUBST(D3D9NINE_LIBS,["$D3D9NINE_LIBS -lxcb"])])
|
|
+ test "x$ac_cv_lib_xcb_xcb_request_check" != xyes && D3D9NINE_MISSING_LIBS="libxcb "
|
|
+ AC_CHECK_LIB(xcb-dri3,xcb_dri3_open,[AC_SUBST(D3D9NINE_LIBS,["$D3D9NINE_LIBS -lxcb-dri3"])])
|
|
+ test "x$ac_cv_lib_xcb_dri3_xcb_dri3_open" != xyes && D3D9NINE_MISSING_LIBS="${D3D9NINE_MISSING_LIBS}libxcb-dri3 "
|
|
+ AC_CHECK_LIB(xcb-present,xcb_present_notify_msc,[AC_SUBST(D3D9NINE_LIBS,["$D3D9NINE_LIBS -lxcb-present"])])
|
|
+ test "x$ac_cv_lib_xcb_present_xcb_present_notify_msc" != xyes && D3D9NINE_MISSING_LIBS="${D3D9NINE_MISSING_LIBS}libxcb-present "
|
|
+ AC_CHECK_LIB(xcb-xfixes,xcb_xfixes_create_region,[AC_SUBST(D3D9NINE_LIBS,["$D3D9NINE_LIBS -lxcb-xfixes"])])
|
|
+ test "x$ac_cv_lib_xcb_xfixes_xcb_xfixes_create_region" != xyes && D3D9NINE_MISSING_LIBS="${D3D9NINE_MISSING_LIBS}libxcb-xfixes "
|
|
+ AC_CHECK_LIB(X11-xcb,XGetXCBConnection,[AC_SUBST(D3D9NINE_LIBS,["$D3D9NINE_LIBS -lX11-xcb"])])
|
|
+ test "x$ac_cv_lib_X11_xcb_XGetXCBConnection" != xyes && D3D9NINE_MISSING_LIBS="${D3D9NINE_MISSING_LIBS}libX11-xcb "
|
|
+ AC_CHECK_LIB(X11,XOpenDisplay,[AC_SUBST(D3D9NINE_LIBS,["$D3D9NINE_LIBS -lX11"])])
|
|
+ test "x$ac_cv_lib_X11_XOpenDisplay" != xyes && D3D9NINE_MISSING_LIBS="${D3D9NINE_MISSING_LIBS}libX11 "
|
|
+ AC_CHECK_LIB(Xext,XextRemoveDisplay,[AC_SUBST(D3D9NINE_LIBS,["$D3D9NINE_LIBS -lXext"])])
|
|
+ test "x$ac_cv_lib_Xext_XextRemoveDisplay" != xyes && D3D9NINE_MISSING_LIBS="${D3D9NINE_MISSING_LIBS}libXext "
|
|
+ # libs for the dri2 fallback
|
|
+ AC_CHECK_LIB(GL,glGenFramebuffers,[AC_SUBST(D3D9NINE_LIBS,["$D3D9NINE_LIBS -lGL"])])
|
|
+ test "x$ac_cv_lib_GL_glGenFramebuffers" != xyes && D3D9NINE_MISSING_LIBS="libGL "
|
|
+ AC_CHECK_LIB(EGL,eglCreateContext,[AC_SUBST(D3D9NINE_LIBS,["$D3D9NINE_LIBS -lEGL"])])
|
|
+ test "x$ac_cv_lib_EGL_eglCreateContext" != xyes && D3D9NINE_MISSING_LIBS="${D3D9NINE_MISSING_LIBS}libEGL"
|
|
+
|
|
+ if test "x$D3D9NINE_MISSING_LIBS" != x
|
|
+ then
|
|
+ if test "x$with_d3d9_nine" = "xyes"
|
|
+ then
|
|
+ AC_MSG_ERROR([Missing libraries to build d3d9-nine.dll: $D3D9NINE_MISSING_LIBS])
|
|
+ else
|
|
+ AC_MSG_NOTICE([Missing libraries to build d3d9-nine.dll: $D3D9NINE_MISSING_LIBS . disabling support])
|
|
+ with_d3d9_nine=no
|
|
+ fi
|
|
+ fi
|
|
+ fi
|
|
+
|
|
+ if test "x$with_d3d9_nine" != "xno"
|
|
+ then
|
|
+ AC_MSG_NOTICE([Checking d3dadapter9 header dependencies])
|
|
+ D3D9NINE_MISSING_HEADERS=""
|
|
+ AC_CHECK_HEADERS([X11/Xlib-xcb.h xcb/dri3.h xcb/present.h X11/Xutil.h X11/Xlib.h pthread.h])
|
|
+ test "x$ac_cv_header_X11_Xlib_xcb_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}X11/Xlib-xcb.h "
|
|
+ test "x$ac_cv_header_xcb_dri3_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}xcb/dri3.h "
|
|
+ test "x$ac_cv_header_xcb_present_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}xcb/present.h "
|
|
+ test "x$ac_cv_header_X11_Xutil_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}X11/Xutil.h "
|
|
+ test "x$ac_cv_header_X11_Xlib_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}X11/Xlib.h "
|
|
+ test "x$ac_cv_header_pthread_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}pthread.h "
|
|
+ # headers for the dri2 fallback
|
|
+ AC_CHECK_HEADERS([X11/Xmd.h X11/Xlibint.h X11/extensions/dri2tokens.h X11/extensions/dri2proto.h X11/extensions/extutil.h GL/gl.h GL/glext.h EGL/egl.h EGL/eglext.h libdrm/drm_fourcc.h libdrm/drm.h],
|
|
+ [],[],[[
|
|
+#include <X11/Xlibint.h>
|
|
+#include <X11/extensions/dri2tokens.h>
|
|
+#include <GL/gl.h>
|
|
+#include <EGL/egl.h>
|
|
+]])
|
|
+ test "x$ac_cv_header_X11_Xmd_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}X11/Xmd.h "
|
|
+ test "x$ac_cv_header_X11_Xlibint_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}X11/Xlibint.h "
|
|
+ test "x$ac_cv_header_X11_extensions_dri2tokens_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}X11/extensions/dri2tokens.h "
|
|
+ test "x$ac_cv_header_X11_extensions_dri2proto_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}X11/extensions/dri2proto.h "
|
|
+ test "x$ac_cv_header_X11_extensions_extutil_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}X11/extensions/extutil.h "
|
|
+ test "x$ac_cv_header_GL_gl_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}GL/gl.h "
|
|
+ test "x$ac_cv_header_GL_glext_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}GL/glext.h "
|
|
+ test "x$ac_cv_header_EGL_egl_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}EGL/egl.h "
|
|
+ test "x$ac_cv_header_EGL_eglext_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}EGL/eglext.h "
|
|
+ test "x$ac_cv_header_libdrm_drm_fourcc_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}libdrm/drm_fourcc.h "
|
|
+ test "x$ac_cv_header_libdrm_drm_h" != xyes && D3D9NINE_MISSING_HEADERS="${D3D9NINE_MISSING_HEADERS}libdrm/drm.h "
|
|
+ if test "x$D3D9NINE_MISSING_HEADERS" != x
|
|
+ then
|
|
+ if test "x$with_d3d9_nine" = "xyes"
|
|
+ then
|
|
+ AC_MSG_ERROR([Missing headers to build d3d9-nine.dll: $D3D9NINE_MISSING_HEADERS])
|
|
+ else
|
|
+ AC_MSG_NOTICE([Missing headers to build d3d9-nine.dll: $D3D9NINE_MISSING_HEADERS . disabling support])
|
|
+ with_d3d9_nine=no
|
|
+ fi
|
|
+ fi
|
|
+ fi
|
|
+
|
|
+ if test "x$with_d3d9_nine" != "xno"
|
|
+ then
|
|
+ # d3d9-nine.dll will be built and an option to use it
|
|
+ # added. The module path can always be overriden by
|
|
+ # a wine registry setting. If the module isn't found
|
|
+ # at execution time, the dll will refuse to load and
|
|
+ # print an error message to the user.
|
|
+ AC_DEFINE(HAVE_D3D9NINE, 1, [Whether d3d9-nine.dll is built])
|
|
+ # default: use pkgconfig to find the gallium nine module.
|
|
+ # Check the module is there.
|
|
+ if test "x$with_d3d9_nine_module" = "xauto"
|
|
+ then
|
|
+ D3DADAPTER9_MODULEDIR=`$PKG_CONFIG --variable=moduledir d3dadapter9 2>/dev/null`
|
|
+ if test "x$D3DADAPTER9_MODULEDIR" = x
|
|
+ then
|
|
+ # legacy path
|
|
+ D3DADAPTER9_MODULEDIR=`$PKG_CONFIG --variable=moduledir d3d 2>/dev/null`
|
|
+ if test "x$D3DADAPTER9_MODULEDIR" = x
|
|
+ then
|
|
+ AC_MSG_ERROR([pkg-config couldn't find Gallium Nine module])
|
|
+ fi
|
|
+ fi
|
|
+ AC_DEFINE_UNQUOTED(D3D9NINE_MODULEPATH, ["`echo ${D3DADAPTER9_MODULEDIR}/d3dadapter9.so.1`"], [Gallium Nine module path])
|
|
+ # Check module
|
|
+ CPPFLAGSBAK=$CPPFLAGS
|
|
+ # link against libdl
|
|
+ CPPFLAGS="$CPPFLAGS -Wl,--no-as-needed -ldl"
|
|
+
|
|
+ AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <dlfcn.h>
|
|
+#include <stdlib.h>]],[[void *handle = dlopen("${D3DADAPTER9_MODULEDIR}/d3dadapter9.so.1", RTLD_GLOBAL | RTLD_NOW);
|
|
+exit((handle && dlsym(handle, "D3DAdapter9GetProc")) ? 0 : 1)]])],
|
|
+ [echo "d3dadapter9.so.1 found at '${D3DADAPTER9_MODULEDIR}/d3dadapter9.so.1'"],
|
|
+ [AC_MSG_ERROR([Couldn't load Gallium nine module at '${D3DADAPTER9_MODULEDIR}/d3dadapter9.so.1' (found by pkg-config)])])
|
|
+ CPPFLAGS=$CPPFLAGSBAK
|
|
+ else
|
|
+ # Manual : do not feed any path, the wine registry will have
|
|
+ # to be used to pass a path. Useful for wine builds
|
|
+ # that are distributed and will run on different
|
|
+ # distros.
|
|
+ # Else feed a path directly. Useful for distro maintainers who
|
|
+ # know where the package would be installed, but don't have
|
|
+ # it installed on their build.
|
|
+ # Don't check if the module is there.
|
|
+ if test "x$with_d3d9_nine_module" != "xmanual"
|
|
+ then
|
|
+ AC_DEFINE_UNQUOTED(D3D9NINE_MODULEPATH, ["`echo ${with_d3d9_nine_module}`"], [Gallium Nine module path])
|
|
+ fi
|
|
+ fi
|
|
+
|
|
+ # by default the headers are found with pkgconfig,
|
|
+ # but it is possible to pass a path to a specific directory.
|
|
+ # that directory must contain a d3dadapter directory
|
|
+ # with d3dadapter9.h, drm.h and present.h
|
|
+ if test "x$with_d3d9_nine_headers_path" = "xauto"
|
|
+ then
|
|
+ AC_PROG_SED
|
|
+ D3DADAPTER9_INCLUDEDIR=`$PKG_CONFIG --variable=includedir d3dadapter9 2>/dev/null`
|
|
+ D3DADAPTER9_MAJOR=`$PKG_CONFIG --modversion d3dadapter9 2>/dev/null | $SED -n 's/\([[^\.]]*\)\..*$/\1/p'`
|
|
+ if test "x$D3DADAPTER9_INCLUDEDIR" = x
|
|
+ then
|
|
+ # legacy path
|
|
+ D3DADAPTER9_INCLUDEDIR=`$PKG_CONFIG --variable=includedir d3d 2>/dev/null`
|
|
+ D3DADAPTER9_MAJOR=`$PKG_CONFIG --modversion d3d 2>/dev/null | $SED -n 's/\([[^\.]]*\)\..*$/\1/p'`
|
|
+ if test "x$D3DADAPTER9_INCLUDEDIR" = x
|
|
+ then
|
|
+ AC_MSG_ERROR([pkg-config couldn't find Gallium Nine headers])
|
|
+ fi
|
|
+ fi
|
|
+ # check major version of package. The major version number guarantees header compatibility.
|
|
+ if test "x$D3DADAPTER9_MAJOR" != x1
|
|
+ then
|
|
+ AC_MSG_ERROR([pkg-config found Gallium Nine Module and Headers, but version is incompatible])
|
|
+ fi
|
|
+ else
|
|
+ D3DADAPTER9_INCLUDEDIR=`echo ${with_d3d9_nine_headers_path}`
|
|
+ fi
|
|
+ AC_DEFINE_UNQUOTED(D3D9NINE_HEADERS_CFLAGS, ["`echo -I${D3DADAPTER9_INCLUDEDIR}`"], [Gallium Nine headers cflags])
|
|
+
|
|
+ AC_DEFINE(D3D9NINE_DRI2, 1, [Whether d3d9-nine DRI2 fallback is compiled])
|
|
+ else
|
|
+ enable_d3d9_nine=${enable_d3d9_nine:-no}
|
|
+ fi
|
|
+
|
|
CPPFLAGS="$ac_save_CPPFLAGS"
|
|
else
|
|
X_CFLAGS=""
|
|
@@ -3096,6 +3283,7 @@ WINE_CONFIG_DLL(d3d8,,[implib])
|
|
WINE_CONFIG_TEST(dlls/d3d8/tests)
|
|
WINE_CONFIG_DLL(d3d9,,[implib])
|
|
WINE_CONFIG_TEST(dlls/d3d9/tests)
|
|
+WINE_CONFIG_DLL(d3d9-nine,,[implib])
|
|
WINE_CONFIG_DLL(d3dcompiler_33)
|
|
WINE_CONFIG_DLL(d3dcompiler_34)
|
|
WINE_CONFIG_DLL(d3dcompiler_35)
|
|
diff --git a/dlls/d3d9-nine/Makefile.in b/dlls/d3d9-nine/Makefile.in
|
|
new file mode 100644
|
|
index 0000000000..c6df8d7dbe
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/Makefile.in
|
|
@@ -0,0 +1,15 @@
|
|
+MODULE = d3d9-nine.dll
|
|
+IMPORTS = dxguid uuid advapi32 gdi32 user32
|
|
+EXTRAINCL = $(X_CFLAGS) $(D3D9NINE_HEADERS_CFLAGS)
|
|
+EXTRALIBS = $(D3D9NINE_LIBS)
|
|
+
|
|
+C_SRCS = \
|
|
+ d3d9_main.c \
|
|
+ d3dadapter9.c \
|
|
+ device_wrap.c \
|
|
+ present.c \
|
|
+ dri3.c \
|
|
+ wndproc.c \
|
|
+ shader_validator.c
|
|
+
|
|
+RC_SRCS = version.rc
|
|
diff --git a/dlls/d3d9-nine/d3d9-nine.spec b/dlls/d3d9-nine/d3d9-nine.spec
|
|
new file mode 100644
|
|
index 0000000000..a33cba51e7
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/d3d9-nine.spec
|
|
@@ -0,0 +1,14 @@
|
|
+@ stdcall Direct3DShaderValidatorCreate9()
|
|
+@ stub PSGPError
|
|
+@ stub PSGPSampleTexture
|
|
+@ stdcall D3DPERF_BeginEvent(long wstr)
|
|
+@ stdcall D3DPERF_EndEvent()
|
|
+@ stdcall D3DPERF_GetStatus()
|
|
+@ stdcall D3DPERF_QueryRepeatFrame()
|
|
+@ stdcall D3DPERF_SetMarker(long wstr)
|
|
+@ stdcall D3DPERF_SetOptions(long)
|
|
+@ stdcall D3DPERF_SetRegion(long wstr)
|
|
+@ stub DebugSetLevel
|
|
+@ stdcall DebugSetMute()
|
|
+@ stdcall Direct3DCreate9(long)
|
|
+@ stdcall Direct3DCreate9Ex(long ptr)
|
|
diff --git a/dlls/d3d9-nine/d3d9_main.c b/dlls/d3d9-nine/d3d9_main.c
|
|
new file mode 100644
|
|
index 0000000000..d1efdf4a71
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/d3d9_main.c
|
|
@@ -0,0 +1,173 @@
|
|
+/*
|
|
+ * Direct3D 9
|
|
+ *
|
|
+ * Copyright 2002-2003 Jason Edmeades
|
|
+ * Copyright 2002-2003 Raphael Junqueira
|
|
+ * Copyright 2005 Oliver Stieber
|
|
+ * Copyright 2015 Patrick Rudolph
|
|
+ *
|
|
+ * 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 "config.h"
|
|
+#include "wine/debug.h"
|
|
+
|
|
+#include <fcntl.h>
|
|
+#include <d3d9.h>
|
|
+
|
|
+#include "d3dadapter9.h"
|
|
+#include "wndproc.h"
|
|
+#include "shader_validator.h"
|
|
+
|
|
+WINE_DEFAULT_DEBUG_CHANNEL(d3d9nine);
|
|
+
|
|
+static int D3DPERF_event_level = 0;
|
|
+static Display *gdi_display;
|
|
+
|
|
+void WINAPI DebugSetMute(void)
|
|
+{
|
|
+ /* nothing to do */
|
|
+}
|
|
+
|
|
+IDirect3D9 * WINAPI DECLSPEC_HOTPATCH Direct3DCreate9(UINT sdk_version)
|
|
+{
|
|
+ IDirect3D9 *native;
|
|
+ TRACE("sdk_version %#x.\n", sdk_version);
|
|
+
|
|
+ if (SUCCEEDED(d3dadapter9_new(gdi_display, FALSE, (IDirect3D9Ex **)&native)))
|
|
+ return native;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+HRESULT WINAPI DECLSPEC_HOTPATCH Direct3DCreate9Ex(UINT sdk_version, IDirect3D9Ex **d3d9ex)
|
|
+{
|
|
+ TRACE("sdk_version %#x, d3d9ex %p.\n", sdk_version, d3d9ex);
|
|
+
|
|
+ return d3dadapter9_new(gdi_display, TRUE, d3d9ex);
|
|
+}
|
|
+
|
|
+/*******************************************************************
|
|
+ * Direct3DShaderValidatorCreate9 (D3D9.@)
|
|
+ *
|
|
+ * No documentation available for this function.
|
|
+ * SDK only says it is internal and shouldn't be used.
|
|
+ */
|
|
+
|
|
+void* WINAPI Direct3DShaderValidatorCreate9(void)
|
|
+{
|
|
+ IDirect3DShaderValidator9Impl* object =
|
|
+ HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ sizeof(IDirect3DShaderValidator9Impl));
|
|
+
|
|
+ object->lpVtbl = &IDirect3DShaderValidator9Vtbl;
|
|
+ object->ref = 1;
|
|
+
|
|
+ FIXME("Returning interface %p\n", object);
|
|
+ return (void*) object;
|
|
+}
|
|
+
|
|
+/*******************************************************************
|
|
+ * DllMain
|
|
+ */
|
|
+BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved)
|
|
+{
|
|
+ switch (reason)
|
|
+ {
|
|
+ case DLL_PROCESS_ATTACH:
|
|
+ if (!(gdi_display = XOpenDisplay( NULL )))
|
|
+ {
|
|
+ ERR("Failed to open display\n");
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ fcntl( ConnectionNumber(gdi_display), F_SETFD, 1 ); /* set close on exec flag */
|
|
+
|
|
+ nine_dll_init(inst);
|
|
+ break;
|
|
+ case DLL_PROCESS_DETACH:
|
|
+ if (!reserved)
|
|
+ return nine_dll_destroy(inst);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+/***********************************************************************
|
|
+ * D3DPERF_BeginEvent (D3D9.@)
|
|
+ */
|
|
+int WINAPI D3DPERF_BeginEvent(D3DCOLOR color, const WCHAR *name)
|
|
+{
|
|
+ TRACE("color 0x%08x, name %s.\n", color, debugstr_w(name));
|
|
+
|
|
+ return D3DPERF_event_level++;
|
|
+}
|
|
+
|
|
+/***********************************************************************
|
|
+ * D3DPERF_EndEvent (D3D9.@)
|
|
+ */
|
|
+int WINAPI D3DPERF_EndEvent(void)
|
|
+{
|
|
+ TRACE("(void) : stub\n");
|
|
+
|
|
+ return --D3DPERF_event_level;
|
|
+}
|
|
+
|
|
+/***********************************************************************
|
|
+ * D3DPERF_GetStatus (D3D9.@)
|
|
+ */
|
|
+DWORD WINAPI D3DPERF_GetStatus(void)
|
|
+{
|
|
+ FIXME("(void) : stub\n");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/***********************************************************************
|
|
+ * D3DPERF_SetOptions (D3D9.@)
|
|
+ *
|
|
+ */
|
|
+void WINAPI D3DPERF_SetOptions(DWORD options)
|
|
+{
|
|
+ FIXME("(%#x) : stub\n", options);
|
|
+}
|
|
+
|
|
+/***********************************************************************
|
|
+ * D3DPERF_QueryRepeatFrame (D3D9.@)
|
|
+ */
|
|
+BOOL WINAPI D3DPERF_QueryRepeatFrame(void)
|
|
+{
|
|
+ FIXME("(void) : stub\n");
|
|
+
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+/***********************************************************************
|
|
+ * D3DPERF_SetMarker (D3D9.@)
|
|
+ */
|
|
+void WINAPI D3DPERF_SetMarker(D3DCOLOR color, const WCHAR *name)
|
|
+{
|
|
+ FIXME("color 0x%08x, name %s stub!\n", color, debugstr_w(name));
|
|
+}
|
|
+
|
|
+/***********************************************************************
|
|
+ * D3DPERF_SetRegion (D3D9.@)
|
|
+ */
|
|
+void WINAPI D3DPERF_SetRegion(D3DCOLOR color, const WCHAR *name)
|
|
+{
|
|
+ FIXME("color 0x%08x, name %s stub!\n", color, debugstr_w(name));
|
|
+}
|
|
diff --git a/dlls/d3d9-nine/d3dadapter9.c b/dlls/d3d9-nine/d3dadapter9.c
|
|
new file mode 100644
|
|
index 0000000000..daa9524361
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/d3dadapter9.c
|
|
@@ -0,0 +1,853 @@
|
|
+/*
|
|
+ * Wine IDirect3D9 interface using ID3DAdapter9
|
|
+ *
|
|
+ * Copyright 2013 Joakim Sindholt
|
|
+ * Christoph Bumiller
|
|
+ * Copyright 2014 David Heidelberger
|
|
+ * Copyright 2014-2015 Axel Davy
|
|
+ * Copyright 2015 Nick Sarnie
|
|
+ * Patrick Rudolph
|
|
+ *
|
|
+ * 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 "config.h"
|
|
+#include "wine/debug.h"
|
|
+
|
|
+WINE_DEFAULT_DEBUG_CHANNEL(d3d9nine);
|
|
+
|
|
+#include <d3dadapter/d3dadapter9.h>
|
|
+#include "present.h"
|
|
+#include "device_wrap.h"
|
|
+
|
|
+/* this represents a snapshot taken at the moment of creation */
|
|
+struct output
|
|
+{
|
|
+ D3DDISPLAYROTATION rotation; /* current rotation */
|
|
+ D3DDISPLAYMODEEX *modes;
|
|
+ unsigned nmodes;
|
|
+ unsigned nmodesalloc;
|
|
+ unsigned current; /* current mode num */
|
|
+
|
|
+ HMONITOR monitor;
|
|
+};
|
|
+
|
|
+struct adapter_group
|
|
+{
|
|
+ struct output *outputs;
|
|
+ unsigned noutputs;
|
|
+ unsigned noutputsalloc;
|
|
+
|
|
+ /* override driver provided DeviceName with this to homogenize device names
|
|
+ * with wine */
|
|
+ WCHAR devname[32];
|
|
+
|
|
+ /* driver stuff */
|
|
+ ID3DAdapter9 *adapter;
|
|
+};
|
|
+
|
|
+struct adapter_map
|
|
+{
|
|
+ unsigned group;
|
|
+ unsigned master;
|
|
+};
|
|
+
|
|
+struct d3dadapter9
|
|
+{
|
|
+ /* COM vtable */
|
|
+ void *vtable;
|
|
+ /* IUnknown reference count */
|
|
+ LONG refs;
|
|
+
|
|
+ /* adapter groups and mappings */
|
|
+ struct adapter_group *groups;
|
|
+ struct adapter_map *map;
|
|
+ unsigned nadapters;
|
|
+ unsigned ngroups;
|
|
+ unsigned ngroupsalloc;
|
|
+
|
|
+ /* true if it implements IDirect3D9Ex */
|
|
+ boolean ex;
|
|
+ Display *gdi_display;
|
|
+};
|
|
+
|
|
+/* convenience wrapper for calls into ID3D9Adapter */
|
|
+#define ADAPTER_GROUP \
|
|
+ This->groups[This->map[Adapter].group]
|
|
+
|
|
+#define ADAPTER_PROC(name, ...) \
|
|
+ ID3DAdapter9_##name(ADAPTER_GROUP.adapter, ## __VA_ARGS__)
|
|
+
|
|
+#define ADAPTER_OUTPUT \
|
|
+ ADAPTER_GROUP.outputs[Adapter-This->map[Adapter].master]
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_CheckDeviceFormat(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat,
|
|
+ DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat);
|
|
+
|
|
+static ULONG WINAPI d3dadapter9_AddRef(struct d3dadapter9 *This)
|
|
+{
|
|
+ ULONG refs = InterlockedIncrement(&This->refs);
|
|
+ TRACE("%p increasing refcount to %u.\n", This, refs);
|
|
+ return refs;
|
|
+}
|
|
+
|
|
+static ULONG WINAPI d3dadapter9_Release(struct d3dadapter9 *This)
|
|
+{
|
|
+ ULONG refs = InterlockedDecrement(&This->refs);
|
|
+ TRACE("%p decreasing refcount to %u.\n", This, refs);
|
|
+ if (refs == 0)
|
|
+ {
|
|
+ /* dtor */
|
|
+ if (This->map)
|
|
+ {
|
|
+ HeapFree(GetProcessHeap(), 0, This->map);
|
|
+ }
|
|
+
|
|
+ if (This->groups)
|
|
+ {
|
|
+ int i, j;
|
|
+ for (i = 0; i < This->ngroups; ++i)
|
|
+ {
|
|
+ if (This->groups[i].outputs)
|
|
+ {
|
|
+ for (j = 0; j < This->groups[i].noutputs; ++j)
|
|
+ {
|
|
+ if (This->groups[i].outputs[j].modes)
|
|
+ {
|
|
+ HeapFree(GetProcessHeap(), 0,
|
|
+ This->groups[i].outputs[j].modes);
|
|
+ }
|
|
+ }
|
|
+ HeapFree(GetProcessHeap(), 0, This->groups[i].outputs);
|
|
+ }
|
|
+
|
|
+ if (This->groups[i].adapter)
|
|
+ ID3DAdapter9_Release(This->groups[i].adapter);
|
|
+ }
|
|
+ HeapFree(GetProcessHeap(), 0, This->groups);
|
|
+ }
|
|
+
|
|
+ HeapFree(GetProcessHeap(), 0, This);
|
|
+ }
|
|
+ return refs;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_QueryInterface(struct d3dadapter9 *This,
|
|
+ REFIID riid, void **ppvObject)
|
|
+{
|
|
+ if (!ppvObject)
|
|
+ return E_POINTER;
|
|
+
|
|
+ if ((IsEqualGUID(&IID_IDirect3D9Ex, riid) && This->ex) ||
|
|
+ IsEqualGUID(&IID_IDirect3D9, riid) ||
|
|
+ IsEqualGUID(&IID_IUnknown, riid))
|
|
+ {
|
|
+ *ppvObject = This;
|
|
+ d3dadapter9_AddRef(This);
|
|
+ return S_OK;
|
|
+ }
|
|
+
|
|
+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
|
|
+ *ppvObject = NULL;
|
|
+
|
|
+ return E_NOINTERFACE;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_RegisterSoftwareDevice(struct d3dadapter9 *This,
|
|
+ void *pInitializeFunction)
|
|
+{
|
|
+ FIXME("(%p, %p), stub!\n", This, pInitializeFunction);
|
|
+ return D3DERR_INVALIDCALL;
|
|
+}
|
|
+
|
|
+static UINT WINAPI d3dadapter9_GetAdapterCount(struct d3dadapter9 *This)
|
|
+{
|
|
+ return This->nadapters;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_GetAdapterIdentifier(struct d3dadapter9 *This,
|
|
+ UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9 *pIdentifier)
|
|
+{
|
|
+ HRESULT hr;
|
|
+ HKEY regkey;
|
|
+
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ hr = ADAPTER_PROC(GetAdapterIdentifier, Flags, pIdentifier);
|
|
+ if (SUCCEEDED(hr))
|
|
+ {
|
|
+ /* Override the driver provided DeviceName with what Wine provided */
|
|
+ ZeroMemory(pIdentifier->DeviceName, sizeof(pIdentifier->DeviceName));
|
|
+ if (!WideCharToMultiByte(CP_ACP, 0, ADAPTER_GROUP.devname, -1,
|
|
+ pIdentifier->DeviceName, sizeof(pIdentifier->DeviceName), NULL, NULL))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ TRACE("DeviceName overriden: %s\n", pIdentifier->DeviceName);
|
|
+
|
|
+ /* Override PCI IDs when wined3d registry keys are set */
|
|
+ if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Direct3DNine", ®key))
|
|
+ {
|
|
+ DWORD type, data;
|
|
+ DWORD size = sizeof(DWORD);
|
|
+
|
|
+ if (!RegQueryValueExA(regkey, "VideoPciDeviceID", 0, &type, (BYTE *)&data, &size) &&
|
|
+ (type == REG_DWORD) && (size == sizeof(DWORD)))
|
|
+ pIdentifier->DeviceId = data;
|
|
+ if (size != sizeof(DWORD))
|
|
+ {
|
|
+ ERR("VideoPciDeviceID is not a DWORD\n");
|
|
+ size = sizeof(DWORD);
|
|
+ }
|
|
+ if (!RegQueryValueExA(regkey, "VideoPciVendorID", 0, &type, (BYTE *)&data, &size) &&
|
|
+ (type == REG_DWORD) && (size == sizeof(DWORD)))
|
|
+ pIdentifier->VendorId = data;
|
|
+ if (size != sizeof(DWORD))
|
|
+ ERR("VideoPciVendorID is not a DWORD\n");
|
|
+ RegCloseKey(regkey);
|
|
+
|
|
+ TRACE("DeviceId:VendorId overridden: %04X:%04X\n", pIdentifier->DeviceId, pIdentifier->VendorId);
|
|
+ }
|
|
+ }
|
|
+ return hr;
|
|
+}
|
|
+
|
|
+static UINT WINAPI d3dadapter9_GetAdapterModeCount(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DFORMAT Format)
|
|
+{
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ if (FAILED(d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL,
|
|
+ Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, Format)))
|
|
+ {
|
|
+ WARN("DeviceFormat not available.\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ TRACE("%u modes.\n", ADAPTER_OUTPUT.nmodes);
|
|
+ return ADAPTER_OUTPUT.nmodes;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_EnumAdapterModes(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE *pMode)
|
|
+{
|
|
+ HRESULT hr;
|
|
+
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ hr = d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL,
|
|
+ Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, Format);
|
|
+
|
|
+ if (FAILED(hr))
|
|
+ {
|
|
+ TRACE("DeviceFormat not available.\n");
|
|
+ return hr;
|
|
+ }
|
|
+
|
|
+ if (Mode >= ADAPTER_OUTPUT.nmodes)
|
|
+ {
|
|
+ WARN("Mode %u does not exist.\n", Mode);
|
|
+ return D3DERR_INVALIDCALL;
|
|
+ }
|
|
+
|
|
+ pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width;
|
|
+ pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height;
|
|
+ pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate;
|
|
+ pMode->Format = Format;
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_GetAdapterDisplayMode(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDISPLAYMODE *pMode)
|
|
+{
|
|
+ UINT Mode;
|
|
+
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ Mode = ADAPTER_OUTPUT.current;
|
|
+ pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width;
|
|
+ pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height;
|
|
+ pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate;
|
|
+ pMode->Format = ADAPTER_OUTPUT.modes[Mode].Format;
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_CheckDeviceType(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDEVTYPE DevType, D3DFORMAT AdapterFormat,
|
|
+ D3DFORMAT BackBufferFormat, BOOL bWindowed)
|
|
+{
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ return ADAPTER_PROC(CheckDeviceType,
|
|
+ DevType, AdapterFormat, BackBufferFormat, bWindowed);
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_CheckDeviceFormat(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat,
|
|
+ DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat)
|
|
+{
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ return ADAPTER_PROC(CheckDeviceFormat,
|
|
+ DeviceType, AdapterFormat, Usage, RType, CheckFormat);
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_CheckDeviceMultiSampleType(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat,
|
|
+ BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD *pQualityLevels)
|
|
+{
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ return ADAPTER_PROC(CheckDeviceMultiSampleType, DeviceType, SurfaceFormat,
|
|
+ Windowed, MultiSampleType, pQualityLevels);
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_CheckDepthStencilMatch(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat,
|
|
+ D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat)
|
|
+{
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ return ADAPTER_PROC(CheckDepthStencilMatch, DeviceType, AdapterFormat,
|
|
+ RenderTargetFormat, DepthStencilFormat);
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_CheckDeviceFormatConversion(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat)
|
|
+{
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ return ADAPTER_PROC(CheckDeviceFormatConversion,
|
|
+ DeviceType, SourceFormat, TargetFormat);
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_GetDeviceCaps(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9 *pCaps)
|
|
+{
|
|
+ HRESULT hr;
|
|
+
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ hr = ADAPTER_PROC(GetDeviceCaps, DeviceType, pCaps);
|
|
+ if (FAILED(hr))
|
|
+ return hr;
|
|
+
|
|
+ pCaps->MasterAdapterOrdinal = This->map[Adapter].master;
|
|
+ pCaps->AdapterOrdinalInGroup = Adapter-This->map[Adapter].master;
|
|
+ pCaps->NumberOfAdaptersInGroup = ADAPTER_GROUP.noutputs;
|
|
+
|
|
+ return hr;
|
|
+}
|
|
+
|
|
+static HMONITOR WINAPI d3dadapter9_GetAdapterMonitor(struct d3dadapter9 *This,
|
|
+ UINT Adapter)
|
|
+{
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return (HMONITOR)0;
|
|
+
|
|
+ return (HMONITOR)ADAPTER_OUTPUT.monitor;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DECLSPEC_HOTPATCH d3dadapter9_CreateDeviceEx(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags,
|
|
+ D3DPRESENT_PARAMETERS *pPresentationParameters,
|
|
+ D3DDISPLAYMODEEX *pFullscreenDisplayMode,
|
|
+ IDirect3DDevice9Ex **ppReturnedDeviceInterface);
|
|
+
|
|
+static HRESULT WINAPI DECLSPEC_HOTPATCH d3dadapter9_CreateDevice(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags,
|
|
+ D3DPRESENT_PARAMETERS *pPresentationParameters,
|
|
+ IDirect3DDevice9 **ppReturnedDeviceInterface)
|
|
+{
|
|
+ HRESULT hr;
|
|
+ hr = d3dadapter9_CreateDeviceEx(This, Adapter, DeviceType, hFocusWindow,
|
|
+ BehaviorFlags, pPresentationParameters, NULL,
|
|
+ (IDirect3DDevice9Ex **)ppReturnedDeviceInterface);
|
|
+ if (FAILED(hr))
|
|
+ return hr;
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static UINT WINAPI d3dadapter9_GetAdapterModeCountEx(struct d3dadapter9 *This,
|
|
+ UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter)
|
|
+{
|
|
+ FIXME("(%p, %u, %p), stub!\n", This, Adapter, pFilter);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_EnumAdapterModesEx(struct d3dadapter9 *This,
|
|
+ UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter, UINT Mode,
|
|
+ D3DDISPLAYMODEEX *pMode)
|
|
+{
|
|
+ FIXME("(%p, %u, %p, %u, %p), stub!\n", This, Adapter, pFilter, Mode, pMode);
|
|
+ return D3DERR_INVALIDCALL;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_GetAdapterDisplayModeEx(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation)
|
|
+{
|
|
+ FIXME("(%p, %u, %p, %p), stub!\n", This, Adapter, pMode, pRotation);
|
|
+ return D3DERR_INVALIDCALL;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DECLSPEC_HOTPATCH d3dadapter9_CreateDeviceEx(struct d3dadapter9 *This,
|
|
+ UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags,
|
|
+ D3DPRESENT_PARAMETERS *pPresentationParameters,
|
|
+ D3DDISPLAYMODEEX *pFullscreenDisplayMode,
|
|
+ IDirect3DDevice9Ex **ppReturnedDeviceInterface)
|
|
+{
|
|
+ ID3DPresentGroup *present;
|
|
+ HRESULT hr;
|
|
+
|
|
+ if (Adapter >= d3dadapter9_GetAdapterCount(This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ {
|
|
+ struct adapter_group *group = &ADAPTER_GROUP;
|
|
+ unsigned nparams, ordinal;
|
|
+
|
|
+ if (BehaviorFlags & D3DCREATE_ADAPTERGROUP_DEVICE)
|
|
+ {
|
|
+ nparams = group->noutputs;
|
|
+ ordinal = 0;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ nparams = 1;
|
|
+ ordinal = Adapter - This->map[Adapter].master;
|
|
+ }
|
|
+ hr = present_create_present_group(This->gdi_display, group->devname, ordinal,
|
|
+ hFocusWindow, pPresentationParameters, nparams, &present, This->ex,
|
|
+ BehaviorFlags);
|
|
+ }
|
|
+
|
|
+ if (FAILED(hr))
|
|
+ {
|
|
+ WARN("Failed to create PresentGroup.\n");
|
|
+ return hr;
|
|
+ }
|
|
+
|
|
+ if (This->ex)
|
|
+ {
|
|
+ hr = ADAPTER_PROC(CreateDeviceEx, Adapter, DeviceType, hFocusWindow,
|
|
+ BehaviorFlags, pPresentationParameters, pFullscreenDisplayMode,
|
|
+ (IDirect3D9Ex *)This, present, ppReturnedDeviceInterface);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* CreateDevice on non-ex */
|
|
+ hr = ADAPTER_PROC(CreateDevice, Adapter, DeviceType, hFocusWindow,
|
|
+ BehaviorFlags, pPresentationParameters, (IDirect3D9 *)This, present,
|
|
+ (IDirect3DDevice9 **)ppReturnedDeviceInterface);
|
|
+ }
|
|
+ if (FAILED(hr))
|
|
+ {
|
|
+ WARN("ADAPTER_PROC failed.\n");
|
|
+ ID3DPresentGroup_Release(present);
|
|
+ return hr;
|
|
+ }
|
|
+
|
|
+ /* Nine returns different vtables for Ex, non Ex and
|
|
+ * if you use the multithread flag or not. This prevents
|
|
+ * things like Steam overlay to work, in addition to the problem
|
|
+ * that functions nine side are not recognized by wine as
|
|
+ * hotpatch-able. If possible, we use our vtable wrapper,
|
|
+ * which solves the problem described above. */
|
|
+ if (enable_device_vtable_wrapper())
|
|
+ (*ppReturnedDeviceInterface)->lpVtbl = get_device_vtable();
|
|
+ return hr;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI d3dadapter9_GetAdapterLUID(struct d3dadapter9 *This,
|
|
+ UINT Adapter, LUID *pLUID)
|
|
+{
|
|
+ FIXME("(%p, %u, %p), stub!\n", This, Adapter, pLUID);
|
|
+ return D3DERR_INVALIDCALL;
|
|
+}
|
|
+
|
|
+static struct adapter_group *add_group(struct d3dadapter9 *This)
|
|
+{
|
|
+ if (This->ngroups >= This->ngroupsalloc)
|
|
+ {
|
|
+ void *r;
|
|
+
|
|
+ if (This->ngroupsalloc == 0)
|
|
+ {
|
|
+ This->ngroupsalloc = 2;
|
|
+ r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ This->ngroupsalloc*sizeof(struct adapter_group));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ This->ngroupsalloc <<= 1;
|
|
+ r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->groups,
|
|
+ This->ngroupsalloc*sizeof(struct adapter_group));
|
|
+ }
|
|
+
|
|
+ if (!r)
|
|
+ return NULL;
|
|
+ This->groups = r;
|
|
+ }
|
|
+
|
|
+ return &This->groups[This->ngroups++];
|
|
+}
|
|
+
|
|
+static void remove_group(struct d3dadapter9 *This)
|
|
+{
|
|
+ struct adapter_group *group = &This->groups[This->ngroups-1];
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < group->noutputs; ++i)
|
|
+ {
|
|
+ HeapFree(GetProcessHeap(), 0, group->outputs[i].modes);
|
|
+ }
|
|
+ HeapFree(GetProcessHeap(), 0, group->outputs);
|
|
+
|
|
+ ZeroMemory(group, sizeof(struct adapter_group));
|
|
+ This->ngroups--;
|
|
+}
|
|
+
|
|
+static struct output *add_output(struct d3dadapter9 *This)
|
|
+{
|
|
+ struct adapter_group *group = &This->groups[This->ngroups-1];
|
|
+
|
|
+ if (group->noutputs >= group->noutputsalloc)
|
|
+ {
|
|
+ void *r;
|
|
+
|
|
+ if (group->noutputsalloc == 0)
|
|
+ {
|
|
+ group->noutputsalloc = 2;
|
|
+ r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ group->noutputsalloc*sizeof(struct output));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ group->noutputsalloc <<= 1;
|
|
+ r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, group->outputs,
|
|
+ group->noutputsalloc*sizeof(struct output));
|
|
+ }
|
|
+
|
|
+ if (!r)
|
|
+ return NULL;
|
|
+ group->outputs = r;
|
|
+ }
|
|
+
|
|
+ return &group->outputs[group->noutputs++];
|
|
+}
|
|
+
|
|
+static void remove_output(struct d3dadapter9 *This)
|
|
+{
|
|
+ struct adapter_group *group = &This->groups[This->ngroups-1];
|
|
+ struct output *out = &group->outputs[group->noutputs-1];
|
|
+
|
|
+ HeapFree(GetProcessHeap(), 0, out->modes);
|
|
+
|
|
+ ZeroMemory(out, sizeof(struct output));
|
|
+ group->noutputs--;
|
|
+}
|
|
+
|
|
+static D3DDISPLAYMODEEX *add_mode(struct d3dadapter9 *This)
|
|
+{
|
|
+ struct adapter_group *group = &This->groups[This->ngroups-1];
|
|
+ struct output *out = &group->outputs[group->noutputs-1];
|
|
+
|
|
+ if (out->nmodes >= out->nmodesalloc)
|
|
+ {
|
|
+ void *r;
|
|
+
|
|
+ if (out->nmodesalloc == 0)
|
|
+ {
|
|
+ out->nmodesalloc = 8;
|
|
+ r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ out->nmodesalloc <<= 1;
|
|
+ r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, out->modes,
|
|
+ out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX));
|
|
+ }
|
|
+
|
|
+ if (!r)
|
|
+ return NULL;
|
|
+ out->modes = r;
|
|
+ }
|
|
+
|
|
+ return &out->modes[out->nmodes++];
|
|
+}
|
|
+
|
|
+static void remove_mode(struct d3dadapter9 *This)
|
|
+{
|
|
+ struct adapter_group *group = &This->groups[This->ngroups-1];
|
|
+ struct output *out = &group->outputs[group->noutputs-1];
|
|
+ out->nmodes--;
|
|
+}
|
|
+
|
|
+static HRESULT fill_groups(struct d3dadapter9 *This)
|
|
+{
|
|
+ DISPLAY_DEVICEW dd;
|
|
+ DEVMODEW dm;
|
|
+ POINT pt;
|
|
+ HDC hdc;
|
|
+ HRESULT hr;
|
|
+ int i, j, k;
|
|
+
|
|
+ WCHAR wdisp[] = {'D','I','S','P','L','A','Y',0};
|
|
+
|
|
+ ZeroMemory(&dd, sizeof(dd));
|
|
+ ZeroMemory(&dm, sizeof(dm));
|
|
+ dd.cb = sizeof(dd);
|
|
+ dm.dmSize = sizeof(dm);
|
|
+
|
|
+ for (i = 0; EnumDisplayDevicesW(NULL, i, &dd, 0); ++i)
|
|
+ {
|
|
+ struct adapter_group *group = add_group(This);
|
|
+ if (!group)
|
|
+ {
|
|
+ ERR("Out of memory.\n");
|
|
+ return E_OUTOFMEMORY;
|
|
+ }
|
|
+
|
|
+ hdc = CreateDCW(wdisp, dd.DeviceName, NULL, NULL);
|
|
+ if (!hdc)
|
|
+ {
|
|
+ remove_group(This);
|
|
+ WARN("Unable to create DC for display %d.\n", i);
|
|
+ goto end_group;
|
|
+ }
|
|
+
|
|
+ hr = present_create_adapter9(This->gdi_display, hdc, &group->adapter);
|
|
+ DeleteDC(hdc);
|
|
+ if (FAILED(hr))
|
|
+ {
|
|
+ remove_group(This);
|
|
+ goto end_group;
|
|
+ }
|
|
+
|
|
+ CopyMemory(group->devname, dd.DeviceName, sizeof(group->devname));
|
|
+ for (j = 0; EnumDisplayDevicesW(group->devname, j, &dd, 0); ++j)
|
|
+ {
|
|
+ struct output *out = add_output(This);
|
|
+ boolean orient = FALSE, monit = FALSE;
|
|
+ if (!out)
|
|
+ {
|
|
+ ERR("Out of memory.\n");
|
|
+ return E_OUTOFMEMORY;
|
|
+ }
|
|
+
|
|
+ for (k = 0; EnumDisplaySettingsExW(dd.DeviceName, k, &dm, 0); ++k)
|
|
+ {
|
|
+ D3DDISPLAYMODEEX *mode = add_mode(This);
|
|
+ if (!out)
|
|
+ {
|
|
+ ERR("Out of memory.\n");
|
|
+ return E_OUTOFMEMORY;
|
|
+ }
|
|
+
|
|
+ mode->Size = sizeof(D3DDISPLAYMODEEX);
|
|
+ mode->Width = dm.dmPelsWidth;
|
|
+ mode->Height = dm.dmPelsHeight;
|
|
+ mode->RefreshRate = dm.dmDisplayFrequency;
|
|
+ mode->ScanLineOrdering =
|
|
+ (dm.dmDisplayFlags & DM_INTERLACED) ?
|
|
+ D3DSCANLINEORDERING_INTERLACED :
|
|
+ D3DSCANLINEORDERING_PROGRESSIVE;
|
|
+
|
|
+ switch (dm.dmBitsPerPel)
|
|
+ {
|
|
+ case 32: mode->Format = D3DFMT_X8R8G8B8; break;
|
|
+ case 24: mode->Format = D3DFMT_R8G8B8; break;
|
|
+ case 16: mode->Format = D3DFMT_R5G6B5; break;
|
|
+ case 8:
|
|
+ remove_mode(This);
|
|
+ goto end_mode;
|
|
+
|
|
+ default:
|
|
+ remove_mode(This);
|
|
+ WARN("Unknown format (%u bpp) in display %d, monitor "
|
|
+ "%d, mode %d.\n", dm.dmBitsPerPel, i, j, k);
|
|
+ goto end_mode;
|
|
+ }
|
|
+
|
|
+ if (!orient)
|
|
+ {
|
|
+ switch (dm.dmDisplayOrientation)
|
|
+ {
|
|
+ case DMDO_DEFAULT:
|
|
+ out->rotation = D3DDISPLAYROTATION_IDENTITY;
|
|
+ break;
|
|
+
|
|
+ case DMDO_90:
|
|
+ out->rotation = D3DDISPLAYROTATION_90;
|
|
+ break;
|
|
+
|
|
+ case DMDO_180:
|
|
+ out->rotation = D3DDISPLAYROTATION_180;
|
|
+ break;
|
|
+
|
|
+ case DMDO_270:
|
|
+ out->rotation = D3DDISPLAYROTATION_270;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ remove_output(This);
|
|
+ WARN("Unknown display rotation in display %d, "
|
|
+ "monitor %d\n", i, j);
|
|
+ goto end_output;
|
|
+ }
|
|
+ orient = TRUE;
|
|
+ }
|
|
+
|
|
+ if (!monit)
|
|
+ {
|
|
+ pt.x = dm.dmPosition.x;
|
|
+ pt.y = dm.dmPosition.y;
|
|
+ out->monitor = MonitorFromPoint(pt, 0);
|
|
+ if (!out->monitor)
|
|
+ {
|
|
+ remove_output(This);
|
|
+ WARN("Unable to get monitor handle for display %d, "
|
|
+ "monitor %d.\n", i, j);
|
|
+ goto end_output;
|
|
+ }
|
|
+ monit = TRUE;
|
|
+ }
|
|
+
|
|
+end_mode:
|
|
+ ZeroMemory(&dm, sizeof(dm));
|
|
+ dm.dmSize = sizeof(dm);
|
|
+ }
|
|
+
|
|
+end_output:
|
|
+ ZeroMemory(&dd, sizeof(dd));
|
|
+ dd.cb = sizeof(dd);
|
|
+ }
|
|
+
|
|
+end_group:
|
|
+ ZeroMemory(&dd, sizeof(dd));
|
|
+ dd.cb = sizeof(dd);
|
|
+ }
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static IDirect3D9ExVtbl d3dadapter9_vtable = {
|
|
+ (void *)d3dadapter9_QueryInterface,
|
|
+ (void *)d3dadapter9_AddRef,
|
|
+ (void *)d3dadapter9_Release,
|
|
+ (void *)d3dadapter9_RegisterSoftwareDevice,
|
|
+ (void *)d3dadapter9_GetAdapterCount,
|
|
+ (void *)d3dadapter9_GetAdapterIdentifier,
|
|
+ (void *)d3dadapter9_GetAdapterModeCount,
|
|
+ (void *)d3dadapter9_EnumAdapterModes,
|
|
+ (void *)d3dadapter9_GetAdapterDisplayMode,
|
|
+ (void *)d3dadapter9_CheckDeviceType,
|
|
+ (void *)d3dadapter9_CheckDeviceFormat,
|
|
+ (void *)d3dadapter9_CheckDeviceMultiSampleType,
|
|
+ (void *)d3dadapter9_CheckDepthStencilMatch,
|
|
+ (void *)d3dadapter9_CheckDeviceFormatConversion,
|
|
+ (void *)d3dadapter9_GetDeviceCaps,
|
|
+ (void *)d3dadapter9_GetAdapterMonitor,
|
|
+ (void *)d3dadapter9_CreateDevice,
|
|
+ (void *)d3dadapter9_GetAdapterModeCountEx,
|
|
+ (void *)d3dadapter9_EnumAdapterModesEx,
|
|
+ (void *)d3dadapter9_GetAdapterDisplayModeEx,
|
|
+ (void *)d3dadapter9_CreateDeviceEx,
|
|
+ (void *)d3dadapter9_GetAdapterLUID
|
|
+};
|
|
+
|
|
+HRESULT d3dadapter9_new(Display *gdi_display, boolean ex, IDirect3D9Ex **ppOut)
|
|
+{
|
|
+ struct d3dadapter9 *This;
|
|
+ HRESULT hr;
|
|
+ unsigned i, j, k;
|
|
+
|
|
+ This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct d3dadapter9));
|
|
+ if (!This)
|
|
+ {
|
|
+ ERR("Out of memory.\n");
|
|
+ return E_OUTOFMEMORY;
|
|
+ }
|
|
+
|
|
+ This->vtable = &d3dadapter9_vtable;
|
|
+ This->refs = 1;
|
|
+ This->ex = ex;
|
|
+ This->gdi_display = gdi_display;
|
|
+
|
|
+ if (!present_has_d3dadapter(gdi_display))
|
|
+ {
|
|
+ ERR("Your display driver doesn't support native D3D9 adapters.\n");
|
|
+ d3dadapter9_Release(This);
|
|
+ return D3DERR_NOTAVAILABLE;
|
|
+ }
|
|
+
|
|
+ if (FAILED(hr = fill_groups(This)))
|
|
+ {
|
|
+ d3dadapter9_Release(This);
|
|
+ return hr;
|
|
+ }
|
|
+
|
|
+ /* map absolute adapter IDs with internal adapters */
|
|
+ for (i = 0; i < This->ngroups; ++i)
|
|
+ {
|
|
+ for (j = 0; j < This->groups[i].noutputs; ++j)
|
|
+ {
|
|
+ This->nadapters++;
|
|
+ }
|
|
+ }
|
|
+ if (This->nadapters == 0)
|
|
+ {
|
|
+ ERR("No available native adapters in system.\n");
|
|
+ d3dadapter9_Release(This);
|
|
+ return D3DERR_NOTAVAILABLE;
|
|
+ }
|
|
+
|
|
+ This->map = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ This->nadapters * sizeof(struct adapter_map));
|
|
+
|
|
+ if (!This->map)
|
|
+ {
|
|
+ d3dadapter9_Release(This);
|
|
+ ERR("Out of memory.\n");
|
|
+ return E_OUTOFMEMORY;
|
|
+ }
|
|
+ for (i = k = 0; i < This->ngroups; ++i)
|
|
+ {
|
|
+ for (j = 0; j < This->groups[i].noutputs; ++j, ++k)
|
|
+ {
|
|
+ This->map[k].master = k-j;
|
|
+ This->map[k].group = i;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ *ppOut = (IDirect3D9Ex *)This;
|
|
+ FIXME("\033[1;32m\nNative Direct3D 9 is active."
|
|
+ "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n");
|
|
+ return D3D_OK;
|
|
+}
|
|
diff --git a/dlls/d3d9-nine/d3dadapter9.h b/dlls/d3d9-nine/d3dadapter9.h
|
|
new file mode 100644
|
|
index 0000000000..ad54f67285
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/d3dadapter9.h
|
|
@@ -0,0 +1,32 @@
|
|
+/*
|
|
+ * D3DAdapter9 interface
|
|
+ *
|
|
+ * Copyright 2015 Patrick Rudolph
|
|
+ *
|
|
+ * 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_D3D9ADAPTER_H
|
|
+#define __WINE_D3D9ADAPTER_H
|
|
+
|
|
+#include <X11/Xlib.h>
|
|
+
|
|
+void d3dadapter9_init(HINSTANCE hinst);
|
|
+
|
|
+void d3dadapter9_destroy(HINSTANCE hinst);
|
|
+
|
|
+HRESULT d3dadapter9_new(Display *gdi_display, boolean ex, IDirect3D9Ex **ppOut);
|
|
+
|
|
+#endif /* __WINE_D3D9ADAPTER_H */
|
|
diff --git a/dlls/d3d9-nine/device_wrap.c b/dlls/d3d9-nine/device_wrap.c
|
|
new file mode 100644
|
|
index 0000000000..e662c6f89a
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/device_wrap.c
|
|
@@ -0,0 +1,500 @@
|
|
+/*
|
|
+ * Copyright 2016 Axel Davy
|
|
+ *
|
|
+ * 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 "config.h"
|
|
+#include "wine/port.h"
|
|
+#include "wine/debug.h"
|
|
+
|
|
+#include <d3d9.h>
|
|
+
|
|
+#include "device_wrap.h"
|
|
+
|
|
+struct IDirect3DDevice9Ex_Minor1
|
|
+{
|
|
+ IDirect3DDevice9ExVtbl *lpVtbl;
|
|
+ IDirect3DDevice9ExVtbl *lpVtbl_internal;
|
|
+};
|
|
+
|
|
+struct IDirect3DSwapChain9Ex_Minor1
|
|
+{
|
|
+ IDirect3DSwapChain9ExVtbl *lpVtbl;
|
|
+ IDirect3DSwapChain9ExVtbl *lpVtbl_internal;
|
|
+};
|
|
+
|
|
+typedef struct IDirect3DDevice9Ex_Minor1 IDirect3DDevice9Ex_Minor1;
|
|
+typedef struct IDirect3DSwapChain9Ex_Minor1 IDirect3DSwapChain9Ex_Minor1;
|
|
+
|
|
+#define SWAPCHAIN_WRAP0(ret, func) \
|
|
+ ret WINAPI WineNineSwapChain9_ ## func(IDirect3DSwapChain9Ex *This) \
|
|
+ { \
|
|
+ return ((IDirect3DSwapChain9Ex_Minor1 *)This)->lpVtbl_internal->func(This); \
|
|
+ }
|
|
+
|
|
+#define SWAPCHAIN_WRAP1(ret, func, type1) \
|
|
+ ret WINAPI WineNineSwapChain9_ ## func(IDirect3DSwapChain9Ex *This, type1 arg1) \
|
|
+ { \
|
|
+ return ((IDirect3DSwapChain9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1); \
|
|
+ }
|
|
+
|
|
+#define SWAPCHAIN_WRAP2(ret, func, type1, type2) \
|
|
+ ret WINAPI WineNineSwapChain9_ ## func(IDirect3DSwapChain9Ex *This, type1 arg1, type2 arg2) \
|
|
+ { \
|
|
+ return ((IDirect3DSwapChain9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2); \
|
|
+ }
|
|
+
|
|
+#define SWAPCHAIN_WRAP3(ret, func, type1, type2, type3) \
|
|
+ ret WINAPI WineNineSwapChain9_ ## func(IDirect3DSwapChain9Ex *This, type1 arg1, type2 arg2, type3 arg3) \
|
|
+ { \
|
|
+ return ((IDirect3DSwapChain9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3); \
|
|
+ }
|
|
+
|
|
+#define SWAPCHAIN_H_WRAP5(ret, func, type1, type2, type3, type4, type5) \
|
|
+ ret WINAPI DECLSPEC_HOTPATCH WineNineSwapChain9_ ## func(IDirect3DSwapChain9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
|
|
+ { \
|
|
+ return ((IDirect3DSwapChain9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_WRAP0(ret, func) \
|
|
+ ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_WRAP1(ret, func, type1) \
|
|
+ ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_WRAP2(ret, func, type1, type2) \
|
|
+ ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_WRAP3(ret, func, type1, type2, type3) \
|
|
+ ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_WRAP4(ret, func, type1, type2, type3, type4) \
|
|
+ ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_WRAP5(ret, func, type1, type2, type3, type4, type5) \
|
|
+ ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_WRAP6(ret, func, type1, type2, type3, type4, type5, type6) \
|
|
+ ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5, arg6); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_WRAP7(ret, func, type1, type2, type3, type4, type5, type6, type7) \
|
|
+ ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5, arg6, arg7); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_WRAP8(ret, func, type1, type2, type3, type4, type5, type6, type7, type8) \
|
|
+ ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_WRAP9(ret, func, type1, type2, type3, type4, type5, type6, type7, type8, type9) \
|
|
+ ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8, type9 arg9) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_H_WRAP0(ret, func) \
|
|
+ ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_H_WRAP1(ret, func, type1) \
|
|
+ ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_H_WRAP2(ret, func, type1, type2) \
|
|
+ ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_H_WRAP3(ret, func, type1, type2, type3) \
|
|
+ ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_H_WRAP4(ret, func, type1, type2, type3, type4) \
|
|
+ ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4); \
|
|
+ }
|
|
+
|
|
+#define DEVICE_H_WRAP5(ret, func, type1, type2, type3, type4, type5) \
|
|
+ ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
|
|
+ { \
|
|
+ return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5); \
|
|
+ }
|
|
+
|
|
+SWAPCHAIN_WRAP2(HRESULT, QueryInterface, REFIID, void **)
|
|
+SWAPCHAIN_WRAP0(ULONG, AddRef)
|
|
+SWAPCHAIN_WRAP0(ULONG, Release)
|
|
+SWAPCHAIN_H_WRAP5(HRESULT, Present, const RECT *, const RECT *, HWND, const RGNDATA *, DWORD)
|
|
+SWAPCHAIN_WRAP1(HRESULT, GetFrontBufferData, IDirect3DSurface9 *)
|
|
+SWAPCHAIN_WRAP3(HRESULT, GetBackBuffer, UINT, D3DBACKBUFFER_TYPE, IDirect3DSurface9 **)
|
|
+SWAPCHAIN_WRAP1(HRESULT, GetRasterStatus, D3DRASTER_STATUS *)
|
|
+SWAPCHAIN_WRAP1(HRESULT, GetDisplayMode, D3DDISPLAYMODE *)
|
|
+SWAPCHAIN_WRAP1(HRESULT, GetDevice, IDirect3DDevice9 **)
|
|
+SWAPCHAIN_WRAP1(HRESULT, GetPresentParameters, D3DPRESENT_PARAMETERS *)
|
|
+SWAPCHAIN_WRAP1(HRESULT, GetLastPresentCount, UINT *)
|
|
+SWAPCHAIN_WRAP1(HRESULT, GetPresentStats, D3DPRESENTSTATS *)
|
|
+SWAPCHAIN_WRAP2(HRESULT, GetDisplayModeEx, D3DDISPLAYMODEEX *, D3DDISPLAYROTATION *)
|
|
+
|
|
+DEVICE_WRAP2(HRESULT, QueryInterface, REFIID, void **)
|
|
+DEVICE_WRAP0(ULONG, AddRef)
|
|
+DEVICE_H_WRAP0(ULONG, Release)
|
|
+DEVICE_WRAP0(HRESULT, TestCooperativeLevel)
|
|
+DEVICE_WRAP0(UINT, GetAvailableTextureMem)
|
|
+DEVICE_WRAP0(HRESULT, EvictManagedResources)
|
|
+DEVICE_WRAP1(HRESULT, GetDirect3D, IDirect3D9 **)
|
|
+DEVICE_WRAP1(HRESULT, GetDeviceCaps, D3DCAPS9 *)
|
|
+DEVICE_WRAP2(HRESULT, GetDisplayMode, UINT, D3DDISPLAYMODE*)
|
|
+DEVICE_WRAP1(HRESULT, GetCreationParameters, D3DDEVICE_CREATION_PARAMETERS *)
|
|
+DEVICE_WRAP3(HRESULT, SetCursorProperties, UINT, UINT, IDirect3DSurface9 *)
|
|
+DEVICE_WRAP3(void, SetCursorPosition, int, int, DWORD)
|
|
+DEVICE_WRAP1(BOOL, ShowCursor, BOOL)
|
|
+/*DEVICE_H_WRAP2(HRESULT, CreateAdditionalSwapChain, D3DPRESENT_PARAMETERS *, IDirect3DSwapChain9 **)*/
|
|
+/*DEVICE_H_WRAP2(HRESULT, GetSwapChain, UINT, IDirect3DSwapChain9 **)*/
|
|
+DEVICE_WRAP0(UINT, GetNumberOfSwapChains)
|
|
+DEVICE_H_WRAP1(HRESULT, Reset, D3DPRESENT_PARAMETERS *)
|
|
+DEVICE_H_WRAP4(HRESULT, Present, const RECT *, const RECT *, HWND, const RGNDATA *)
|
|
+DEVICE_WRAP4(HRESULT, GetBackBuffer, UINT, UINT, D3DBACKBUFFER_TYPE, IDirect3DSurface9 **)
|
|
+DEVICE_WRAP2(HRESULT, GetRasterStatus, UINT, D3DRASTER_STATUS *)
|
|
+DEVICE_WRAP1(HRESULT, SetDialogBoxMode, BOOL)
|
|
+DEVICE_H_WRAP3(void, SetGammaRamp, UINT, DWORD, const D3DGAMMARAMP *)
|
|
+DEVICE_WRAP2(void, GetGammaRamp, UINT, D3DGAMMARAMP *)
|
|
+DEVICE_WRAP8(HRESULT, CreateTexture, UINT, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DTexture9 **, HANDLE *)
|
|
+DEVICE_WRAP9(HRESULT, CreateVolumeTexture, UINT, UINT, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DVolumeTexture9 **, HANDLE *)
|
|
+DEVICE_WRAP7(HRESULT, CreateCubeTexture, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DCubeTexture9 **, HANDLE *)
|
|
+DEVICE_WRAP6(HRESULT, CreateVertexBuffer, UINT, DWORD, DWORD, D3DPOOL, IDirect3DVertexBuffer9 **, HANDLE *)
|
|
+DEVICE_WRAP6(HRESULT, CreateIndexBuffer, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DIndexBuffer9 **, HANDLE *)
|
|
+DEVICE_WRAP8(HRESULT, CreateRenderTarget, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, DWORD, BOOL, IDirect3DSurface9 **, HANDLE *)
|
|
+DEVICE_WRAP8(HRESULT, CreateDepthStencilSurface, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, DWORD, BOOL, IDirect3DSurface9 **, HANDLE *)
|
|
+DEVICE_WRAP4(HRESULT, UpdateSurface, IDirect3DSurface9 *, const RECT *, IDirect3DSurface9 *, const POINT *)
|
|
+DEVICE_WRAP2(HRESULT, UpdateTexture, IDirect3DBaseTexture9 *, IDirect3DBaseTexture9 *)
|
|
+DEVICE_WRAP2(HRESULT, GetRenderTargetData, IDirect3DSurface9 *, IDirect3DSurface9 *)
|
|
+DEVICE_WRAP2(HRESULT, GetFrontBufferData, UINT, IDirect3DSurface9 *)
|
|
+DEVICE_WRAP5(HRESULT, StretchRect, IDirect3DSurface9 *, const RECT *, IDirect3DSurface9 *, const RECT *, D3DTEXTUREFILTERTYPE)
|
|
+DEVICE_WRAP3(HRESULT, ColorFill, IDirect3DSurface9 *, const RECT *, D3DCOLOR)
|
|
+DEVICE_WRAP6(HRESULT, CreateOffscreenPlainSurface, UINT, UINT, D3DFORMAT, D3DPOOL, IDirect3DSurface9 **, HANDLE *)
|
|
+DEVICE_WRAP2(HRESULT, SetRenderTarget, DWORD, IDirect3DSurface9 *)
|
|
+DEVICE_WRAP2(HRESULT, GetRenderTarget, DWORD, IDirect3DSurface9 **)
|
|
+DEVICE_WRAP1(HRESULT, SetDepthStencilSurface, IDirect3DSurface9 *)
|
|
+DEVICE_WRAP1(HRESULT, GetDepthStencilSurface, IDirect3DSurface9 **)
|
|
+DEVICE_WRAP0(HRESULT, BeginScene)
|
|
+DEVICE_H_WRAP0(HRESULT, EndScene)
|
|
+DEVICE_WRAP6(HRESULT, Clear, DWORD, const D3DRECT *, DWORD, D3DCOLOR, float, DWORD)
|
|
+DEVICE_WRAP2(HRESULT, SetTransform, D3DTRANSFORMSTATETYPE, const D3DMATRIX *)
|
|
+DEVICE_WRAP2(HRESULT, GetTransform, D3DTRANSFORMSTATETYPE, D3DMATRIX *)
|
|
+DEVICE_WRAP2(HRESULT, MultiplyTransform, D3DTRANSFORMSTATETYPE, const D3DMATRIX *)
|
|
+DEVICE_WRAP1(HRESULT, SetViewport, const D3DVIEWPORT9 *)
|
|
+DEVICE_WRAP1(HRESULT, GetViewport, D3DVIEWPORT9 *)
|
|
+DEVICE_WRAP1(HRESULT, SetMaterial, const D3DMATERIAL9 *)
|
|
+DEVICE_WRAP1(HRESULT, GetMaterial, D3DMATERIAL9 *)
|
|
+DEVICE_WRAP2(HRESULT, SetLight, DWORD, const D3DLIGHT9 *)
|
|
+DEVICE_WRAP2(HRESULT, GetLight, DWORD, D3DLIGHT9 *)
|
|
+DEVICE_WRAP2(HRESULT, LightEnable, DWORD, BOOL)
|
|
+DEVICE_WRAP2(HRESULT, GetLightEnable, DWORD, BOOL *)
|
|
+DEVICE_WRAP2(HRESULT, SetClipPlane, DWORD, const float *)
|
|
+DEVICE_WRAP2(HRESULT, GetClipPlane, DWORD, float *)
|
|
+DEVICE_H_WRAP2(HRESULT, SetRenderState, D3DRENDERSTATETYPE, DWORD)
|
|
+DEVICE_WRAP2(HRESULT, GetRenderState, D3DRENDERSTATETYPE, DWORD *)
|
|
+DEVICE_WRAP2(HRESULT, CreateStateBlock, D3DSTATEBLOCKTYPE, IDirect3DStateBlock9 **)
|
|
+DEVICE_WRAP0(HRESULT, BeginStateBlock)
|
|
+DEVICE_WRAP1(HRESULT, EndStateBlock, IDirect3DStateBlock9 **)
|
|
+DEVICE_WRAP1(HRESULT, SetClipStatus, const D3DCLIPSTATUS9 *)
|
|
+DEVICE_WRAP1(HRESULT, GetClipStatus, D3DCLIPSTATUS9 *)
|
|
+DEVICE_WRAP2(HRESULT, GetTexture, DWORD, IDirect3DBaseTexture9 **)
|
|
+DEVICE_WRAP2(HRESULT, SetTexture, DWORD, IDirect3DBaseTexture9 *)
|
|
+DEVICE_WRAP3(HRESULT, GetTextureStageState, DWORD, D3DTEXTURESTAGESTATETYPE, DWORD *)
|
|
+DEVICE_WRAP3(HRESULT, SetTextureStageState, DWORD, D3DTEXTURESTAGESTATETYPE, DWORD)
|
|
+DEVICE_WRAP3(HRESULT, GetSamplerState, DWORD, D3DSAMPLERSTATETYPE, DWORD *)
|
|
+DEVICE_H_WRAP3(HRESULT, SetSamplerState, DWORD, D3DSAMPLERSTATETYPE, DWORD)
|
|
+DEVICE_WRAP1(HRESULT, ValidateDevice, DWORD *)
|
|
+DEVICE_WRAP2(HRESULT, SetPaletteEntries, UINT, const PALETTEENTRY *)
|
|
+DEVICE_WRAP2(HRESULT, GetPaletteEntries, UINT, PALETTEENTRY *)
|
|
+DEVICE_WRAP1(HRESULT, SetCurrentTexturePalette, UINT)
|
|
+DEVICE_WRAP1(HRESULT, GetCurrentTexturePalette, UINT *)
|
|
+DEVICE_WRAP1(HRESULT, SetScissorRect, const RECT *)
|
|
+DEVICE_WRAP1(HRESULT, GetScissorRect, RECT *)
|
|
+DEVICE_WRAP1(HRESULT, SetSoftwareVertexProcessing, BOOL)
|
|
+DEVICE_WRAP0(BOOL, GetSoftwareVertexProcessing)
|
|
+DEVICE_WRAP1(HRESULT, SetNPatchMode, float)
|
|
+DEVICE_WRAP0(float, GetNPatchMode)
|
|
+DEVICE_WRAP3(HRESULT, DrawPrimitive, D3DPRIMITIVETYPE, UINT, UINT)
|
|
+DEVICE_WRAP6(HRESULT, DrawIndexedPrimitive, D3DPRIMITIVETYPE, INT, UINT, UINT, UINT, UINT)
|
|
+DEVICE_WRAP4(HRESULT, DrawPrimitiveUP, D3DPRIMITIVETYPE, UINT, const void *, UINT)
|
|
+DEVICE_WRAP8(HRESULT, DrawIndexedPrimitiveUP, D3DPRIMITIVETYPE, UINT, UINT, UINT, const void *, D3DFORMAT, const void *, UINT)
|
|
+DEVICE_WRAP6(HRESULT, ProcessVertices, UINT, UINT, UINT, IDirect3DVertexBuffer9 *, IDirect3DVertexDeclaration9 *, DWORD)
|
|
+DEVICE_WRAP2(HRESULT, CreateVertexDeclaration, const D3DVERTEXELEMENT9 *, IDirect3DVertexDeclaration9 **)
|
|
+DEVICE_WRAP1(HRESULT, SetVertexDeclaration, IDirect3DVertexDeclaration9 *)
|
|
+DEVICE_WRAP1(HRESULT, GetVertexDeclaration, IDirect3DVertexDeclaration9 **)
|
|
+DEVICE_WRAP1(HRESULT, SetFVF, DWORD)
|
|
+DEVICE_WRAP1(HRESULT, GetFVF, DWORD *)
|
|
+DEVICE_WRAP2(HRESULT, CreateVertexShader, const DWORD *, IDirect3DVertexShader9 **)
|
|
+DEVICE_WRAP1(HRESULT, SetVertexShader, IDirect3DVertexShader9 *)
|
|
+DEVICE_WRAP1(HRESULT, GetVertexShader, IDirect3DVertexShader9 **)
|
|
+DEVICE_WRAP3(HRESULT, SetVertexShaderConstantF, UINT, const float *, UINT)
|
|
+DEVICE_WRAP3(HRESULT, GetVertexShaderConstantF, UINT, float *, UINT)
|
|
+DEVICE_WRAP3(HRESULT, SetVertexShaderConstantI, UINT, const int *, UINT)
|
|
+DEVICE_WRAP3(HRESULT, GetVertexShaderConstantI, UINT, int *, UINT)
|
|
+DEVICE_WRAP3(HRESULT, SetVertexShaderConstantB, UINT, const BOOL *, UINT)
|
|
+DEVICE_WRAP3(HRESULT, GetVertexShaderConstantB, UINT, BOOL *, UINT)
|
|
+DEVICE_WRAP4(HRESULT, SetStreamSource, UINT, IDirect3DVertexBuffer9 *, UINT, UINT)
|
|
+DEVICE_WRAP4(HRESULT, GetStreamSource, UINT, IDirect3DVertexBuffer9 **, UINT *, UINT *)
|
|
+DEVICE_WRAP2(HRESULT, SetStreamSourceFreq, UINT, UINT)
|
|
+DEVICE_WRAP2(HRESULT, GetStreamSourceFreq, UINT, UINT *)
|
|
+DEVICE_WRAP1(HRESULT, SetIndices, IDirect3DIndexBuffer9 *)
|
|
+DEVICE_WRAP1(HRESULT, GetIndices, IDirect3DIndexBuffer9 **)
|
|
+DEVICE_WRAP2(HRESULT, CreatePixelShader, const DWORD *, IDirect3DPixelShader9 **)
|
|
+DEVICE_WRAP1(HRESULT, SetPixelShader, IDirect3DPixelShader9 *)
|
|
+DEVICE_WRAP1(HRESULT, GetPixelShader, IDirect3DPixelShader9 **)
|
|
+DEVICE_WRAP3(HRESULT, SetPixelShaderConstantF, UINT, const float *, UINT)
|
|
+DEVICE_WRAP3(HRESULT, GetPixelShaderConstantF, UINT, float *, UINT)
|
|
+DEVICE_WRAP3(HRESULT, SetPixelShaderConstantI, UINT, const int *, UINT)
|
|
+DEVICE_WRAP3(HRESULT, GetPixelShaderConstantI, UINT, int *, UINT)
|
|
+DEVICE_WRAP3(HRESULT, SetPixelShaderConstantB, UINT, const BOOL *, UINT)
|
|
+DEVICE_WRAP3(HRESULT, GetPixelShaderConstantB, UINT, BOOL *, UINT)
|
|
+DEVICE_WRAP3(HRESULT, DrawRectPatch, UINT, const float *, const D3DRECTPATCH_INFO *)
|
|
+DEVICE_WRAP3(HRESULT, DrawTriPatch, UINT, const float *, const D3DTRIPATCH_INFO *)
|
|
+DEVICE_WRAP1(HRESULT, DeletePatch, UINT)
|
|
+DEVICE_WRAP2(HRESULT, CreateQuery, D3DQUERYTYPE, IDirect3DQuery9 **)
|
|
+DEVICE_WRAP4(HRESULT, SetConvolutionMonoKernel, UINT, UINT, float *, float *)
|
|
+DEVICE_WRAP8(HRESULT, ComposeRects, IDirect3DSurface9 *, IDirect3DSurface9 *, IDirect3DVertexBuffer9 *, UINT, IDirect3DVertexBuffer9 *, D3DCOMPOSERECTSOP, int, int)
|
|
+DEVICE_H_WRAP5(HRESULT, PresentEx, const RECT *, const RECT *, HWND, const RGNDATA *, DWORD)
|
|
+DEVICE_WRAP1(HRESULT, GetGPUThreadPriority, INT *)
|
|
+DEVICE_WRAP1(HRESULT, SetGPUThreadPriority, INT)
|
|
+DEVICE_WRAP1(HRESULT, WaitForVBlank, UINT)
|
|
+DEVICE_WRAP2(HRESULT, CheckResourceResidency, IDirect3DResource9 **, UINT32)
|
|
+DEVICE_WRAP1(HRESULT, SetMaximumFrameLatency, UINT)
|
|
+DEVICE_WRAP1(HRESULT, GetMaximumFrameLatency, UINT *)
|
|
+DEVICE_WRAP1(HRESULT, CheckDeviceState, HWND)
|
|
+DEVICE_WRAP9(HRESULT, CreateRenderTargetEx, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, DWORD, BOOL, IDirect3DSurface9 **, HANDLE *, DWORD)
|
|
+DEVICE_WRAP7(HRESULT, CreateOffscreenPlainSurfaceEx, UINT, UINT, D3DFORMAT, D3DPOOL, IDirect3DSurface9 **, HANDLE *, DWORD)
|
|
+DEVICE_WRAP9(HRESULT, CreateDepthStencilSurfaceEx, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, DWORD, BOOL, IDirect3DSurface9 **, HANDLE *, DWORD)
|
|
+DEVICE_H_WRAP2(HRESULT, ResetEx, D3DPRESENT_PARAMETERS *, D3DDISPLAYMODEEX *)
|
|
+DEVICE_WRAP3(HRESULT, GetDisplayModeEx, UINT, D3DDISPLAYMODEEX *, D3DDISPLAYROTATION *)
|
|
+
|
|
+IDirect3DSwapChain9ExVtbl WineNineSwapChain9Ex_vtable = {
|
|
+ WineNineSwapChain9_QueryInterface,
|
|
+ WineNineSwapChain9_AddRef,
|
|
+ WineNineSwapChain9_Release,
|
|
+ WineNineSwapChain9_Present,
|
|
+ WineNineSwapChain9_GetFrontBufferData,
|
|
+ WineNineSwapChain9_GetBackBuffer,
|
|
+ WineNineSwapChain9_GetRasterStatus,
|
|
+ WineNineSwapChain9_GetDisplayMode,
|
|
+ WineNineSwapChain9_GetDevice,
|
|
+ WineNineSwapChain9_GetPresentParameters,
|
|
+ WineNineSwapChain9_GetLastPresentCount,
|
|
+ WineNineSwapChain9_GetPresentStats,
|
|
+ WineNineSwapChain9_GetDisplayModeEx
|
|
+};
|
|
+
|
|
+HRESULT WINAPI DECLSPEC_HOTPATCH WineNineDevice9_CreateAdditionalSwapChain(IDirect3DDevice9Ex *This, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DSwapChain9 **pSwapChain)
|
|
+{
|
|
+ HRESULT hr;
|
|
+
|
|
+ hr = ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->CreateAdditionalSwapChain(This, pPresentationParameters, pSwapChain);
|
|
+ if (FAILED(hr))
|
|
+ return hr;
|
|
+
|
|
+ (*pSwapChain)->lpVtbl = (IDirect3DSwapChain9Vtbl *)&WineNineSwapChain9Ex_vtable;
|
|
+
|
|
+ return hr;
|
|
+}
|
|
+
|
|
+HRESULT WINAPI DECLSPEC_HOTPATCH WineNineDevice9_GetSwapChain(IDirect3DDevice9Ex *This, UINT iSwapChain, IDirect3DSwapChain9 **pSwapChain)
|
|
+{
|
|
+ HRESULT hr;
|
|
+
|
|
+ hr = ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->GetSwapChain(This, iSwapChain, pSwapChain);
|
|
+ if (FAILED(hr))
|
|
+ return hr;
|
|
+
|
|
+ (*pSwapChain)->lpVtbl = (IDirect3DSwapChain9Vtbl *)&WineNineSwapChain9Ex_vtable;
|
|
+
|
|
+ return hr;
|
|
+}
|
|
+
|
|
+
|
|
+IDirect3DDevice9ExVtbl WineNineDevice9_vtable = {
|
|
+ WineNineDevice9_QueryInterface,
|
|
+ WineNineDevice9_AddRef,
|
|
+ WineNineDevice9_Release,
|
|
+ WineNineDevice9_TestCooperativeLevel,
|
|
+ WineNineDevice9_GetAvailableTextureMem,
|
|
+ WineNineDevice9_EvictManagedResources,
|
|
+ WineNineDevice9_GetDirect3D,
|
|
+ WineNineDevice9_GetDeviceCaps,
|
|
+ WineNineDevice9_GetDisplayMode,
|
|
+ WineNineDevice9_GetCreationParameters,
|
|
+ WineNineDevice9_SetCursorProperties,
|
|
+ WineNineDevice9_SetCursorPosition,
|
|
+ WineNineDevice9_ShowCursor,
|
|
+ WineNineDevice9_CreateAdditionalSwapChain,
|
|
+ WineNineDevice9_GetSwapChain,
|
|
+ WineNineDevice9_GetNumberOfSwapChains,
|
|
+ WineNineDevice9_Reset,
|
|
+ WineNineDevice9_Present,
|
|
+ WineNineDevice9_GetBackBuffer,
|
|
+ WineNineDevice9_GetRasterStatus,
|
|
+ WineNineDevice9_SetDialogBoxMode,
|
|
+ WineNineDevice9_SetGammaRamp,
|
|
+ WineNineDevice9_GetGammaRamp,
|
|
+ WineNineDevice9_CreateTexture,
|
|
+ WineNineDevice9_CreateVolumeTexture,
|
|
+ WineNineDevice9_CreateCubeTexture,
|
|
+ WineNineDevice9_CreateVertexBuffer,
|
|
+ WineNineDevice9_CreateIndexBuffer,
|
|
+ WineNineDevice9_CreateRenderTarget,
|
|
+ WineNineDevice9_CreateDepthStencilSurface,
|
|
+ WineNineDevice9_UpdateSurface,
|
|
+ WineNineDevice9_UpdateTexture,
|
|
+ WineNineDevice9_GetRenderTargetData,
|
|
+ WineNineDevice9_GetFrontBufferData,
|
|
+ WineNineDevice9_StretchRect,
|
|
+ WineNineDevice9_ColorFill,
|
|
+ WineNineDevice9_CreateOffscreenPlainSurface,
|
|
+ WineNineDevice9_SetRenderTarget,
|
|
+ WineNineDevice9_GetRenderTarget,
|
|
+ WineNineDevice9_SetDepthStencilSurface,
|
|
+ WineNineDevice9_GetDepthStencilSurface,
|
|
+ WineNineDevice9_BeginScene,
|
|
+ WineNineDevice9_EndScene,
|
|
+ WineNineDevice9_Clear,
|
|
+ WineNineDevice9_SetTransform,
|
|
+ WineNineDevice9_GetTransform,
|
|
+ WineNineDevice9_MultiplyTransform,
|
|
+ WineNineDevice9_SetViewport,
|
|
+ WineNineDevice9_GetViewport,
|
|
+ WineNineDevice9_SetMaterial,
|
|
+ WineNineDevice9_GetMaterial,
|
|
+ WineNineDevice9_SetLight,
|
|
+ WineNineDevice9_GetLight,
|
|
+ WineNineDevice9_LightEnable,
|
|
+ WineNineDevice9_GetLightEnable,
|
|
+ WineNineDevice9_SetClipPlane,
|
|
+ WineNineDevice9_GetClipPlane,
|
|
+ WineNineDevice9_SetRenderState,
|
|
+ WineNineDevice9_GetRenderState,
|
|
+ WineNineDevice9_CreateStateBlock,
|
|
+ WineNineDevice9_BeginStateBlock,
|
|
+ WineNineDevice9_EndStateBlock,
|
|
+ WineNineDevice9_SetClipStatus,
|
|
+ WineNineDevice9_GetClipStatus,
|
|
+ WineNineDevice9_GetTexture,
|
|
+ WineNineDevice9_SetTexture,
|
|
+ WineNineDevice9_GetTextureStageState,
|
|
+ WineNineDevice9_SetTextureStageState,
|
|
+ WineNineDevice9_GetSamplerState,
|
|
+ WineNineDevice9_SetSamplerState,
|
|
+ WineNineDevice9_ValidateDevice,
|
|
+ WineNineDevice9_SetPaletteEntries,
|
|
+ WineNineDevice9_GetPaletteEntries,
|
|
+ WineNineDevice9_SetCurrentTexturePalette,
|
|
+ WineNineDevice9_GetCurrentTexturePalette,
|
|
+ WineNineDevice9_SetScissorRect,
|
|
+ WineNineDevice9_GetScissorRect,
|
|
+ WineNineDevice9_SetSoftwareVertexProcessing,
|
|
+ WineNineDevice9_GetSoftwareVertexProcessing,
|
|
+ WineNineDevice9_SetNPatchMode,
|
|
+ WineNineDevice9_GetNPatchMode,
|
|
+ WineNineDevice9_DrawPrimitive,
|
|
+ WineNineDevice9_DrawIndexedPrimitive,
|
|
+ WineNineDevice9_DrawPrimitiveUP,
|
|
+ WineNineDevice9_DrawIndexedPrimitiveUP,
|
|
+ WineNineDevice9_ProcessVertices,
|
|
+ WineNineDevice9_CreateVertexDeclaration,
|
|
+ WineNineDevice9_SetVertexDeclaration,
|
|
+ WineNineDevice9_GetVertexDeclaration,
|
|
+ WineNineDevice9_SetFVF,
|
|
+ WineNineDevice9_GetFVF,
|
|
+ WineNineDevice9_CreateVertexShader,
|
|
+ WineNineDevice9_SetVertexShader,
|
|
+ WineNineDevice9_GetVertexShader,
|
|
+ WineNineDevice9_SetVertexShaderConstantF,
|
|
+ WineNineDevice9_GetVertexShaderConstantF,
|
|
+ WineNineDevice9_SetVertexShaderConstantI,
|
|
+ WineNineDevice9_GetVertexShaderConstantI,
|
|
+ WineNineDevice9_SetVertexShaderConstantB,
|
|
+ WineNineDevice9_GetVertexShaderConstantB,
|
|
+ WineNineDevice9_SetStreamSource,
|
|
+ WineNineDevice9_GetStreamSource,
|
|
+ WineNineDevice9_SetStreamSourceFreq,
|
|
+ WineNineDevice9_GetStreamSourceFreq,
|
|
+ WineNineDevice9_SetIndices,
|
|
+ WineNineDevice9_GetIndices,
|
|
+ WineNineDevice9_CreatePixelShader,
|
|
+ WineNineDevice9_SetPixelShader,
|
|
+ WineNineDevice9_GetPixelShader,
|
|
+ WineNineDevice9_SetPixelShaderConstantF,
|
|
+ WineNineDevice9_GetPixelShaderConstantF,
|
|
+ WineNineDevice9_SetPixelShaderConstantI,
|
|
+ WineNineDevice9_GetPixelShaderConstantI,
|
|
+ WineNineDevice9_SetPixelShaderConstantB,
|
|
+ WineNineDevice9_GetPixelShaderConstantB,
|
|
+ WineNineDevice9_DrawRectPatch,
|
|
+ WineNineDevice9_DrawTriPatch,
|
|
+ WineNineDevice9_DeletePatch,
|
|
+ WineNineDevice9_CreateQuery,
|
|
+ WineNineDevice9_SetConvolutionMonoKernel,
|
|
+ WineNineDevice9_ComposeRects,
|
|
+ WineNineDevice9_PresentEx,
|
|
+ WineNineDevice9_GetGPUThreadPriority,
|
|
+ WineNineDevice9_SetGPUThreadPriority,
|
|
+ WineNineDevice9_WaitForVBlank,
|
|
+ WineNineDevice9_CheckResourceResidency,
|
|
+ WineNineDevice9_SetMaximumFrameLatency,
|
|
+ WineNineDevice9_GetMaximumFrameLatency,
|
|
+ WineNineDevice9_CheckDeviceState,
|
|
+ WineNineDevice9_CreateRenderTargetEx,
|
|
+ WineNineDevice9_CreateOffscreenPlainSurfaceEx,
|
|
+ WineNineDevice9_CreateDepthStencilSurfaceEx,
|
|
+ WineNineDevice9_ResetEx,
|
|
+ WineNineDevice9_GetDisplayModeEx
|
|
+};
|
|
+
|
|
+IDirect3DDevice9ExVtbl *get_device_vtable()
|
|
+{
|
|
+ return &WineNineDevice9_vtable;
|
|
+}
|
|
diff --git a/dlls/d3d9-nine/device_wrap.h b/dlls/d3d9-nine/device_wrap.h
|
|
new file mode 100644
|
|
index 0000000000..8f5e7206a0
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/device_wrap.h
|
|
@@ -0,0 +1,26 @@
|
|
+/*
|
|
+ * Copyright 2016 Axel Davy
|
|
+ *
|
|
+ * 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 __NINE_DEVICE_WRAP_H
|
|
+#define __NINE_DEVICE_WRAP_H
|
|
+
|
|
+#include <d3dadapter/d3dadapter9.h>
|
|
+
|
|
+IDirect3DDevice9ExVtbl *get_device_vtable(void);
|
|
+
|
|
+#endif /* __NINE_DEVICE_WRAP_H */
|
|
diff --git a/dlls/d3d9-nine/dri3.c b/dlls/d3d9-nine/dri3.c
|
|
new file mode 100644
|
|
index 0000000000..3946e7f8bf
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/dri3.c
|
|
@@ -0,0 +1,1426 @@
|
|
+/*
|
|
+ * Wine DRI3 interface
|
|
+ *
|
|
+ * Copyright 2014-2015 Axel Davy
|
|
+ * Copyright 2015 Patrick Rudolph
|
|
+ *
|
|
+ * 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 "config.h"
|
|
+#include "wine/debug.h"
|
|
+
|
|
+WINE_DEFAULT_DEBUG_CHANNEL(d3d9nine);
|
|
+
|
|
+#include "dri3.h"
|
|
+
|
|
+#include <fcntl.h>
|
|
+#include <unistd.h>
|
|
+#include <pthread.h>
|
|
+
|
|
+#include <X11/Xlib-xcb.h>
|
|
+#include <xcb/dri3.h>
|
|
+#include <xcb/present.h>
|
|
+
|
|
+#include "winbase.h"
|
|
+
|
|
+#ifdef D3D9NINE_DRI2
|
|
+#include <sys/ioctl.h>
|
|
+
|
|
+#define BOOL X_BOOL
|
|
+#define BYTE X_BYTE
|
|
+#define INT8 X_INT8
|
|
+#define INT16 X_INT16
|
|
+#define INT32 X_INT32
|
|
+#define INT64 X_INT64
|
|
+#include <X11/Xmd.h>
|
|
+#undef BOOL
|
|
+#undef BYTE
|
|
+#undef INT8
|
|
+#undef INT16
|
|
+#undef INT32
|
|
+#undef INT64
|
|
+#undef LONG64
|
|
+
|
|
+#include <X11/Xlibint.h>
|
|
+#include <X11/extensions/dri2tokens.h>
|
|
+#include <X11/extensions/dri2proto.h>
|
|
+#include <X11/extensions/extutil.h>
|
|
+#define GL_GLEXT_PROTOTYPES 1
|
|
+#define EGL_EGLEXT_PROTOTYPES 1
|
|
+#define GL_GLEXT_LEGACY 1
|
|
+
|
|
+/* workaround for broken ABI on x86_64 due to windef.h */
|
|
+#undef APIENTRY
|
|
+#undef APIENTRYP
|
|
+#include <GL/gl.h>
|
|
+
|
|
+/* workaround gl header bug */
|
|
+#define glBlendColor glBlendColorLEV
|
|
+#define glBlendEquation glBlendEquationLEV
|
|
+#include <GL/glext.h>
|
|
+#include <EGL/egl.h>
|
|
+#include <EGL/eglext.h>
|
|
+#include <libdrm/drm_fourcc.h>
|
|
+#include <libdrm/drm.h>
|
|
+
|
|
+static EGLDisplay display = NULL;
|
|
+static int display_ref = 0;
|
|
+
|
|
+struct DRI2priv {
|
|
+ Display *dpy;
|
|
+ EGLDisplay display;
|
|
+ EGLContext context;
|
|
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_func;
|
|
+ PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR_func;
|
|
+ PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR_func;
|
|
+};
|
|
+#endif
|
|
+
|
|
+struct PRESENTPriv {
|
|
+ xcb_connection_t *xcb_connection;
|
|
+ xcb_connection_t *xcb_connection_bis; /* to avoid libxcb thread bugs, use a different connection to present pixmaps */
|
|
+ XID window;
|
|
+ uint64_t last_msc;
|
|
+ uint64_t last_target;
|
|
+ uint32_t last_serial_given;
|
|
+ xcb_special_event_t *special_event;
|
|
+ PRESENTPixmapPriv *first_present_priv;
|
|
+ int pixmap_present_pending;
|
|
+ BOOL idle_notify_since_last_check;
|
|
+ BOOL notify_with_serial_pending;
|
|
+ CRITICAL_SECTION mutex_present; /* protect readind/writing present_priv things */
|
|
+ CRITICAL_SECTION mutex_xcb_wait;
|
|
+ BOOL xcb_wait;
|
|
+};
|
|
+
|
|
+struct PRESENTPixmapPriv {
|
|
+ PRESENTpriv *present_priv;
|
|
+ Pixmap pixmap;
|
|
+ BOOL released;
|
|
+ unsigned int width;
|
|
+ unsigned int height;
|
|
+ unsigned int depth;
|
|
+ unsigned int present_complete_pending;
|
|
+ uint32_t serial;
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ struct {
|
|
+ BOOL is_dri2;
|
|
+ struct DRI2priv *dri2_priv;
|
|
+ GLuint fbo_read;
|
|
+ GLuint fbo_write;
|
|
+ GLuint texture_read;
|
|
+ GLuint texture_write;
|
|
+ } dri2_info;
|
|
+#endif
|
|
+ BOOL last_present_was_flip;
|
|
+ PRESENTPixmapPriv *next;
|
|
+};
|
|
+
|
|
+BOOL DRI3CheckExtension(Display *dpy, int major, int minor)
|
|
+{
|
|
+ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
|
|
+ xcb_dri3_query_version_cookie_t dri3_cookie;
|
|
+ xcb_dri3_query_version_reply_t *dri3_reply;
|
|
+ xcb_generic_error_t *error;
|
|
+ const xcb_query_extension_reply_t *extension;
|
|
+ int fd;
|
|
+
|
|
+ xcb_prefetch_extension_data(xcb_connection, &xcb_dri3_id);
|
|
+
|
|
+ extension = xcb_get_extension_data(xcb_connection, &xcb_dri3_id);
|
|
+ if (!(extension && extension->present))
|
|
+ {
|
|
+ ERR("DRI3 extension is not present\n");
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ dri3_cookie = xcb_dri3_query_version(xcb_connection, major, minor);
|
|
+
|
|
+ dri3_reply = xcb_dri3_query_version_reply(xcb_connection, dri3_cookie, &error);
|
|
+ if (!dri3_reply)
|
|
+ {
|
|
+ free(error);
|
|
+ ERR("Issue getting requested version of DRI3: %d,%d\n", major, minor);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ if (!DRI3Open(dpy, DefaultScreen(dpy), &fd))
|
|
+ {
|
|
+ ERR("DRI3 advertised, but not working\n");
|
|
+ return FALSE;
|
|
+ }
|
|
+ close(fd);
|
|
+
|
|
+ TRACE("DRI3 version %d,%d found. %d %d requested\n", major, minor,
|
|
+ (int)dri3_reply->major_version, (int)dri3_reply->minor_version);
|
|
+ free(dri3_reply);
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+#ifdef D3D9NINE_DRI2
|
|
+
|
|
+BOOL DRI2FallbackInit(Display *dpy, struct DRI2priv **priv)
|
|
+{
|
|
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_func;
|
|
+ PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR_func;
|
|
+ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT_func;
|
|
+ PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR_func;
|
|
+ EGLint major, minor;
|
|
+ EGLConfig config;
|
|
+ EGLContext context;
|
|
+ EGLint i;
|
|
+ EGLBoolean b;
|
|
+ EGLenum current_api = 0;
|
|
+ const char *extensions;
|
|
+ EGLint config_attribs[] = {
|
|
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
|
|
+ EGL_NONE
|
|
+ };
|
|
+ EGLint context_compatibility_attribs[] = {
|
|
+ EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR,
|
|
+ EGL_NONE
|
|
+ };
|
|
+
|
|
+ current_api = eglQueryAPI();
|
|
+ eglGetPlatformDisplayEXT_func = (PFNEGLGETPLATFORMDISPLAYEXTPROC)
|
|
+ eglGetProcAddress("eglGetPlatformDisplayEXT");
|
|
+
|
|
+ if (!eglGetPlatformDisplayEXT_func)
|
|
+ return FALSE;
|
|
+ if (!display)
|
|
+ display = eglGetPlatformDisplayEXT_func(EGL_PLATFORM_X11_EXT, dpy, NULL);
|
|
+ if (!display)
|
|
+ return FALSE;
|
|
+ /* count references on display for multi device setups */
|
|
+ display_ref++;
|
|
+
|
|
+ if (eglInitialize(display, &major, &minor) != EGL_TRUE)
|
|
+ goto clean_egl_display;
|
|
+
|
|
+ extensions = eglQueryString(display, EGL_CLIENT_APIS);
|
|
+ if (!extensions || !strstr(extensions, "OpenGL"))
|
|
+ goto clean_egl_display;
|
|
+
|
|
+ extensions = eglQueryString(display, EGL_EXTENSIONS);
|
|
+ if (!extensions || !strstr(extensions, "EGL_EXT_image_dma_buf_import") ||
|
|
+ !strstr(extensions, "EGL_KHR_create_context") ||
|
|
+ !strstr(extensions, "EGL_KHR_surfaceless_context") ||
|
|
+ !strstr(extensions, "EGL_KHR_image_base"))
|
|
+ goto clean_egl_display;
|
|
+
|
|
+ if (!eglChooseConfig(display, config_attribs, &config, 1, &i))
|
|
+ goto clean_egl_display;
|
|
+
|
|
+ b = eglBindAPI(EGL_OPENGL_API);
|
|
+ if (b == EGL_FALSE)
|
|
+ goto clean_egl_display;
|
|
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_compatibility_attribs);
|
|
+ if (context == EGL_NO_CONTEXT)
|
|
+ goto clean_egl_display;
|
|
+
|
|
+ glEGLImageTargetTexture2DOES_func = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)
|
|
+ eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
|
+
|
|
+ eglCreateImageKHR_func = (PFNEGLCREATEIMAGEKHRPROC)
|
|
+ eglGetProcAddress("eglCreateImageKHR");
|
|
+
|
|
+ eglDestroyImageKHR_func = (PFNEGLDESTROYIMAGEKHRPROC)
|
|
+ eglGetProcAddress("eglDestroyImageKHR");
|
|
+
|
|
+ if (!eglCreateImageKHR_func ||
|
|
+ !glEGLImageTargetTexture2DOES_func ||
|
|
+ !eglDestroyImageKHR_func)
|
|
+ {
|
|
+ ERR("eglGetProcAddress failed !");
|
|
+ goto clean_egl;
|
|
+ }
|
|
+
|
|
+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
+
|
|
+ *priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ sizeof(struct DRI2priv));
|
|
+ if (!*priv)
|
|
+ goto clean_egl;
|
|
+ (*priv)->dpy = dpy;
|
|
+ (*priv)->display = display;
|
|
+ (*priv)->context = context;
|
|
+ (*priv)->glEGLImageTargetTexture2DOES_func = glEGLImageTargetTexture2DOES_func;
|
|
+ (*priv)->eglCreateImageKHR_func = eglCreateImageKHR_func;
|
|
+ (*priv)->eglDestroyImageKHR_func = eglDestroyImageKHR_func;
|
|
+ eglBindAPI(current_api);
|
|
+ return TRUE;
|
|
+
|
|
+clean_egl:
|
|
+ eglDestroyContext(display, context);
|
|
+
|
|
+clean_egl_display:
|
|
+ eglTerminate(display);
|
|
+ eglBindAPI(current_api);
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+/* hypothesis: at this step all textures, etc are destroyed */
|
|
+void DRI2FallbackDestroy(struct DRI2priv *priv)
|
|
+{
|
|
+ EGLenum current_api;
|
|
+ current_api = eglQueryAPI();
|
|
+ eglBindAPI(EGL_OPENGL_API);
|
|
+ eglMakeCurrent(priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
+ eglDestroyContext(priv->display, priv->context);
|
|
+ if (display)
|
|
+ {
|
|
+ /* destroy display connection with last device */
|
|
+ display_ref--;
|
|
+ if (!display_ref)
|
|
+ {
|
|
+ eglTerminate(display);
|
|
+ display = NULL;
|
|
+ }
|
|
+ }
|
|
+ eglBindAPI(current_api);
|
|
+ HeapFree(GetProcessHeap(), 0, priv);
|
|
+}
|
|
+
|
|
+BOOL DRI2FallbackCheckSupport(Display *dpy)
|
|
+{
|
|
+ struct DRI2priv *priv;
|
|
+ int fd;
|
|
+ if (!DRI2FallbackInit(dpy, &priv))
|
|
+ return FALSE;
|
|
+ DRI2FallbackDestroy(priv);
|
|
+ if (!DRI2FallbackOpen(dpy, DefaultScreen(dpy), &fd))
|
|
+ return FALSE;
|
|
+ close(fd);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+BOOL PRESENTCheckExtension(Display *dpy, int major, int minor)
|
|
+{
|
|
+ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
|
|
+ xcb_present_query_version_cookie_t present_cookie;
|
|
+ xcb_present_query_version_reply_t *present_reply;
|
|
+ xcb_generic_error_t *error;
|
|
+ const xcb_query_extension_reply_t *extension;
|
|
+
|
|
+ xcb_prefetch_extension_data(xcb_connection, &xcb_present_id);
|
|
+
|
|
+ extension = xcb_get_extension_data(xcb_connection, &xcb_present_id);
|
|
+ if (!(extension && extension->present))
|
|
+ {
|
|
+ ERR("PRESENT extension is not present\n");
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ present_cookie = xcb_present_query_version(xcb_connection, major, minor);
|
|
+
|
|
+ present_reply = xcb_present_query_version_reply(xcb_connection, present_cookie, &error);
|
|
+ if (!present_reply)
|
|
+ {
|
|
+ free(error);
|
|
+ ERR("Issue getting requested version of PRESENT: %d,%d\n", major, minor);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ TRACE("PRESENT version %d,%d found. %u %u requested\n", major, minor,
|
|
+ present_reply->major_version, present_reply->minor_version);
|
|
+
|
|
+ free(present_reply);
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+BOOL DRI3Open(Display *dpy, int screen, int *device_fd)
|
|
+{
|
|
+ xcb_dri3_open_cookie_t cookie;
|
|
+ xcb_dri3_open_reply_t *reply;
|
|
+ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
|
|
+ int fd;
|
|
+ Window root = RootWindow(dpy, screen);
|
|
+
|
|
+ cookie = xcb_dri3_open(xcb_connection, root, 0);
|
|
+
|
|
+ reply = xcb_dri3_open_reply(xcb_connection, cookie, NULL);
|
|
+ if (!reply)
|
|
+ return FALSE;
|
|
+
|
|
+ if (reply->nfd != 1)
|
|
+ {
|
|
+ free(reply);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ fd = xcb_dri3_open_reply_fds(xcb_connection, reply)[0];
|
|
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
|
|
+
|
|
+ *device_fd = fd;
|
|
+ free(reply);
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+#ifdef D3D9NINE_DRI2
|
|
+
|
|
+static XExtensionInfo _dri2_info_data;
|
|
+static XExtensionInfo *dri2_info = &_dri2_info_data;
|
|
+static char dri2_name[] = DRI2_NAME;
|
|
+
|
|
+#define DRI2CheckExtension(dpy, i, val) \
|
|
+ XextCheckExtension(dpy, i, dri2_name, val)
|
|
+
|
|
+static int close_display(Display *dpy, XExtCodes *codes);
|
|
+static Bool wire_to_event(Display *dpy, XEvent *re, xEvent *event);
|
|
+static Status event_to_wire(Display *dpy, XEvent *re, xEvent *event);
|
|
+static int error( Display *dpy, xError *err, XExtCodes *codes, int *ret_code );
|
|
+
|
|
+static XExtensionHooks dri2_hooks = {
|
|
+ NULL, /* create_gc */
|
|
+ NULL, /* copy_gc */
|
|
+ NULL, /* flush_gc */
|
|
+ NULL, /* free_gc */
|
|
+ NULL, /* create_font */
|
|
+ NULL, /* free_font */
|
|
+ close_display, /* close_display */
|
|
+ wire_to_event, /* wire_to_event */
|
|
+ event_to_wire, /* event_to_wire */
|
|
+ error, /* error */
|
|
+ NULL, /* error_string */
|
|
+};
|
|
+static XEXT_GENERATE_CLOSE_DISPLAY(close_display, dri2_info);
|
|
+static XEXT_GENERATE_FIND_DISPLAY(find_display, dri2_info,
|
|
+ dri2_name, &dri2_hooks, 0, NULL);
|
|
+static Bool wire_to_event(Display *dpy, XEvent *re, xEvent *event)
|
|
+{
|
|
+ XExtDisplayInfo *info = find_display(dpy);
|
|
+ DRI2CheckExtension(dpy, info, False);
|
|
+ TRACE("dri2 wire_to_event\n");
|
|
+ return False;
|
|
+}
|
|
+
|
|
+static Status event_to_wire(Display *dpy, XEvent *re, xEvent *event)
|
|
+{
|
|
+ XExtDisplayInfo *info = find_display(dpy);
|
|
+ DRI2CheckExtension(dpy, info, False);
|
|
+ TRACE("dri2 event_to_wire\n");
|
|
+ return False;
|
|
+}
|
|
+
|
|
+static int error(Display *dpy, xError *err, XExtCodes *codes, int *ret_code)
|
|
+{
|
|
+ TRACE("dri2 error\n");
|
|
+ return False;
|
|
+}
|
|
+
|
|
+#define XALIGN(x) (((x) + 3) & (~3))
|
|
+
|
|
+static BOOL DRI2Connect(Display *dpy, XID window, unsigned driver_type, char **device)
|
|
+{
|
|
+ XExtDisplayInfo *info = find_display(dpy);
|
|
+ xDRI2ConnectReply rep;
|
|
+ xDRI2ConnectReq *req;
|
|
+ int dev_len, driv_len;
|
|
+ char *driver;
|
|
+
|
|
+ DRI2CheckExtension(dpy, info, False);
|
|
+
|
|
+ *device = NULL;
|
|
+
|
|
+ LockDisplay(dpy);
|
|
+ GetReq(DRI2Connect, req);
|
|
+ req->reqType = info->codes->major_opcode;
|
|
+ req->dri2ReqType = X_DRI2Connect;
|
|
+ req->window = window;
|
|
+ req->driverType = driver_type;
|
|
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
|
|
+ {
|
|
+ UnlockDisplay(dpy);
|
|
+ SyncHandle();
|
|
+ return False;
|
|
+ }
|
|
+
|
|
+ /* check string lengths */
|
|
+ dev_len = rep.deviceNameLength;
|
|
+ driv_len = rep.driverNameLength;
|
|
+ if (dev_len == 0 || driv_len == 0)
|
|
+ {
|
|
+ _XEatData(dpy, XALIGN(dev_len) + XALIGN(driv_len));
|
|
+ UnlockDisplay(dpy);
|
|
+ SyncHandle();
|
|
+ return False;
|
|
+ }
|
|
+
|
|
+ /* read out driver */
|
|
+ driver = HeapAlloc(GetProcessHeap(), 0, driv_len + 1);
|
|
+ if (!driver)
|
|
+ {
|
|
+ _XEatData(dpy, XALIGN(dev_len) + XALIGN(driv_len));
|
|
+ UnlockDisplay(dpy);
|
|
+ SyncHandle();
|
|
+ return False;
|
|
+ }
|
|
+ _XReadPad(dpy, driver, driv_len);
|
|
+ HeapFree(GetProcessHeap(), 0, driver); /* we don't need the driver */
|
|
+
|
|
+ /* read out device */
|
|
+ *device = HeapAlloc(GetProcessHeap(), 0, dev_len + 1);
|
|
+ if (!*device)
|
|
+ {
|
|
+ _XEatData(dpy, XALIGN(dev_len));
|
|
+ UnlockDisplay(dpy);
|
|
+ SyncHandle();
|
|
+ return False;
|
|
+ }
|
|
+ _XReadPad(dpy, *device, dev_len);
|
|
+ (*device)[dev_len] = '\0';
|
|
+
|
|
+ UnlockDisplay(dpy);
|
|
+ SyncHandle();
|
|
+
|
|
+ return True;
|
|
+}
|
|
+
|
|
+static Bool DRI2Authenticate(Display *dpy, XID window, uint32_t token)
|
|
+{
|
|
+ XExtDisplayInfo *info = find_display(dpy);
|
|
+ xDRI2AuthenticateReply rep;
|
|
+ xDRI2AuthenticateReq *req;
|
|
+
|
|
+ DRI2CheckExtension(dpy, info, False);
|
|
+
|
|
+ LockDisplay(dpy);
|
|
+ GetReq(DRI2Authenticate, req);
|
|
+ req->reqType = info->codes->major_opcode;
|
|
+ req->dri2ReqType = X_DRI2Authenticate;
|
|
+ req->window = window;
|
|
+ req->magic = token;
|
|
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse))
|
|
+ {
|
|
+ UnlockDisplay(dpy);
|
|
+ SyncHandle();
|
|
+ return False;
|
|
+ }
|
|
+ UnlockDisplay(dpy);
|
|
+ SyncHandle();
|
|
+
|
|
+ return rep.authenticated ? True : False;
|
|
+}
|
|
+
|
|
+BOOL DRI2FallbackOpen(Display *dpy, int screen, int *device_fd)
|
|
+{
|
|
+ char *device;
|
|
+ int fd;
|
|
+ Window root = RootWindow(dpy, screen);
|
|
+ drm_auth_t auth;
|
|
+
|
|
+ if (!DRI2Connect(dpy, root, DRI2DriverDRI, &device))
|
|
+ return FALSE;
|
|
+
|
|
+ fd = open(device, O_RDWR);
|
|
+ HeapFree(GetProcessHeap(), 0, device);
|
|
+ if (fd < 0)
|
|
+ return FALSE;
|
|
+
|
|
+ if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth) != 0)
|
|
+ {
|
|
+ close(fd);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ if (!DRI2Authenticate(dpy, root, auth.magic))
|
|
+ {
|
|
+ close(fd);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ *device_fd = fd;
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+
|
|
+BOOL DRI3PixmapFromDmaBuf(Display *dpy, int screen, int fd, int width, int height,
|
|
+ int stride, int depth, int bpp, Pixmap *pixmap)
|
|
+{
|
|
+ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
|
|
+ Window root = RootWindow(dpy, screen);
|
|
+ xcb_void_cookie_t cookie;
|
|
+ xcb_generic_error_t *error;
|
|
+
|
|
+ cookie = xcb_dri3_pixmap_from_buffer_checked(xcb_connection,
|
|
+ (*pixmap = xcb_generate_id(xcb_connection)), root, 0,
|
|
+ width, height, stride, depth, bpp, fd);
|
|
+
|
|
+ error = xcb_request_check(xcb_connection, cookie); /* performs a flush */
|
|
+ if (error)
|
|
+ {
|
|
+ ERR("Error using DRI3 to convert a DmaBufFd to pixmap\n");
|
|
+ return FALSE;
|
|
+ }
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+BOOL DRI3DmaBufFromPixmap(Display *dpy, Pixmap pixmap, int *fd, int *width, int *height,
|
|
+ int *stride, int *depth, int *bpp)
|
|
+{
|
|
+ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
|
|
+ xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
|
|
+ xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
|
|
+
|
|
+ bp_cookie = xcb_dri3_buffer_from_pixmap(xcb_connection, pixmap);
|
|
+ bp_reply = xcb_dri3_buffer_from_pixmap_reply(xcb_connection, bp_cookie, NULL);
|
|
+ if (!bp_reply)
|
|
+ return FALSE;
|
|
+ *fd = xcb_dri3_buffer_from_pixmap_reply_fds(xcb_connection, bp_reply)[0];
|
|
+ *width = bp_reply->width;
|
|
+ *height = bp_reply->height;
|
|
+ *stride = bp_reply->stride;
|
|
+ *depth = bp_reply->depth;
|
|
+ *bpp = bp_reply->depth;
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static PRESENTPixmapPriv *PRESENTFindPixmapPriv(PRESENTpriv *present_priv, uint32_t serial)
|
|
+{
|
|
+ PRESENTPixmapPriv *current = present_priv->first_present_priv;
|
|
+
|
|
+ while (current)
|
|
+ {
|
|
+ if (current->serial == serial)
|
|
+ return current;
|
|
+ current = current->next;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void PRESENThandle_events(PRESENTpriv *present_priv, xcb_present_generic_event_t *ge)
|
|
+{
|
|
+ PRESENTPixmapPriv *present_pixmap_priv = NULL;
|
|
+
|
|
+ switch (ge->evtype)
|
|
+ {
|
|
+ case XCB_PRESENT_COMPLETE_NOTIFY:
|
|
+ {
|
|
+ xcb_present_complete_notify_event_t *ce = (void *) ge;
|
|
+ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC)
|
|
+ {
|
|
+ if (ce->serial)
|
|
+ present_priv->notify_with_serial_pending = FALSE;
|
|
+ free(ce);
|
|
+ return;
|
|
+ }
|
|
+ present_pixmap_priv = PRESENTFindPixmapPriv(present_priv, ce->serial);
|
|
+ if (!present_pixmap_priv || ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
|
|
+ {
|
|
+ ERR("FATAL ERROR: PRESENT handling failed\n");
|
|
+ free(ce);
|
|
+ return;
|
|
+ }
|
|
+ present_pixmap_priv->present_complete_pending--;
|
|
+ switch (ce->mode)
|
|
+ {
|
|
+ case XCB_PRESENT_COMPLETE_MODE_FLIP:
|
|
+ present_pixmap_priv->last_present_was_flip = TRUE;
|
|
+ break;
|
|
+ case XCB_PRESENT_COMPLETE_MODE_COPY:
|
|
+ present_pixmap_priv->last_present_was_flip = FALSE;
|
|
+ break;
|
|
+ }
|
|
+ present_priv->pixmap_present_pending--;
|
|
+ present_priv->last_msc = ce->msc;
|
|
+ break;
|
|
+ }
|
|
+ case XCB_PRESENT_EVENT_IDLE_NOTIFY:
|
|
+ {
|
|
+ xcb_present_idle_notify_event_t *ie = (void *) ge;
|
|
+ present_pixmap_priv = PRESENTFindPixmapPriv(present_priv, ie->serial);
|
|
+ if (!present_pixmap_priv || present_pixmap_priv->pixmap != ie->pixmap)
|
|
+ {
|
|
+ ERR("FATAL ERROR: PRESENT handling failed\n");
|
|
+ free(ie);
|
|
+ return;
|
|
+ }
|
|
+ present_pixmap_priv->released = TRUE;
|
|
+ present_priv->idle_notify_since_last_check = TRUE;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ free(ge);
|
|
+}
|
|
+
|
|
+static void PRESENTflush_events(PRESENTpriv *present_priv, BOOL assert_no_other_thread_waiting)
|
|
+{
|
|
+ xcb_generic_event_t *ev;
|
|
+
|
|
+ if ((present_priv->xcb_wait && !assert_no_other_thread_waiting) || /* don't steal events to someone waiting */
|
|
+ !present_priv->special_event)
|
|
+ return;
|
|
+
|
|
+ while ((ev = xcb_poll_for_special_event(present_priv->xcb_connection,
|
|
+ present_priv->special_event)) != NULL)
|
|
+ {
|
|
+ PRESENThandle_events(present_priv, (void *) ev);
|
|
+ }
|
|
+}
|
|
+
|
|
+static BOOL PRESENTwait_events(PRESENTpriv *present_priv, BOOL allow_other_threads)
|
|
+{
|
|
+ xcb_generic_event_t *ev;
|
|
+
|
|
+ if (allow_other_threads)
|
|
+ {
|
|
+ present_priv->xcb_wait = TRUE;
|
|
+ EnterCriticalSection(&present_priv->mutex_xcb_wait);
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ }
|
|
+ ev = xcb_wait_for_special_event(present_priv->xcb_connection, present_priv->special_event);
|
|
+ if (allow_other_threads)
|
|
+ {
|
|
+ LeaveCriticalSection(&present_priv->mutex_xcb_wait);
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+ present_priv->xcb_wait = FALSE;
|
|
+ }
|
|
+ if (!ev)
|
|
+ {
|
|
+ ERR("FATAL error: xcb had an error\n");
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ PRESENThandle_events(present_priv, (void *) ev);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static struct xcb_connection_t *create_xcb_connection(Display *dpy)
|
|
+{
|
|
+ int screen_num = DefaultScreen(dpy);
|
|
+ xcb_connection_t *ret;
|
|
+ xcb_xfixes_query_version_cookie_t cookie;
|
|
+ xcb_xfixes_query_version_reply_t *rep;
|
|
+
|
|
+ ret = xcb_connect(DisplayString(dpy), &screen_num);
|
|
+ cookie = xcb_xfixes_query_version_unchecked(ret, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
|
|
+ rep = xcb_xfixes_query_version_reply(ret, cookie, NULL);
|
|
+ if (rep)
|
|
+ free(rep);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+BOOL PRESENTInit(Display *dpy, PRESENTpriv **present_priv)
|
|
+{
|
|
+ *present_priv = (PRESENTpriv *) HeapAlloc(GetProcessHeap(),
|
|
+ HEAP_ZERO_MEMORY, sizeof(PRESENTpriv));
|
|
+
|
|
+ if (!*present_priv)
|
|
+ return FALSE;
|
|
+
|
|
+ (*present_priv)->xcb_connection = create_xcb_connection(dpy);
|
|
+ (*present_priv)->xcb_connection_bis = create_xcb_connection(dpy);
|
|
+
|
|
+ InitializeCriticalSection(&(*present_priv)->mutex_present);
|
|
+ InitializeCriticalSection(&(*present_priv)->mutex_xcb_wait);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static void PRESENTForceReleases(PRESENTpriv *present_priv)
|
|
+{
|
|
+ PRESENTPixmapPriv *current = NULL;
|
|
+
|
|
+ if (!present_priv->window)
|
|
+ return;
|
|
+
|
|
+ /* There should be no other thread listening for events here.
|
|
+ * This can happen when hDestWindowOverride changes without reset.
|
|
+ * This case should never happen, but can happen in theory.*/
|
|
+ if (present_priv->xcb_wait)
|
|
+ {
|
|
+ xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 0, 0, 0, 0);
|
|
+ xcb_flush(present_priv->xcb_connection);
|
|
+ EnterCriticalSection(&present_priv->mutex_xcb_wait);
|
|
+ LeaveCriticalSection(&present_priv->mutex_xcb_wait);
|
|
+ /* the problem here is that we don't have access to the event the other thread got.
|
|
+ * It is either presented event, idle event or notify event.
|
|
+ */
|
|
+ while (present_priv->pixmap_present_pending >= 2)
|
|
+ PRESENTwait_events(present_priv, FALSE);
|
|
+ PRESENTflush_events(present_priv, TRUE);
|
|
+ /* Remaining events to come can be a pair of present/idle,
|
|
+ * or an idle, or nothing. To be sure we are after all pixmaps
|
|
+ * have been presented, add an event to the queue that can only
|
|
+ * be after the present event, then if we receive an event more,
|
|
+ * we are sure all pixmaps were presented */
|
|
+ present_priv->notify_with_serial_pending = TRUE;
|
|
+ xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window,
|
|
+ 1, present_priv->last_target + 5, 0, 0);
|
|
+
|
|
+ xcb_flush(present_priv->xcb_connection);
|
|
+ while (present_priv->notify_with_serial_pending)
|
|
+ PRESENTwait_events(present_priv, FALSE);
|
|
+ /* Now we are sure we are not expecting any new event */
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ while (present_priv->pixmap_present_pending) /* wait all sent pixmaps are presented */
|
|
+ PRESENTwait_events(present_priv, FALSE);
|
|
+ PRESENTflush_events(present_priv, TRUE); /* may be remaining idle event */
|
|
+ /* Since idle events are send with the complete events when it is not flips,
|
|
+ * we are not expecting any new event here */
|
|
+ }
|
|
+
|
|
+ current = present_priv->first_present_priv;
|
|
+ while (current)
|
|
+ {
|
|
+ if (!current->released)
|
|
+ {
|
|
+ if (!current->last_present_was_flip && !present_priv->xcb_wait)
|
|
+ {
|
|
+ ERR("ERROR: a pixmap seems not released by PRESENT for no reason. Code bug.\n");
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* Present the same pixmap with a non-valid part to force the copy mode and the releases */
|
|
+ xcb_xfixes_region_t valid, update;
|
|
+ xcb_rectangle_t rect_update;
|
|
+ rect_update.x = 0;
|
|
+ rect_update.y = 0;
|
|
+ rect_update.width = 8;
|
|
+ rect_update.height = 1;
|
|
+ valid = xcb_generate_id(present_priv->xcb_connection);
|
|
+ update = xcb_generate_id(present_priv->xcb_connection);
|
|
+ xcb_xfixes_create_region(present_priv->xcb_connection, valid, 1, &rect_update);
|
|
+ xcb_xfixes_create_region(present_priv->xcb_connection, update, 1, &rect_update);
|
|
+ /* here we know the pixmap has been presented. Thus if it is on screen,
|
|
+ * the following request can only make it released by the server if it is not */
|
|
+ xcb_present_pixmap(present_priv->xcb_connection, present_priv->window,
|
|
+ current->pixmap, 0, valid, update, 0, 0, None, None,
|
|
+ None, XCB_PRESENT_OPTION_COPY | XCB_PRESENT_OPTION_ASYNC, 0, 0, 0, 0, NULL);
|
|
+ xcb_flush(present_priv->xcb_connection);
|
|
+ PRESENTwait_events(present_priv, FALSE); /* by assumption this can only be idle event */
|
|
+ PRESENTflush_events(present_priv, TRUE); /* Shoudln't be needed */
|
|
+ }
|
|
+ }
|
|
+ current = current->next;
|
|
+ }
|
|
+ /* Now all pixmaps are released (possibility if xcb_wait is true that one is not aware yet),
|
|
+ * and we don't expect any new Present event to come from Xserver */
|
|
+}
|
|
+
|
|
+static void PRESENTFreeXcbQueue(PRESENTpriv *present_priv)
|
|
+{
|
|
+ if (present_priv->window)
|
|
+ {
|
|
+ xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event);
|
|
+ present_priv->last_msc = 0;
|
|
+ present_priv->last_target = 0;
|
|
+ present_priv->special_event = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+static BOOL PRESENTPrivChangeWindow(PRESENTpriv *present_priv, XID window)
|
|
+{
|
|
+ xcb_void_cookie_t cookie;
|
|
+ xcb_generic_error_t *error;
|
|
+ xcb_present_event_t eid;
|
|
+
|
|
+ PRESENTForceReleases(present_priv);
|
|
+ PRESENTFreeXcbQueue(present_priv);
|
|
+ present_priv->window = window;
|
|
+
|
|
+ if (window)
|
|
+ {
|
|
+ cookie = xcb_present_select_input_checked(present_priv->xcb_connection,
|
|
+ (eid = xcb_generate_id(present_priv->xcb_connection)), window,
|
|
+ XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY | XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
|
|
+
|
|
+ present_priv->special_event = xcb_register_for_special_xge(present_priv->xcb_connection,
|
|
+ &xcb_present_id, eid, NULL);
|
|
+
|
|
+ error = xcb_request_check(present_priv->xcb_connection, cookie); /* performs a flush */
|
|
+ if (error || !present_priv->special_event)
|
|
+ {
|
|
+ ERR("FAILED to use the X PRESENT extension. Was the destination a window ?\n");
|
|
+ if (present_priv->special_event)
|
|
+ xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event);
|
|
+ present_priv->special_event = NULL;
|
|
+ present_priv->window = 0;
|
|
+ }
|
|
+ }
|
|
+ return (present_priv->window != 0);
|
|
+}
|
|
+
|
|
+/* Destroy the content, except the link and the struct mem */
|
|
+static void PRESENTDestroyPixmapContent(Display *dpy, PRESENTPixmapPriv *present_pixmap)
|
|
+{
|
|
+ XFreePixmap(dpy, present_pixmap->pixmap);
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ if (present_pixmap->dri2_info.is_dri2)
|
|
+ {
|
|
+ struct DRI2priv *dri2_priv = present_pixmap->dri2_info.dri2_priv;
|
|
+ EGLenum current_api;
|
|
+ current_api = eglQueryAPI();
|
|
+ eglBindAPI(EGL_OPENGL_API);
|
|
+ if (eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context))
|
|
+ {
|
|
+ glDeleteFramebuffers(1, &present_pixmap->dri2_info.fbo_read);
|
|
+ glDeleteFramebuffers(1, &present_pixmap->dri2_info.fbo_write);
|
|
+ glDeleteTextures(1, &present_pixmap->dri2_info.texture_read);
|
|
+ glDeleteTextures(1, &present_pixmap->dri2_info.texture_write);
|
|
+ }
|
|
+ else
|
|
+ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
|
|
+
|
|
+ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
+ eglBindAPI(current_api);
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
+void PRESENTDestroy(Display *dpy, PRESENTpriv *present_priv)
|
|
+{
|
|
+ PRESENTPixmapPriv *current = NULL;
|
|
+
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+
|
|
+ PRESENTForceReleases(present_priv);
|
|
+
|
|
+ current = present_priv->first_present_priv;
|
|
+ while (current)
|
|
+ {
|
|
+ PRESENTPixmapPriv *next = current->next;
|
|
+ PRESENTDestroyPixmapContent(dpy, current);
|
|
+ HeapFree(GetProcessHeap(), 0, current);
|
|
+ current = next;
|
|
+ }
|
|
+
|
|
+ PRESENTFreeXcbQueue(present_priv);
|
|
+
|
|
+ xcb_disconnect(present_priv->xcb_connection);
|
|
+ xcb_disconnect(present_priv->xcb_connection_bis);
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ DeleteCriticalSection(&present_priv->mutex_present);
|
|
+ DeleteCriticalSection(&present_priv->mutex_xcb_wait);
|
|
+
|
|
+ HeapFree(GetProcessHeap(), 0, present_priv);
|
|
+}
|
|
+
|
|
+BOOL PRESENTPixmapInit(PRESENTpriv *present_priv, Pixmap pixmap, PRESENTPixmapPriv **present_pixmap_priv)
|
|
+{
|
|
+ xcb_get_geometry_cookie_t cookie;
|
|
+ xcb_get_geometry_reply_t *reply;
|
|
+
|
|
+ cookie = xcb_get_geometry(present_priv->xcb_connection, pixmap);
|
|
+ reply = xcb_get_geometry_reply(present_priv->xcb_connection, cookie, NULL);
|
|
+
|
|
+ if (!reply)
|
|
+ return FALSE;
|
|
+
|
|
+ *present_pixmap_priv = (PRESENTPixmapPriv *) HeapAlloc(GetProcessHeap(),
|
|
+ HEAP_ZERO_MEMORY, sizeof(PRESENTPixmapPriv));
|
|
+
|
|
+ if (!*present_pixmap_priv)
|
|
+ {
|
|
+ free(reply);
|
|
+ return FALSE;
|
|
+ }
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+
|
|
+ (*present_pixmap_priv)->released = TRUE;
|
|
+ (*present_pixmap_priv)->pixmap = pixmap;
|
|
+ (*present_pixmap_priv)->present_priv = present_priv;
|
|
+ (*present_pixmap_priv)->next = present_priv->first_present_priv;
|
|
+ (*present_pixmap_priv)->width = reply->width;
|
|
+ (*present_pixmap_priv)->height = reply->height;
|
|
+ (*present_pixmap_priv)->depth = reply->depth;
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ (*present_pixmap_priv)->dri2_info.is_dri2 = FALSE;
|
|
+#endif
|
|
+ free(reply);
|
|
+
|
|
+ present_priv->last_serial_given++;
|
|
+ (*present_pixmap_priv)->serial = present_priv->last_serial_given;
|
|
+ present_priv->first_present_priv = *present_pixmap_priv;
|
|
+
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+#ifdef D3D9NINE_DRI2
|
|
+
|
|
+BOOL DRI2FallbackPRESENTPixmap(PRESENTpriv *present_priv, struct DRI2priv *dri2_priv,
|
|
+ int fd, int width, int height, int stride, int depth,
|
|
+ int bpp, PRESENTPixmapPriv **present_pixmap_priv)
|
|
+{
|
|
+ Window root = RootWindow(dri2_priv->dpy, DefaultScreen(dri2_priv->dpy));
|
|
+ Pixmap pixmap;
|
|
+ EGLImageKHR image;
|
|
+ GLuint texture_read, texture_write, fbo_read, fbo_write;
|
|
+ EGLint attribs[] = {
|
|
+ EGL_WIDTH, 0,
|
|
+ EGL_HEIGHT, 0,
|
|
+ EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
|
|
+ EGL_DMA_BUF_PLANE0_FD_EXT, 0,
|
|
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
|
|
+ EGL_DMA_BUF_PLANE0_PITCH_EXT, 0,
|
|
+ EGL_NONE
|
|
+ };
|
|
+ EGLenum current_api = 0;
|
|
+ int status;
|
|
+
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+
|
|
+ pixmap = XCreatePixmap(dri2_priv->dpy, root, width, height, 24);
|
|
+ if (!pixmap)
|
|
+ goto fail;
|
|
+
|
|
+ attribs[1] = width;
|
|
+ attribs[3] = height;
|
|
+ attribs[7] = fd;
|
|
+ attribs[11] = stride;
|
|
+
|
|
+ current_api = eglQueryAPI();
|
|
+ eglBindAPI(EGL_OPENGL_API);
|
|
+
|
|
+ /* We bind the dma-buf to a EGLImage, then to a texture, and then to a fbo.
|
|
+ * Note that we can delete the EGLImage, but we shouldn't delete the texture,
|
|
+ * else the fbo is invalid */
|
|
+
|
|
+ image = dri2_priv->eglCreateImageKHR_func(dri2_priv->display,
|
|
+ EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
|
|
+
|
|
+ if (image == EGL_NO_IMAGE_KHR)
|
|
+ goto fail;
|
|
+ close(fd);
|
|
+
|
|
+ if (eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context))
|
|
+ {
|
|
+ glGenTextures(1, &texture_read);
|
|
+ glBindTexture(GL_TEXTURE_2D, texture_read);
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
+ dri2_priv->glEGLImageTargetTexture2DOES_func(GL_TEXTURE_2D, image);
|
|
+ glGenFramebuffers(1, &fbo_read);
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo_read);
|
|
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
|
|
+ GL_COLOR_ATTACHMENT0,
|
|
+ GL_TEXTURE_2D, texture_read,
|
|
+ 0);
|
|
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
+ if (status != GL_FRAMEBUFFER_COMPLETE)
|
|
+ goto fail;
|
|
+ glBindTexture(GL_TEXTURE_2D, 0);
|
|
+ dri2_priv->eglDestroyImageKHR_func(dri2_priv->display, image);
|
|
+
|
|
+ /* We bind a newly created pixmap (to which we want to copy the content)
|
|
+ * to an EGLImage, then to a texture, then to a fbo. */
|
|
+ image = dri2_priv->eglCreateImageKHR_func(dri2_priv->display,
|
|
+ dri2_priv->context,
|
|
+ EGL_NATIVE_PIXMAP_KHR,
|
|
+ (void *)pixmap, NULL);
|
|
+ if (image == EGL_NO_IMAGE_KHR)
|
|
+ goto fail;
|
|
+
|
|
+ glGenTextures(1, &texture_write);
|
|
+ glBindTexture(GL_TEXTURE_2D, texture_write);
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
+ dri2_priv->glEGLImageTargetTexture2DOES_func(GL_TEXTURE_2D, image);
|
|
+ glGenFramebuffers(1, &fbo_write);
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo_write);
|
|
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
|
|
+ GL_COLOR_ATTACHMENT0,
|
|
+ GL_TEXTURE_2D, texture_write,
|
|
+ 0);
|
|
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
+ if (status != GL_FRAMEBUFFER_COMPLETE)
|
|
+ goto fail;
|
|
+ glBindTexture(GL_TEXTURE_2D, 0);
|
|
+ dri2_priv->eglDestroyImageKHR_func(dri2_priv->display, image);
|
|
+ }
|
|
+ else
|
|
+ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
|
|
+
|
|
+ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
+
|
|
+ *present_pixmap_priv = (PRESENTPixmapPriv *) HeapAlloc(GetProcessHeap(),
|
|
+ HEAP_ZERO_MEMORY, sizeof(PRESENTPixmapPriv));
|
|
+
|
|
+ if (!*present_pixmap_priv)
|
|
+ goto fail;
|
|
+
|
|
+ (*present_pixmap_priv)->released = TRUE;
|
|
+ (*present_pixmap_priv)->pixmap = pixmap;
|
|
+ (*present_pixmap_priv)->present_priv = present_priv;
|
|
+ (*present_pixmap_priv)->next = present_priv->first_present_priv;
|
|
+ (*present_pixmap_priv)->width = width;
|
|
+ (*present_pixmap_priv)->height = height;
|
|
+ (*present_pixmap_priv)->depth = depth;
|
|
+ (*present_pixmap_priv)->dri2_info.is_dri2 = TRUE;
|
|
+ (*present_pixmap_priv)->dri2_info.dri2_priv = dri2_priv;
|
|
+ (*present_pixmap_priv)->dri2_info.fbo_read = fbo_read;
|
|
+ (*present_pixmap_priv)->dri2_info.fbo_write = fbo_write;
|
|
+ (*present_pixmap_priv)->dri2_info.texture_read = texture_read;
|
|
+ (*present_pixmap_priv)->dri2_info.texture_write = texture_write;
|
|
+
|
|
+ present_priv->last_serial_given++;
|
|
+ (*present_pixmap_priv)->serial = present_priv->last_serial_given;
|
|
+ present_priv->first_present_priv = *present_pixmap_priv;
|
|
+
|
|
+ eglBindAPI(current_api);
|
|
+
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return TRUE;
|
|
+fail:
|
|
+ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
+ eglBindAPI(current_api);
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+BOOL PRESENTTryFreePixmap(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv)
|
|
+{
|
|
+ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
|
|
+ PRESENTPixmapPriv *current;
|
|
+
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+
|
|
+ if (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending)
|
|
+ {
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ if (present_priv->first_present_priv == present_pixmap_priv)
|
|
+ {
|
|
+ present_priv->first_present_priv = present_pixmap_priv->next;
|
|
+ goto free_priv;
|
|
+ }
|
|
+
|
|
+ current = present_priv->first_present_priv;
|
|
+ while (current->next != present_pixmap_priv)
|
|
+ current = current->next;
|
|
+ current->next = present_pixmap_priv->next;
|
|
+free_priv:
|
|
+ PRESENTDestroyPixmapContent(dpy, present_pixmap_priv);
|
|
+ HeapFree(GetProcessHeap(), 0, present_pixmap_priv);
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+BOOL PRESENTHelperCopyFront(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv)
|
|
+{
|
|
+ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
|
|
+ xcb_void_cookie_t cookie;
|
|
+ xcb_generic_error_t *error;
|
|
+ uint32_t v = 0;
|
|
+ xcb_gcontext_t gc;
|
|
+
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+
|
|
+ if (!present_priv->window)
|
|
+ {
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ gc = xcb_generate_id(present_priv->xcb_connection);
|
|
+ xcb_create_gc(present_priv->xcb_connection, gc, present_priv->window,
|
|
+ XCB_GC_GRAPHICS_EXPOSURES, &v);
|
|
+
|
|
+ cookie = xcb_copy_area_checked(present_priv->xcb_connection,
|
|
+ present_priv->window, present_pixmap_priv->pixmap, gc,
|
|
+ 0, 0, 0, 0, present_pixmap_priv->width, present_pixmap_priv->height);
|
|
+
|
|
+ error = xcb_request_check(present_priv->xcb_connection, cookie);
|
|
+ xcb_free_gc(present_priv->xcb_connection, gc);
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return (error != NULL);
|
|
+}
|
|
+
|
|
+BOOL PRESENTPixmap(Display *dpy, XID window, PRESENTPixmapPriv *present_pixmap_priv,
|
|
+ const UINT PresentationInterval, const BOOL PresentAsync, const BOOL SwapEffectCopy,
|
|
+ const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion)
|
|
+{
|
|
+ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ struct DRI2priv *dri2_priv = present_pixmap_priv->dri2_info.dri2_priv;
|
|
+ EGLenum current_api = 0;
|
|
+#endif
|
|
+ xcb_void_cookie_t cookie;
|
|
+ xcb_generic_error_t *error;
|
|
+ int64_t target_msc, presentationInterval;
|
|
+ xcb_xfixes_region_t valid, update;
|
|
+ int16_t x_off, y_off;
|
|
+ uint32_t options = XCB_PRESENT_OPTION_NONE;
|
|
+
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+
|
|
+ if (window != present_priv->window)
|
|
+ PRESENTPrivChangeWindow(present_priv, window);
|
|
+
|
|
+ if (!window)
|
|
+ {
|
|
+ ERR("ERROR: Try to Present a pixmap on a NULL window\n");
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ PRESENTflush_events(present_priv, FALSE);
|
|
+ /* Note: present_pixmap_priv->present_complete_pending may be non-0, because
|
|
+ * on some paths the Xserver sends the complete event just after the idle
|
|
+ * event. */
|
|
+ if (!present_pixmap_priv->released)
|
|
+ {
|
|
+ ERR("FATAL ERROR: Trying to Present a pixmap not released\n");
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return FALSE;
|
|
+ }
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ if (present_pixmap_priv->dri2_info.is_dri2)
|
|
+ {
|
|
+ current_api = eglQueryAPI();
|
|
+ eglBindAPI(EGL_OPENGL_API);
|
|
+ if (eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context))
|
|
+ {
|
|
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_read);
|
|
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_write);
|
|
+
|
|
+ glBlitFramebuffer(0, 0, present_pixmap_priv->width, present_pixmap_priv->height,
|
|
+ 0, 0, present_pixmap_priv->width, present_pixmap_priv->height,
|
|
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
+ glFlush(); /* Perhaps useless */
|
|
+ }
|
|
+ else
|
|
+ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
|
|
+
|
|
+ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
+ eglBindAPI(current_api);
|
|
+ }
|
|
+#endif
|
|
+ target_msc = present_priv->last_msc;
|
|
+
|
|
+ presentationInterval = PresentationInterval;
|
|
+ if (PresentAsync)
|
|
+ options |= XCB_PRESENT_OPTION_ASYNC;
|
|
+ if (SwapEffectCopy)
|
|
+ options |= XCB_PRESENT_OPTION_COPY;
|
|
+
|
|
+ target_msc += presentationInterval * (present_priv->pixmap_present_pending + 1);
|
|
+
|
|
+ /* Note: PRESENT defines some way to do partial copy:
|
|
+ * presentproto:
|
|
+ * 'x-off' and 'y-off' define the location in the window where
|
|
+ * the 0,0 location of the pixmap will be presented. valid-area
|
|
+ * and update-area are relative to the pixmap.
|
|
+ */
|
|
+ if (!pSourceRect && !pDestRect && !pDirtyRegion)
|
|
+ {
|
|
+ valid = 0;
|
|
+ update = 0;
|
|
+ x_off = 0;
|
|
+ y_off = 0;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ xcb_rectangle_t rect_update;
|
|
+ xcb_rectangle_t *rect_updates;
|
|
+ int i;
|
|
+
|
|
+ rect_update.x = 0;
|
|
+ rect_update.y = 0;
|
|
+ rect_update.width = present_pixmap_priv->width;
|
|
+ rect_update.height = present_pixmap_priv->height;
|
|
+ x_off = 0;
|
|
+ y_off = 0;
|
|
+ if (pSourceRect)
|
|
+ {
|
|
+ x_off = -pSourceRect->left;
|
|
+ y_off = -pSourceRect->top;
|
|
+ rect_update.x = pSourceRect->left;
|
|
+ rect_update.y = pSourceRect->top;
|
|
+ rect_update.width = pSourceRect->right - pSourceRect->left;
|
|
+ rect_update.height = pSourceRect->bottom - pSourceRect->top;
|
|
+ }
|
|
+ if (pDestRect)
|
|
+ {
|
|
+ x_off += pDestRect->left;
|
|
+ y_off += pDestRect->top;
|
|
+ rect_update.width = pDestRect->right - pDestRect->left;
|
|
+ rect_update.height = pDestRect->bottom - pDestRect->top;
|
|
+ /* Note: the size of pDestRect and pSourceRect are supposed to be the same size
|
|
+ * because the driver would have done things to assure that. */
|
|
+ }
|
|
+ valid = xcb_generate_id(present_priv->xcb_connection_bis);
|
|
+ update = xcb_generate_id(present_priv->xcb_connection_bis);
|
|
+ xcb_xfixes_create_region(present_priv->xcb_connection_bis, valid, 1, &rect_update);
|
|
+ if (pDirtyRegion && pDirtyRegion->rdh.nCount)
|
|
+ {
|
|
+ rect_updates = (void *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ sizeof(xcb_rectangle_t) * pDirtyRegion->rdh.nCount);
|
|
+
|
|
+ for (i = 0; i < pDirtyRegion->rdh.nCount; i++)
|
|
+ {
|
|
+ RECT rc;
|
|
+ memcpy(&rc, pDirtyRegion->Buffer + i * sizeof(RECT), sizeof(RECT));
|
|
+ rect_update.x = rc.left;
|
|
+ rect_update.y = rc.top;
|
|
+ rect_update.width = rc.right - rc.left;
|
|
+ rect_update.height = rc.bottom - rc.top;
|
|
+ memcpy(rect_updates + i * sizeof(xcb_rectangle_t), &rect_update, sizeof(xcb_rectangle_t));
|
|
+ }
|
|
+ xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, pDirtyRegion->rdh.nCount, rect_updates);
|
|
+ HeapFree(GetProcessHeap(), 0, rect_updates);
|
|
+ } else
|
|
+ xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, 1, &rect_update);
|
|
+ }
|
|
+
|
|
+ cookie = xcb_present_pixmap_checked(present_priv->xcb_connection_bis,
|
|
+ window, present_pixmap_priv->pixmap, present_pixmap_priv->serial,
|
|
+ valid, update, x_off, y_off, None, None, None, options,
|
|
+ target_msc, 0, 0, 0, NULL);
|
|
+ error = xcb_request_check(present_priv->xcb_connection_bis, cookie); /* performs a flush */
|
|
+
|
|
+ if (update)
|
|
+ xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, update);
|
|
+ if (valid)
|
|
+ xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, valid);
|
|
+
|
|
+ if (error)
|
|
+ {
|
|
+ xcb_get_geometry_cookie_t cookie_geom;
|
|
+ xcb_get_geometry_reply_t *reply;
|
|
+
|
|
+ cookie_geom = xcb_get_geometry(present_priv->xcb_connection_bis, window);
|
|
+ reply = xcb_get_geometry_reply(present_priv->xcb_connection_bis, cookie_geom, NULL);
|
|
+
|
|
+ ERR("Error using PRESENT. Here some debug info\n");
|
|
+ if (!reply)
|
|
+ {
|
|
+ ERR("Error querying window info. Perhaps it doesn't exist anymore\n");
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return FALSE;
|
|
+ }
|
|
+ ERR("Pixmap: width=%d, height=%d, depth=%d\n",
|
|
+ present_pixmap_priv->width, present_pixmap_priv->height,
|
|
+ present_pixmap_priv->depth);
|
|
+
|
|
+ ERR("Window: width=%d, height=%d, depth=%d, x=%d, y=%d\n",
|
|
+ (int) reply->width, (int) reply->height,
|
|
+ (int) reply->depth, (int) reply->x, (int) reply->y);
|
|
+
|
|
+ ERR("Present parameter: PresentationInterval=%d, Pending presentations=%d\n",
|
|
+ PresentationInterval, present_priv->pixmap_present_pending);
|
|
+
|
|
+ if (present_pixmap_priv->depth != reply->depth)
|
|
+ ERR("Depths are different. PRESENT needs the pixmap and the window have same depth\n");
|
|
+ free(reply);
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return FALSE;
|
|
+ }
|
|
+ present_priv->last_target = target_msc;
|
|
+ present_priv->pixmap_present_pending++;
|
|
+ present_pixmap_priv->present_complete_pending++;
|
|
+ present_pixmap_priv->released = FALSE;
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+BOOL PRESENTWaitPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv)
|
|
+{
|
|
+ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
|
|
+
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+
|
|
+ PRESENTflush_events(present_priv, FALSE);
|
|
+
|
|
+ /* The part with present_pixmap_priv->present_complete_pending is legacy behaviour.
|
|
+ * It matters for SwapEffectCopy with swapinterval > 0. */
|
|
+ while (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending)
|
|
+ {
|
|
+ /* Note: following if should not happen because we'll never
|
|
+ * use two PRESENTWaitPixmapReleased in parallels on same window.
|
|
+ * However it would make it work in that case */
|
|
+ if (present_priv->xcb_wait)
|
|
+ {
|
|
+ /* we allow only one thread to dispatch events */
|
|
+ EnterCriticalSection(&present_priv->mutex_xcb_wait);
|
|
+ /* here the other thread got an event but hasn't treated it yet */
|
|
+ LeaveCriticalSection(&present_priv->mutex_xcb_wait);
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ Sleep(10); /* Let it treat the event */
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+ }
|
|
+ else if (!PRESENTwait_events(present_priv, TRUE))
|
|
+ {
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return FALSE;
|
|
+ }
|
|
+ }
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+BOOL PRESENTIsPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv)
|
|
+{
|
|
+ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
|
|
+ BOOL ret;
|
|
+
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+
|
|
+ PRESENTflush_events(present_priv, FALSE);
|
|
+
|
|
+ ret = present_pixmap_priv->released;
|
|
+
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+BOOL PRESENTWaitReleaseEvent(PRESENTpriv *present_priv)
|
|
+{
|
|
+
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+
|
|
+ while (!present_priv->idle_notify_since_last_check)
|
|
+ {
|
|
+ /* Note: following if should not happen because we'll never
|
|
+ * use two PRESENTWaitPixmapReleased in parallels on same window.
|
|
+ * However it would make it work in that case */
|
|
+ if (present_priv->xcb_wait)
|
|
+ {
|
|
+ /* we allow only one thread to dispatch events */
|
|
+ EnterCriticalSection(&present_priv->mutex_xcb_wait);
|
|
+ /* here the other thread got an event but hasn't treated it yet */
|
|
+ LeaveCriticalSection(&present_priv->mutex_xcb_wait);
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ Sleep(10); /* Let it treat the event */
|
|
+ EnterCriticalSection(&present_priv->mutex_present);
|
|
+ }
|
|
+ else if (!PRESENTwait_events(present_priv, TRUE))
|
|
+ {
|
|
+ ERR("Issue in PRESENTWaitReleaseEvent\n");
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return FALSE;
|
|
+ }
|
|
+ }
|
|
+ present_priv->idle_notify_since_last_check = FALSE;
|
|
+
|
|
+ LeaveCriticalSection(&present_priv->mutex_present);
|
|
+ return TRUE;
|
|
+}
|
|
diff --git a/dlls/d3d9-nine/dri3.h b/dlls/d3d9-nine/dri3.h
|
|
new file mode 100644
|
|
index 0000000000..3c9309dedb
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/dri3.h
|
|
@@ -0,0 +1,91 @@
|
|
+/*
|
|
+ * Wine X11DRV DRI3 interface
|
|
+ *
|
|
+ * Copyright 2014 Axel Davy
|
|
+ *
|
|
+ * 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_DRI3_H
|
|
+#define __WINE_DRI3_H
|
|
+
|
|
+#ifndef __WINE_CONFIG_H
|
|
+# error You must include config.h to use this header
|
|
+#endif
|
|
+
|
|
+#include <X11/Xlib.h>
|
|
+#include <wingdi.h>
|
|
+
|
|
+BOOL DRI3CheckExtension(Display *dpy, int major, int minor);
|
|
+
|
|
+#ifdef D3D9NINE_DRI2
|
|
+struct DRI2priv;
|
|
+
|
|
+BOOL DRI2FallbackInit(Display *dpy, struct DRI2priv **priv);
|
|
+
|
|
+void DRI2FallbackDestroy(struct DRI2priv *priv);
|
|
+
|
|
+BOOL DRI2FallbackCheckSupport(Display *dpy);
|
|
+#endif
|
|
+
|
|
+BOOL PRESENTCheckExtension(Display *dpy, int major, int minor);
|
|
+
|
|
+BOOL DRI3Open(Display *dpy, int screen, int *device_fd);
|
|
+
|
|
+#ifdef D3D9NINE_DRI2
|
|
+BOOL DRI2FallbackOpen(Display *dpy, int screen, int *device_fd);
|
|
+#endif
|
|
+
|
|
+BOOL DRI3PixmapFromDmaBuf(Display *dpy, int screen, int fd, int width, int height,
|
|
+ int stride, int depth, int bpp, Pixmap *pixmap);
|
|
+
|
|
+BOOL DRI3DmaBufFromPixmap(Display *dpy, Pixmap pixmap, int *fd, int *width, int *height,
|
|
+ int *stride, int *depth, int *bpp);
|
|
+
|
|
+typedef struct PRESENTPriv PRESENTpriv;
|
|
+typedef struct PRESENTPixmapPriv PRESENTPixmapPriv;
|
|
+
|
|
+BOOL PRESENTInit(Display *dpy, PRESENTpriv **present_priv);
|
|
+
|
|
+/* will clean properly and free all PRESENTPixmapPriv associated to PRESENTpriv.
|
|
+ * PRESENTPixmapPriv should not be freed by something else.
|
|
+ * If never a PRESENTPixmapPriv has to be destroyed,
|
|
+ * please destroy the current PRESENTpriv and create a new one.
|
|
+ * This will take care than all pixmaps are released */
|
|
+void PRESENTDestroy(Display *dpy, PRESENTpriv *present_priv);
|
|
+
|
|
+BOOL PRESENTPixmapInit(PRESENTpriv *present_priv, Pixmap pixmap, PRESENTPixmapPriv **present_pixmap_priv);
|
|
+
|
|
+#ifdef D3D9NINE_DRI2
|
|
+BOOL DRI2FallbackPRESENTPixmap(PRESENTpriv *present_priv, struct DRI2priv *priv,
|
|
+ int fd, int width, int height, int stride, int depth,
|
|
+ int bpp, PRESENTPixmapPriv **present_pixmap_priv);
|
|
+#endif
|
|
+
|
|
+BOOL PRESENTTryFreePixmap(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv);
|
|
+
|
|
+BOOL PRESENTHelperCopyFront(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv);
|
|
+
|
|
+BOOL PRESENTPixmap(Display *dpy, XID window, PRESENTPixmapPriv *present_pixmap_priv,
|
|
+ const UINT PresentationInterval, const BOOL PresentAsync, const BOOL SwapEffectCopy,
|
|
+ const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion);
|
|
+
|
|
+BOOL PRESENTWaitPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv);
|
|
+
|
|
+BOOL PRESENTIsPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv);
|
|
+
|
|
+BOOL PRESENTWaitReleaseEvent(PRESENTpriv *present_priv);
|
|
+
|
|
+#endif /* __WINE_DRI3_H */
|
|
diff --git a/dlls/d3d9-nine/present.c b/dlls/d3d9-nine/present.c
|
|
new file mode 100644
|
|
index 0000000000..2d9390a358
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/present.c
|
|
@@ -0,0 +1,1748 @@
|
|
+/*
|
|
+ * Wine ID3DAdapter9 support functions
|
|
+ *
|
|
+ * Copyright 2013 Joakim Sindholt
|
|
+ * Christoph Bumiller
|
|
+ * Copyright 2014 Tiziano Bacocco
|
|
+ * David Heidelberger
|
|
+ * Copyright 2014-2015 Axel Davy
|
|
+ * Copyright 2015 Patrick Rudolph
|
|
+ *
|
|
+ * 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 "config.h"
|
|
+#include "wine/port.h"
|
|
+#include "wine/debug.h"
|
|
+
|
|
+WINE_DEFAULT_DEBUG_CHANNEL(d3d9nine);
|
|
+
|
|
+#include <d3dadapter/drm.h>
|
|
+#include <X11/Xutil.h>
|
|
+
|
|
+#include "dri3.h"
|
|
+#include "wndproc.h"
|
|
+
|
|
+#include "wine/library.h" // for wine_dl*
|
|
+#include "wine/unicode.h" // for strcpyW
|
|
+
|
|
+#ifndef D3DPRESENT_DONOTWAIT
|
|
+#define D3DPRESENT_DONOTWAIT 0x00000001
|
|
+#endif
|
|
+
|
|
+#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR 1
|
|
+#if defined (ID3DPresent_SetPresentParameters2)
|
|
+#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 3
|
|
+#elif defined (ID3DPresent_ResolutionMismatch)
|
|
+#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 2
|
|
+#elif defined (ID3DPresent_GetWindowOccluded)
|
|
+#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 1
|
|
+#else
|
|
+#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 0
|
|
+#endif
|
|
+
|
|
+static const struct D3DAdapter9DRM *d3d9_drm = NULL;
|
|
+#ifdef D3D9NINE_DRI2
|
|
+static int is_dri2_fallback = 0;
|
|
+#endif
|
|
+
|
|
+/* Start section of x11drv.h */
|
|
+#define X11DRV_ESCAPE 6789
|
|
+enum x11drv_escape_codes
|
|
+{
|
|
+ X11DRV_SET_DRAWABLE, /* set current drawable for a DC */
|
|
+ X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
|
|
+ X11DRV_START_EXPOSURES, /* start graphics exposures */
|
|
+ X11DRV_END_EXPOSURES, /* end graphics exposures */
|
|
+ X11DRV_FLUSH_GL_DRAWABLE /* flush changes made to the gl drawable */
|
|
+};
|
|
+
|
|
+struct x11drv_escape_get_drawable
|
|
+{
|
|
+ enum x11drv_escape_codes code; /* escape code (X11DRV_GET_DRAWABLE) */
|
|
+ Drawable drawable; /* X drawable */
|
|
+ Drawable gl_drawable; /* GL drawable */
|
|
+ int pixel_format; /* internal GL pixel format */
|
|
+};
|
|
+/* End section x11drv.h */
|
|
+
|
|
+static XContext d3d_hwnd_context;
|
|
+static CRITICAL_SECTION context_section;
|
|
+static CRITICAL_SECTION_DEBUG critsect_debug =
|
|
+{
|
|
+ 0, 0, &context_section,
|
|
+ { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
|
|
+ 0, 0, { (DWORD_PTR)(__FILE__ ": context_section") }
|
|
+};
|
|
+static CRITICAL_SECTION context_section = { &critsect_debug, -1, 0, 0, 0, 0 };
|
|
+
|
|
+const GUID IID_ID3DPresent = { 0x77D60E80, 0xF1E6, 0x11DF, { 0x9E, 0x39, 0x95, 0x0C, 0xDF, 0xD7, 0x20, 0x85 } };
|
|
+const GUID IID_ID3DPresentGroup = { 0xB9C3016E, 0xF32A, 0x11DF, { 0x9C, 0x18, 0x92, 0xEA, 0xDE, 0xD7, 0x20, 0x85 } };
|
|
+
|
|
+struct d3d_drawable
|
|
+{
|
|
+ Drawable drawable; /* X11 drawable */
|
|
+ HDC hdc;
|
|
+ HWND wnd; /* HWND (for convenience) */
|
|
+};
|
|
+
|
|
+struct DRI3Present
|
|
+{
|
|
+ /* COM vtable */
|
|
+ void *vtable;
|
|
+ /* IUnknown reference count */
|
|
+ LONG refs;
|
|
+
|
|
+ D3DPRESENT_PARAMETERS params;
|
|
+ HWND focus_wnd;
|
|
+ PRESENTpriv *present_priv;
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ struct DRI2priv *dri2_priv;
|
|
+#endif
|
|
+
|
|
+ WCHAR devname[32];
|
|
+ HCURSOR hCursor;
|
|
+
|
|
+ DEVMODEW initial_mode;
|
|
+
|
|
+ DWORD style;
|
|
+ DWORD style_ex;
|
|
+
|
|
+ BOOL reapply_mode;
|
|
+ BOOL ex;
|
|
+ BOOL resolution_mismatch;
|
|
+ BOOL occluded;
|
|
+ BOOL drop_wnd_messages;
|
|
+ BOOL no_window_changes;
|
|
+ Display *gdi_display;
|
|
+
|
|
+ UINT present_interval;
|
|
+ BOOL present_async;
|
|
+ BOOL present_swapeffectcopy;
|
|
+ BOOL allow_discard_delayed_release;
|
|
+ BOOL tear_free_discard;
|
|
+ struct d3d_drawable *d3d;
|
|
+};
|
|
+
|
|
+struct D3DWindowBuffer
|
|
+{
|
|
+ PRESENTPixmapPriv *present_pixmap_priv;
|
|
+};
|
|
+
|
|
+static void free_d3dadapter_drawable(struct d3d_drawable *d3d)
|
|
+{
|
|
+ ReleaseDC(d3d->wnd, d3d->hdc);
|
|
+ HeapFree(GetProcessHeap(), 0, d3d);
|
|
+}
|
|
+
|
|
+static void destroy_d3dadapter_drawable(Display *gdi_display, HWND hwnd)
|
|
+{
|
|
+ struct d3d_drawable *d3d;
|
|
+
|
|
+ EnterCriticalSection(&context_section);
|
|
+ if (!XFindContext(gdi_display, (XID)hwnd,
|
|
+ d3d_hwnd_context, (char **)&d3d))
|
|
+ {
|
|
+ XDeleteContext(gdi_display, (XID)hwnd, d3d_hwnd_context);
|
|
+ free_d3dadapter_drawable(d3d);
|
|
+ }
|
|
+ LeaveCriticalSection(&context_section);
|
|
+}
|
|
+
|
|
+static RECT DRI3Present_GetClientRecWindowRelative(HWND hwnd)
|
|
+{
|
|
+ RECT rect;
|
|
+ RECT wnd;
|
|
+
|
|
+ /* Get client space dimensions */
|
|
+ GetClientRect(hwnd, &rect);
|
|
+
|
|
+ /* Get window in screen space */
|
|
+ GetWindowRect(hwnd, &wnd);
|
|
+
|
|
+ /* Transform to offset */
|
|
+ MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT) &wnd, 2);
|
|
+ wnd.top *= -1;
|
|
+ wnd.left *= -1;
|
|
+ wnd.bottom = wnd.top + rect.bottom;
|
|
+ wnd.right = wnd.left + rect.right;
|
|
+
|
|
+ return wnd;
|
|
+}
|
|
+
|
|
+static struct d3d_drawable *create_d3dadapter_drawable(HWND hwnd)
|
|
+{
|
|
+ struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
|
|
+ struct d3d_drawable *d3d;
|
|
+
|
|
+ d3d = HeapAlloc(GetProcessHeap(), 0, sizeof(*d3d));
|
|
+ if (!d3d)
|
|
+ {
|
|
+ ERR("Couldn't allocate d3d_drawable.\n");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ d3d->hdc = GetDCEx(hwnd, 0, DCX_CACHE | DCX_CLIPSIBLINGS);
|
|
+ if (ExtEscape(d3d->hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
|
|
+ sizeof(extesc), (LPSTR)&extesc) <= 0)
|
|
+ {
|
|
+ ERR("Unexpected error in X Drawable lookup (hwnd=%p, hdc=%p)\n", hwnd, d3d->hdc);
|
|
+ ReleaseDC(hwnd, d3d->hdc);
|
|
+ HeapFree(GetProcessHeap(), 0, d3d);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ d3d->drawable = extesc.drawable;
|
|
+ d3d->wnd = hwnd;
|
|
+
|
|
+ return d3d;
|
|
+}
|
|
+
|
|
+static struct d3d_drawable *get_d3d_drawable(Display *gdi_display, HWND hwnd)
|
|
+{
|
|
+ struct d3d_drawable *d3d, *race;
|
|
+
|
|
+ EnterCriticalSection(&context_section);
|
|
+ if (!XFindContext(gdi_display, (XID)hwnd, d3d_hwnd_context, (char **)&d3d))
|
|
+ {
|
|
+ return d3d;
|
|
+ }
|
|
+ LeaveCriticalSection(&context_section);
|
|
+
|
|
+ TRACE("No d3d_drawable attached to hwnd %p, creating one.\n", hwnd);
|
|
+
|
|
+ d3d = create_d3dadapter_drawable(hwnd);
|
|
+ if (!d3d)
|
|
+ return NULL;
|
|
+
|
|
+ EnterCriticalSection(&context_section);
|
|
+ if (!XFindContext(gdi_display, (XID)hwnd,
|
|
+ d3d_hwnd_context, (char **)&race))
|
|
+ {
|
|
+ /* apparently someone beat us to creating this d3d drawable. Let's not
|
|
+ waste more time with X11 calls and just use theirs instead. */
|
|
+ free_d3dadapter_drawable(d3d);
|
|
+ return race;
|
|
+ }
|
|
+ XSaveContext(gdi_display, (XID)hwnd, d3d_hwnd_context, (char *)d3d);
|
|
+ return d3d;
|
|
+}
|
|
+
|
|
+static void release_d3d_drawable(struct d3d_drawable *d3d)
|
|
+{
|
|
+ if (!d3d)
|
|
+ ERR("Driver internal error: d3d_drawable is NULL\n");
|
|
+ LeaveCriticalSection(&context_section);
|
|
+}
|
|
+
|
|
+static ULONG WINAPI DRI3Present_AddRef(struct DRI3Present *This)
|
|
+{
|
|
+ ULONG refs = InterlockedIncrement(&This->refs);
|
|
+ TRACE("%p increasing refcount to %u.\n", This, refs);
|
|
+ return refs;
|
|
+}
|
|
+
|
|
+static ULONG WINAPI DRI3Present_Release(struct DRI3Present *This)
|
|
+{
|
|
+ ULONG refs = InterlockedDecrement(&This->refs);
|
|
+ TRACE("%p decreasing refcount to %u.\n", This, refs);
|
|
+ if (refs == 0)
|
|
+ {
|
|
+ /* dtor */
|
|
+ (void) nine_unregister_window(This->focus_wnd);
|
|
+ if (This->d3d)
|
|
+ destroy_d3dadapter_drawable(This->gdi_display, This->d3d->wnd);
|
|
+ ChangeDisplaySettingsExW(This->devname, &(This->initial_mode), 0, CDS_FULLSCREEN, NULL);
|
|
+ PRESENTDestroy(This->gdi_display, This->present_priv);
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ if (is_dri2_fallback)
|
|
+ DRI2FallbackDestroy(This->dri2_priv);
|
|
+#endif
|
|
+ HeapFree(GetProcessHeap(), 0, This);
|
|
+ }
|
|
+ return refs;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_QueryInterface(struct DRI3Present *This,
|
|
+ REFIID riid, void **ppvObject)
|
|
+{
|
|
+ if (!ppvObject)
|
|
+ return E_POINTER;
|
|
+
|
|
+ if (IsEqualGUID(&IID_ID3DPresent, riid) ||
|
|
+ IsEqualGUID(&IID_IUnknown, riid))
|
|
+ {
|
|
+ *ppvObject = This;
|
|
+ DRI3Present_AddRef(This);
|
|
+ return S_OK;
|
|
+ }
|
|
+
|
|
+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
|
|
+ *ppvObject = NULL;
|
|
+
|
|
+ return E_NOINTERFACE;
|
|
+}
|
|
+
|
|
+static HRESULT DRI3Present_ChangePresentParameters(struct DRI3Present *This,
|
|
+ D3DPRESENT_PARAMETERS *params);
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_SetPresentParameters(struct DRI3Present *This,
|
|
+ D3DPRESENT_PARAMETERS *pPresentationParameters,
|
|
+ D3DDISPLAYMODEEX *pFullscreenDisplayMode)
|
|
+{
|
|
+ if (pFullscreenDisplayMode)
|
|
+ FIXME("Ignoring pFullscreenDisplayMode\n");
|
|
+ return DRI3Present_ChangePresentParameters(This, pPresentationParameters);
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_D3DWindowBufferFromDmaBuf(struct DRI3Present *This,
|
|
+ int dmaBufFd, int width, int height, int stride, int depth,
|
|
+ int bpp, struct D3DWindowBuffer **out)
|
|
+{
|
|
+ Pixmap pixmap;
|
|
+
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ if (is_dri2_fallback)
|
|
+ {
|
|
+ *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ sizeof(struct D3DWindowBuffer));
|
|
+ if (!DRI2FallbackPRESENTPixmap(This->present_priv, This->dri2_priv,
|
|
+ dmaBufFd, width, height, stride, depth,
|
|
+ bpp, &((*out)->present_pixmap_priv)))
|
|
+ {
|
|
+ ERR("DRI2FallbackPRESENTPixmap failed\n");
|
|
+ HeapFree(GetProcessHeap(), 0, *out);
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+ }
|
|
+ return D3D_OK;
|
|
+ }
|
|
+#endif
|
|
+ if (!DRI3PixmapFromDmaBuf(This->gdi_display, DefaultScreen(This->gdi_display),
|
|
+ dmaBufFd, width, height, stride, depth, bpp, &pixmap))
|
|
+ {
|
|
+ ERR("DRI3PixmapFromDmaBuf failed\n");
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+ }
|
|
+
|
|
+ *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ sizeof(struct D3DWindowBuffer));
|
|
+ if (!PRESENTPixmapInit(This->present_priv, pixmap, &((*out)->present_pixmap_priv)))
|
|
+ {
|
|
+ ERR("PRESENTPixmapInit failed\n");
|
|
+ HeapFree(GetProcessHeap(), 0, *out);
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+ }
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_DestroyD3DWindowBuffer(struct DRI3Present *This,
|
|
+ struct D3DWindowBuffer *buffer)
|
|
+{
|
|
+ /* the pixmap is managed by the PRESENT backend.
|
|
+ * But if it can delete it right away, we may have
|
|
+ * better performance */
|
|
+ PRESENTTryFreePixmap(This->gdi_display, buffer->present_pixmap_priv);
|
|
+ HeapFree(GetProcessHeap(), 0, buffer);
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_WaitBufferReleased(struct DRI3Present *This,
|
|
+ struct D3DWindowBuffer *buffer)
|
|
+{
|
|
+ if(!PRESENTWaitPixmapReleased(buffer->present_pixmap_priv))
|
|
+ {
|
|
+ ERR("PRESENTWaitPixmapReleased failed\n");
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+ }
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_FrontBufferCopy(struct DRI3Present *This,
|
|
+ struct D3DWindowBuffer *buffer)
|
|
+{
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ if (is_dri2_fallback)
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+#endif
|
|
+ if (PRESENTHelperCopyFront(This->gdi_display, buffer->present_pixmap_priv))
|
|
+ return D3D_OK;
|
|
+ else
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+}
|
|
+
|
|
+/* Try to detect client side window decorations by walking the X Drawable up.
|
|
+ * In case there's an intermediate Drawable, server side window decorations are used.
|
|
+ * TODO: Find a X11 function to query for window decorations.
|
|
+ */
|
|
+static BOOL DRI3Present_HasClientSideWindowDecorations(struct DRI3Present *This,
|
|
+ HWND hwnd)
|
|
+{
|
|
+ struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
|
|
+ Window Wroot;
|
|
+ Window Wparent;
|
|
+ Window *Wchildren;
|
|
+ unsigned int numchildren;
|
|
+ HWND parent;
|
|
+ HDC hdc;
|
|
+ BOOL ret = TRUE;
|
|
+
|
|
+ parent = GetParent(hwnd);
|
|
+ if (!parent)
|
|
+ parent = GetDesktopWindow();
|
|
+ if (!parent)
|
|
+ {
|
|
+ ERR("Unexpected error getting the parent hwnd (hwnd=%p)\n", hwnd);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ hdc = GetDCEx(hwnd, 0, DCX_CACHE | DCX_CLIPSIBLINGS);
|
|
+ if (!hdc)
|
|
+ return FALSE;
|
|
+ if (ExtEscape(hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
|
|
+ sizeof(extesc), (LPSTR)&extesc) <= 0)
|
|
+ {
|
|
+ ERR("Unexpected error in X Drawable lookup (hwnd=%p, hdc=%p)\n", hwnd, hdc);
|
|
+ ReleaseDC(hwnd, hdc);
|
|
+ return FALSE;
|
|
+ }
|
|
+ ReleaseDC(hwnd, hdc);
|
|
+
|
|
+ if (XQueryTree(This->gdi_display, extesc.drawable, &Wroot, &Wparent, &Wchildren, &numchildren))
|
|
+ {
|
|
+ hdc = GetDCEx(parent, 0, DCX_CACHE | DCX_CLIPSIBLINGS);
|
|
+ if (!hdc)
|
|
+ return FALSE;
|
|
+
|
|
+ if (ExtEscape(hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
|
|
+ sizeof(extesc), (LPSTR)&extesc) <= 0)
|
|
+ {
|
|
+ ERR("Unexpected error in X Drawable lookup (hwnd=%p, hdc=%p)\n", parent, hdc);
|
|
+ ReleaseDC(parent, hdc);
|
|
+ return FALSE;
|
|
+ }
|
|
+ ReleaseDC(parent, hdc);
|
|
+
|
|
+ if (Wparent != extesc.drawable)
|
|
+ {
|
|
+ /* Found at least one intermediate window */
|
|
+ ret = FALSE;
|
|
+ }
|
|
+ if (Wchildren)
|
|
+ free(Wchildren);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_PresentBuffer( struct DRI3Present *This,
|
|
+ struct D3DWindowBuffer *buffer, HWND hWndOverride, const RECT *pSourceRect,
|
|
+ const RECT *pDestRect, const RGNDATA *pDirtyRegion, DWORD Flags )
|
|
+{
|
|
+ struct d3d_drawable *d3d;
|
|
+ RECT dest_translate;
|
|
+ RECT offset;
|
|
+ HWND hwnd;
|
|
+
|
|
+ if (hWndOverride)
|
|
+ hwnd = hWndOverride;
|
|
+ else if (This->params.hDeviceWindow)
|
|
+ hwnd = This->params.hDeviceWindow;
|
|
+ else
|
|
+ hwnd = This->focus_wnd;
|
|
+
|
|
+ d3d = get_d3d_drawable(This->gdi_display, hwnd);
|
|
+
|
|
+ if (!d3d)
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+
|
|
+ /* TODO: should we use a list here instead ? */
|
|
+ if (This->d3d && (This->d3d->wnd != d3d->wnd))
|
|
+ destroy_d3dadapter_drawable(This->gdi_display, This->d3d->wnd);
|
|
+
|
|
+ This->d3d = d3d;
|
|
+
|
|
+ /* In case of client side window decorations we need to add an offset within
|
|
+ * the X drawable.
|
|
+ * FIXME: Call once on window style / size change */
|
|
+ if (DRI3Present_HasClientSideWindowDecorations(This, hwnd))
|
|
+ {
|
|
+ offset = DRI3Present_GetClientRecWindowRelative(hwnd);
|
|
+
|
|
+ if ((offset.top != 0) || (offset.left != 0))
|
|
+ {
|
|
+ if (!pDestRect)
|
|
+ pDestRect = (const RECT *) &offset;
|
|
+ else
|
|
+ {
|
|
+ dest_translate.top = pDestRect->top + offset.top;
|
|
+ dest_translate.left = pDestRect->left + offset.left;
|
|
+ dest_translate.bottom = pDestRect->bottom + offset.bottom;
|
|
+ dest_translate.right = pDestRect->right + offset.right;
|
|
+ pDestRect = (const RECT *) &dest_translate;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!PRESENTPixmap(This->gdi_display, d3d->drawable, buffer->present_pixmap_priv,
|
|
+ This->present_interval, This->present_async, This->present_swapeffectcopy,
|
|
+ pSourceRect, pDestRect, pDirtyRegion))
|
|
+ {
|
|
+ release_d3d_drawable(d3d);
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+ }
|
|
+ release_d3d_drawable(d3d);
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+/* Based on wine's wined3d_get_adapter_raster_status. */
|
|
+static HRESULT WINAPI DRI3Present_GetRasterStatus( struct DRI3Present *This,
|
|
+ D3DRASTER_STATUS *pRasterStatus )
|
|
+{
|
|
+ LONGLONG freq_per_frame, freq_per_line;
|
|
+ LARGE_INTEGER counter, freq_per_sec;
|
|
+ unsigned refresh_rate, height;
|
|
+
|
|
+ TRACE("This=%p, pRasterStatus=%p\n", This, pRasterStatus);
|
|
+
|
|
+ if (!QueryPerformanceCounter(&counter) || !QueryPerformanceFrequency(&freq_per_sec))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ if (This->params.Windowed)
|
|
+ {
|
|
+ refresh_rate = This->initial_mode.dmDisplayFrequency;
|
|
+ height = This->initial_mode.dmPelsHeight;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ refresh_rate = This->params.FullScreen_RefreshRateInHz;
|
|
+ height = This->params.BackBufferHeight;
|
|
+ }
|
|
+
|
|
+ if (refresh_rate == 0)
|
|
+ refresh_rate = 60;
|
|
+
|
|
+ TRACE("refresh_rate=%u, height=%u\n", refresh_rate, height);
|
|
+
|
|
+ freq_per_frame = freq_per_sec.QuadPart / refresh_rate;
|
|
+ /* Assume 20 scan lines in the vertical blank. */
|
|
+ freq_per_line = freq_per_frame / (height + 20);
|
|
+ pRasterStatus->ScanLine = (counter.QuadPart % freq_per_frame) / freq_per_line;
|
|
+ if (pRasterStatus->ScanLine < height)
|
|
+ pRasterStatus->InVBlank = FALSE;
|
|
+ else
|
|
+ {
|
|
+ pRasterStatus->ScanLine = 0;
|
|
+ pRasterStatus->InVBlank = TRUE;
|
|
+ }
|
|
+
|
|
+ TRACE("Returning fake value, InVBlank %u, ScanLine %u.\n",
|
|
+ pRasterStatus->InVBlank, pRasterStatus->ScanLine);
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_GetDisplayMode( struct DRI3Present *This,
|
|
+ D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation )
|
|
+{
|
|
+ DEVMODEW dm;
|
|
+
|
|
+ ZeroMemory(&dm, sizeof(dm));
|
|
+ dm.dmSize = sizeof(dm);
|
|
+
|
|
+ EnumDisplaySettingsExW(This->devname, ENUM_CURRENT_SETTINGS, &dm, 0);
|
|
+ pMode->Width = dm.dmPelsWidth;
|
|
+ pMode->Height = dm.dmPelsHeight;
|
|
+ pMode->RefreshRate = dm.dmDisplayFrequency;
|
|
+ pMode->ScanLineOrdering = (dm.dmDisplayFlags & DM_INTERLACED) ?
|
|
+ D3DSCANLINEORDERING_INTERLACED : D3DSCANLINEORDERING_PROGRESSIVE;
|
|
+
|
|
+ /* XXX This is called "guessing" */
|
|
+ switch (dm.dmBitsPerPel)
|
|
+ {
|
|
+ case 32: pMode->Format = D3DFMT_X8R8G8B8; break;
|
|
+ case 24: pMode->Format = D3DFMT_R8G8B8; break;
|
|
+ case 16: pMode->Format = D3DFMT_R5G6B5; break;
|
|
+ default:
|
|
+ WARN("Unknown display format with %u bpp.\n", dm.dmBitsPerPel);
|
|
+ pMode->Format = D3DFMT_UNKNOWN;
|
|
+ }
|
|
+
|
|
+ switch (dm.dmDisplayOrientation)
|
|
+ {
|
|
+ case DMDO_DEFAULT: *pRotation = D3DDISPLAYROTATION_IDENTITY; break;
|
|
+ case DMDO_90: *pRotation = D3DDISPLAYROTATION_90; break;
|
|
+ case DMDO_180: *pRotation = D3DDISPLAYROTATION_180; break;
|
|
+ case DMDO_270: *pRotation = D3DDISPLAYROTATION_270; break;
|
|
+ default:
|
|
+ WARN("Unknown display rotation %u.\n", dm.dmDisplayOrientation);
|
|
+ *pRotation = D3DDISPLAYROTATION_IDENTITY;
|
|
+ }
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_GetPresentStats( struct DRI3Present *This, D3DPRESENTSTATS *pStats )
|
|
+{
|
|
+ FIXME("(%p, %p), stub!\n", This, pStats);
|
|
+ return D3DERR_INVALIDCALL;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_GetCursorPos( struct DRI3Present *This, POINT *pPoint )
|
|
+{
|
|
+ BOOL ok;
|
|
+ HWND draw_window;
|
|
+
|
|
+ if (!pPoint)
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ draw_window = This->params.hDeviceWindow ?
|
|
+ This->params.hDeviceWindow : This->focus_wnd;
|
|
+
|
|
+ ok = GetCursorPos(pPoint);
|
|
+ ok = ok && ScreenToClient(draw_window, pPoint);
|
|
+ return ok ? S_OK : D3DERR_DRIVERINTERNALERROR;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_SetCursorPos( struct DRI3Present *This, POINT *pPoint )
|
|
+{
|
|
+ BOOL ok;
|
|
+ POINT real_pos;
|
|
+
|
|
+ if (!pPoint)
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ ok = SetCursorPos(pPoint->x, pPoint->y);
|
|
+ if (!ok)
|
|
+ goto error;
|
|
+
|
|
+ ok = GetCursorPos(&real_pos);
|
|
+ if (!ok || real_pos.x != pPoint->x || real_pos.y != pPoint->y)
|
|
+ goto error;
|
|
+
|
|
+ return D3D_OK;
|
|
+
|
|
+error:
|
|
+ SetCursor(NULL); /* Hide cursor rather than put wrong pos */
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+}
|
|
+
|
|
+/* Note: assuming 32x32 cursor */
|
|
+static HRESULT WINAPI DRI3Present_SetCursor( struct DRI3Present *This, void *pBitmap,
|
|
+ POINT *pHotspot, BOOL bShow )
|
|
+{
|
|
+ if (pBitmap)
|
|
+ {
|
|
+ ICONINFO info;
|
|
+ HCURSOR cursor;
|
|
+
|
|
+ DWORD mask[32];
|
|
+ memset(mask, ~0, sizeof(mask));
|
|
+
|
|
+ if (!pHotspot)
|
|
+ return D3DERR_INVALIDCALL;
|
|
+ info.fIcon = FALSE;
|
|
+ info.xHotspot = pHotspot->x;
|
|
+ info.yHotspot = pHotspot->y;
|
|
+ info.hbmMask = CreateBitmap(32, 32, 1, 1, mask);
|
|
+ info.hbmColor = CreateBitmap(32, 32, 1, 32, pBitmap);
|
|
+
|
|
+ cursor = CreateIconIndirect(&info);
|
|
+ if (info.hbmMask) DeleteObject(info.hbmMask);
|
|
+ if (info.hbmColor) DeleteObject(info.hbmColor);
|
|
+ if (cursor)
|
|
+ DestroyCursor(This->hCursor);
|
|
+ This->hCursor = cursor;
|
|
+ }
|
|
+ SetCursor(bShow ? This->hCursor : NULL);
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_SetGammaRamp( struct DRI3Present *This,
|
|
+ const D3DGAMMARAMP *pRamp, HWND hWndOverride )
|
|
+{
|
|
+ HWND hWnd = hWndOverride ? hWndOverride : This->focus_wnd;
|
|
+ HDC hdc;
|
|
+ BOOL ok;
|
|
+ if (!pRamp)
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ hdc = GetDC(hWnd);
|
|
+ ok = SetDeviceGammaRamp(hdc, (void *)pRamp);
|
|
+ ReleaseDC(hWnd, hdc);
|
|
+ return ok ? D3D_OK : D3DERR_DRIVERINTERNALERROR;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_GetWindowInfo( struct DRI3Present *This,
|
|
+ HWND hWnd, int *width, int *height, int *depth )
|
|
+{
|
|
+ HRESULT hr;
|
|
+ RECT pRect;
|
|
+
|
|
+ if (!hWnd)
|
|
+ hWnd = This->focus_wnd;
|
|
+ hr = GetClientRect(hWnd, &pRect);
|
|
+ if (!hr)
|
|
+ return D3DERR_INVALIDCALL;
|
|
+ *width = pRect.right - pRect.left;
|
|
+ *height = pRect.bottom - pRect.top;
|
|
+ *depth = 24; //TODO
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+#if WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR >= 1
|
|
+static BOOL WINAPI DRI3Present_GetWindowOccluded(struct DRI3Present *This)
|
|
+{
|
|
+ return This->occluded;
|
|
+}
|
|
+#endif
|
|
+
|
|
+#if WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR >= 2
|
|
+static BOOL WINAPI DRI3Present_ResolutionMismatch(struct DRI3Present *This)
|
|
+{
|
|
+ /* The resolution might change due to a third party app.
|
|
+ * Poll this function to get the device's resolution match.
|
|
+ * A device reset is required to restore the requested resolution.
|
|
+ */
|
|
+ return This->resolution_mismatch;
|
|
+}
|
|
+
|
|
+static HANDLE WINAPI DRI3Present_CreateThread( struct DRI3Present *This,
|
|
+ void *pThreadfunc, void *pParam )
|
|
+{
|
|
+ LPTHREAD_START_ROUTINE lpStartAddress =
|
|
+ (LPTHREAD_START_ROUTINE) pThreadfunc;
|
|
+
|
|
+ return CreateThread(NULL, 0, lpStartAddress, pParam, 0, NULL);
|
|
+}
|
|
+
|
|
+static BOOL WINAPI DRI3Present_WaitForThread( struct DRI3Present *This, HANDLE thread )
|
|
+{
|
|
+ DWORD ExitCode = 0;
|
|
+ while (GetExitCodeThread(thread, &ExitCode) && ExitCode == STILL_ACTIVE)
|
|
+ Sleep(10);
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+#endif
|
|
+
|
|
+#if WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR >= 3
|
|
+static HRESULT WINAPI DRI3Present_SetPresentParameters2( struct DRI3Present *This, D3DPRESENT_PARAMETERS2 *pParams )
|
|
+{
|
|
+ This->allow_discard_delayed_release = pParams->AllowDISCARDDelayedRelease;
|
|
+ This->tear_free_discard = pParams->AllowDISCARDDelayedRelease && pParams->TearFreeDISCARD;
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static BOOL WINAPI DRI3Present_IsBufferReleased( struct DRI3Present *This, struct D3DWindowBuffer *buffer )
|
|
+{
|
|
+ return PRESENTIsPixmapReleased(buffer->present_pixmap_priv);
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3Present_WaitBufferReleaseEvent( struct DRI3Present *This )
|
|
+{
|
|
+ PRESENTWaitReleaseEvent(This->present_priv);
|
|
+ return D3D_OK;
|
|
+}
|
|
+#endif
|
|
+
|
|
+/*----------*/
|
|
+
|
|
+static ID3DPresentVtbl DRI3Present_vtable = {
|
|
+ (void *)DRI3Present_QueryInterface,
|
|
+ (void *)DRI3Present_AddRef,
|
|
+ (void *)DRI3Present_Release,
|
|
+ (void *)DRI3Present_SetPresentParameters,
|
|
+ (void *)DRI3Present_D3DWindowBufferFromDmaBuf,
|
|
+ (void *)DRI3Present_DestroyD3DWindowBuffer,
|
|
+ (void *)DRI3Present_WaitBufferReleased,
|
|
+ (void *)DRI3Present_FrontBufferCopy,
|
|
+ (void *)DRI3Present_PresentBuffer,
|
|
+ (void *)DRI3Present_GetRasterStatus,
|
|
+ (void *)DRI3Present_GetDisplayMode,
|
|
+ (void *)DRI3Present_GetPresentStats,
|
|
+ (void *)DRI3Present_GetCursorPos,
|
|
+ (void *)DRI3Present_SetCursorPos,
|
|
+ (void *)DRI3Present_SetCursor,
|
|
+ (void *)DRI3Present_SetGammaRamp,
|
|
+ (void *)DRI3Present_GetWindowInfo,
|
|
+#if WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR >= 1
|
|
+ (void *)DRI3Present_GetWindowOccluded,
|
|
+#endif
|
|
+#if WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR >= 2
|
|
+ (void *)DRI3Present_ResolutionMismatch,
|
|
+ (void *)DRI3Present_CreateThread,
|
|
+ (void *)DRI3Present_WaitForThread,
|
|
+#endif
|
|
+#if WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR >= 3
|
|
+ (void *)DRI3Present_SetPresentParameters2,
|
|
+ (void *)DRI3Present_IsBufferReleased,
|
|
+ (void *)DRI3Present_WaitBufferReleaseEvent,
|
|
+#endif
|
|
+};
|
|
+
|
|
+/* The following code is based on WINE's wined3d/device.c and
|
|
+ * wined3d/swapchain.c and WINE's d3d9 files. */
|
|
+
|
|
+static LONG fullscreen_style(LONG style)
|
|
+{
|
|
+ /* Make sure the window is managed, otherwise we won't get keyboard input. */
|
|
+ style |= WS_POPUP | WS_SYSMENU;
|
|
+ style &= ~(WS_CAPTION | WS_THICKFRAME);
|
|
+
|
|
+ return style;
|
|
+}
|
|
+
|
|
+static LONG fullscreen_exstyle(LONG exstyle)
|
|
+{
|
|
+ /* Filter out window decorations. */
|
|
+ exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
|
|
+
|
|
+ return exstyle;
|
|
+}
|
|
+
|
|
+static HRESULT DRI3Present_ChangeDisplaySettingsIfNeccessary(struct DRI3Present *This, DEVMODEW *new_mode)
|
|
+{
|
|
+ DEVMODEW current_mode;
|
|
+ LONG hr;
|
|
+
|
|
+ /* Filter invalid resolution */
|
|
+ if (!new_mode->dmPelsWidth || !new_mode->dmPelsHeight)
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ /* Ignore invalid frequency requested */
|
|
+ if (new_mode->dmDisplayFrequency > 1000)
|
|
+ new_mode->dmDisplayFrequency = 0;
|
|
+
|
|
+ ZeroMemory(¤t_mode, sizeof(DEVMODEW));
|
|
+ current_mode.dmSize = sizeof(DEVMODEW);
|
|
+ /* Only change the mode if necessary. */
|
|
+ if (!EnumDisplaySettingsW(This->devname, ENUM_CURRENT_SETTINGS, ¤t_mode))
|
|
+ ERR("Failed to get current display mode.\n");
|
|
+ else if (current_mode.dmPelsWidth != new_mode->dmPelsWidth
|
|
+ || current_mode.dmPelsHeight != new_mode->dmPelsHeight
|
|
+ || (current_mode.dmDisplayFrequency != new_mode->dmDisplayFrequency
|
|
+ && (new_mode->dmFields & DM_DISPLAYFREQUENCY)))
|
|
+ {
|
|
+ hr = ChangeDisplaySettingsExW(This->devname, new_mode, 0, CDS_FULLSCREEN, NULL);
|
|
+ if (hr != DISP_CHANGE_SUCCESSFUL)
|
|
+ {
|
|
+ /* try again without display RefreshRate */
|
|
+ if (new_mode->dmFields & DM_DISPLAYFREQUENCY)
|
|
+ {
|
|
+ new_mode->dmFields &= ~DM_DISPLAYFREQUENCY;
|
|
+ new_mode->dmDisplayFrequency = 0;
|
|
+ hr = ChangeDisplaySettingsExW(This->devname, new_mode, 0, CDS_FULLSCREEN, NULL);
|
|
+ if (hr != DISP_CHANGE_SUCCESSFUL)
|
|
+ {
|
|
+ ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
|
|
+ return D3DERR_INVALIDCALL;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
|
|
+ return D3DERR_INVALIDCALL;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+LRESULT device_process_message(struct DRI3Present *present, HWND window, BOOL unicode,
|
|
+ UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
|
|
+{
|
|
+ boolean drop_wnd_messages;
|
|
+ DEVMODEW current_mode;
|
|
+ DEVMODEW new_mode;
|
|
+
|
|
+ TRACE("Got message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
|
|
+ window, message, wparam, lparam);
|
|
+
|
|
+ if (present->drop_wnd_messages && message != WM_DISPLAYCHANGE)
|
|
+ {
|
|
+ TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
|
|
+ window, message, wparam, lparam);
|
|
+ if (unicode)
|
|
+ return DefWindowProcW(window, message, wparam, lparam);
|
|
+ else
|
|
+ return DefWindowProcA(window, message, wparam, lparam);
|
|
+ }
|
|
+
|
|
+ if (message == WM_DESTROY)
|
|
+ {
|
|
+ TRACE("unregister window %p.\n", window);
|
|
+ (void) nine_unregister_window(window);
|
|
+ }
|
|
+ else if (message == WM_DISPLAYCHANGE)
|
|
+ {
|
|
+ /* Ex restores display mode, while non Ex requires the
|
|
+ * user to call Device::Reset() */
|
|
+ ZeroMemory(¤t_mode, sizeof(DEVMODEW));
|
|
+ current_mode.dmSize = sizeof(current_mode);
|
|
+ if (!present->ex &&
|
|
+ !present->params.Windowed &&
|
|
+ present->params.hDeviceWindow &&
|
|
+ EnumDisplaySettingsW(present->devname, ENUM_CURRENT_SETTINGS, ¤t_mode) &&
|
|
+ (current_mode.dmPelsWidth != present->params.BackBufferWidth ||
|
|
+ current_mode.dmPelsHeight != present->params.BackBufferHeight))
|
|
+ {
|
|
+ present->resolution_mismatch = TRUE;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ present->resolution_mismatch = FALSE;
|
|
+ }
|
|
+ }
|
|
+ else if (message == WM_ACTIVATEAPP)
|
|
+ {
|
|
+ drop_wnd_messages = present->drop_wnd_messages;
|
|
+ present->drop_wnd_messages = TRUE;
|
|
+
|
|
+ if (wparam == WA_INACTIVE)
|
|
+ {
|
|
+ present->occluded = TRUE;
|
|
+ present->reapply_mode = TRUE;
|
|
+
|
|
+ ZeroMemory(&new_mode, sizeof(DEVMODEW));
|
|
+ new_mode.dmSize = sizeof(new_mode);
|
|
+ if (EnumDisplaySettingsW(present->devname, ENUM_REGISTRY_SETTINGS, &new_mode))
|
|
+ DRI3Present_ChangeDisplaySettingsIfNeccessary(present, &new_mode);
|
|
+
|
|
+ if (!present->no_window_changes &&
|
|
+ IsWindowVisible(present->params.hDeviceWindow))
|
|
+ ShowWindow(present->params.hDeviceWindow, SW_MINIMIZE);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ present->occluded = FALSE;
|
|
+
|
|
+ if (!present->no_window_changes)
|
|
+ {
|
|
+ /* restore window */
|
|
+ SetWindowPos(present->params.hDeviceWindow, NULL, 0, 0,
|
|
+ present->params.BackBufferWidth, present->params.BackBufferHeight,
|
|
+ SWP_NOACTIVATE | SWP_NOZORDER);
|
|
+ }
|
|
+
|
|
+ if (present->ex)
|
|
+ {
|
|
+ ZeroMemory(&new_mode, sizeof(DEVMODEW));
|
|
+ new_mode.dmSize = sizeof(new_mode);
|
|
+ new_mode.dmPelsWidth = present->params.BackBufferWidth;
|
|
+ new_mode.dmPelsHeight = present->params.BackBufferHeight;
|
|
+ new_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
|
|
+ if (present->params.FullScreen_RefreshRateInHz)
|
|
+ {
|
|
+ new_mode.dmFields |= DM_DISPLAYFREQUENCY;
|
|
+ new_mode.dmDisplayFrequency = present->params.FullScreen_RefreshRateInHz;
|
|
+ }
|
|
+ DRI3Present_ChangeDisplaySettingsIfNeccessary(present, &new_mode);
|
|
+ }
|
|
+ }
|
|
+ present->drop_wnd_messages = drop_wnd_messages;
|
|
+ }
|
|
+ else if (message == WM_SYSCOMMAND)
|
|
+ {
|
|
+ if (wparam == SC_RESTORE)
|
|
+ {
|
|
+ if (unicode)
|
|
+ DefWindowProcW(window, message, wparam, lparam);
|
|
+ else
|
|
+ DefWindowProcA(window, message, wparam, lparam);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (unicode)
|
|
+ return CallWindowProcW(proc, window, message, wparam, lparam);
|
|
+ else
|
|
+ return CallWindowProcA(proc, window, message, wparam, lparam);
|
|
+}
|
|
+
|
|
+static void setup_fullscreen_window(struct DRI3Present *This,
|
|
+ HWND hwnd, int w, int h)
|
|
+{
|
|
+ boolean drop_wnd_messages;
|
|
+ LONG style, style_ex;
|
|
+
|
|
+ This->style = GetWindowLongW(hwnd, GWL_STYLE);
|
|
+ This->style_ex = GetWindowLongW(hwnd, GWL_EXSTYLE);
|
|
+
|
|
+ style = fullscreen_style(This->style);
|
|
+ style_ex = fullscreen_exstyle(This->style_ex);
|
|
+
|
|
+ drop_wnd_messages = This->drop_wnd_messages;
|
|
+ This->drop_wnd_messages = TRUE;
|
|
+
|
|
+ SetWindowLongW(hwnd, GWL_STYLE, style);
|
|
+ SetWindowLongW(hwnd, GWL_EXSTYLE, style_ex);
|
|
+
|
|
+ SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, w, h,
|
|
+ SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
|
|
+
|
|
+ This->drop_wnd_messages = drop_wnd_messages;
|
|
+}
|
|
+
|
|
+static void move_fullscreen_window(struct DRI3Present *This,
|
|
+ HWND hwnd, int w, int h)
|
|
+{
|
|
+ boolean drop_wnd_messages;
|
|
+ LONG style, style_ex;
|
|
+
|
|
+ /* move draw window back to place */
|
|
+
|
|
+ style = GetWindowLongW(hwnd, GWL_STYLE);
|
|
+ style_ex = GetWindowLongW(hwnd, GWL_EXSTYLE);
|
|
+
|
|
+ style = fullscreen_style(style);
|
|
+ style_ex = fullscreen_exstyle(style_ex);
|
|
+
|
|
+ drop_wnd_messages = This->drop_wnd_messages;
|
|
+ This->drop_wnd_messages = TRUE;
|
|
+ SetWindowLongW(hwnd, GWL_STYLE, style);
|
|
+ SetWindowLongW(hwnd, GWL_EXSTYLE, style_ex);
|
|
+ SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, w, h,
|
|
+ SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
|
|
+ This->drop_wnd_messages = drop_wnd_messages;
|
|
+}
|
|
+
|
|
+static void restore_fullscreen_window(struct DRI3Present *This,
|
|
+ HWND hwnd)
|
|
+{
|
|
+ boolean drop_wnd_messages;
|
|
+ LONG style, style_ex;
|
|
+
|
|
+ /* switch from fullscreen to window */
|
|
+ style = GetWindowLongW(hwnd, GWL_STYLE);
|
|
+ style_ex = GetWindowLongW(hwnd, GWL_EXSTYLE);
|
|
+ /* These flags are set by us, not the
|
|
+ * application, and we want to ignore them in the test below, since it's
|
|
+ * not the application's fault that they changed. Additionally, we want to
|
|
+ * preserve the current status of these flags (i.e. don't restore them) to
|
|
+ * more closely emulate the behavior of Direct3D, which leaves these flags
|
|
+ * alone when returning to windowed mode. */
|
|
+ This->style ^= (This->style ^ style) & WS_VISIBLE;
|
|
+ This->style_ex ^= (This->style_ex ^ style_ex) & WS_EX_TOPMOST;
|
|
+
|
|
+ /* Only restore the style if the application didn't modify it during the
|
|
+ * fullscreen phase. Some applications change it before calling Reset()
|
|
+ * when switching between windowed and fullscreen modes (HL2), some
|
|
+ * depend on the original style (Eve Online). */
|
|
+ drop_wnd_messages = This->drop_wnd_messages;
|
|
+ This->drop_wnd_messages = TRUE;
|
|
+ if (style == fullscreen_style(This->style) &&
|
|
+ style_ex == fullscreen_exstyle(This->style_ex))
|
|
+ {
|
|
+ SetWindowLongW(hwnd, GWL_STYLE, This->style);
|
|
+ SetWindowLongW(hwnd, GWL_EXSTYLE, This->style_ex);
|
|
+ }
|
|
+ SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED |
|
|
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
|
|
+ SWP_NOACTIVATE);
|
|
+ This->drop_wnd_messages = drop_wnd_messages;
|
|
+
|
|
+ This->style = 0;
|
|
+ This->style_ex = 0;
|
|
+}
|
|
+
|
|
+static void DRI3Present_UpdatePresentationInterval(struct DRI3Present *This)
|
|
+{
|
|
+ switch(This->params.PresentationInterval)
|
|
+ {
|
|
+ case D3DPRESENT_INTERVAL_DEFAULT:
|
|
+ case D3DPRESENT_INTERVAL_ONE:
|
|
+ This->present_interval = 1;
|
|
+ This->present_async = FALSE;
|
|
+ break;
|
|
+ case D3DPRESENT_INTERVAL_TWO:
|
|
+ This->present_interval = 2;
|
|
+ This->present_async = FALSE;
|
|
+ break;
|
|
+ case D3DPRESENT_INTERVAL_THREE:
|
|
+ This->present_interval = 3;
|
|
+ This->present_async = FALSE;
|
|
+ break;
|
|
+ case D3DPRESENT_INTERVAL_FOUR:
|
|
+ This->present_interval = 4;
|
|
+ This->present_async = FALSE;
|
|
+ break;
|
|
+ case D3DPRESENT_INTERVAL_IMMEDIATE:
|
|
+ default:
|
|
+ This->present_interval = 0;
|
|
+ This->present_async =
|
|
+ !(This->params.SwapEffect == D3DSWAPEFFECT_DISCARD &&
|
|
+ This->tear_free_discard);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* D3DSWAPEFFECT_COPY: Force Copy.
|
|
+ * This->present_interval == 0: Force Copy to have buffers
|
|
+ * release as soon as possible (the display server/compositor
|
|
+ * won't hold any buffer), unless DISCARD and
|
|
+ * allow_discard_delayed_release */
|
|
+ This->present_swapeffectcopy =
|
|
+ This->params.SwapEffect == D3DSWAPEFFECT_COPY ||
|
|
+ (This->present_interval == 0 &&
|
|
+ !(This->params.SwapEffect == D3DSWAPEFFECT_DISCARD &&
|
|
+ This->allow_discard_delayed_release));
|
|
+}
|
|
+
|
|
+static HRESULT DRI3Present_ChangePresentParameters(struct DRI3Present *This,
|
|
+ D3DPRESENT_PARAMETERS *params)
|
|
+{
|
|
+ HWND focus_window = This->focus_wnd ? This->focus_wnd : params->hDeviceWindow;
|
|
+ RECT rect;
|
|
+ DEVMODEW new_mode;
|
|
+ HRESULT hr;
|
|
+ boolean drop_wnd_messages;
|
|
+
|
|
+ TRACE("This=%p, params=%p, focus_window=%p, params->hDeviceWindow=%p\n",
|
|
+ This, params, focus_window, params->hDeviceWindow);
|
|
+
|
|
+ This->params.SwapEffect = params->SwapEffect;
|
|
+ This->params.AutoDepthStencilFormat = params->AutoDepthStencilFormat;
|
|
+ This->params.Flags = params->Flags;
|
|
+ This->params.FullScreen_RefreshRateInHz = params->FullScreen_RefreshRateInHz;
|
|
+ This->params.PresentationInterval = params->PresentationInterval;
|
|
+ This->params.EnableAutoDepthStencil = params->EnableAutoDepthStencil;
|
|
+ if (!params->hDeviceWindow)
|
|
+ params->hDeviceWindow = This->params.hDeviceWindow;
|
|
+ else
|
|
+ This->params.hDeviceWindow = params->hDeviceWindow;
|
|
+
|
|
+ if ((This->params.BackBufferWidth != params->BackBufferWidth) ||
|
|
+ (This->params.BackBufferHeight != params->BackBufferHeight) ||
|
|
+ (This->params.Windowed != params->Windowed) ||
|
|
+ This->reapply_mode)
|
|
+ {
|
|
+ This->reapply_mode = FALSE;
|
|
+
|
|
+ if (!params->Windowed)
|
|
+ {
|
|
+ TRACE("Setting fullscreen mode: %dx%d@%d\n", params->BackBufferWidth,
|
|
+ params->BackBufferHeight, params->FullScreen_RefreshRateInHz);
|
|
+
|
|
+ /* switch display mode */
|
|
+ ZeroMemory(&new_mode, sizeof(DEVMODEW));
|
|
+ new_mode.dmPelsWidth = params->BackBufferWidth;
|
|
+ new_mode.dmPelsHeight = params->BackBufferHeight;
|
|
+ new_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
|
|
+ if (params->FullScreen_RefreshRateInHz)
|
|
+ {
|
|
+ new_mode.dmFields |= DM_DISPLAYFREQUENCY;
|
|
+ new_mode.dmDisplayFrequency = params->FullScreen_RefreshRateInHz;
|
|
+ }
|
|
+ new_mode.dmSize = sizeof(DEVMODEW);
|
|
+ hr = DRI3Present_ChangeDisplaySettingsIfNeccessary(This, &new_mode);
|
|
+ if (FAILED(hr))
|
|
+ return hr;
|
|
+
|
|
+ /* Dirty as BackBufferWidth and BackBufferHeight hasn't been set yet */
|
|
+ This->resolution_mismatch = FALSE;
|
|
+ }
|
|
+ else if(!This->params.Windowed && params->Windowed)
|
|
+ {
|
|
+ TRACE("Setting fullscreen mode: %dx%d@%d\n", This->initial_mode.dmPelsWidth,
|
|
+ This->initial_mode.dmPelsHeight, This->initial_mode.dmDisplayFrequency);
|
|
+
|
|
+ hr = DRI3Present_ChangeDisplaySettingsIfNeccessary(This, &This->initial_mode);
|
|
+ if (FAILED(hr))
|
|
+ return hr;
|
|
+
|
|
+ /* Dirty as BackBufferWidth and BackBufferHeight hasn't been set yet */
|
|
+ This->resolution_mismatch = FALSE;
|
|
+ }
|
|
+
|
|
+ if (This->params.Windowed)
|
|
+ {
|
|
+ if (!params->Windowed)
|
|
+ {
|
|
+ /* switch from window to fullscreen */
|
|
+ if (!nine_register_window(focus_window, This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ SetWindowPos(focus_window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
|
+
|
|
+ setup_fullscreen_window(This, params->hDeviceWindow,
|
|
+ params->BackBufferWidth, params->BackBufferHeight);
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (!params->Windowed)
|
|
+ {
|
|
+ /* switch from fullscreen to fullscreen */
|
|
+ drop_wnd_messages = This->drop_wnd_messages;
|
|
+ This->drop_wnd_messages = TRUE;
|
|
+ MoveWindow(params->hDeviceWindow, 0, 0,
|
|
+ params->BackBufferWidth,
|
|
+ params->BackBufferHeight,
|
|
+ TRUE);
|
|
+ This->drop_wnd_messages = drop_wnd_messages;
|
|
+ }
|
|
+ else if (This->style || This->style_ex)
|
|
+ {
|
|
+ restore_fullscreen_window(This, params->hDeviceWindow);
|
|
+ }
|
|
+
|
|
+ if (params->Windowed && !nine_unregister_window(focus_window))
|
|
+ ERR("Window %p is not registered with nine.\n", focus_window);
|
|
+ }
|
|
+ This->params.Windowed = params->Windowed;
|
|
+ }
|
|
+ else if (!params->Windowed)
|
|
+ {
|
|
+ move_fullscreen_window(This, params->hDeviceWindow, params->BackBufferWidth, params->BackBufferHeight);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ TRACE("Nothing changed.\n");
|
|
+ }
|
|
+ if (!params->BackBufferWidth || !params->BackBufferHeight) {
|
|
+ if (!params->Windowed)
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ if (!GetClientRect(params->hDeviceWindow, &rect))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ if (params->BackBufferWidth == 0)
|
|
+ params->BackBufferWidth = rect.right - rect.left;
|
|
+
|
|
+ if (params->BackBufferHeight == 0)
|
|
+ params->BackBufferHeight = rect.bottom - rect.top;
|
|
+ }
|
|
+
|
|
+ /* Set as last in case of failed reset those aren't updated */
|
|
+ This->params.BackBufferWidth = params->BackBufferWidth;
|
|
+ This->params.BackBufferHeight = params->BackBufferHeight;
|
|
+ This->params.BackBufferFormat = params->BackBufferFormat;
|
|
+ This->params.BackBufferCount = params->BackBufferCount;
|
|
+ This->params.MultiSampleType = params->MultiSampleType;
|
|
+ This->params.MultiSampleQuality = params->MultiSampleQuality;
|
|
+
|
|
+ DRI3Present_UpdatePresentationInterval(This);
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+/* The following code isn't based on WINE's wined3d or d3d9. */
|
|
+
|
|
+static HRESULT DRI3Present_new(Display *gdi_display, const WCHAR *devname,
|
|
+ D3DPRESENT_PARAMETERS *params, HWND focus_wnd, struct DRI3Present **out,
|
|
+ boolean ex, boolean no_window_changes)
|
|
+{
|
|
+ struct DRI3Present *This;
|
|
+ HWND focus_window;
|
|
+ DEVMODEW new_mode;
|
|
+ HRESULT hr;
|
|
+ RECT rect;
|
|
+
|
|
+ if (!focus_wnd && !params->hDeviceWindow)
|
|
+ {
|
|
+ ERR("No focus HWND specified for presentation backend.\n");
|
|
+ return D3DERR_INVALIDCALL;
|
|
+ }
|
|
+
|
|
+ This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ sizeof(struct DRI3Present));
|
|
+ if (!This)
|
|
+ {
|
|
+ ERR("Out of memory.\n");
|
|
+ return E_OUTOFMEMORY;
|
|
+ }
|
|
+
|
|
+ This->gdi_display = gdi_display;
|
|
+ This->vtable = &DRI3Present_vtable;
|
|
+ This->refs = 1;
|
|
+ This->focus_wnd = focus_wnd;
|
|
+ This->ex = ex;
|
|
+ This->no_window_changes = no_window_changes;
|
|
+
|
|
+ /* store current resolution */
|
|
+ ZeroMemory(&(This->initial_mode), sizeof(This->initial_mode));
|
|
+ This->initial_mode.dmSize = sizeof(This->initial_mode);
|
|
+ EnumDisplaySettingsExW(This->devname, ENUM_CURRENT_SETTINGS, &(This->initial_mode), 0);
|
|
+
|
|
+ if (!params->hDeviceWindow)
|
|
+ params->hDeviceWindow = This->focus_wnd;
|
|
+
|
|
+ if (!params->Windowed) {
|
|
+ focus_window = This->focus_wnd ? This->focus_wnd : params->hDeviceWindow;
|
|
+
|
|
+ if (!nine_register_window(focus_window, This))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+
|
|
+ SetWindowPos(focus_window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
|
+
|
|
+ /* switch display mode */
|
|
+ ZeroMemory(&new_mode, sizeof(DEVMODEW));
|
|
+ new_mode.dmSize = sizeof(DEVMODEW);
|
|
+ new_mode.dmPelsWidth = params->BackBufferWidth;
|
|
+ new_mode.dmPelsHeight = params->BackBufferHeight;
|
|
+ new_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
|
|
+
|
|
+ if (params->FullScreen_RefreshRateInHz)
|
|
+ {
|
|
+ new_mode.dmFields |= DM_DISPLAYFREQUENCY;
|
|
+ new_mode.dmDisplayFrequency = params->FullScreen_RefreshRateInHz;
|
|
+ }
|
|
+
|
|
+ hr = DRI3Present_ChangeDisplaySettingsIfNeccessary(This, &new_mode);
|
|
+ if (FAILED(hr))
|
|
+ {
|
|
+ nine_unregister_window(focus_window);
|
|
+ HeapFree(GetProcessHeap(), 0, This);
|
|
+ return hr;
|
|
+ }
|
|
+
|
|
+ /* Dirty as BackBufferWidth and BackBufferHeight hasn't been set yet */
|
|
+ This->resolution_mismatch = FALSE;
|
|
+
|
|
+ setup_fullscreen_window(This, params->hDeviceWindow,
|
|
+ params->BackBufferWidth, params->BackBufferHeight);
|
|
+ } else {
|
|
+ GetClientRect(params->hDeviceWindow, &rect);
|
|
+ if (!params->BackBufferWidth || !params->BackBufferHeight) {
|
|
+
|
|
+ if (params->BackBufferWidth == 0)
|
|
+ params->BackBufferWidth = rect.right - rect.left;
|
|
+
|
|
+ if (params->BackBufferHeight == 0)
|
|
+ params->BackBufferHeight = rect.bottom - rect.top;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ This->params = *params;
|
|
+
|
|
+ DRI3Present_UpdatePresentationInterval(This);
|
|
+
|
|
+ strcpyW(This->devname, devname);
|
|
+
|
|
+ PRESENTInit(gdi_display, &(This->present_priv));
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ if (is_dri2_fallback && !DRI2FallbackInit(gdi_display, &(This->dri2_priv)))
|
|
+ return D3DERR_INVALIDCALL;
|
|
+#endif
|
|
+ *out = This;
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+struct DRI3PresentGroup
|
|
+{
|
|
+ /* COM vtable */
|
|
+ void *vtable;
|
|
+ /* IUnknown reference count */
|
|
+ LONG refs;
|
|
+
|
|
+ boolean ex;
|
|
+ struct DRI3Present **present_backends;
|
|
+ unsigned npresent_backends;
|
|
+ Display *gdi_display;
|
|
+ boolean no_window_changes;
|
|
+};
|
|
+
|
|
+static ULONG WINAPI DRI3PresentGroup_AddRef(struct DRI3PresentGroup *This)
|
|
+{
|
|
+ ULONG refs = InterlockedIncrement(&This->refs);
|
|
+ TRACE("%p increasing refcount to %u.\n", This, refs);
|
|
+ return refs;
|
|
+}
|
|
+
|
|
+static ULONG WINAPI DRI3PresentGroup_Release(struct DRI3PresentGroup *This)
|
|
+{
|
|
+ ULONG refs = InterlockedDecrement(&This->refs);
|
|
+ TRACE("%p decreasing refcount to %u.\n", This, refs);
|
|
+ if (refs == 0)
|
|
+ {
|
|
+ unsigned i;
|
|
+ if (This->present_backends)
|
|
+ {
|
|
+ for (i = 0; i < This->npresent_backends; ++i)
|
|
+ {
|
|
+ if (This->present_backends[i])
|
|
+ DRI3Present_Release(This->present_backends[i]);
|
|
+ }
|
|
+ HeapFree(GetProcessHeap(), 0, This->present_backends);
|
|
+ }
|
|
+ HeapFree(GetProcessHeap(), 0, This);
|
|
+ }
|
|
+ return refs;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3PresentGroup_QueryInterface(struct DRI3PresentGroup *This,
|
|
+ REFIID riid, void **ppvObject )
|
|
+{
|
|
+ if (!ppvObject)
|
|
+ return E_POINTER;
|
|
+ if (IsEqualGUID(&IID_ID3DPresentGroup, riid) ||
|
|
+ IsEqualGUID(&IID_IUnknown, riid))
|
|
+ {
|
|
+ *ppvObject = This;
|
|
+ DRI3PresentGroup_AddRef(This);
|
|
+ return S_OK;
|
|
+ }
|
|
+
|
|
+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
|
|
+ *ppvObject = NULL;
|
|
+
|
|
+ return E_NOINTERFACE;
|
|
+}
|
|
+
|
|
+static UINT WINAPI DRI3PresentGroup_GetMultiheadCount(struct DRI3PresentGroup *This)
|
|
+{
|
|
+ FIXME("(%p), stub!\n", This);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3PresentGroup_GetPresent(struct DRI3PresentGroup *This,
|
|
+ UINT Index, ID3DPresent **ppPresent)
|
|
+{
|
|
+ if (Index >= DRI3PresentGroup_GetMultiheadCount(This))
|
|
+ {
|
|
+ ERR("Index >= MultiHeadCount\n");
|
|
+ return D3DERR_INVALIDCALL;
|
|
+ }
|
|
+ DRI3Present_AddRef(This->present_backends[Index]);
|
|
+ *ppPresent = (ID3DPresent *)This->present_backends[Index];
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+static HRESULT WINAPI DRI3PresentGroup_CreateAdditionalPresent(struct DRI3PresentGroup *This,
|
|
+ D3DPRESENT_PARAMETERS *pPresentationParameters, ID3DPresent **ppPresent)
|
|
+{
|
|
+ HRESULT hr;
|
|
+ hr = DRI3Present_new(This->gdi_display, This->present_backends[0]->devname,
|
|
+ pPresentationParameters, 0, (struct DRI3Present **)ppPresent,
|
|
+ This->ex, This->no_window_changes);
|
|
+
|
|
+ return hr;
|
|
+}
|
|
+
|
|
+static void WINAPI DRI3PresentGroup_GetVersion(struct DRI3PresentGroup *This,
|
|
+ int *major, int *minor)
|
|
+{
|
|
+ *major = WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR;
|
|
+ *minor = WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR;
|
|
+}
|
|
+
|
|
+static ID3DPresentGroupVtbl DRI3PresentGroup_vtable = {
|
|
+ (void *)DRI3PresentGroup_QueryInterface,
|
|
+ (void *)DRI3PresentGroup_AddRef,
|
|
+ (void *)DRI3PresentGroup_Release,
|
|
+ (void *)DRI3PresentGroup_GetMultiheadCount,
|
|
+ (void *)DRI3PresentGroup_GetPresent,
|
|
+ (void *)DRI3PresentGroup_CreateAdditionalPresent,
|
|
+ (void *)DRI3PresentGroup_GetVersion
|
|
+};
|
|
+
|
|
+HRESULT present_create_present_group(Display *gdi_display, const WCHAR *device_name,
|
|
+ UINT adapter, HWND focus_wnd, D3DPRESENT_PARAMETERS *params,
|
|
+ unsigned nparams, ID3DPresentGroup **group, boolean ex, DWORD BehaviorFlags)
|
|
+{
|
|
+ struct DRI3PresentGroup *This;
|
|
+ DISPLAY_DEVICEW dd;
|
|
+ HRESULT hr;
|
|
+ unsigned i;
|
|
+
|
|
+ This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ sizeof(struct DRI3PresentGroup));
|
|
+ if (!This)
|
|
+ {
|
|
+ ERR("Out of memory.\n");
|
|
+ return E_OUTOFMEMORY;
|
|
+ }
|
|
+
|
|
+ This->gdi_display = gdi_display;
|
|
+ This->vtable = &DRI3PresentGroup_vtable;
|
|
+ This->refs = 1;
|
|
+ This->ex = ex;
|
|
+ This->npresent_backends = nparams;
|
|
+ This->no_window_changes = !!(BehaviorFlags & D3DCREATE_NOWINDOWCHANGES);
|
|
+ This->present_backends = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
+ This->npresent_backends * sizeof(struct DRI3Present *));
|
|
+ if (!This->present_backends)
|
|
+ {
|
|
+ DRI3PresentGroup_Release(This);
|
|
+ ERR("Out of memory.\n");
|
|
+ return E_OUTOFMEMORY;
|
|
+ }
|
|
+
|
|
+ if (nparams != 1)
|
|
+ adapter = 0;
|
|
+
|
|
+ for (i = 0; i < This->npresent_backends; ++i)
|
|
+ {
|
|
+ ZeroMemory(&dd, sizeof(dd));
|
|
+ dd.cb = sizeof(dd);
|
|
+ /* find final device name */
|
|
+ if (!EnumDisplayDevicesW(device_name, adapter + i, &dd, 0))
|
|
+ {
|
|
+ WARN("Couldn't find subdevice %d from `%s'\n",
|
|
+ i, debugstr_w(device_name));
|
|
+ }
|
|
+
|
|
+ /* create an ID3DPresent for it */
|
|
+ hr = DRI3Present_new(gdi_display, dd.DeviceName, ¶ms[i],
|
|
+ focus_wnd, &This->present_backends[i], ex, This->no_window_changes);
|
|
+ if (FAILED(hr))
|
|
+ {
|
|
+ DRI3PresentGroup_Release(This);
|
|
+ return hr;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ *group = (ID3DPresentGroup *)This;
|
|
+ TRACE("Returning %p\n", *group);
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+HRESULT present_create_adapter9(Display *gdi_display, HDC hdc, ID3DAdapter9 **out)
|
|
+{
|
|
+ struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE };
|
|
+ HRESULT hr;
|
|
+ int fd;
|
|
+
|
|
+ if (!d3d9_drm)
|
|
+ {
|
|
+ ERR("DRM drivers are not supported on your system.\n");
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+ }
|
|
+
|
|
+ if (ExtEscape(hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc,
|
|
+ sizeof(extesc), (LPSTR)&extesc) <= 0)
|
|
+ ERR("X11 drawable lookup failed (hdc=%p)\n", hdc);
|
|
+
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ if (!is_dri2_fallback && !DRI3Open(gdi_display, DefaultScreen(gdi_display), &fd))
|
|
+#else
|
|
+ if (!DRI3Open(gdi_display, DefaultScreen(gdi_display), &fd))
|
|
+#endif
|
|
+ {
|
|
+ ERR("DRI3Open failed (fd=%d)\n", fd);
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+ }
|
|
+#ifdef D3D9NINE_DRI2
|
|
+ if (is_dri2_fallback && !DRI2FallbackOpen(gdi_display, DefaultScreen(gdi_display), &fd))
|
|
+ {
|
|
+ ERR("DRI2Open failed (fd=%d)\n", fd);
|
|
+ return D3DERR_DRIVERINTERNALERROR;
|
|
+ }
|
|
+#endif
|
|
+ hr = d3d9_drm->create_adapter(fd, out);
|
|
+ if (FAILED(hr))
|
|
+ {
|
|
+ ERR("Unable to create ID3DAdapter9 (fd=%d)\n", fd);
|
|
+ return hr;
|
|
+ }
|
|
+
|
|
+ TRACE("Created ID3DAdapter9 with fd %d\n", fd);
|
|
+
|
|
+ return D3D_OK;
|
|
+}
|
|
+
|
|
+BOOL present_has_d3dadapter(Display *gdi_display)
|
|
+{
|
|
+ static const void * WINAPI (*pD3DAdapter9GetProc)(const char *);
|
|
+ static void *handle = NULL;
|
|
+ static int done = 0;
|
|
+ HKEY regkey;
|
|
+ LSTATUS rc;
|
|
+ char *path = NULL;
|
|
+
|
|
+ char errbuf[256];
|
|
+ char pathbuf[MAX_PATH];
|
|
+
|
|
+ /* like in opengl.c (single threaded assumption OK?) */
|
|
+ if (done)
|
|
+ return handle != NULL;
|
|
+ done = 1;
|
|
+
|
|
+ if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Direct3DNine", ®key))
|
|
+ {
|
|
+ DWORD type;
|
|
+ DWORD size = 0;
|
|
+
|
|
+ rc = RegQueryValueExA(regkey, "ModulePath", 0, &type, NULL, &size);
|
|
+ if (rc == ERROR_FILE_NOT_FOUND)
|
|
+ goto use_default_path;
|
|
+
|
|
+ TRACE("Reading registry key for module path\n");
|
|
+ if (rc != ERROR_SUCCESS || type != REG_SZ)
|
|
+ {
|
|
+ ERR("Failed to read Direct3DNine ModulePath registry key: Invalid content\n");
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ path = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + 1);
|
|
+ if (!path)
|
|
+ {
|
|
+ ERR("Out of memory\n");
|
|
+ return FALSE;
|
|
+ }
|
|
+ rc = RegQueryValueExA(regkey, "ModulePath", 0, &type, (LPBYTE)path, &size);
|
|
+ if (rc != ERROR_SUCCESS)
|
|
+ {
|
|
+ ERR("Failed to read Direct3DNine registry\n");
|
|
+ goto cleanup;
|
|
+ }
|
|
+ /* Split colon separated path for multi-arch support */
|
|
+ if (strstr(path, ":"))
|
|
+ {
|
|
+ char *tmp_path = strstr(path, ":");
|
|
+
|
|
+ /* Replace colon by string terminate */
|
|
+ *tmp_path = 0;
|
|
+ tmp_path ++;
|
|
+ handle = wine_dlopen(path,
|
|
+ RTLD_GLOBAL | RTLD_NOW, errbuf, sizeof(errbuf));
|
|
+ if (!handle)
|
|
+ {
|
|
+ TRACE("Failed to load '%s': %s\n", path, errbuf);
|
|
+
|
|
+ handle = wine_dlopen(tmp_path,
|
|
+ RTLD_GLOBAL | RTLD_NOW, errbuf, sizeof(errbuf));
|
|
+ if (!handle)
|
|
+ {
|
|
+ TRACE("Failed to load '%s': %s\n", tmp_path, errbuf);
|
|
+ ERR("Failed to load '%s' and '%s' set by ModulePath.\n",
|
|
+ path, tmp_path);
|
|
+ goto cleanup;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ handle = wine_dlopen(path,
|
|
+ RTLD_GLOBAL | RTLD_NOW, errbuf, sizeof(errbuf));
|
|
+ if (!handle)
|
|
+ {
|
|
+ TRACE("Failed to load %s: %s\n", path, errbuf);
|
|
+ ERR("Failed to load '%s' set by ModulePath.\n", path);
|
|
+ goto cleanup;
|
|
+ }
|
|
+ }
|
|
+ memcpy(pathbuf, path, size >= sizeof(pathbuf) ? (sizeof(pathbuf)-1) : size);
|
|
+ pathbuf[sizeof(pathbuf)-1] = 0;
|
|
+
|
|
+ HeapFree(GetProcessHeap(), 0, path);
|
|
+ }
|
|
+
|
|
+use_default_path:
|
|
+#if !defined(D3D9NINE_MODULEPATH)
|
|
+ if (!handle)
|
|
+ {
|
|
+ ERR("d3d9-nine.dll was built without default module path.\n"
|
|
+ "Setting Software\\Wine\\Direct3DNine ModulePath is required\n");
|
|
+ goto cleanup;
|
|
+ }
|
|
+#else
|
|
+ if (!handle)
|
|
+ {
|
|
+ handle = wine_dlopen(D3D9NINE_MODULEPATH,
|
|
+ RTLD_GLOBAL | RTLD_NOW, errbuf, sizeof(errbuf));
|
|
+ if (!handle)
|
|
+ {
|
|
+ ERR("Failed to load '%s': %s\n", D3D9NINE_MODULEPATH, errbuf);
|
|
+ goto cleanup;
|
|
+ }
|
|
+ memcpy(pathbuf, D3D9NINE_MODULEPATH,
|
|
+ sizeof(D3D9NINE_MODULEPATH) >= sizeof(pathbuf) ?
|
|
+ (sizeof(pathbuf)-1) : sizeof(D3D9NINE_MODULEPATH));
|
|
+ pathbuf[sizeof(pathbuf)-1] = 0;
|
|
+ }
|
|
+#endif
|
|
+ /* find our entry point in d3dadapter9 */
|
|
+ pD3DAdapter9GetProc = wine_dlsym(handle, "D3DAdapter9GetProc",
|
|
+ errbuf, sizeof(errbuf));
|
|
+ if (!pD3DAdapter9GetProc)
|
|
+ {
|
|
+ ERR("Failed to get the entry point from %s: %s", pathbuf, errbuf);
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ /* get a handle to the drm backend struct */
|
|
+ d3d9_drm = pD3DAdapter9GetProc("drm");
|
|
+ if (!d3d9_drm)
|
|
+ {
|
|
+ ERR("%s doesn't support the drm backend.\n", pathbuf);
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ /* verify that we're binary compatible */
|
|
+ if (d3d9_drm->major_version != 0)
|
|
+ {
|
|
+ ERR("Version mismatch. %s has %d.%d, was expecting 0.x\n",
|
|
+ pathbuf, d3d9_drm->major_version, d3d9_drm->minor_version);
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ /* this will be used to store d3d_drawables */
|
|
+ d3d_hwnd_context = XUniqueContext();
|
|
+
|
|
+ if (!PRESENTCheckExtension(gdi_display, 1, 0))
|
|
+ {
|
|
+ ERR("Unable to query PRESENT.\n");
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ if (!DRI3CheckExtension(gdi_display, 1, 0))
|
|
+ {
|
|
+#ifndef D3D9NINE_DRI2
|
|
+ ERR("Unable to query DRI3.\n");
|
|
+ goto cleanup;
|
|
+#else
|
|
+ ERR("Unable to query DRI3. Trying DRI2 fallback (slower performance).\n");
|
|
+ is_dri2_fallback = 1;
|
|
+ if (!DRI2FallbackCheckSupport(gdi_display))
|
|
+ {
|
|
+ ERR("DRI2 fallback unsupported\n");
|
|
+ goto cleanup;
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ return TRUE;
|
|
+
|
|
+cleanup:
|
|
+ ERR("\033[1;31m\nNative Direct3D 9 will be unavailable."
|
|
+ "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n");
|
|
+ if (handle)
|
|
+ {
|
|
+ wine_dlclose(handle, NULL, 0);
|
|
+ handle = NULL;
|
|
+ }
|
|
+
|
|
+ if (path)
|
|
+ HeapFree(GetProcessHeap(), 0, path);
|
|
+
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+BOOL enable_device_vtable_wrapper(void)
|
|
+{
|
|
+ if (!d3d9_drm)
|
|
+ {
|
|
+ ERR("enable_device_vtable_wrapper call before init.\n");
|
|
+ return FALSE;
|
|
+ }
|
|
+ /* Since minor version 1, we can assume a copy of the internal vtable is stored in second pos.
|
|
+ * For now always enable if possible the wrapper (enables Steam overlay for example),
|
|
+ * we might in the future let user choose. */
|
|
+ return d3d9_drm->minor_version >= 1;
|
|
+}
|
|
diff --git a/dlls/d3d9-nine/present.h b/dlls/d3d9-nine/present.h
|
|
new file mode 100644
|
|
index 0000000000..a5516877f1
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/present.h
|
|
@@ -0,0 +1,40 @@
|
|
+/*
|
|
+ * Wine present interface
|
|
+ *
|
|
+ * Copyright 2015 Patrick Rudolph
|
|
+ *
|
|
+ * 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_PRESENT_H
|
|
+#define __WINE_PRESENT_H
|
|
+
|
|
+#ifndef __WINE_CONFIG_H
|
|
+# error You must include config.h to use this header
|
|
+#endif
|
|
+
|
|
+#include <X11/Xlib.h>
|
|
+
|
|
+HRESULT present_create_present_group(Display *gdi_display, const WCHAR *device_name, UINT adapter,
|
|
+ HWND focus, D3DPRESENT_PARAMETERS *params, unsigned nparams, ID3DPresentGroup **group,
|
|
+ boolean ex, DWORD BehaviorFlags);
|
|
+
|
|
+HRESULT present_create_adapter9(Display *gdi_display, HDC hdc, ID3DAdapter9 **adapter);
|
|
+
|
|
+BOOL present_has_d3dadapter(Display *gdi_display);
|
|
+
|
|
+BOOL enable_device_vtable_wrapper(void);
|
|
+
|
|
+#endif /* __WINE_PRESENT_H */
|
|
diff --git a/dlls/d3d9-nine/shader_validator.c b/dlls/d3d9-nine/shader_validator.c
|
|
new file mode 100644
|
|
index 0000000000..03848b2aa2
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/shader_validator.c
|
|
@@ -0,0 +1,88 @@
|
|
+/*
|
|
+ * Direct3D 9 ShaderValidator
|
|
+ *
|
|
+ * Copyright 2016 Patrick Rudolph
|
|
+ *
|
|
+ * 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"
|
|
+WINE_DEFAULT_DEBUG_CHANNEL(d3d9nine);
|
|
+
|
|
+#include "winbase.h"
|
|
+
|
|
+#include "shader_validator.h"
|
|
+
|
|
+static HRESULT WINAPI IDirect3DShaderValidator9Impl_QueryInterface(IDirect3DShaderValidator9Impl *This,
|
|
+ REFIID riid, LPVOID* ppobj)
|
|
+{
|
|
+ /* TODO: AddRef(iface). */
|
|
+ *ppobj = This;
|
|
+ TRACE("This=%p, riid=%s, object=%p.\n", This, debugstr_guid(riid), ppobj);
|
|
+
|
|
+ return S_OK;
|
|
+}
|
|
+
|
|
+static ULONG WINAPI IDirect3DShaderValidator9Impl_AddRef(IDirect3DShaderValidator9Impl *This)
|
|
+{
|
|
+ ULONG ref = InterlockedIncrement(&This->ref);
|
|
+ TRACE("This=%p increasing refcount to %u.\n", This, ref);
|
|
+
|
|
+ return ref;
|
|
+}
|
|
+
|
|
+static ULONG WINAPI IDirect3DShaderValidator9Impl_Release(IDirect3DShaderValidator9Impl *This)
|
|
+{
|
|
+ ULONG ref = InterlockedDecrement(&This->ref);
|
|
+ TRACE("This=%p decreasing refcount to %u.\n", This, ref);
|
|
+
|
|
+ if (ref == 0)
|
|
+ HeapFree(GetProcessHeap(), 0, This);
|
|
+
|
|
+ return ref;
|
|
+}
|
|
+
|
|
+static LONG WINAPI IDirect3DShaderValidator9Impl_Begin(IDirect3DShaderValidator9Impl *This,
|
|
+ void* callback, void* unknown1, ULONG unknown2)
|
|
+{
|
|
+ TRACE("This=%p, callback=%p, unknown1=%p, unknown2=%u\n", This, callback, unknown1, unknown2);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static LONG WINAPI IDirect3DShaderValidator9Impl_Instruction(IDirect3DShaderValidator9Impl *This,
|
|
+ const char* unknown1, unsigned int unknown2, const unsigned long* unknown3, unsigned int unknown4)
|
|
+{
|
|
+ TRACE("This=%p, unknown1=%p, unknown2=%u, unknown3=%p, unknown4=%u\n", This, unknown1, unknown2, unknown3, unknown4);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static LONG WINAPI IDirect3DShaderValidator9Impl_End(IDirect3DShaderValidator9Impl *This)
|
|
+{
|
|
+ TRACE("This=%p\n", This);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+const void *IDirect3DShaderValidator9Vtbl[] =
|
|
+{
|
|
+ /* IUnknown */
|
|
+ IDirect3DShaderValidator9Impl_QueryInterface,
|
|
+ IDirect3DShaderValidator9Impl_AddRef,
|
|
+ IDirect3DShaderValidator9Impl_Release,
|
|
+ /* IDirect3DShaderValidator9 */
|
|
+ IDirect3DShaderValidator9Impl_Begin,
|
|
+ IDirect3DShaderValidator9Impl_Instruction,
|
|
+ IDirect3DShaderValidator9Impl_End
|
|
+};
|
|
+
|
|
diff --git a/dlls/d3d9-nine/shader_validator.h b/dlls/d3d9-nine/shader_validator.h
|
|
new file mode 100644
|
|
index 0000000000..07a5e2d2b4
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/shader_validator.h
|
|
@@ -0,0 +1,29 @@
|
|
+/*
|
|
+ * Direct3D 9 ShaderValidator
|
|
+ *
|
|
+ * Copyright 2016 Patrick Rudolph
|
|
+ *
|
|
+ * 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
|
|
+ *
|
|
+ */
|
|
+
|
|
+typedef struct IDirect3DShaderValidator9Impl
|
|
+{
|
|
+ /* IUnknown fields */
|
|
+ void *lpVtbl;
|
|
+ LONG ref;
|
|
+} IDirect3DShaderValidator9Impl;
|
|
+
|
|
+const void *IDirect3DShaderValidator9Vtbl[6];
|
|
diff --git a/dlls/d3d9-nine/version.rc b/dlls/d3d9-nine/version.rc
|
|
new file mode 100644
|
|
index 0000000000..bfafc2f24a
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/version.rc
|
|
@@ -0,0 +1,26 @@
|
|
+/*
|
|
+ * Copyright 2015 Patrick Rudolph
|
|
+ *
|
|
+ * 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
|
|
+ */
|
|
+
|
|
+#define WINE_FILEDESCRIPTION_STR "Wine Gallium Nine Direct3D"
|
|
+#define WINE_FILENAME_STR "d3d9-nine.dll"
|
|
+#define WINE_FILEVERSION 5,3,1,904
|
|
+#define WINE_FILEVERSION_STR "5.3.1.904"
|
|
+#define WINE_PRODUCTVERSION 5,3,1,904
|
|
+#define WINE_PRODUCTVERSION_STR "5.3.1.904"
|
|
+
|
|
+#include "wine/wine_common_ver.rc"
|
|
diff --git a/dlls/d3d9-nine/wndproc.c b/dlls/d3d9-nine/wndproc.c
|
|
new file mode 100644
|
|
index 0000000000..0ed80de7d7
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/wndproc.c
|
|
@@ -0,0 +1,277 @@
|
|
+/*
|
|
+ * Copyright 2016 Patrick Rudolph
|
|
+ *
|
|
+ * Based on the file wined3d_main.c taken from wined3d:
|
|
+ * All credits go to the original developers:
|
|
+ *
|
|
+ * Copyright 2002-2003 The wine-d3d team
|
|
+ * Copyright 2002-2003 Raphael Junqueira
|
|
+ * Copyright 2004 Jason Edmeades
|
|
+ * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
|
|
+ * Copyright 2009 Henri Verbeet 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 "config.h"
|
|
+#include "wine/port.h"
|
|
+
|
|
+#include <stdarg.h>
|
|
+#include <math.h>
|
|
+#include <limits.h>
|
|
+#define NONAMELESSUNION
|
|
+#define NONAMELESSSTRUCT
|
|
+#define COBJMACROS
|
|
+#include "windef.h"
|
|
+#include "winbase.h"
|
|
+#include "winreg.h"
|
|
+#include "wingdi.h"
|
|
+#include "winuser.h"
|
|
+#include "wine/debug.h"
|
|
+#include "wine/unicode.h"
|
|
+
|
|
+#include "wndproc.h"
|
|
+
|
|
+WINE_DEFAULT_DEBUG_CHANNEL(d3dadapter);
|
|
+
|
|
+struct nine_wndproc
|
|
+{
|
|
+ HWND window;
|
|
+ BOOL unicode;
|
|
+ WNDPROC proc;
|
|
+ struct DRI3Present *present;
|
|
+};
|
|
+
|
|
+struct nine_wndproc_table
|
|
+{
|
|
+ struct nine_wndproc *entries;
|
|
+ unsigned int count;
|
|
+ unsigned int size;
|
|
+};
|
|
+
|
|
+static struct nine_wndproc_table wndproc_table;
|
|
+
|
|
+static CRITICAL_SECTION nine_wndproc_cs;
|
|
+static CRITICAL_SECTION_DEBUG nine_wndproc_cs_debug =
|
|
+{
|
|
+ 0, 0, &nine_wndproc_cs,
|
|
+ {&nine_wndproc_cs_debug.ProcessLocksList,
|
|
+ &nine_wndproc_cs_debug.ProcessLocksList},
|
|
+ 0, 0, {(DWORD_PTR)(__FILE__ ": nine_wndproc_cs")}
|
|
+};
|
|
+static CRITICAL_SECTION nine_wndproc_cs = {&nine_wndproc_cs_debug, -1, 0, 0, 0, 0};
|
|
+
|
|
+BOOL nine_dll_init(HINSTANCE hInstDLL)
|
|
+{
|
|
+ WNDCLASSA wc;
|
|
+
|
|
+ /* We need our own window class for a fake window which we use to retrieve GL capabilities */
|
|
+ /* We might need CS_OWNDC in the future if we notice strange things on Windows.
|
|
+ * Various articles/posts about OpenGL problems on Windows recommend this. */
|
|
+ wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
+ wc.lpfnWndProc = DefWindowProcA;
|
|
+ wc.cbClsExtra = 0;
|
|
+ wc.cbWndExtra = 0;
|
|
+ wc.hInstance = hInstDLL;
|
|
+ wc.hIcon = LoadIconA(NULL, (const char *)IDI_WINLOGO);
|
|
+ wc.hCursor = LoadCursorA(NULL, (const char *)IDC_ARROW);
|
|
+ wc.hbrBackground = NULL;
|
|
+ wc.lpszMenuName = NULL;
|
|
+ wc.lpszClassName = NINE_WINDOW_CLASS_NAME;
|
|
+
|
|
+ if (!RegisterClassA(&wc))
|
|
+ {
|
|
+ ERR("Failed to register window class '%s'!\n", NINE_WINDOW_CLASS_NAME);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ DisableThreadLibraryCalls(hInstDLL);
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+BOOL nine_dll_destroy(HINSTANCE hInstDLL)
|
|
+{
|
|
+ unsigned int i;
|
|
+
|
|
+ for (i = 0; i < wndproc_table.count; ++i)
|
|
+ {
|
|
+ /* Trying to unregister these would be futile. These entries can only
|
|
+ * exist if either we skipped them in nine_unregister_window() due
|
|
+ * to the application replacing the wndproc after the entry was
|
|
+ * registered, or if the application still has an active nine
|
|
+ * device. In the latter case the application has bigger problems than
|
|
+ * these entries. */
|
|
+ WARN("Leftover wndproc table entry %p.\n", &wndproc_table.entries[i]);
|
|
+ }
|
|
+ HeapFree(GetProcessHeap(), 0, wndproc_table.entries);
|
|
+
|
|
+ UnregisterClassA(NINE_WINDOW_CLASS_NAME, hInstDLL);
|
|
+
|
|
+ DeleteCriticalSection(&nine_wndproc_cs);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static void nine_wndproc_mutex_lock(void)
|
|
+{
|
|
+ EnterCriticalSection(&nine_wndproc_cs);
|
|
+}
|
|
+
|
|
+static void nine_wndproc_mutex_unlock(void)
|
|
+{
|
|
+ LeaveCriticalSection(&nine_wndproc_cs);
|
|
+}
|
|
+
|
|
+static struct nine_wndproc *nine_find_wndproc(HWND window)
|
|
+{
|
|
+ unsigned int i;
|
|
+
|
|
+ for (i = 0; i < wndproc_table.count; ++i)
|
|
+ {
|
|
+ if (wndproc_table.entries[i].window == window)
|
|
+ {
|
|
+ return &wndproc_table.entries[i];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static LRESULT CALLBACK nine_wndproc(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
|
|
+{
|
|
+ struct nine_wndproc *entry;
|
|
+ struct DRI3Present *present;
|
|
+ BOOL unicode;
|
|
+ WNDPROC proc;
|
|
+
|
|
+ nine_wndproc_mutex_lock();
|
|
+ entry = nine_find_wndproc(window);
|
|
+
|
|
+ if (!entry)
|
|
+ {
|
|
+ nine_wndproc_mutex_unlock();
|
|
+ ERR("Window %p is not registered with nine.\n", window);
|
|
+ return DefWindowProcW(window, message, wparam, lparam);
|
|
+ }
|
|
+
|
|
+ present = entry->present;
|
|
+ unicode = entry->unicode;
|
|
+ proc = entry->proc;
|
|
+ nine_wndproc_mutex_unlock();
|
|
+
|
|
+ if (present)
|
|
+ return device_process_message(present, window, unicode, message, wparam, lparam, proc);
|
|
+ if (unicode)
|
|
+ return CallWindowProcW(proc, window, message, wparam, lparam);
|
|
+ return CallWindowProcA(proc, window, message, wparam, lparam);
|
|
+}
|
|
+
|
|
+BOOL nine_register_window(HWND window, struct DRI3Present *present)
|
|
+{
|
|
+ struct nine_wndproc *entry;
|
|
+
|
|
+ nine_wndproc_mutex_lock();
|
|
+
|
|
+ if (nine_find_wndproc(window))
|
|
+ {
|
|
+ nine_wndproc_mutex_unlock();
|
|
+ WARN("Window %p is already registered with nine.\n", window);
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+ if (wndproc_table.size == wndproc_table.count)
|
|
+ {
|
|
+ unsigned int new_size = max(1, wndproc_table.size * 2);
|
|
+ struct nine_wndproc *new_entries;
|
|
+
|
|
+ if (!wndproc_table.entries) new_entries = HeapAlloc(GetProcessHeap(), 0, new_size * sizeof(*new_entries));
|
|
+ else new_entries = HeapReAlloc(GetProcessHeap(), 0, wndproc_table.entries, new_size * sizeof(*new_entries));
|
|
+
|
|
+ if (!new_entries)
|
|
+ {
|
|
+ nine_wndproc_mutex_unlock();
|
|
+ ERR("Failed to grow table.\n");
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ wndproc_table.entries = new_entries;
|
|
+ wndproc_table.size = new_size;
|
|
+ }
|
|
+
|
|
+ entry = &wndproc_table.entries[wndproc_table.count++];
|
|
+ entry->window = window;
|
|
+ entry->unicode = IsWindowUnicode(window);
|
|
+ /* Set a window proc that matches the window. Some applications (e.g. NoX)
|
|
+ * replace the window proc after we've set ours, and expect to be able to
|
|
+ * call the previous one (ours) directly, without using CallWindowProc(). */
|
|
+ if (entry->unicode)
|
|
+ entry->proc = (WNDPROC)SetWindowLongPtrW(window, GWLP_WNDPROC, (LONG_PTR)nine_wndproc);
|
|
+ else
|
|
+ entry->proc = (WNDPROC)SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)nine_wndproc);
|
|
+ entry->present = present;
|
|
+
|
|
+ nine_wndproc_mutex_unlock();
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+BOOL nine_unregister_window(HWND window)
|
|
+{
|
|
+ struct nine_wndproc *entry, *last;
|
|
+ LONG_PTR proc;
|
|
+
|
|
+ nine_wndproc_mutex_lock();
|
|
+
|
|
+ if (!(entry = nine_find_wndproc(window)))
|
|
+ {
|
|
+ nine_wndproc_mutex_unlock();
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ if (entry->unicode)
|
|
+ {
|
|
+ proc = GetWindowLongPtrW(window, GWLP_WNDPROC);
|
|
+ if (proc != (LONG_PTR)nine_wndproc)
|
|
+ {
|
|
+ entry->present = NULL;
|
|
+ nine_wndproc_mutex_unlock();
|
|
+ WARN("Not unregistering window %p, window proc %#lx doesn't match nine window proc %p.\n",
|
|
+ window, proc, nine_wndproc);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ SetWindowLongPtrW(window, GWLP_WNDPROC, (LONG_PTR)entry->proc);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
|
|
+ if (proc != (LONG_PTR)nine_wndproc)
|
|
+ {
|
|
+ entry->present = NULL;
|
|
+ nine_wndproc_mutex_unlock();
|
|
+ WARN("Not unregistering window %p, window proc %#lx doesn't match nine window proc %p.\n",
|
|
+ window, proc, nine_wndproc);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)entry->proc);
|
|
+ }
|
|
+
|
|
+ last = &wndproc_table.entries[--wndproc_table.count];
|
|
+ if (entry != last) *entry = *last;
|
|
+
|
|
+ nine_wndproc_mutex_unlock();
|
|
+ return TRUE;
|
|
+}
|
|
diff --git a/dlls/d3d9-nine/wndproc.h b/dlls/d3d9-nine/wndproc.h
|
|
new file mode 100644
|
|
index 0000000000..15f26d491a
|
|
--- /dev/null
|
|
+++ b/dlls/d3d9-nine/wndproc.h
|
|
@@ -0,0 +1,41 @@
|
|
+/*
|
|
+ * Direct3D wine internal interface main
|
|
+ *
|
|
+ * Copyright 2002-2003 The wine-d3d team
|
|
+ * Copyright 2002-2003 Raphael Junqueira
|
|
+ * Copyright 2004 Jason Edmeades
|
|
+ * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
|
|
+ * Copyright 2009 Henri Verbeet 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_NINE_WNDPROC_H
|
|
+#define __WINE_NINE_WNDPROC_H
|
|
+
|
|
+struct DRI3Present;
|
|
+
|
|
+BOOL nine_register_window(HWND window, struct DRI3Present *present);
|
|
+BOOL nine_unregister_window(HWND window);
|
|
+
|
|
+BOOL nine_dll_init(HINSTANCE hInstDLL);
|
|
+BOOL nine_dll_destroy(HINSTANCE hInstDLL);
|
|
+
|
|
+LRESULT device_process_message(struct DRI3Present *present, HWND window, BOOL unicode,
|
|
+ UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc);
|
|
+
|
|
+#define NINE_WINDOW_CLASS_NAME "Gallium_Nine_Window"
|
|
+
|
|
+#endif
|
|
--
|
|
2.14.1
|
|
|