├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.rst ├── bootstrap.sh ├── common ├── compiler.h ├── debug.c ├── debug.h ├── library.c ├── library.h ├── meson.build ├── registry.c └── registry.h ├── d3d9-nine ├── backend.c ├── backend.h ├── d3d9.spec ├── d3d9_main.c ├── d3dadapter9.c ├── d3dadapter9.h ├── device_wrap.c ├── device_wrap.h ├── dri2.c ├── dri3.c ├── meson.build ├── present.c ├── present.h ├── shader_validator.c ├── shader_validator.h ├── version.rc ├── wndproc.c ├── wndproc.h ├── xcb_present.c └── xcb_present.h ├── meson.build ├── meson_options.txt ├── ninewinecfg ├── main.c ├── meson.build ├── ninewinecfg.manifest ├── ninewinecfg.rc ├── nls │ ├── cze.rc │ ├── deu.rc │ ├── eng.rc │ ├── fra.rc │ ├── hun.rc │ ├── jpn.rc │ └── por.rc └── resource.h ├── release.sh └── tools ├── .gitignore ├── cross-wine32.in ├── cross-wine64.in ├── get_version.sh └── nine-install.sh /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-20.04 10 | steps: 11 | - name: Fix broken github setup 12 | # https://github.com/actions/runner-images/issues/4589 13 | run: > 14 | sudo dpkg -l | 15 | awk '/ii lib.*deb.sury.org/ {gsub(/:.*/, s, $2); print $2}' | 16 | xargs apt show -a | 17 | awk '/Package:/ {p=$2} /APT-Sources: .*focal\/main/ {print p"/focal"}' | 18 | sudo xargs eatmydata apt install --allow-downgrades 19 | - name: Setup repositories 20 | run: | 21 | sudo dpkg --add-architecture i386 22 | sudo wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key 23 | sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/focal/winehq-focal.sources 24 | sudo apt-get update -y 25 | - name: Install dependencies 26 | run: > 27 | sudo apt-get install -y 28 | gcc-multilib 29 | meson 30 | winehq-stable=6.0.0~focal-1 31 | wine-stable=6.0.0~focal-1 32 | wine-stable-amd64=6.0.0~focal-1 33 | wine-stable-i386=6.0.0~focal-1 34 | wine-stable-dev=6.0.0~focal-1 35 | libdrm-dev 36 | libdrm-dev:i386 37 | libx11-xcb-dev 38 | libx11-xcb-dev:i386 39 | libxcb-present-dev 40 | libxcb-present-dev:i386 41 | libxcb-dri3-dev 42 | libxcb-dri3-dev:i386 43 | libxcb-dri2-0-dev 44 | libxcb-dri2-0-dev:i386 45 | libegl1-mesa-dev 46 | libegl1-mesa-dev:i386 47 | libgl1-mesa-dev 48 | libgl1-mesa-dev:i386 49 | libd3dadapter9-mesa-dev 50 | libd3dadapter9-mesa-dev:i386 51 | - name: Checkout 52 | uses: actions/checkout@v4 53 | with: 54 | fetch-depth: 0 55 | - name: Setup environment 56 | run: > 57 | if test "${GITHUB_REF:0:10}" = "refs/tags/"; then 58 | echo "RELEASE_TARBALL=/tmp/gallium-nine-standalone-${GITHUB_REF:10}.tar.gz" >> $GITHUB_ENV 59 | else 60 | echo "RELEASE_TARBALL=/tmp/gallium-nine-standalone-${GITHUB_SHA:0:8}.tar.gz" >> $GITHUB_ENV 61 | fi 62 | - name: Compile 63 | run: ./release.sh -o "${RELEASE_TARBALL}" -- -Ddri2=true -Ddistro-independent=true 64 | - name: Upload artifact 65 | uses: actions/upload-artifact@v4 66 | with: 67 | name: build 68 | path: ${{ env.RELEASE_TARBALL }} 69 | - name: Release 70 | uses: softprops/action-gh-release@v2 71 | if: startsWith(github.ref, 'refs/tags/') 72 | with: 73 | files: ${{ env.RELEASE_TARBALL }} 74 | env: 75 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Release artifacts 2 | gallium-nine-standalone.tar.gz 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Gallium Nine Standalone |buildstate| 2 | ==================================== 3 | 4 | .. |buildstate| image:: https://github.com/iXit/wine-nine-standalone/actions/workflows/build.yml/badge.svg?branch=master 5 | :target: https://github.com/iXit/wine-nine-standalone/actions 6 | 7 | .. image:: https://wiki.ixit.cz/_media/gallium-nine.png 8 | :target: https://wiki.ixit.cz/d3d9 9 | 10 | About 11 | ----- 12 | Gallium Nine allows to run any Direct3D 9 application with nearly no CPU overhead, which provides a smoother gaming experience and increased FPS. 13 | 14 | Gallium Nine Standalone, as the name implies, is a standalone version of the `WINE `_ parts of `Gallium Nine `_. 15 | 16 | This decouples Gallium Nine from the WINE tree, so that it can be used with any WINE version. There is no need for any WINE patches. A stable, development, or staging WINE release is sufficient. 17 | 18 | Gallium Nine Standalone consists of two parts: 19 | 20 | * ``d3d9-nine.dll``: Gallium Nine Direct3D 9 library 21 | * ``ninewinecfg.exe``: GUI to enable/disable Gallium Nine with some additional info about the current state 22 | 23 | Objective 24 | --------- 25 | * Official distro packages 26 | 27 | Gallium Nine is a fork of the WINE tree, without any chances to be merged upstream. The decoupling of the WINE tree makes it its own upstream. 28 | 29 | * Ease updates for the user 30 | 31 | WINE can be updated independently of Gallium Nine Standalone. Users can mix releases of both projects to their liking. Switching between staging and non-staging does not require a rebuild. 32 | 33 | Requirements 34 | ------------ 35 | * A Gallium based graphics driver (`Mesa 3D `_) 36 | * Mesa's Gallium Nine state tracker (d3dadapter9.so) 37 | 38 | Packages 39 | -------- 40 | Your distribution may provide a package, avoiding the need to compile the code yourself. The exact usage instructions may vary in this case so check your distribution for the details. The currently known packages are: 41 | 42 | * Arch Linux - releases: `wine-nine `_, snapshots: `gallium-nine-git (AUR) `_ 43 | * Gentoo Linux - `app-emulation/gallium-nine-standalone `_ 44 | * Slackware Linux - `wine-nine-standalone `_ 45 | 46 | We also provide distro independent release binaries, available as `GitHub releases `_. You can either download these yourself (see Usage_ below), or install them via `Winetricks `_. 47 | 48 | Usage 49 | ----- 50 | This part assumes that you downloaded a release binary or compiled using `release.sh` yourself. 51 | 52 | * Extract the tarball in e.g. your home directory 53 | * run the ``nine-install.sh`` script from the directory you extracted the tarball in 54 | 55 | The latter symlinks the extracted binaries to your WINE prefix and enables Gallium Nine Standalone. To target another WINE prefix than the standard ``~/.wine``, just set ``WINEPREFIX`` accordingly before you run ``nine-install.sh``. 56 | 57 | Gallium Nine Standalone comes with a GUI. 58 | 59 | For the 32bit version run ``wine ninewinecfg`` and for 64bit ``wine64 ninewinecfg``. 60 | 61 | Compiling 62 | --------- 63 | Please see `our wiki `_, which also includes distro specific help. 64 | 65 | Backends 66 | -------- 67 | The DRI3 backend is the preferred one and has the lowest CPU and memory overhead. 68 | 69 | As fallback for legacy platforms the DRI2 backend can be used, which has more CPU overhead and a bigger memory footprint. 70 | The DRI2 fallback relies on mesa's EGL which provides EGLImages. 71 | 72 | Intel Drivers 73 | ------------- 74 | Gallium Nine could be used with the new Crocus driver (included since Mesa 21.2) on older Shader model 3.0 aka feature level 9_3 compatible Intel gen4-7 graphics (GMA X3000, GMA 4500, HD 2000-5000; year 2007-2014). 75 | 76 | Use the environment variable ``MESA_LOADER_DRIVER_OVERRIDE=crocus`` to force using Crocus instead of i965. 77 | 78 | All newer Intel iGPU hardware (Broadwell+) is supported through the already working Iris driver. 79 | 80 | Debugging 81 | --------- 82 | You can use the environment variable ``D3D_BACKEND`` to force one of the supported backends: 83 | 84 | * dri3 85 | * dri2 86 | 87 | If not specified it prefers DRI3 over DRI2 if available. 88 | 89 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | 4 | SRC="$(dirname "$(readlink -f "$0")")" 5 | 6 | PKG_CONFIG_32= 7 | PKG_CONFIG_64= 8 | test -z "$WINE32_LIBDIR" && WINE32_LIBDIR=/nonexistant 9 | test -z "$WINE64_LIBDIR" && WINE64_LIBDIR=/nonexistant 10 | 11 | ID= 12 | ID_LIKE= 13 | while test -n "${1:-}"; do 14 | case "$1" in 15 | --distro) 16 | shift 17 | if test -n "${1:-}"; then 18 | ID=$1 19 | else 20 | echo "Required DISTRO missing" 21 | exit 1 22 | fi 23 | ;; 24 | *) 25 | echo "Unrecognized option: $1" 26 | exit 1 27 | ;; 28 | esac 29 | shift 30 | done 31 | test -z "$ID" && . /etc/os-release 32 | 33 | for i in $ID $ID_LIKE; do 34 | case $i in 35 | debian|ubuntu) 36 | PKG_CONFIG_32=i686-linux-gnu-pkg-config 37 | PKG_CONFIG_64=x86_64-linux-gnu-pkg-config 38 | ;; 39 | gentoo|arch|archlinux) 40 | PKG_CONFIG_32=i686-pc-linux-gnu-pkg-config 41 | PKG_CONFIG_64=x86_64-pc-linux-gnu-pkg-config 42 | ;; 43 | opensuse|suse) 44 | PKG_CONFIG_32=i586-suse-linux-gnu-pkg-config 45 | PKG_CONFIG_64=x86_64-suse-linux-gnu-pkg-config 46 | ;; 47 | fedora|rhel) 48 | PKG_CONFIG_32=i686-redhat-linux-gnu-pkg-config 49 | PKG_CONFIG_64=x86_64-redhat-linux-gnu-pkg-config 50 | ;; 51 | slackware) 52 | PKG_CONFIG_32=i586-slackware-linux-gnu-pkg-config 53 | PKG_CONFIG_64=x86_64-slackware-linux-gnu-pkg-config 54 | ;; 55 | solus) 56 | PKG_CONFIG_32=pkg-config 57 | PKG_CONFIG_64=x86_64-solus-linux-gnu-pkg-config 58 | ;; 59 | nixos) 60 | PKG_CONFIG_32=pkg-config 61 | PKG_CONFIG_64=pkg-config 62 | ;; 63 | *) 64 | continue 65 | ;; 66 | esac 67 | 68 | break 69 | done 70 | 71 | if test -z "$PKG_CONFIG_32" -o -z "$PKG_CONFIG_64"; then 72 | printf '%s\n' "unknown distro (\"$ID\", like \"$ID_LIKE\")" \ 73 | "please add support to this script and open a pull request!" 74 | exit 1 75 | fi 76 | 77 | printf '%s\n' "found $i compatible distro" 78 | 79 | sed -e "s|@PKG_CONFIG@|$PKG_CONFIG_32|" \ 80 | -e "s|@WINE32_LIBDIR@|$WINE32_LIBDIR|" \ 81 | < "$SRC"/tools/cross-wine32.in \ 82 | > "$SRC"/tools/cross-wine32 83 | 84 | sed -e "s|@PKG_CONFIG@|$PKG_CONFIG_64|" \ 85 | -e "s|@WINE64_LIBDIR@|$WINE64_LIBDIR|" \ 86 | < "$SRC"/tools/cross-wine64.in \ 87 | > "$SRC"/tools/cross-wine64 88 | 89 | exit 0 90 | -------------------------------------------------------------------------------- /common/compiler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #ifndef __COMPILER_H 4 | #define __COMPILER_H 5 | 6 | #define NINE_ATTR_PRINTF(index, check) __attribute__((format(printf, index, check))) 7 | #define NINE_ATTR_ALIGNED(alignment) __attribute__((aligned(alignment))) 8 | 9 | #endif /* __COMPILER_H */ 10 | -------------------------------------------------------------------------------- /common/debug.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "debug.h" 10 | 11 | unsigned char __nine_debug_flags = (1 << __NINE_DBCL_FIXME) | 12 | (1 << __NINE_DBCL_ERR); 13 | 14 | /* a single simple ring buffer for all threads */ 15 | #define NINE_DEBUG_BUFFERSIZE 1024 16 | 17 | static struct 18 | { 19 | char buf[NINE_DEBUG_BUFFERSIZE] NINE_ATTR_ALIGNED(16); 20 | LONG pos; 21 | } __nine_debug; 22 | 23 | static char *__nine_debug_buf(size_t len) 24 | { 25 | LONG pos_cur, pos_use, pos_new; 26 | 27 | if (len > NINE_DEBUG_BUFFERSIZE) 28 | return NULL; 29 | 30 | retry: 31 | pos_cur = __nine_debug.pos; 32 | 33 | if (pos_cur + len > NINE_DEBUG_BUFFERSIZE) 34 | pos_use = 0; 35 | else 36 | pos_use = pos_cur; 37 | 38 | pos_new = (pos_use + len + 15) & ~15; 39 | 40 | if (!__sync_bool_compare_and_swap(&__nine_debug.pos, pos_cur, pos_new)) 41 | goto retry; 42 | 43 | return __nine_debug.buf + pos_use; 44 | } 45 | 46 | const char *__nine_dbg_strdup(const char *s, size_t len) 47 | { 48 | char *buf = __nine_debug_buf(len + 1); 49 | 50 | if (!buf) 51 | return NULL; 52 | 53 | return memcpy(buf, s, len + 1); 54 | } 55 | 56 | static void nine_dbg_init() __attribute__((constructor)); 57 | static void nine_dbg_init() 58 | { 59 | char *env; 60 | struct stat st1, st2; 61 | 62 | /* check for stderr pointing to /dev/null */ 63 | if (!fstat(STDERR_FILENO, &st1) && S_ISCHR(st1.st_mode) && 64 | !stat("/dev/null", &st2) && S_ISCHR(st2.st_mode) && 65 | st1.st_rdev == st2.st_rdev) 66 | { 67 | __nine_debug_flags = 0; 68 | return; 69 | } 70 | 71 | /* new style debug mask */ 72 | env = getenv("D3D_DEBUG"); 73 | if (env) 74 | { 75 | __nine_debug_flags = strtol(env, NULL, 0); 76 | return; 77 | } 78 | 79 | /* fallback to old style WINE debug channel */ 80 | env = getenv("WINEDEBUG"); 81 | if (!env) 82 | return; 83 | 84 | /* just the most basic version, no support for classes */ 85 | if (strstr(env, "d3d9nine")) 86 | __nine_debug_flags = (1 << __NINE_DBCL_FIXME) | 87 | (1 << __NINE_DBCL_ERR) | 88 | (1 << __NINE_DBCL_WARN) | 89 | (1 << __NINE_DBCL_TRACE); 90 | } 91 | -------------------------------------------------------------------------------- /common/debug.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #ifndef __COMMON_DEBUG_H 4 | #define __COMMON_DEBUG_H 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include "compiler.h" 13 | 14 | enum __nine_debug_class 15 | { 16 | __NINE_DBCL_FIXME, 17 | __NINE_DBCL_ERR, 18 | __NINE_DBCL_WARN, 19 | __NINE_DBCL_TRACE, 20 | }; 21 | 22 | extern unsigned char __nine_debug_flags; 23 | 24 | const char *__nine_dbg_strdup(const char *s, size_t len); 25 | 26 | static inline int __nine_dbg_log(enum __nine_debug_class dbcl, const char *function, 27 | const char *format, ...) NINE_ATTR_PRINTF(3, 4); 28 | static inline int __nine_dbg_log(enum __nine_debug_class dbcl, const char *function, 29 | const char *format, ...) 30 | { 31 | char buf[1024] NINE_ATTR_ALIGNED(16); 32 | va_list args; 33 | int n; 34 | 35 | static const char *const classes[] = { "fixme", "err", "warn", "trace" }; 36 | n = sprintf(buf, "%s:d3d9nine:%s ", classes[dbcl], function); 37 | 38 | va_start(args, format); 39 | n += vsnprintf(buf + n, sizeof(buf) - n, format, args); 40 | va_end(args); 41 | 42 | return write(STDERR_FILENO, buf, n); 43 | } 44 | 45 | #define __NINE_DPRINTF(dbcl, args...) \ 46 | do { \ 47 | if (__nine_debug_flags & (1 << dbcl)) \ 48 | __nine_dbg_log(dbcl, __FUNCTION__, args); \ 49 | } while (0) 50 | 51 | #define FIXME(args...) __NINE_DPRINTF(__NINE_DBCL_FIXME, args) 52 | #define ERR(args...) __NINE_DPRINTF(__NINE_DBCL_ERR, args) 53 | #define WARN(args...) __NINE_DPRINTF(__NINE_DBCL_WARN, args) 54 | #define TRACE(args...) __NINE_DPRINTF(__NINE_DBCL_TRACE, args) 55 | 56 | static inline const char *nine_dbg_sprintf(const char *format, ...) NINE_ATTR_PRINTF(1, 2); 57 | static inline const char *nine_dbg_sprintf(const char *format, ...) 58 | { 59 | char buffer[256] NINE_ATTR_ALIGNED(16); 60 | va_list args; 61 | size_t len; 62 | 63 | va_start(args, format); 64 | len = vsnprintf(buffer, sizeof(buffer), format, args); 65 | va_end(args); 66 | return __nine_dbg_strdup(buffer, len); 67 | } 68 | 69 | /* see WINE's wine_dbgstr_an() */ 70 | static inline const char *nine_dbgstr_an( const char *str, int n ) 71 | { 72 | static const char hex[16] = "0123456789abcdef"; 73 | char buffer[256] NINE_ATTR_ALIGNED(16); 74 | char *dst = buffer; 75 | 76 | if (!str) return "(null)"; 77 | if (!((ULONG_PTR)str >> 16)) return nine_dbg_sprintf( "#%04x", LOWORD(str) ); 78 | if (IsBadStringPtrA( str, n )) return "(invalid)"; 79 | if (n == -1) for (n = 0; str[n]; n++) ; 80 | *dst++ = '"'; 81 | while (n-- > 0 && dst <= buffer + sizeof(buffer) - 9) 82 | { 83 | unsigned char c = *str++; 84 | switch (c) 85 | { 86 | case '\n': *dst++ = '\\'; *dst++ = 'n'; break; 87 | case '\r': *dst++ = '\\'; *dst++ = 'r'; break; 88 | case '\t': *dst++ = '\\'; *dst++ = 't'; break; 89 | case '"': *dst++ = '\\'; *dst++ = '"'; break; 90 | case '\\': *dst++ = '\\'; *dst++ = '\\'; break; 91 | default: 92 | if (c < ' ' || c >= 127) 93 | { 94 | *dst++ = '\\'; 95 | *dst++ = 'x'; 96 | *dst++ = hex[(c >> 4) & 0x0f]; 97 | *dst++ = hex[c & 0x0f]; 98 | } 99 | else *dst++ = c; 100 | } 101 | } 102 | *dst++ = '"'; 103 | if (n > 0) 104 | { 105 | *dst++ = '.'; 106 | *dst++ = '.'; 107 | *dst++ = '.'; 108 | } 109 | *dst = 0; 110 | return __nine_dbg_strdup( buffer, dst - buffer ); 111 | } 112 | 113 | /* see WINE's wine_dbgstr_wn() */ 114 | static inline const char *nine_dbgstr_wn( const WCHAR *str, int n ) 115 | { 116 | static const char hex[16] = "0123456789abcdef"; 117 | char buffer[256] NINE_ATTR_ALIGNED(16); 118 | char *dst = buffer; 119 | 120 | if (!str) return "(null)"; 121 | if (!((ULONG_PTR)str >> 16)) return nine_dbg_sprintf( "#%04x", LOWORD(str) ); 122 | if (IsBadStringPtrW( str, n )) return "(invalid)"; 123 | if (n == -1) for (n = 0; str[n]; n++) ; 124 | *dst++ = 'L'; 125 | *dst++ = '"'; 126 | while (n-- > 0 && dst <= buffer + sizeof(buffer) - 10) 127 | { 128 | WCHAR c = *str++; 129 | switch (c) 130 | { 131 | case '\n': *dst++ = '\\'; *dst++ = 'n'; break; 132 | case '\r': *dst++ = '\\'; *dst++ = 'r'; break; 133 | case '\t': *dst++ = '\\'; *dst++ = 't'; break; 134 | case '"': *dst++ = '\\'; *dst++ = '"'; break; 135 | case '\\': *dst++ = '\\'; *dst++ = '\\'; break; 136 | default: 137 | if (c < ' ' || c >= 127) 138 | { 139 | *dst++ = '\\'; 140 | *dst++ = hex[(c >> 12) & 0x0f]; 141 | *dst++ = hex[(c >> 8) & 0x0f]; 142 | *dst++ = hex[(c >> 4) & 0x0f]; 143 | *dst++ = hex[c & 0x0f]; 144 | } 145 | else *dst++ = c; 146 | } 147 | } 148 | *dst++ = '"'; 149 | if (n > 0) 150 | { 151 | *dst++ = '.'; 152 | *dst++ = '.'; 153 | *dst++ = '.'; 154 | } 155 | *dst = 0; 156 | return __nine_dbg_strdup( buffer, dst - buffer ); 157 | } 158 | 159 | /* see WINE's wine_dbgstr_a() */ 160 | static inline const char *nine_dbgstr_a( const char *s ) 161 | { 162 | return nine_dbgstr_an( s, -1 ); 163 | } 164 | 165 | /* see WINE's wine_dbgstr_w() */ 166 | static inline const char *nine_dbgstr_w( const WCHAR *s ) 167 | { 168 | return nine_dbgstr_wn( s, -1 ); 169 | } 170 | 171 | /* see WINE's wine_dbgstr_guid() */ 172 | static inline const char *nine_dbgstr_guid( const GUID *id ) 173 | { 174 | if (!id) return "(null)"; 175 | if (!((ULONG_PTR)id >> 16)) return nine_dbg_sprintf( "", (WORD)(ULONG_PTR)id ); 176 | return nine_dbg_sprintf( "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", 177 | (unsigned int)id->Data1, id->Data2, id->Data3, 178 | id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], 179 | id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); 180 | } 181 | 182 | /* see WINE's wine_dbgstr_point() */ 183 | static inline const char *nine_dbgstr_point( const POINT *pt ) 184 | { 185 | if (!pt) return "(null)"; 186 | return nine_dbg_sprintf( "(%d,%d)", (int)pt->x, (int)pt->y ); 187 | } 188 | 189 | /* see WINE's wine_dbgstr_rect() */ 190 | static inline const char *nine_dbgstr_rect( const RECT *rect ) 191 | { 192 | if (!rect) return "(null)"; 193 | return nine_dbg_sprintf( "(%d,%d)-(%d,%d)", (int)rect->left, (int)rect->top, 194 | (int)rect->right, (int)rect->bottom ); 195 | } 196 | 197 | #endif /* __COMMON_DEBUG_H */ 198 | -------------------------------------------------------------------------------- /common/library.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "../common/debug.h" 11 | #include "library.h" 12 | #include "registry.h" 13 | 14 | #define D3DADAPTER9 "d3dadapter9.so.1" 15 | 16 | static void *open_d3dadapter(char *paths, char **res, char **err) 17 | { 18 | char *next, *end, *p, *lasterr = NULL; 19 | void *handle = NULL; 20 | char path[MAX_PATH]; 21 | struct stat st; 22 | int len; 23 | 24 | end = paths + strlen(paths); 25 | for (p = paths; p < end; p = next + 1) 26 | { 27 | next = strchr(p, ':'); 28 | if (!next) 29 | next = end; 30 | 31 | len = next - p; 32 | snprintf(path, sizeof(path), "%.*s", len, p); 33 | 34 | if (!stat(path, &st) && S_ISDIR(st.st_mode)) 35 | strcat(path, "/" D3DADAPTER9); 36 | 37 | TRACE("Trying to load '%s'\n", path); 38 | handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW); 39 | 40 | if (handle) { 41 | if (res) 42 | *res = strdup(path); 43 | 44 | break; 45 | } 46 | 47 | free(lasterr); 48 | lasterr = strdup(dlerror()); 49 | 50 | TRACE("Failed to load '%s': %s\n", path, lasterr); 51 | } 52 | 53 | if (handle || !err) 54 | { 55 | free(lasterr); 56 | lasterr = NULL; 57 | } 58 | 59 | if (handle) 60 | TRACE("Loaded '%s'\n", path); 61 | 62 | if (err) 63 | *err = lasterr; 64 | 65 | return handle; 66 | } 67 | 68 | void *common_load_d3dadapter(char **path, char **err) 69 | { 70 | static void *handle = NULL; 71 | char *env, *reg; 72 | 73 | env = getenv("D3D_MODULE_PATH"); 74 | if (env) 75 | { 76 | handle = open_d3dadapter(env, path, err); 77 | 78 | if (!handle) 79 | ERR("Failed to load " D3DADAPTER9 " set by D3D_MODULE_PATH (%s)\n", env); 80 | 81 | return handle; 82 | } 83 | 84 | if (common_get_registry_string(reg_path_nine, reg_key_module_path, ®)) 85 | { 86 | handle = open_d3dadapter(reg, path, err); 87 | 88 | if (!handle) 89 | ERR("Failed to load " D3DADAPTER9 " set by ModulePath (%s)\n", reg); 90 | 91 | HeapFree(GetProcessHeap(), 0, reg); 92 | 93 | return handle; 94 | } 95 | 96 | #if defined(D3D9NINE_MODULEPATH) 97 | handle = open_d3dadapter(D3D9NINE_MODULEPATH, path, err); 98 | 99 | if (!handle) 100 | ERR("Failed to load " D3DADAPTER9 " set by builtin default '%s'\n", 101 | D3D9NINE_MODULEPATH); 102 | 103 | return handle; 104 | #else 105 | handle = open_d3dadapter("/usr/lib/x86_64-linux-gnu/d3d:" // 64bit debian/ubuntu 106 | "/usr/lib/i386-linux-gnu/d3d:" // 32bit debian/ubuntu 107 | "/usr/lib64/d3d:" // 64bit gentoo/suse/fedora 108 | "/usr/lib/d3d:" // 32bit suse/fedora, 64bit arch 109 | "/usr/lib32/d3d:" // 32bit arch/gentoo 110 | "/usr/lib/x86_64-linux-gnu/GL/lib/d3d:" // 64bit flatpak runtime 111 | "/usr/lib/i386-linux-gnu/GL/lib/d3d" // 32bit flatpak runtime 112 | , path, err); 113 | 114 | if (!handle) 115 | ERR(D3DADAPTER9 " was not found on your system.\n" 116 | "Setting the envvar D3D_MODULE_PATH or " 117 | "regkey Software\\Wine\\Direct3DNine\\ModulePath is required\n"); 118 | 119 | return handle; 120 | #endif 121 | } 122 | -------------------------------------------------------------------------------- /common/library.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #ifndef __COMMON_LIBRARY_H 4 | #define __COMMON_LIBRARY_H 5 | 6 | void *common_load_d3dadapter(char **path, char **err); 7 | 8 | #endif /* __COMMON_LIBRARY_H */ 9 | -------------------------------------------------------------------------------- /common/meson.build: -------------------------------------------------------------------------------- 1 | libd3d9common = static_library( 2 | 'd3d9common', 3 | [ 4 | 'debug.c', 5 | 'library.c', 6 | 'registry.c', 7 | ], 8 | install : false, 9 | ) 10 | -------------------------------------------------------------------------------- /common/registry.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | 5 | #include "../common/debug.h" 6 | #include "registry.h" 7 | 8 | const char * const reg_path_dll_overrides = "Software\\Wine\\DllOverrides"; 9 | const char * const reg_path_dll_redirects = "Software\\Wine\\DllRedirects"; 10 | const char * const reg_key_d3d9 = "d3d9"; 11 | const char * const reg_path_nine = "Software\\Wine\\Direct3DNine"; 12 | const char * const reg_key_module_path = "ModulePath"; 13 | const char * const reg_value_override = "native"; 14 | 15 | BOOL common_get_registry_string(LPCSTR path, LPCSTR name, LPSTR *value) 16 | { 17 | HKEY regkey; 18 | DWORD type; 19 | DWORD size = 0; 20 | 21 | TRACE("Getting string key '%s' at 'HKCU\\%s'\n", name, path); 22 | 23 | if (RegOpenKeyA(HKEY_CURRENT_USER, path, ®key) != ERROR_SUCCESS) 24 | { 25 | TRACE("Failed to open path 'HKCU\\%s'\n", path); 26 | return FALSE; 27 | } 28 | 29 | if (RegQueryValueExA(regkey, name, 0, &type, NULL, &size) != ERROR_SUCCESS) 30 | { 31 | TRACE("Failed to query key '%s' at 'HKCU\\%s'\n", name, path); 32 | RegCloseKey(regkey); 33 | return FALSE; 34 | } 35 | 36 | if (type != REG_SZ) 37 | { 38 | TRACE("Key '%s' at 'HKCU\\%s' is not a string\n", name, path); 39 | RegCloseKey(regkey); 40 | return FALSE; 41 | } 42 | 43 | *value = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + 1); 44 | if (!(*value)) 45 | { 46 | RegCloseKey(regkey); 47 | return FALSE; 48 | } 49 | 50 | if (RegQueryValueExA(regkey, name, 0, &type, (LPBYTE)*value, &size) != ERROR_SUCCESS) 51 | { 52 | TRACE("Failed to read value of key '%s' at 'HKCU\\%s'\n", name, path); 53 | HeapFree(GetProcessHeap(), 0, *value); 54 | RegCloseKey(regkey); 55 | return FALSE; 56 | } 57 | 58 | RegCloseKey(regkey); 59 | 60 | TRACE("Value is '%s'\n", *value); 61 | 62 | return TRUE; 63 | } 64 | 65 | BOOL common_set_registry_string(LPCSTR path, LPCSTR name, LPCSTR value) 66 | { 67 | HKEY regkey; 68 | 69 | TRACE("Setting key '%s' at 'HKCU\\%s' to '%s'\n", name, path, value); 70 | 71 | if (RegCreateKeyA(HKEY_CURRENT_USER, path, ®key) != ERROR_SUCCESS) 72 | { 73 | TRACE("Failed to open path 'HKCU\\%s'\n", path); 74 | return FALSE; 75 | } 76 | 77 | if (RegSetValueExA(regkey, name, 0, REG_SZ, (LPBYTE)value, strlen(value)) != ERROR_SUCCESS) 78 | { 79 | TRACE("Failed to write key '%s' at 'HKCU\\%s'\n", name, path); 80 | RegCloseKey(regkey); 81 | return FALSE; 82 | } 83 | 84 | RegCloseKey(regkey); 85 | 86 | return TRUE; 87 | } 88 | 89 | BOOL common_del_registry_key(LPCSTR path, LPCSTR name) 90 | { 91 | HKEY regkey; 92 | LSTATUS rc; 93 | 94 | TRACE("Deleting key '%s' at 'HKCU\\%s'\n", name, path); 95 | 96 | rc = RegOpenKeyA(HKEY_CURRENT_USER, path, ®key); 97 | if (rc == ERROR_FILE_NOT_FOUND) 98 | return TRUE; 99 | 100 | if (rc != ERROR_SUCCESS) 101 | { 102 | TRACE("Failed to open path 'HKCU\\%s'\n", path); 103 | return FALSE; 104 | } 105 | 106 | rc = RegDeleteValueA(regkey, name); 107 | if (rc != ERROR_FILE_NOT_FOUND && rc != ERROR_SUCCESS) 108 | { 109 | TRACE("Failed to delete key '%s' at 'HKCU\\%s'\n", name, path); 110 | RegCloseKey(regkey); 111 | return FALSE; 112 | } 113 | 114 | RegCloseKey(regkey); 115 | 116 | return TRUE; 117 | } 118 | -------------------------------------------------------------------------------- /common/registry.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #ifndef __COMMON_REGISTRY_H 4 | #define __COMMON_REGISTRY_H 5 | 6 | #include 7 | 8 | extern const char * const reg_path_dll_overrides; 9 | extern const char * const reg_path_dll_redirects; 10 | extern const char * const reg_key_d3d9; 11 | extern const char * const reg_path_nine; 12 | extern const char * const reg_key_module_path; 13 | extern const char * const reg_value_override; 14 | 15 | BOOL common_get_registry_string(LPCSTR path, LPCSTR name, LPSTR *value); 16 | BOOL common_set_registry_string(LPCSTR path, LPCSTR name, LPCSTR value); 17 | BOOL common_del_registry_key(LPCSTR path, LPCSTR name); 18 | 19 | #endif /* __COMMON_REGISTRY_H */ 20 | -------------------------------------------------------------------------------- /d3d9-nine/backend.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Wine D3D9 DRI backend interface 4 | * 5 | * Copyright 2019 Patrick Rudolph 6 | * Copyright 2014-2015 Axel Davy 7 | * Copyright 2015-2019 Patrick Rudolph 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "../common/debug.h" 15 | #include "../common/registry.h" 16 | #include "backend.h" 17 | #include "xcb_present.h" 18 | 19 | extern const struct dri_backend_funcs dri3_funcs; 20 | #ifdef D3D9NINE_DRI2 21 | extern const struct dri_backend_funcs dri2_funcs; 22 | #endif 23 | 24 | static const struct dri_backend_funcs *backends[] = { 25 | &dri3_funcs, 26 | #ifdef D3D9NINE_DRI2 27 | &dri2_funcs, 28 | #endif 29 | }; 30 | 31 | static const int backends_count = sizeof(backends) / sizeof(*backends); 32 | 33 | static const char *backend_getenv() 34 | { 35 | const char *env = getenv("D3D_BACKEND"); 36 | static BOOL first = TRUE; 37 | 38 | if (env && first) 39 | { 40 | first = FALSE; 41 | WARN("Backend overwritten by D3D_BACKEND: %s\n", env); 42 | } 43 | 44 | return env; 45 | } 46 | 47 | BOOL backend_probe(Display *dpy) 48 | { 49 | int i; 50 | const char *env; 51 | struct dri_backend_priv *p; 52 | 53 | TRACE("dpy=%p\n", dpy); 54 | 55 | if (!dpy) 56 | return FALSE; 57 | 58 | env = backend_getenv(); 59 | 60 | for (i = 0; i < backends_count; ++i) 61 | { 62 | if (env && strcmp(env, backends[i]->name)) 63 | continue; 64 | 65 | if (!backends[i]->probe(dpy)) 66 | { 67 | TRACE("Error probing backend %s\n", backends[i]->name); 68 | continue; 69 | } 70 | 71 | if (!backends[i]->create(dpy, DefaultScreen(dpy), &p)) 72 | { 73 | TRACE("Error creating backend %s\n", backends[i]->name); 74 | continue; 75 | } 76 | 77 | if (!backends[i]->init(p)) 78 | { 79 | TRACE("Error initializing backend %s\n", backends[i]->name); 80 | backends[i]->destroy(p); 81 | continue; 82 | } 83 | 84 | backends[i]->destroy(p); 85 | 86 | if (i != 0) 87 | fprintf(stderr, "\033[1;31mDRI3 backend not active (slower performance)\033[0m\n"); 88 | 89 | return TRUE; 90 | } 91 | 92 | return FALSE; 93 | } 94 | 95 | struct dri_backend *backend_create(Display *dpy, int screen) 96 | { 97 | struct dri_backend *dri_backend; 98 | int i; 99 | const char *env; 100 | 101 | TRACE("dpy=%p screen=%d\n", dpy, screen); 102 | 103 | dri_backend = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dri_backend)); 104 | if (!dri_backend) 105 | return NULL; 106 | 107 | dri_backend->funcs = NULL; 108 | dri_backend->priv = NULL; 109 | 110 | env = backend_getenv(); 111 | 112 | for (i = 0; i < backends_count; ++i) 113 | { 114 | if (env && strcmp(env, backends[i]->name)) 115 | continue; 116 | 117 | if (!backends[i]->probe(dpy)) 118 | continue; 119 | 120 | if (backends[i]->create(dpy, screen, &dri_backend->priv)) 121 | { 122 | TRACE("Active backend: %s\n", backends[i]->name); 123 | 124 | dri_backend->funcs = backends[i]; 125 | return dri_backend; 126 | } 127 | 128 | ERR("Error creating backend %s\n", backends[i]->name); 129 | } 130 | 131 | HeapFree(GetProcessHeap(), 0, dri_backend); 132 | return NULL; 133 | } 134 | 135 | void backend_destroy(struct dri_backend *dri_backend) 136 | { 137 | TRACE("dri_backend=%p\n", dri_backend); 138 | 139 | if (!dri_backend) 140 | return; 141 | 142 | if (dri_backend->priv) 143 | dri_backend->funcs->destroy(dri_backend->priv); 144 | 145 | HeapFree(GetProcessHeap(), 0, dri_backend); 146 | } 147 | -------------------------------------------------------------------------------- /d3d9-nine/backend.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Wine D3D9 DRI backend interface 4 | * 5 | * Copyright 2019 Patrick Rudolph 6 | */ 7 | 8 | #ifndef __NINE_BACKEND_H 9 | #define __NINE_BACKEND_H 10 | 11 | #include 12 | 13 | struct dri_backend_priv; 14 | struct buffer_priv; 15 | struct PRESENTpriv; 16 | struct PRESENTPixmapPriv; 17 | typedef struct PRESENTPriv PRESENTpriv; 18 | typedef struct PRESENTPixmapPriv PRESENTPixmapPriv; 19 | 20 | struct D3DWindowBuffer 21 | { 22 | PRESENTPixmapPriv *present_pixmap_priv; 23 | struct buffer_priv *priv; /* backend private data */ 24 | }; 25 | 26 | struct dri_backend_funcs { 27 | const char * const name; 28 | 29 | BOOL (*probe)(Display *dpy); 30 | 31 | BOOL (*create)(Display *dpy, int screen, struct dri_backend_priv **priv); 32 | void (*destroy)(struct dri_backend_priv *priv); 33 | 34 | BOOL (*init)(struct dri_backend_priv *priv); 35 | void (*deinit)(struct dri_backend_priv *priv); 36 | int (*get_fd)(struct dri_backend_priv *priv); 37 | 38 | BOOL (*window_buffer_from_dmabuf)(struct dri_backend_priv *priv, 39 | PRESENTpriv *present_priv, int fd, int width, int height, 40 | int stride, int depth, int bpp, struct D3DWindowBuffer **out); 41 | BOOL (*copy_front)(PRESENTPixmapPriv *present_pixmap_priv); 42 | 43 | BOOL (*present_pixmap)(struct dri_backend_priv *priv, struct buffer_priv *buffer_priv); 44 | void (*destroy_pixmap)(struct dri_backend_priv *priv, struct buffer_priv *buffer_priv); 45 | }; 46 | 47 | struct dri_backend { 48 | const struct dri_backend_funcs *funcs; 49 | struct dri_backend_priv *priv; /* backend private data */ 50 | }; 51 | 52 | BOOL backend_probe(Display *dpy); 53 | 54 | struct dri_backend *backend_create(Display *dpy, int screen); 55 | void backend_destroy(struct dri_backend *dri_backend); 56 | 57 | #endif /* __NINE_BACKEND_H */ 58 | -------------------------------------------------------------------------------- /d3d9-nine/d3d9.spec: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | @ stdcall Direct3DShaderValidatorCreate9() 3 | @ stub PSGPError 4 | @ stub PSGPSampleTexture 5 | @ stdcall D3DPERF_BeginEvent(long wstr) 6 | @ stdcall D3DPERF_EndEvent() 7 | @ stdcall D3DPERF_GetStatus() 8 | @ stdcall D3DPERF_QueryRepeatFrame() 9 | @ stdcall D3DPERF_SetMarker(long wstr) 10 | @ stdcall D3DPERF_SetOptions(long) 11 | @ stdcall D3DPERF_SetRegion(long wstr) 12 | @ stub DebugSetLevel 13 | @ stdcall DebugSetMute() 14 | @ stdcall Direct3DCreate9(long) 15 | @ stdcall Direct3DCreate9Ex(long ptr) 16 | -------------------------------------------------------------------------------- /d3d9-nine/d3d9_main.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Direct3D 9 4 | * 5 | * Copyright 2002-2003 Jason Edmeades 6 | * Copyright 2002-2003 Raphael Junqueira 7 | * Copyright 2005 Oliver Stieber 8 | * Copyright 2015 Patrick Rudolph 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | #include "../common/debug.h" 15 | #include "d3dadapter9.h" 16 | #include "wndproc.h" 17 | #include "shader_validator.h" 18 | 19 | static int D3DPERF_event_level = 0; 20 | static Display *gdi_display; 21 | 22 | void WINAPI DebugSetMute(void) 23 | { 24 | /* nothing to do */ 25 | } 26 | 27 | IDirect3D9 * WINAPI DECLSPEC_HOTPATCH Direct3DCreate9(UINT sdk_version) 28 | { 29 | IDirect3D9 *native; 30 | TRACE("sdk_version %#x.\n", sdk_version); 31 | 32 | if (SUCCEEDED(d3dadapter9_new(gdi_display, FALSE, (IDirect3D9Ex **)&native))) 33 | return native; 34 | 35 | return NULL; 36 | } 37 | 38 | HRESULT WINAPI DECLSPEC_HOTPATCH Direct3DCreate9Ex(UINT sdk_version, IDirect3D9Ex **d3d9ex) 39 | { 40 | TRACE("sdk_version %#x, d3d9ex %p.\n", sdk_version, d3d9ex); 41 | 42 | return d3dadapter9_new(gdi_display, TRUE, d3d9ex); 43 | } 44 | 45 | /******************************************************************* 46 | * Direct3DShaderValidatorCreate9 (D3D9.@) 47 | * 48 | * No documentation available for this function. 49 | * SDK only says it is internal and shouldn't be used. 50 | */ 51 | 52 | void* WINAPI Direct3DShaderValidatorCreate9(void) 53 | { 54 | IDirect3DShaderValidator9Impl* object = 55 | HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 56 | sizeof(IDirect3DShaderValidator9Impl)); 57 | 58 | object->lpVtbl = &IDirect3DShaderValidator9Vtbl; 59 | object->ref = 1; 60 | 61 | TRACE("Returning interface %p\n", object); 62 | return (void*) object; 63 | } 64 | 65 | /******************************************************************* 66 | * DllMain 67 | */ 68 | BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved) 69 | { 70 | switch (reason) 71 | { 72 | case DLL_PROCESS_ATTACH: 73 | if (!(gdi_display = XOpenDisplay( NULL ))) 74 | { 75 | ERR("Failed to open display\n"); 76 | return FALSE; 77 | } 78 | 79 | fcntl( ConnectionNumber(gdi_display), F_SETFD, 1 ); /* set close on exec flag */ 80 | 81 | nine_dll_init(inst); 82 | break; 83 | case DLL_PROCESS_DETACH: 84 | if (!reserved) 85 | return nine_dll_destroy(inst); 86 | break; 87 | } 88 | 89 | return TRUE; 90 | } 91 | 92 | /*********************************************************************** 93 | * D3DPERF_BeginEvent (D3D9.@) 94 | */ 95 | int WINAPI D3DPERF_BeginEvent(D3DCOLOR color, const WCHAR *name) 96 | { 97 | TRACE("color 0x%08x, name %s.\n", (UINT)color, nine_dbgstr_w(name)); 98 | 99 | return D3DPERF_event_level++; 100 | } 101 | 102 | /*********************************************************************** 103 | * D3DPERF_EndEvent (D3D9.@) 104 | */ 105 | int WINAPI D3DPERF_EndEvent(void) 106 | { 107 | TRACE("(void) : stub\n"); 108 | 109 | return --D3DPERF_event_level; 110 | } 111 | 112 | /*********************************************************************** 113 | * D3DPERF_GetStatus (D3D9.@) 114 | */ 115 | DWORD WINAPI D3DPERF_GetStatus(void) 116 | { 117 | FIXME("(void) : stub\n"); 118 | 119 | return 0; 120 | } 121 | 122 | /*********************************************************************** 123 | * D3DPERF_SetOptions (D3D9.@) 124 | * 125 | */ 126 | void WINAPI D3DPERF_SetOptions(DWORD options) 127 | { 128 | FIXME("(%#x) : stub\n", (UINT)options); 129 | } 130 | 131 | /*********************************************************************** 132 | * D3DPERF_QueryRepeatFrame (D3D9.@) 133 | */ 134 | BOOL WINAPI D3DPERF_QueryRepeatFrame(void) 135 | { 136 | FIXME("(void) : stub\n"); 137 | 138 | return FALSE; 139 | } 140 | 141 | /*********************************************************************** 142 | * D3DPERF_SetMarker (D3D9.@) 143 | */ 144 | void WINAPI D3DPERF_SetMarker(D3DCOLOR color, const WCHAR *name) 145 | { 146 | FIXME("color 0x%08x, name %s stub!\n", (UINT)color, nine_dbgstr_w(name)); 147 | } 148 | 149 | /*********************************************************************** 150 | * D3DPERF_SetRegion (D3D9.@) 151 | */ 152 | void WINAPI D3DPERF_SetRegion(D3DCOLOR color, const WCHAR *name) 153 | { 154 | FIXME("color 0x%08x, name %s stub!\n", (UINT)color, nine_dbgstr_w(name)); 155 | } 156 | -------------------------------------------------------------------------------- /d3d9-nine/d3dadapter9.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Wine IDirect3D9 interface using ID3DAdapter9 4 | * 5 | * Copyright 2013 Joakim Sindholt 6 | * Christoph Bumiller 7 | * Copyright 2014 David Heidelberger 8 | * Copyright 2014-2015 Axel Davy 9 | * Copyright 2015 Nick Sarnie 10 | * Patrick Rudolph 11 | */ 12 | 13 | #include 14 | 15 | #include "../common/debug.h" 16 | #include "present.h" 17 | #include "device_wrap.h" 18 | #include "backend.h" 19 | 20 | /* this represents a snapshot taken at the moment of creation */ 21 | struct output 22 | { 23 | D3DDISPLAYROTATION rotation; /* current rotation */ 24 | D3DDISPLAYMODEEX *modes; 25 | unsigned nmodes; 26 | unsigned nmodesalloc; 27 | 28 | HMONITOR monitor; 29 | }; 30 | 31 | struct adapter_group 32 | { 33 | struct output *outputs; 34 | unsigned noutputs; 35 | unsigned noutputsalloc; 36 | 37 | /* override driver provided DeviceName with this to homogenize device names 38 | * with wine */ 39 | WCHAR devname[32]; 40 | 41 | /* driver stuff */ 42 | ID3DAdapter9 *adapter; 43 | /* DRI backend */ 44 | struct dri_backend *dri_backend; 45 | }; 46 | 47 | struct adapter_map 48 | { 49 | unsigned group; 50 | unsigned master; 51 | }; 52 | 53 | struct d3dadapter9 54 | { 55 | /* COM vtable */ 56 | void *vtable; 57 | /* IUnknown reference count */ 58 | LONG refs; 59 | 60 | /* adapter groups and mappings */ 61 | struct adapter_group *groups; 62 | struct adapter_map *map; 63 | unsigned nadapters; 64 | unsigned ngroups; 65 | unsigned ngroupsalloc; 66 | 67 | /* true if it implements IDirect3D9Ex */ 68 | boolean ex; 69 | Display *gdi_display; 70 | }; 71 | 72 | /* convenience wrapper for calls into ID3D9Adapter */ 73 | #define ADAPTER_GROUP \ 74 | This->groups[This->map[Adapter].group] 75 | 76 | #define ADAPTER_PROC(name, ...) \ 77 | ID3DAdapter9_##name(ADAPTER_GROUP.adapter, ## __VA_ARGS__) 78 | 79 | #define ADAPTER_OUTPUT \ 80 | ADAPTER_GROUP.outputs[Adapter-This->map[Adapter].master] 81 | 82 | static int get_current_mode(struct d3dadapter9 *This, UINT Adapter) 83 | { 84 | DEVMODEW m; 85 | D3DSCANLINEORDERING slo; 86 | D3DFORMAT f; 87 | int i; 88 | 89 | memset(&m, 0, sizeof(m)); 90 | m.dmSize = sizeof(m); 91 | EnumDisplaySettingsExW(ADAPTER_GROUP.devname, ENUM_CURRENT_SETTINGS, &m, 0); 92 | 93 | switch (m.dmBitsPerPel) 94 | { 95 | case 32: 96 | f = D3DFMT_X8R8G8B8; 97 | break; 98 | case 24: 99 | f = D3DFMT_R8G8B8; 100 | break; 101 | case 16: 102 | f = D3DFMT_R5G6B5; 103 | break; 104 | default: 105 | return -1; 106 | } 107 | 108 | if (m.dmDisplayFlags & DM_INTERLACED) 109 | slo = D3DSCANLINEORDERING_INTERLACED; 110 | else 111 | slo = D3DSCANLINEORDERING_PROGRESSIVE; 112 | 113 | for (i = 0; i < ADAPTER_OUTPUT.nmodes; i++) 114 | { 115 | if (ADAPTER_OUTPUT.modes[i].Width != m.dmPelsWidth) 116 | continue; 117 | 118 | if (ADAPTER_OUTPUT.modes[i].Height != m.dmPelsHeight) 119 | continue; 120 | 121 | if (ADAPTER_OUTPUT.modes[i].RefreshRate != m.dmDisplayFrequency) 122 | continue; 123 | 124 | if (ADAPTER_OUTPUT.modes[i].Format != f) 125 | continue; 126 | 127 | if (ADAPTER_OUTPUT.modes[i].ScanLineOrdering != slo) 128 | continue; 129 | 130 | TRACE("current mode %d (%ux%ux%u)\n", i, 131 | (UINT)m.dmPelsWidth, (UINT)m.dmPelsHeight, (UINT)m.dmBitsPerPel); 132 | 133 | return i; 134 | } 135 | 136 | return -1; 137 | } 138 | 139 | static HRESULT WINAPI d3dadapter9_CheckDeviceFormat(struct d3dadapter9 *This, 140 | UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, 141 | DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat); 142 | 143 | static ULONG WINAPI d3dadapter9_AddRef(struct d3dadapter9 *This) 144 | { 145 | ULONG refs = InterlockedIncrement(&This->refs); 146 | TRACE("%p increasing refcount to %u.\n", This, (UINT)refs); 147 | return refs; 148 | } 149 | 150 | static ULONG WINAPI d3dadapter9_Release(struct d3dadapter9 *This) 151 | { 152 | ULONG refs = InterlockedDecrement(&This->refs); 153 | TRACE("%p decreasing refcount to %u.\n", This, (UINT)refs); 154 | if (refs == 0) 155 | { 156 | /* dtor */ 157 | if (This->map) 158 | { 159 | HeapFree(GetProcessHeap(), 0, This->map); 160 | } 161 | 162 | if (This->groups) 163 | { 164 | int i, j; 165 | for (i = 0; i < This->ngroups; ++i) 166 | { 167 | if (This->groups[i].outputs) 168 | { 169 | for (j = 0; j < This->groups[i].noutputs; ++j) 170 | { 171 | if (This->groups[i].outputs[j].modes) 172 | { 173 | HeapFree(GetProcessHeap(), 0, 174 | This->groups[i].outputs[j].modes); 175 | } 176 | } 177 | HeapFree(GetProcessHeap(), 0, This->groups[i].outputs); 178 | } 179 | 180 | if (This->groups[i].adapter) 181 | ID3DAdapter9_Release(This->groups[i].adapter); 182 | 183 | backend_destroy(This->groups[i].dri_backend); 184 | } 185 | HeapFree(GetProcessHeap(), 0, This->groups); 186 | } 187 | 188 | HeapFree(GetProcessHeap(), 0, This); 189 | } 190 | return refs; 191 | } 192 | 193 | static HRESULT WINAPI d3dadapter9_QueryInterface(struct d3dadapter9 *This, 194 | REFIID riid, void **ppvObject) 195 | { 196 | if (!ppvObject) 197 | return E_POINTER; 198 | 199 | if ((IsEqualGUID(&IID_IDirect3D9Ex, riid) && This->ex) || 200 | IsEqualGUID(&IID_IDirect3D9, riid) || 201 | IsEqualGUID(&IID_IUnknown, riid)) 202 | { 203 | *ppvObject = This; 204 | d3dadapter9_AddRef(This); 205 | return S_OK; 206 | } 207 | 208 | WARN("%s not implemented, returning E_NOINTERFACE.\n", nine_dbgstr_guid(riid)); 209 | *ppvObject = NULL; 210 | 211 | return E_NOINTERFACE; 212 | } 213 | 214 | static HRESULT WINAPI d3dadapter9_RegisterSoftwareDevice(struct d3dadapter9 *This, 215 | void *pInitializeFunction) 216 | { 217 | FIXME("(%p, %p), stub!\n", This, pInitializeFunction); 218 | return D3DERR_INVALIDCALL; 219 | } 220 | 221 | static UINT WINAPI d3dadapter9_GetAdapterCount(struct d3dadapter9 *This) 222 | { 223 | return This->nadapters; 224 | } 225 | 226 | static HRESULT WINAPI d3dadapter9_GetAdapterIdentifier(struct d3dadapter9 *This, 227 | UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9 *pIdentifier) 228 | { 229 | HRESULT hr; 230 | HKEY regkey; 231 | 232 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 233 | return D3DERR_INVALIDCALL; 234 | 235 | hr = ADAPTER_PROC(GetAdapterIdentifier, Flags, pIdentifier); 236 | if (SUCCEEDED(hr)) 237 | { 238 | /* Override the driver provided DeviceName with what Wine provided */ 239 | ZeroMemory(pIdentifier->DeviceName, sizeof(pIdentifier->DeviceName)); 240 | if (!WideCharToMultiByte(CP_ACP, 0, ADAPTER_GROUP.devname, -1, 241 | pIdentifier->DeviceName, sizeof(pIdentifier->DeviceName), NULL, NULL)) 242 | return D3DERR_INVALIDCALL; 243 | 244 | TRACE("DeviceName overriden: %s\n", pIdentifier->DeviceName); 245 | 246 | /* Override PCI IDs when wined3d registry keys are set */ 247 | if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Direct3DNine", ®key)) 248 | { 249 | DWORD type, data; 250 | DWORD size = sizeof(DWORD); 251 | 252 | if (!RegQueryValueExA(regkey, "VideoPciDeviceID", 0, &type, (BYTE *)&data, &size) && 253 | (type == REG_DWORD) && (size == sizeof(DWORD))) 254 | pIdentifier->DeviceId = data; 255 | if (size != sizeof(DWORD)) 256 | { 257 | ERR("VideoPciDeviceID is not a DWORD\n"); 258 | size = sizeof(DWORD); 259 | } 260 | if (!RegQueryValueExA(regkey, "VideoPciVendorID", 0, &type, (BYTE *)&data, &size) && 261 | (type == REG_DWORD) && (size == sizeof(DWORD))) 262 | pIdentifier->VendorId = data; 263 | if (size != sizeof(DWORD)) 264 | ERR("VideoPciVendorID is not a DWORD\n"); 265 | RegCloseKey(regkey); 266 | 267 | TRACE("DeviceId:VendorId overridden: %04X:%04X\n", 268 | (UINT)pIdentifier->DeviceId, (UINT)pIdentifier->VendorId); 269 | } 270 | } 271 | return hr; 272 | } 273 | 274 | static UINT WINAPI d3dadapter9_GetAdapterModeCount(struct d3dadapter9 *This, 275 | UINT Adapter, D3DFORMAT Format) 276 | { 277 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 278 | return D3DERR_INVALIDCALL; 279 | 280 | if (FAILED(d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL, 281 | Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, Format))) 282 | { 283 | WARN("DeviceFormat not available.\n"); 284 | return 0; 285 | } 286 | 287 | TRACE("%u modes.\n", ADAPTER_OUTPUT.nmodes); 288 | return ADAPTER_OUTPUT.nmodes; 289 | } 290 | 291 | static HRESULT WINAPI d3dadapter9_EnumAdapterModes(struct d3dadapter9 *This, 292 | UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE *pMode) 293 | { 294 | HRESULT hr; 295 | 296 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 297 | return D3DERR_INVALIDCALL; 298 | 299 | hr = d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL, 300 | Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, Format); 301 | 302 | if (FAILED(hr)) 303 | { 304 | TRACE("DeviceFormat not available.\n"); 305 | return hr; 306 | } 307 | 308 | if (Mode >= ADAPTER_OUTPUT.nmodes) 309 | { 310 | WARN("Mode %u does not exist.\n", Mode); 311 | return D3DERR_INVALIDCALL; 312 | } 313 | 314 | pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width; 315 | pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height; 316 | pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate; 317 | pMode->Format = Format; 318 | 319 | return D3D_OK; 320 | } 321 | 322 | static HRESULT WINAPI d3dadapter9_GetAdapterDisplayMode(struct d3dadapter9 *This, 323 | UINT Adapter, D3DDISPLAYMODE *pMode) 324 | { 325 | int Mode; 326 | 327 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 328 | return D3DERR_INVALIDCALL; 329 | 330 | Mode = get_current_mode(This, Adapter); 331 | if (Mode < 0) 332 | return D3DERR_INVALIDCALL; 333 | 334 | pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width; 335 | pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height; 336 | pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate; 337 | pMode->Format = ADAPTER_OUTPUT.modes[Mode].Format; 338 | 339 | return D3D_OK; 340 | } 341 | 342 | static HRESULT WINAPI d3dadapter9_CheckDeviceType(struct d3dadapter9 *This, 343 | UINT Adapter, D3DDEVTYPE DevType, D3DFORMAT AdapterFormat, 344 | D3DFORMAT BackBufferFormat, BOOL bWindowed) 345 | { 346 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 347 | return D3DERR_INVALIDCALL; 348 | 349 | return ADAPTER_PROC(CheckDeviceType, 350 | DevType, AdapterFormat, BackBufferFormat, bWindowed); 351 | } 352 | 353 | static HRESULT WINAPI d3dadapter9_CheckDeviceFormat(struct d3dadapter9 *This, 354 | UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, 355 | DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) 356 | { 357 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 358 | return D3DERR_INVALIDCALL; 359 | 360 | return ADAPTER_PROC(CheckDeviceFormat, 361 | DeviceType, AdapterFormat, Usage, RType, CheckFormat); 362 | } 363 | 364 | static HRESULT WINAPI d3dadapter9_CheckDeviceMultiSampleType(struct d3dadapter9 *This, 365 | UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, 366 | BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD *pQualityLevels) 367 | { 368 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 369 | return D3DERR_INVALIDCALL; 370 | 371 | return ADAPTER_PROC(CheckDeviceMultiSampleType, DeviceType, SurfaceFormat, 372 | Windowed, MultiSampleType, pQualityLevels); 373 | } 374 | 375 | static HRESULT WINAPI d3dadapter9_CheckDepthStencilMatch(struct d3dadapter9 *This, 376 | UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, 377 | D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) 378 | { 379 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 380 | return D3DERR_INVALIDCALL; 381 | 382 | return ADAPTER_PROC(CheckDepthStencilMatch, DeviceType, AdapterFormat, 383 | RenderTargetFormat, DepthStencilFormat); 384 | } 385 | 386 | static HRESULT WINAPI d3dadapter9_CheckDeviceFormatConversion(struct d3dadapter9 *This, 387 | UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) 388 | { 389 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 390 | return D3DERR_INVALIDCALL; 391 | 392 | return ADAPTER_PROC(CheckDeviceFormatConversion, 393 | DeviceType, SourceFormat, TargetFormat); 394 | } 395 | 396 | static HRESULT WINAPI d3dadapter9_GetDeviceCaps(struct d3dadapter9 *This, 397 | UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9 *pCaps) 398 | { 399 | HRESULT hr; 400 | 401 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 402 | return D3DERR_INVALIDCALL; 403 | 404 | hr = ADAPTER_PROC(GetDeviceCaps, DeviceType, pCaps); 405 | if (FAILED(hr)) 406 | return hr; 407 | 408 | pCaps->MasterAdapterOrdinal = This->map[Adapter].master; 409 | pCaps->AdapterOrdinalInGroup = Adapter-This->map[Adapter].master; 410 | pCaps->NumberOfAdaptersInGroup = ADAPTER_GROUP.noutputs; 411 | 412 | return hr; 413 | } 414 | 415 | static HMONITOR WINAPI d3dadapter9_GetAdapterMonitor(struct d3dadapter9 *This, 416 | UINT Adapter) 417 | { 418 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 419 | return (HMONITOR)0; 420 | 421 | return (HMONITOR)ADAPTER_OUTPUT.monitor; 422 | } 423 | 424 | static HRESULT WINAPI DECLSPEC_HOTPATCH d3dadapter9_CreateDeviceEx(struct d3dadapter9 *This, 425 | UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, 426 | D3DPRESENT_PARAMETERS *pPresentationParameters, 427 | D3DDISPLAYMODEEX *pFullscreenDisplayMode, 428 | IDirect3DDevice9Ex **ppReturnedDeviceInterface); 429 | 430 | static HRESULT WINAPI DECLSPEC_HOTPATCH d3dadapter9_CreateDevice(struct d3dadapter9 *This, 431 | UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, 432 | D3DPRESENT_PARAMETERS *pPresentationParameters, 433 | IDirect3DDevice9 **ppReturnedDeviceInterface) 434 | { 435 | HRESULT hr; 436 | hr = d3dadapter9_CreateDeviceEx(This, Adapter, DeviceType, hFocusWindow, 437 | BehaviorFlags, pPresentationParameters, NULL, 438 | (IDirect3DDevice9Ex **)ppReturnedDeviceInterface); 439 | if (FAILED(hr)) 440 | return hr; 441 | 442 | return D3D_OK; 443 | } 444 | 445 | static UINT WINAPI d3dadapter9_GetAdapterModeCountEx(struct d3dadapter9 *This, 446 | UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter) 447 | { 448 | FIXME("(%p, %u, %p), half stub!\n", This, Adapter, pFilter); 449 | return d3dadapter9_GetAdapterModeCount(This, Adapter, pFilter->Format); 450 | } 451 | 452 | static HRESULT WINAPI d3dadapter9_EnumAdapterModesEx(struct d3dadapter9 *This, 453 | UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter, UINT Mode, 454 | D3DDISPLAYMODEEX *pMode) 455 | { 456 | HRESULT hr; 457 | 458 | FIXME("(%p, %u, %p, %u, %p), half stub!\n", This, Adapter, pFilter, Mode, pMode); 459 | 460 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 461 | return D3DERR_INVALIDCALL; 462 | 463 | hr = d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL, 464 | pFilter->Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, pFilter->Format); 465 | 466 | if (FAILED(hr)) 467 | { 468 | TRACE("DeviceFormat not available.\n"); 469 | return hr; 470 | } 471 | 472 | if (Mode >= ADAPTER_OUTPUT.nmodes) 473 | { 474 | WARN("Mode %u does not exist.\n", Mode); 475 | return D3DERR_INVALIDCALL; 476 | } 477 | 478 | pMode->Size = ADAPTER_OUTPUT.modes[Mode].Size; 479 | pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width; 480 | pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height; 481 | pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate; 482 | pMode->Format = ADAPTER_OUTPUT.modes[Mode].Format; 483 | pMode->ScanLineOrdering = ADAPTER_OUTPUT.modes[Mode].ScanLineOrdering; 484 | 485 | return D3D_OK; 486 | } 487 | 488 | static HRESULT WINAPI d3dadapter9_GetAdapterDisplayModeEx(struct d3dadapter9 *This, 489 | UINT Adapter, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) 490 | { 491 | int Mode; 492 | 493 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 494 | return D3DERR_INVALIDCALL; 495 | 496 | if (pMode) 497 | { 498 | Mode = get_current_mode(This, Adapter); 499 | if (Mode < 0) 500 | return D3DERR_INVALIDCALL; 501 | 502 | pMode->Size = sizeof(D3DDISPLAYMODEEX); 503 | pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width; 504 | pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height; 505 | pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate; 506 | pMode->Format = ADAPTER_OUTPUT.modes[Mode].Format; 507 | pMode->ScanLineOrdering = ADAPTER_OUTPUT.modes[Mode].ScanLineOrdering; 508 | } 509 | if (pRotation) 510 | *pRotation = ADAPTER_OUTPUT.rotation; 511 | 512 | return D3D_OK; 513 | } 514 | 515 | static HRESULT WINAPI DECLSPEC_HOTPATCH d3dadapter9_CreateDeviceEx(struct d3dadapter9 *This, 516 | UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, 517 | D3DPRESENT_PARAMETERS *pPresentationParameters, 518 | D3DDISPLAYMODEEX *pFullscreenDisplayMode, 519 | IDirect3DDevice9Ex **ppReturnedDeviceInterface) 520 | { 521 | ID3DPresentGroup *present; 522 | HRESULT hr; 523 | 524 | if (Adapter >= d3dadapter9_GetAdapterCount(This)) 525 | return D3DERR_INVALIDCALL; 526 | 527 | { 528 | struct adapter_group *group = &ADAPTER_GROUP; 529 | unsigned nparams; 530 | 531 | if (BehaviorFlags & D3DCREATE_ADAPTERGROUP_DEVICE) 532 | nparams = group->noutputs; 533 | else 534 | nparams = 1; 535 | 536 | hr = present_create_present_group(This->gdi_display, group->devname, 537 | hFocusWindow, pPresentationParameters, nparams, &present, This->ex, 538 | BehaviorFlags, group->dri_backend); 539 | } 540 | 541 | if (FAILED(hr)) 542 | { 543 | WARN("Failed to create PresentGroup.\n"); 544 | return hr; 545 | } 546 | 547 | if (This->ex) 548 | { 549 | hr = ADAPTER_PROC(CreateDeviceEx, Adapter, DeviceType, hFocusWindow, 550 | BehaviorFlags, pPresentationParameters, pFullscreenDisplayMode, 551 | (IDirect3D9Ex *)This, present, ppReturnedDeviceInterface); 552 | } 553 | else 554 | { 555 | /* CreateDevice on non-ex */ 556 | hr = ADAPTER_PROC(CreateDevice, Adapter, DeviceType, hFocusWindow, 557 | BehaviorFlags, pPresentationParameters, (IDirect3D9 *)This, present, 558 | (IDirect3DDevice9 **)ppReturnedDeviceInterface); 559 | } 560 | if (FAILED(hr)) 561 | { 562 | WARN("ADAPTER_PROC failed.\n"); 563 | ID3DPresentGroup_Release(present); 564 | return hr; 565 | } 566 | 567 | /* Nine returns different vtables for Ex, non Ex and 568 | * if you use the multithread flag or not. This prevents 569 | * things like Steam overlay to work, in addition to the problem 570 | * that functions nine side are not recognized by wine as 571 | * hotpatch-able. If possible, we use our vtable wrapper, 572 | * which solves the problem described above. */ 573 | if (enable_device_vtable_wrapper()) 574 | (*ppReturnedDeviceInterface)->lpVtbl = get_device_vtable(); 575 | return hr; 576 | } 577 | 578 | static HRESULT WINAPI d3dadapter9_GetAdapterLUID(struct d3dadapter9 *This, 579 | UINT Adapter, LUID *pLUID) 580 | { 581 | FIXME("(%p, %u, %p), stub!\n", This, Adapter, pLUID); 582 | return D3DERR_INVALIDCALL; 583 | } 584 | 585 | static struct adapter_group *add_group(struct d3dadapter9 *This) 586 | { 587 | if (This->ngroups >= This->ngroupsalloc) 588 | { 589 | void *r; 590 | 591 | if (This->ngroupsalloc == 0) 592 | { 593 | This->ngroupsalloc = 2; 594 | r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 595 | This->ngroupsalloc*sizeof(struct adapter_group)); 596 | } 597 | else 598 | { 599 | This->ngroupsalloc <<= 1; 600 | r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->groups, 601 | This->ngroupsalloc*sizeof(struct adapter_group)); 602 | } 603 | 604 | if (!r) 605 | return NULL; 606 | This->groups = r; 607 | } 608 | 609 | return &This->groups[This->ngroups++]; 610 | } 611 | 612 | static void remove_group(struct d3dadapter9 *This) 613 | { 614 | struct adapter_group *group = &This->groups[This->ngroups-1]; 615 | int i; 616 | 617 | for (i = 0; i < group->noutputs; ++i) 618 | { 619 | HeapFree(GetProcessHeap(), 0, group->outputs[i].modes); 620 | } 621 | HeapFree(GetProcessHeap(), 0, group->outputs); 622 | 623 | backend_destroy(group->dri_backend); 624 | 625 | ZeroMemory(group, sizeof(struct adapter_group)); 626 | This->ngroups--; 627 | } 628 | 629 | static struct output *add_output(struct d3dadapter9 *This) 630 | { 631 | struct adapter_group *group = &This->groups[This->ngroups-1]; 632 | 633 | if (group->noutputs >= group->noutputsalloc) 634 | { 635 | void *r; 636 | 637 | if (group->noutputsalloc == 0) 638 | { 639 | group->noutputsalloc = 2; 640 | r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 641 | group->noutputsalloc*sizeof(struct output)); 642 | } 643 | else 644 | { 645 | group->noutputsalloc <<= 1; 646 | r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, group->outputs, 647 | group->noutputsalloc*sizeof(struct output)); 648 | } 649 | 650 | if (!r) 651 | return NULL; 652 | group->outputs = r; 653 | } 654 | 655 | return &group->outputs[group->noutputs++]; 656 | } 657 | 658 | static void remove_output(struct d3dadapter9 *This) 659 | { 660 | struct adapter_group *group = &This->groups[This->ngroups-1]; 661 | struct output *out = &group->outputs[group->noutputs-1]; 662 | 663 | HeapFree(GetProcessHeap(), 0, out->modes); 664 | 665 | ZeroMemory(out, sizeof(struct output)); 666 | group->noutputs--; 667 | } 668 | 669 | static D3DDISPLAYMODEEX *add_mode(struct d3dadapter9 *This) 670 | { 671 | struct adapter_group *group = &This->groups[This->ngroups-1]; 672 | struct output *out = &group->outputs[group->noutputs-1]; 673 | 674 | if (out->nmodes >= out->nmodesalloc) 675 | { 676 | void *r; 677 | 678 | if (out->nmodesalloc == 0) 679 | { 680 | out->nmodesalloc = 8; 681 | r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 682 | out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX)); 683 | } 684 | else 685 | { 686 | out->nmodesalloc <<= 1; 687 | r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, out->modes, 688 | out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX)); 689 | } 690 | 691 | if (!r) 692 | return NULL; 693 | out->modes = r; 694 | } 695 | 696 | return &out->modes[out->nmodes++]; 697 | } 698 | 699 | static void remove_mode(struct d3dadapter9 *This) 700 | { 701 | struct adapter_group *group = &This->groups[This->ngroups-1]; 702 | struct output *out = &group->outputs[group->noutputs-1]; 703 | out->nmodes--; 704 | } 705 | 706 | static HRESULT fill_groups(struct d3dadapter9 *This) 707 | { 708 | DISPLAY_DEVICEW dd; 709 | DEVMODEW dm; 710 | POINT pt; 711 | HDC hdc; 712 | HRESULT hr; 713 | int i, j, k; 714 | 715 | const WCHAR wdisp[] = {'D','I','S','P','L','A','Y',0}; 716 | 717 | ZeroMemory(&dd, sizeof(dd)); 718 | ZeroMemory(&dm, sizeof(dm)); 719 | dd.cb = sizeof(dd); 720 | dm.dmSize = sizeof(dm); 721 | 722 | for (i = 0; EnumDisplayDevicesW(NULL, i, &dd, 0); ++i) 723 | { 724 | struct adapter_group *group = add_group(This); 725 | if (!group) 726 | { 727 | ERR("Out of memory.\n"); 728 | return E_OUTOFMEMORY; 729 | } 730 | 731 | hdc = CreateDCW(wdisp, dd.DeviceName, NULL, NULL); 732 | if (!hdc) 733 | { 734 | remove_group(This); 735 | WARN("Unable to create DC for display %d.\n", i); 736 | goto end_group; 737 | } 738 | 739 | group->dri_backend = backend_create(This->gdi_display, DefaultScreen(This->gdi_display)); 740 | if (!group->dri_backend) 741 | { 742 | ERR("Unable to open backend for display %d.\n", i); 743 | goto end_group; 744 | } 745 | 746 | hr = present_create_adapter9(This->gdi_display, hdc, group->dri_backend, 747 | &group->adapter); 748 | 749 | DeleteDC(hdc); 750 | if (FAILED(hr)) 751 | { 752 | remove_group(This); 753 | goto end_group; 754 | } 755 | 756 | CopyMemory(group->devname, dd.DeviceName, sizeof(group->devname)); 757 | for (j = 0; EnumDisplayDevicesW(group->devname, j, &dd, 0); ++j) 758 | { 759 | struct output *out = add_output(This); 760 | boolean orient = FALSE, monit = FALSE; 761 | if (!out) 762 | { 763 | ERR("Out of memory.\n"); 764 | return E_OUTOFMEMORY; 765 | } 766 | 767 | for (k = 0; EnumDisplaySettingsExW(group->devname, k, &dm, 0); ++k) 768 | { 769 | D3DDISPLAYMODEEX *mode = add_mode(This); 770 | if (!out) 771 | { 772 | ERR("Out of memory.\n"); 773 | return E_OUTOFMEMORY; 774 | } 775 | 776 | mode->Size = sizeof(D3DDISPLAYMODEEX); 777 | mode->Width = dm.dmPelsWidth; 778 | mode->Height = dm.dmPelsHeight; 779 | mode->RefreshRate = dm.dmDisplayFrequency; 780 | mode->ScanLineOrdering = 781 | (dm.dmDisplayFlags & DM_INTERLACED) ? 782 | D3DSCANLINEORDERING_INTERLACED : 783 | D3DSCANLINEORDERING_PROGRESSIVE; 784 | 785 | switch (dm.dmBitsPerPel) 786 | { 787 | case 32: mode->Format = D3DFMT_X8R8G8B8; break; 788 | case 24: mode->Format = D3DFMT_R8G8B8; break; 789 | case 16: mode->Format = D3DFMT_R5G6B5; break; 790 | case 8: 791 | remove_mode(This); 792 | goto end_mode; 793 | 794 | default: 795 | remove_mode(This); 796 | WARN("Unknown format (%u bpp) in display %d, monitor " 797 | "%d, mode %d.\n", (UINT)dm.dmBitsPerPel, i, j, k); 798 | goto end_mode; 799 | } 800 | 801 | if (!orient) 802 | { 803 | switch (dm.dmDisplayOrientation) 804 | { 805 | case DMDO_DEFAULT: 806 | out->rotation = D3DDISPLAYROTATION_IDENTITY; 807 | break; 808 | 809 | case DMDO_90: 810 | out->rotation = D3DDISPLAYROTATION_90; 811 | break; 812 | 813 | case DMDO_180: 814 | out->rotation = D3DDISPLAYROTATION_180; 815 | break; 816 | 817 | case DMDO_270: 818 | out->rotation = D3DDISPLAYROTATION_270; 819 | break; 820 | 821 | default: 822 | remove_output(This); 823 | WARN("Unknown display rotation in display %d, " 824 | "monitor %d\n", i, j); 825 | goto end_output; 826 | } 827 | orient = TRUE; 828 | } 829 | 830 | if (!monit) 831 | { 832 | pt.x = dm.dmPosition.x; 833 | pt.y = dm.dmPosition.y; 834 | out->monitor = MonitorFromPoint(pt, 0); 835 | if (!out->monitor) 836 | { 837 | remove_output(This); 838 | WARN("Unable to get monitor handle for display %d, " 839 | "monitor %d.\n", i, j); 840 | goto end_output; 841 | } 842 | monit = TRUE; 843 | } 844 | 845 | end_mode: 846 | ZeroMemory(&dm, sizeof(dm)); 847 | dm.dmSize = sizeof(dm); 848 | } 849 | 850 | end_output: 851 | ZeroMemory(&dd, sizeof(dd)); 852 | dd.cb = sizeof(dd); 853 | } 854 | 855 | end_group: 856 | ZeroMemory(&dd, sizeof(dd)); 857 | dd.cb = sizeof(dd); 858 | } 859 | 860 | return D3D_OK; 861 | } 862 | 863 | static IDirect3D9ExVtbl d3dadapter9_vtable = { 864 | (void *)d3dadapter9_QueryInterface, 865 | (void *)d3dadapter9_AddRef, 866 | (void *)d3dadapter9_Release, 867 | (void *)d3dadapter9_RegisterSoftwareDevice, 868 | (void *)d3dadapter9_GetAdapterCount, 869 | (void *)d3dadapter9_GetAdapterIdentifier, 870 | (void *)d3dadapter9_GetAdapterModeCount, 871 | (void *)d3dadapter9_EnumAdapterModes, 872 | (void *)d3dadapter9_GetAdapterDisplayMode, 873 | (void *)d3dadapter9_CheckDeviceType, 874 | (void *)d3dadapter9_CheckDeviceFormat, 875 | (void *)d3dadapter9_CheckDeviceMultiSampleType, 876 | (void *)d3dadapter9_CheckDepthStencilMatch, 877 | (void *)d3dadapter9_CheckDeviceFormatConversion, 878 | (void *)d3dadapter9_GetDeviceCaps, 879 | (void *)d3dadapter9_GetAdapterMonitor, 880 | (void *)d3dadapter9_CreateDevice, 881 | (void *)d3dadapter9_GetAdapterModeCountEx, 882 | (void *)d3dadapter9_EnumAdapterModesEx, 883 | (void *)d3dadapter9_GetAdapterDisplayModeEx, 884 | (void *)d3dadapter9_CreateDeviceEx, 885 | (void *)d3dadapter9_GetAdapterLUID 886 | }; 887 | 888 | HRESULT d3dadapter9_new(Display *gdi_display, boolean ex, IDirect3D9Ex **ppOut) 889 | { 890 | struct d3dadapter9 *This; 891 | HRESULT hr; 892 | unsigned i, j, k; 893 | 894 | This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct d3dadapter9)); 895 | if (!This) 896 | { 897 | ERR("Out of memory.\n"); 898 | return E_OUTOFMEMORY; 899 | } 900 | 901 | This->vtable = &d3dadapter9_vtable; 902 | This->refs = 1; 903 | This->ex = ex; 904 | This->gdi_display = gdi_display; 905 | 906 | if (!present_has_d3dadapter(gdi_display)) 907 | { 908 | ERR("Your display driver doesn't support native D3D9 adapters.\n"); 909 | d3dadapter9_Release(This); 910 | return D3DERR_NOTAVAILABLE; 911 | } 912 | 913 | if (FAILED(hr = fill_groups(This))) 914 | { 915 | d3dadapter9_Release(This); 916 | return hr; 917 | } 918 | 919 | /* map absolute adapter IDs with internal adapters */ 920 | for (i = 0; i < This->ngroups; ++i) 921 | { 922 | for (j = 0; j < This->groups[i].noutputs; ++j) 923 | { 924 | This->nadapters++; 925 | } 926 | } 927 | if (This->nadapters == 0) 928 | { 929 | ERR("No available native adapters in system.\n"); 930 | d3dadapter9_Release(This); 931 | return D3DERR_NOTAVAILABLE; 932 | } 933 | 934 | This->map = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 935 | This->nadapters * sizeof(struct adapter_map)); 936 | 937 | if (!This->map) 938 | { 939 | d3dadapter9_Release(This); 940 | ERR("Out of memory.\n"); 941 | return E_OUTOFMEMORY; 942 | } 943 | for (i = k = 0; i < This->ngroups; ++i) 944 | { 945 | for (j = 0; j < This->groups[i].noutputs; ++j, ++k) 946 | { 947 | This->map[k].master = k-j; 948 | This->map[k].group = i; 949 | } 950 | } 951 | 952 | *ppOut = (IDirect3D9Ex *)This; 953 | 954 | fprintf(stderr, "\033[1;32mNative Direct3D 9 " NINE_VERSION " is active.\n" 955 | "For more information visit " NINE_URL "\033[0m\n"); 956 | 957 | return D3D_OK; 958 | } 959 | -------------------------------------------------------------------------------- /d3d9-nine/d3dadapter9.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * D3DAdapter9 interface 4 | * 5 | * Copyright 2015 Patrick Rudolph 6 | */ 7 | 8 | #ifndef __NINE_D3D9ADAPTER_H 9 | #define __NINE_D3D9ADAPTER_H 10 | 11 | #include 12 | #include 13 | 14 | void d3dadapter9_init(HINSTANCE hinst); 15 | 16 | void d3dadapter9_destroy(HINSTANCE hinst); 17 | 18 | HRESULT d3dadapter9_new(Display *gdi_display, boolean ex, IDirect3D9Ex **ppOut); 19 | 20 | #endif /* __NINE_D3D9ADAPTER_H */ 21 | -------------------------------------------------------------------------------- /d3d9-nine/device_wrap.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Copyright 2016 Axel Davy 4 | */ 5 | 6 | #include 7 | 8 | #include "device_wrap.h" 9 | 10 | struct IDirect3DDevice9Ex_Minor1 11 | { 12 | IDirect3DDevice9ExVtbl *lpVtbl; 13 | IDirect3DDevice9ExVtbl *lpVtbl_internal; 14 | }; 15 | 16 | struct IDirect3DSwapChain9Ex_Minor1 17 | { 18 | IDirect3DSwapChain9ExVtbl *lpVtbl; 19 | IDirect3DSwapChain9ExVtbl *lpVtbl_internal; 20 | }; 21 | 22 | typedef struct IDirect3DDevice9Ex_Minor1 IDirect3DDevice9Ex_Minor1; 23 | typedef struct IDirect3DSwapChain9Ex_Minor1 IDirect3DSwapChain9Ex_Minor1; 24 | 25 | #define SWAPCHAIN_WRAP0(ret, func) \ 26 | ret WINAPI WineNineSwapChain9_ ## func(IDirect3DSwapChain9Ex *This) \ 27 | { \ 28 | return ((IDirect3DSwapChain9Ex_Minor1 *)This)->lpVtbl_internal->func(This); \ 29 | } 30 | 31 | #define SWAPCHAIN_WRAP1(ret, func, type1) \ 32 | ret WINAPI WineNineSwapChain9_ ## func(IDirect3DSwapChain9Ex *This, type1 arg1) \ 33 | { \ 34 | return ((IDirect3DSwapChain9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1); \ 35 | } 36 | 37 | #define SWAPCHAIN_WRAP2(ret, func, type1, type2) \ 38 | ret WINAPI WineNineSwapChain9_ ## func(IDirect3DSwapChain9Ex *This, type1 arg1, type2 arg2) \ 39 | { \ 40 | return ((IDirect3DSwapChain9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2); \ 41 | } 42 | 43 | #define SWAPCHAIN_WRAP3(ret, func, type1, type2, type3) \ 44 | ret WINAPI WineNineSwapChain9_ ## func(IDirect3DSwapChain9Ex *This, type1 arg1, type2 arg2, type3 arg3) \ 45 | { \ 46 | return ((IDirect3DSwapChain9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3); \ 47 | } 48 | 49 | #define SWAPCHAIN_H_WRAP5(ret, func, type1, type2, type3, type4, type5) \ 50 | ret WINAPI DECLSPEC_HOTPATCH WineNineSwapChain9_ ## func(IDirect3DSwapChain9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ 51 | { \ 52 | return ((IDirect3DSwapChain9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5); \ 53 | } 54 | 55 | #define DEVICE_WRAP0(ret, func) \ 56 | ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This) \ 57 | { \ 58 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This); \ 59 | } 60 | 61 | #define DEVICE_WRAP1(ret, func, type1) \ 62 | ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1) \ 63 | { \ 64 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1); \ 65 | } 66 | 67 | #define DEVICE_WRAP2(ret, func, type1, type2) \ 68 | ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2) \ 69 | { \ 70 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2); \ 71 | } 72 | 73 | #define DEVICE_WRAP3(ret, func, type1, type2, type3) \ 74 | ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3) \ 75 | { \ 76 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3); \ 77 | } 78 | 79 | #define DEVICE_WRAP4(ret, func, type1, type2, type3, type4) \ 80 | ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ 81 | { \ 82 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4); \ 83 | } 84 | 85 | #define DEVICE_WRAP5(ret, func, type1, type2, type3, type4, type5) \ 86 | ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ 87 | { \ 88 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5); \ 89 | } 90 | 91 | #define DEVICE_WRAP6(ret, func, type1, type2, type3, type4, type5, type6) \ 92 | ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \ 93 | { \ 94 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5, arg6); \ 95 | } 96 | 97 | #define DEVICE_WRAP7(ret, func, type1, type2, type3, type4, type5, type6, type7) \ 98 | ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7) \ 99 | { \ 100 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5, arg6, arg7); \ 101 | } 102 | 103 | #define DEVICE_WRAP8(ret, func, type1, type2, type3, type4, type5, type6, type7, type8) \ 104 | ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8) \ 105 | { \ 106 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); \ 107 | } 108 | 109 | #define DEVICE_WRAP9(ret, func, type1, type2, type3, type4, type5, type6, type7, type8, type9) \ 110 | ret WINAPI WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8, type9 arg9) \ 111 | { \ 112 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); \ 113 | } 114 | 115 | #define DEVICE_H_WRAP0(ret, func) \ 116 | ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This) \ 117 | { \ 118 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This); \ 119 | } 120 | 121 | #define DEVICE_H_WRAP1(ret, func, type1) \ 122 | ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1) \ 123 | { \ 124 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1); \ 125 | } 126 | 127 | #define DEVICE_H_WRAP2(ret, func, type1, type2) \ 128 | ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2) \ 129 | { \ 130 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2); \ 131 | } 132 | 133 | #define DEVICE_H_WRAP3(ret, func, type1, type2, type3) \ 134 | ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3) \ 135 | { \ 136 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3); \ 137 | } 138 | 139 | #define DEVICE_H_WRAP4(ret, func, type1, type2, type3, type4) \ 140 | ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ 141 | { \ 142 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4); \ 143 | } 144 | 145 | #define DEVICE_H_WRAP5(ret, func, type1, type2, type3, type4, type5) \ 146 | ret WINAPI DECLSPEC_HOTPATCH WineNineDevice9_ ## func(IDirect3DDevice9Ex *This, type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ 147 | { \ 148 | return ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->func(This, arg1, arg2, arg3, arg4, arg5); \ 149 | } 150 | 151 | SWAPCHAIN_WRAP2(HRESULT, QueryInterface, REFIID, void **) 152 | SWAPCHAIN_WRAP0(ULONG, AddRef) 153 | SWAPCHAIN_WRAP0(ULONG, Release) 154 | SWAPCHAIN_H_WRAP5(HRESULT, Present, const RECT *, const RECT *, HWND, const RGNDATA *, DWORD) 155 | SWAPCHAIN_WRAP1(HRESULT, GetFrontBufferData, IDirect3DSurface9 *) 156 | SWAPCHAIN_WRAP3(HRESULT, GetBackBuffer, UINT, D3DBACKBUFFER_TYPE, IDirect3DSurface9 **) 157 | SWAPCHAIN_WRAP1(HRESULT, GetRasterStatus, D3DRASTER_STATUS *) 158 | SWAPCHAIN_WRAP1(HRESULT, GetDisplayMode, D3DDISPLAYMODE *) 159 | SWAPCHAIN_WRAP1(HRESULT, GetDevice, IDirect3DDevice9 **) 160 | SWAPCHAIN_WRAP1(HRESULT, GetPresentParameters, D3DPRESENT_PARAMETERS *) 161 | SWAPCHAIN_WRAP1(HRESULT, GetLastPresentCount, UINT *) 162 | SWAPCHAIN_WRAP1(HRESULT, GetPresentStats, D3DPRESENTSTATS *) 163 | SWAPCHAIN_WRAP2(HRESULT, GetDisplayModeEx, D3DDISPLAYMODEEX *, D3DDISPLAYROTATION *) 164 | 165 | DEVICE_WRAP2(HRESULT, QueryInterface, REFIID, void **) 166 | DEVICE_WRAP0(ULONG, AddRef) 167 | DEVICE_H_WRAP0(ULONG, Release) 168 | DEVICE_WRAP0(HRESULT, TestCooperativeLevel) 169 | DEVICE_WRAP0(UINT, GetAvailableTextureMem) 170 | DEVICE_WRAP0(HRESULT, EvictManagedResources) 171 | DEVICE_WRAP1(HRESULT, GetDirect3D, IDirect3D9 **) 172 | DEVICE_WRAP1(HRESULT, GetDeviceCaps, D3DCAPS9 *) 173 | DEVICE_WRAP2(HRESULT, GetDisplayMode, UINT, D3DDISPLAYMODE*) 174 | DEVICE_WRAP1(HRESULT, GetCreationParameters, D3DDEVICE_CREATION_PARAMETERS *) 175 | DEVICE_WRAP3(HRESULT, SetCursorProperties, UINT, UINT, IDirect3DSurface9 *) 176 | DEVICE_WRAP3(void, SetCursorPosition, int, int, DWORD) 177 | DEVICE_WRAP1(BOOL, ShowCursor, BOOL) 178 | /*DEVICE_H_WRAP2(HRESULT, CreateAdditionalSwapChain, D3DPRESENT_PARAMETERS *, IDirect3DSwapChain9 **)*/ 179 | /*DEVICE_H_WRAP2(HRESULT, GetSwapChain, UINT, IDirect3DSwapChain9 **)*/ 180 | DEVICE_WRAP0(UINT, GetNumberOfSwapChains) 181 | DEVICE_H_WRAP1(HRESULT, Reset, D3DPRESENT_PARAMETERS *) 182 | DEVICE_H_WRAP4(HRESULT, Present, const RECT *, const RECT *, HWND, const RGNDATA *) 183 | DEVICE_WRAP4(HRESULT, GetBackBuffer, UINT, UINT, D3DBACKBUFFER_TYPE, IDirect3DSurface9 **) 184 | DEVICE_WRAP2(HRESULT, GetRasterStatus, UINT, D3DRASTER_STATUS *) 185 | DEVICE_WRAP1(HRESULT, SetDialogBoxMode, BOOL) 186 | DEVICE_H_WRAP3(void, SetGammaRamp, UINT, DWORD, const D3DGAMMARAMP *) 187 | DEVICE_WRAP2(void, GetGammaRamp, UINT, D3DGAMMARAMP *) 188 | DEVICE_WRAP8(HRESULT, CreateTexture, UINT, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DTexture9 **, HANDLE *) 189 | DEVICE_WRAP9(HRESULT, CreateVolumeTexture, UINT, UINT, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DVolumeTexture9 **, HANDLE *) 190 | DEVICE_WRAP7(HRESULT, CreateCubeTexture, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DCubeTexture9 **, HANDLE *) 191 | DEVICE_WRAP6(HRESULT, CreateVertexBuffer, UINT, DWORD, DWORD, D3DPOOL, IDirect3DVertexBuffer9 **, HANDLE *) 192 | DEVICE_WRAP6(HRESULT, CreateIndexBuffer, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DIndexBuffer9 **, HANDLE *) 193 | DEVICE_WRAP8(HRESULT, CreateRenderTarget, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, DWORD, BOOL, IDirect3DSurface9 **, HANDLE *) 194 | DEVICE_WRAP8(HRESULT, CreateDepthStencilSurface, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, DWORD, BOOL, IDirect3DSurface9 **, HANDLE *) 195 | DEVICE_WRAP4(HRESULT, UpdateSurface, IDirect3DSurface9 *, const RECT *, IDirect3DSurface9 *, const POINT *) 196 | DEVICE_WRAP2(HRESULT, UpdateTexture, IDirect3DBaseTexture9 *, IDirect3DBaseTexture9 *) 197 | DEVICE_WRAP2(HRESULT, GetRenderTargetData, IDirect3DSurface9 *, IDirect3DSurface9 *) 198 | DEVICE_WRAP2(HRESULT, GetFrontBufferData, UINT, IDirect3DSurface9 *) 199 | DEVICE_WRAP5(HRESULT, StretchRect, IDirect3DSurface9 *, const RECT *, IDirect3DSurface9 *, const RECT *, D3DTEXTUREFILTERTYPE) 200 | DEVICE_WRAP3(HRESULT, ColorFill, IDirect3DSurface9 *, const RECT *, D3DCOLOR) 201 | DEVICE_WRAP6(HRESULT, CreateOffscreenPlainSurface, UINT, UINT, D3DFORMAT, D3DPOOL, IDirect3DSurface9 **, HANDLE *) 202 | DEVICE_WRAP2(HRESULT, SetRenderTarget, DWORD, IDirect3DSurface9 *) 203 | DEVICE_WRAP2(HRESULT, GetRenderTarget, DWORD, IDirect3DSurface9 **) 204 | DEVICE_WRAP1(HRESULT, SetDepthStencilSurface, IDirect3DSurface9 *) 205 | DEVICE_WRAP1(HRESULT, GetDepthStencilSurface, IDirect3DSurface9 **) 206 | DEVICE_WRAP0(HRESULT, BeginScene) 207 | DEVICE_H_WRAP0(HRESULT, EndScene) 208 | DEVICE_WRAP6(HRESULT, Clear, DWORD, const D3DRECT *, DWORD, D3DCOLOR, float, DWORD) 209 | DEVICE_WRAP2(HRESULT, SetTransform, D3DTRANSFORMSTATETYPE, const D3DMATRIX *) 210 | DEVICE_WRAP2(HRESULT, GetTransform, D3DTRANSFORMSTATETYPE, D3DMATRIX *) 211 | DEVICE_WRAP2(HRESULT, MultiplyTransform, D3DTRANSFORMSTATETYPE, const D3DMATRIX *) 212 | DEVICE_WRAP1(HRESULT, SetViewport, const D3DVIEWPORT9 *) 213 | DEVICE_WRAP1(HRESULT, GetViewport, D3DVIEWPORT9 *) 214 | DEVICE_WRAP1(HRESULT, SetMaterial, const D3DMATERIAL9 *) 215 | DEVICE_WRAP1(HRESULT, GetMaterial, D3DMATERIAL9 *) 216 | DEVICE_WRAP2(HRESULT, SetLight, DWORD, const D3DLIGHT9 *) 217 | DEVICE_WRAP2(HRESULT, GetLight, DWORD, D3DLIGHT9 *) 218 | DEVICE_WRAP2(HRESULT, LightEnable, DWORD, BOOL) 219 | DEVICE_WRAP2(HRESULT, GetLightEnable, DWORD, BOOL *) 220 | DEVICE_WRAP2(HRESULT, SetClipPlane, DWORD, const float *) 221 | DEVICE_WRAP2(HRESULT, GetClipPlane, DWORD, float *) 222 | DEVICE_H_WRAP2(HRESULT, SetRenderState, D3DRENDERSTATETYPE, DWORD) 223 | DEVICE_WRAP2(HRESULT, GetRenderState, D3DRENDERSTATETYPE, DWORD *) 224 | DEVICE_WRAP2(HRESULT, CreateStateBlock, D3DSTATEBLOCKTYPE, IDirect3DStateBlock9 **) 225 | DEVICE_WRAP0(HRESULT, BeginStateBlock) 226 | DEVICE_WRAP1(HRESULT, EndStateBlock, IDirect3DStateBlock9 **) 227 | DEVICE_WRAP1(HRESULT, SetClipStatus, const D3DCLIPSTATUS9 *) 228 | DEVICE_WRAP1(HRESULT, GetClipStatus, D3DCLIPSTATUS9 *) 229 | DEVICE_WRAP2(HRESULT, GetTexture, DWORD, IDirect3DBaseTexture9 **) 230 | DEVICE_WRAP2(HRESULT, SetTexture, DWORD, IDirect3DBaseTexture9 *) 231 | DEVICE_WRAP3(HRESULT, GetTextureStageState, DWORD, D3DTEXTURESTAGESTATETYPE, DWORD *) 232 | DEVICE_WRAP3(HRESULT, SetTextureStageState, DWORD, D3DTEXTURESTAGESTATETYPE, DWORD) 233 | DEVICE_WRAP3(HRESULT, GetSamplerState, DWORD, D3DSAMPLERSTATETYPE, DWORD *) 234 | DEVICE_H_WRAP3(HRESULT, SetSamplerState, DWORD, D3DSAMPLERSTATETYPE, DWORD) 235 | DEVICE_WRAP1(HRESULT, ValidateDevice, DWORD *) 236 | DEVICE_WRAP2(HRESULT, SetPaletteEntries, UINT, const PALETTEENTRY *) 237 | DEVICE_WRAP2(HRESULT, GetPaletteEntries, UINT, PALETTEENTRY *) 238 | DEVICE_WRAP1(HRESULT, SetCurrentTexturePalette, UINT) 239 | DEVICE_WRAP1(HRESULT, GetCurrentTexturePalette, UINT *) 240 | DEVICE_WRAP1(HRESULT, SetScissorRect, const RECT *) 241 | DEVICE_WRAP1(HRESULT, GetScissorRect, RECT *) 242 | DEVICE_WRAP1(HRESULT, SetSoftwareVertexProcessing, BOOL) 243 | DEVICE_WRAP0(BOOL, GetSoftwareVertexProcessing) 244 | DEVICE_WRAP1(HRESULT, SetNPatchMode, float) 245 | DEVICE_WRAP0(float, GetNPatchMode) 246 | DEVICE_WRAP3(HRESULT, DrawPrimitive, D3DPRIMITIVETYPE, UINT, UINT) 247 | DEVICE_WRAP6(HRESULT, DrawIndexedPrimitive, D3DPRIMITIVETYPE, INT, UINT, UINT, UINT, UINT) 248 | DEVICE_WRAP4(HRESULT, DrawPrimitiveUP, D3DPRIMITIVETYPE, UINT, const void *, UINT) 249 | DEVICE_WRAP8(HRESULT, DrawIndexedPrimitiveUP, D3DPRIMITIVETYPE, UINT, UINT, UINT, const void *, D3DFORMAT, const void *, UINT) 250 | DEVICE_WRAP6(HRESULT, ProcessVertices, UINT, UINT, UINT, IDirect3DVertexBuffer9 *, IDirect3DVertexDeclaration9 *, DWORD) 251 | DEVICE_WRAP2(HRESULT, CreateVertexDeclaration, const D3DVERTEXELEMENT9 *, IDirect3DVertexDeclaration9 **) 252 | DEVICE_WRAP1(HRESULT, SetVertexDeclaration, IDirect3DVertexDeclaration9 *) 253 | DEVICE_WRAP1(HRESULT, GetVertexDeclaration, IDirect3DVertexDeclaration9 **) 254 | DEVICE_WRAP1(HRESULT, SetFVF, DWORD) 255 | DEVICE_WRAP1(HRESULT, GetFVF, DWORD *) 256 | DEVICE_WRAP2(HRESULT, CreateVertexShader, const DWORD *, IDirect3DVertexShader9 **) 257 | DEVICE_WRAP1(HRESULT, SetVertexShader, IDirect3DVertexShader9 *) 258 | DEVICE_WRAP1(HRESULT, GetVertexShader, IDirect3DVertexShader9 **) 259 | DEVICE_WRAP3(HRESULT, SetVertexShaderConstantF, UINT, const float *, UINT) 260 | DEVICE_WRAP3(HRESULT, GetVertexShaderConstantF, UINT, float *, UINT) 261 | DEVICE_WRAP3(HRESULT, SetVertexShaderConstantI, UINT, const int *, UINT) 262 | DEVICE_WRAP3(HRESULT, GetVertexShaderConstantI, UINT, int *, UINT) 263 | DEVICE_WRAP3(HRESULT, SetVertexShaderConstantB, UINT, const BOOL *, UINT) 264 | DEVICE_WRAP3(HRESULT, GetVertexShaderConstantB, UINT, BOOL *, UINT) 265 | DEVICE_WRAP4(HRESULT, SetStreamSource, UINT, IDirect3DVertexBuffer9 *, UINT, UINT) 266 | DEVICE_WRAP4(HRESULT, GetStreamSource, UINT, IDirect3DVertexBuffer9 **, UINT *, UINT *) 267 | DEVICE_WRAP2(HRESULT, SetStreamSourceFreq, UINT, UINT) 268 | DEVICE_WRAP2(HRESULT, GetStreamSourceFreq, UINT, UINT *) 269 | DEVICE_WRAP1(HRESULT, SetIndices, IDirect3DIndexBuffer9 *) 270 | DEVICE_WRAP1(HRESULT, GetIndices, IDirect3DIndexBuffer9 **) 271 | DEVICE_WRAP2(HRESULT, CreatePixelShader, const DWORD *, IDirect3DPixelShader9 **) 272 | DEVICE_WRAP1(HRESULT, SetPixelShader, IDirect3DPixelShader9 *) 273 | DEVICE_WRAP1(HRESULT, GetPixelShader, IDirect3DPixelShader9 **) 274 | DEVICE_WRAP3(HRESULT, SetPixelShaderConstantF, UINT, const float *, UINT) 275 | DEVICE_WRAP3(HRESULT, GetPixelShaderConstantF, UINT, float *, UINT) 276 | DEVICE_WRAP3(HRESULT, SetPixelShaderConstantI, UINT, const int *, UINT) 277 | DEVICE_WRAP3(HRESULT, GetPixelShaderConstantI, UINT, int *, UINT) 278 | DEVICE_WRAP3(HRESULT, SetPixelShaderConstantB, UINT, const BOOL *, UINT) 279 | DEVICE_WRAP3(HRESULT, GetPixelShaderConstantB, UINT, BOOL *, UINT) 280 | DEVICE_WRAP3(HRESULT, DrawRectPatch, UINT, const float *, const D3DRECTPATCH_INFO *) 281 | DEVICE_WRAP3(HRESULT, DrawTriPatch, UINT, const float *, const D3DTRIPATCH_INFO *) 282 | DEVICE_WRAP1(HRESULT, DeletePatch, UINT) 283 | DEVICE_WRAP2(HRESULT, CreateQuery, D3DQUERYTYPE, IDirect3DQuery9 **) 284 | DEVICE_WRAP4(HRESULT, SetConvolutionMonoKernel, UINT, UINT, float *, float *) 285 | DEVICE_WRAP8(HRESULT, ComposeRects, IDirect3DSurface9 *, IDirect3DSurface9 *, IDirect3DVertexBuffer9 *, UINT, IDirect3DVertexBuffer9 *, D3DCOMPOSERECTSOP, int, int) 286 | DEVICE_H_WRAP5(HRESULT, PresentEx, const RECT *, const RECT *, HWND, const RGNDATA *, DWORD) 287 | DEVICE_WRAP1(HRESULT, GetGPUThreadPriority, INT *) 288 | DEVICE_WRAP1(HRESULT, SetGPUThreadPriority, INT) 289 | DEVICE_WRAP1(HRESULT, WaitForVBlank, UINT) 290 | DEVICE_WRAP2(HRESULT, CheckResourceResidency, IDirect3DResource9 **, UINT32) 291 | DEVICE_WRAP1(HRESULT, SetMaximumFrameLatency, UINT) 292 | DEVICE_WRAP1(HRESULT, GetMaximumFrameLatency, UINT *) 293 | DEVICE_WRAP1(HRESULT, CheckDeviceState, HWND) 294 | DEVICE_WRAP9(HRESULT, CreateRenderTargetEx, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, DWORD, BOOL, IDirect3DSurface9 **, HANDLE *, DWORD) 295 | DEVICE_WRAP7(HRESULT, CreateOffscreenPlainSurfaceEx, UINT, UINT, D3DFORMAT, D3DPOOL, IDirect3DSurface9 **, HANDLE *, DWORD) 296 | DEVICE_WRAP9(HRESULT, CreateDepthStencilSurfaceEx, UINT, UINT, D3DFORMAT, D3DMULTISAMPLE_TYPE, DWORD, BOOL, IDirect3DSurface9 **, HANDLE *, DWORD) 297 | DEVICE_H_WRAP2(HRESULT, ResetEx, D3DPRESENT_PARAMETERS *, D3DDISPLAYMODEEX *) 298 | DEVICE_WRAP3(HRESULT, GetDisplayModeEx, UINT, D3DDISPLAYMODEEX *, D3DDISPLAYROTATION *) 299 | 300 | IDirect3DSwapChain9ExVtbl WineNineSwapChain9Ex_vtable = { 301 | WineNineSwapChain9_QueryInterface, 302 | WineNineSwapChain9_AddRef, 303 | WineNineSwapChain9_Release, 304 | WineNineSwapChain9_Present, 305 | WineNineSwapChain9_GetFrontBufferData, 306 | WineNineSwapChain9_GetBackBuffer, 307 | WineNineSwapChain9_GetRasterStatus, 308 | WineNineSwapChain9_GetDisplayMode, 309 | WineNineSwapChain9_GetDevice, 310 | WineNineSwapChain9_GetPresentParameters, 311 | WineNineSwapChain9_GetLastPresentCount, 312 | WineNineSwapChain9_GetPresentStats, 313 | WineNineSwapChain9_GetDisplayModeEx 314 | }; 315 | 316 | HRESULT WINAPI DECLSPEC_HOTPATCH WineNineDevice9_CreateAdditionalSwapChain(IDirect3DDevice9Ex *This, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DSwapChain9 **pSwapChain) 317 | { 318 | HRESULT hr; 319 | 320 | hr = ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->CreateAdditionalSwapChain(This, pPresentationParameters, pSwapChain); 321 | if (FAILED(hr)) 322 | return hr; 323 | 324 | (*pSwapChain)->lpVtbl = (IDirect3DSwapChain9Vtbl *)&WineNineSwapChain9Ex_vtable; 325 | 326 | return hr; 327 | } 328 | 329 | HRESULT WINAPI DECLSPEC_HOTPATCH WineNineDevice9_GetSwapChain(IDirect3DDevice9Ex *This, UINT iSwapChain, IDirect3DSwapChain9 **pSwapChain) 330 | { 331 | HRESULT hr; 332 | 333 | hr = ((IDirect3DDevice9Ex_Minor1 *)This)->lpVtbl_internal->GetSwapChain(This, iSwapChain, pSwapChain); 334 | if (FAILED(hr)) 335 | return hr; 336 | 337 | (*pSwapChain)->lpVtbl = (IDirect3DSwapChain9Vtbl *)&WineNineSwapChain9Ex_vtable; 338 | 339 | return hr; 340 | } 341 | 342 | 343 | IDirect3DDevice9ExVtbl WineNineDevice9_vtable = { 344 | WineNineDevice9_QueryInterface, 345 | WineNineDevice9_AddRef, 346 | WineNineDevice9_Release, 347 | WineNineDevice9_TestCooperativeLevel, 348 | WineNineDevice9_GetAvailableTextureMem, 349 | WineNineDevice9_EvictManagedResources, 350 | WineNineDevice9_GetDirect3D, 351 | WineNineDevice9_GetDeviceCaps, 352 | WineNineDevice9_GetDisplayMode, 353 | WineNineDevice9_GetCreationParameters, 354 | WineNineDevice9_SetCursorProperties, 355 | WineNineDevice9_SetCursorPosition, 356 | WineNineDevice9_ShowCursor, 357 | WineNineDevice9_CreateAdditionalSwapChain, 358 | WineNineDevice9_GetSwapChain, 359 | WineNineDevice9_GetNumberOfSwapChains, 360 | WineNineDevice9_Reset, 361 | WineNineDevice9_Present, 362 | WineNineDevice9_GetBackBuffer, 363 | WineNineDevice9_GetRasterStatus, 364 | WineNineDevice9_SetDialogBoxMode, 365 | WineNineDevice9_SetGammaRamp, 366 | WineNineDevice9_GetGammaRamp, 367 | WineNineDevice9_CreateTexture, 368 | WineNineDevice9_CreateVolumeTexture, 369 | WineNineDevice9_CreateCubeTexture, 370 | WineNineDevice9_CreateVertexBuffer, 371 | WineNineDevice9_CreateIndexBuffer, 372 | WineNineDevice9_CreateRenderTarget, 373 | WineNineDevice9_CreateDepthStencilSurface, 374 | WineNineDevice9_UpdateSurface, 375 | WineNineDevice9_UpdateTexture, 376 | WineNineDevice9_GetRenderTargetData, 377 | WineNineDevice9_GetFrontBufferData, 378 | WineNineDevice9_StretchRect, 379 | WineNineDevice9_ColorFill, 380 | WineNineDevice9_CreateOffscreenPlainSurface, 381 | WineNineDevice9_SetRenderTarget, 382 | WineNineDevice9_GetRenderTarget, 383 | WineNineDevice9_SetDepthStencilSurface, 384 | WineNineDevice9_GetDepthStencilSurface, 385 | WineNineDevice9_BeginScene, 386 | WineNineDevice9_EndScene, 387 | WineNineDevice9_Clear, 388 | WineNineDevice9_SetTransform, 389 | WineNineDevice9_GetTransform, 390 | WineNineDevice9_MultiplyTransform, 391 | WineNineDevice9_SetViewport, 392 | WineNineDevice9_GetViewport, 393 | WineNineDevice9_SetMaterial, 394 | WineNineDevice9_GetMaterial, 395 | WineNineDevice9_SetLight, 396 | WineNineDevice9_GetLight, 397 | WineNineDevice9_LightEnable, 398 | WineNineDevice9_GetLightEnable, 399 | WineNineDevice9_SetClipPlane, 400 | WineNineDevice9_GetClipPlane, 401 | WineNineDevice9_SetRenderState, 402 | WineNineDevice9_GetRenderState, 403 | WineNineDevice9_CreateStateBlock, 404 | WineNineDevice9_BeginStateBlock, 405 | WineNineDevice9_EndStateBlock, 406 | WineNineDevice9_SetClipStatus, 407 | WineNineDevice9_GetClipStatus, 408 | WineNineDevice9_GetTexture, 409 | WineNineDevice9_SetTexture, 410 | WineNineDevice9_GetTextureStageState, 411 | WineNineDevice9_SetTextureStageState, 412 | WineNineDevice9_GetSamplerState, 413 | WineNineDevice9_SetSamplerState, 414 | WineNineDevice9_ValidateDevice, 415 | WineNineDevice9_SetPaletteEntries, 416 | WineNineDevice9_GetPaletteEntries, 417 | WineNineDevice9_SetCurrentTexturePalette, 418 | WineNineDevice9_GetCurrentTexturePalette, 419 | WineNineDevice9_SetScissorRect, 420 | WineNineDevice9_GetScissorRect, 421 | WineNineDevice9_SetSoftwareVertexProcessing, 422 | WineNineDevice9_GetSoftwareVertexProcessing, 423 | WineNineDevice9_SetNPatchMode, 424 | WineNineDevice9_GetNPatchMode, 425 | WineNineDevice9_DrawPrimitive, 426 | WineNineDevice9_DrawIndexedPrimitive, 427 | WineNineDevice9_DrawPrimitiveUP, 428 | WineNineDevice9_DrawIndexedPrimitiveUP, 429 | WineNineDevice9_ProcessVertices, 430 | WineNineDevice9_CreateVertexDeclaration, 431 | WineNineDevice9_SetVertexDeclaration, 432 | WineNineDevice9_GetVertexDeclaration, 433 | WineNineDevice9_SetFVF, 434 | WineNineDevice9_GetFVF, 435 | WineNineDevice9_CreateVertexShader, 436 | WineNineDevice9_SetVertexShader, 437 | WineNineDevice9_GetVertexShader, 438 | WineNineDevice9_SetVertexShaderConstantF, 439 | WineNineDevice9_GetVertexShaderConstantF, 440 | WineNineDevice9_SetVertexShaderConstantI, 441 | WineNineDevice9_GetVertexShaderConstantI, 442 | WineNineDevice9_SetVertexShaderConstantB, 443 | WineNineDevice9_GetVertexShaderConstantB, 444 | WineNineDevice9_SetStreamSource, 445 | WineNineDevice9_GetStreamSource, 446 | WineNineDevice9_SetStreamSourceFreq, 447 | WineNineDevice9_GetStreamSourceFreq, 448 | WineNineDevice9_SetIndices, 449 | WineNineDevice9_GetIndices, 450 | WineNineDevice9_CreatePixelShader, 451 | WineNineDevice9_SetPixelShader, 452 | WineNineDevice9_GetPixelShader, 453 | WineNineDevice9_SetPixelShaderConstantF, 454 | WineNineDevice9_GetPixelShaderConstantF, 455 | WineNineDevice9_SetPixelShaderConstantI, 456 | WineNineDevice9_GetPixelShaderConstantI, 457 | WineNineDevice9_SetPixelShaderConstantB, 458 | WineNineDevice9_GetPixelShaderConstantB, 459 | WineNineDevice9_DrawRectPatch, 460 | WineNineDevice9_DrawTriPatch, 461 | WineNineDevice9_DeletePatch, 462 | WineNineDevice9_CreateQuery, 463 | WineNineDevice9_SetConvolutionMonoKernel, 464 | WineNineDevice9_ComposeRects, 465 | WineNineDevice9_PresentEx, 466 | WineNineDevice9_GetGPUThreadPriority, 467 | WineNineDevice9_SetGPUThreadPriority, 468 | WineNineDevice9_WaitForVBlank, 469 | WineNineDevice9_CheckResourceResidency, 470 | WineNineDevice9_SetMaximumFrameLatency, 471 | WineNineDevice9_GetMaximumFrameLatency, 472 | WineNineDevice9_CheckDeviceState, 473 | WineNineDevice9_CreateRenderTargetEx, 474 | WineNineDevice9_CreateOffscreenPlainSurfaceEx, 475 | WineNineDevice9_CreateDepthStencilSurfaceEx, 476 | WineNineDevice9_ResetEx, 477 | WineNineDevice9_GetDisplayModeEx 478 | }; 479 | 480 | IDirect3DDevice9ExVtbl *get_device_vtable() 481 | { 482 | return &WineNineDevice9_vtable; 483 | } 484 | -------------------------------------------------------------------------------- /d3d9-nine/device_wrap.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Copyright 2016 Axel Davy 4 | */ 5 | 6 | #ifndef __NINE_DEVICE_WRAP_H 7 | #define __NINE_DEVICE_WRAP_H 8 | 9 | #include 10 | 11 | IDirect3DDevice9ExVtbl *get_device_vtable(void); 12 | 13 | #endif /* __NINE_DEVICE_WRAP_H */ 14 | -------------------------------------------------------------------------------- /d3d9-nine/dri2.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Wine DRI2 interface 4 | * 5 | * Copyright 2014-2015 Axel Davy 6 | * Copyright 2015-2019 Patrick Rudolph 7 | */ 8 | 9 | #ifdef D3D9NINE_DRI2 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "../common/debug.h" 27 | #include "backend.h" 28 | #include "xcb_present.h" 29 | 30 | const char * const lib_egl = "libEGL.so.1"; 31 | 32 | static EGLDisplay display = NULL; 33 | static int display_ref = 0; 34 | 35 | struct dri2_pixmap_priv { 36 | GLuint fbo_read; 37 | GLuint fbo_write; 38 | GLuint texture_read; 39 | GLuint texture_write; 40 | unsigned int width; 41 | unsigned int height; 42 | struct dri2_pixmap_priv *next; 43 | }; 44 | 45 | struct dri2_priv { 46 | struct dri2_pixmap_priv *first_dri2_priv; 47 | Display *dpy; 48 | int screen; 49 | int fd; 50 | EGLDisplay display; 51 | EGLContext context; 52 | void *h_egl; 53 | 54 | /* egl */ 55 | void *(*eglGetProcAddress)(const char *procname); 56 | EGLContext (*eglCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); 57 | EGLBoolean (*eglDestroyContext)(EGLDisplay dpy, EGLContext ctx); 58 | EGLint (*eglGetError)(void); 59 | EGLBoolean (*eglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor); 60 | EGLBoolean (*eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); 61 | const char *(*eglQueryString)(EGLDisplay dpy, EGLint name); 62 | EGLBoolean (*eglTerminate)(EGLDisplay dpy); 63 | EGLBoolean (*eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); 64 | EGLBoolean (*eglBindAPI)(EGLenum api); 65 | EGLenum (*eglQueryAPI)(void); 66 | 67 | /* eglext */ 68 | EGLImageKHR (*eglCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); 69 | EGLBoolean (*eglDestroyImageKHR)(EGLDisplay dpy, EGLImageKHR image); 70 | EGLDisplay (*eglGetPlatformDisplayEXT)(EGLenum platform, void *native_display, const EGLint *attrib_list); 71 | 72 | /* gl */ 73 | void (*glFlush)(void); 74 | void (*glTexParameteri)(GLenum target, GLenum pname, GLint param); 75 | void (*glGenTextures)(GLsizei n, GLuint *textures); 76 | void (*glDeleteTextures)(GLsizei n, const GLuint *textures); 77 | void (*glBindTexture)(GLenum target, GLuint texture); 78 | void (*glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image); 79 | 80 | /* glext */ 81 | void (*glBindFramebuffer)(GLenum target, GLuint framebuffer); 82 | void (*glDeleteFramebuffers)(GLsizei n, const GLuint *framebuffers); 83 | void (*glGenFramebuffers)(GLsizei n, GLuint *framebuffers); 84 | GLenum (*glCheckFramebufferStatus)(GLenum target); 85 | void (*glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); 86 | void (*glBlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); 87 | }; 88 | 89 | static BOOL dri2_connect(Display *dpy, XID window, unsigned driver_type, char **device) 90 | { 91 | xcb_connection_t *conn = XGetXCBConnection(dpy); 92 | xcb_dri2_connect_cookie_t cookie; 93 | xcb_dri2_connect_reply_t *reply; 94 | xcb_generic_error_t *conn_error = NULL; 95 | 96 | *device = NULL; 97 | 98 | cookie = xcb_dri2_connect(conn, window, driver_type); 99 | reply = xcb_dri2_connect_reply(conn, cookie, &conn_error); 100 | 101 | if (conn_error) { 102 | free(conn_error); 103 | return False; 104 | } 105 | 106 | if (!reply) { 107 | return False; 108 | } 109 | 110 | /* read out device */ 111 | *device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 112 | xcb_dri2_connect_device_name_length(reply) + 1); 113 | if (!*device) { 114 | free(reply); 115 | return False; 116 | } 117 | strcpy(*device, xcb_dri2_connect_device_name(reply)); 118 | 119 | free(reply); 120 | 121 | return True; 122 | } 123 | 124 | static Bool dri2_authenticate(Display *dpy, XID window, uint32_t token) 125 | { 126 | xcb_generic_error_t *auth_error = NULL; 127 | xcb_dri2_authenticate_cookie_t cookie; 128 | xcb_connection_t *conn = XGetXCBConnection(dpy); 129 | 130 | cookie = xcb_dri2_authenticate(conn, window, token); 131 | Bool authenticated; 132 | 133 | xcb_dri2_authenticate_reply_t *reply = 134 | xcb_dri2_authenticate_reply(conn, cookie, &auth_error); 135 | if (auth_error) { 136 | free(auth_error); 137 | return FALSE; 138 | } 139 | if (!reply) { 140 | return FALSE; 141 | } 142 | 143 | authenticated = reply->authenticated; 144 | free(reply); 145 | 146 | return authenticated; 147 | } 148 | 149 | static void *dri2_eglGetProcAddress(struct dri2_priv *priv, const char *procname) 150 | { 151 | void *p; 152 | 153 | p = dlsym(priv->h_egl, procname); 154 | if (p) 155 | return p; 156 | 157 | if (priv->eglGetProcAddress) 158 | p = priv->eglGetProcAddress(procname); 159 | 160 | if (!p) 161 | ERR("%s is missing but required\n", procname); 162 | 163 | return p; 164 | } 165 | 166 | static BOOL dri2_create(Display *dpy, int screen, struct dri_backend_priv **priv) 167 | { 168 | struct dri2_priv *p; 169 | char *device; 170 | int fd; 171 | Window root = RootWindow(dpy, screen); 172 | drm_auth_t auth; 173 | 174 | if (!dri2_connect(dpy, root, XCB_DRI2_DRIVER_TYPE_DRI, &device)) 175 | return FALSE; 176 | 177 | fd = open(device, O_RDWR); 178 | HeapFree(GetProcessHeap(), 0, device); 179 | if (fd < 0) 180 | return FALSE; 181 | 182 | if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth) != 0) 183 | { 184 | close(fd); 185 | return FALSE; 186 | } 187 | 188 | if (!dri2_authenticate(dpy, root, auth.magic)) 189 | { 190 | close(fd); 191 | return FALSE; 192 | } 193 | 194 | p = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct dri2_priv)); 195 | if (!p) 196 | { 197 | close(fd); 198 | return FALSE; 199 | } 200 | 201 | p->dpy = dpy; 202 | p->screen = screen; 203 | p->fd = fd; 204 | 205 | p->h_egl = dlopen(lib_egl, RTLD_LAZY); 206 | if (!p->h_egl) 207 | { 208 | ERR("failed to open %s: %s\n", lib_egl, dlerror()); 209 | goto err_egl; 210 | } 211 | 212 | #define DRI2_EGLGETPROCADDRESS(procname) \ 213 | p->procname = dri2_eglGetProcAddress(p, #procname); \ 214 | if (!p->procname) \ 215 | goto err_egl; 216 | 217 | DRI2_EGLGETPROCADDRESS(eglGetProcAddress); 218 | DRI2_EGLGETPROCADDRESS(eglCreateContext); 219 | DRI2_EGLGETPROCADDRESS(eglDestroyContext); 220 | DRI2_EGLGETPROCADDRESS(eglGetError); 221 | DRI2_EGLGETPROCADDRESS(eglInitialize); 222 | DRI2_EGLGETPROCADDRESS(eglMakeCurrent); 223 | DRI2_EGLGETPROCADDRESS(eglQueryString); 224 | DRI2_EGLGETPROCADDRESS(eglTerminate); 225 | DRI2_EGLGETPROCADDRESS(eglChooseConfig); 226 | DRI2_EGLGETPROCADDRESS(eglBindAPI); 227 | DRI2_EGLGETPROCADDRESS(eglQueryAPI); 228 | DRI2_EGLGETPROCADDRESS(eglCreateImageKHR); 229 | DRI2_EGLGETPROCADDRESS(eglDestroyImageKHR); 230 | DRI2_EGLGETPROCADDRESS(eglGetPlatformDisplayEXT); 231 | 232 | DRI2_EGLGETPROCADDRESS(glFlush); 233 | DRI2_EGLGETPROCADDRESS(glTexParameteri); 234 | DRI2_EGLGETPROCADDRESS(glGenTextures); 235 | DRI2_EGLGETPROCADDRESS(glDeleteTextures); 236 | DRI2_EGLGETPROCADDRESS(glBindTexture); 237 | DRI2_EGLGETPROCADDRESS(glEGLImageTargetTexture2DOES); 238 | DRI2_EGLGETPROCADDRESS(glBindFramebuffer); 239 | DRI2_EGLGETPROCADDRESS(glDeleteFramebuffers); 240 | DRI2_EGLGETPROCADDRESS(glGenFramebuffers); 241 | DRI2_EGLGETPROCADDRESS(glCheckFramebufferStatus); 242 | DRI2_EGLGETPROCADDRESS(glFramebufferTexture2D); 243 | DRI2_EGLGETPROCADDRESS(glBlitFramebuffer); 244 | 245 | #undef DRI2_EGLGETPROCADDRESS 246 | 247 | *priv = (struct dri_backend_priv *)p; 248 | 249 | return TRUE; 250 | 251 | err_egl: 252 | close(fd); 253 | HeapFree(GetProcessHeap(), 0, p); 254 | return FALSE; 255 | } 256 | 257 | static BOOL dri2_init(struct dri_backend_priv *priv) 258 | { 259 | struct dri2_priv *p = (struct dri2_priv *)priv; 260 | EGLint major, minor; 261 | EGLConfig config; 262 | EGLContext context; 263 | EGLint i; 264 | EGLBoolean b; 265 | EGLenum current_api = 0; 266 | const char *extensions; 267 | EGLint config_attribs[] = { 268 | EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, 269 | EGL_NONE 270 | }; 271 | EGLint context_compatibility_attribs[] = { 272 | EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, 273 | EGL_NONE 274 | }; 275 | 276 | current_api = p->eglQueryAPI(); 277 | 278 | if (!display) 279 | display = p->eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, p->dpy, NULL); 280 | if (!display) 281 | return FALSE; 282 | /* count references on display for multi device setups */ 283 | display_ref++; 284 | 285 | if (p->eglInitialize(display, &major, &minor) != EGL_TRUE) 286 | goto clean_egl_display; 287 | 288 | extensions = p->eglQueryString(display, EGL_CLIENT_APIS); 289 | if (!extensions || !strstr(extensions, "OpenGL")) 290 | goto clean_egl_display; 291 | 292 | extensions = p->eglQueryString(display, EGL_EXTENSIONS); 293 | if (!extensions || !strstr(extensions, "EGL_EXT_image_dma_buf_import") || 294 | !strstr(extensions, "EGL_KHR_create_context") || 295 | !strstr(extensions, "EGL_KHR_surfaceless_context") || 296 | !strstr(extensions, "EGL_KHR_image_base")) 297 | goto clean_egl_display; 298 | 299 | if (!p->eglChooseConfig(display, config_attribs, &config, 1, &i)) 300 | goto clean_egl_display; 301 | 302 | b = p->eglBindAPI(EGL_OPENGL_API); 303 | if (b == EGL_FALSE) 304 | goto clean_egl_display; 305 | context = p->eglCreateContext(display, config, EGL_NO_CONTEXT, context_compatibility_attribs); 306 | if (context == EGL_NO_CONTEXT) 307 | goto clean_egl_display; 308 | 309 | p->eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 310 | 311 | p->display = display; 312 | p->context = context; 313 | 314 | p->eglBindAPI(current_api); 315 | return TRUE; 316 | 317 | clean_egl_display: 318 | p->eglTerminate(display); 319 | p->eglBindAPI(current_api); 320 | return FALSE; 321 | } 322 | 323 | static int dri2_get_fd(struct dri_backend_priv *priv) 324 | { 325 | struct dri2_priv *p = (struct dri2_priv *)priv; 326 | 327 | return p->fd; 328 | } 329 | 330 | static BOOL dri2_present_pixmap(struct dri_backend_priv *priv, struct buffer_priv *buffer_priv) 331 | { 332 | struct dri2_priv *p = (struct dri2_priv *)priv; 333 | struct dri2_pixmap_priv *pp = (struct dri2_pixmap_priv *)buffer_priv; 334 | EGLenum current_api = 0; 335 | 336 | current_api = p->eglQueryAPI(); 337 | p->eglBindAPI(EGL_OPENGL_API); 338 | if (p->eglMakeCurrent(p->display, EGL_NO_SURFACE, EGL_NO_SURFACE, p->context)) 339 | { 340 | p->glBindFramebuffer(GL_READ_FRAMEBUFFER, pp->fbo_read); 341 | p->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, pp->fbo_write); 342 | 343 | p->glBlitFramebuffer(0, 0, pp->width, pp->height, 0, 0, pp->width, pp->height, 344 | GL_COLOR_BUFFER_BIT, GL_NEAREST); 345 | p->glFlush(); /* Perhaps useless */ 346 | } 347 | else 348 | { 349 | ERR("eglMakeCurrent failed with 0x%0X\n", p->eglGetError()); 350 | return FALSE; 351 | } 352 | 353 | p->eglMakeCurrent(p->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 354 | p->eglBindAPI(current_api); 355 | 356 | return TRUE; 357 | } 358 | 359 | static BOOL dri2_present(struct dri_backend_priv *priv, int fd, int width, int height, int stride, 360 | int depth, int bpp, struct buffer_priv **buffer_priv, Pixmap *pixmap) 361 | { 362 | struct dri2_priv *p = (struct dri2_priv *)priv; 363 | struct dri2_pixmap_priv *pp; 364 | EGLImageKHR image; 365 | GLuint texture_read, texture_write, fbo_read, fbo_write; 366 | EGLint attribs[] = { 367 | EGL_WIDTH, 0, 368 | EGL_HEIGHT, 0, 369 | EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888, 370 | EGL_DMA_BUF_PLANE0_FD_EXT, 0, 371 | EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, 372 | EGL_DMA_BUF_PLANE0_PITCH_EXT, 0, 373 | EGL_NONE 374 | }; 375 | EGLenum current_api = 0; 376 | int status; 377 | 378 | TRACE("fd=%d, width=%d, height=%d, stride=%d, depth=%d, bpp=%d\n", 379 | fd, width, height, stride, depth, bpp); 380 | 381 | attribs[1] = width; 382 | attribs[3] = height; 383 | attribs[7] = fd; 384 | attribs[11] = stride; 385 | 386 | current_api = p->eglQueryAPI(); 387 | p->eglBindAPI(EGL_OPENGL_API); 388 | 389 | /* We bind the dma-buf to a EGLImage, then to a texture, and then to a fbo. 390 | * Note that we can delete the EGLImage, but we shouldn't delete the texture, 391 | * else the fbo is invalid */ 392 | 393 | image = p->eglCreateImageKHR(p->display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, 394 | NULL, attribs); 395 | 396 | if (image == EGL_NO_IMAGE_KHR) { 397 | ERR("eglCreateImageKHR failed with 0x%0X\n", p->eglGetError()); 398 | goto fail; 399 | } 400 | close(fd); 401 | 402 | if (p->eglMakeCurrent(p->display, EGL_NO_SURFACE, EGL_NO_SURFACE, p->context)) 403 | { 404 | p->glGenTextures(1, &texture_read); 405 | p->glBindTexture(GL_TEXTURE_2D, texture_read); 406 | p->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 407 | p->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 408 | p->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); 409 | p->glGenFramebuffers(1, &fbo_read); 410 | p->glBindFramebuffer(GL_FRAMEBUFFER, fbo_read); 411 | p->glFramebufferTexture2D(GL_FRAMEBUFFER, 412 | GL_COLOR_ATTACHMENT0, 413 | GL_TEXTURE_2D, texture_read, 414 | 0); 415 | status = p->glCheckFramebufferStatus(GL_FRAMEBUFFER); 416 | if (status != GL_FRAMEBUFFER_COMPLETE) 417 | goto fail; 418 | p->glBindTexture(GL_TEXTURE_2D, 0); 419 | p->eglDestroyImageKHR(p->display, image); 420 | 421 | /* We bind a newly created pixmap (to which we want to copy the content) 422 | * to an EGLImage, then to a texture, then to a fbo. */ 423 | image = p->eglCreateImageKHR(p->display, p->context, EGL_NATIVE_PIXMAP_KHR, 424 | (void *)*pixmap, NULL); 425 | if (image == EGL_NO_IMAGE_KHR) 426 | goto fail; 427 | 428 | p->glGenTextures(1, &texture_write); 429 | p->glBindTexture(GL_TEXTURE_2D, texture_write); 430 | p->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 431 | p->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 432 | p->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); 433 | p->glGenFramebuffers(1, &fbo_write); 434 | p->glBindFramebuffer(GL_FRAMEBUFFER, fbo_write); 435 | p->glFramebufferTexture2D(GL_FRAMEBUFFER, 436 | GL_COLOR_ATTACHMENT0, 437 | GL_TEXTURE_2D, texture_write, 438 | 0); 439 | status = p->glCheckFramebufferStatus(GL_FRAMEBUFFER); 440 | if (status != GL_FRAMEBUFFER_COMPLETE) 441 | goto fail; 442 | p->glBindTexture(GL_TEXTURE_2D, 0); 443 | p->eglDestroyImageKHR(p->display, image); 444 | } 445 | else 446 | ERR("eglMakeCurrent failed with 0x%0X\n", p->eglGetError()); 447 | 448 | p->eglMakeCurrent(p->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 449 | 450 | pp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct dri2_pixmap_priv)); 451 | 452 | if (!pp) 453 | goto fail; 454 | 455 | pp->fbo_read = fbo_read; 456 | pp->fbo_write = fbo_write; 457 | pp->texture_read = texture_read; 458 | pp->texture_write = texture_write; 459 | pp->width = width; 460 | pp->height = height; 461 | pp->next = p->first_dri2_priv; 462 | p->first_dri2_priv = pp; 463 | 464 | *buffer_priv = (struct buffer_priv *)pp; 465 | 466 | p->eglBindAPI(current_api); 467 | 468 | return TRUE; 469 | fail: 470 | p->eglMakeCurrent(p->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 471 | p->eglBindAPI(current_api); 472 | return FALSE; 473 | } 474 | 475 | static BOOL dri2_window_buffer_from_dmabuf(struct dri_backend_priv *priv, 476 | PRESENTpriv *present_priv, int fd, int width, int height, 477 | int stride, int depth, int bpp, struct D3DWindowBuffer **out) 478 | { 479 | struct dri2_priv *p = (struct dri2_priv *)priv; 480 | Pixmap pixmap; 481 | 482 | TRACE("present_priv=%p dmaBufFd=%d\n", present_priv, fd); 483 | 484 | if (!out) 485 | return FALSE; 486 | 487 | *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 488 | sizeof(struct D3DWindowBuffer)); 489 | if (!*out) 490 | return FALSE; 491 | 492 | if (!PRESENTPixmapCreate(present_priv, p->screen, &pixmap, 493 | width, height, stride, depth, bpp)) 494 | { 495 | HeapFree(GetProcessHeap(), 0, *out); 496 | ERR("Failed to create pixmap\n"); 497 | return FALSE; 498 | } 499 | 500 | if (!dri2_present(priv, fd, width, height, stride, depth, bpp, 501 | &(*out)->priv, &pixmap)) 502 | { 503 | ERR("dri2_present failed\n"); 504 | HeapFree(GetProcessHeap(), 0, *out); 505 | return FALSE; 506 | } 507 | 508 | if (!PRESENTPixmapInit(present_priv, pixmap, &((*out)->present_pixmap_priv))) 509 | { 510 | ERR("PRESENTPixmapInit failed\n"); 511 | HeapFree(GetProcessHeap(), 0, *out); 512 | return FALSE; 513 | } 514 | 515 | return TRUE; 516 | } 517 | 518 | static BOOL dri2_copy_front(PRESENTPixmapPriv *present_pixmap_priv) 519 | { 520 | return FALSE; 521 | } 522 | 523 | static void dri2_destroy_pixmap(struct dri_backend_priv *priv, struct buffer_priv *buffer_priv) 524 | { 525 | struct dri2_priv *p = (struct dri2_priv *)priv; 526 | struct dri2_pixmap_priv *pp = (struct dri2_pixmap_priv *)buffer_priv; 527 | EGLenum current_api; 528 | 529 | if (p->first_dri2_priv == pp) 530 | { 531 | p->first_dri2_priv = pp->next; 532 | } 533 | else 534 | { 535 | struct dri2_pixmap_priv *current; 536 | 537 | current = p->first_dri2_priv; 538 | while (current->next != pp) 539 | current = current->next; 540 | current->next = pp->next; 541 | } 542 | 543 | current_api = p->eglQueryAPI(); 544 | 545 | p->eglBindAPI(EGL_OPENGL_API); 546 | if (p->eglMakeCurrent(p->display, EGL_NO_SURFACE, EGL_NO_SURFACE, p->context)) 547 | { 548 | p->glDeleteFramebuffers(1, &pp->fbo_read); 549 | p->glDeleteFramebuffers(1, &pp->fbo_write); 550 | p->glDeleteTextures(1, &pp->texture_read); 551 | p->glDeleteTextures(1, &pp->texture_write); 552 | } 553 | else 554 | ERR("eglMakeCurrent failed with 0x%0X\n", p->eglGetError()); 555 | 556 | p->eglMakeCurrent(p->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 557 | p->eglBindAPI(current_api); 558 | 559 | HeapFree(GetProcessHeap(), 0, pp); 560 | } 561 | 562 | /* hypothesis: at this step all textures, etc are destroyed */ 563 | static void dri2_deinit(struct dri_backend_priv *priv) 564 | { 565 | struct dri2_priv *p = (struct dri2_priv *)priv; 566 | EGLenum current_api; 567 | struct dri2_pixmap_priv *current; 568 | 569 | current = p->first_dri2_priv; 570 | while (current) 571 | { 572 | struct dri2_pixmap_priv *next = current->next; 573 | dri2_destroy_pixmap(priv, (struct buffer_priv *)current); 574 | current = next; 575 | } 576 | 577 | current_api = p->eglQueryAPI(); 578 | p->eglBindAPI(EGL_OPENGL_API); 579 | p->eglMakeCurrent(p->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 580 | p->eglDestroyContext(p->display, p->context); 581 | if (display) 582 | { 583 | /* destroy display connection with last device */ 584 | display_ref--; 585 | if (!display_ref) 586 | { 587 | p->eglTerminate(display); 588 | display = NULL; 589 | } 590 | } 591 | p->eglBindAPI(current_api); 592 | } 593 | 594 | static void dri2_destroy(struct dri_backend_priv *priv) 595 | { 596 | struct dri2_priv *p = (struct dri2_priv *)priv; 597 | 598 | if (!display_ref) 599 | dlclose(p->h_egl); 600 | 601 | close(p->fd); 602 | 603 | HeapFree(GetProcessHeap(), 0, p); 604 | } 605 | 606 | static BOOL dri2_probe(Display *dpy) 607 | { 608 | xcb_connection_t *conn = XGetXCBConnection(dpy); 609 | xcb_dri2_query_version_cookie_t dri2_cookie; 610 | xcb_dri2_query_version_reply_t *dri2_reply; 611 | xcb_generic_error_t *error; 612 | const xcb_query_extension_reply_t *extension; 613 | /* Request API version 1.4 */ 614 | const int major = 1; 615 | const int minor = 4; 616 | 617 | xcb_prefetch_extension_data(conn, &xcb_dri2_id); 618 | 619 | extension = xcb_get_extension_data(conn, &xcb_dri2_id); 620 | if (!(extension && extension->present)) 621 | { 622 | WARN("DRI2 extension is not present\n"); 623 | return FALSE; 624 | } 625 | 626 | dri2_cookie = xcb_dri2_query_version(conn, major, minor); 627 | 628 | dri2_reply = xcb_dri2_query_version_reply(conn, dri2_cookie, &error); 629 | if (!dri2_reply) 630 | { 631 | free(error); 632 | WARN("Issue getting requested v%d.%d of DRI2\n", major, minor); 633 | return FALSE; 634 | } 635 | 636 | TRACE("DRI2 v%d.%d requested, v%d.%d found\n", major, minor, 637 | (int)dri2_reply->major_version, (int)dri2_reply->minor_version); 638 | free(dri2_reply); 639 | 640 | return TRUE; 641 | } 642 | 643 | const struct dri_backend_funcs dri2_funcs = { 644 | .name = "dri2", 645 | .probe = dri2_probe, 646 | .create = dri2_create, 647 | .destroy = dri2_destroy, 648 | .init = dri2_init, 649 | .deinit = dri2_deinit, 650 | .get_fd = dri2_get_fd, 651 | .window_buffer_from_dmabuf = dri2_window_buffer_from_dmabuf, 652 | .copy_front = dri2_copy_front, 653 | .present_pixmap = dri2_present_pixmap, 654 | .destroy_pixmap = dri2_destroy_pixmap, 655 | }; 656 | #endif 657 | -------------------------------------------------------------------------------- /d3d9-nine/dri3.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Wine DRI3 interface 4 | * 5 | * Copyright 2014-2015 Axel Davy 6 | * Copyright 2015 Patrick Rudolph 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../common/debug.h" 17 | #include "backend.h" 18 | #include "xcb_present.h" 19 | 20 | struct dri3_priv { 21 | Display *dpy; 22 | int screen; 23 | int fd; 24 | }; 25 | 26 | static BOOL dri3_create(Display *dpy, int screen, struct dri_backend_priv **priv) 27 | { 28 | struct dri3_priv *p; 29 | xcb_dri3_open_cookie_t cookie; 30 | xcb_dri3_open_reply_t *reply; 31 | xcb_connection_t *xcb_connection = XGetXCBConnection(dpy); 32 | int fd; 33 | Window root = RootWindow(dpy, screen); 34 | 35 | cookie = xcb_dri3_open(xcb_connection, root, 0); 36 | 37 | reply = xcb_dri3_open_reply(xcb_connection, cookie, NULL); 38 | if (!reply) 39 | return FALSE; 40 | 41 | if (reply->nfd != 1) 42 | { 43 | free(reply); 44 | return FALSE; 45 | } 46 | 47 | fd = xcb_dri3_open_reply_fds(xcb_connection, reply)[0]; 48 | fcntl(fd, F_SETFD, FD_CLOEXEC); 49 | 50 | free(reply); 51 | 52 | p = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct dri3_priv)); 53 | if (!p) 54 | { 55 | close(fd); 56 | return FALSE; 57 | } 58 | 59 | p->dpy = dpy; 60 | p->screen = screen; 61 | p->fd = fd; 62 | 63 | *priv = (struct dri_backend_priv *)p; 64 | 65 | return TRUE; 66 | } 67 | 68 | static void dri3_destroy(struct dri_backend_priv *priv) 69 | { 70 | struct dri3_priv *p = (struct dri3_priv *)priv; 71 | 72 | close(p->fd); 73 | 74 | HeapFree(GetProcessHeap(), 0, p); 75 | } 76 | 77 | static BOOL dri3_init(struct dri_backend_priv *priv) 78 | { 79 | return TRUE; 80 | } 81 | 82 | static void dri3_deinit(struct dri_backend_priv *priv) 83 | { 84 | } 85 | 86 | static int dri3_get_fd(struct dri_backend_priv *priv) 87 | { 88 | struct dri3_priv *p = (struct dri3_priv *)priv; 89 | 90 | return p->fd; 91 | } 92 | 93 | static BOOL dri3_window_buffer_from_dmabuf(struct dri_backend_priv *priv, 94 | PRESENTpriv *present_priv, int fd, int width, int height, 95 | int stride, int depth, int bpp, struct D3DWindowBuffer **out) 96 | { 97 | struct dri3_priv *p = (struct dri3_priv *)priv; 98 | Pixmap pixmap; 99 | xcb_connection_t *xcb_connection = XGetXCBConnection(p->dpy); 100 | Window root = RootWindow(p->dpy, p->screen); 101 | xcb_void_cookie_t cookie; 102 | xcb_generic_error_t *error; 103 | 104 | TRACE("present_priv=%p dmaBufFd=%d\n", present_priv, fd); 105 | 106 | if (!out) 107 | goto err; 108 | 109 | *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 110 | sizeof(struct D3DWindowBuffer)); 111 | if (!*out) 112 | goto err; 113 | 114 | cookie = xcb_dri3_pixmap_from_buffer_checked(xcb_connection, 115 | (pixmap = xcb_generate_id(xcb_connection)), root, 0, 116 | width, height, stride, depth, bpp, fd); 117 | 118 | error = xcb_request_check(xcb_connection, cookie); /* performs a flush */ 119 | if (error) 120 | { 121 | ERR("Error using DRI3 to convert a DmaBufFd to pixmap\n"); 122 | goto err; 123 | } 124 | 125 | if (!PRESENTPixmapInit(present_priv, pixmap, &((*out)->present_pixmap_priv))) 126 | { 127 | ERR("PRESENTPixmapInit failed\n"); 128 | HeapFree(GetProcessHeap(), 0, *out); 129 | return FALSE; 130 | } 131 | 132 | return TRUE; 133 | 134 | err: 135 | ERR("dri3_window_buffer_from_dmabuf failed\n"); 136 | if (out) 137 | HeapFree(GetProcessHeap(), 0, *out); 138 | return FALSE; 139 | } 140 | 141 | static BOOL dri3_copy_front(PRESENTPixmapPriv *present_pixmap_priv) 142 | { 143 | return PRESENTHelperCopyFront(present_pixmap_priv); 144 | } 145 | 146 | static BOOL dri3_present_pixmap(struct dri_backend_priv *priv, struct buffer_priv *buffer_priv) 147 | { 148 | return TRUE; 149 | } 150 | 151 | static void dri3_destroy_pixmap(struct dri_backend_priv *priv, struct buffer_priv *buffer_priv) 152 | { 153 | } 154 | 155 | static BOOL dri3_probe(Display *dpy) 156 | { 157 | xcb_connection_t *xcb_connection = XGetXCBConnection(dpy); 158 | xcb_dri3_query_version_cookie_t dri3_cookie; 159 | xcb_dri3_query_version_reply_t *dri3_reply; 160 | xcb_generic_error_t *error; 161 | const xcb_query_extension_reply_t *extension; 162 | const int major = 1; 163 | const int minor = 0; 164 | 165 | xcb_prefetch_extension_data(xcb_connection, &xcb_dri3_id); 166 | 167 | extension = xcb_get_extension_data(xcb_connection, &xcb_dri3_id); 168 | if (!(extension && extension->present)) 169 | { 170 | WARN("DRI3 extension is not present\n"); 171 | return FALSE; 172 | } 173 | 174 | dri3_cookie = xcb_dri3_query_version(xcb_connection, major, minor); 175 | 176 | dri3_reply = xcb_dri3_query_version_reply(xcb_connection, dri3_cookie, &error); 177 | if (!dri3_reply) 178 | { 179 | free(error); 180 | WARN("Issue getting requested v%d.%d of DRI3\n", major, minor); 181 | return FALSE; 182 | } 183 | 184 | TRACE("DRI3 v%d.%d found, v%d.%d requested\n", major, minor, 185 | (int)dri3_reply->major_version, (int)dri3_reply->minor_version); 186 | free(dri3_reply); 187 | 188 | return TRUE; 189 | } 190 | 191 | const struct dri_backend_funcs dri3_funcs = { 192 | .name = "dri3", 193 | .probe = dri3_probe, 194 | .create = dri3_create, 195 | .destroy = dri3_destroy, 196 | .init = dri3_init, 197 | .deinit = dri3_deinit, 198 | .get_fd = dri3_get_fd, 199 | .window_buffer_from_dmabuf = dri3_window_buffer_from_dmabuf, 200 | .copy_front = dri3_copy_front, 201 | .present_pixmap = dri3_present_pixmap, 202 | .destroy_pixmap = dri3_destroy_pixmap, 203 | }; 204 | -------------------------------------------------------------------------------- /d3d9-nine/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | 3 | d3d9_res = custom_target( 4 | 'version.res', 5 | input : 'version.rc', 6 | output : 'version.res', 7 | command : wrc, 8 | ) 9 | 10 | d3d9_dll = shared_library( 11 | 'd3d9-nine.dll', 12 | [ 13 | 'backend.c', 14 | 'd3d9_main.c', 15 | 'd3dadapter9.c', 16 | 'device_wrap.c', 17 | 'dri2.c', 18 | 'dri3.c', 19 | 'present.c', 20 | 'shader_validator.c', 21 | 'wndproc.c', 22 | 'xcb_present.c', 23 | d3d9_res, 24 | ], 25 | name_prefix : '', 26 | link_with : [ 27 | libd3d9common, 28 | ], 29 | dependencies : [ 30 | dep_d3dadapter9, 31 | dep_dl, 32 | dep_x11, 33 | dep_x11_xcb, 34 | dep_xcb, 35 | dep_xcb_dri2, 36 | dep_xcb_dri3, 37 | dep_xcb_present, 38 | dep_xcb_xfixes, 39 | dep_gl, 40 | dep_egl, 41 | dep_dxguid, 42 | dep_uuid, 43 | dep_advapi32, 44 | dep_user32, 45 | ], 46 | install : true, 47 | vs_module_defs : 'd3d9.spec', 48 | objects : 'd3d9.spec', 49 | ) 50 | 51 | d3d9_fake = shared_library( 52 | 'd3d9-nine', 53 | [ 54 | d3d9_res, 55 | ], 56 | name_prefix : '', 57 | name_suffix : 'dll.fake', 58 | install : true, 59 | ) 60 | -------------------------------------------------------------------------------- /d3d9-nine/present.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Wine present interface 4 | * 5 | * Copyright 2015 Patrick Rudolph 6 | */ 7 | 8 | #ifndef __NINE_PRESENT_H 9 | #define __NINE_PRESENT_H 10 | 11 | #include 12 | #include 13 | 14 | struct dri_backend; 15 | 16 | HRESULT present_create_present_group(Display *gdi_display, const WCHAR *device_name, 17 | HWND focus, D3DPRESENT_PARAMETERS *params, unsigned nparams, ID3DPresentGroup **group, 18 | boolean ex, DWORD BehaviorFlags, struct dri_backend *dri_backend); 19 | 20 | HRESULT present_create_adapter9(Display *gdi_display, HDC hdc, 21 | struct dri_backend *dri_backend, ID3DAdapter9 **adapter); 22 | 23 | BOOL present_has_d3dadapter(Display *gdi_display); 24 | 25 | BOOL enable_device_vtable_wrapper(void); 26 | 27 | #endif /* __NINE_PRESENT_H */ 28 | -------------------------------------------------------------------------------- /d3d9-nine/shader_validator.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Direct3D 9 ShaderValidator 4 | * 5 | * Copyright 2016 Patrick Rudolph 6 | */ 7 | 8 | #include 9 | 10 | #include "../common/debug.h" 11 | #include "shader_validator.h" 12 | 13 | static HRESULT WINAPI IDirect3DShaderValidator9Impl_QueryInterface(IDirect3DShaderValidator9Impl *This, 14 | REFIID riid, LPVOID* ppobj) 15 | { 16 | /* TODO: AddRef(iface). */ 17 | *ppobj = This; 18 | TRACE("This=%p, riid=%s, object=%p.\n", This, nine_dbgstr_guid(riid), ppobj); 19 | 20 | return S_OK; 21 | } 22 | 23 | static ULONG WINAPI IDirect3DShaderValidator9Impl_AddRef(IDirect3DShaderValidator9Impl *This) 24 | { 25 | ULONG ref = InterlockedIncrement(&This->ref); 26 | TRACE("This=%p increasing refcount to %u.\n", This, (UINT)ref); 27 | 28 | return ref; 29 | } 30 | 31 | static ULONG WINAPI IDirect3DShaderValidator9Impl_Release(IDirect3DShaderValidator9Impl *This) 32 | { 33 | ULONG ref = InterlockedDecrement(&This->ref); 34 | TRACE("This=%p decreasing refcount to %u.\n", This, (UINT)ref); 35 | 36 | if (ref == 0) 37 | HeapFree(GetProcessHeap(), 0, This); 38 | 39 | return ref; 40 | } 41 | 42 | static LONG WINAPI IDirect3DShaderValidator9Impl_Begin(IDirect3DShaderValidator9Impl *This, 43 | void* callback, void* unknown1, ULONG unknown2) 44 | { 45 | TRACE("This=%p, callback=%p, unknown1=%p, unknown2=%u\n", 46 | This, callback, unknown1, (UINT)unknown2); 47 | return 1; 48 | } 49 | 50 | static LONG WINAPI IDirect3DShaderValidator9Impl_Instruction(IDirect3DShaderValidator9Impl *This, 51 | const char* unknown1, unsigned int unknown2, const unsigned long* unknown3, unsigned int unknown4) 52 | { 53 | TRACE("This=%p, unknown1=%p, unknown2=%u, unknown3=%p, unknown4=%u\n", 54 | This, unknown1, unknown2, unknown3, unknown4); 55 | return 1; 56 | } 57 | 58 | static LONG WINAPI IDirect3DShaderValidator9Impl_End(IDirect3DShaderValidator9Impl *This) 59 | { 60 | TRACE("This=%p\n", This); 61 | return 1; 62 | } 63 | 64 | const void *IDirect3DShaderValidator9Vtbl[] = 65 | { 66 | /* IUnknown */ 67 | IDirect3DShaderValidator9Impl_QueryInterface, 68 | IDirect3DShaderValidator9Impl_AddRef, 69 | IDirect3DShaderValidator9Impl_Release, 70 | /* IDirect3DShaderValidator9 */ 71 | IDirect3DShaderValidator9Impl_Begin, 72 | IDirect3DShaderValidator9Impl_Instruction, 73 | IDirect3DShaderValidator9Impl_End 74 | }; 75 | 76 | -------------------------------------------------------------------------------- /d3d9-nine/shader_validator.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Direct3D 9 ShaderValidator 4 | * 5 | * Copyright 2016 Patrick Rudolph 6 | */ 7 | 8 | #ifndef __NINE_SHADER_VALIDATOR_H 9 | #define __NINE_SHADER_VALIDATOR_H 10 | 11 | #include 12 | 13 | typedef struct IDirect3DShaderValidator9Impl 14 | { 15 | /* IUnknown fields */ 16 | void *lpVtbl; 17 | LONG ref; 18 | } IDirect3DShaderValidator9Impl; 19 | 20 | extern const void *IDirect3DShaderValidator9Vtbl[6]; 21 | 22 | #endif /* __NINE_SHADER_VALIDATOR_H */ 23 | -------------------------------------------------------------------------------- /d3d9-nine/version.rc: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Copyright 2015 Patrick Rudolph 4 | */ 5 | 6 | #include 7 | 8 | VS_VERSION_INFO VERSIONINFO 9 | FILEVERSION NINE_MAJOR,NINE_MINOR,NINE_BUILD,NINE_REVISION 10 | PRODUCTVERSION NINE_MAJOR,NINE_MINOR,NINE_BUILD,NINE_REVISION 11 | FILEFLAGSMASK 63 12 | FILEFLAGS 0 13 | FILEOS VOS_UNKNOWN 14 | FILETYPE VFT_DLL 15 | FILESUBTYPE VFT2_UNKNOWN 16 | { 17 | BLOCK "StringFileInfo" 18 | { 19 | /* LANG_ENGLISH/SUBLANG_DEFAULT, CP1200 (Unicode) */ 20 | BLOCK "0409" "04B0" 21 | { 22 | VALUE "CompanyName", "" 23 | VALUE "FileDescription", "Wine Gallium Nine Direct3D" 24 | VALUE "FileVersion", NINE_VERSION 25 | VALUE "InternalName", "" 26 | VALUE "LegalCopyright", "" 27 | VALUE "OriginalFilename", "d3d9-nine.dll" 28 | VALUE "ProductName", "Wine" 29 | VALUE "ProductVersion", NINE_VERSION 30 | } 31 | } 32 | BLOCK "VarFileInfo" 33 | { 34 | /* LANG_ENGLISH/SUBLANG_DEFAULT, CP1200 (Unicode) */ 35 | VALUE "Translation", 0x0409, 0x04B0 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /d3d9-nine/wndproc.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Copyright 2016 Patrick Rudolph 4 | * 5 | * Based on the file wined3d_main.c taken from wined3d: 6 | * All credits go to the original developers: 7 | * 8 | * Copyright 2002-2003 The wine-d3d team 9 | * Copyright 2002-2003 Raphael Junqueira 10 | * Copyright 2004 Jason Edmeades 11 | * Copyright 2007-2008 Stefan Dösinger for CodeWeavers 12 | * Copyright 2009 Henri Verbeet for CodeWeavers 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "../common/debug.h" 21 | #include "wndproc.h" 22 | 23 | struct nine_wndproc 24 | { 25 | HWND window; 26 | BOOL unicode; 27 | WNDPROC proc; 28 | struct DRIPresent *present; 29 | }; 30 | 31 | struct nine_wndproc_table 32 | { 33 | struct nine_wndproc *entries; 34 | unsigned int count; 35 | unsigned int size; 36 | }; 37 | 38 | static struct nine_wndproc_table wndproc_table; 39 | 40 | static CRITICAL_SECTION nine_wndproc_cs; 41 | static CRITICAL_SECTION_DEBUG nine_wndproc_cs_debug = 42 | { 43 | 0, 0, &nine_wndproc_cs, 44 | {&nine_wndproc_cs_debug.ProcessLocksList, 45 | &nine_wndproc_cs_debug.ProcessLocksList}, 46 | 0, 0, {/*(DWORD_PTR)(__FILE__ ": nine_wndproc_cs")*/} 47 | }; 48 | static CRITICAL_SECTION nine_wndproc_cs = {&nine_wndproc_cs_debug, -1, 0, 0, 0, 0}; 49 | 50 | BOOL nine_dll_init(HINSTANCE hInstDLL) 51 | { 52 | DisableThreadLibraryCalls(hInstDLL); 53 | 54 | return TRUE; 55 | } 56 | 57 | BOOL nine_dll_destroy(HINSTANCE hInstDLL) 58 | { 59 | unsigned int i; 60 | 61 | for (i = 0; i < wndproc_table.count; ++i) 62 | { 63 | /* Trying to unregister these would be futile. These entries can only 64 | * exist if either we skipped them in nine_unregister_window() due 65 | * to the application replacing the wndproc after the entry was 66 | * registered, or if the application still has an active nine 67 | * device. In the latter case the application has bigger problems than 68 | * these entries. */ 69 | WARN("Leftover wndproc table entry %p.\n", &wndproc_table.entries[i]); 70 | } 71 | 72 | HeapFree(GetProcessHeap(), 0, wndproc_table.entries); 73 | 74 | DeleteCriticalSection(&nine_wndproc_cs); 75 | 76 | return TRUE; 77 | } 78 | 79 | static void nine_wndproc_mutex_lock(void) 80 | { 81 | EnterCriticalSection(&nine_wndproc_cs); 82 | } 83 | 84 | static void nine_wndproc_mutex_unlock(void) 85 | { 86 | LeaveCriticalSection(&nine_wndproc_cs); 87 | } 88 | 89 | static struct nine_wndproc *nine_find_wndproc(HWND window) 90 | { 91 | unsigned int i; 92 | 93 | for (i = 0; i < wndproc_table.count; ++i) 94 | { 95 | if (wndproc_table.entries[i].window == window) 96 | { 97 | return &wndproc_table.entries[i]; 98 | } 99 | } 100 | 101 | return NULL; 102 | } 103 | 104 | static LRESULT CALLBACK nine_wndproc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) 105 | { 106 | struct nine_wndproc *entry; 107 | struct DRIPresent *present; 108 | BOOL unicode; 109 | WNDPROC proc; 110 | 111 | nine_wndproc_mutex_lock(); 112 | entry = nine_find_wndproc(window); 113 | 114 | if (!entry) 115 | { 116 | nine_wndproc_mutex_unlock(); 117 | ERR("Window %p is not registered with nine.\n", window); 118 | return DefWindowProcW(window, message, wparam, lparam); 119 | } 120 | 121 | present = entry->present; 122 | unicode = entry->unicode; 123 | proc = entry->proc; 124 | nine_wndproc_mutex_unlock(); 125 | 126 | if (present) 127 | return device_process_message(present, window, unicode, message, wparam, lparam, proc); 128 | if (unicode) 129 | return CallWindowProcW(proc, window, message, wparam, lparam); 130 | return CallWindowProcA(proc, window, message, wparam, lparam); 131 | } 132 | 133 | BOOL nine_register_window(HWND window, struct DRIPresent *present) 134 | { 135 | struct nine_wndproc *entry; 136 | 137 | nine_wndproc_mutex_lock(); 138 | 139 | if (nine_find_wndproc(window)) 140 | { 141 | nine_wndproc_mutex_unlock(); 142 | WARN("Window %p is already registered with nine.\n", window); 143 | return TRUE; 144 | } 145 | 146 | if (wndproc_table.size == wndproc_table.count) 147 | { 148 | unsigned int new_size = max(1, wndproc_table.size * 2); 149 | struct nine_wndproc *new_entries; 150 | 151 | if (!wndproc_table.entries) new_entries = HeapAlloc(GetProcessHeap(), 0, new_size * sizeof(*new_entries)); 152 | else new_entries = HeapReAlloc(GetProcessHeap(), 0, wndproc_table.entries, new_size * sizeof(*new_entries)); 153 | 154 | if (!new_entries) 155 | { 156 | nine_wndproc_mutex_unlock(); 157 | ERR("Failed to grow table.\n"); 158 | return FALSE; 159 | } 160 | 161 | wndproc_table.entries = new_entries; 162 | wndproc_table.size = new_size; 163 | } 164 | 165 | entry = &wndproc_table.entries[wndproc_table.count++]; 166 | entry->window = window; 167 | entry->unicode = IsWindowUnicode(window); 168 | /* Set a window proc that matches the window. Some applications (e.g. NoX) 169 | * replace the window proc after we've set ours, and expect to be able to 170 | * call the previous one (ours) directly, without using CallWindowProc(). */ 171 | if (entry->unicode) 172 | entry->proc = (WNDPROC)SetWindowLongPtrW(window, GWLP_WNDPROC, (LONG_PTR)nine_wndproc); 173 | else 174 | entry->proc = (WNDPROC)SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)nine_wndproc); 175 | entry->present = present; 176 | 177 | nine_wndproc_mutex_unlock(); 178 | 179 | return TRUE; 180 | } 181 | 182 | BOOL nine_unregister_window(HWND window) 183 | { 184 | struct nine_wndproc *entry, *last; 185 | LONG_PTR proc; 186 | 187 | nine_wndproc_mutex_lock(); 188 | 189 | if (!(entry = nine_find_wndproc(window))) 190 | { 191 | nine_wndproc_mutex_unlock(); 192 | return FALSE; 193 | } 194 | 195 | if (entry->unicode) 196 | { 197 | proc = GetWindowLongPtrW(window, GWLP_WNDPROC); 198 | if (proc != (LONG_PTR)nine_wndproc) 199 | { 200 | entry->present = NULL; 201 | nine_wndproc_mutex_unlock(); 202 | WARN("Not unregistering window %p, window proc %#lx doesn't match nine window proc %p.\n", 203 | window, proc, nine_wndproc); 204 | return FALSE; 205 | } 206 | 207 | SetWindowLongPtrW(window, GWLP_WNDPROC, (LONG_PTR)entry->proc); 208 | } 209 | else 210 | { 211 | proc = GetWindowLongPtrA(window, GWLP_WNDPROC); 212 | if (proc != (LONG_PTR)nine_wndproc) 213 | { 214 | entry->present = NULL; 215 | nine_wndproc_mutex_unlock(); 216 | WARN("Not unregistering window %p, window proc %#lx doesn't match nine window proc %p.\n", 217 | window, proc, nine_wndproc); 218 | return FALSE; 219 | } 220 | 221 | SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)entry->proc); 222 | } 223 | 224 | last = &wndproc_table.entries[--wndproc_table.count]; 225 | if (entry != last) *entry = *last; 226 | 227 | nine_wndproc_mutex_unlock(); 228 | return TRUE; 229 | } 230 | -------------------------------------------------------------------------------- /d3d9-nine/wndproc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Direct3D wine internal interface main 4 | * 5 | * Copyright 2002-2003 The wine-d3d team 6 | * Copyright 2002-2003 Raphael Junqueira 7 | * Copyright 2004 Jason Edmeades 8 | * Copyright 2007-2008 Stefan Dösinger for CodeWeavers 9 | * Copyright 2009 Henri Verbeet for CodeWeavers 10 | */ 11 | 12 | #ifndef __NINE_WNDPROC_H 13 | #define __NINE_WNDPROC_H 14 | 15 | #include 16 | 17 | struct DRIPresent; 18 | 19 | BOOL nine_register_window(HWND window, struct DRIPresent *present); 20 | BOOL nine_unregister_window(HWND window); 21 | 22 | BOOL nine_dll_init(HINSTANCE hInstDLL); 23 | BOOL nine_dll_destroy(HINSTANCE hInstDLL); 24 | 25 | LRESULT device_process_message(struct DRIPresent *present, HWND window, BOOL unicode, 26 | UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc); 27 | 28 | #endif /* __NINE_WNDPROC_H */ 29 | -------------------------------------------------------------------------------- /d3d9-nine/xcb_present.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Wine XCB PRESENT interface 4 | * 5 | * Copyright 2014 Axel Davy 6 | * Copyright 2019 Patrick Rudolph 7 | */ 8 | 9 | #ifndef __NINE_XCB_PRESENT_H 10 | #define __NINE_XCB_PRESENT_H 11 | 12 | #include 13 | #include 14 | 15 | LONG PRESENTGetNewSerial(void); 16 | 17 | BOOL PRESENTCheckExtension(Display *dpy, int major, int minor); 18 | 19 | typedef struct PRESENTPriv PRESENTpriv; 20 | typedef struct PRESENTPixmapPriv PRESENTPixmapPriv; 21 | 22 | BOOL PRESENTInit(Display *dpy, PRESENTpriv **present_priv); 23 | 24 | /* will clean properly and free all PRESENTPixmapPriv associated to PRESENTpriv. 25 | * PRESENTPixmapPriv should not be freed by something else. 26 | * If never a PRESENTPixmapPriv has to be destroyed, 27 | * please destroy the current PRESENTpriv and create a new one. 28 | * This will take care than all pixmaps are released */ 29 | void PRESENTDestroy(PRESENTpriv *present_priv); 30 | 31 | BOOL PRESENTGetGeom(PRESENTpriv *present_priv, XID window, int *width, int *height, int *depth); 32 | BOOL PRESENTGeomUpdated(PRESENTpriv *present_priv); 33 | 34 | BOOL PRESENTPixmapCreate(PRESENTpriv *present_priv, int screen, 35 | Pixmap *pixmap, int width, int height, int stride, int depth, 36 | int bpp); 37 | 38 | BOOL PRESENTPixmapInit(PRESENTpriv *present_priv, Pixmap pixmap, PRESENTPixmapPriv **present_pixmap_priv); 39 | 40 | BOOL PRESENTTryFreePixmap(PRESENTPixmapPriv *present_pixmap_priv); 41 | 42 | BOOL PRESENTHelperCopyFront(PRESENTPixmapPriv *present_pixmap_priv); 43 | 44 | BOOL PRESENTPixmapPrepare(XID window, PRESENTPixmapPriv *present_pixmap_priv); 45 | 46 | BOOL PRESENTPixmap(XID window, PRESENTPixmapPriv *present_pixmap_priv, 47 | const UINT PresentationInterval, const BOOL PresentAsync, const BOOL SwapEffectCopy, 48 | const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion); 49 | 50 | BOOL PRESENTWaitPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv); 51 | 52 | BOOL PRESENTIsPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv); 53 | 54 | BOOL PRESENTWaitReleaseEvent(PRESENTpriv *present_priv); 55 | 56 | #endif /* __NINE_XCB_PRESENT_H */ 57 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | 3 | project( 4 | 'Gallium Nine Standalone', 5 | ['c'], 6 | version : run_command( 7 | find_program('tools/get_version.sh', native : true), 8 | check : true, 9 | ).stdout(), 10 | license : 'LGPL2.1+', 11 | meson_version : '>= 0.46', 12 | default_options : [ 13 | 'buildtype=debugoptimized', 14 | 'b_ndebug=if-release', 15 | ], 16 | ) 17 | 18 | project_url = 'https://github.com/iXit/wine-nine-standalone' 19 | 20 | cc = meson.get_compiler('c', native : false) 21 | find_program(cc.cmd_array()[0], native : false) 22 | 23 | null_dep = dependency('', required : false) 24 | 25 | pp_args = [ 26 | # undefine winegcc's mingw compatiblity macros, x11-xcb and egl get confused 27 | '-U_WIN32', '-U__WIN32', '-U__WIN32__', '-U__WINNT', '-U__WINNT__', 28 | '-D_GNU_SOURCE', 29 | '-DWIN32_LEAN_AND_MEAN', 30 | '-DDECLSPEC_HOTPATCH=__attribute__((__ms_hook_prologue__))', 31 | '-DNINE_VERSION="v' + meson.project_version() + '"', 32 | '-DNINE_URL="' + project_url + '"', 33 | ] 34 | 35 | code = '''#ifndef __WINE__ 36 | #error 1 37 | #endif''' 38 | 39 | if not cc.compiles(code, name: 'winegcc check') 40 | error('A WINE cross compiler is required') 41 | endif 42 | 43 | if not cc.has_header_symbol('windows.h', 'wine_get_unix_file_name') 44 | error('WINE headers not found') 45 | endif 46 | 47 | version = meson.project_version().split('-')[0].split('.') 48 | wrc = [ 49 | find_program('wrc'), 50 | '-DNINE_MAJOR=' + version[0], 51 | '-DNINE_MINOR=' + version[1], 52 | '-DNINE_BUILD=' + version[2], 53 | '-DNINE_REVISION=' + version[3], 54 | '-DNINE_VERSION="v' + meson.project_version() + '"', 55 | '-DNINE_PROJECT="' + meson.project_name() + '"', 56 | '-i', '@INPUT@', 57 | '-o', '@OUTPUT@', 58 | ] 59 | 60 | if cc.has_function('dlopen') 61 | dep_dl = null_dep 62 | else 63 | dep_dl = cc.find_library('dl') 64 | endif 65 | 66 | foreach fn : ['dlopen', 'dlclose', 'dlsym', 'dladdr'] 67 | if not cc.has_function(fn, dependencies : dep_dl) 68 | error(fn + ' is required') 69 | endif 70 | endforeach 71 | 72 | dep_d3dadapter9 = dependency('d3d', required : false) 73 | if not dep_d3dadapter9.found() 74 | message('trying alternative name for d3d...') 75 | dep_d3dadapter9 = dependency('d3dadapter9') 76 | endif 77 | 78 | dep_x11 = dependency('x11') 79 | dep_x11_xcb = dependency('x11-xcb') 80 | dep_xcb = dependency('xcb') 81 | dep_xcb_dri3 = dependency('xcb-dri3') 82 | dep_xcb_present = dependency('xcb-present') 83 | dep_xcb_xfixes = dependency('xcb-xfixes') 84 | 85 | dep_gl = null_dep 86 | dep_egl = null_dep 87 | dep_xcb_dri2 = null_dep 88 | _dri2 = get_option('dri2') 89 | if _dri2 != 'false' 90 | dep_gl = dependency('gl', required : _dri2 == 'true') 91 | dep_egl = dependency('egl', required : _dri2 == 'true') 92 | dep_xcb_dri2 = dependency('xcb-dri2', required: _dri2 == 'true') 93 | if dep_gl.found() and dep_egl.found() and dep_xcb_dri2.found() 94 | dep_gl = dep_gl.partial_dependency(includes : true) 95 | dep_egl = dep_egl.partial_dependency(includes : true) 96 | pp_args += '-DD3D9NINE_DRI2=1' 97 | message('DRI2 support is enabled') 98 | else 99 | warning('DRI2 support disabled, dependencies not found') 100 | endif 101 | else 102 | message('DRI2 support is disabled') 103 | endif 104 | 105 | dep_dxguid = cc.find_library('dxguid') 106 | dep_uuid = cc.find_library('uuid') 107 | dep_advapi32 = cc.find_library('advapi32') 108 | dep_gdi32 = cc.find_library('gdi32') 109 | dep_user32 = cc.find_library('user32') 110 | dep_shell32 = cc.find_library('shell32') 111 | dep_comctl32 = cc.find_library('comctl32') 112 | dep_ole32 = cc.find_library('ole32') 113 | 114 | moduledir = dep_d3dadapter9.get_pkgconfig_variable('moduledir') 115 | 116 | _distroindependent = get_option('distro-independent') 117 | if (not _distroindependent) and (moduledir == '') 118 | error('no d3dadapter9.so.1 default module path available') 119 | endif 120 | 121 | if _distroindependent 122 | message('distro independent build') 123 | else 124 | message('d3dadapter9.so.1 default module path: ' + moduledir) 125 | pp_args += '-DD3D9NINE_MODULEPATH="' + moduledir + '"' 126 | endif 127 | 128 | foreach arg : pp_args 129 | add_project_arguments(arg, language : ['c']) 130 | endforeach 131 | 132 | subdir('common') 133 | subdir('d3d9-nine') 134 | subdir('ninewinecfg') 135 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | 3 | option( 4 | 'dri2', 5 | type : 'combo', 6 | value : 'auto', 7 | choices : ['auto', 'true', 'false'], 8 | description : 'enable DRI2 support', 9 | ) 10 | 11 | option( 12 | 'distro-independent', 13 | type : 'boolean', 14 | value : 'false', 15 | description : 'find d3dadapter9.so.1 at runtime at known distro library directories', 16 | ) 17 | -------------------------------------------------------------------------------- /ninewinecfg/main.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * NineWineCfg main entry point 4 | * 5 | * Copyright 2002 Jaco Greeff 6 | * Copyright 2003 Dimitrie O. Paun 7 | * Copyright 2003 Mike Hearn 8 | * Copyright 2017 Patrick Rudolph 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "../common/debug.h" 27 | #include "../common/library.h" 28 | #include "../common/registry.h" 29 | #include "resource.h" 30 | 31 | static const char * const fn_nine_dll = "d3d9-nine.dll"; 32 | static const char * const fn_backup_dll = "d3d9-nine.bak"; 33 | static const char * const fn_d3d9_dll = "d3d9.dll"; 34 | static const char * const fn_nine_exe = "ninewinecfg.exe"; 35 | 36 | static BOOL isWin64(void) 37 | { 38 | return sizeof(void*) == 8; 39 | } 40 | 41 | static BOOL isWoW64(void) 42 | { 43 | BOOL is_wow64; 44 | 45 | return IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64; 46 | } 47 | 48 | static DWORD executeCmdline(LPSTR cmdline) 49 | { 50 | STARTUPINFOA si; 51 | PROCESS_INFORMATION pi; 52 | DWORD exit_code; 53 | 54 | ZeroMemory( &si, sizeof(si) ); 55 | si.cb = sizeof(si); 56 | ZeroMemory( &pi, sizeof(pi) ); 57 | 58 | TRACE("Executing cmdline '%s'\n", cmdline); 59 | 60 | if (!CreateProcessA(NULL, cmdline, NULL, NULL, 61 | FALSE, 0, NULL, NULL, &si, &pi )) 62 | { 63 | ERR("CreateProcessA failed, error=%d\n", (int)GetLastError()); 64 | return ~0u; 65 | } 66 | 67 | if (WaitForSingleObject( pi.hProcess, INFINITE ) != WAIT_OBJECT_0) 68 | { 69 | ERR("WaitForSingleObject failed, error=%d\n", (int)GetLastError()); 70 | return ~0u; 71 | } 72 | 73 | if (!GetExitCodeProcess( pi.hProcess, &exit_code )) 74 | { 75 | ERR("GetExitCodeProcess failed, error=%d\n", (int)GetLastError()); 76 | return ~0u; 77 | } 78 | 79 | TRACE("Exit code: %u\n", (UINT)exit_code); 80 | 81 | return exit_code; 82 | } 83 | 84 | static BOOL Call32bitNineWineCfg(BOOL state) 85 | { 86 | CHAR buf[MAX_PATH + 6]; 87 | 88 | if (!GetSystemWow64DirectoryA(buf, sizeof(buf))) 89 | return FALSE; 90 | 91 | strcat(buf, "\\"); 92 | strcat(buf, fn_nine_exe); 93 | 94 | if (state) 95 | strcat(buf, " -e -n"); 96 | else 97 | strcat(buf, " -d -n"); 98 | 99 | return executeCmdline(buf) == 0; 100 | } 101 | 102 | static BOOL Call64bitNineWineCfg(BOOL state) 103 | { 104 | void *redir; 105 | CHAR buf[MAX_PATH + 6]; 106 | BOOL res; 107 | 108 | Wow64DisableWow64FsRedirection( &redir ); 109 | 110 | if (!GetSystemDirectoryA((LPSTR)buf, sizeof(buf))) 111 | return FALSE; 112 | 113 | strcat(buf, "\\"); 114 | strcat(buf, fn_nine_exe); 115 | 116 | if (state) 117 | strcat(buf, " -e -n"); 118 | else 119 | strcat(buf, " -d -n"); 120 | 121 | res = executeCmdline(buf) == 0; 122 | 123 | Wow64RevertWow64FsRedirection( redir ); 124 | 125 | return res; 126 | } 127 | 128 | static char *unix_filename(const LPCSTR filename) 129 | { 130 | int len; 131 | WCHAR *filename_w; 132 | char *filename_u; 133 | 134 | len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0); 135 | filename_w = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 136 | if (!filename_w) 137 | return NULL; 138 | 139 | MultiByteToWideChar(CP_ACP, 0, filename, -1, filename_w, len); 140 | 141 | filename_u = wine_get_unix_file_name(filename_w); 142 | 143 | HeapFree(GetProcessHeap(), 0, filename_w); 144 | 145 | return filename_u; 146 | } 147 | 148 | static BOOL file_exist(LPCSTR filename, BOOL link) 149 | { 150 | BOOL ret; 151 | char *fn = unix_filename(filename); 152 | struct stat sb; 153 | 154 | if (!fn) 155 | return FALSE; 156 | 157 | if (link) 158 | ret = !lstat(fn, &sb); 159 | else 160 | ret = !stat(fn, &sb); 161 | 162 | TRACE("%s: %d (%d)\n", nine_dbgstr_a(fn), ret, link); 163 | 164 | HeapFree(GetProcessHeap(), 0, fn); 165 | 166 | return ret; 167 | } 168 | 169 | static BOOL rename_file(LPCSTR OldPath, LPCSTR NewPath) 170 | { 171 | BOOL ret; 172 | char *src = unix_filename(OldPath); 173 | if (!src) 174 | return FALSE; 175 | 176 | char *dst = unix_filename(NewPath); 177 | if (!dst) 178 | { 179 | HeapFree(GetProcessHeap(), 0, src); 180 | return FALSE; 181 | } 182 | 183 | if (!rename(src, dst)) 184 | { 185 | ret = TRUE; 186 | TRACE("Renamed from %s to %s\n", nine_dbgstr_a(src), 187 | nine_dbgstr_a(dst)); 188 | } else { 189 | ret = FALSE; 190 | ERR("Failed to rename from %s to %s\n", nine_dbgstr_a(src), 191 | nine_dbgstr_a(dst)); 192 | } 193 | 194 | HeapFree(GetProcessHeap(), 0, src); 195 | HeapFree(GetProcessHeap(), 0, dst); 196 | 197 | return ret; 198 | } 199 | 200 | static BOOL remove_file(LPCSTR filename) 201 | { 202 | BOOL ret; 203 | char *fn = unix_filename(filename); 204 | 205 | if (!fn) 206 | return FALSE; 207 | 208 | if (!unlink(fn)) 209 | { 210 | ret = TRUE; 211 | TRACE("Removed %s\n", nine_dbgstr_a(fn)); 212 | } else { 213 | ret = FALSE; 214 | ERR("Failed to remove %s\n", nine_dbgstr_a(fn)); 215 | } 216 | 217 | HeapFree(GetProcessHeap(), 0, fn); 218 | 219 | return ret; 220 | } 221 | 222 | static BOOL create_symlink(LPCSTR target, LPCSTR filename) 223 | { 224 | BOOL ret; 225 | char *fn = unix_filename(filename); 226 | 227 | if (!fn) 228 | return FALSE; 229 | 230 | if (!symlink(target, fn)) 231 | { 232 | TRACE("Symlinked '%s' to '%s'\n", nine_dbgstr_a(fn), 233 | nine_dbgstr_a(target)); 234 | ret = TRUE; 235 | } else { 236 | ERR("Failed to symlinked '%s' to '%s'\n", nine_dbgstr_a(fn), 237 | nine_dbgstr_a(target)); 238 | ret = FALSE; 239 | } 240 | 241 | HeapFree(GetProcessHeap(), 0, fn); 242 | 243 | return ret; 244 | } 245 | 246 | static BOOL is_nine_symlink(LPCSTR filename) 247 | { 248 | ssize_t ret; 249 | char *fn = unix_filename(filename); 250 | CHAR buf[MAX_PATH]; 251 | 252 | if (!fn) 253 | return FALSE; 254 | 255 | ret = readlink(fn, buf, sizeof(buf)); 256 | if ((ret < strlen(fn_nine_dll)) || (ret == sizeof(buf))) 257 | return FALSE; 258 | 259 | buf[ret] = 0; 260 | return !strcmp(buf + ret - strlen(fn_nine_dll), fn_nine_dll); 261 | } 262 | 263 | static BOOL nine_get_system_path(CHAR *pOut, DWORD SizeOut) 264 | { 265 | if (isWoW64()) 266 | { 267 | return !!GetSystemWow64DirectoryA((LPSTR)pOut, SizeOut); 268 | } 269 | else 270 | { 271 | return !!GetSystemDirectoryA((LPSTR)pOut, SizeOut); 272 | } 273 | } 274 | 275 | /* 276 | * Winecfg 277 | */ 278 | static LPWSTR load_message(DWORD id) 279 | { 280 | LPWSTR msg = NULL; 281 | FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM 282 | | FORMAT_MESSAGE_ALLOCATE_BUFFER 283 | | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, id, 284 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 285 | (LPWSTR)&msg, 0, NULL); 286 | return msg; 287 | } 288 | 289 | static WCHAR *load_string (UINT id) 290 | { 291 | WCHAR buf[1024]; 292 | int len; 293 | WCHAR* newStr; 294 | 295 | len = LoadStringW (GetModuleHandleW(NULL), id, buf, sizeof(buf)/sizeof(buf[0])); 296 | if (len < 1) 297 | return NULL; 298 | 299 | newStr = HeapAlloc (GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR)); 300 | memcpy (newStr, buf, len * sizeof (WCHAR)); 301 | newStr[len] = 0; 302 | 303 | return newStr; 304 | } 305 | 306 | static void set_dlg_string(HWND hwnd, int dlg_id, int res_id) 307 | { 308 | WCHAR *s = load_string(res_id); 309 | SetDlgItemTextW(hwnd, dlg_id, s); 310 | HeapFree(GetProcessHeap(), 0, s); 311 | } 312 | 313 | /* 314 | * Gallium nine 315 | */ 316 | static BOOL nine_registry_enabled(void) 317 | { 318 | BOOL ret = FALSE; 319 | LPSTR value; 320 | 321 | if (common_get_registry_string(reg_path_dll_overrides, reg_key_d3d9, &value)) 322 | { 323 | ret = !strcmp(value, reg_value_override); 324 | HeapFree(GetProcessHeap(), 0, value); 325 | } 326 | 327 | return ret; 328 | } 329 | 330 | static BOOL nine_get(void) 331 | { 332 | CHAR buf[MAX_PATH]; 333 | 334 | if (!nine_registry_enabled()) 335 | return FALSE; 336 | 337 | if (!nine_get_system_path(buf, sizeof(buf))) 338 | { 339 | ERR("Failed to get system path\n"); 340 | return FALSE; 341 | } 342 | strcat(buf, "\\"); 343 | strcat(buf, fn_d3d9_dll); 344 | 345 | return is_nine_symlink(buf) && file_exist(buf, FALSE); 346 | } 347 | 348 | static void nine_set(BOOL status, BOOL NoOtherArch) 349 | { 350 | CHAR dst[MAX_PATH], dst_back[MAX_PATH]; 351 | 352 | /* Prevent infinite recursion if called from other arch already */ 353 | if (!NoOtherArch) 354 | { 355 | /* Started as 64bit, call 32bit process */ 356 | if (isWin64()) 357 | Call32bitNineWineCfg(status); 358 | /* Started as 32bit, call 64bit process */ 359 | else if (isWoW64()) 360 | Call64bitNineWineCfg(status); 361 | } 362 | 363 | /* Delete unused DllRedirects key */ 364 | common_del_registry_key(reg_path_dll_redirects, reg_key_d3d9); 365 | 366 | /* enable native dll */ 367 | if (!status) 368 | { 369 | if (!common_del_registry_key(reg_path_dll_overrides, reg_key_d3d9)) 370 | ERR("Failed to delete 'HKCU\\%s\\%s'\n'", reg_path_dll_overrides, reg_key_d3d9); 371 | } 372 | else 373 | { 374 | if (!common_set_registry_string(reg_path_dll_overrides, reg_key_d3d9, reg_value_override)) 375 | ERR("Failed to write 'HKCU\\%s\\%s'\n", reg_path_dll_overrides, reg_key_d3d9); 376 | } 377 | 378 | if (!nine_get_system_path(dst, sizeof(dst))) { 379 | ERR("Failed to get system path\n"); 380 | return; 381 | } 382 | strcat(dst, "\\"); 383 | strcpy(dst_back, dst); 384 | strcat(dst, fn_d3d9_dll); 385 | strcat(dst_back, fn_backup_dll); 386 | 387 | if (status) 388 | { 389 | HMODULE hmod; 390 | 391 | /* Sanity: Always recreate symlink */ 392 | if (file_exist(dst, TRUE)) 393 | { 394 | if (!file_exist(dst_back, TRUE)) 395 | rename_file(dst, dst_back); 396 | else 397 | remove_file(dst); 398 | } 399 | 400 | hmod = LoadLibraryExA(fn_nine_dll, NULL, DONT_RESOLVE_DLL_REFERENCES); 401 | if (hmod) 402 | { 403 | Dl_info info; 404 | 405 | if (dladdr(hmod, &info) && info.dli_fname) 406 | create_symlink(info.dli_fname, dst); 407 | else 408 | ERR("dladdr failed to get file path\n"); 409 | 410 | FreeLibrary(hmod); 411 | } else { 412 | LPWSTR msg = load_message(GetLastError()); 413 | ERR("Couldn't load %s: %s\n", fn_nine_dll, nine_dbgstr_w(msg)); 414 | LocalFree(msg); 415 | } 416 | } else { 417 | if (is_nine_symlink(dst)) 418 | { 419 | remove_file(dst); 420 | if (file_exist(dst_back, TRUE)) 421 | rename_file(dst_back, dst); 422 | } 423 | } 424 | } 425 | 426 | typedef HRESULT (WINAPI *LPDIRECT3DCREATE9EX)(UINT, IDirect3D9Ex **); 427 | 428 | static void load_settings(HWND dialog) 429 | { 430 | HMODULE hmod = NULL; 431 | char *path = NULL, *err = NULL; 432 | LPDIRECT3DCREATE9EX Direct3DCreate9ExPtr = NULL; 433 | IDirect3D9Ex *iface = NULL; 434 | void *handle; 435 | HRESULT hr; 436 | 437 | EnableWindow(GetDlgItem(dialog, IDC_ENABLE_NATIVE_D3D9), 0); 438 | CheckDlgButton(dialog, IDC_ENABLE_NATIVE_D3D9, nine_get() ? BST_CHECKED : BST_UNCHECKED); 439 | 440 | SetDlgItemTextA(dialog, IDC_NINE_STATE_TIP_SO, NULL); 441 | SetDlgItemTextA(dialog, IDC_NINE_STATE_TIP_DLL, NULL); 442 | SetDlgItemTextA(dialog, IDC_NINE_STATE_TIP_CREATE, NULL); 443 | 444 | set_dlg_string(dialog, IDC_GB_NINE_SETTINGS, IDS_GB_NINE_SETTINGS); 445 | set_dlg_string(dialog, IDC_GB_INSTALL_STATE, IDS_GB_INSTALL_STATE); 446 | set_dlg_string(dialog, IDC_TEXT_MESA_DEP, IDS_TEXT_MESA_DEP); 447 | set_dlg_string(dialog, IDC_TEXT_LOAD_D3DADAPTER, IDS_TEXT_LOAD_D3DADAPTER); 448 | set_dlg_string(dialog, IDC_TEXT_D3D9_NINE_LOAD, IDS_TEXT_D3D9_NINE_LOAD); 449 | set_dlg_string(dialog, IDC_TEXT_CREATE_D3D9_DEV, IDS_TEXT_CREATE_D3D9_DEV); 450 | set_dlg_string(dialog, IDC_ENABLE_NATIVE_D3D9, IDS_BTN_ENABLE_NINE); 451 | 452 | CheckDlgButton(dialog, IDC_NINE_STATE_SO, BST_UNCHECKED); 453 | CheckDlgButton(dialog, IDC_NINE_STATE_DLL, BST_UNCHECKED); 454 | CheckDlgButton(dialog, IDC_NINE_STATE_CREATE, BST_UNCHECKED); 455 | 456 | handle = common_load_d3dadapter(&path, &err); 457 | 458 | if (handle) 459 | { 460 | CheckDlgButton(dialog, IDC_NINE_STATE_SO, BST_CHECKED); 461 | SetDlgItemTextA(dialog, IDC_NINE_STATE_TIP_SO, path); 462 | } 463 | else 464 | { 465 | SetDlgItemTextA(dialog, IDC_NINE_STATE_TIP_SO, err); 466 | goto out; 467 | } 468 | 469 | hmod = LoadLibraryA(fn_nine_dll); 470 | if (hmod) 471 | Direct3DCreate9ExPtr = (LPDIRECT3DCREATE9EX) 472 | GetProcAddress(hmod, "Direct3DCreate9Ex"); 473 | 474 | if (hmod && Direct3DCreate9ExPtr) 475 | { 476 | CheckDlgButton(dialog, IDC_NINE_STATE_DLL, BST_CHECKED); 477 | { 478 | Dl_info info; 479 | 480 | if (dladdr(hmod, &info) && info.dli_fname) 481 | SetDlgItemTextA(dialog, IDC_NINE_STATE_TIP_DLL, info.dli_fname); 482 | else 483 | SetDlgItemTextA(dialog, IDC_NINE_STATE_TIP_DLL, dlerror()); 484 | } 485 | } 486 | else 487 | { 488 | LPWSTR msg = load_message(GetLastError()); 489 | SetDlgItemTextW(dialog, IDC_NINE_STATE_TIP_DLL, msg); 490 | LocalFree(msg); 491 | 492 | goto out; 493 | } 494 | 495 | hr = Direct3DCreate9ExPtr(0, &iface); 496 | if (SUCCEEDED(hr)) 497 | { 498 | IDirect3DDevice9_Release(iface); 499 | CheckDlgButton(dialog, IDC_NINE_STATE_CREATE, BST_CHECKED); 500 | } 501 | else 502 | { 503 | int ids; 504 | 505 | switch (hr) 506 | { 507 | case E_OUTOFMEMORY: 508 | ids = IDS_ERR_OUTOFMEMORY; 509 | break; 510 | case D3DERR_NOTAVAILABLE: 511 | ids = IDS_ERR_D3D_NOTAVAILABLE; 512 | break; 513 | default: 514 | ids = IDS_ERR_UNKNOWN; 515 | break; 516 | } 517 | 518 | set_dlg_string(dialog, IDC_NINE_STATE_TIP_CREATE, ids); 519 | goto out; 520 | } 521 | 522 | EnableWindow(GetDlgItem(dialog, IDC_ENABLE_NATIVE_D3D9), 1); 523 | 524 | out: 525 | if (hmod) 526 | FreeLibrary(hmod); 527 | if (handle) 528 | dlclose(handle); 529 | 530 | free(path); 531 | free(err); 532 | } 533 | 534 | static BOOL nine_probe() 535 | { 536 | HMODULE hmod; 537 | LPDIRECT3DCREATE9EX Direct3DCreate9ExPtr; 538 | IDirect3D9Ex *iface; 539 | HRESULT hr; 540 | 541 | hmod = LoadLibraryA(fn_nine_dll); 542 | if (!hmod) 543 | return FALSE; 544 | 545 | Direct3DCreate9ExPtr = (LPDIRECT3DCREATE9EX)GetProcAddress(hmod, "Direct3DCreate9Ex"); 546 | 547 | if (!Direct3DCreate9ExPtr) 548 | { 549 | FreeLibrary(hmod); 550 | return FALSE; 551 | } 552 | 553 | hr = Direct3DCreate9ExPtr(0, &iface); 554 | if (SUCCEEDED(hr)) 555 | IDirect3DDevice9_Release(iface); 556 | 557 | FreeLibrary(hmod); 558 | return SUCCEEDED(hr); 559 | } 560 | 561 | static BOOL ProcessCmdLine(WCHAR *cmdline, BOOL *result) 562 | { 563 | WCHAR **argv; 564 | int argc, i; 565 | BOOL NoOtherArch = FALSE; 566 | BOOL NineSet = FALSE; 567 | BOOL NineClear = FALSE; 568 | 569 | argv = CommandLineToArgvW(cmdline, &argc); 570 | 571 | if (!argv) 572 | return FALSE; 573 | 574 | if (argc == 1) 575 | { 576 | LocalFree(argv); 577 | return FALSE; 578 | } 579 | 580 | for (i = 1; i < argc; i++) 581 | { 582 | if (argv[i][0] != '/' && argv[i][0] != '-') 583 | break; /* No flags specified. */ 584 | 585 | if (!argv[i][1] && argv[i][0] == '-') 586 | break; /* '-' is a filename. It indicates we should use stdin. */ 587 | 588 | if (argv[i][1] && argv[i][2] && argv[i][2] != ':') 589 | break; /* This is a file path beginning with '/'. */ 590 | 591 | switch (towupper(argv[i][1])) 592 | { 593 | case '?': 594 | case 'H': 595 | ERR("\nSupported arguments: [-p][-e|-d][-n]\n" \ 596 | "\t-p Probe if the current setup is capable of using nine\n" \ 597 | "\t-e Enable nine\n" \ 598 | "\t-d Disable nine\n" \ 599 | "\t-n Do not call other arch exe\n"); 600 | return TRUE; 601 | case 'P': 602 | *result = nine_probe(); 603 | return TRUE; 604 | case 'E': 605 | NineSet = TRUE; 606 | break; 607 | case 'D': 608 | NineClear = TRUE; 609 | break; 610 | case 'N': 611 | NoOtherArch = TRUE; 612 | break; 613 | default: 614 | return FALSE; 615 | } 616 | } 617 | 618 | if (NineSet && !NineClear) 619 | { 620 | nine_set(TRUE, NoOtherArch); 621 | *result = nine_get(); 622 | return TRUE; 623 | } 624 | else if (NineClear && !NineSet) 625 | { 626 | nine_set(FALSE, NoOtherArch); 627 | *result = !nine_get(); 628 | return TRUE; 629 | } 630 | 631 | return FALSE; 632 | } 633 | 634 | static INT_PTR CALLBACK AppDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 635 | { 636 | switch (uMsg) 637 | { 638 | case WM_INITDIALOG: 639 | load_settings(hDlg); 640 | break; 641 | 642 | case WM_COMMAND: 643 | if (HIWORD(wParam) != BN_CLICKED) break; 644 | switch (LOWORD(wParam)) 645 | { 646 | case IDC_ENABLE_NATIVE_D3D9: 647 | nine_set(IsDlgButtonChecked(hDlg, IDC_ENABLE_NATIVE_D3D9) == BST_UNCHECKED, FALSE); 648 | CheckDlgButton(hDlg, IDC_ENABLE_NATIVE_D3D9, nine_get() ? BST_CHECKED : BST_UNCHECKED); 649 | SendMessageW(GetParent(hDlg), PSM_CHANGED, 0, 0); 650 | return TRUE; 651 | } 652 | break; 653 | } 654 | 655 | return FALSE; 656 | } 657 | 658 | static INT_PTR CALLBACK AboutDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 659 | { 660 | switch (uMsg) 661 | { 662 | case WM_INITDIALOG: 663 | set_dlg_string(hDlg, IDC_GB_LICENSE, IDS_GB_LICENSE); 664 | set_dlg_string(hDlg, IDC_GB_AUTHORS, IDS_GB_AUTHORS); 665 | 666 | SetDlgItemTextA(hDlg, IDC_NINE_URL, "" NINE_URL ""); 667 | break; 668 | 669 | case WM_NOTIFY: 670 | switch (((LPNMHDR)lParam)->code) 671 | { 672 | case NM_CLICK: 673 | case NM_RETURN: 674 | if (wParam == IDC_NINE_URL) 675 | ShellExecuteA(NULL, "open", NINE_URL, NULL, NULL, SW_SHOW); 676 | 677 | break; 678 | } 679 | 680 | break; 681 | } 682 | 683 | return FALSE; 684 | } 685 | 686 | static INT_PTR 687 | doPropertySheet (HINSTANCE hInstance, HWND hOwner) 688 | { 689 | PROPSHEETPAGEW psp[2]; 690 | PROPSHEETHEADERW psh; 691 | INT_PTR res; 692 | WCHAR *tab_main = load_string(IDS_TAB_MAIN); 693 | WCHAR *tab_about = load_string(IDS_TAB_ABOUT); 694 | WCHAR *title = load_string(IDS_NINECFG_TITLE); 695 | 696 | psp[0].dwSize = sizeof (PROPSHEETPAGEW); 697 | psp[0].dwFlags = PSP_USETITLE; 698 | psp[0].hInstance = hInstance; 699 | psp[0].pszTemplate = MAKEINTRESOURCEW (IDD_NINE); 700 | psp[0].pszIcon = NULL; 701 | psp[0].pfnDlgProc = AppDlgProc; 702 | psp[0].pszTitle = tab_main; 703 | psp[0].lParam = 0; 704 | 705 | psp[1].dwSize = sizeof (PROPSHEETPAGEW); 706 | psp[1].dwFlags = PSP_USETITLE; 707 | psp[1].hInstance = hInstance; 708 | psp[1].pszTemplate = MAKEINTRESOURCEW (IDD_ABOUT); 709 | psp[1].pszIcon = NULL; 710 | psp[1].pfnDlgProc = AboutDlgProc; 711 | psp[1].pszTitle = tab_about; 712 | psp[1].lParam = 0; 713 | 714 | /* 715 | * Fill out the PROPSHEETHEADER 716 | */ 717 | psh.dwSize = sizeof (PROPSHEETHEADERW); 718 | psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_USECALLBACK | PSH_NOAPPLYNOW; 719 | psh.hwndParent = hOwner; 720 | psh.hInstance = hInstance; 721 | psh.pszIcon = NULL; 722 | psh.pszCaption = title; 723 | psh.nPages = sizeof(psp) / sizeof(psp[0]); 724 | psh.ppsp = psp; 725 | psh.pfnCallback = NULL; 726 | psh.nStartPage = 0; 727 | 728 | /* 729 | * Display the modal property sheet 730 | */ 731 | res = PropertySheetW (&psh); 732 | 733 | HeapFree(GetProcessHeap(), 0, title); 734 | HeapFree(GetProcessHeap(), 0, tab_about); 735 | HeapFree(GetProcessHeap(), 0, tab_main); 736 | 737 | return res; 738 | } 739 | 740 | /***************************************************************************** 741 | * Name : WinMain 742 | * Description: Main windows entry point 743 | * Parameters : hInstance 744 | * hPrev 745 | * szCmdLine 746 | * nShow 747 | * Returns : Program exit code 748 | */ 749 | int WINAPI 750 | WinMain (HINSTANCE hInstance, HINSTANCE hPrev, LPSTR szCmdLine, int nShow) 751 | { 752 | BOOL res = FALSE; 753 | 754 | if (ProcessCmdLine(GetCommandLineW(), &res)) 755 | { 756 | if (!res) 757 | return 1; 758 | 759 | return 0; 760 | } 761 | 762 | /* 763 | * The next 9 lines should be all that is needed 764 | * for the Wine Configuration property sheet 765 | */ 766 | InitCommonControls (); 767 | CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 768 | if (doPropertySheet (hInstance, NULL) > 0) 769 | { 770 | TRACE("OK\n"); 771 | } 772 | else 773 | { 774 | TRACE("Cancel\n"); 775 | } 776 | CoUninitialize(); 777 | ExitProcess (0); 778 | 779 | return 0; 780 | } 781 | -------------------------------------------------------------------------------- /ninewinecfg/meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | 3 | ninewinecfg_res = custom_target( 4 | 'ninewinecfg.res', 5 | input : 'ninewinecfg.rc', 6 | output : 'ninewinecfg.res', 7 | depend_files : [ 8 | 'resource.h', 9 | 'ninewinecfg.manifest', 10 | 'nls/', 11 | ], 12 | command : wrc, 13 | ) 14 | 15 | ninewinecfg_exe = executable( 16 | 'ninewinecfg.exe.so', 17 | [ 18 | 'main.c', 19 | ninewinecfg_res, 20 | ], 21 | gui_app : true, 22 | link_with : [ 23 | libd3d9common, 24 | ], 25 | dependencies : [ 26 | dep_dl, 27 | dep_shell32, 28 | dep_gdi32, 29 | dep_advapi32, 30 | dep_user32, 31 | dep_comctl32, 32 | dep_ole32, 33 | ], 34 | install : true 35 | ) 36 | 37 | ninewinecfg_fake = executable( 38 | 'ninewinecfg', 39 | [ 40 | ninewinecfg_res, 41 | ], 42 | name_prefix : '', 43 | name_suffix : 'exe.fake', 44 | install : true, 45 | ) 46 | -------------------------------------------------------------------------------- /ninewinecfg/ninewinecfg.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ninewinecfg/ninewinecfg.rc: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * WineCfg resources 4 | * 5 | * Copyright 2002 Jaco Greeff 6 | * Copyright 2003 Dimitrie O. Paun 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "resource.h" 15 | 16 | /* filenames are in ISO 639-2 */ 17 | #include "nls/eng.rc" 18 | #include "nls/cze.rc" 19 | #include "nls/deu.rc" 20 | #include "nls/fra.rc" 21 | #include "nls/hun.rc" 22 | #include "nls/jpn.rc" 23 | #include "nls/por.rc" 24 | 25 | IDD_ABOUT DIALOG 0, 0, 260, 196 26 | STYLE WS_CHILD | WS_DISABLED 27 | FONT 8, "MS Shell Dlg" 28 | BEGIN 29 | CTEXT NINE_PROJECT,IDC_STATIC,16,8,228,8 30 | CTEXT NINE_VERSION,IDC_STATIC,16,20,228,8 31 | CONTROL "",IDC_NINE_URL,"SysLink",WS_TABSTOP | LWS_TRANSPARENT,54,32,160,8 32 | 33 | GROUPBOX "",IDC_GB_LICENSE,8,52,244,40 34 | CTEXT "GNU Lesser General Public License, version 2.1",IDC_STATIC,16,64,228,8 35 | CTEXT "MESA: MIT License",IDC_STATIC,16,76,228,8 36 | 37 | GROUPBOX "",IDC_GB_AUTHORS,8,100,244,86 38 | CTEXT "Joakim Sindholt\nChristoph Bumiller\nTiziano Bacocco\nDavid Heidelberg\nAxel Davy\nNick Sarnie\nPatrick Rudolph\nAndre Heider",IDC_STATIC,16,112,228,64 39 | END 40 | 41 | IDD_NINE DIALOG 0, 0, 260, 196 42 | STYLE WS_CHILD | WS_DISABLED 43 | FONT 8, "MS Shell Dlg" 44 | BEGIN 45 | GROUPBOX "",IDC_GB_NINE_SETTINGS,8,8,244,52 46 | LTEXT "",IDC_TEXT_MESA_DEP,16,24,230,16, SS_LEFT | WS_GROUP | BS_VCENTER 47 | CONTROL "",IDC_ENABLE_NATIVE_D3D9,"Button",BS_CHECKBOX | WS_TABSTOP,16,44,230,8 48 | 49 | GROUPBOX "",IDC_GB_INSTALL_STATE,8,66,248,120 50 | 51 | CONTROL "",IDC_NINE_STATE_SO,"Button",BS_CHECKBOX | WS_DISABLED,16,86,10,8 52 | LTEXT "",IDC_TEXT_LOAD_D3DADAPTER,26,86,220,8 53 | LTEXT "Tip",IDC_NINE_STATE_TIP_SO,32,98,210,16 54 | 55 | CONTROL "",IDC_NINE_STATE_DLL,"Button",BS_CHECKBOX | WS_DISABLED,16,118,10,8 56 | LTEXT "",IDC_TEXT_D3D9_NINE_LOAD,26,118,220,8 57 | LTEXT "Tip",IDC_NINE_STATE_TIP_DLL,32,130,210,16 58 | 59 | CONTROL "",IDC_NINE_STATE_CREATE,"Button",BS_CHECKBOX | WS_DISABLED,16,150,10,8 60 | LTEXT "",IDC_TEXT_CREATE_D3D9_DEV,26,150,220,8 61 | LTEXT "Tip",IDC_NINE_STATE_TIP_CREATE,32,162,210,16 62 | END 63 | 64 | LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL 65 | 66 | VS_VERSION_INFO VERSIONINFO 67 | FILEVERSION NINE_MAJOR,NINE_MINOR,NINE_BUILD,NINE_REVISION 68 | PRODUCTVERSION NINE_MAJOR,NINE_MINOR,NINE_BUILD,NINE_REVISION 69 | FILEFLAGSMASK 63 70 | FILEFLAGS 0 71 | FILEOS VOS_UNKNOWN 72 | FILETYPE VFT_APP 73 | FILESUBTYPE VFT2_UNKNOWN 74 | { 75 | BLOCK "StringFileInfo" 76 | { 77 | /* LANG_ENGLISH/SUBLANG_DEFAULT, CP1200 (Unicode) */ 78 | BLOCK "0409" "04B0" 79 | { 80 | VALUE "CompanyName", "" 81 | VALUE "FileDescription", "Wine Gallium Nine Configuration" 82 | VALUE "FileVersion", NINE_VERSION 83 | VALUE "InternalName", "" 84 | VALUE "LegalCopyright", "" 85 | VALUE "OriginalFilename", "ninewinecfg.exe" 86 | VALUE "ProductName", "Wine" 87 | VALUE "ProductVersion", NINE_VERSION 88 | } 89 | } 90 | BLOCK "VarFileInfo" 91 | { 92 | /* LANG_ENGLISH/SUBLANG_DEFAULT, CP1200 (Unicode) */ 93 | VALUE "Translation", 0x0409, 0x04B0 94 | } 95 | } 96 | 97 | 1 RT_MANIFEST ninewinecfg.manifest 98 | -------------------------------------------------------------------------------- /ninewinecfg/nls/cze.rc: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma code_page(65001) /* UTF-8 */ 4 | 5 | STRINGTABLE LANGUAGE LANG_CZECH, SUBLANG_CZECH_CZECH_REPUBLIC 6 | BEGIN 7 | IDS_TAB_MAIN "Globální nastavení" 8 | IDS_TAB_ABOUT "O aplikaci" 9 | 10 | IDS_GB_LICENSE "Licence" 11 | IDS_GB_AUTHORS "Autoři" 12 | IDS_TEXT_MESA_DEP "Gallium Nine vyžaduje grafický ovladač MESA gallium" 13 | 14 | IDS_TEXT_LOAD_D3DADAPTER "Načítání d3d9adapter9 bylo úspěšné" 15 | IDS_TEXT_D3D9_NINE_LOAD "d3d9-nine.dll lze načíst" 16 | IDS_TEXT_CREATE_D3D9_DEV "Direct3D9 zařízení bylo úspěšně vytvořeno" 17 | 18 | IDS_BTN_ENABLE_NINE "Povolit &Gallium Nine pro navýšení grafického výkonu D3D9 aplikací" 19 | 20 | IDS_GB_NINE_SETTINGS "Nastavení Gallium Nine" 21 | IDS_GB_INSTALL_STATE "Stav instalace" 22 | 23 | IDS_NINECFG_TITLE "Konfigurace Gallium Nine" 24 | 25 | IDS_ERR_UNKNOWN "Neznámá chyba" 26 | IDS_ERR_OUTOFMEMORY "Nedostatek paměti" 27 | IDS_ERR_D3D_NOTAVAILABLE "Nenalezena žádná kompatibilní GPU. Na systémech s více GPU může být nutné nejprve nastavit DRI_PRIME=1" 28 | END 29 | 30 | -------------------------------------------------------------------------------- /ninewinecfg/nls/deu.rc: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Copyright 2019 Patrick Rudolph 4 | */ 5 | 6 | #pragma code_page(65001) /* UTF-8 */ 7 | 8 | STRINGTABLE LANGUAGE LANG_GERMAN, SUBLANG_GERMAN 9 | BEGIN 10 | IDS_TAB_MAIN "Globale Einstellungen" 11 | IDS_TAB_ABOUT "Über" 12 | 13 | IDS_GB_LICENSE "Lizenz" 14 | IDS_GB_AUTHORS "Authoren" 15 | IDS_TEXT_MESA_DEP "Gallium Nine benötigt einen kompatiblen MESA Grafiktreiber" 16 | 17 | IDS_TEXT_LOAD_D3DADAPTER "Laden des d3d9adapter9 war erfolgreich" 18 | IDS_TEXT_D3D9_NINE_LOAD "d3d9-nine.dll kann geladen werden" 19 | IDS_TEXT_CREATE_D3D9_DEV "Erzeugen eines Direct3D 9 Geräts war erfolgreich" 20 | 21 | IDS_BTN_ENABLE_NINE "&Gallium Nine für bessere D3D9 Grafikleistung nutzen" 22 | 23 | IDS_GB_NINE_SETTINGS "Gallium Nine Einstellungen" 24 | IDS_GB_INSTALL_STATE "Installationsstatus" 25 | 26 | IDS_NINECFG_TITLE "Nine Konfigurator" 27 | 28 | IDS_ERR_UNKNOWN "Unbekannter Fehler" 29 | IDS_ERR_OUTOFMEMORY "Kein Speicher mehr frei" 30 | IDS_ERR_D3D_NOTAVAILABLE "Keine kompatible GPU gefunden. Auf einem Hybrid-Grafik System kannst du mit DRI_PRIME=1 evt. die zweite GPU verwenden." 31 | END 32 | 33 | -------------------------------------------------------------------------------- /ninewinecfg/nls/eng.rc: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Copyright 2019 Patrick Rudolph 4 | */ 5 | 6 | #pragma code_page(65001) /* UTF-8 */ 7 | 8 | STRINGTABLE LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT 9 | BEGIN 10 | IDS_TAB_MAIN "Global options" 11 | IDS_TAB_ABOUT "About" 12 | 13 | IDS_GB_LICENSE "Licence" 14 | IDS_GB_AUTHORS "Authors" 15 | IDS_TEXT_MESA_DEP "Gallium Nine requires a MESA gallium graphics driver" 16 | 17 | IDS_TEXT_LOAD_D3DADAPTER "Loading of d3d9adapter9 succeeded" 18 | IDS_TEXT_D3D9_NINE_LOAD "d3d9-nine.dll is loadable" 19 | IDS_TEXT_CREATE_D3D9_DEV "Creating a Direct3D 9 device succeeded" 20 | 21 | IDS_BTN_ENABLE_NINE "Enable &Gallium Nine for better D3D9 graphic performance" 22 | 23 | IDS_GB_NINE_SETTINGS "Gallium Nine settings" 24 | IDS_GB_INSTALL_STATE "Install state" 25 | 26 | IDS_NINECFG_TITLE "Nine configuration" 27 | 28 | IDS_ERR_UNKNOWN "Unknown error" 29 | IDS_ERR_OUTOFMEMORY "Out of memory" 30 | IDS_ERR_D3D_NOTAVAILABLE "No compatible GPU found. On a hybrid graphics setup, you might need to set DRI_PRIME=1 first" 31 | END 32 | 33 | -------------------------------------------------------------------------------- /ninewinecfg/nls/fra.rc: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Copyright 2019 Axel Davy 4 | */ 5 | 6 | #pragma code_page(65001) /* UTF-8 */ 7 | 8 | STRINGTABLE LANGUAGE LANG_FRENCH, SUBLANG_FRENCH 9 | BEGIN 10 | IDS_TAB_MAIN "Options globales" 11 | IDS_TAB_ABOUT "À propos" 12 | 13 | IDS_GB_LICENSE "Licence" 14 | IDS_GB_AUTHORS "Auteurs" 15 | IDS_TEXT_MESA_DEP "Gallium Nine nécessite un pilote graphique Mesa avec l'interface gallium" 16 | 17 | IDS_TEXT_LOAD_D3DADAPTER "Succès du chargement de d3d9adapter9" 18 | IDS_TEXT_D3D9_NINE_LOAD "d3d9-nine.dll peut être chargé" 19 | IDS_TEXT_CREATE_D3D9_DEV "Succès de la création de l'interface Direct3D 9" 20 | 21 | IDS_BTN_ENABLE_NINE "Activer &Gallium Nine pour de meilleures performances Direct3D 9" 22 | 23 | IDS_GB_NINE_SETTINGS "Paramètres de Gallium Nine" 24 | IDS_GB_INSTALL_STATE "Status d'installation" 25 | 26 | IDS_NINECFG_TITLE "Configuration de Gallium Nine" 27 | 28 | IDS_ERR_UNKNOWN "Erreur inconnue" 29 | IDS_ERR_OUTOFMEMORY "Allocation de mémoire échouée" 30 | IDS_ERR_D3D_NOTAVAILABLE "Aucun GPU compatible trouvé. Sur un système multi-gpu, essayez DRI_PRIME=1" 31 | END 32 | 33 | -------------------------------------------------------------------------------- /ninewinecfg/nls/hun.rc: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma code_page(65001) /* UTF-8 */ 4 | 5 | STRINGTABLE LANGUAGE LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY 6 | BEGIN 7 | IDS_TAB_MAIN "Globális beállítások" 8 | IDS_TAB_ABOUT "Rólunk" 9 | 10 | IDS_GB_LICENSE "Licensz" 11 | IDS_GB_AUTHORS "Szerzők" 12 | IDS_TEXT_MESA_DEP "A Gallium Nine futtatásához egy MESA gallium graphics driverre van szükség" 13 | IDS_TEXT_LOAD_D3DADAPTER "A d3d9adapter9 betöltése sikeres" 14 | IDS_TEXT_D3D9_NINE_LOAD "d3d9-nine.dll betölthető" 15 | IDS_TEXT_CREATE_D3D9_DEV "Direct3D 9 eszköz létrehozása sikeres" 16 | 17 | IDS_BTN_ENABLE_NINE "Engedélyezi a &Gallium Nine-t a jobb D3D9 grafikus teljesítményhez" 18 | 19 | IDS_GB_NINE_SETTINGS "Gallium Nine beállítások" 20 | IDS_GB_INSTALL_STATE "Telepítés állapota" 21 | 22 | IDS_NINECFG_TITLE "Nine konfiguráció" 23 | 24 | IDS_ERR_UNKNOWN "Ismeretlen hiba" 25 | IDS_ERR_OUTOFMEMORY "Elfogyott a memória" 26 | IDS_ERR_D3D_NOTAVAILABLE "Nem található kompatibilits GPU. Hibrid grafika esetén érdemes megpróbálni a DRI_PRIME=1 környezeti változó beállítását." 27 | END 28 | -------------------------------------------------------------------------------- /ninewinecfg/nls/jpn.rc: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Copyright 2019 Masanori Kakura 4 | */ 5 | 6 | #pragma code_page(65001) /* UTF-8 */ 7 | 8 | STRINGTABLE LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT 9 | BEGIN 10 | IDS_TAB_MAIN "全体設定" 11 | IDS_TAB_ABOUT "情報" 12 | 13 | IDS_GB_LICENSE "ライセンス" 14 | IDS_GB_AUTHORS "作者" 15 | IDS_TEXT_MESA_DEP "Gallium Nine は MESA gallium グラフィックス ドライバを必要とします" 16 | 17 | IDS_TEXT_LOAD_D3DADAPTER "d3d9adapter9 の読み込みに成功" 18 | IDS_TEXT_D3D9_NINE_LOAD "d3d9-nine.dll が読み込み可能" 19 | IDS_TEXT_CREATE_D3D9_DEV "Direct3D 9 デバイスの作成に成功" 20 | 21 | IDS_BTN_ENABLE_NINE "Gallium Nine を有効にして D3D9 のグラフィック パフォーマンスを向上させる(&G)" 22 | 23 | IDS_GB_NINE_SETTINGS "Gallium Nine の設定" 24 | IDS_GB_INSTALL_STATE "インストールの状態" 25 | 26 | IDS_NINECFG_TITLE "Nine 設定" 27 | 28 | IDS_ERR_UNKNOWN "不明なエラーです" 29 | IDS_ERR_OUTOFMEMORY "メモリ確保に失敗しました" 30 | IDS_ERR_D3D_NOTAVAILABLE "対応する GPU が見つかりません。ハイブリッド グラフィックス構成の場合、まず DRI_PRIME=1 を試してください" 31 | END 32 | 33 | -------------------------------------------------------------------------------- /ninewinecfg/nls/por.rc: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma code_page(65001) /* UTF-8 */ 4 | 5 | STRINGTABLE LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE 6 | BEGIN 7 | IDS_TAB_MAIN "Opções globais" 8 | IDS_TAB_ABOUT "Sobre" 9 | 10 | IDS_GB_LICENSE "Licença" 11 | IDS_GB_AUTHORS "Autores" 12 | IDS_TEXT_MESA_DEP "Gallium Nine requer um driver gráfico MESA gallium" 13 | 14 | IDS_TEXT_LOAD_D3DADAPTER "O carregamento do d3d9adapter9 foi bem-sucedido" 15 | IDS_TEXT_D3D9_NINE_LOAD "d3d9-nine.dll pode ser carregado" 16 | IDS_TEXT_CREATE_D3D9_DEV "Criação de dispositivo Direct3D 9 foi bem-sucedida" 17 | 18 | IDS_BTN_ENABLE_NINE "Ative &Gallium Nine para melhor desempenho gráfico D3D9" 19 | 20 | IDS_GB_NINE_SETTINGS "Configurações do Gallium Nine" 21 | IDS_GB_INSTALL_STATE "Status de instalação" 22 | 23 | IDS_NINECFG_TITLE "Configuração do Nine" 24 | 25 | IDS_ERR_UNKNOWN "Erro desconhecido" 26 | IDS_ERR_OUTOFMEMORY "Sem memória" 27 | IDS_ERR_D3D_NOTAVAILABLE "Nenhuma GPU compatível foi encontrada. Em um sistema com múltiplas GPUs, tente usar DRI_PRIME=1" 28 | END 29 | 30 | -------------------------------------------------------------------------------- /ninewinecfg/resource.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | /* 3 | * Ninewinecfg resource definitions 4 | * 5 | * Copyright 2017 Patrick Rudolph 6 | */ 7 | 8 | #ifndef __NINECFG_RESOURCE_H 9 | #define __NINECFG_RESOURCE_H 10 | 11 | #define IDC_STATIC -1 12 | #define IDS_TAB_MAIN 1 13 | #define IDS_TAB_ABOUT 2 14 | 15 | #define IDS_NINECFG_TITLE 4 16 | #define IDS_NINECFG_NINE_SUPPORT_NOT_COMPILED 6 17 | 18 | #define IDS_GB_LICENSE 7 19 | #define IDS_GB_AUTHORS 8 20 | #define IDS_TEXT_MESA_DEP 9 21 | 22 | #define IDS_TEXT_LOAD_D3DADAPTER 10 23 | #define IDS_TEXT_D3D9_NINE_LOAD 11 24 | #define IDS_TEXT_CREATE_D3D9_DEV 12 25 | 26 | #define IDS_BTN_ENABLE_NINE 13 27 | 28 | #define IDS_GB_NINE_SETTINGS 14 29 | #define IDS_GB_INSTALL_STATE 15 30 | 31 | #define IDD_NINE 30 32 | #define IDC_ENABLE_NATIVE_D3D9 31 33 | 34 | #define IDC_NINE_STATE_SO 32 35 | #define IDC_NINE_STATE_DLL 33 36 | #define IDC_NINE_STATE_CREATE 34 37 | 38 | #define IDC_NINE_STATE_TIP_SO 35 39 | #define IDC_NINE_STATE_TIP_DLL 36 40 | #define IDC_NINE_STATE_TIP_CREATE 37 41 | 42 | #define IDC_GB_LICENSE 38 43 | #define IDC_GB_AUTHORS 39 44 | #define IDC_GB_NINE_SETTINGS 40 45 | #define IDC_GB_INSTALL_STATE 41 46 | 47 | #define IDC_TEXT_MESA_DEP 42 48 | #define IDC_TEXT_LOAD_D3DADAPTER 43 49 | #define IDC_TEXT_D3D9_NINE_LOAD 44 50 | #define IDC_TEXT_CREATE_D3D9_DEV 45 51 | 52 | #define IDD_ABOUT 50 53 | #define IDC_NINE_URL 51 54 | 55 | #define IDS_ERR_UNKNOWN 100 56 | #define IDS_ERR_OUTOFMEMORY 101 57 | #define IDS_ERR_D3D_NOTAVAILABLE 102 58 | 59 | #endif /* __NINECFG_RESOURCE_H */ 60 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | 4 | SRC=$(dirname "$(readlink -f "$0")") 5 | OUT=$PWD/gallium-nine-standalone.tar.gz 6 | 7 | while getopts "o:h" opt; do 8 | case "$opt" in 9 | o) 10 | OUT=$OPTARG 11 | ;; 12 | h|\?) 13 | printf "%s [OPTION] [-- MESONARGS]\n" "$0" 14 | printf "\t-o FILE\t\tcreate release as FILE\n" 15 | printf "\t-h\t\tprint this help\n" 16 | printf "\t-- MESONARGS\tpass MESONARGS to meson\n" 17 | exit 1 18 | ;; 19 | esac 20 | done 21 | 22 | shift $((OPTIND - 1)) 23 | 24 | echo "creating $OUT" 25 | echo "additional meson args: $*" 26 | 27 | "$SRC"/bootstrap.sh 28 | 29 | TMP=$(mktemp -d) 30 | PREFIX="$TMP/gallium-nine-standalone" 31 | 32 | meson \ 33 | --cross-file "$SRC/tools/cross-wine64" \ 34 | --buildtype "release" \ 35 | --prefix "$PREFIX" \ 36 | --bindir bin64 \ 37 | --libdir lib64 \ 38 | "$@" \ 39 | "$TMP/build64" 40 | 41 | ninja -C "$TMP/build64" install 42 | 43 | meson \ 44 | --cross-file "$SRC/tools/cross-wine32" \ 45 | --buildtype "release" \ 46 | --prefix "$PREFIX" \ 47 | --bindir bin32 \ 48 | --libdir lib32 \ 49 | "$@" \ 50 | "$TMP/build32" 51 | 52 | ninja -C "$TMP/build32" install 53 | 54 | install -m 644 "$SRC/LICENSE" "$PREFIX/" 55 | install -m 644 "$SRC/README.rst" "$PREFIX/" 56 | install -m 755 "$SRC/tools/nine-install.sh" "$PREFIX/" 57 | tar --owner=nine:1000 --group=nine:1000 -C "$TMP" -czf "$OUT" gallium-nine-standalone 58 | 59 | printf "\nenjoy your release: %s\n" "$OUT" 60 | 61 | exit 0 62 | -------------------------------------------------------------------------------- /tools/.gitignore: -------------------------------------------------------------------------------- 1 | cross-wine32 2 | cross-wine64 3 | -------------------------------------------------------------------------------- /tools/cross-wine32.in: -------------------------------------------------------------------------------- 1 | [binaries] 2 | c = 'winegcc' 3 | ar = 'ar' 4 | strip = 'strip' 5 | pkgconfig = '@PKG_CONFIG@' 6 | 7 | # This throws a deprecation warning, but fixing that breaks CI 8 | [properties] 9 | c_args = ['-m32'] 10 | c_link_args = ['-m32', '-mwindows', '-L@WINE32_LIBDIR@'] 11 | needs_exe_wrapper = true 12 | 13 | [host_machine] 14 | system = 'linux' 15 | cpu_family = 'x86' 16 | cpu = 'i686' 17 | endian = 'little' 18 | -------------------------------------------------------------------------------- /tools/cross-wine64.in: -------------------------------------------------------------------------------- 1 | [binaries] 2 | c = 'winegcc' 3 | ar = 'ar' 4 | strip = 'strip' 5 | pkgconfig = '@PKG_CONFIG@' 6 | 7 | # This throws a deprecation warning, but fixing that breaks CI 8 | [properties] 9 | c_args = ['-m64'] 10 | c_link_args = ['-m64', '-mwindows', '-L@WINE64_LIBDIR@'] 11 | needs_exe_wrapper = true 12 | 13 | [host_machine] 14 | system = 'linux' 15 | cpu_family = 'x86_64' 16 | cpu = 'x86_64' 17 | endian = 'little' 18 | -------------------------------------------------------------------------------- /tools/get_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | MAJOR=0 4 | MINOR=11 5 | BUILD=0 6 | REVISION=$(git rev-list --count HEAD 2>/dev/null || echo "0") 7 | STAGE="devel" 8 | 9 | printf "%s.%s.%s.%s-%s" "$MAJOR" "$MINOR" "$BUILD" "$REVISION" "$STAGE" 10 | 11 | exit 0 12 | -------------------------------------------------------------------------------- /tools/nine-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | BASE=$(dirname "$(readlink -f "$0")") 4 | 5 | die() { 6 | echo "$*" 7 | exit 1 8 | } 9 | 10 | wine --version >/dev/null 2>&1 || die "wine not found" 11 | DST=$(wine winepath -u 'c:\windows\system32') 12 | 13 | echo "installing 32bit binaries to $DST" 14 | ln -sf "$BASE/lib32/d3d9-nine.dll.so" "$DST/d3d9-nine.dll" 15 | ln -sf "$BASE/bin32/ninewinecfg.exe.so" "$DST/ninewinecfg.exe" 16 | 17 | unset HAVE_WINE64 18 | wine64 winepath >/dev/null 2>&1 && HAVE_WINE64=1 19 | 20 | if test -z "$HAVE_WINE64"; then 21 | echo "wine64 not found, skipping 64bit" 22 | echo "enabling gallium nine" 23 | wine ninewinecfg.exe -e 24 | exit 0 25 | fi 26 | 27 | DST=$(wine64 winepath -u 'c:\windows\system32') 28 | 29 | echo "installing 64bit binaries to $DST" 30 | ln -sf "$BASE/lib64/d3d9-nine.dll.so" "$DST/d3d9-nine.dll" 31 | ln -sf "$BASE/bin64/ninewinecfg.exe.so" "$DST/ninewinecfg.exe" 32 | 33 | echo "enabling gallium nine" 34 | wine64 ninewinecfg.exe -e 35 | 36 | echo "done" 37 | exit 0 38 | --------------------------------------------------------------------------------