Ticket #5877: 0ad_changes-for-e2k.patch
File 0ad_changes-for-e2k.patch, 130.3 KB (added by , 3 years ago) |
---|
-
binaries/data/mods/public/gui/credits/texts/programming.json
1 1 { 2 2 "Title": "Programming", 3 3 "Content": [ 4 4 { 5 5 "Title": "Programming managers", 6 6 "List": [ 7 7 { "nick": "Acumen", "name": "Stuart Walpole" }, 8 8 { "nick": "Dak Lozar", "name": "Dave Loeser" }, 9 9 { "nick": "h20", "name": "Daniel Wilhelm" }, 10 10 { "nick": "Janwas", "name": "Jan Wassenberg" }, 11 11 { "nick": "Raj", "name": "Raj Sharma" } 12 12 ] 13 13 }, 14 14 { 15 15 "Subtitle": "Special thanks to", 16 16 "List": [ 17 17 { "nick": "leper", "name": "Georg Kilzer" }, 18 18 { "nick": "Ykkrosh", "name": "Philip Taylor" } 19 19 ] 20 20 }, 21 21 { 22 22 "List": [ 23 23 { "nick": "01d55" }, 24 24 { "nick": "aBothe", "name": "Alexander Bothe" }, 25 25 { "nick": "Acumen", "name": "Stuart Walpole" }, 26 26 { "nick": "adrian", "name": "Adrian Boguszewszki" }, 27 27 { "name": "Adrian Fatol" }, 28 28 { "nick": "AI-Amsterdam" }, 29 29 { "nick": "Alan", "name": "Alan Kemp" }, 30 30 { "nick": "Alex", "name": "Alexander Yakobovich" }, 31 31 { "nick": "alpha123", "name": "Peter P. Cannici" }, 32 32 { "nick": "Ampaex", "name": "Antonio Vazquez" }, 33 33 { "name": "André Puel" }, 34 34 { "nick": "andy5995", "name": "Andy Alt" }, 35 35 { "nick": "Angen" }, 36 36 { "nick": "Arfrever", "name": "Arfrever Frehtes Taifersar Arahesis" }, 37 37 { "nick": "ArnH", "name": "Arno Hemelhof" }, 38 38 { "nick": "Aurium", "name": "Aurélio Heckert" }, 39 39 { "nick": "badmadblacksad", "name": "Martin F" }, 40 40 { "nick": "badosu", "name": "Amadeus Folego" }, 41 41 { "nick": "bb", "name": "Bouke Jansen" }, 42 42 { "nick": "Ben", "name": "Ben Vinegar" }, 43 43 { "nick": "Bird" }, 44 44 { "nick": "Blue", "name": "Richard Welsh" }, 45 45 { "nick": "bmwiedemann" }, 46 46 { "nick": "boeseRaupe", "name": "Michael Kluge" }, 47 47 { "nick": "bog_dan_ro", "name": "BogDan Vatra" }, 48 48 { "nick": "Bonk", "name": "Christopher Ebbert" }, 49 49 { "nick": "Boudica" }, 50 50 { "nick": "Caius", "name": "Lars Kemmann" }, 51 51 { "nick": "Calefaction", "name": "Matt Holmes" }, 52 52 { "nick": "Calvinh", "name": "Carl-Johan Höiby" }, 53 53 { "nick": "causative", "name": "Bart Parkis" }, 54 54 { "name": "Cédric Houbart" }, 55 55 { "nick": "Chakakhan", "name": "Kenny Long" }, 56 56 { "nick": "Clockwork-Muse", "name": "Stephen A. Imhoff" }, 57 57 { "nick": "Cracker78", "name": "Chad Heim" }, 58 58 { "nick": "Crynux", "name": "Stephen J. Fewer" }, 59 59 { "nick": "cwprogger" }, 60 60 { "nick": "cygal", "name": "Quentin Pradet" }, 61 61 { "nick": "Dak Lozar", "name": "Dave Loeser" }, 62 62 { "nick": "dalerank", "name": "Sergey Kushnirenko" }, 63 63 { "nick": "dan", "name": "Dan Strandberg" }, 64 64 { "nick": "DanCar", "name": "Daniel Cardenas" }, 65 65 { "nick": "danger89", "name": "Melroy van den Berg" }, 66 66 { "name": "Daniel Trevitz" }, 67 67 { "nick": "Dariost", "name": "Dario Ostuni" }, 68 68 { "nick": "Dave", "name": "David Protasowski" }, 69 69 { "nick": "dax", "name": "Dacian Fiordean" }, 70 70 { "nick": "deebee", "name": "Deepak Anthony" }, 71 71 { "nick": "Deiz" }, 72 72 { "nick": "Dietger", "name": "Dietger van Antwerpen" }, 73 73 { "nick": "DigitalSeraphim", "name": "Nick Owens" }, 74 74 { "nick": "dp304" }, 75 75 { "nick": "dpiquet", "name": "Damien Piquet" }, 76 76 { "nick": "dumbo" }, 77 77 { "nick": "Dunedan", "name": "Daniel Roschka" }, 78 78 { "nick": "dvangennip", "name": "Doménique" }, 79 79 { "nick": "Echelon9", "name": "Rhys Kidd" }, 80 80 { "nick": "echotangoecho" }, 81 81 { "nick": "eihrul", "name": "Lee Salzman" }, 82 82 { "nick": "elexis", "name": "Alexander Heinsius" }, 83 83 { "nick": "EmjeR", "name": "Matthijs de Rijk" }, 84 84 { "nick": "EMontana" }, 85 85 { "nick": "ericb" }, 86 86 { "nick": "evanssthomas", "name": "Evans Thomas" }, 87 87 { "nick": "Evulant", "name": "Alexander S." }, 88 88 { "nick": "fabio", "name": "Fabio Pedretti" }, 89 89 { "nick": "falsevision", "name": "Mahdi Khodadadifard" }, 90 90 { "nick": "fatherbushido", "name": "Nicolas Tisserand" }, 91 91 { "nick": "fcxSanya", "name": "Alexander Olkhovskiy" }, 92 92 { "nick": "FeXoR", "name": "Florian Finke" }, 93 93 { "nick": "Fire Giant", "name": "Malte Schwarzkopf" }, 94 94 { "name": "Fork AD" }, 95 95 { "nick": "fpre", "name": "Frederick Stallmeyer" }, 96 96 { "nick": "Freagarach" }, 97 97 { "nick": "freenity", "name": "Anton Galitch" }, 98 98 { "nick": "Gallaecio", "name": "Adrián Chaves" }, 99 99 { "nick": "gbish (aka Iny)", "name": "Grant Bishop" }, 100 100 { "nick": "Gee", "name": "Gustav Larsson" }, 101 101 { "nick": "Gentz", "name": "Hal Gentz" }, 102 102 { "nick": "gerbilOFdoom" }, 103 103 { "nick": "godlikeldh" }, 104 104 { "nick": "greybeard", "name": "Joe Cocovich" }, 105 105 { "nick": "grillaz" }, 106 106 { "nick": "Grugnas", "name": "Giuseppe Tranchese" }, 107 107 { "nick": "gudo" }, 108 108 { "nick": "Guuts", "name": "Matthew Guttag" }, 109 109 { "nick": "h20", "name": "Daniel Wilhelm" }, 110 110 { "nick": "Hannibal_Barca", "name": "Clive Juhász S." }, 111 111 { "nick": "Haommin" }, 112 112 { "nick": "happyconcepts", "name": "Ben Bird" }, 113 113 { "nick": "historic_bruno", "name": "Ben Brian" }, 114 114 { "nick": "idanwin" }, 115 115 { "nick": "Imarok", "name": "J. S." }, 116 116 { "nick": "Inari" }, 117 117 { "nick": "infyquest", "name": "Vijay Kiran Kamuju" }, 118 118 { "nick": "irishninja", "name": "Brian Broll" }, 119 119 { "nick": "IronNerd", "name": "Matthew McMullan" }, 120 120 { "nick": "Itms", "name": "Nicolas Auvray" }, 121 121 { "nick": "Jaison", "name": "Marco tom Suden" }, 122 122 { "nick": "jammus", "name": "James Scott" }, 123 123 { "nick": "Janwas", "name": "Jan Wassenberg" }, 124 124 { "nick": "javiergodas", "name": "Javier Godas Vieitez" }, 125 125 { "nick": "Jgwman" }, 126 126 { "nick": "JonBaer", "name": "Jon Baer" }, 127 127 { "nick": "Josh", "name": "Joshua J. Bakita" }, 128 128 { "nick": "joskar", "name": "Johnny Oskarsson" }, 129 129 { "nick": "jP_wanN", "name": "Jonas Platte" }, 130 130 { "nick": "Jubalbarca", "name": "James Baillie" }, 131 131 { "nick": "JubJub", "name": "Sebastian Vetter" }, 132 132 { "nick": "jurgemaister" }, 133 133 { "nick": "kabzerek", "name": "Grzegorz Kabza" }, 134 134 { "nick": "Kai", "name": "Kai Chen" }, 135 135 { "name": "Kareem Ergawy" }, 136 136 { "nick": "kevmo", "name": "Kevin Caffrey" }, 137 137 { "nick": "kezz", "name": "Graeme Kerry" }, 138 138 { "nick": "kingadami", "name": "Adam Winsor" }, 139 139 { "nick": "kingbasil", "name": "Giannis Fafalios" }, 140 140 { "nick": "Krinkle", "name": "Timo Tijhof" }, 141 141 { "nick": "lafferjm", "name": "Justin Lafferty" }, 142 142 { "nick": "LeanderH", "name": "Leander Hemelhof" }, 143 143 { "nick": "leper", "name": "Georg Kilzer" }, 144 144 { "nick": "Link Mauve", "name": "Emmanuel Gil Peyrot" }, 145 145 { "nick": "LittleDev" }, 146 146 { "nick": "livingaftermidnight", "name": "Will Dull" }, 147 147 { "nick": "Louhike" }, 148 148 { "nick": "lsdh" }, 149 149 { "nick": "Ludovic", "name": "Ludovic Rousseau" }, 150 150 { "nick": "luiko", "name": "Luis Carlos Garcia Barajas" }, 151 151 { "nick": "m0l0t0ph", "name": "Christoph Gielisch" }, 152 152 { "nick": "madmax", "name": "Abhijit Nandy" }, 153 153 { "nick": "madpilot", "name": "Guido Falsi" }, 154 154 { "nick": "markcho" }, 155 155 { "nick": "MarkT", "name": "Mark Thompson" }, 156 156 { "nick": "Markus" }, 157 157 { "nick": "Mate-86", "name": "Mate Kovacs" }, 158 158 { "nick": "Matei", "name": "Matei Zaharia" }, 159 159 { "nick": "MattDoerksen", "name": "Matt Doerksen" }, 160 160 { "nick": "mattlott", "name": "Matt Lott" }, 161 161 { "nick": "maveric", "name": "Anton Protko" }, 162 162 { "nick": "Micnasty", "name": "Travis Gorkin" }, 163 163 { "name": "Mikołaj \"Bajter\" Korcz" }, 164 164 { "nick": "mimo" }, 165 165 { "nick": "mk12", "name": "Mitchell Kember" }, 166 166 { "nick": "mmayfield45", "name": "Michael Mayfield" }, 167 167 { "nick": "mmoanis", "name": "Mohamed Moanis" }, 168 168 { "nick": "Molotov", "name": "Dario Alvarez" }, 169 169 { "nick": "mpmoreti", "name": "Marcos Paulo Moreti" }, 170 170 { "nick": "mreiland", "name": "Michael Reiland" }, 171 171 { "nick": "myconid" }, 172 172 { "nick": "nani", "name": "S. N." }, 173 173 { "nick": "nd3c3nt", "name": "Gavin Fowler" }, 174 174 { "nick": "nephele" }, 175 175 { "nick": "Nescio" }, 176 176 { "nick": "niektb", "name": "Niek ten Brinke" }, 177 177 { "nick": "njm" }, 178 178 { "nick": "NoMonkey", "name": "John Mena" }, 179 179 { "nick": "norsnor" }, 180 180 { "nick": "notpete", "name": "Rich Cross" }, 181 181 { "nick": "nwtour" }, 182 182 { "nick": "odoaker", "name": "Ágoston Sipos" }, 183 183 { "nick": "Offensive ePeen", "name": "Jared Ryan Bills" }, 184 184 { "nick": "Ols", "name": "Oliver Whiteman" }, 185 185 { "nick": "olsner", "name": "Simon Brenner" }, 186 186 { "nick": "OptimusShepard", "name": "Pirmin Stanglmeier" }, 187 187 { "nick": "otero" }, 188 188 { "nick": "Palaxin", "name": "David A. Freitag" }, 189 189 { "name": "Paul Withers" }, 190 190 { "nick": "paulobezerr", "name": "Paulo George Gomes Bezerra" }, 191 191 { "nick": "pcpa", "name": "Paulo Andrade" }, 192 192 { "nick": "Pendingchaos" }, 193 193 { "nick": "PeteVasi", "name": "Pete Vasiliauskas" }, 194 194 { "nick": "pilino1234" }, 195 195 { "nick": "PingvinBetyar", "name": "Schronk Tamás" }, 196 196 { "nick": "plugwash", "name": "Peter Michael Green" }, 197 197 { "nick": "Polakrity" }, 198 198 { "nick": "Poya", "name": "Poya Manouchehri" }, 199 199 { "nick": "prefect", "name": "Nicolai Hähnle" }, 200 200 { "nick": "Prodigal Son" }, 201 201 { "nick": "pstumpf", "name": "Pascal Stumpf" }, 202 202 { "nick": "pyrolink", "name": "Andrew Decker" }, 203 203 { "nick": "quantumstate", "name": "Jonathan Waller" }, 204 204 { "nick": "QuickShot", "name": "Walter Krawec" }, 205 205 { "nick": "quonter" }, 206 206 { "nick": "qwertz" }, 207 207 { "nick": "Radagast" }, 208 208 { "nick": "Raj", "name": "Raj Sharma" }, 209 209 { "nick": "ramtzok1", "name": "Ram" }, 210 210 { "nick": "rapidelectron", "name": "Christian Weihsbach" }, 211 { "nick": "r-a-sattarov", "name": "Ramil Sattarov" }, 211 212 { "nick": "RedFox", "name": "Jorma Rebane" }, 212 213 { "nick": "RefinedCode" }, 213 214 { "nick": "Riemer" }, 214 215 { "name": "Rolf Sievers" }, 215 216 { "nick": "s0600204", "name": "Matthew Norwood" }, 216 217 { "nick": "sacha_vrand", "name": "Sacha Vrand" }, 217 218 { "nick": "SafaAlfulaij" }, 218 219 { "name": "Samuel Guarnieri" }, 219 220 { "nick": "Sandarac" }, 220 221 { "nick": "sanderd17", "name": "Sander Deryckere" }, 221 222 { "nick": "sathyam", "name": "Sathyam Vellal" }, 222 223 { "nick": "sbirmi", "name": "Sharad Birmiwal" }, 223 224 { "nick": "sbte", "name": "Sven Baars" }, 224 225 { "nick": "scroogie", "name": "André Gemünd" }, 225 226 { "nick": "scythetwirler", "name": "Casey X." }, 226 227 { "nick": "serveurix" }, 227 228 { "nick": "Shane", "name": "Shane Grant" }, 228 229 { "nick": "shh" }, 229 230 { "nick": "Silk", "name": "Josh Godsiff" }, 230 231 { "nick": "silure" }, 231 232 { "nick": "Simikolon", "name": "Yannick & Simon" }, 232 233 { "nick": "smiley", "name": "M. L." }, 233 234 { "nick": "Spahbod", "name": "Omid Davoodi" }, 234 235 { "nick": "Stan", "name": "Stanislas Dolcini" }, 235 236 { "nick": "Stefan" }, 236 237 { "nick": "StefanBruens", "name": "Stefan Brüns" }, 237 238 { "nick": "stilz", "name": "Sławomir Zborowski" }, 238 239 { "nick": "stwf", "name": "Steven Fuchs" }, 239 240 { "nick": "svott", "name": "Sven Ott" }, 240 241 { "nick": "t4nk004" }, 241 242 { "nick": "tau" }, 242 243 { "nick": "tbm", "name": "Martin Michlmayr" }, 243 244 { "nick": "Teiresias" }, 244 245 { "nick": "temple" }, 245 246 { "nick": "texane" }, 246 247 { "nick": "thamlett", "name": "Timothy Hamlett" }, 247 248 { "nick": "thedrunkyak", "name": "Dan Fuhr" }, 248 249 { "nick": "Tobbi" }, 249 250 { "nick": "TrinityDeath", "name": "Jethro Lu" }, 250 251 { "nick": "triumvir", "name": "Corin Schedler" }, 251 252 { "nick": "trompetin17", "name": "Juan Guillermo" }, 252 253 { "nick": "user1", "name": "A. C." }, 253 254 { "nick": "usey11" }, 254 255 { "nick": "vincent_c", "name": "Vincent Cheng" }, 255 256 { "nick": "vinhig", "name": "Vincent Higginson" }, 256 257 { "nick": "vladislavbelov", "name": "Vladislav Belov" }, 257 258 { "nick": "voroskoi" }, 258 259 { "nick": "vts", "name": "Jeroen DR" }, 259 260 { "nick": "wacko", "name": "Andrew Spiering" }, 260 261 { "nick": "WhiteTreePaladin", "name": "Brian Ashley" }, 261 262 { "nick": "wraitii", "name": "Lancelot de Ferrière le Vayer" }, 262 263 { "nick": "Xentelian", "name": "Mark Strawson" }, 263 264 { "nick": "Xienen", "name": "Dayle Flowers" }, 264 265 { "nick": "xtizer", "name": "Matt Green" }, 265 266 { "nick": "yashi", "name": "Yasushi Shoji" }, 266 267 { "nick": "Ykkrosh", "name": "Philip Taylor" }, 267 268 { "nick": "Yves" }, 268 269 { "nick": "Zeusthor", "name": "Jeffrey Tavares" }, 269 270 { "nick": "zoot" }, 270 271 { "nick": "zsol", "name": "Zsolt Dollenstein" }, 271 272 { "nick": "ztamas", "name": "Tamas Zolnai" }, 272 273 { "nick": "Zyi", "name": "Charles De Meulenaer" } 273 274 ] 274 275 } 275 276 ] 276 277 } -
build/premake/premake5.lua
1 1 newoption { trigger = "android", description = "Use non-working Android cross-compiling mode" } 2 2 newoption { trigger = "atlas", description = "Include Atlas scenario editor projects" } 3 3 newoption { trigger = "coverage", description = "Enable code coverage data collection (GCC only)" } 4 4 newoption { trigger = "gles", description = "Use non-working OpenGL ES 2.0 mode" } 5 5 newoption { trigger = "icc", description = "Use Intel C++ Compiler (Linux only; should use either \"--cc icc\" or --without-pch too, and then set CXX=icpc before calling make)" } 6 6 newoption { trigger = "jenkins-tests", description = "Configure CxxTest to use the XmlPrinter runner which produces Jenkins-compatible output" } 7 7 newoption { trigger = "minimal-flags", description = "Only set compiler/linker flags that are really needed. Has no effect on Windows builds" } 8 8 newoption { trigger = "outpath", description = "Location for generated project files" } 9 9 newoption { trigger = "with-system-mozjs", description = "Search standard paths for libmozjs60, instead of using bundled copy" } 10 10 newoption { trigger = "with-system-nvtt", description = "Search standard paths for nvidia-texture-tools library, instead of using bundled copy" } 11 11 newoption { trigger = "without-audio", description = "Disable use of OpenAL/Ogg/Vorbis APIs" } 12 12 newoption { trigger = "without-lobby", description = "Disable the use of gloox and the multiplayer lobby" } 13 13 newoption { trigger = "without-miniupnpc", description = "Disable use of miniupnpc for port forwarding" } 14 14 newoption { trigger = "without-nvtt", description = "Disable use of NVTT" } 15 15 newoption { trigger = "without-pch", description = "Disable generation and usage of precompiled headers" } 16 16 newoption { trigger = "without-tests", description = "Disable generation of test projects" } 17 17 18 18 -- Linux/BSD specific options 19 19 newoption { trigger = "prefer-local-libs", description = "Prefer locally built libs. Any local libraries used must also be listed within a file within /etc/ld.so.conf.d so the dynamic linker can find them at runtime." } 20 20 21 21 -- OS X specific options 22 22 newoption { trigger = "macosx-bundle", description = "Enable OSX bundle, the argument is the bundle identifier string (e.g. com.wildfiregames.0ad)" } 23 23 newoption { trigger = "macosx-version-min", description = "Set minimum required version of the OS X API, the build will possibly fail if an older SDK is used, while newer API functions will be weakly linked (i.e. resolved at runtime)" } 24 24 newoption { trigger = "sysroot", description = "Set compiler system root path, used for building against a non-system SDK. For example /usr/local becomes SYSROOT/user/local" } 25 25 26 26 -- Windows specific options 27 27 newoption { trigger = "build-shared-glooxwrapper", description = "Rebuild glooxwrapper DLL for Windows. Requires the same compiler version that gloox was built with" } 28 28 newoption { trigger = "use-shared-glooxwrapper", description = "Use prebuilt glooxwrapper DLL for Windows" } 29 29 newoption { trigger = "large-address-aware", description = "Make the executable large address aware. Do not use for development, in order to spot memory issues easily" } 30 30 31 31 -- Install options 32 32 newoption { trigger = "bindir", description = "Directory for executables (typically '/usr/games'); default is to be relocatable" } 33 33 newoption { trigger = "datadir", description = "Directory for data files (typically '/usr/share/games/0ad'); default is ../data/ relative to executable" } 34 34 newoption { trigger = "libdir", description = "Directory for libraries (typically '/usr/lib/games/0ad'); default is ./ relative to executable" } 35 35 36 36 -- Root directory of project checkout relative to this .lua file 37 37 rootdir = "../.." 38 38 39 39 dofile("extern_libs5.lua") 40 40 41 41 -- detect compiler for non-Windows 42 42 if os.istarget("macosx") then 43 43 cc = "clang" 44 44 elseif os.istarget("linux") and _OPTIONS["icc"] then 45 45 cc = "icc" 46 46 elseif not os.istarget("windows") then 47 47 cc = os.getenv("CC") 48 48 if cc == nil or cc == "" then 49 49 local hasgcc = os.execute("which gcc > .gccpath") 50 50 local f = io.open(".gccpath", "r") 51 51 local gccpath = f:read("*line") 52 52 f:close() 53 53 os.execute("rm .gccpath") 54 54 if gccpath == nil then 55 55 cc = "clang" 56 56 else 57 57 cc = "gcc" 58 58 end 59 59 end 60 60 end 61 61 62 62 -- detect CPU architecture (simplistic, currently only supports x86, amd64 and ARM) 63 63 arch = "x86" 64 64 if _OPTIONS["android"] then 65 65 arch = "arm" 66 66 elseif os.istarget("windows") then 67 67 if os.getenv("PROCESSOR_ARCHITECTURE") == "amd64" or os.getenv("PROCESSOR_ARCHITEW6432") == "amd64" then 68 68 arch = "amd64" 69 69 end 70 70 else 71 71 arch = os.getenv("HOSTTYPE") 72 72 if arch == "x86_64" or arch == "amd64" then 73 73 arch = "amd64" 74 74 else 75 75 os.execute(cc .. " -dumpmachine > .gccmachine.tmp") 76 76 local f = io.open(".gccmachine.tmp", "r") 77 77 local machine = f:read("*line") 78 78 f:close() 79 79 if string.find(machine, "x86_64") == 1 or string.find(machine, "amd64") == 1 then 80 80 arch = "amd64" 81 81 elseif string.find(machine, "i.86") == 1 then 82 82 arch = "x86" 83 83 elseif string.find(machine, "arm") == 1 then 84 84 arch = "arm" 85 85 elseif string.find(machine, "aarch64") == 1 then 86 86 arch = "aarch64" 87 elseif string.find(machine, "e2k") == 1 then 88 arch = "e2k" 87 89 else 88 90 print("WARNING: Cannot determine architecture from GCC, assuming x86") 89 91 end 90 92 end 91 93 end 92 94 93 95 -- Test whether we need to link libexecinfo. 94 96 -- This is mostly the case on musl systems, as well as on BSD systems : only glibc provides the 95 97 -- backtrace symbols we require in the libc, for other libcs we use the libexecinfo library. 96 98 local link_execinfo = false 97 99 if os.istarget("bsd") then 98 100 link_execinfo = true 99 101 elseif os.istarget("linux") then 100 102 local _, link_errorCode = os.outputof(cc .. " ./tests/execinfo.c -o /dev/null") 101 103 if link_errorCode ~= 0 then 102 104 link_execinfo = true 103 105 end 104 106 end 105 107 106 108 -- Set up the Workspace 107 109 workspace "pyrogenesis" 108 110 targetdir(rootdir.."/binaries/system") 109 111 libdirs(rootdir.."/binaries/system") 110 112 if not _OPTIONS["outpath"] then 111 113 error("You must specify the 'outpath' parameter") 112 114 end 113 115 location(_OPTIONS["outpath"]) 114 116 configurations { "Release", "Debug" } 115 117 116 118 source_root = rootdir.."/source/" -- default for most projects - overridden by local in others 117 119 118 120 -- Rationale: projects should not have any additional include paths except for 119 121 -- those required by external libraries. Instead, we should always write the 120 122 -- full relative path, e.g. #include "maths/Vector3d.h". This avoids confusion 121 123 -- ("which file is meant?") and avoids enormous include path lists. 122 124 123 125 124 126 -- projects: engine static libs, main exe, atlas, atlas frontends, test. 125 127 126 128 -------------------------------------------------------------------------------- 127 129 -- project helper functions 128 130 -------------------------------------------------------------------------------- 129 131 130 132 function project_set_target(project_name) 131 133 132 134 -- Note: On Windows, ".exe" is added on the end, on unices the name is used directly 133 135 134 136 local obj_dir_prefix = _OPTIONS["outpath"].."/obj/"..project_name.."_" 135 137 136 138 filter "Debug" 137 139 objdir(obj_dir_prefix.."Debug") 138 140 targetsuffix("_dbg") 139 141 140 142 filter "Release" 141 143 objdir(obj_dir_prefix.."Release") 142 144 143 145 filter { } 144 146 145 147 end 146 148 147 149 148 150 function project_set_build_flags() 149 151 150 152 editandcontinue "Off" 151 153 152 154 if not _OPTIONS["minimal-flags"] then 153 155 symbols "On" 154 156 end 155 157 156 158 if cc ~= "icc" and (os.istarget("windows") or not _OPTIONS["minimal-flags"]) then 157 159 -- adds the -Wall compiler flag 158 160 warnings "Extra" -- this causes far too many warnings/remarks on ICC 159 161 end 160 162 161 163 -- disable Windows debug heap, since it makes malloc/free hugely slower when 162 164 -- running inside a debugger 163 165 if os.istarget("windows") then 164 166 debugenvs { "_NO_DEBUG_HEAP=1" } 165 167 end 166 168 167 169 filter "Debug" 168 170 defines { "DEBUG" } 169 171 170 172 filter "Release" 171 173 if os.istarget("windows") or not _OPTIONS["minimal-flags"] then 172 174 optimize "Speed" 173 175 end 174 176 defines { "NDEBUG", "CONFIG_FINAL=1" } 175 177 176 178 filter { } 177 179 178 180 if _OPTIONS["gles"] then 179 181 defines { "CONFIG2_GLES=1" } 180 182 end 181 183 182 184 if _OPTIONS["without-audio"] then 183 185 defines { "CONFIG2_AUDIO=0" } 184 186 end 185 187 186 188 if _OPTIONS["without-nvtt"] then 187 189 defines { "CONFIG2_NVTT=0" } 188 190 end 189 191 190 192 if _OPTIONS["without-lobby"] then 191 193 defines { "CONFIG2_LOBBY=0" } 192 194 end 193 195 194 196 if _OPTIONS["without-miniupnpc"] then 195 197 defines { "CONFIG2_MINIUPNPC=0" } 196 198 end 197 199 198 200 -- required for the lowlevel library. must be set from all projects that use it, otherwise it assumes it is 199 201 -- being used as a DLL (which is currently not the case in 0ad) 200 202 defines { "LIB_STATIC_LINK" } 201 203 202 204 -- Enable C++17 standard. 203 205 filter "action:vs*" 204 206 buildoptions { "/std:c++17" } 205 207 filter "action:not vs*" 206 208 buildoptions { "-std=c++17" } 207 209 filter {} 208 210 209 211 -- various platform-specific build flags 210 212 if os.istarget("windows") then 211 213 212 214 flags { "MultiProcessorCompile" } 213 215 214 216 -- use native wchar_t type (not typedef to unsigned short) 215 217 nativewchar "on" 216 218 217 219 else -- *nix 218 220 219 221 -- TODO, FIXME: This check is incorrect because it means that some additional flags will be added inside the "else" branch if the 220 222 -- compiler is ICC and minimal-flags is specified (ticket: #2994) 221 223 if cc == "icc" and not _OPTIONS["minimal-flags"] then 222 224 buildoptions { 223 225 "-w1", 224 226 -- "-Wabi", 225 227 -- "-Wp64", -- complains about OBJECT_TO_JSVAL which is annoying 226 228 "-Wpointer-arith", 227 229 "-Wreturn-type", 228 230 -- "-Wshadow", 229 231 "-Wuninitialized", 230 232 "-Wunknown-pragmas", 231 233 "-Wunused-function", 232 234 "-wd1292" -- avoid lots of 'attribute "__nonnull__" ignored' 233 235 } 234 236 filter "Debug" 235 237 buildoptions { "-O0" } -- ICC defaults to -O2 236 238 filter { } 237 239 if os.istarget("macosx") then 238 240 linkoptions { "-multiply_defined","suppress" } 239 241 end 240 242 else 241 243 -- exclude most non-essential build options for minimal-flags 242 244 if not _OPTIONS["minimal-flags"] then 243 245 buildoptions { 244 246 -- enable most of the standard warnings 245 247 "-Wno-switch", -- enumeration value not handled in switch (this is sometimes useful, but results in lots of noise) 246 248 "-Wno-reorder", -- order of initialization list in constructors (lots of noise) 247 249 "-Wno-invalid-offsetof", -- offsetof on non-POD types (see comment in renderer/PatchRData.cpp) 248 250 249 251 "-Wextra", 250 252 "-Wno-missing-field-initializers", -- (this is common in external headers we can't fix) 251 253 252 254 -- add some other useful warnings that need to be enabled explicitly 253 255 "-Wunused-parameter", 254 256 "-Wredundant-decls", -- (useful for finding some multiply-included header files) 255 257 -- "-Wformat=2", -- (useful sometimes, but a bit noisy, so skip it by default) 256 258 -- "-Wcast-qual", -- (useful for checking const-correctness, but a bit noisy, so skip it by default) 257 259 "-Wnon-virtual-dtor", -- (sometimes noisy but finds real bugs) 258 260 "-Wundef", -- (useful for finding macro name typos) 259 261 260 262 -- enable security features (stack checking etc) that shouldn't have 261 263 -- a significant effect on performance and can catch bugs 262 264 "-fstack-protector-all", 263 265 "-U_FORTIFY_SOURCE", -- (avoid redefinition warning if already defined) 264 266 "-D_FORTIFY_SOURCE=2", 265 267 266 268 -- always enable strict aliasing (useful in debug builds because of the warnings) 267 269 "-fstrict-aliasing", 268 270 269 271 -- don't omit frame pointers (for now), because performance will be impacted 270 272 -- negatively by the way this breaks profilers more than it will be impacted 271 273 -- positively by the optimisation 272 274 "-fno-omit-frame-pointer" 273 275 } 274 276 275 277 if not _OPTIONS["without-pch"] then 276 278 buildoptions { 277 279 -- do something (?) so that ccache can handle compilation with PCH enabled 278 280 -- (ccache 3.1+ also requires CCACHE_SLOPPINESS=time_macros for this to work) 279 281 "-fpch-preprocess" 280 282 } 281 283 end 282 284 283 285 if os.istarget("linux") or os.istarget("bsd") then 284 286 buildoptions { "-fPIC" } 285 287 linkoptions { "-Wl,--no-undefined", "-Wl,--as-needed", "-Wl,-z,relro" } 286 288 end 287 289 288 290 if arch == "x86" then 289 291 buildoptions { 290 292 -- To support intrinsics like __sync_bool_compare_and_swap on x86 291 293 -- we need to set -march to something that supports them (i686). 292 294 -- We use pentium3 to also enable other features like mmx and sse, 293 295 -- while tuning for generic to have good performance on every 294 296 -- supported CPU. 295 297 -- Note that all these features are already supported on amd64. 296 298 "-march=pentium3 -mtune=generic" 297 299 } 298 300 end 299 301 end 300 302 301 303 if arch == "arm" then 302 304 -- disable warnings about va_list ABI change and use 303 305 -- compile-time flags for futher configuration. 304 306 buildoptions { "-Wno-psabi" } 305 307 if _OPTIONS["android"] then 306 308 -- Android uses softfp, so we should too. 307 309 buildoptions { "-mfloat-abi=softfp" } 308 310 end 309 311 end 310 312 311 313 if _OPTIONS["coverage"] then 312 314 buildoptions { "-fprofile-arcs", "-ftest-coverage" } 313 315 links { "gcov" } 314 316 end 315 317 316 318 -- MacOS 10.12 only supports processors with SSE 4.1, so enable that. 317 319 if os.istarget("macosx") then 318 320 buildoptions { "-msse4.1" } 319 321 end 320 322 321 323 -- Check if SDK path should be used 322 324 if _OPTIONS["sysroot"] then 323 325 buildoptions { "-isysroot " .. _OPTIONS["sysroot"] } 324 326 linkoptions { "-Wl,-syslibroot," .. _OPTIONS["sysroot"] } 325 327 end 326 328 327 329 -- On OS X, sometimes we need to specify the minimum API version to use 328 330 if _OPTIONS["macosx-version-min"] then 329 331 buildoptions { "-mmacosx-version-min=" .. _OPTIONS["macosx-version-min"] } 330 332 -- clang and llvm-gcc look at mmacosx-version-min to determine link target 331 333 -- and CRT version, and use it to set the macosx_version_min linker flag 332 334 linkoptions { "-mmacosx-version-min=" .. _OPTIONS["macosx-version-min"] } 333 335 end 334 336 335 337 -- Check if we're building a bundle 336 338 if _OPTIONS["macosx-bundle"] then 337 339 defines { "BUNDLE_IDENTIFIER=" .. _OPTIONS["macosx-bundle"] } 338 340 end 339 341 340 342 -- Only libc++ is supported on MacOS 341 343 if os.istarget("macosx") then 342 344 buildoptions { "-stdlib=libc++" } 343 345 linkoptions { "-stdlib=libc++" } 344 346 end 345 347 end 346 348 347 349 buildoptions { 348 350 -- Hide symbols in dynamic shared objects by default, for efficiency and for equivalence with 349 351 -- Windows - they should be exported explicitly with __attribute__ ((visibility ("default"))) 350 352 "-fvisibility=hidden" 351 353 } 352 354 353 355 if _OPTIONS["bindir"] then 354 356 defines { "INSTALLED_BINDIR=" .. _OPTIONS["bindir"] } 355 357 end 356 358 if _OPTIONS["datadir"] then 357 359 defines { "INSTALLED_DATADIR=" .. _OPTIONS["datadir"] } 358 360 end 359 361 if _OPTIONS["libdir"] then 360 362 defines { "INSTALLED_LIBDIR=" .. _OPTIONS["libdir"] } 361 363 end 362 364 363 365 if os.istarget("linux") or os.istarget("bsd") then 364 366 if _OPTIONS["prefer-local-libs"] then 365 367 libdirs { "/usr/local/lib" } 366 368 end 367 369 368 370 -- To use our local shared libraries, they need to be found in the 369 371 -- runtime dynamic linker path. Add their path to -rpath. 370 372 if _OPTIONS["libdir"] then 371 373 linkoptions {"-Wl,-rpath," .. _OPTIONS["libdir"] } 372 374 else 373 375 -- On FreeBSD we need to allow use of $ORIGIN 374 376 if os.istarget("bsd") then 375 377 linkoptions { "-Wl,-z,origin" } 376 378 end 377 379 378 380 -- Adding the executable path and taking care of correct escaping 379 381 if _ACTION == "gmake" then 380 382 linkoptions { "-Wl,-rpath,'$$ORIGIN'" } 381 383 elseif _ACTION == "codeblocks" then 382 384 linkoptions { "-Wl,-R\\\\$$$ORIGIN" } 383 385 end 384 386 end 385 387 end 386 388 387 389 end 388 390 end 389 391 390 392 -- create a project and set the attributes that are common to all projects. 391 393 function project_create(project_name, target_type) 392 394 393 395 project(project_name) 394 396 language "C++" 395 397 kind(target_type) 396 398 397 399 filter "action:vs2017" 398 400 toolset "v141_xp" 399 401 filter {} 400 402 401 403 filter "action:vs*" 402 404 buildoptions "/utf-8" 403 405 filter {} 404 406 405 407 project_set_target(project_name) 406 408 project_set_build_flags() 407 409 end 408 410 409 411 410 412 -- OSX creates a .app bundle if the project type of the main application is set to "WindowedApp". 411 413 -- We don't want this because this bundle would be broken (it lacks all the resources and external dependencies, Info.plist etc...) 412 414 -- Windows opens a console in the background if it's set to ConsoleApp, which is not what we want. 413 415 -- I didn't check if this setting matters for linux, but WindowedApp works there. 414 416 function get_main_project_target_type() 415 417 if _OPTIONS["android"] then 416 418 return "SharedLib" 417 419 elseif os.istarget("macosx") then 418 420 return "ConsoleApp" 419 421 else 420 422 return "WindowedApp" 421 423 end 422 424 end 423 425 424 426 425 427 -- source_root: rel_source_dirs and rel_include_dirs are relative to this directory 426 428 -- rel_source_dirs: A table of subdirectories. All source files in these directories are added. 427 429 -- rel_include_dirs: A table of subdirectories to be included. 428 430 -- extra_params: table including zero or more of the following: 429 431 -- * no_pch: If specified, no precompiled headers are used for this project. 430 432 -- * pch_dir: If specified, this directory will be used for precompiled headers instead of the default 431 433 -- <source_root>/pch/<projectname>/. 432 434 -- * extra_files: table of filenames (relative to source_root) to add to project 433 435 -- * extra_links: table of library names to add to link step 434 436 function project_add_contents(source_root, rel_source_dirs, rel_include_dirs, extra_params) 435 437 436 438 for i,v in pairs(rel_source_dirs) do 437 439 local prefix = source_root..v.."/" 438 440 files { prefix.."*.cpp", prefix.."*.h", prefix.."*.inl", prefix.."*.js", prefix.."*.asm", prefix.."*.mm" } 439 441 end 440 442 441 443 -- Put the project-specific PCH directory at the start of the 442 444 -- include path, so '#include "precompiled.h"' will look in 443 445 -- there first 444 446 local pch_dir 445 447 if not extra_params["pch_dir"] then 446 448 pch_dir = source_root .. "pch/" .. project().name .. "/" 447 449 else 448 450 pch_dir = extra_params["pch_dir"] 449 451 end 450 452 includedirs { pch_dir } 451 453 452 454 -- Precompiled Headers 453 455 -- rationale: we need one PCH per static lib, since one global header would 454 456 -- increase dependencies. To that end, we can either include them as 455 457 -- "projectdir/precompiled.h", or add "source/PCH/projectdir" to the 456 458 -- include path and put the PCH there. The latter is better because 457 459 -- many projects contain several dirs and it's unclear where there the 458 460 -- PCH should be stored. This way is also a bit easier to use in that 459 461 -- source files always include "precompiled.h". 460 462 -- Notes: 461 463 -- * Visual Assist manages to use the project include path and can 462 464 -- correctly open these files from the IDE. 463 465 -- * precompiled.cpp (needed to "Create" the PCH) also goes in 464 466 -- the abovementioned dir. 465 467 if (not _OPTIONS["without-pch"] and not extra_params["no_pch"]) then 466 468 filter "action:vs*" 467 469 pchheader("precompiled.h") 468 470 filter "action:xcode*" 469 471 pchheader("../"..pch_dir.."precompiled.h") 470 472 filter { "action:not vs*", "action:not xcode*" } 471 473 pchheader(pch_dir.."precompiled.h") 472 474 filter {} 473 475 pchsource(pch_dir.."precompiled.cpp") 474 476 defines { "CONFIG_ENABLE_PCH=1" } 475 477 files { pch_dir.."precompiled.h", pch_dir.."precompiled.cpp" } 476 478 else 477 479 defines { "CONFIG_ENABLE_PCH=0" } 478 480 flags { "NoPCH" } 479 481 end 480 482 481 483 -- next is source root dir, for absolute (nonrelative) includes 482 484 -- (e.g. "lib/precompiled.h") 483 485 includedirs { source_root } 484 486 485 487 for i,v in pairs(rel_include_dirs) do 486 488 includedirs { source_root .. v } 487 489 end 488 490 489 491 if extra_params["extra_files"] then 490 492 for i,v in pairs(extra_params["extra_files"]) do 491 493 -- .rc files are only needed on Windows 492 494 if path.getextension(v) ~= ".rc" or os.istarget("windows") then 493 495 files { source_root .. v } 494 496 end 495 497 end 496 498 end 497 499 498 500 if extra_params["extra_links"] then 499 501 links { extra_params["extra_links"] } 500 502 end 501 503 end 502 504 503 505 504 506 -- Add command-line options to set up the manifest dependencies for Windows 505 507 -- (See lib/sysdep/os/win/manifest.cpp) 506 508 function project_add_manifest() 507 509 linkoptions { "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df'\"" } 508 510 end 509 511 510 512 -------------------------------------------------------------------------------- 511 513 -- engine static libraries 512 514 -------------------------------------------------------------------------------- 513 515 514 516 -- the engine is split up into several static libraries. this eases separate 515 517 -- distribution of those components, reduces dependencies a bit, and can 516 518 -- also speed up builds. 517 519 -- more to the point, it is necessary to efficiently support a separate 518 520 -- test executable that also includes much of the game code. 519 521 520 522 -- names of all static libs created. automatically added to the 521 523 -- main app project later (see explanation at end of this file) 522 524 static_lib_names = {} 523 525 static_lib_names_debug = {} 524 526 static_lib_names_release = {} 525 527 526 528 -- set up one of the static libraries into which the main engine code is split. 527 529 -- extra_params: 528 530 -- no_default_link: If specified, linking won't be done by default. 529 531 -- For the rest of extra_params, see project_add_contents(). 530 532 -- note: rel_source_dirs and rel_include_dirs are relative to global source_root. 531 533 function setup_static_lib_project (project_name, rel_source_dirs, extern_libs, extra_params) 532 534 533 535 local target_type = "StaticLib" 534 536 project_create(project_name, target_type) 535 537 project_add_contents(source_root, rel_source_dirs, {}, extra_params) 536 538 project_add_extern_libs(extern_libs, target_type) 537 539 538 540 if not extra_params["no_default_link"] then 539 541 table.insert(static_lib_names, project_name) 540 542 end 541 543 542 544 -- Deactivate Run Time Type Information. Performance of dynamic_cast is very poor. 543 545 -- The exception to this principle is Atlas UI, which is not a static library. 544 546 rtti "off" 545 547 546 548 if os.istarget("macosx") and _OPTIONS["macosx-version-min"] then 547 549 xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } 548 550 end 549 551 end 550 552 551 553 function setup_third_party_static_lib_project (project_name, rel_source_dirs, extern_libs, extra_params) 552 554 553 555 setup_static_lib_project(project_name, rel_source_dirs, extern_libs, extra_params) 554 556 includedirs { source_root .. "third_party/" .. project_name .. "/include/" } 555 557 end 556 558 557 559 function setup_shared_lib_project (project_name, rel_source_dirs, extern_libs, extra_params) 558 560 559 561 local target_type = "SharedLib" 560 562 project_create(project_name, target_type) 561 563 project_add_contents(source_root, rel_source_dirs, {}, extra_params) 562 564 project_add_extern_libs(extern_libs, target_type) 563 565 564 566 if not extra_params["no_default_link"] then 565 567 table.insert(static_lib_names, project_name) 566 568 end 567 569 568 570 if os.istarget("windows") then 569 571 links { "delayimp" } 570 572 elseif os.istarget("macosx") and _OPTIONS["macosx-version-min"] then 571 573 xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } 572 574 end 573 575 end 574 576 575 577 576 578 -- this is where the source tree is chopped up into static libs. 577 579 -- can be changed very easily; just copy+paste a new setup_static_lib_project, 578 580 -- or remove existing ones. static libs are automagically added to 579 581 -- main_exe link step. 580 582 function setup_all_libs () 581 583 582 584 -- relative to global source_root. 583 585 local source_dirs = {} 584 586 -- names of external libraries used (see libraries_dir comment) 585 587 local extern_libs = {} 586 588 587 589 588 590 source_dirs = { 589 591 "network", 590 592 } 591 593 extern_libs = { 592 594 "spidermonkey", 593 595 "enet", 594 596 "boost", -- dragged in via server->simulation.h->random 595 597 "fmt", 596 598 } 597 599 if not _OPTIONS["without-miniupnpc"] then 598 600 table.insert(extern_libs, "miniupnpc") 599 601 end 600 602 setup_static_lib_project("network", source_dirs, extern_libs, {}) 601 603 602 604 source_dirs = { 603 605 "rlinterface", 604 606 } 605 607 extern_libs = { 606 608 "boost", -- dragged in via simulation.h and scriptinterface.h 607 609 "fmt", 608 610 "spidermonkey", 609 611 } 610 612 setup_static_lib_project("rlinterface", source_dirs, extern_libs, { no_pch = 1 }) 611 613 612 614 source_dirs = { 613 615 "third_party/tinygettext/src", 614 616 } 615 617 extern_libs = { 616 618 "iconv", 617 619 "boost", 618 620 "fmt", 619 621 } 620 622 setup_third_party_static_lib_project("tinygettext", source_dirs, extern_libs, { } ) 621 623 622 624 -- it's an external library and we don't want to modify its source to fix warnings, so we just disable them to avoid noise in the compile output 623 625 filter "action:vs*" 624 626 buildoptions { 625 627 "/wd4127", 626 628 "/wd4309", 627 629 "/wd4800", 628 630 "/wd4100", 629 631 "/wd4996", 630 632 "/wd4099", 631 633 "/wd4503" 632 634 } 633 635 filter {} 634 636 635 637 636 638 if not _OPTIONS["without-lobby"] then 637 639 source_dirs = { 638 640 "lobby", 639 641 "lobby/scripting", 640 642 "i18n", 641 643 "third_party/encryption" 642 644 } 643 645 644 646 extern_libs = { 645 647 "spidermonkey", 646 648 "boost", 647 649 "enet", 648 650 "gloox", 649 651 "icu", 650 652 "iconv", 651 653 "libsodium", 652 654 "tinygettext", 653 655 "fmt", 654 656 } 655 657 setup_static_lib_project("lobby", source_dirs, extern_libs, {}) 656 658 657 659 if _OPTIONS["use-shared-glooxwrapper"] and not _OPTIONS["build-shared-glooxwrapper"] then 658 660 table.insert(static_lib_names_debug, "glooxwrapper_dbg") 659 661 table.insert(static_lib_names_release, "glooxwrapper") 660 662 else 661 663 source_dirs = { 662 664 "lobby/glooxwrapper", 663 665 } 664 666 extern_libs = { 665 667 "boost", 666 668 "gloox", 667 669 "fmt", 668 670 } 669 671 if _OPTIONS["build-shared-glooxwrapper"] then 670 672 setup_shared_lib_project("glooxwrapper", source_dirs, extern_libs, {}) 671 673 else 672 674 setup_static_lib_project("glooxwrapper", source_dirs, extern_libs, {}) 673 675 end 674 676 end 675 677 else 676 678 source_dirs = { 677 679 "lobby/scripting", 678 680 "third_party/encryption" 679 681 } 680 682 extern_libs = { 681 683 "spidermonkey", 682 684 "boost", 683 685 "libsodium", 684 686 "fmt", 685 687 } 686 688 setup_static_lib_project("lobby", source_dirs, extern_libs, {}) 687 689 files { source_root.."lobby/Globals.cpp" } 688 690 end 689 691 690 692 691 693 source_dirs = { 692 694 "simulation2", 693 695 "simulation2/components", 694 696 "simulation2/helpers", 695 697 "simulation2/scripting", 696 698 "simulation2/serialization", 697 699 "simulation2/system", 698 700 "simulation2/testcomponents", 699 701 } 700 702 extern_libs = { 701 703 "boost", 702 704 "opengl", 703 705 "spidermonkey", 704 706 "fmt", 705 707 } 706 708 setup_static_lib_project("simulation2", source_dirs, extern_libs, {}) 707 709 708 710 709 711 source_dirs = { 710 712 "scriptinterface", 711 713 "scriptinterface/third_party" 712 714 } 713 715 extern_libs = { 714 716 "boost", 715 717 "spidermonkey", 716 718 "valgrind", 717 719 "sdl", 718 720 "fmt", 719 721 } 720 722 setup_static_lib_project("scriptinterface", source_dirs, extern_libs, {}) 721 723 722 724 723 725 source_dirs = { 724 726 "ps", 725 727 "ps/scripting", 726 728 "network/scripting", 727 729 "ps/GameSetup", 728 730 "ps/XML", 729 731 "soundmanager", 730 732 "soundmanager/data", 731 733 "soundmanager/items", 732 734 "soundmanager/scripting", 733 735 "maths", 734 736 "maths/scripting", 735 737 "i18n", 736 738 "i18n/scripting", 737 739 } 738 740 extern_libs = { 739 741 "spidermonkey", 740 742 "sdl", -- key definitions 741 743 "libxml2", 742 744 "opengl", 743 745 "zlib", 744 746 "boost", 745 747 "enet", 746 748 "libcurl", 747 749 "tinygettext", 748 750 "icu", 749 751 "iconv", 750 752 "libsodium", 751 753 "fmt", 752 754 } 753 755 754 756 if not _OPTIONS["without-audio"] then 755 757 table.insert(extern_libs, "openal") 756 758 table.insert(extern_libs, "vorbis") 757 759 end 758 760 759 761 setup_static_lib_project("engine", source_dirs, extern_libs, {}) 760 762 761 763 762 764 source_dirs = { 763 765 "graphics", 764 766 "graphics/scripting", 765 767 "renderer", 766 768 "renderer/scripting", 767 769 "third_party/mikktspace", 768 770 "third_party/ogre3d_preprocessor" 769 771 } 770 772 extern_libs = { 771 773 "opengl", 772 774 "sdl", -- key definitions 773 775 "spidermonkey", -- for graphics/scripting 774 776 "boost", 775 777 "fmt", 776 778 } 777 779 if not _OPTIONS["without-nvtt"] then 778 780 table.insert(extern_libs, "nvtt") 779 781 end 780 782 setup_static_lib_project("graphics", source_dirs, extern_libs, {}) 781 783 782 784 783 785 source_dirs = { 784 786 "tools/atlas/GameInterface", 785 787 "tools/atlas/GameInterface/Handlers" 786 788 } 787 789 extern_libs = { 788 790 "boost", 789 791 "sdl", -- key definitions 790 792 "opengl", 791 793 "spidermonkey", 792 794 "fmt", 793 795 } 794 796 setup_static_lib_project("atlas", source_dirs, extern_libs, {}) 795 797 796 798 797 799 source_dirs = { 798 800 "gui", 799 801 "gui/ObjectTypes", 800 802 "gui/ObjectBases", 801 803 "gui/Scripting", 802 804 "gui/SettingTypes", 803 805 "i18n" 804 806 } 805 807 extern_libs = { 806 808 "spidermonkey", 807 809 "sdl", -- key definitions 808 810 "opengl", 809 811 "boost", 810 812 "enet", 811 813 "tinygettext", 812 814 "icu", 813 815 "iconv", 814 816 "fmt", 815 817 } 816 818 if not _OPTIONS["without-audio"] then 817 819 table.insert(extern_libs, "openal") 818 820 end 819 821 setup_static_lib_project("gui", source_dirs, extern_libs, {}) 820 822 821 823 822 824 source_dirs = { 823 825 "lib", 824 826 "lib/adts", 825 827 "lib/allocators", 826 828 "lib/external_libraries", 827 829 "lib/file", 828 830 "lib/file/archive", 829 831 "lib/file/common", 830 832 "lib/file/io", 831 833 "lib/file/vfs", 832 834 "lib/pch", 833 835 "lib/posix", 834 836 "lib/res", 835 837 "lib/res/graphics", 836 838 "lib/sysdep", 837 839 "lib/tex" 838 840 } 839 841 extern_libs = { 840 842 "boost", 841 843 "sdl", 842 844 "openal", 843 845 "opengl", 844 846 "libpng", 845 847 "zlib", 846 848 "valgrind", 847 849 "cxxtest", 848 850 "fmt", 849 851 } 850 852 851 853 -- CPU architecture-specific 852 854 if arch == "amd64" then 853 855 table.insert(source_dirs, "lib/sysdep/arch/amd64"); 854 856 table.insert(source_dirs, "lib/sysdep/arch/x86_x64"); 855 857 elseif arch == "x86" then 856 858 table.insert(source_dirs, "lib/sysdep/arch/ia32"); 857 859 table.insert(source_dirs, "lib/sysdep/arch/x86_x64"); 858 860 elseif arch == "arm" then 859 861 table.insert(source_dirs, "lib/sysdep/arch/arm"); 860 862 elseif arch == "aarch64" then 861 863 table.insert(source_dirs, "lib/sysdep/arch/aarch64"); 864 elseif arch == "e2k" then 865 table.insert(source_dirs, "lib/sysdep/arch/e2k"); 862 866 end 863 867 864 868 -- OS-specific 865 869 sysdep_dirs = { 866 870 linux = { "lib/sysdep/os/linux", "lib/sysdep/os/unix" }, 867 871 -- note: RC file must be added to main_exe project. 868 872 -- note: don't add "lib/sysdep/os/win/aken.cpp" because that must be compiled with the DDK. 869 873 windows = { "lib/sysdep/os/win", "lib/sysdep/os/win/wposix", "lib/sysdep/os/win/whrt" }, 870 874 macosx = { "lib/sysdep/os/osx", "lib/sysdep/os/unix" }, 871 875 bsd = { "lib/sysdep/os/bsd", "lib/sysdep/os/unix", "lib/sysdep/os/unix/x" }, 872 876 } 873 877 for i,v in pairs(sysdep_dirs[os.target()]) do 874 878 table.insert(source_dirs, v); 875 879 end 876 880 877 881 if os.istarget("linux") then 878 882 if _OPTIONS["android"] then 879 883 table.insert(source_dirs, "lib/sysdep/os/android") 880 884 else 881 885 table.insert(source_dirs, "lib/sysdep/os/unix/x") 882 886 end 883 887 end 884 888 885 889 -- On OSX, disable precompiled headers because C++ files and Objective-C++ files are 886 890 -- mixed in this project. To fix that, we would need per-file basis configuration which 887 891 -- is not yet supported by the gmake action in premake. We should look into using gmake2. 888 892 extra_params = {} 889 893 if os.istarget("macosx") then 890 894 extra_params = { no_pch = 1 } 891 895 end 892 896 893 897 -- runtime-library-specific 894 898 if _ACTION == "vs2017" then 895 899 table.insert(source_dirs, "lib/sysdep/rtl/msc"); 896 900 else 897 901 table.insert(source_dirs, "lib/sysdep/rtl/gcc"); 898 902 end 899 903 900 904 setup_static_lib_project("lowlevel", source_dirs, extern_libs, extra_params) 901 905 902 906 903 907 -- Third-party libraries that are built as part of the main project, 904 908 -- not built externally and then linked 905 909 source_dirs = { 906 910 "third_party/mongoose", 907 911 } 908 912 extern_libs = { 909 913 } 910 914 setup_static_lib_project("mongoose", source_dirs, extern_libs, { no_pch = 1 }) 911 915 912 916 913 917 -- CxxTest mock function support 914 918 extern_libs = { 915 919 "boost", 916 920 "cxxtest", 917 921 } 918 922 919 923 -- 'real' implementations, to be linked against the main executable 920 924 -- (files are added manually and not with setup_static_lib_project 921 925 -- because not all files in the directory are included) 922 926 setup_static_lib_project("mocks_real", {}, extern_libs, { no_default_link = 1, no_pch = 1 }) 923 927 files { "mocks/*.h", source_root.."mocks/*_real.cpp" } 924 928 -- 'test' implementations, to be linked against the test executable 925 929 setup_static_lib_project("mocks_test", {}, extern_libs, { no_default_link = 1, no_pch = 1 }) 926 930 files { source_root.."mocks/*.h", source_root.."mocks/*_test.cpp" } 927 931 end 928 932 929 933 -------------------------------------------------------------------------------- 930 934 -- main EXE 931 935 -------------------------------------------------------------------------------- 932 936 933 937 -- used for main EXE as well as test 934 938 used_extern_libs = { 935 939 "opengl", 936 940 "sdl", 937 941 938 942 "libpng", 939 943 "zlib", 940 944 941 945 "spidermonkey", 942 946 "libxml2", 943 947 944 948 "boost", 945 949 "cxxtest", 946 950 "comsuppw", 947 951 "enet", 948 952 "libcurl", 949 953 "tinygettext", 950 954 "icu", 951 955 "iconv", 952 956 "libsodium", 953 957 "fmt", 954 958 955 959 "valgrind", 956 960 } 957 961 958 962 if not os.istarget("windows") and not _OPTIONS["android"] and not os.istarget("macosx") then 959 963 -- X11 should only be linked on *nix 960 964 table.insert(used_extern_libs, "x11") 961 965 end 962 966 963 967 if not _OPTIONS["without-audio"] then 964 968 table.insert(used_extern_libs, "openal") 965 969 table.insert(used_extern_libs, "vorbis") 966 970 end 967 971 968 972 if not _OPTIONS["without-nvtt"] then 969 973 table.insert(used_extern_libs, "nvtt") 970 974 end 971 975 972 976 if not _OPTIONS["without-lobby"] then 973 977 table.insert(used_extern_libs, "gloox") 974 978 end 975 979 976 980 if not _OPTIONS["without-miniupnpc"] then 977 981 table.insert(used_extern_libs, "miniupnpc") 978 982 end 979 983 980 984 -- Bundles static libs together with main.cpp and builds game executable. 981 985 function setup_main_exe () 982 986 983 987 local target_type = get_main_project_target_type() 984 988 project_create("pyrogenesis", target_type) 985 989 986 990 filter "system:not macosx" 987 991 linkgroups 'On' 988 992 filter {} 989 993 990 994 links { "mocks_real" } 991 995 992 996 local extra_params = { 993 997 extra_files = { "main.cpp" }, 994 998 no_pch = 1 995 999 } 996 1000 project_add_contents(source_root, {}, {}, extra_params) 997 1001 project_add_extern_libs(used_extern_libs, target_type) 998 1002 999 1003 dependson { "Collada" } 1000 1004 1001 1005 rtti "off" 1002 1006 1003 1007 -- Platform Specifics 1004 1008 if os.istarget("windows") then 1005 1009 1006 1010 files { source_root.."lib/sysdep/os/win/icon.rc" } 1007 1011 -- from "lowlevel" static lib; must be added here to be linked in 1008 1012 files { source_root.."lib/sysdep/os/win/error_dialog.rc" } 1009 1013 1010 1014 linkoptions { 1011 1015 -- wraps main thread in a __try block(see wseh.cpp). replace with mainCRTStartup if that's undesired. 1012 1016 "/ENTRY:wseh_EntryPoint", 1013 1017 1014 1018 -- see wstartup.h 1015 1019 "/INCLUDE:_wstartup_InitAndRegisterShutdown", 1016 1020 1017 1021 -- allow manual unload of delay-loaded DLLs 1018 1022 "/DELAY:UNLOAD", 1019 1023 } 1020 1024 1021 1025 -- allow the executable to use more than 2GB of RAM. 1022 1026 -- this should not be enabled during development, so that memory issues are easily spotted. 1023 1027 if _OPTIONS["large-address-aware"] then 1024 1028 linkoptions { "/LARGEADDRESSAWARE" } 1025 1029 end 1026 1030 1027 1031 -- see manifest.cpp 1028 1032 project_add_manifest() 1029 1033 1030 1034 elseif os.istarget("linux") or os.istarget("bsd") then 1031 1035 1032 1036 if not _OPTIONS["android"] and not (os.getversion().description == "OpenBSD") then 1033 1037 links { "rt" } 1034 1038 end 1035 1039 1036 1040 if _OPTIONS["android"] then 1037 1041 -- NDK's STANDALONE-TOOLCHAIN.html says this is required 1038 1042 linkoptions { "-Wl,--fix-cortex-a8" } 1039 1043 1040 1044 links { "log" } 1041 1045 end 1042 1046 1043 1047 if link_execinfo then 1044 1048 links { 1045 1049 "execinfo" 1046 1050 } 1047 1051 end 1048 1052 1049 1053 if os.istarget("linux") or os.getversion().description == "GNU/kFreeBSD" then 1050 1054 links { 1051 1055 -- Dynamic libraries (needed for linking for gold) 1052 1056 "dl", 1053 1057 } 1054 1058 end 1055 1059 1056 1060 -- Threading support 1057 1061 buildoptions { "-pthread" } 1058 1062 if not _OPTIONS["android"] then 1059 1063 linkoptions { "-pthread" } 1060 1064 end 1061 1065 1062 1066 -- For debug_resolve_symbol 1063 1067 filter "Debug" 1064 1068 linkoptions { "-rdynamic" } 1065 1069 filter { } 1066 1070 1067 1071 elseif os.istarget("macosx") then 1068 1072 1069 1073 links { "pthread" } 1070 1074 links { "ApplicationServices.framework", "Cocoa.framework", "CoreFoundation.framework" } 1071 1075 if _OPTIONS["macosx-version-min"] then 1072 1076 xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } 1073 1077 end 1074 1078 end 1075 1079 end 1076 1080 1077 1081 1078 1082 -------------------------------------------------------------------------------- 1079 1083 -- atlas 1080 1084 -------------------------------------------------------------------------------- 1081 1085 1082 1086 -- setup a typical Atlas component project 1083 1087 -- extra_params, rel_source_dirs and rel_include_dirs: as in project_add_contents; 1084 1088 function setup_atlas_project(project_name, target_type, rel_source_dirs, rel_include_dirs, extern_libs, extra_params) 1085 1089 1086 1090 local source_root = rootdir.."/source/tools/atlas/" .. project_name .. "/" 1087 1091 project_create(project_name, target_type) 1088 1092 1089 1093 -- if not specified, the default for atlas pch files is in the project root. 1090 1094 if not extra_params["pch_dir"] then 1091 1095 extra_params["pch_dir"] = source_root 1092 1096 end 1093 1097 1094 1098 project_add_contents(source_root, rel_source_dirs, rel_include_dirs, extra_params) 1095 1099 project_add_extern_libs(extern_libs, target_type) 1096 1100 1097 1101 -- Platform Specifics 1098 1102 if os.istarget("windows") then 1099 1103 -- Link to required libraries 1100 1104 links { "winmm", "delayimp" } 1101 1105 1102 1106 elseif os.istarget("linux") or os.istarget("bsd") then 1103 1107 buildoptions { "-rdynamic", "-fPIC" } 1104 1108 linkoptions { "-fPIC", "-rdynamic" } 1105 1109 1106 1110 -- warnings triggered by wxWidgets 1107 1111 buildoptions { "-Wno-unused-local-typedefs" } 1108 1112 1109 1113 elseif os.istarget("macosx") then 1110 1114 -- install_name settings aren't really supported yet by premake, but there are plans for the future. 1111 1115 -- we currently use this hack to work around some bugs with wrong install_names. 1112 1116 if target_type == "SharedLib" then 1113 1117 if _OPTIONS["macosx-bundle"] then 1114 1118 -- If we're building a bundle, it will be in ../Frameworks 1115 1119 filter "Debug" 1116 1120 linkoptions { "-install_name @executable_path/../Frameworks/lib"..project_name.."_dbg.dylib" } 1117 1121 filter "Release" 1118 1122 linkoptions { "-install_name @executable_path/../Frameworks/lib"..project_name..".dylib" } 1119 1123 filter { } 1120 1124 else 1121 1125 filter "Debug" 1122 1126 linkoptions { "-install_name @executable_path/lib"..project_name.."_dbg.dylib" } 1123 1127 filter "Release" 1124 1128 linkoptions { "-install_name @executable_path/lib"..project_name..".dylib" } 1125 1129 filter { } 1126 1130 end 1127 1131 end 1128 1132 end 1129 1133 1130 1134 end 1131 1135 1132 1136 1133 1137 -- build all Atlas component projects 1134 1138 function setup_atlas_projects() 1135 1139 1136 1140 setup_atlas_project("AtlasObject", "StaticLib", 1137 1141 { -- src 1138 1142 ".", 1139 1143 "../../../third_party/jsonspirit" 1140 1144 1141 1145 },{ -- include 1142 1146 "../../../third_party/jsonspirit" 1143 1147 },{ -- extern_libs 1144 1148 "boost", 1145 1149 "iconv", 1146 1150 "libxml2" 1147 1151 },{ -- extra_params 1148 1152 no_pch = 1 1149 1153 }) 1150 1154 1151 1155 atlas_src = { 1152 1156 "ActorEditor", 1153 1157 "CustomControls/Buttons", 1154 1158 "CustomControls/Canvas", 1155 1159 "CustomControls/ColorDialog", 1156 1160 "CustomControls/DraggableListCtrl", 1157 1161 "CustomControls/EditableListCtrl", 1158 1162 "CustomControls/FileHistory", 1159 1163 "CustomControls/HighResTimer", 1160 1164 "CustomControls/MapDialog", 1161 1165 "CustomControls/MapResizeDialog", 1162 1166 "CustomControls/SnapSplitterWindow", 1163 1167 "CustomControls/VirtualDirTreeCtrl", 1164 1168 "CustomControls/Windows", 1165 1169 "General", 1166 1170 "General/VideoRecorder", 1167 1171 "Misc", 1168 1172 "ScenarioEditor", 1169 1173 "ScenarioEditor/Sections/Common", 1170 1174 "ScenarioEditor/Sections/Cinema", 1171 1175 "ScenarioEditor/Sections/Environment", 1172 1176 "ScenarioEditor/Sections/Map", 1173 1177 "ScenarioEditor/Sections/Object", 1174 1178 "ScenarioEditor/Sections/Player", 1175 1179 "ScenarioEditor/Sections/Terrain", 1176 1180 "ScenarioEditor/Tools", 1177 1181 "ScenarioEditor/Tools/Common", 1178 1182 } 1179 1183 atlas_extra_links = { 1180 1184 "AtlasObject" 1181 1185 } 1182 1186 1183 1187 atlas_extern_libs = { 1184 1188 "boost", 1185 1189 "comsuppw", 1186 1190 "iconv", 1187 1191 "libxml2", 1188 1192 "sdl", -- key definitions 1189 1193 "wxwidgets", 1190 1194 "zlib", 1191 1195 } 1192 1196 if not os.istarget("windows") and not os.istarget("macosx") then 1193 1197 -- X11 should only be linked on *nix 1194 1198 table.insert(atlas_extern_libs, "x11") 1195 1199 end 1196 1200 1197 1201 setup_atlas_project("AtlasUI", "SharedLib", atlas_src, 1198 1202 { -- include 1199 1203 "..", 1200 1204 "CustomControls", 1201 1205 "Misc", 1202 1206 "../../../third_party/jsonspirit" 1203 1207 }, 1204 1208 atlas_extern_libs, 1205 1209 { -- extra_params 1206 1210 pch_dir = rootdir.."/source/tools/atlas/AtlasUI/Misc/", 1207 1211 no_pch = false, 1208 1212 extra_links = atlas_extra_links, 1209 1213 extra_files = { "Misc/atlas.rc" } 1210 1214 }) 1211 1215 end 1212 1216 1213 1217 1214 1218 -- Atlas 'frontend' tool-launching projects 1215 1219 function setup_atlas_frontend_project (project_name) 1216 1220 1217 1221 local target_type = get_main_project_target_type() 1218 1222 project_create(project_name, target_type) 1219 1223 1220 1224 local source_root = rootdir.."/source/tools/atlas/AtlasFrontends/" 1221 1225 files { source_root..project_name..".cpp" } 1222 1226 1223 1227 if os.istarget("windows") then 1224 1228 files { source_root..project_name..".rc" } 1225 1229 end 1226 1230 1227 1231 includedirs { source_root .. ".." } 1228 1232 1229 1233 -- Platform Specifics 1230 1234 if os.istarget("windows") then 1231 1235 -- see manifest.cpp 1232 1236 project_add_manifest() 1233 1237 1234 1238 else -- Non-Windows, = Unix 1235 1239 links { "AtlasObject" } 1236 1240 end 1237 1241 1238 1242 links { "AtlasUI" } 1239 1243 1240 1244 end 1241 1245 1242 1246 function setup_atlas_frontends() 1243 1247 setup_atlas_frontend_project("ActorEditor") 1244 1248 end 1245 1249 1246 1250 1247 1251 -------------------------------------------------------------------------------- 1248 1252 -- collada 1249 1253 -------------------------------------------------------------------------------- 1250 1254 1251 1255 function setup_collada_project(project_name, target_type, rel_source_dirs, rel_include_dirs, extern_libs, extra_params) 1252 1256 1253 1257 project_create(project_name, target_type) 1254 1258 local source_root = source_root.."collada/" 1255 1259 extra_params["pch_dir"] = source_root 1256 1260 project_add_contents(source_root, rel_source_dirs, rel_include_dirs, extra_params) 1257 1261 project_add_extern_libs(extern_libs, target_type) 1258 1262 1259 1263 -- Platform Specifics 1260 1264 if os.istarget("windows") then 1261 1265 characterset "MBCS" 1262 1266 elseif os.istarget("linux") then 1263 1267 defines { "LINUX" } 1264 1268 1265 1269 links { 1266 1270 "dl", 1267 1271 } 1268 1272 1269 1273 -- FCollada is not aliasing-safe, so disallow dangerous optimisations 1270 1274 -- (TODO: It'd be nice to fix FCollada, but that looks hard) 1271 1275 buildoptions { "-fno-strict-aliasing" } 1272 1276 1273 1277 buildoptions { "-rdynamic" } 1274 1278 linkoptions { "-rdynamic" } 1275 1279 1276 1280 elseif os.istarget("bsd") then 1277 1281 if os.getversion().description == "OpenBSD" then 1278 1282 links { "c", } 1279 1283 end 1280 1284 1281 1285 if os.getversion().description == "GNU/kFreeBSD" then 1282 1286 links { 1283 1287 "dl", 1284 1288 } 1285 1289 end 1286 1290 1287 1291 buildoptions { "-fno-strict-aliasing" } 1288 1292 1289 1293 buildoptions { "-rdynamic" } 1290 1294 linkoptions { "-rdynamic" } 1291 1295 1292 1296 elseif os.istarget("macosx") then 1293 1297 -- define MACOS-something? 1294 1298 1295 1299 -- install_name settings aren't really supported yet by premake, but there are plans for the future. 1296 1300 -- we currently use this hack to work around some bugs with wrong install_names. 1297 1301 if target_type == "SharedLib" then 1298 1302 if _OPTIONS["macosx-bundle"] then 1299 1303 -- If we're building a bundle, it will be in ../Frameworks 1300 1304 linkoptions { "-install_name @executable_path/../Frameworks/lib"..project_name..".dylib" } 1301 1305 else 1302 1306 linkoptions { "-install_name @executable_path/lib"..project_name..".dylib" } 1303 1307 end 1304 1308 end 1305 1309 1306 1310 buildoptions { "-fno-strict-aliasing" } 1307 1311 -- On OSX, fcollada uses a few utility functions from coreservices 1308 1312 links { "CoreServices.framework" } 1309 1313 end 1310 1314 1311 1315 end 1312 1316 1313 1317 -- build all Collada component projects 1314 1318 function setup_collada_projects() 1315 1319 1316 1320 setup_collada_project("Collada", "SharedLib", 1317 1321 { -- src 1318 1322 "." 1319 1323 },{ -- include 1320 1324 },{ -- extern_libs 1321 1325 "fcollada", 1322 1326 "iconv", 1323 1327 "libxml2" 1324 1328 },{ -- extra_params 1325 1329 }) 1326 1330 1327 1331 end 1328 1332 1329 1333 1330 1334 -------------------------------------------------------------------------------- 1331 1335 -- tests 1332 1336 -------------------------------------------------------------------------------- 1333 1337 1334 1338 function setup_tests() 1335 1339 1336 1340 local cxxtest = require "cxxtest" 1337 1341 1338 1342 if os.istarget("windows") then 1339 1343 cxxtest.setpath(rootdir.."/build/bin/cxxtestgen.exe") 1340 1344 else 1341 1345 cxxtest.setpath(rootdir.."/libraries/source/cxxtest-4.4/bin/cxxtestgen") 1342 1346 end 1343 1347 1344 1348 local runner = "ErrorPrinter" 1345 1349 if _OPTIONS["jenkins-tests"] then 1346 1350 runner = "XmlPrinter" 1347 1351 end 1348 1352 1349 1353 local includefiles = { 1350 1354 -- Precompiled headers - the header is added to all generated .cpp files 1351 1355 -- note that the header isn't actually precompiled here, only #included 1352 1356 -- so that the build stage can use it as a precompiled header. 1353 1357 "precompiled.h", 1354 1358 -- This is required to build against SDL 2.0.4 on Windows. 1355 1359 "lib/external_libraries/libsdl.h", 1356 1360 } 1357 1361 1358 1362 cxxtest.init(source_root, true, runner, includefiles) 1359 1363 1360 1364 local target_type = get_main_project_target_type() 1361 1365 project_create("test", target_type) 1362 1366 1363 1367 -- Find header files in 'test' subdirectories 1364 1368 local all_files = os.matchfiles(source_root .. "**/tests/*.h") 1365 1369 local test_files = {} 1366 1370 for i,v in pairs(all_files) do 1367 1371 -- Don't include sysdep tests on the wrong sys 1368 1372 -- Don't include Atlas tests unless Atlas is being built 1369 1373 if not (string.find(v, "/sysdep/os/win/") and not os.istarget("windows")) and 1370 1374 not (string.find(v, "/tools/atlas/") and not _OPTIONS["atlas"]) and 1371 1375 not (string.find(v, "/sysdep/arch/x86_x64/") and ((arch ~= "amd64") or (arch ~= "x86"))) 1372 1376 then 1373 1377 table.insert(test_files, v) 1374 1378 end 1375 1379 end 1376 1380 1377 1381 cxxtest.configure_project(test_files) 1378 1382 1379 1383 filter "system:not macosx" 1380 1384 linkgroups 'On' 1381 1385 filter {} 1382 1386 1383 1387 links { static_lib_names } 1384 1388 filter "Debug" 1385 1389 links { static_lib_names_debug } 1386 1390 filter "Release" 1387 1391 links { static_lib_names_release } 1388 1392 filter { } 1389 1393 1390 1394 links { "mocks_test" } 1391 1395 if _OPTIONS["atlas"] then 1392 1396 links { "AtlasObject" } 1393 1397 end 1394 1398 extra_params = { 1395 1399 extra_files = { "test_setup.cpp" }, 1396 1400 } 1397 1401 1398 1402 project_add_contents(source_root, {}, {}, extra_params) 1399 1403 project_add_extern_libs(used_extern_libs, target_type) 1400 1404 1401 1405 dependson { "Collada" } 1402 1406 1403 1407 rtti "off" 1404 1408 1405 1409 -- TODO: should fix the duplication between this OS-specific linking 1406 1410 -- code, and the similar version in setup_main_exe 1407 1411 1408 1412 if os.istarget("windows") then 1409 1413 -- from "lowlevel" static lib; must be added here to be linked in 1410 1414 files { source_root.."lib/sysdep/os/win/error_dialog.rc" } 1411 1415 1412 1416 -- see wstartup.h 1413 1417 linkoptions { "/INCLUDE:_wstartup_InitAndRegisterShutdown" } 1414 1418 -- Enables console for the TEST project on Windows 1415 1419 linkoptions { "/SUBSYSTEM:CONSOLE" } 1416 1420 1417 1421 project_add_manifest() 1418 1422 1419 1423 elseif os.istarget("linux") or os.istarget("bsd") then 1420 1424 1421 1425 if link_execinfo then 1422 1426 links { 1423 1427 "execinfo" 1424 1428 } 1425 1429 end 1426 1430 if not _OPTIONS["android"] and not (os.getversion().description == "OpenBSD") then 1427 1431 links { "rt" } 1428 1432 end 1429 1433 1430 1434 if _OPTIONS["android"] then 1431 1435 -- NDK's STANDALONE-TOOLCHAIN.html says this is required 1432 1436 linkoptions { "-Wl,--fix-cortex-a8" } 1433 1437 end 1434 1438 1435 1439 if os.istarget("linux") or os.getversion().description == "GNU/kFreeBSD" then 1436 1440 links { 1437 1441 -- Dynamic libraries (needed for linking for gold) 1438 1442 "dl", 1439 1443 } 1440 1444 end 1441 1445 1442 1446 -- Threading support 1443 1447 buildoptions { "-pthread" } 1444 1448 if not _OPTIONS["android"] then 1445 1449 linkoptions { "-pthread" } 1446 1450 end 1447 1451 1448 1452 -- For debug_resolve_symbol 1449 1453 filter "Debug" 1450 1454 linkoptions { "-rdynamic" } 1451 1455 filter { } 1452 1456 1453 1457 includedirs { source_root .. "pch/test/" } 1454 1458 1455 1459 elseif os.istarget("macosx") and _OPTIONS["macosx-version-min"] then 1456 1460 xcodebuildsettings { MACOSX_DEPLOYMENT_TARGET = _OPTIONS["macosx-version-min"] } 1457 1461 end 1458 1462 end 1459 1463 1460 1464 -- must come first, so that VC sets it as the default project and therefore 1461 1465 -- allows running via F5 without the "where is the EXE" dialog. 1462 1466 setup_main_exe() 1463 1467 1464 1468 setup_all_libs() 1465 1469 1466 1470 -- add the static libs to the main EXE project. only now (after 1467 1471 -- setup_all_libs has run) are the lib names known. cannot move 1468 1472 -- setup_main_exe to run after setup_all_libs (see comment above). 1469 1473 -- we also don't want to hardcode the names - that would require more 1470 1474 -- work when changing the static lib breakdown. 1471 1475 project("pyrogenesis") -- Set the main project active 1472 1476 links { static_lib_names } 1473 1477 filter "Debug" 1474 1478 links { static_lib_names_debug } 1475 1479 filter "Release" 1476 1480 links { static_lib_names_release } 1477 1481 filter { } 1478 1482 1479 1483 if _OPTIONS["atlas"] then 1480 1484 setup_atlas_projects() 1481 1485 setup_atlas_frontends() 1482 1486 end 1483 1487 1484 1488 setup_collada_projects() 1485 1489 1486 1490 if not _OPTIONS["without-tests"] then 1487 1491 setup_tests() 1488 1492 end -
source/graphics/Color.cpp
1 /* Copyright (C) 20 19Wildfire Games.1 /* Copyright (C) 2020 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or 7 7 * (at your option) any later version. 8 8 * 9 9 * 0 A.D. is distributed in the hope that it will be useful, 10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 12 * GNU General Public License for more details. 13 13 * 14 14 * You should have received a copy of the GNU General Public License 15 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 16 */ 17 17 18 18 #include "precompiled.h" 19 19 20 20 #include "graphics/Color.h" 21 21 22 22 #include "graphics/SColor.h" 23 23 #include "maths/MathUtil.h" 24 24 #include "ps/CLogger.h" 25 25 #include "ps/CStr.h" 26 26 27 27 #if HAVE_SSE 28 28 # include <xmmintrin.h> 29 30 #if ARCH_X86_X64 29 31 # include "lib/sysdep/arch/x86_x64/x86_x64.h" 30 32 #endif 31 33 34 bool IsSSEEnabled() 35 { 36 #if ARCH_X86_X64 37 return x86_x64::Cap(x86_x64::CAP_SSE); 38 #elif ARCH_E2K 39 return true; 40 #else 41 return false; 42 #endif 43 } 44 #endif // HAVE_SSE 45 32 46 static SColor4ub fallback_ConvertRGBColorTo4ub(const RGBColor& src) 33 47 { 34 48 SColor4ub result; 35 49 result.R = Clamp(static_cast<int>(src.X * 255), 0, 255); 36 50 result.G = Clamp(static_cast<int>(src.Y * 255), 0, 255); 37 51 result.B = Clamp(static_cast<int>(src.Z * 255), 0, 255); 38 52 result.A = 255; 39 53 return result; 40 54 } 41 55 42 56 // on IA32, this is replaced by an SSE assembly version in ia32.cpp 43 57 SColor4ub (*ConvertRGBColorTo4ub)(const RGBColor& src) = fallback_ConvertRGBColorTo4ub; 44 58 45 59 46 60 // Assembler-optimized function for color conversion 47 61 #if HAVE_SSE 48 62 static SColor4ub sse_ConvertRGBColorTo4ub(const RGBColor& src) 49 63 { 50 64 const __m128 zero = _mm_setzero_ps(); 51 65 const __m128 _255 = _mm_set_ss(255.0f); 52 66 __m128 r = _mm_load_ss(&src.X); 53 67 __m128 g = _mm_load_ss(&src.Y); 54 68 __m128 b = _mm_load_ss(&src.Z); 55 69 56 70 // C = min(255, 255*max(C, 0)) ( == Clamp(255*C, 0, 255) ) 57 71 r = _mm_max_ss(r, zero); 58 72 g = _mm_max_ss(g, zero); 59 73 b = _mm_max_ss(b, zero); 60 74 61 75 r = _mm_mul_ss(r, _255); 62 76 g = _mm_mul_ss(g, _255); 63 77 b = _mm_mul_ss(b, _255); 64 78 65 79 r = _mm_min_ss(r, _255); 66 80 g = _mm_min_ss(g, _255); 67 81 b = _mm_min_ss(b, _255); 68 82 69 83 // convert to integer and combine channels using bit logic 70 84 int ri = _mm_cvtss_si32(r); 71 85 int gi = _mm_cvtss_si32(g); 72 86 int bi = _mm_cvtss_si32(b); 73 87 74 88 return SColor4ub(ri, gi, bi, 0xFF); 75 89 } 76 90 #endif 77 91 78 92 void ColorActivateFastImpl() 79 93 { 80 94 #if HAVE_SSE 81 if ( x86_x64::Cap(x86_x64::CAP_SSE))95 if (IsSSEEnabled()) 82 96 { 83 97 ConvertRGBColorTo4ub = sse_ConvertRGBColorTo4ub; 84 98 return; 85 99 } 86 100 #endif 87 101 debug_printf("No SSE available. Slow fallback routines will be used.\n"); 88 102 } 89 103 90 104 /** 91 105 * Important: This function does not modify the value if parsing fails. 92 106 */ 93 107 bool CColor::ParseString(const CStr8& value, int defaultAlpha) 94 108 { 95 109 const size_t NUM_VALS = 4; 96 110 int values[NUM_VALS] = { 0, 0, 0, defaultAlpha }; 97 111 std::stringstream stream; 98 112 stream.str(value); 99 113 // Parse each value 100 114 size_t i; 101 115 for (i = 0; i < NUM_VALS; ++i) 102 116 { 103 117 if (stream.eof()) 104 118 break; 105 119 106 120 stream >> values[i]; 107 121 if ((stream.rdstate() & std::stringstream::failbit) != 0) 108 122 { 109 123 LOGWARNING("Unable to parse CColor parameters. Your input: '%s'", value.c_str()); 110 124 return false; 111 125 } 112 126 if (values[i] < 0 || values[i] > 255) 113 127 { 114 128 LOGWARNING("Invalid value (<0 or >255) when parsing CColor parameters. Your input: '%s'", value.c_str()); 115 129 return false; 116 130 } 117 131 } 118 132 119 133 if (i < 3) 120 134 { 121 135 LOGWARNING("Not enough parameters when parsing as CColor. Your input: '%s'", value.c_str()); 122 136 return false; 123 137 } 124 138 if (!stream.eof()) 125 139 { 126 140 LOGWARNING("Too many parameters when parsing as CColor. Your input: '%s'", value.c_str()); 127 141 return false; 128 142 } 129 143 130 144 r = values[0] / 255.f; 131 145 g = values[1] / 255.f; 132 146 b = values[2] / 255.f; 133 147 a = values[3] / 255.f; 134 148 135 149 return true; 136 150 } 137 151 138 152 bool CColor::operator==(const CColor& color) const 139 153 { 140 154 return 141 155 r == color.r && 142 156 g == color.g && 143 157 b == color.b && 144 158 a == color.a; 145 159 } -
source/graphics/Color.h
1 /* Copyright (C) 20 19Wildfire Games.1 /* Copyright (C) 2020 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or 7 7 * (at your option) any later version. 8 8 * 9 9 * 0 A.D. is distributed in the hope that it will be useful, 10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 12 * GNU General Public License for more details. 13 13 * 14 14 * You should have received a copy of the GNU General Public License 15 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 16 */ 17 17 18 18 #ifndef INCLUDED_COLOR 19 19 #define INCLUDED_COLOR 20 20 21 21 #include "graphics/SColor.h" 22 22 #include "maths/Vector3D.h" 23 23 #include "maths/Vector4D.h" 24 24 25 // Detects CPU SSE Support. 26 bool IsSSEEnabled(); 27 25 28 // Simple defines for 3 and 4 component floating point colors - just map to 26 29 // corresponding vector types. 27 30 typedef CVector3D RGBColor; 28 31 typedef CVector4D RGBAColor; 29 32 30 33 // Convert float RGB(A) colors to unsigned byte. 31 34 // Exposed as function pointer because it is set at init-time to 32 35 // one of several implementations depending on CPU caps. 33 36 extern SColor4ub (*ConvertRGBColorTo4ub)(const RGBColor& src); 34 37 35 38 // call once ia32_Init has run; detects CPU caps and activates the best 36 39 // possible codepath. 37 40 extern void ColorActivateFastImpl(); 38 41 39 42 class CStr8; 40 43 41 44 struct CColor 42 45 { 43 46 CColor() : r(-1.f), g(-1.f), b(-1.f), a(1.f) {} 44 47 CColor(float cr, float cg, float cb, float ca) : r(cr), g(cg), b(cb), a(ca) {} 45 48 46 49 /** 47 50 * Returns whether this has been set to a valid color. 48 51 */ 49 52 operator bool() const 50 53 { 51 54 return r >= 0 && g >= 0 && b >= 0 && a >= 0; 52 55 } 53 56 54 57 /** 55 58 * Try to parse @p Value as a color. Returns true on success, false otherwise. 56 59 * Leaves the color unchanged if it failed. 57 60 * @param value Should be "r g b" or "r g b a" where each value is an integer in [0,255]. 58 61 * @param defaultAlpha The alpha value that is used if the format of @p Value is "r g b". 59 62 */ 60 63 bool ParseString(const CStr8& value, int defaultAlpha = 255); 61 64 62 65 bool operator==(const CColor& color) const; 63 66 bool operator!=(const CColor& color) const 64 67 { 65 68 return !(*this == color); 66 69 } 67 70 68 71 // For passing to glColor[34]fv: 69 72 const float* FloatArray() const { return &r; } 70 73 71 74 // For passing to CRenderer: 72 75 SColor4ub AsSColor4ub() const 73 76 { 74 77 return SColor4ub( 75 78 static_cast<u8>(r * 255.f), 76 79 static_cast<u8>(g * 255.f), 77 80 static_cast<u8>(b * 255.f), 78 81 static_cast<u8>(a * 255.f) 79 82 ); 80 83 } 81 84 82 85 float r, g, b, a; 83 86 }; 84 87 85 88 #endif // INCLUDED_COLOR -
source/lib/byte_order.h
1 /* Copyright (C) 20 15Wildfire Games.1 /* Copyright (C) 2020 Wildfire Games. 2 2 * 3 3 * Permission is hereby granted, free of charge, to any person obtaining 4 4 * a copy of this software and associated documentation files (the 5 5 * "Software"), to deal in the Software without restriction, including 6 6 * without limitation the rights to use, copy, modify, merge, publish, 7 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 8 * permit persons to whom the Software is furnished to do so, subject to 9 9 * the following conditions: 10 10 * 11 11 * The above copyright notice and this permission notice shall be included 12 12 * in all copies or substantial portions of the Software. 13 13 * 14 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 21 */ 22 22 23 23 /* 24 24 * byte order (endianness) support routines. 25 25 */ 26 26 27 27 #ifndef INCLUDED_BYTE_ORDER 28 28 #define INCLUDED_BYTE_ORDER 29 29 30 30 #include "lib/sysdep/cpu.h" 31 31 32 32 // detect byte order via predefined macros. 33 33 #ifndef BYTE_ORDER 34 34 # define LITTLE_ENDIAN 0x4321 35 35 # define BIG_ENDIAN 0x1234 36 # if ARCH_IA32 || ARCH_IA64 || ARCH_AMD64 || ARCH_ALPHA || ARCH_ARM || ARCH_AARCH64 || ARCH_MIPS || defined(__LITTLE_ENDIAN__)36 # if ARCH_IA32 || ARCH_IA64 || ARCH_AMD64 || ARCH_ALPHA || ARCH_ARM || ARCH_AARCH64 || ARCH_MIPS || ARCH_E2K || defined(__LITTLE_ENDIAN__) 37 37 # define BYTE_ORDER LITTLE_ENDIAN 38 38 # else 39 39 # define BYTE_ORDER BIG_ENDIAN 40 40 # endif 41 41 #endif 42 42 43 43 44 44 /** 45 45 * convert 4 characters to u32 (at compile time) for easy comparison. 46 46 * output is in native byte order; e.g. FOURCC_LE can be used instead. 47 47 **/ 48 48 #define FOURCC(a,b,c,d) // real definition is below 49 49 #undef FOURCC 50 50 51 51 // implementation rationale: 52 52 // - can't pass code as string, and use s[0]..s[3], because 53 53 // VC6/7 don't realize the macro is constant 54 54 // (it should be usable as a switch{} expression) 55 55 // - the casts are ugly but necessary. u32 is required because u8 << 8 == 0; 56 56 // the additional u8 cast ensures each character is treated as unsigned 57 57 // (otherwise, they'd be promoted to signed int before the u32 cast, 58 58 // which would break things). 59 59 60 60 /// big-endian version of FOURCC 61 61 #define FOURCC_BE(a,b,c,d) ( ((u32)(u8)a) << 24 | ((u32)(u8)b) << 16 | \ 62 62 ((u32)(u8)c) << 8 | ((u32)(u8)d) << 0 ) 63 63 64 64 /// little-endian version of FOURCC 65 65 #define FOURCC_LE(a,b,c,d) ( ((u32)(u8)a) << 0 | ((u32)(u8)b) << 8 | \ 66 66 ((u32)(u8)c) << 16 | ((u32)(u8)d) << 24 ) 67 67 68 68 #if BYTE_ORDER == BIG_ENDIAN 69 69 # define FOURCC FOURCC_BE 70 70 #else 71 71 # define FOURCC FOURCC_LE 72 72 #endif 73 73 74 74 75 75 #if BYTE_ORDER == BIG_ENDIAN 76 76 // convert a little-endian number to/from native byte order. 77 77 # define to_le16(x) swap16(x) 78 78 # define to_le32(x) swap32(x) 79 79 # define to_le64(x) swap64(x) 80 80 // convert a big-endian number to/from native byte order. 81 81 # define to_be16(x) (x) 82 82 # define to_be32(x) (x) 83 83 # define to_be64(x) (x) 84 84 #else // LITTLE_ENDIAN 85 85 // convert a little-endian number to/from native byte order. 86 86 # define to_le16(x) (x) 87 87 # define to_le32(x) (x) 88 88 # define to_le64(x) (x) 89 89 // convert a big-endian number to/from native byte order. 90 90 # define to_be16(x) swap16(x) 91 91 # define to_be32(x) swap32(x) 92 92 # define to_be64(x) swap64(x) 93 93 #endif 94 94 95 95 /// read a little-endian number from memory into native byte order. 96 96 LIB_API u16 read_le16(const void* p); 97 97 LIB_API u32 read_le32(const void* p); /// see read_le16 98 98 LIB_API u64 read_le64(const void* p); /// see read_le16 99 99 100 100 /// read a big-endian number from memory into native byte order. 101 101 LIB_API u16 read_be16(const void* p); 102 102 LIB_API u32 read_be32(const void* p); /// see read_be16 103 103 LIB_API u64 read_be64(const void* p); /// see read_be16 104 104 105 105 /// write a little-endian number to memory in native byte order. 106 106 LIB_API void write_le16(void* p, u16 x); 107 107 LIB_API void write_le32(void* p, u32 x); /// see write_le16 108 108 LIB_API void write_le64(void* p, u64 x); /// see write_le16 109 109 110 110 /// write a big-endian number to memory in native byte order. 111 111 LIB_API void write_be16(void* p, u16 x); 112 112 LIB_API void write_be32(void* p, u32 x); /// see write_be16 113 113 LIB_API void write_be64(void* p, u64 x); /// see write_be16 114 114 115 115 /** 116 116 * zero-extend \<size\> (truncated to 8) bytes of little-endian data to u64, 117 117 * starting at address \<p\> (need not be aligned). 118 118 **/ 119 119 LIB_API u64 movzx_le64(const u8* p, size_t size); 120 120 LIB_API u64 movzx_be64(const u8* p, size_t size); 121 121 122 122 /** 123 123 * sign-extend \<size\> (truncated to 8) bytes of little-endian data to i64, 124 124 * starting at address \<p\> (need not be aligned). 125 125 **/ 126 126 LIB_API i64 movsx_le64(const u8* p, size_t size); 127 127 LIB_API i64 movsx_be64(const u8* p, size_t size); 128 128 129 129 130 130 #if ICC_VERSION 131 131 #define swap32 _bswap 132 132 #define swap64 _bswap64 133 133 #elif MSC_VERSION 134 134 extern unsigned short _byteswap_ushort(unsigned short); 135 135 extern unsigned long _byteswap_ulong(unsigned long); 136 136 extern unsigned __int64 _byteswap_uint64(unsigned __int64); 137 137 #pragma intrinsic(_byteswap_ushort) 138 138 #pragma intrinsic(_byteswap_ulong) 139 139 #pragma intrinsic(_byteswap_uint64) 140 140 # define swap16 _byteswap_ushort 141 141 # define swap32 _byteswap_ulong 142 142 # define swap64 _byteswap_uint64 143 143 #elif defined(linux) 144 144 # include <asm/byteorder.h> 145 145 # if defined(__arch__swab16) && !defined(swap16) 146 146 # define swap16 __arch__swab16 147 147 # endif 148 148 # if defined(__arch__swab32) && !defined(swap32) 149 149 # define swap32 __arch__swab32 150 150 # endif 151 151 # if defined(__arch__swab64) && !defined(swap64) 152 152 # define swap64 __arch__swab64 153 153 # endif 154 154 #endif 155 155 156 156 #ifndef swap16 157 157 LIB_API u16 swap16(const u16 x); 158 158 #endif 159 159 #ifndef swap32 160 160 LIB_API u32 swap32(const u32 x); 161 161 #endif 162 162 #ifndef swap64 163 163 LIB_API u64 swap64(const u64 x); 164 164 #endif 165 165 166 166 #endif // #ifndef INCLUDED_BYTE_ORDER -
source/lib/sysdep/arch/e2k/e2k.cpp
1 /* Copyright (C) 2020 Wildfire Games. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining 4 * a copy of this software and associated documentation files (the 5 * "Software"), to deal in the Software without restriction, including 6 * without limitation the rights to use, copy, modify, merge, publish, 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 * permit persons to whom the Software is furnished to do so, subject to 9 * the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 /** 24 * Routines specific to E2K (MCST Elbrus 2000) 25 */ 26 27 #include "precompiled.h" 28 29 #include "lib/sysdep/cpu.h" 30 31 intptr_t cpu_AtomicAdd(volatile intptr_t* location, intptr_t increment) 32 { 33 return __sync_fetch_and_add(location, increment); 34 } 35 36 bool cpu_CAS(volatile intptr_t* location, intptr_t expected, intptr_t newValue) 37 { 38 return __sync_bool_compare_and_swap(location, expected, newValue); 39 } 40 41 bool cpu_CAS64(volatile i64* location, i64 expected, i64 newValue) 42 { 43 return __sync_bool_compare_and_swap(location, expected, newValue); 44 } 45 46 const char* cpu_IdentifierString() 47 { 48 return __builtin_cpu_name(); 49 } -
source/lib/sysdep/arch.h
1 /* Copyright (C) 20 15Wildfire Games.1 /* Copyright (C) 2020 Wildfire Games. 2 2 * 3 3 * Permission is hereby granted, free of charge, to any person obtaining 4 4 * a copy of this software and associated documentation files (the 5 5 * "Software"), to deal in the Software without restriction, including 6 6 * without limitation the rights to use, copy, modify, merge, publish, 7 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 8 * permit persons to whom the Software is furnished to do so, subject to 9 9 * the following conditions: 10 10 * 11 11 * The above copyright notice and this permission notice shall be included 12 12 * in all copies or substantial portions of the Software. 13 13 * 14 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 21 */ 22 22 23 23 /* 24 24 * CPU architecture detection. 25 25 */ 26 26 27 27 #ifndef INCLUDED_ARCH 28 28 #define INCLUDED_ARCH 29 29 30 30 // detect target CPU architecture via predefined macros 31 31 // .. IA-32 32 32 #if defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__i386__) || defined(__i386) || defined(i386) 33 33 # define ARCH_IA32 1 34 34 #else 35 35 # define ARCH_IA32 0 36 36 #endif 37 37 // .. IA-64 38 38 #if defined(_M_IA64) || defined(__ia64__) 39 39 # define ARCH_IA64 1 40 40 #else 41 41 # define ARCH_IA64 0 42 42 #endif 43 43 // .. AMD64 44 44 #if defined(_M_X64) || defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) 45 45 # define ARCH_AMD64 1 46 46 #else 47 47 # define ARCH_AMD64 0 48 48 #endif 49 49 // .. Alpha 50 50 #if defined(_M_ALPHA) || defined(__alpha__) || defined(__alpha) 51 51 # define ARCH_ALPHA 1 52 52 #else 53 53 # define ARCH_ALPHA 0 54 54 #endif 55 55 // .. ARM 56 56 #if defined(__arm__) 57 57 # define ARCH_ARM 1 58 58 #else 59 59 # define ARCH_ARM 0 60 60 #endif 61 61 // .. AArch64 (ARM64) 62 62 #if defined(__aarch64__) 63 63 # define ARCH_AARCH64 1 64 64 #else 65 65 # define ARCH_AARCH64 0 66 66 #endif 67 67 // .. MIPS 68 68 #if defined(__MIPS__) || defined(__mips__) || defined(__mips) 69 69 # define ARCH_MIPS 1 70 70 #else 71 71 # define ARCH_MIPS 0 72 72 #endif 73 // .. E2K (MCST Elbrus 2000) 74 #if defined(__e2k__) 75 # define ARCH_E2K 1 76 #else 77 # define ARCH_E2K 0 78 #endif 73 79 74 80 // ensure exactly one architecture has been detected 75 #if (ARCH_IA32+ARCH_IA64+ARCH_AMD64+ARCH_ALPHA+ARCH_ARM+ARCH_AARCH64+ARCH_MIPS ) != 181 #if (ARCH_IA32+ARCH_IA64+ARCH_AMD64+ARCH_ALPHA+ARCH_ARM+ARCH_AARCH64+ARCH_MIPS+ARCH_E2K) != 1 76 82 # error "architecture not correctly detected (either none or multiple ARCH_* defined)" 77 83 #endif 78 84 79 85 // "X86_X64"-specific code requires either IA-32 or AMD64 80 86 #define ARCH_X86_X64 (ARCH_IA32|ARCH_AMD64) 81 87 82 88 #endif // #ifndef INCLUDED_ARCH -
source/lib/sysdep/compiler.h
1 /* Copyright (c) 20 19Wildfire Games.1 /* Copyright (c) 2020 Wildfire Games. 2 2 * 3 3 * Permission is hereby granted, free of charge, to any person obtaining 4 4 * a copy of this software and associated documentation files (the 5 5 * "Software"), to deal in the Software without restriction, including 6 6 * without limitation the rights to use, copy, modify, merge, publish, 7 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 8 * permit persons to whom the Software is furnished to do so, subject to 9 9 * the following conditions: 10 10 * 11 11 * The above copyright notice and this permission notice shall be included 12 12 * in all copies or substantial portions of the Software. 13 13 * 14 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 21 */ 22 22 23 23 /* 24 24 * compiler-specific macros and fixes 25 25 */ 26 26 27 27 #ifndef INCLUDED_COMPILER 28 28 #define INCLUDED_COMPILER 29 29 30 30 // detect compiler and its version (0 if not present, otherwise 31 31 // major*100 + minor). note that more than one *_VERSION may be 32 32 // non-zero due to interoperability (e.g. ICC with MSC). 33 33 // .. VC 34 34 #ifdef _MSC_VER 35 35 # define MSC_VERSION _MSC_VER 36 36 #else 37 37 # define MSC_VERSION 0 38 38 #endif 39 39 // .. ICC (VC-compatible, GCC-compatible) 40 40 #if defined(__INTEL_COMPILER) 41 41 # define ICC_VERSION __INTEL_COMPILER 42 42 #else 43 43 # define ICC_VERSION 0 44 44 #endif 45 45 // .. LCC (VC-compatible) 46 #if defined(__LCC__) 46 // LCC-Win32 and MCST LCC compilers define same identifier (__LCC__). 47 // Have been added check of MCST Elbrus 2000 (e2k) architecture. 48 #if defined(__LCC__) && !defined(__e2k__) 47 49 # define LCC_VERSION __LCC__ 48 50 #else 49 51 # define LCC_VERSION 0 50 52 #endif 53 // .. MCST LCC (eLbrus C/C++ Compiler) 54 #if defined(__LCC__) && defined(__e2k__) 55 # define MCST_LCC_VERSION (__LCC__*100 + __LCC_MINOR__) 56 #else 57 # define MCST_LCC_VERSION 0 58 #endif 51 59 // .. GCC 52 60 #ifdef __GNUC__ 53 61 # define GCC_VERSION (__GNUC__*100 + __GNUC_MINOR__) 54 62 #else 55 63 # define GCC_VERSION 0 56 64 #endif 57 65 // .. Clang/LLVM (GCC-compatible) 58 66 // use Clang's feature checking macros to check for availability of features 59 67 // http://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros 60 68 #ifdef __clang__ 61 69 # define CLANG_VERSION (__clang_major__*100 + __clang_minor__) 62 70 #else 63 71 # define CLANG_VERSION 0 64 72 #endif 65 73 66 74 // Clang/LLVM feature check macro compatibility 67 75 #ifndef __has_feature 68 76 # define __has_feature(x) 0 69 77 #endif 70 78 71 79 #ifndef __has_cpp_attribute 72 80 # define __has_cpp_attribute(x) 0 73 81 #endif 74 82 75 83 // check if compiling in pure C mode (not C++) with support for C99. 76 84 // (this is more convenient than testing __STDC_VERSION__ directly) 77 85 // 78 86 // note: C99 provides several useful but disjunct bits of functionality. 79 87 // unfortunately, most C++ compilers do not offer a complete implementation. 80 88 // however, many of these features are likely to be added to C++, and/or are 81 89 // already available as extensions. what we'll do is add a HAVE_ macro for 82 90 // each feature and test those instead. they are set if HAVE_C99, or also if 83 91 // the compiler happens to support something compatible. 84 92 // 85 93 // rationale: lying about __STDC_VERSION__ via Premake so as to enable support 86 94 // for some C99 functions doesn't work. Mac OS X headers would then use the 87 95 // restrict keyword, which is never supported by g++ (because that might 88 96 // end up breaking valid C++98 programs). 89 97 #define HAVE_C99 0 90 98 #ifdef __STDC_VERSION__ 91 99 # if __STDC_VERSION__ >= 199901L 92 100 # undef HAVE_C99 93 101 # define HAVE_C99 1 94 102 # endif 95 103 #endif 96 104 97 105 // Streaming SIMD Extensions (not supported by all GCC) 98 106 // this only ascertains compiler support; use x86_x64::Cap to 99 107 // check whether the instructions are supported by the CPU. 100 108 #ifndef HAVE_SSE 101 109 # if GCC_VERSION && defined(__SSE__) 102 110 # define HAVE_SSE 1 103 111 # elif MSC_VERSION // also includes ICC 104 112 # define HAVE_SSE 1 105 113 # else 106 114 # define HAVE_SSE 0 107 115 # endif 108 116 #endif 109 117 110 118 #ifndef HAVE_SSE2 111 119 # if GCC_VERSION && defined(__SSE2__) 112 120 # define HAVE_SSE2 1 113 121 # elif MSC_VERSION // also includes ICC 114 122 # define HAVE_SSE2 1 115 123 # else 116 124 # define HAVE_SSE2 0 117 125 # endif 118 126 #endif 119 127 120 128 #endif // #ifndef INCLUDED_COMPILER -
source/ps/GameSetup/HWDetect.cpp
1 1 /* Copyright (C) 2020 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or 7 7 * (at your option) any later version. 8 8 * 9 9 * 0 A.D. is distributed in the hope that it will be useful, 10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 12 * GNU General Public License for more details. 13 13 * 14 14 * You should have received a copy of the GNU General Public License 15 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 16 */ 17 17 18 18 #include "precompiled.h" 19 19 20 20 #include "scriptinterface/ScriptInterface.h" 21 21 22 22 #include "lib/ogl.h" 23 23 #if CONFIG2_AUDIO 24 24 #include "lib/snd.h" 25 25 #endif 26 26 #include "lib/svn_revision.h" 27 27 #include "lib/timer.h" 28 28 #include "lib/utf8.h" 29 29 #include "lib/external_libraries/libsdl.h" 30 30 #include "lib/res/graphics/ogl_tex.h" 31 31 #include "lib/posix/posix_utsname.h" 32 32 #include "lib/sysdep/cpu.h" 33 33 #include "lib/sysdep/gfx.h" 34 34 #include "lib/sysdep/numa.h" 35 35 #include "lib/sysdep/os_cpu.h" 36 36 #if ARCH_X86_X64 37 37 # include "lib/sysdep/arch/x86_x64/cache.h" 38 38 # include "lib/sysdep/arch/x86_x64/topology.h" 39 39 #endif 40 40 #include "ps/CLogger.h" 41 41 #include "ps/ConfigDB.h" 42 42 #include "ps/Filesystem.h" 43 43 #include "ps/GameSetup/Config.h" 44 44 #include "ps/Profile.h" 45 45 #include "ps/scripting/JSInterface_ConfigDB.h" 46 46 #include "ps/scripting/JSInterface_Debug.h" 47 47 #include "ps/UserReport.h" 48 48 #include "ps/VideoMode.h" 49 49 50 50 // TODO: Support OpenGL platforms which don’t use GLX as well. 51 51 #if defined(SDL_VIDEO_DRIVER_X11) && !CONFIG2_GLES 52 52 #include <GL/glx.h> 53 53 #include <SDL_syswm.h> 54 54 55 55 // Define the GLX_MESA_query_renderer macros if built with 56 56 // an old Mesa (<10.0) that doesn't provide them 57 57 #ifndef GLX_MESA_query_renderer 58 58 #define GLX_MESA_query_renderer 1 59 59 #define GLX_RENDERER_VENDOR_ID_MESA 0x8183 60 60 #define GLX_RENDERER_DEVICE_ID_MESA 0x8184 61 61 #define GLX_RENDERER_VERSION_MESA 0x8185 62 62 #define GLX_RENDERER_ACCELERATED_MESA 0x8186 63 63 #define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187 64 64 #define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188 65 65 #define GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189 66 66 #define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A 67 67 #define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B 68 68 #define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C 69 69 #define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D 70 70 #define GLX_RENDERER_ID_MESA 0x818E 71 71 #endif /* GLX_MESA_query_renderer */ 72 72 73 73 #endif 74 74 75 75 static void ReportSDL(const ScriptInterface& scriptInterface, JS::HandleValue settings); 76 76 static void ReportGLLimits(const ScriptInterface& scriptInterface, JS::HandleValue settings); 77 77 78 78 #if ARCH_X86_X64 79 79 void ConvertCaches(const ScriptInterface& scriptInterface, x86_x64::IdxCache idxCache, JS::MutableHandleValue ret) 80 80 { 81 81 ScriptRequest rq(scriptInterface); 82 82 83 83 ScriptInterface::CreateArray(rq, ret); 84 84 85 85 for (size_t idxLevel = 0; idxLevel < x86_x64::Cache::maxLevels; ++idxLevel) 86 86 { 87 87 const x86_x64::Cache* pcache = x86_x64::Caches(idxCache+idxLevel); 88 88 if (pcache->m_Type == x86_x64::Cache::kNull || pcache->m_NumEntries == 0) 89 89 continue; 90 90 91 91 JS::RootedValue cache(rq.cx); 92 92 93 93 ScriptInterface::CreateObject( 94 94 rq, 95 95 &cache, 96 96 "type", static_cast<u32>(pcache->m_Type), 97 97 "level", static_cast<u32>(pcache->m_Level), 98 98 "associativity", static_cast<u32>(pcache->m_Associativity), 99 99 "linesize", static_cast<u32>(pcache->m_EntrySize), 100 100 "sharedby", static_cast<u32>(pcache->m_SharedBy), 101 101 "totalsize", static_cast<u32>(pcache->TotalSize())); 102 102 103 103 scriptInterface.SetPropertyInt(ret, idxLevel, cache); 104 104 } 105 105 } 106 106 107 107 void ConvertTLBs(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) 108 108 { 109 109 ScriptRequest rq(scriptInterface); 110 110 111 111 ScriptInterface::CreateArray(rq, ret); 112 112 113 113 for(size_t i = 0; ; i++) 114 114 { 115 115 const x86_x64::Cache* ptlb = x86_x64::Caches(x86_x64::TLB+i); 116 116 if (!ptlb) 117 117 break; 118 118 119 119 JS::RootedValue tlb(rq.cx); 120 120 121 121 ScriptInterface::CreateObject( 122 122 rq, 123 123 &tlb, 124 124 "type", static_cast<u32>(ptlb->m_Type), 125 125 "level", static_cast<u32>(ptlb->m_Level), 126 126 "associativity", static_cast<u32>(ptlb->m_Associativity), 127 127 "pagesize", static_cast<u32>(ptlb->m_EntrySize), 128 128 "entries", static_cast<u32>(ptlb->m_NumEntries)); 129 129 130 130 scriptInterface.SetPropertyInt(ret, i, tlb); 131 131 } 132 132 } 133 133 #endif 134 134 135 135 void SetDisableAudio(ScriptInterface::CmptPrivate* UNUSED(pCmptPrivate), bool disabled) 136 136 { 137 137 g_DisableAudio = disabled; 138 138 } 139 139 140 140 void RunHardwareDetection() 141 141 { 142 142 TIMER(L"RunHardwareDetection"); 143 143 144 144 ScriptInterface scriptInterface("Engine", "HWDetect", g_ScriptContext); 145 145 146 146 ScriptRequest rq(scriptInterface); 147 147 148 148 JSI_Debug::RegisterScriptFunctions(scriptInterface); // Engine.DisplayErrorDialog 149 149 JSI_ConfigDB::RegisterScriptFunctions(scriptInterface); 150 150 151 151 scriptInterface.RegisterFunction<void, bool, &SetDisableAudio>("SetDisableAudio"); 152 152 153 153 // Load the detection script: 154 154 155 155 const wchar_t* scriptName = L"hwdetect/hwdetect.js"; 156 156 CVFSFile file; 157 157 if (file.Load(g_VFS, scriptName) != PSRETURN_OK) 158 158 { 159 159 LOGERROR("Failed to load hardware detection script"); 160 160 return; 161 161 } 162 162 163 163 std::string code = file.DecodeUTF8(); // assume it's UTF-8 164 164 scriptInterface.LoadScript(scriptName, code); 165 165 166 166 // Collect all the settings we'll pass to the script: 167 167 // (We'll use this same data for the opt-in online reporting system, so it 168 168 // includes some fields that aren't directly useful for the hwdetect script) 169 169 170 170 JS::RootedValue settings(rq.cx); 171 171 ScriptInterface::CreateObject(rq, &settings); 172 172 173 173 scriptInterface.SetProperty(settings, "os_unix", OS_UNIX); 174 174 scriptInterface.SetProperty(settings, "os_bsd", OS_BSD); 175 175 scriptInterface.SetProperty(settings, "os_linux", OS_LINUX); 176 176 scriptInterface.SetProperty(settings, "os_android", OS_ANDROID); 177 177 scriptInterface.SetProperty(settings, "os_macosx", OS_MACOSX); 178 178 scriptInterface.SetProperty(settings, "os_win", OS_WIN); 179 179 180 180 scriptInterface.SetProperty(settings, "arch_ia32", ARCH_IA32); 181 181 scriptInterface.SetProperty(settings, "arch_amd64", ARCH_AMD64); 182 182 scriptInterface.SetProperty(settings, "arch_arm", ARCH_ARM); 183 183 scriptInterface.SetProperty(settings, "arch_aarch64", ARCH_AARCH64); 184 scriptInterface.SetProperty(settings, "arch_e2k", ARCH_E2K); 184 185 185 186 #ifdef NDEBUG 186 187 scriptInterface.SetProperty(settings, "build_debug", 0); 187 188 #else 188 189 scriptInterface.SetProperty(settings, "build_debug", 1); 189 190 #endif 190 191 scriptInterface.SetProperty(settings, "build_opengles", CONFIG2_GLES); 191 192 192 193 scriptInterface.SetProperty(settings, "build_datetime", std::string(__DATE__ " " __TIME__)); 193 194 scriptInterface.SetProperty(settings, "build_revision", std::wstring(svn_revision)); 194 195 195 196 scriptInterface.SetProperty(settings, "build_msc", (int)MSC_VERSION); 196 197 scriptInterface.SetProperty(settings, "build_icc", (int)ICC_VERSION); 197 198 scriptInterface.SetProperty(settings, "build_gcc", (int)GCC_VERSION); 198 199 scriptInterface.SetProperty(settings, "build_clang", (int)CLANG_VERSION); 199 200 200 201 scriptInterface.SetProperty(settings, "gfx_card", gfx::CardName()); 201 202 scriptInterface.SetProperty(settings, "gfx_drv_ver", gfx::DriverInfo()); 202 203 #if CONFIG2_AUDIO 203 204 scriptInterface.SetProperty(settings, "snd_card", snd_card); 204 205 scriptInterface.SetProperty(settings, "snd_drv_ver", snd_drv_ver); 205 206 #endif 206 207 ReportSDL(scriptInterface, settings); 207 208 208 209 ReportGLLimits(scriptInterface, settings); 209 210 210 211 scriptInterface.SetProperty(settings, "video_desktop_xres", g_VideoMode.GetDesktopXRes()); 211 212 scriptInterface.SetProperty(settings, "video_desktop_yres", g_VideoMode.GetDesktopYRes()); 212 213 scriptInterface.SetProperty(settings, "video_desktop_bpp", g_VideoMode.GetDesktopBPP()); 213 214 scriptInterface.SetProperty(settings, "video_desktop_freq", g_VideoMode.GetDesktopFreq()); 214 215 215 216 struct utsname un; 216 217 uname(&un); 217 218 scriptInterface.SetProperty(settings, "uname_sysname", std::string(un.sysname)); 218 219 scriptInterface.SetProperty(settings, "uname_release", std::string(un.release)); 219 220 scriptInterface.SetProperty(settings, "uname_version", std::string(un.version)); 220 221 scriptInterface.SetProperty(settings, "uname_machine", std::string(un.machine)); 221 222 222 223 #if OS_LINUX 223 224 { 224 225 std::ifstream ifs("/etc/lsb-release"); 225 226 if (ifs.good()) 226 227 { 227 228 std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>()); 228 229 scriptInterface.SetProperty(settings, "linux_release", str); 229 230 } 230 231 } 231 232 #endif 232 233 233 234 scriptInterface.SetProperty(settings, "cpu_identifier", std::string(cpu_IdentifierString())); 234 235 scriptInterface.SetProperty(settings, "cpu_frequency", os_cpu_ClockFrequency()); 235 236 scriptInterface.SetProperty(settings, "cpu_pagesize", (u32)os_cpu_PageSize()); 236 237 scriptInterface.SetProperty(settings, "cpu_largepagesize", (u32)os_cpu_LargePageSize()); 237 238 scriptInterface.SetProperty(settings, "cpu_numprocs", (u32)os_cpu_NumProcessors()); 238 239 #if ARCH_X86_X64 239 240 scriptInterface.SetProperty(settings, "cpu_numpackages", (u32)topology::NumPackages()); 240 241 scriptInterface.SetProperty(settings, "cpu_coresperpackage", (u32)topology::CoresPerPackage()); 241 242 scriptInterface.SetProperty(settings, "cpu_logicalpercore", (u32)topology::LogicalPerCore()); 242 243 scriptInterface.SetProperty(settings, "cpu_numcaches", (u32)topology::NumCaches()); 243 244 #endif 244 245 245 246 scriptInterface.SetProperty(settings, "numa_numnodes", (u32)numa_NumNodes()); 246 247 scriptInterface.SetProperty(settings, "numa_factor", numa_Factor()); 247 248 scriptInterface.SetProperty(settings, "numa_interleaved", numa_IsMemoryInterleaved()); 248 249 249 250 scriptInterface.SetProperty(settings, "ram_total", (u32)os_cpu_MemorySize()); 250 251 scriptInterface.SetProperty(settings, "ram_total_os", (u32)os_cpu_QueryMemorySize()); 251 252 252 253 #if ARCH_X86_X64 253 254 scriptInterface.SetProperty(settings, "x86_vendor", (u32)x86_x64::Vendor()); 254 255 scriptInterface.SetProperty(settings, "x86_model", (u32)x86_x64::Model()); 255 256 scriptInterface.SetProperty(settings, "x86_family", (u32)x86_x64::Family()); 256 257 257 258 u32 caps0, caps1, caps2, caps3; 258 259 x86_x64::GetCapBits(&caps0, &caps1, &caps2, &caps3); 259 260 scriptInterface.SetProperty(settings, "x86_caps[0]", caps0); 260 261 scriptInterface.SetProperty(settings, "x86_caps[1]", caps1); 261 262 scriptInterface.SetProperty(settings, "x86_caps[2]", caps2); 262 263 scriptInterface.SetProperty(settings, "x86_caps[3]", caps3); 263 264 264 265 JS::RootedValue tmpVal(rq.cx); 265 266 ConvertCaches(scriptInterface, x86_x64::L1I, &tmpVal); 266 267 scriptInterface.SetProperty(settings, "x86_icaches", tmpVal); 267 268 ConvertCaches(scriptInterface, x86_x64::L1D, &tmpVal); 268 269 scriptInterface.SetProperty(settings, "x86_dcaches", tmpVal); 269 270 ConvertTLBs(scriptInterface, &tmpVal); 270 271 scriptInterface.SetProperty(settings, "x86_tlbs", tmpVal); 271 272 #endif 272 273 273 274 scriptInterface.SetProperty(settings, "timer_resolution", timer_Resolution()); 274 275 275 276 // The version should be increased for every meaningful change. 276 277 const int reportVersion = 13; 277 278 278 279 // Send the same data to the reporting system 279 280 g_UserReporter.SubmitReport( 280 281 "hwdetect", 281 282 reportVersion, 282 283 scriptInterface.StringifyJSON(&settings, false), 283 284 scriptInterface.StringifyJSON(&settings, true)); 284 285 285 286 // Run the detection script: 286 287 JS::RootedValue global(rq.cx, rq.globalValue()); 287 288 scriptInterface.CallFunctionVoid(global, "RunHardwareDetection", settings); 288 289 } 289 290 290 291 static void ReportSDL(const ScriptInterface& scriptInterface, JS::HandleValue settings) 291 292 { 292 293 SDL_version build, runtime; 293 294 SDL_VERSION(&build); 294 295 295 296 char version[16]; 296 297 snprintf(version, ARRAY_SIZE(version), "%d.%d.%d", build.major, build.minor, build.patch); 297 298 scriptInterface.SetProperty(settings, "sdl_build_version", version); 298 299 299 300 SDL_GetVersion(&runtime); 300 301 snprintf(version, ARRAY_SIZE(version), "%d.%d.%d", runtime.major, runtime.minor, runtime.patch); 301 302 scriptInterface.SetProperty(settings, "sdl_runtime_version", version); 302 303 303 304 // This is null in atlas (and further the call triggers an assertion). 304 305 const char* backend = g_VideoMode.GetWindow() ? GetSDLSubsystem(g_VideoMode.GetWindow()) : "none"; 305 306 scriptInterface.SetProperty(settings, "sdl_video_backend", backend ? backend : "unknown"); 306 307 } 307 308 308 309 static void ReportGLLimits(const ScriptInterface& scriptInterface, JS::HandleValue settings) 309 310 { 310 311 const char* errstr = "(error)"; 311 312 312 313 #define INTEGER(id) do { \ 313 314 GLint i = -1; \ 314 315 glGetIntegerv(GL_##id, &i); \ 315 316 if (ogl_SquelchError(GL_INVALID_ENUM)) \ 316 317 scriptInterface.SetProperty(settings, "GL_" #id, errstr); \ 317 318 else \ 318 319 scriptInterface.SetProperty(settings, "GL_" #id, i); \ 319 320 } while (false) 320 321 321 322 #define INTEGER2(id) do { \ 322 323 GLint i[2] = { -1, -1 }; \ 323 324 glGetIntegerv(GL_##id, i); \ 324 325 if (ogl_SquelchError(GL_INVALID_ENUM)) { \ 325 326 scriptInterface.SetProperty(settings, "GL_" #id "[0]", errstr); \ 326 327 scriptInterface.SetProperty(settings, "GL_" #id "[1]", errstr); \ 327 328 } else { \ 328 329 scriptInterface.SetProperty(settings, "GL_" #id "[0]", i[0]); \ 329 330 scriptInterface.SetProperty(settings, "GL_" #id "[1]", i[1]); \ 330 331 } \ 331 332 } while (false) 332 333 333 334 #define FLOAT(id) do { \ 334 335 GLfloat f = std::numeric_limits<GLfloat>::quiet_NaN(); \ 335 336 glGetFloatv(GL_##id, &f); \ 336 337 if (ogl_SquelchError(GL_INVALID_ENUM)) \ 337 338 scriptInterface.SetProperty(settings, "GL_" #id, errstr); \ 338 339 else \ 339 340 scriptInterface.SetProperty(settings, "GL_" #id, f); \ 340 341 } while (false) 341 342 342 343 #define FLOAT2(id) do { \ 343 344 GLfloat f[2] = { std::numeric_limits<GLfloat>::quiet_NaN(), std::numeric_limits<GLfloat>::quiet_NaN() }; \ 344 345 glGetFloatv(GL_##id, f); \ 345 346 if (ogl_SquelchError(GL_INVALID_ENUM)) { \ 346 347 scriptInterface.SetProperty(settings, "GL_" #id "[0]", errstr); \ 347 348 scriptInterface.SetProperty(settings, "GL_" #id "[1]", errstr); \ 348 349 } else { \ 349 350 scriptInterface.SetProperty(settings, "GL_" #id "[0]", f[0]); \ 350 351 scriptInterface.SetProperty(settings, "GL_" #id "[1]", f[1]); \ 351 352 } \ 352 353 } while (false) 353 354 354 355 #define STRING(id) do { \ 355 356 const char* c = (const char*)glGetString(GL_##id); \ 356 357 if (!c) c = ""; \ 357 358 if (ogl_SquelchError(GL_INVALID_ENUM)) c = errstr; \ 358 359 scriptInterface.SetProperty(settings, "GL_" #id, std::string(c)); \ 359 360 } while (false) 360 361 361 362 #define QUERY(target, pname) do { \ 362 363 GLint i = -1; \ 363 364 pglGetQueryivARB(GL_##target, GL_##pname, &i); \ 364 365 if (ogl_SquelchError(GL_INVALID_ENUM)) \ 365 366 scriptInterface.SetProperty(settings, "GL_" #target ".GL_" #pname, errstr); \ 366 367 else \ 367 368 scriptInterface.SetProperty(settings, "GL_" #target ".GL_" #pname, i); \ 368 369 } while (false) 369 370 370 371 #define VERTEXPROGRAM(id) do { \ 371 372 GLint i = -1; \ 372 373 pglGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_##id, &i); \ 373 374 if (ogl_SquelchError(GL_INVALID_ENUM)) \ 374 375 scriptInterface.SetProperty(settings, "GL_VERTEX_PROGRAM_ARB.GL_" #id, errstr); \ 375 376 else \ 376 377 scriptInterface.SetProperty(settings, "GL_VERTEX_PROGRAM_ARB.GL_" #id, i); \ 377 378 } while (false) 378 379 379 380 #define FRAGMENTPROGRAM(id) do { \ 380 381 GLint i = -1; \ 381 382 pglGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_##id, &i); \ 382 383 if (ogl_SquelchError(GL_INVALID_ENUM)) \ 383 384 scriptInterface.SetProperty(settings, "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, errstr); \ 384 385 else \ 385 386 scriptInterface.SetProperty(settings, "GL_FRAGMENT_PROGRAM_ARB.GL_" #id, i); \ 386 387 } while (false) 387 388 388 389 #define BOOL(id) INTEGER(id) 389 390 390 391 ogl_WarnIfError(); 391 392 392 393 // Core OpenGL 1.3: 393 394 // (We don't bother checking extension strings for anything older than 1.3; 394 395 // it'll just produce harmless warnings) 395 396 STRING(VERSION); 396 397 STRING(VENDOR); 397 398 STRING(RENDERER); 398 399 STRING(EXTENSIONS); 399 400 #if !CONFIG2_GLES 400 401 INTEGER(MAX_LIGHTS); 401 402 INTEGER(MAX_CLIP_PLANES); 402 403 // Skip MAX_COLOR_MATRIX_STACK_DEPTH (only in imaging subset) 403 404 INTEGER(MAX_MODELVIEW_STACK_DEPTH); 404 405 INTEGER(MAX_PROJECTION_STACK_DEPTH); 405 406 INTEGER(MAX_TEXTURE_STACK_DEPTH); 406 407 #endif 407 408 INTEGER(SUBPIXEL_BITS); 408 409 #if !CONFIG2_GLES 409 410 INTEGER(MAX_3D_TEXTURE_SIZE); 410 411 #endif 411 412 INTEGER(MAX_TEXTURE_SIZE); 412 413 INTEGER(MAX_CUBE_MAP_TEXTURE_SIZE); 413 414 #if !CONFIG2_GLES 414 415 INTEGER(MAX_PIXEL_MAP_TABLE); 415 416 INTEGER(MAX_NAME_STACK_DEPTH); 416 417 INTEGER(MAX_LIST_NESTING); 417 418 INTEGER(MAX_EVAL_ORDER); 418 419 #endif 419 420 INTEGER2(MAX_VIEWPORT_DIMS); 420 421 #if !CONFIG2_GLES 421 422 INTEGER(MAX_ATTRIB_STACK_DEPTH); 422 423 INTEGER(MAX_CLIENT_ATTRIB_STACK_DEPTH); 423 424 INTEGER(AUX_BUFFERS); 424 425 BOOL(RGBA_MODE); 425 426 BOOL(INDEX_MODE); 426 427 BOOL(DOUBLEBUFFER); 427 428 BOOL(STEREO); 428 429 #endif 429 430 FLOAT2(ALIASED_POINT_SIZE_RANGE); 430 431 #if !CONFIG2_GLES 431 432 FLOAT2(SMOOTH_POINT_SIZE_RANGE); 432 433 FLOAT(SMOOTH_POINT_SIZE_GRANULARITY); 433 434 #endif 434 435 FLOAT2(ALIASED_LINE_WIDTH_RANGE); 435 436 #if !CONFIG2_GLES 436 437 FLOAT2(SMOOTH_LINE_WIDTH_RANGE); 437 438 FLOAT(SMOOTH_LINE_WIDTH_GRANULARITY); 438 439 // Skip MAX_CONVOLUTION_WIDTH, MAX_CONVOLUTION_HEIGHT (only in imaging subset) 439 440 INTEGER(MAX_ELEMENTS_INDICES); 440 441 INTEGER(MAX_ELEMENTS_VERTICES); 441 442 INTEGER(MAX_TEXTURE_UNITS); 442 443 #endif 443 444 INTEGER(SAMPLE_BUFFERS); 444 445 INTEGER(SAMPLES); 445 446 // TODO: compressed texture formats 446 447 INTEGER(RED_BITS); 447 448 INTEGER(GREEN_BITS); 448 449 INTEGER(BLUE_BITS); 449 450 INTEGER(ALPHA_BITS); 450 451 #if !CONFIG2_GLES 451 452 INTEGER(INDEX_BITS); 452 453 #endif 453 454 INTEGER(DEPTH_BITS); 454 455 INTEGER(STENCIL_BITS); 455 456 #if !CONFIG2_GLES 456 457 INTEGER(ACCUM_RED_BITS); 457 458 INTEGER(ACCUM_GREEN_BITS); 458 459 INTEGER(ACCUM_BLUE_BITS); 459 460 INTEGER(ACCUM_ALPHA_BITS); 460 461 #endif 461 462 462 463 #if !CONFIG2_GLES 463 464 464 465 // Core OpenGL 2.0 (treated as extensions): 465 466 466 467 if (ogl_HaveExtension("GL_EXT_texture_lod_bias")) 467 468 { 468 469 FLOAT(MAX_TEXTURE_LOD_BIAS_EXT); 469 470 } 470 471 471 472 if (ogl_HaveExtension("GL_ARB_occlusion_query")) 472 473 { 473 474 QUERY(SAMPLES_PASSED, QUERY_COUNTER_BITS); 474 475 } 475 476 476 477 if (ogl_HaveExtension("GL_ARB_shading_language_100")) 477 478 { 478 479 STRING(SHADING_LANGUAGE_VERSION_ARB); 479 480 } 480 481 481 482 if (ogl_HaveExtension("GL_ARB_vertex_shader")) 482 483 { 483 484 INTEGER(MAX_VERTEX_ATTRIBS_ARB); 484 485 INTEGER(MAX_VERTEX_UNIFORM_COMPONENTS_ARB); 485 486 INTEGER(MAX_VARYING_FLOATS_ARB); 486 487 INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB); 487 488 INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB); 488 489 } 489 490 490 491 if (ogl_HaveExtension("GL_ARB_fragment_shader")) 491 492 { 492 493 INTEGER(MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB); 493 494 } 494 495 495 496 if (ogl_HaveExtension("GL_ARB_vertex_shader") || ogl_HaveExtension("GL_ARB_fragment_shader") || 496 497 ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program")) 497 498 { 498 499 INTEGER(MAX_TEXTURE_IMAGE_UNITS_ARB); 499 500 INTEGER(MAX_TEXTURE_COORDS_ARB); 500 501 } 501 502 502 503 if (ogl_HaveExtension("GL_ARB_draw_buffers")) 503 504 { 504 505 INTEGER(MAX_DRAW_BUFFERS_ARB); 505 506 } 506 507 507 508 // Core OpenGL 3.0: 508 509 509 510 if (ogl_HaveExtension("GL_EXT_gpu_shader4")) 510 511 { 511 512 INTEGER(MIN_PROGRAM_TEXEL_OFFSET); // no _EXT version of these in glext.h 512 513 INTEGER(MAX_PROGRAM_TEXEL_OFFSET); 513 514 } 514 515 515 516 if (ogl_HaveExtension("GL_EXT_framebuffer_object")) 516 517 { 517 518 INTEGER(MAX_COLOR_ATTACHMENTS_EXT); 518 519 INTEGER(MAX_RENDERBUFFER_SIZE_EXT); 519 520 } 520 521 521 522 if (ogl_HaveExtension("GL_EXT_framebuffer_multisample")) 522 523 { 523 524 INTEGER(MAX_SAMPLES_EXT); 524 525 } 525 526 526 527 if (ogl_HaveExtension("GL_EXT_texture_array")) 527 528 { 528 529 INTEGER(MAX_ARRAY_TEXTURE_LAYERS_EXT); 529 530 } 530 531 531 532 if (ogl_HaveExtension("GL_EXT_transform_feedback")) 532 533 { 533 534 INTEGER(MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT); 534 535 INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT); 535 536 INTEGER(MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT); 536 537 } 537 538 538 539 539 540 // Other interesting extensions: 540 541 541 542 if (ogl_HaveExtension("GL_EXT_timer_query") || ogl_HaveExtension("GL_ARB_timer_query")) 542 543 { 543 544 QUERY(TIME_ELAPSED, QUERY_COUNTER_BITS); 544 545 } 545 546 546 547 if (ogl_HaveExtension("GL_ARB_timer_query")) 547 548 { 548 549 QUERY(TIMESTAMP, QUERY_COUNTER_BITS); 549 550 } 550 551 551 552 if (ogl_HaveExtension("GL_EXT_texture_filter_anisotropic")) 552 553 { 553 554 FLOAT(MAX_TEXTURE_MAX_ANISOTROPY_EXT); 554 555 } 555 556 556 557 if (ogl_HaveExtension("GL_ARB_texture_rectangle")) 557 558 { 558 559 INTEGER(MAX_RECTANGLE_TEXTURE_SIZE_ARB); 559 560 } 560 561 561 562 if (ogl_HaveExtension("GL_ARB_vertex_program") || ogl_HaveExtension("GL_ARB_fragment_program")) 562 563 { 563 564 INTEGER(MAX_PROGRAM_MATRICES_ARB); 564 565 INTEGER(MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB); 565 566 } 566 567 567 568 if (ogl_HaveExtension("GL_ARB_vertex_program")) 568 569 { 569 570 VERTEXPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB); 570 571 VERTEXPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB); 571 572 VERTEXPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB); 572 573 VERTEXPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB); 573 574 VERTEXPROGRAM(MAX_PROGRAM_PARAMETERS_ARB); 574 575 VERTEXPROGRAM(MAX_PROGRAM_ATTRIBS_ARB); 575 576 VERTEXPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB); 576 577 VERTEXPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB); 577 578 VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB); 578 579 VERTEXPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB); 579 580 VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB); 580 581 VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB); 581 582 582 583 if (ogl_HaveExtension("GL_ARB_fragment_program")) 583 584 { 584 585 // The spec seems to say these should be supported, but 585 586 // Mesa complains about them so let's not bother 586 587 /* 587 588 VERTEXPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB); 588 589 VERTEXPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB); 589 590 VERTEXPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB); 590 591 VERTEXPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB); 591 592 VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB); 592 593 VERTEXPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB); 593 594 */ 594 595 } 595 596 } 596 597 597 598 if (ogl_HaveExtension("GL_ARB_fragment_program")) 598 599 { 599 600 FRAGMENTPROGRAM(MAX_PROGRAM_ENV_PARAMETERS_ARB); 600 601 FRAGMENTPROGRAM(MAX_PROGRAM_LOCAL_PARAMETERS_ARB); 601 602 FRAGMENTPROGRAM(MAX_PROGRAM_INSTRUCTIONS_ARB); 602 603 FRAGMENTPROGRAM(MAX_PROGRAM_ALU_INSTRUCTIONS_ARB); 603 604 FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INSTRUCTIONS_ARB); 604 605 FRAGMENTPROGRAM(MAX_PROGRAM_TEX_INDIRECTIONS_ARB); 605 606 FRAGMENTPROGRAM(MAX_PROGRAM_TEMPORARIES_ARB); 606 607 FRAGMENTPROGRAM(MAX_PROGRAM_PARAMETERS_ARB); 607 608 FRAGMENTPROGRAM(MAX_PROGRAM_ATTRIBS_ARB); 608 609 FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB); 609 610 FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB); 610 611 FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB); 611 612 FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB); 612 613 FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_TEMPORARIES_ARB); 613 614 FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_PARAMETERS_ARB); 614 615 FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ATTRIBS_ARB); 615 616 616 617 if (ogl_HaveExtension("GL_ARB_vertex_program")) 617 618 { 618 619 // The spec seems to say these should be supported, but 619 620 // Intel drivers on Windows complain about them so let's not bother 620 621 /* 621 622 FRAGMENTPROGRAM(MAX_PROGRAM_ADDRESS_REGISTERS_ARB); 622 623 FRAGMENTPROGRAM(MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB); 623 624 */ 624 625 } 625 626 } 626 627 627 628 if (ogl_HaveExtension("GL_ARB_geometry_shader4")) 628 629 { 629 630 INTEGER(MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB); 630 631 INTEGER(MAX_GEOMETRY_OUTPUT_VERTICES_ARB); 631 632 INTEGER(MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB); 632 633 INTEGER(MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB); 633 634 INTEGER(MAX_GEOMETRY_VARYING_COMPONENTS_ARB); 634 635 INTEGER(MAX_VERTEX_VARYING_COMPONENTS_ARB); 635 636 } 636 637 637 638 #else // CONFIG2_GLES 638 639 639 640 // Core OpenGL ES 2.0: 640 641 641 642 STRING(SHADING_LANGUAGE_VERSION); 642 643 INTEGER(MAX_VERTEX_ATTRIBS); 643 644 INTEGER(MAX_VERTEX_UNIFORM_VECTORS); 644 645 INTEGER(MAX_VARYING_VECTORS); 645 646 INTEGER(MAX_COMBINED_TEXTURE_IMAGE_UNITS); 646 647 INTEGER(MAX_VERTEX_TEXTURE_IMAGE_UNITS); 647 648 INTEGER(MAX_FRAGMENT_UNIFORM_VECTORS); 648 649 INTEGER(MAX_TEXTURE_IMAGE_UNITS); 649 650 INTEGER(MAX_RENDERBUFFER_SIZE); 650 651 651 652 #endif // CONFIG2_GLES 652 653 653 654 654 655 // TODO: Support OpenGL platforms which don’t use GLX as well. 655 656 #if defined(SDL_VIDEO_DRIVER_X11) && !CONFIG2_GLES 656 657 657 658 #define GLXQCR_INTEGER(id) do { \ 658 659 unsigned int i = UINT_MAX; \ 659 660 if (pglXQueryCurrentRendererIntegerMESA(id, &i)) \ 660 661 scriptInterface.SetProperty(settings, #id, i); \ 661 662 } while (false) 662 663 663 664 #define GLXQCR_INTEGER2(id) do { \ 664 665 unsigned int i[2] = { UINT_MAX, UINT_MAX }; \ 665 666 if (pglXQueryCurrentRendererIntegerMESA(id, i)) { \ 666 667 scriptInterface.SetProperty(settings, #id "[0]", i[0]); \ 667 668 scriptInterface.SetProperty(settings, #id "[1]", i[1]); \ 668 669 } \ 669 670 } while (false) 670 671 671 672 #define GLXQCR_INTEGER3(id) do { \ 672 673 unsigned int i[3] = { UINT_MAX, UINT_MAX, UINT_MAX }; \ 673 674 if (pglXQueryCurrentRendererIntegerMESA(id, i)) { \ 674 675 scriptInterface.SetProperty(settings, #id "[0]", i[0]); \ 675 676 scriptInterface.SetProperty(settings, #id "[1]", i[1]); \ 676 677 scriptInterface.SetProperty(settings, #id "[2]", i[2]); \ 677 678 } \ 678 679 } while (false) 679 680 680 681 #define GLXQCR_STRING(id) do { \ 681 682 const char* str = pglXQueryCurrentRendererStringMESA(id); \ 682 683 if (str) \ 683 684 scriptInterface.SetProperty(settings, #id ".string", str); \ 684 685 } while (false) 685 686 686 687 687 688 SDL_SysWMinfo wminfo; 688 689 SDL_VERSION(&wminfo.version); 689 690 const int ret = SDL_GetWindowWMInfo(g_VideoMode.GetWindow(), &wminfo); 690 691 if (ret && wminfo.subsystem == SDL_SYSWM_X11) 691 692 { 692 693 Display* dpy = wminfo.info.x11.display; 693 694 int scrnum = DefaultScreen(dpy); 694 695 695 696 const char* glxexts = glXQueryExtensionsString(dpy, scrnum); 696 697 697 698 scriptInterface.SetProperty(settings, "glx_extensions", glxexts); 698 699 699 700 if (strstr(glxexts, "GLX_MESA_query_renderer") && pglXQueryCurrentRendererIntegerMESA && pglXQueryCurrentRendererStringMESA) 700 701 { 701 702 GLXQCR_INTEGER(GLX_RENDERER_VENDOR_ID_MESA); 702 703 GLXQCR_INTEGER(GLX_RENDERER_DEVICE_ID_MESA); 703 704 GLXQCR_INTEGER3(GLX_RENDERER_VERSION_MESA); 704 705 GLXQCR_INTEGER(GLX_RENDERER_ACCELERATED_MESA); 705 706 GLXQCR_INTEGER(GLX_RENDERER_VIDEO_MEMORY_MESA); 706 707 GLXQCR_INTEGER(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA); 707 708 GLXQCR_INTEGER(GLX_RENDERER_PREFERRED_PROFILE_MESA); 708 709 GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA); 709 710 GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA); 710 711 GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA); 711 712 GLXQCR_INTEGER2(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA); 712 713 GLXQCR_STRING(GLX_RENDERER_VENDOR_ID_MESA); 713 714 GLXQCR_STRING(GLX_RENDERER_DEVICE_ID_MESA); 714 715 } 715 716 } 716 717 #endif // SDL_VIDEO_DRIVER_X11 717 718 718 719 } -
source/renderer/ModelRenderer.cpp
1 1 /* Copyright (C) 2020 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or 7 7 * (at your option) any later version. 8 8 * 9 9 * 0 A.D. is distributed in the hope that it will be useful, 10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 12 * GNU General Public License for more details. 13 13 * 14 14 * You should have received a copy of the GNU General Public License 15 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 16 */ 17 17 18 18 #include "precompiled.h" 19 19 20 20 #include "graphics/Color.h" 21 21 #include "graphics/LightEnv.h" 22 22 #include "graphics/Material.h" 23 23 #include "graphics/Model.h" 24 24 #include "graphics/ModelDef.h" 25 25 #include "graphics/ShaderManager.h" 26 26 #include "graphics/TextureManager.h" 27 27 #include "lib/allocators/allocator_adapters.h" 28 28 #include "lib/allocators/arena.h" 29 29 #include "lib/hash.h" 30 30 #include "lib/ogl.h" 31 31 #include "maths/Vector3D.h" 32 32 #include "maths/Vector4D.h" 33 33 #include "ps/CLogger.h" 34 34 #include "ps/Profile.h" 35 35 #include "renderer/MikktspaceWrap.h" 36 36 #include "renderer/ModelRenderer.h" 37 37 #include "renderer/ModelVertexRenderer.h" 38 38 #include "renderer/Renderer.h" 39 39 #include "renderer/RenderModifiers.h" 40 40 #include "renderer/SkyManager.h" 41 41 #include "renderer/TimeManager.h" 42 42 #include "renderer/WaterManager.h" 43 43 44 #if ARCH_X86_X6445 # include "lib/sysdep/arch/x86_x64/x86_x64.h"46 #endif47 48 44 /////////////////////////////////////////////////////////////////////////////////////////////// 49 45 // ModelRenderer implementation 50 46 51 #if ARCH_X86_X6447 #if HAVE_SSE 52 48 static bool g_EnableSSE = false; 53 49 #endif 54 50 55 51 void ModelRenderer::Init() 56 52 { 57 #if ARCH_X86_X6458 if ( x86_x64::Cap(x86_x64::CAP_SSE))53 #if HAVE_SSE 54 if (IsSSEEnabled()) 59 55 g_EnableSSE = true; 60 56 #endif 61 57 } 62 58 63 59 // Helper function to copy object-space position and normal vectors into arrays. 64 60 void ModelRenderer::CopyPositionAndNormals( 65 61 const CModelDefPtr& mdef, 66 62 const VertexArrayIterator<CVector3D>& Position, 67 63 const VertexArrayIterator<CVector3D>& Normal) 68 64 { 69 65 size_t numVertices = mdef->GetNumVertices(); 70 66 SModelVertex* vertices = mdef->GetVertices(); 71 67 72 68 for (size_t j = 0; j < numVertices; ++j) 73 69 { 74 70 Position[j] = vertices[j].m_Coords; 75 71 Normal[j] = vertices[j].m_Norm; 76 72 } 77 73 } 78 74 79 75 // Helper function to transform position and normal vectors into world-space. 80 76 void ModelRenderer::BuildPositionAndNormals( 81 77 CModel* model, 82 78 const VertexArrayIterator<CVector3D>& Position, 83 79 const VertexArrayIterator<CVector3D>& Normal) 84 80 { 85 81 CModelDefPtr mdef = model->GetModelDef(); 86 82 size_t numVertices = mdef->GetNumVertices(); 87 83 SModelVertex* vertices = mdef->GetVertices(); 88 84 89 85 if (model->IsSkinned()) 90 86 { 91 87 // boned model - calculate skinned vertex positions/normals 92 88 93 89 // Avoid the noisy warnings that occur inside SkinPoint/SkinNormal in 94 90 // some broken situations 95 91 if (numVertices && vertices[0].m_Blend.m_Bone[0] == 0xff) 96 92 { 97 93 LOGERROR("Model %s is boned with unboned animation", mdef->GetName().string8()); 98 94 return; 99 95 } 100 96 101 97 #if HAVE_SSE 102 98 if (g_EnableSSE) 103 99 { 104 100 CModelDef::SkinPointsAndNormals_SSE(numVertices, Position, Normal, vertices, mdef->GetBlendIndices(), model->GetAnimatedBoneMatrices()); 105 101 } 106 102 else 107 103 #endif 108 104 { 109 105 CModelDef::SkinPointsAndNormals(numVertices, Position, Normal, vertices, mdef->GetBlendIndices(), model->GetAnimatedBoneMatrices()); 110 106 } 111 107 } 112 108 else 113 109 { 114 110 PROFILE("software transform"); 115 111 // just copy regular positions, transform normals to world space 116 112 const CMatrix3D& transform = model->GetTransform(); 117 113 const CMatrix3D& invtransform = model->GetInvTransform(); 118 114 for (size_t j = 0; j < numVertices; ++j) 119 115 { 120 116 transform.Transform(vertices[j].m_Coords, Position[j]); 121 117 invtransform.RotateTransposed(vertices[j].m_Norm, Normal[j]); 122 118 } 123 119 } 124 120 } 125 121 126 122 127 123 // Helper function for lighting 128 124 void ModelRenderer::BuildColor4ub( 129 125 CModel* model, 130 126 const VertexArrayIterator<CVector3D>& Normal, 131 127 const VertexArrayIterator<SColor4ub>& Color) 132 128 { 133 129 PROFILE("lighting vertices"); 134 130 135 131 CModelDefPtr mdef = model->GetModelDef(); 136 132 size_t numVertices = mdef->GetNumVertices(); 137 133 const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); 138 134 CColor shadingColor = model->GetShadingColor(); 139 135 140 136 for (size_t j = 0; j < numVertices; ++j) 141 137 { 142 138 RGBColor tempcolor = lightEnv.EvaluateUnitScaled(Normal[j]); 143 139 tempcolor.X *= shadingColor.r; 144 140 tempcolor.Y *= shadingColor.g; 145 141 tempcolor.Z *= shadingColor.b; 146 142 Color[j] = ConvertRGBColorTo4ub(tempcolor); 147 143 } 148 144 } 149 145 150 146 151 147 void ModelRenderer::GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices, bool gpuSkinning) 152 148 { 153 149 MikkTSpace ms(mdef, newVertices, gpuSkinning); 154 150 ms.Generate(); 155 151 } 156 152 157 153 158 154 // Copy UV coordinates 159 155 void ModelRenderer::BuildUV( 160 156 const CModelDefPtr& mdef, 161 157 const VertexArrayIterator<float[2]>& UV, 162 158 int UVset) 163 159 { 164 160 size_t numVertices = mdef->GetNumVertices(); 165 161 SModelVertex* vertices = mdef->GetVertices(); 166 162 167 163 for (size_t j = 0; j < numVertices; ++j) 168 164 { 169 165 UV[j][0] = vertices[j].m_UVs[UVset * 2]; 170 166 UV[j][1] = 1.0 - vertices[j].m_UVs[UVset * 2 + 1]; 171 167 } 172 168 } 173 169 174 170 175 171 // Build default indices array. 176 172 void ModelRenderer::BuildIndices( 177 173 const CModelDefPtr& mdef, 178 174 const VertexArrayIterator<u16>& Indices) 179 175 { 180 176 size_t idxidx = 0; 181 177 SModelFace* faces = mdef->GetFaces(); 182 178 183 179 for (size_t j = 0; j < mdef->GetNumFaces(); ++j) 184 180 { 185 181 SModelFace& face = faces[j]; 186 182 Indices[idxidx++] = face.m_Verts[0]; 187 183 Indices[idxidx++] = face.m_Verts[1]; 188 184 Indices[idxidx++] = face.m_Verts[2]; 189 185 } 190 186 } 191 187 192 188 193 189 194 190 /////////////////////////////////////////////////////////////////////////////////////////////// 195 191 // ShaderModelRenderer implementation 196 192 197 193 198 194 /** 199 195 * Internal data of the ShaderModelRenderer. 200 196 * 201 197 * Separated into the source file to increase implementation hiding (and to 202 198 * avoid some causes of recompiles). 203 199 */ 204 200 struct ShaderModelRenderer::ShaderModelRendererInternals 205 201 { 206 202 ShaderModelRendererInternals(ShaderModelRenderer* r) : m_Renderer(r) { } 207 203 208 204 /// Back-link to "our" renderer 209 205 ShaderModelRenderer* m_Renderer; 210 206 211 207 /// ModelVertexRenderer used for vertex transformations 212 208 ModelVertexRendererPtr vertexRenderer; 213 209 214 210 /// List of submitted models for rendering in this frame 215 211 std::vector<CModel*> submissions[CRenderer::CULL_MAX]; 216 212 }; 217 213 218 214 219 215 // Construction/Destruction 220 216 ShaderModelRenderer::ShaderModelRenderer(ModelVertexRendererPtr vertexrenderer) 221 217 { 222 218 m = new ShaderModelRendererInternals(this); 223 219 m->vertexRenderer = vertexrenderer; 224 220 } 225 221 226 222 ShaderModelRenderer::~ShaderModelRenderer() 227 223 { 228 224 delete m; 229 225 } 230 226 231 227 // Submit one model. 232 228 void ShaderModelRenderer::Submit(int cullGroup, CModel* model) 233 229 { 234 230 CModelRData* rdata = (CModelRData*)model->GetRenderData(); 235 231 236 232 // Ensure model data is valid 237 233 const void* key = m->vertexRenderer.get(); 238 234 if (!rdata || rdata->GetKey() != key) 239 235 { 240 236 rdata = m->vertexRenderer->CreateModelData(key, model); 241 237 model->SetRenderData(rdata); 242 238 model->SetDirty(~0u); 243 239 } 244 240 245 241 m->submissions[cullGroup].push_back(model); 246 242 } 247 243 248 244 249 245 // Call update for all submitted models and enter the rendering phase 250 246 void ShaderModelRenderer::PrepareModels() 251 247 { 252 248 for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) 253 249 { 254 250 for (size_t i = 0; i < m->submissions[cullGroup].size(); ++i) 255 251 { 256 252 CModel* model = m->submissions[cullGroup][i]; 257 253 258 254 model->ValidatePosition(); 259 255 260 256 CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData()); 261 257 ENSURE(rdata->GetKey() == m->vertexRenderer.get()); 262 258 263 259 m->vertexRenderer->UpdateModelData(model, rdata, rdata->m_UpdateFlags); 264 260 rdata->m_UpdateFlags = 0; 265 261 } 266 262 } 267 263 } 268 264 269 265 270 266 // Clear the submissions list 271 267 void ShaderModelRenderer::EndFrame() 272 268 { 273 269 for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) 274 270 m->submissions[cullGroup].clear(); 275 271 } 276 272 277 273 278 274 // Helper structs for ShaderModelRenderer::Render(): 279 275 280 276 struct SMRSortByDistItem 281 277 { 282 278 size_t techIdx; 283 279 CModel* model; 284 280 float dist; 285 281 }; 286 282 287 283 struct SMRBatchModel 288 284 { 289 285 bool operator()(CModel* a, CModel* b) 290 286 { 291 287 if (a->GetModelDef() < b->GetModelDef()) 292 288 return true; 293 289 if (b->GetModelDef() < a->GetModelDef()) 294 290 return false; 295 291 296 292 if (a->GetMaterial().GetDiffuseTexture() < b->GetMaterial().GetDiffuseTexture()) 297 293 return true; 298 294 if (b->GetMaterial().GetDiffuseTexture() < a->GetMaterial().GetDiffuseTexture()) 299 295 return false; 300 296 301 297 return a->GetMaterial().GetStaticUniforms() < b->GetMaterial().GetStaticUniforms(); 302 298 } 303 299 }; 304 300 305 301 struct SMRCompareSortByDistItem 306 302 { 307 303 bool operator()(const SMRSortByDistItem& a, const SMRSortByDistItem& b) 308 304 { 309 305 // Prefer items with greater distance, so we draw back-to-front 310 306 return (a.dist > b.dist); 311 307 312 308 // (Distances will almost always be distinct, so we don't need to bother 313 309 // tie-breaking on modeldef/texture/etc) 314 310 } 315 311 }; 316 312 317 313 struct SMRMaterialBucketKey 318 314 { 319 315 SMRMaterialBucketKey(CStrIntern effect, const CShaderDefines& defines) 320 316 : effect(effect), defines(defines) { } 321 317 322 318 CStrIntern effect; 323 319 CShaderDefines defines; 324 320 325 321 bool operator==(const SMRMaterialBucketKey& b) const 326 322 { 327 323 return (effect == b.effect && defines == b.defines); 328 324 } 329 325 330 326 private: 331 327 SMRMaterialBucketKey& operator=(const SMRMaterialBucketKey&); 332 328 }; 333 329 334 330 struct SMRMaterialBucketKeyHash 335 331 { 336 332 size_t operator()(const SMRMaterialBucketKey& key) const 337 333 { 338 334 size_t hash = 0; 339 335 hash_combine(hash, key.effect.GetHash()); 340 336 hash_combine(hash, key.defines.GetHash()); 341 337 return hash; 342 338 } 343 339 }; 344 340 345 341 struct SMRTechBucket 346 342 { 347 343 CShaderTechniquePtr tech; 348 344 CModel** models; 349 345 size_t numModels; 350 346 351 347 // Model list is stored as pointers, not as a std::vector, 352 348 // so that sorting lists of this struct is fast 353 349 }; 354 350 355 351 struct SMRCompareTechBucket 356 352 { 357 353 bool operator()(const SMRTechBucket& a, const SMRTechBucket& b) 358 354 { 359 355 return a.tech < b.tech; 360 356 } 361 357 }; 362 358 363 359 void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags) 364 360 { 365 361 if (m->submissions[cullGroup].empty()) 366 362 return; 367 363 368 364 CMatrix3D worldToCam; 369 365 g_Renderer.GetViewCamera().GetOrientation().GetInverse(worldToCam); 370 366 371 367 /* 372 368 * Rendering approach: 373 369 * 374 370 * m->submissions contains the list of CModels to render. 375 371 * 376 372 * The data we need to render a model is: 377 373 * - CShaderTechnique 378 374 * - CTexture 379 375 * - CShaderUniforms 380 376 * - CModelDef (mesh data) 381 377 * - CModel (model instance data) 382 378 * 383 379 * For efficient rendering, we need to batch the draw calls to minimise state changes. 384 380 * (Uniform and texture changes are assumed to be cheaper than binding new mesh data, 385 381 * and shader changes are assumed to be most expensive.) 386 382 * First, group all models that share a technique to render them together. 387 383 * Within those groups, sub-group by CModelDef. 388 384 * Within those sub-groups, sub-sub-group by CTexture. 389 385 * Within those sub-sub-groups, sub-sub-sub-group by CShaderUniforms. 390 386 * 391 387 * Alpha-blended models have to be sorted by distance from camera, 392 388 * then we can batch as long as the order is preserved. 393 389 * Non-alpha-blended models can be arbitrarily reordered to maximise batching. 394 390 * 395 391 * For each model, the CShaderTechnique is derived from: 396 392 * - The current global 'context' defines 397 393 * - The CModel's material's defines 398 394 * - The CModel's material's shader effect name 399 395 * 400 396 * There are a smallish number of materials, and a smaller number of techniques. 401 397 * 402 398 * To minimise technique lookups, we first group models by material, 403 399 * in 'materialBuckets' (a hash table). 404 400 * 405 401 * For each material bucket we then look up the appropriate shader technique. 406 402 * If the technique requires sort-by-distance, the model is added to the 407 403 * 'sortByDistItems' list with its computed distance. 408 404 * Otherwise, the bucket's list of models is sorted by modeldef+texture+uniforms, 409 405 * then the technique and model list is added to 'techBuckets'. 410 406 * 411 407 * 'techBuckets' is then sorted by technique, to improve batching when multiple 412 408 * materials map onto the same technique. 413 409 * 414 410 * (Note that this isn't perfect batching: we don't sort across models in 415 411 * multiple buckets that share a technique. In practice that shouldn't reduce 416 412 * batching much (we rarely have one mesh used with multiple materials), 417 413 * and it saves on copying and lets us sort smaller lists.) 418 414 * 419 415 * Extra tech buckets are added for the sorted-by-distance models without reordering. 420 416 * Finally we render by looping over each tech bucket, then looping over the model 421 417 * list in each, rebinding the GL state whenever it changes. 422 418 */ 423 419 424 420 Allocators::DynamicArena arena(256 * KiB); 425 421 using ModelListAllocator = ProxyAllocator<CModel*, Allocators::DynamicArena>; 426 422 using ModelList_t = std::vector<CModel*, ModelListAllocator>; 427 423 using MaterialBuckets_t = std::unordered_map< 428 424 SMRMaterialBucketKey, 429 425 ModelList_t, 430 426 SMRMaterialBucketKeyHash, 431 427 std::equal_to<SMRMaterialBucketKey>, 432 428 ProxyAllocator< 433 429 std::pair<const SMRMaterialBucketKey, ModelList_t>, 434 430 Allocators::DynamicArena> >; 435 431 436 432 MaterialBuckets_t materialBuckets((MaterialBuckets_t::allocator_type(arena))); 437 433 438 434 { 439 435 PROFILE3("bucketing by material"); 440 436 441 437 for (size_t i = 0; i < m->submissions[cullGroup].size(); ++i) 442 438 { 443 439 CModel* model = m->submissions[cullGroup][i]; 444 440 445 441 uint32_t condFlags = 0; 446 442 447 443 const CShaderConditionalDefines& condefs = model->GetMaterial().GetConditionalDefines(); 448 444 for (size_t j = 0; j < condefs.GetSize(); ++j) 449 445 { 450 446 const CShaderConditionalDefines::CondDefine& item = condefs.GetItem(j); 451 447 int type = item.m_CondType; 452 448 switch (type) 453 449 { 454 450 case DCOND_DISTANCE: 455 451 { 456 452 CVector3D modelpos = model->GetTransform().GetTranslation(); 457 453 float dist = worldToCam.Transform(modelpos).Z; 458 454 459 455 float dmin = item.m_CondArgs[0]; 460 456 float dmax = item.m_CondArgs[1]; 461 457 462 458 if ((dmin < 0 || dist >= dmin) && (dmax < 0 || dist < dmax)) 463 459 condFlags |= (1 << j); 464 460 465 461 break; 466 462 } 467 463 } 468 464 } 469 465 470 466 CShaderDefines defs = model->GetMaterial().GetShaderDefines(condFlags); 471 467 SMRMaterialBucketKey key(model->GetMaterial().GetShaderEffect(), defs); 472 468 473 469 MaterialBuckets_t::iterator it = materialBuckets.find(key); 474 470 if (it == materialBuckets.end()) 475 471 { 476 472 std::pair<MaterialBuckets_t::iterator, bool> inserted = materialBuckets.insert( 477 473 std::make_pair(key, ModelList_t(ModelList_t::allocator_type(arena)))); 478 474 inserted.first->second.reserve(32); 479 475 inserted.first->second.push_back(model); 480 476 } 481 477 else 482 478 { 483 479 it->second.push_back(model); 484 480 } 485 481 } 486 482 } 487 483 488 484 typedef ProxyAllocator<SMRSortByDistItem, Allocators::DynamicArena> SortByDistItemsAllocator; 489 485 std::vector<SMRSortByDistItem, SortByDistItemsAllocator> sortByDistItems((SortByDistItemsAllocator(arena))); 490 486 491 487 typedef ProxyAllocator<CShaderTechniquePtr, Allocators::DynamicArena> SortByTechItemsAllocator; 492 488 std::vector<CShaderTechniquePtr, SortByTechItemsAllocator> sortByDistTechs((SortByTechItemsAllocator(arena))); 493 489 // indexed by sortByDistItems[i].techIdx 494 490 // (which stores indexes instead of CShaderTechniquePtr directly 495 491 // to avoid the shared_ptr copy cost when sorting; maybe it'd be better 496 492 // if we just stored raw CShaderTechnique* and assumed the shader manager 497 493 // will keep it alive long enough) 498 494 499 495 typedef ProxyAllocator<SMRTechBucket, Allocators::DynamicArena> TechBucketsAllocator; 500 496 std::vector<SMRTechBucket, TechBucketsAllocator> techBuckets((TechBucketsAllocator(arena))); 501 497 502 498 { 503 499 PROFILE3("processing material buckets"); 504 500 for (MaterialBuckets_t::iterator it = materialBuckets.begin(); it != materialBuckets.end(); ++it) 505 501 { 506 502 CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(it->first.effect, context, it->first.defines); 507 503 508 504 // Skip invalid techniques (e.g. from data file errors) 509 505 if (!tech) 510 506 continue; 511 507 512 508 if (tech->GetSortByDistance()) 513 509 { 514 510 // Add the tech into a vector so we can index it 515 511 // (There might be duplicates in this list, but that doesn't really matter) 516 512 if (sortByDistTechs.empty() || sortByDistTechs.back() != tech) 517 513 sortByDistTechs.push_back(tech); 518 514 size_t techIdx = sortByDistTechs.size() - 1; 519 515 520 516 // Add each model into sortByDistItems 521 517 for (size_t i = 0; i < it->second.size(); ++i) 522 518 { 523 519 SMRSortByDistItem itemWithDist; 524 520 itemWithDist.techIdx = techIdx; 525 521 526 522 CModel* model = it->second[i]; 527 523 itemWithDist.model = model; 528 524 529 525 CVector3D modelpos = model->GetTransform().GetTranslation(); 530 526 itemWithDist.dist = worldToCam.Transform(modelpos).Z; 531 527 532 528 sortByDistItems.push_back(itemWithDist); 533 529 } 534 530 } 535 531 else 536 532 { 537 533 // Sort model list by modeldef+texture, for batching 538 534 // TODO: This only sorts by base texture. While this is an OK approximation 539 535 // for most cases (as related samplers are usually used together), it would be better 540 536 // to take all the samplers into account when sorting here. 541 537 std::sort(it->second.begin(), it->second.end(), SMRBatchModel()); 542 538 543 539 // Add a tech bucket pointing at this model list 544 540 SMRTechBucket techBucket = { tech, &it->second[0], it->second.size() }; 545 541 techBuckets.push_back(techBucket); 546 542 } 547 543 } 548 544 } 549 545 550 546 { 551 547 PROFILE3("sorting tech buckets"); 552 548 // Sort by technique, for better batching 553 549 std::sort(techBuckets.begin(), techBuckets.end(), SMRCompareTechBucket()); 554 550 } 555 551 556 552 // List of models corresponding to sortByDistItems[i].model 557 553 // (This exists primarily because techBuckets wants a CModel**; 558 554 // we could avoid the cost of copying into this list by adding 559 555 // a stride length into techBuckets and not requiring contiguous CModel*s) 560 556 std::vector<CModel*, ModelListAllocator> sortByDistModels((ModelListAllocator(arena))); 561 557 562 558 if (!sortByDistItems.empty()) 563 559 { 564 560 { 565 561 PROFILE3("sorting items by dist"); 566 562 std::sort(sortByDistItems.begin(), sortByDistItems.end(), SMRCompareSortByDistItem()); 567 563 } 568 564 569 565 { 570 566 PROFILE3("batching dist-sorted items"); 571 567 572 568 sortByDistModels.reserve(sortByDistItems.size()); 573 569 574 570 // Find runs of distance-sorted models that share a technique, 575 571 // and create a new tech bucket for each run 576 572 577 573 size_t start = 0; // start of current run 578 574 size_t currentTechIdx = sortByDistItems[start].techIdx; 579 575 580 576 for (size_t end = 0; end < sortByDistItems.size(); ++end) 581 577 { 582 578 sortByDistModels.push_back(sortByDistItems[end].model); 583 579 584 580 size_t techIdx = sortByDistItems[end].techIdx; 585 581 if (techIdx != currentTechIdx) 586 582 { 587 583 // Start of a new run - push the old run into a new tech bucket 588 584 SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], end - start }; 589 585 techBuckets.push_back(techBucket); 590 586 start = end; 591 587 currentTechIdx = techIdx; 592 588 } 593 589 } 594 590 595 591 // Add the tech bucket for the final run 596 592 SMRTechBucket techBucket = { sortByDistTechs[currentTechIdx], &sortByDistModels[start], sortByDistItems.size() - start }; 597 593 techBuckets.push_back(techBucket); 598 594 } 599 595 } 600 596 601 597 { 602 598 PROFILE3("rendering bucketed submissions"); 603 599 604 600 size_t idxTechStart = 0; 605 601 606 602 // This vector keeps track of texture changes during rendering. It is kept outside the 607 603 // loops to avoid excessive reallocations. The token allocation of 64 elements 608 604 // should be plenty, though it is reallocated below (at a cost) if necessary. 609 605 typedef ProxyAllocator<CTexture*, Allocators::DynamicArena> TextureListAllocator; 610 606 std::vector<CTexture*, TextureListAllocator> currentTexs((TextureListAllocator(arena))); 611 607 currentTexs.reserve(64); 612 608 613 609 // texBindings holds the identifier bindings in the shader, which can no longer be defined 614 610 // statically in the ShaderRenderModifier class. texBindingNames uses interned strings to 615 611 // keep track of when bindings need to be reevaluated. 616 612 typedef ProxyAllocator<CShaderProgram::Binding, Allocators::DynamicArena> BindingListAllocator; 617 613 std::vector<CShaderProgram::Binding, BindingListAllocator> texBindings((BindingListAllocator(arena))); 618 614 texBindings.reserve(64); 619 615 620 616 typedef ProxyAllocator<CStrIntern, Allocators::DynamicArena> BindingNamesListAllocator; 621 617 std::vector<CStrIntern, BindingNamesListAllocator> texBindingNames((BindingNamesListAllocator(arena))); 622 618 texBindingNames.reserve(64); 623 619 624 620 while (idxTechStart < techBuckets.size()) 625 621 { 626 622 CShaderTechniquePtr currentTech = techBuckets[idxTechStart].tech; 627 623 628 624 // Find runs [idxTechStart, idxTechEnd) in techBuckets of the same technique 629 625 size_t idxTechEnd; 630 626 for (idxTechEnd = idxTechStart + 1; idxTechEnd < techBuckets.size(); ++idxTechEnd) 631 627 { 632 628 if (techBuckets[idxTechEnd].tech != currentTech) 633 629 break; 634 630 } 635 631 636 632 // For each of the technique's passes, render all the models in this run 637 633 for (int pass = 0; pass < currentTech->GetNumPasses(); ++pass) 638 634 { 639 635 currentTech->BeginPass(pass); 640 636 641 637 const CShaderProgramPtr& shader = currentTech->GetShader(pass); 642 638 int streamflags = shader->GetStreamFlags(); 643 639 644 640 modifier->BeginPass(shader); 645 641 646 642 m->vertexRenderer->BeginPass(streamflags); 647 643 648 644 // When the shader technique changes, textures need to be 649 645 // rebound, so ensure there are no remnants from the last pass. 650 646 // (the vector size is set to 0, but memory is not freed) 651 647 currentTexs.clear(); 652 648 texBindings.clear(); 653 649 texBindingNames.clear(); 654 650 655 651 CModelDef* currentModeldef = NULL; 656 652 CShaderUniforms currentStaticUniforms; 657 653 658 654 for (size_t idx = idxTechStart; idx < idxTechEnd; ++idx) 659 655 { 660 656 CModel** models = techBuckets[idx].models; 661 657 size_t numModels = techBuckets[idx].numModels; 662 658 for (size_t i = 0; i < numModels; ++i) 663 659 { 664 660 CModel* model = models[i]; 665 661 666 662 if (flags && !(model->GetFlags() & flags)) 667 663 continue; 668 664 669 665 const CMaterial::SamplersVector& samplers = model->GetMaterial().GetSamplers(); 670 666 size_t samplersNum = samplers.size(); 671 667 672 668 // make sure the vectors are the right virtual sizes, and also 673 669 // reallocate if there are more samplers than expected. 674 670 if (currentTexs.size() != samplersNum) 675 671 { 676 672 currentTexs.resize(samplersNum, NULL); 677 673 texBindings.resize(samplersNum, CShaderProgram::Binding()); 678 674 texBindingNames.resize(samplersNum, CStrIntern()); 679 675 680 676 // ensure they are definitely empty 681 677 std::fill(texBindings.begin(), texBindings.end(), CShaderProgram::Binding()); 682 678 std::fill(currentTexs.begin(), currentTexs.end(), (CTexture*)NULL); 683 679 std::fill(texBindingNames.begin(), texBindingNames.end(), CStrIntern()); 684 680 } 685 681 686 682 // bind the samplers to the shader 687 683 for (size_t s = 0; s < samplersNum; ++s) 688 684 { 689 685 const CMaterial::TextureSampler& samp = samplers[s]; 690 686 691 687 // check that the handles are current 692 688 // and reevaluate them if necessary 693 689 if (texBindingNames[s] != samp.Name || !texBindings[s].Active()) 694 690 { 695 691 texBindings[s] = shader->GetTextureBinding(samp.Name); 696 692 texBindingNames[s] = samp.Name; 697 693 } 698 694 699 695 // same with the actual sampler bindings 700 696 CTexture* newTex = samp.Sampler.get(); 701 697 if (texBindings[s].Active() && newTex != currentTexs[s]) 702 698 { 703 699 shader->BindTexture(texBindings[s], newTex->GetHandle()); 704 700 currentTexs[s] = newTex; 705 701 } 706 702 } 707 703 708 704 // Bind modeldef when it changes 709 705 CModelDef* newModeldef = model->GetModelDef().get(); 710 706 if (newModeldef != currentModeldef) 711 707 { 712 708 currentModeldef = newModeldef; 713 709 m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef); 714 710 } 715 711 716 712 // Bind all uniforms when any change 717 713 CShaderUniforms newStaticUniforms = model->GetMaterial().GetStaticUniforms(); 718 714 if (newStaticUniforms != currentStaticUniforms) 719 715 { 720 716 currentStaticUniforms = newStaticUniforms; 721 717 currentStaticUniforms.BindUniforms(shader); 722 718 } 723 719 724 720 const CShaderRenderQueries& renderQueries = model->GetMaterial().GetRenderQueries(); 725 721 726 722 for (size_t q = 0; q < renderQueries.GetSize(); ++q) 727 723 { 728 724 CShaderRenderQueries::RenderQuery rq = renderQueries.GetItem(q); 729 725 if (rq.first == RQUERY_TIME) 730 726 { 731 727 CShaderProgram::Binding binding = shader->GetUniformBinding(rq.second); 732 728 if (binding.Active()) 733 729 { 734 730 double time = g_Renderer.GetTimeManager().GetGlobalTime(); 735 731 shader->Uniform(binding, time, 0.0f, 0.0f, 0.0f); 736 732 } 737 733 } 738 734 else if (rq.first == RQUERY_WATER_TEX) 739 735 { 740 736 WaterManager* WaterMgr = g_Renderer.GetWaterManager(); 741 737 double time = WaterMgr->m_WaterTexTimer; 742 738 double period = 1.6; 743 739 int curTex = static_cast<int>(time * 60.0 / period) % 60; 744 740 745 741 if (WaterMgr->m_RenderWater && WaterMgr->WillRenderFancyWater()) 746 742 shader->BindTexture(str_waterTex, WaterMgr->m_NormalMap[curTex]); 747 743 else 748 744 shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture()); 749 745 } 750 746 else if (rq.first == RQUERY_SKY_CUBE) 751 747 { 752 748 shader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube()); 753 749 } 754 750 } 755 751 756 752 modifier->PrepareModel(shader, model); 757 753 758 754 CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData()); 759 755 ENSURE(rdata->GetKey() == m->vertexRenderer.get()); 760 756 761 757 m->vertexRenderer->RenderModel(shader, streamflags, model, rdata); 762 758 } 763 759 } 764 760 765 761 m->vertexRenderer->EndPass(streamflags); 766 762 767 763 currentTech->EndPass(pass); 768 764 } 769 765 770 766 idxTechStart = idxTechEnd; 771 767 } 772 768 } 773 769 }