GlDriver.hx 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951
  1. package h3d.impl;
  2. import h3d.impl.Driver;
  3. import h3d.mat.Pass;
  4. import h3d.mat.Stencil;
  5. import h3d.mat.Data;
  6. #if (js||hlsdl||usegl)
  7. #if js
  8. import hxd.impl.TypedArray;
  9. private typedef GL = js.html.webgl.GL2;
  10. private typedef Uniform = js.html.webgl.UniformLocation;
  11. private typedef Program = js.html.webgl.Program;
  12. private typedef GLShader = js.html.webgl.Shader;
  13. private typedef Framebuffer = js.html.webgl.Framebuffer;
  14. #elseif hlsdl
  15. import sdl.GL;
  16. private typedef Uniform = sdl.GL.Uniform;
  17. private typedef Program = sdl.GL.Program;
  18. private typedef GLShader = sdl.GL.Shader;
  19. private typedef Framebuffer = sdl.GL.Framebuffer;
  20. private typedef Texture = h3d.impl.Driver.Texture;
  21. private typedef Query = h3d.impl.Driver.Query;
  22. private typedef VertexArray = sdl.GL.VertexArray;
  23. #elseif usegl
  24. import haxe.GLTypes;
  25. private typedef Uniform = haxe.GLTypes.Uniform;
  26. private typedef Program = haxe.GLTypes.Program;
  27. private typedef GLShader = haxe.GLTypes.Shader;
  28. private typedef Framebuffer = haxe.GLTypes.Framebuffer;
  29. private typedef Texture = h3d.impl.Driver.Texture;
  30. private typedef Query = h3d.impl.Driver.Query;
  31. private typedef VertexArray = haxe.GLTypes.VertexArray;
  32. #end
  33. #if usegl
  34. private typedef ShaderCompiler = haxe.GLTypes.ShaderCompiler;
  35. #else
  36. private typedef ShaderCompiler = hxsl.GlslOut;
  37. #end
  38. private class CompiledShader {
  39. public var s : GLShader;
  40. public var vertex : Bool;
  41. public var globals : Uniform;
  42. public var params : Uniform;
  43. public var textures : Array<{ u : Uniform, t : hxsl.Ast.Type, mode : Int }>;
  44. public var buffers : Array<Int>;
  45. public var shader : hxsl.RuntimeShader.RuntimeShaderData;
  46. public function new(s,vertex,shader) {
  47. this.s = s;
  48. this.vertex = vertex;
  49. this.shader = shader;
  50. }
  51. }
  52. private class CompiledAttribute {
  53. public var index : Int;
  54. public var type : Int;
  55. public var size : Int;
  56. public var divisor : Int;
  57. public function new() {
  58. }
  59. }
  60. private class CompiledProgram {
  61. public var p : Program;
  62. public var vertex : CompiledShader;
  63. public var fragment : CompiledShader;
  64. public var format : hxd.BufferFormat;
  65. public var attribs : Array<CompiledAttribute>;
  66. public var hasAttribIndex : Int;
  67. public function new() {
  68. }
  69. }
  70. @:access(h3d.impl.Shader)
  71. #if (hlsdl||usegl)
  72. @:build(h3d.impl.MacroHelper.replaceGL())
  73. #end
  74. class GlDriver extends Driver {
  75. #if js
  76. var canvas : js.html.CanvasElement;
  77. var mrtExt : { function drawBuffersWEBGL( colors : Array<Int> ) : Void; };
  78. static var UID = 0;
  79. public var gl : GL;
  80. public static var ALLOW_WEBGL2 = true;
  81. #end
  82. #if (hlsdl||usegl)
  83. var commonVA : VertexArray;
  84. #end
  85. var commonFB : Framebuffer;
  86. var curAttribs : Array<Bool> = new Array<Bool>();
  87. var maxIdxCurAttribs : Int = 0;
  88. var curShader : CompiledProgram;
  89. var curBuffer : h3d.Buffer;
  90. var curIndexBuffer : IndexBuffer;
  91. var curMatBits : Int = -1;
  92. var curStOpBits : Int = -1;
  93. var curStMaskBits : Int = -1;
  94. var curStEnabled : Bool = false;
  95. var defStencil : Stencil;
  96. var programs : Map<Int, CompiledProgram>;
  97. var frame : Int;
  98. var lastActiveIndex : Int = 0;
  99. var curColorMask = -1;
  100. var currentDivisor : Array<Int> = [for( i in 0...32 ) 0];
  101. var bufferWidth : Int;
  102. var bufferHeight : Int;
  103. var curTarget : h3d.mat.Texture;
  104. var curTargets : Array<h3d.mat.Texture> = [];
  105. var numTargets : Int;
  106. var curTargetLayer : Int;
  107. var curTargetMip : Int;
  108. var debug : Bool;
  109. var glDebug : Bool;
  110. var boundTextures : Array<Texture> = [];
  111. var glES : Null<Float>;
  112. var shaderVersion : Null<Int>;
  113. var firstShader = true;
  114. var rightHanded = false;
  115. var hasMultiIndirect = false;
  116. var maxCompressedTexturesSupport = 0;
  117. var drawMode : Int;
  118. var isIntelGpu : Bool;
  119. static var BLACK = new h3d.Vector(0,0,0,0);
  120. /**
  121. Perform OUT_OF_MEMORY checks when allocating textures/buffers.
  122. Default true, except in WebGL (false)
  123. **/
  124. public static var outOfMemoryCheck = #if js false #else true #end;
  125. public function new(antiAlias=0) {
  126. #if js
  127. canvas = @:privateAccess hxd.Window.getInstance().canvas;
  128. var options = {alpha:false,stencil:true,antialias:antiAlias>0};
  129. if(ALLOW_WEBGL2)
  130. gl = cast canvas.getContext("webgl2",options);
  131. if( gl == null )
  132. gl = cast canvas.getContextWebGL(options);
  133. if( gl == null ) throw "Could not acquire GL context";
  134. // debug if webgl_debug.js is included
  135. if( js.Syntax.typeof(untyped WebGLDebugUtils) != "undefined" ) {
  136. gl = untyped WebGLDebugUtils.makeDebugContext(gl);
  137. glDebug = true;
  138. }
  139. #if multidriver
  140. canvas.setAttribute("class", canvas.getAttribute("class") + " _id_" + (UID++));
  141. #end
  142. #end
  143. commonFB = gl.createFramebuffer();
  144. programs = new Map();
  145. defStencil = new Stencil();
  146. frame = hxd.Timer.frameCount;
  147. #if hlsdl
  148. hasMultiIndirect = gl.getConfigParameter(0) > 0;
  149. maxCompressedTexturesSupport = 7;
  150. var driver = getDriverName(false).toLowerCase();
  151. isIntelGpu = ~/intel.*graphics/.match(driver);
  152. #end
  153. #if hlmesa
  154. hasMultiIndirect = true;
  155. maxCompressedTexturesSupport = 7;
  156. #end
  157. var v : String = gl.getParameter(GL.VERSION);
  158. var reg = ~/ES ([0-9]+\.[0-9]+)/;
  159. if( reg.match(v) )
  160. glES = Std.parseFloat(reg.matched(1));
  161. #if !js
  162. if( glES == null ) {
  163. commonVA = gl.createVertexArray();
  164. gl.bindVertexArray( commonVA );
  165. }
  166. #end
  167. var reg = ~/[0-9]+\.[0-9]+/;
  168. var v : String = gl.getParameter(GL.SHADING_LANGUAGE_VERSION);
  169. if( reg.match(v) ) {
  170. #if js
  171. glES = Std.parseFloat(reg.matched(0));
  172. #end
  173. shaderVersion = Math.round( Std.parseFloat(reg.matched(0)) * 100 );
  174. }
  175. drawMode = GL.TRIANGLES;
  176. #if js
  177. // make sure to enable extensions
  178. makeFeatures();
  179. // We need to get instanced rendering by it's ANGLE extension if we are using webgl1
  180. if(hasFeature(InstancedRendering) && glES < 3) {
  181. var extension:js.html.webgl.extension.ANGLEInstancedArrays = cast gl.getExtension("ANGLE_instanced_arrays");
  182. Reflect.setField(gl,"vertexAttribDivisor",extension.vertexAttribDivisorANGLE);
  183. Reflect.setField(gl,"drawElementsInstanced",extension.drawElementsInstancedANGLE);
  184. }
  185. // setup shader optim
  186. hxsl.SharedShader.UNROLL_LOOPS = !hasFeature(ShaderModel3);
  187. #else
  188. gl.enable(GL.TEXTURE_CUBE_MAP_SEAMLESS);
  189. gl.finish(); // prevent glError() on first bufferData
  190. #end
  191. gl.pixelStorei(GL.PACK_ALIGNMENT, 1);
  192. gl.pixelStorei(GL.UNPACK_ALIGNMENT, 1);
  193. }
  194. override function setRenderFlag( r : RenderFlag, value : Int ) {
  195. switch( r ) {
  196. case CameraHandness:
  197. rightHanded = value > 0;
  198. default:
  199. }
  200. }
  201. override function logImpl( str : String ) {
  202. #if js
  203. untyped console.log(str);
  204. #else
  205. Sys.println(str);
  206. #end
  207. }
  208. override function setDebug(d) {
  209. this.debug = d;
  210. }
  211. override function begin(frame) {
  212. this.frame = frame;
  213. resetStream();
  214. gl.useProgram(null);
  215. curShader = null;
  216. curBuffer = null;
  217. }
  218. function makeCompiler() {
  219. var glout = new ShaderCompiler();
  220. glout.glES = glES;
  221. glout.version = shaderVersion;
  222. #if !usegl
  223. @:privateAccess glout.intelDriverFix = isIntelGpu;
  224. #end
  225. return glout;
  226. }
  227. override function getNativeShaderCode( shader : hxsl.RuntimeShader ) {
  228. inline function compile(sh) {
  229. return makeCompiler().run(sh);
  230. }
  231. return "// vertex:\n" + compile(shader.vertex.data) + "// fragment:\n" + compile(shader.fragment.data);
  232. }
  233. override public function getDriverName(details:Bool) {
  234. var render = gl.getParameter(GL.RENDERER);
  235. if( details )
  236. render += " GLv" + gl.getParameter(GL.VERSION);
  237. else
  238. render = render.split("/").shift(); // GeForce reports "/PCIe/SSE2" extension
  239. #if js
  240. render = render.split("WebGL ").join("");
  241. #end
  242. return "OpenGL "+render;
  243. }
  244. function compileShader( glout : ShaderCompiler, shader : hxsl.RuntimeShader.RuntimeShaderData ) {
  245. var type = shader.vertex ? GL.VERTEX_SHADER : GL.FRAGMENT_SHADER;
  246. var s = gl.createShader(type);
  247. if( shader.code == null ){
  248. shader.code = glout.run(shader.data);
  249. #if !heaps_compact_mem
  250. shader.data.funs = null;
  251. #end
  252. }
  253. gl.shaderSource(s, shader.code);
  254. gl.compileShader(s);
  255. var log = gl.getShaderInfoLog(s);
  256. if ( gl.getShaderParameter(s, GL.COMPILE_STATUS) != cast 1 ) {
  257. var log = gl.getShaderInfoLog(s);
  258. var lid = Std.parseInt(log.substr(9));
  259. var line = lid == null ? null : shader.code.split("\n")[lid - 1];
  260. if( line == null ) line = "" else line = "(" + StringTools.trim(line) + ")";
  261. var codeLines = shader.code.split("\n");
  262. for( i in 0...codeLines.length )
  263. codeLines[i] = (i+1) + "\t" + codeLines[i];
  264. throw "An error occurred compiling the shaders: " + log + line+"\n\n"+codeLines.join("\n");
  265. }
  266. return new CompiledShader(s, shader.vertex, shader);
  267. }
  268. function initShader( p : CompiledProgram, s : CompiledShader, shader : hxsl.RuntimeShader.RuntimeShaderData, rt : hxsl.RuntimeShader ) {
  269. var prefix = s.vertex ? "vertex" : "fragment";
  270. s.globals = gl.getUniformLocation(p.p, prefix + "Globals");
  271. s.params = gl.getUniformLocation(p.p, prefix + "Params");
  272. s.textures = [];
  273. var index = 0;
  274. var curT = null;
  275. var mode = 0;
  276. var name = "";
  277. var t = shader.textures;
  278. while( t != null ) {
  279. var tt = t.type;
  280. var count = 1;
  281. switch( tt ) {
  282. case TChannel(_): tt = TSampler2D;
  283. case TArray(t,SConst(n)): tt = t; count = n;
  284. default:
  285. }
  286. if( tt != curT ) {
  287. curT = tt;
  288. name = switch( tt ) {
  289. case TSampler2D: mode = GL.TEXTURE_2D; "Textures";
  290. case TSamplerCube: mode = GL.TEXTURE_CUBE_MAP; "TexturesCube";
  291. case TSampler2DArray: mode = GL.TEXTURE_2D_ARRAY; "TexturesArray";
  292. default: throw "Unsupported texture type "+tt;
  293. }
  294. index = 0;
  295. }
  296. for( i in 0...count ) {
  297. var loc = gl.getUniformLocation(p.p, prefix+name+"["+index+"]");
  298. /*
  299. This is a texture that is used in HxSL but has been optimized out by GLSL compiler.
  300. While some drivers will correctly report `null` here, some others (AMD) will instead
  301. return a uniform but still mismatch the texture slot, leading to swapped textures or
  302. incorrect rendering. We also don't handle texture skipping in DirectX.
  303. Fix is to make sure HxSL will optimize the texture out.
  304. Alternate fix is to improve HxSL so he does it on its own.
  305. */
  306. if( loc == null )
  307. throw "Texture "+rt.spec.instances[t.instance].shader.data.name+"."+t.name+" is missing from generated shader";
  308. s.textures.push({ u : loc, t : curT, mode : mode });
  309. index++;
  310. }
  311. t = t.next;
  312. }
  313. if( shader.bufferCount > 0 ) {
  314. s.buffers = [for( i in 0...shader.bufferCount ) gl.getUniformBlockIndex(p.p,(shader.vertex?"vertex_":"")+"uniform_buffer"+i)];
  315. var start = 0;
  316. if( !s.vertex ) start = rt.vertex.bufferCount;
  317. for( i in 0...shader.bufferCount )
  318. gl.uniformBlockBinding(p.p,s.buffers[i],i + start);
  319. }
  320. }
  321. override function selectShader( shader : hxsl.RuntimeShader ) {
  322. var p = programs.get(shader.id);
  323. if( p == null ) {
  324. p = new CompiledProgram();
  325. var glout = makeCompiler();
  326. p.vertex = compileShader(glout,shader.vertex);
  327. p.fragment = compileShader(glout,shader.fragment);
  328. p.p = gl.createProgram();
  329. #if ((hlsdl || usegl) && !hlmesa)
  330. if( glES == null ) {
  331. var outCount = 0;
  332. for( v in shader.fragment.data.vars )
  333. switch( v.kind ) {
  334. case Output:
  335. gl.bindFragDataLocation(p.p, outCount++, glout.varNames.exists(v.id) ? glout.varNames.get(v.id) : v.name);
  336. default:
  337. }
  338. }
  339. #end
  340. gl.attachShader(p.p, p.vertex.s);
  341. gl.attachShader(p.p, p.fragment.s);
  342. var log = null;
  343. try {
  344. gl.linkProgram(p.p);
  345. if( gl.getProgramParameter(p.p, GL.LINK_STATUS) != cast 1 )
  346. log = gl.getProgramInfoLog(p.p);
  347. } catch( e : Dynamic ) {
  348. throw "Shader linkage error: "+Std.string(e)+" ("+getDriverName(false)+")";
  349. }
  350. gl.deleteShader(p.vertex.s);
  351. gl.deleteShader(p.fragment.s);
  352. if( log != null ) {
  353. #if js
  354. gl.deleteProgram(p.p);
  355. #end
  356. #if hlsdl
  357. /*
  358. Tentative patch on some driver that report an higher shader version that it's allowed to use.
  359. */
  360. if( log == "" && shaderVersion > 130 && firstShader ) {
  361. shaderVersion -= 10;
  362. return selectShader(shader);
  363. }
  364. #end
  365. throw "Program linkage failure: "+log+"\nVertex=\n"+shader.vertex.code+"\n\nFragment=\n"+shader.fragment.code;
  366. }
  367. firstShader = false;
  368. initShader(p, p.vertex, shader.vertex, shader);
  369. initShader(p, p.fragment, shader.fragment, shader);
  370. p.attribs = [];
  371. p.hasAttribIndex = 0;
  372. var format : Array<hxd.BufferFormat.BufferInput> = [];
  373. for( v in shader.vertex.data.vars )
  374. switch( v.kind ) {
  375. case Input:
  376. var t = hxd.BufferFormat.InputFormat.fromHXSL(v.type);
  377. var index = gl.getAttribLocation(p.p, glout.varNames.exists(v.id) ? glout.varNames.get(v.id) : v.name);
  378. if( index < 0 )
  379. continue;
  380. if( index >= 32 )
  381. throw "assert";
  382. var a = new CompiledAttribute();
  383. a.type = GL.FLOAT;
  384. a.index = index;
  385. a.size = t.getSize();
  386. switch( v.type ) {
  387. case TBytes(n):
  388. a.type = GL.BYTE;
  389. a.size = n;
  390. default:
  391. }
  392. a.divisor = 0;
  393. if( v.qualifiers != null ) {
  394. for( q in v.qualifiers )
  395. switch( q ) {
  396. case PerInstance(n): a.divisor = n;
  397. default:
  398. }
  399. }
  400. p.attribs.push(a);
  401. p.hasAttribIndex |= 1 << a.index;
  402. format.push({ name : v.name, type : t });
  403. default:
  404. }
  405. p.format = hxd.BufferFormat.make(format);
  406. programs.set(shader.id, p);
  407. }
  408. if( curShader == p ) return false;
  409. setProgram(p);
  410. return true;
  411. }
  412. function setProgram( p : CompiledProgram ) {
  413. gl.useProgram(p.p);
  414. for( a in p.attribs )
  415. if( !curAttribs[a.index] ) {
  416. gl.enableVertexAttribArray(a.index);
  417. curAttribs[a.index] = true;
  418. if (maxIdxCurAttribs < a.index) {
  419. maxIdxCurAttribs = a.index;
  420. }
  421. }
  422. var lastIdxCurAttribTrue = 0;
  423. for( i in 0...maxIdxCurAttribs+1 ) {
  424. if( curAttribs[i] && p.hasAttribIndex & (1 << i) == 0) {
  425. gl.disableVertexAttribArray(i);
  426. curAttribs[i] = false;
  427. } else if (curAttribs[i]) {
  428. lastIdxCurAttribTrue = i;
  429. }
  430. }
  431. maxIdxCurAttribs = lastIdxCurAttribTrue;
  432. curShader = p;
  433. curBuffer = null;
  434. for( i in 0...boundTextures.length )
  435. boundTextures[i] = null;
  436. }
  437. override function uploadShaderBuffers( buf : h3d.shader.Buffers, which : h3d.shader.Buffers.BufferKind ) {
  438. uploadBuffer(buf, curShader.vertex, buf.vertex, which);
  439. uploadBuffer(buf, curShader.fragment, buf.fragment, which);
  440. }
  441. function uploadBuffer( buffer : h3d.shader.Buffers, s : CompiledShader, buf : h3d.shader.Buffers.ShaderBuffers, which : h3d.shader.Buffers.BufferKind ) {
  442. switch( which ) {
  443. case Globals:
  444. if( s.globals != null ) {
  445. #if hl
  446. gl.uniform4fv(s.globals, streamData(hl.Bytes.getArray(buf.globals.toData()), 0, s.shader.globalsSize * 16), 0, s.shader.globalsSize * 4);
  447. #else
  448. var a = buf.globals.subarray(0, s.shader.globalsSize * 4);
  449. gl.uniform4fv(s.globals, a);
  450. #end
  451. }
  452. case Params:
  453. if( s.params != null ) {
  454. #if hl
  455. gl.uniform4fv(s.params, streamData(hl.Bytes.getArray(buf.params.toData()), 0, s.shader.paramsSize * 16), 0, s.shader.paramsSize * 4);
  456. #else
  457. var a = buf.params.subarray(0, s.shader.paramsSize * 4);
  458. gl.uniform4fv(s.params, a);
  459. #end
  460. }
  461. case Buffers:
  462. if( s.buffers != null ) {
  463. var start = 0;
  464. if( !s.vertex && curShader.vertex.buffers != null )
  465. start = curShader.vertex.buffers.length;
  466. for( i in 0...s.buffers.length )
  467. gl.bindBufferBase(GL.UNIFORM_BUFFER, i + start, buf.buffers[i].vbuf);
  468. }
  469. case Textures:
  470. var tcount = s.textures.length;
  471. for( i in 0...s.textures.length ) {
  472. var t = buf.tex[i];
  473. var pt = s.textures[i];
  474. if( t == null || t.isDisposed() ) {
  475. switch( pt.t ) {
  476. case TSampler2D:
  477. var color = h3d.mat.Defaults.loadingTextureColor;
  478. t = h3d.mat.Texture.fromColor(color, (color >>> 24) / 255);
  479. case TSamplerCube:
  480. t = h3d.mat.Texture.defaultCubeTexture();
  481. default:
  482. throw "Missing texture";
  483. }
  484. }
  485. if( t != null && t.t == null && t.realloc != null ) {
  486. var s = curShader;
  487. t.alloc();
  488. t.realloc();
  489. if( curShader != s ) {
  490. // realloc triggered a shader change !
  491. // we need to reset the original shader and reupload everything
  492. setProgram(s);
  493. uploadShaderBuffers(buffer,Globals);
  494. uploadShaderBuffers(buffer,Params);
  495. uploadShaderBuffers(buffer,Textures);
  496. return;
  497. }
  498. }
  499. t.lastFrame = frame;
  500. if( pt.u == null ) continue;
  501. var idx = s.vertex ? i : curShader.vertex.textures.length + i;
  502. if( boundTextures[idx] != t.t ) {
  503. boundTextures[idx] = t.t;
  504. #if multidriver
  505. if( t.t.driver != this )
  506. throw "Invalid texture context";
  507. #end
  508. var mode = getBindType(t);
  509. if( mode != pt.mode )
  510. throw "Texture format mismatch: "+t+" should be "+pt.t;
  511. gl.activeTexture(GL.TEXTURE0 + idx);
  512. gl.uniform1i(pt.u, idx);
  513. gl.bindTexture(mode, t.t.t);
  514. lastActiveIndex = idx;
  515. }
  516. var mip = Type.enumIndex(t.mipMap);
  517. var filter = Type.enumIndex(t.filter);
  518. var wrap = Type.enumIndex(t.wrap);
  519. var bits = mip | (filter << 3) | (wrap << 6);
  520. if( bits != t.t.bits ) {
  521. t.t.bits = bits;
  522. var flags = TFILTERS[mip][filter];
  523. var mode = pt.mode;
  524. gl.texParameteri(mode, GL.TEXTURE_MAG_FILTER, flags[0]);
  525. gl.texParameteri(mode, GL.TEXTURE_MIN_FILTER, flags[1]);
  526. gl.texParameteri(mode, GL.TEXTURE_COMPARE_MODE, GL.NONE);
  527. var w = TWRAP[wrap];
  528. gl.texParameteri(mode, GL.TEXTURE_WRAP_S, w);
  529. gl.texParameteri(mode, GL.TEXTURE_WRAP_T, w);
  530. }
  531. if( t.t.startMip != t.startingMip ) {
  532. gl.texParameteri(pt.mode, GL.TEXTURE_BASE_LEVEL, t.startingMip);
  533. t.t.startMip = t.startingMip;
  534. }
  535. #if !js
  536. if( t.lodBias != t.t.bias ) {
  537. t.t.bias = t.lodBias;
  538. gl.texParameterf(pt.mode, GL.TEXTURE_LOD_BIAS, t.lodBias);
  539. }
  540. #end
  541. }
  542. }
  543. }
  544. override function selectMaterial( pass : Pass ) {
  545. var bits = @:privateAccess pass.bits;
  546. /*
  547. When rendering to a render target, our output will be flipped in Y to match
  548. output texture coordinates. We also need to flip our culling.
  549. The result is inverted if we are using a right handed camera.
  550. */
  551. if( (curTarget == null) == rightHanded ) {
  552. switch( pass.culling ) {
  553. case Back: bits = (bits & ~Pass.culling_mask) | (2 << Pass.culling_offset);
  554. case Front: bits = (bits & ~Pass.culling_mask) | (1 << Pass.culling_offset);
  555. default:
  556. }
  557. }
  558. selectMaterialBits(bits);
  559. if( curColorMask != pass.colorMask ) {
  560. var m = pass.colorMask;
  561. gl.colorMask(m & 1 != 0, m & 2 != 0, m & 4 != 0, m & 8 != 0);
  562. var mi = m >> 4;
  563. if ( mi > 0 ) {
  564. #if (hl_ver >= version("1.14.0"))
  565. var i = 1;
  566. do {
  567. if ( mi & 15 > 0 ) {
  568. gl.colorMaski(i, mi & 1 != 0, mi & 2 != 0, mi & 4 != 0, mi & 8 != 0);
  569. }
  570. mi = mi >> 4;
  571. i++;
  572. } while ( mi > 0 );
  573. #else
  574. throw "GL ColorMaski support requires hlsdl 1.14+";
  575. #end
  576. }
  577. curColorMask = m;
  578. }
  579. var s = defStencil;
  580. if( pass.stencil == null ) {
  581. if( curStEnabled ) {
  582. gl.disable(GL.STENCIL_TEST);
  583. curStEnabled = false;
  584. }
  585. } else {
  586. s = pass.stencil;
  587. if( !curStEnabled ) {
  588. gl.enable(GL.STENCIL_TEST);
  589. curStEnabled = true;
  590. }
  591. }
  592. @:privateAccess selectStencilBits(s.opBits, s.maskBits);
  593. // TODO : Blend Op value sync
  594. }
  595. function selectMaterialBits( bits : Int ) {
  596. var diff = bits ^ curMatBits;
  597. if( curMatBits < 0 ) diff = -1;
  598. if( diff == 0 )
  599. return;
  600. var wireframe = bits & Pass.wireframe_mask != 0;
  601. #if hlsdl
  602. if ( wireframe ) {
  603. gl.polygonMode(GL.FRONT_AND_BACK, GL.LINE);
  604. // Force set to cull = None
  605. bits = (bits & ~Pass.culling_mask);
  606. diff |= Pass.culling_mask;
  607. } else {
  608. gl.polygonMode(GL.FRONT_AND_BACK, GL.FILL);
  609. }
  610. #else
  611. // Not entirely accurate wireframe, but the best possible on WebGL.
  612. drawMode = wireframe ? GL.LINE_STRIP : GL.TRIANGLES;
  613. #end
  614. if( diff & Pass.culling_mask != 0 ) {
  615. var cull = Pass.getCulling(bits);
  616. if( cull == 0 )
  617. gl.disable(GL.CULL_FACE);
  618. else {
  619. if( curMatBits < 0 || Pass.getCulling(curMatBits) == 0 )
  620. gl.enable(GL.CULL_FACE);
  621. gl.cullFace(FACES[cull]);
  622. }
  623. }
  624. if( diff & (Pass.blendSrc_mask | Pass.blendDst_mask | Pass.blendAlphaSrc_mask | Pass.blendAlphaDst_mask) != 0 ) {
  625. var csrc = Pass.getBlendSrc(bits);
  626. var cdst = Pass.getBlendDst(bits);
  627. var asrc = Pass.getBlendAlphaSrc(bits);
  628. var adst = Pass.getBlendAlphaDst(bits);
  629. if( csrc == asrc && cdst == adst ) {
  630. if( csrc == 0 && cdst == 1 )
  631. gl.disable(GL.BLEND);
  632. else {
  633. if( curMatBits < 0 || (Pass.getBlendSrc(curMatBits) == 0 && Pass.getBlendDst(curMatBits) == 1) ) gl.enable(GL.BLEND);
  634. gl.blendFunc(BLEND[csrc], BLEND[cdst]);
  635. }
  636. } else {
  637. if( curMatBits < 0 || (Pass.getBlendSrc(curMatBits) == 0 && Pass.getBlendDst(curMatBits) == 1) ) gl.enable(GL.BLEND);
  638. gl.blendFuncSeparate(BLEND[csrc], BLEND[cdst], BLEND[asrc], BLEND[adst]);
  639. }
  640. }
  641. if( diff & (Pass.blendOp_mask | Pass.blendAlphaOp_mask) != 0 ) {
  642. var cop = Pass.getBlendOp(bits);
  643. var aop = Pass.getBlendAlphaOp(bits);
  644. if( cop == aop ) {
  645. gl.blendEquation(OP[cop]);
  646. }
  647. else
  648. gl.blendEquationSeparate(OP[cop], OP[aop]);
  649. }
  650. if( diff & Pass.depthWrite_mask != 0 )
  651. gl.depthMask(Pass.getDepthWrite(bits) != 0);
  652. if( diff & Pass.depthTest_mask != 0 ) {
  653. var cmp = Pass.getDepthTest(bits);
  654. if( cmp == 0 )
  655. gl.disable(GL.DEPTH_TEST);
  656. else {
  657. if( curMatBits < 0 || Pass.getDepthTest(curMatBits) == 0 ) gl.enable(GL.DEPTH_TEST);
  658. gl.depthFunc(COMPARE[cmp]);
  659. }
  660. }
  661. curMatBits = bits;
  662. }
  663. function selectStencilBits( opBits : Int, maskBits : Int ) {
  664. var diffOp = opBits ^ curStOpBits;
  665. var diffMask = maskBits ^ curStMaskBits;
  666. if ( (diffOp | diffMask) == 0 ) return;
  667. if( diffOp & (Stencil.frontSTfail_mask | Stencil.frontDPfail_mask | Stencil.frontPass_mask) != 0 ) {
  668. gl.stencilOpSeparate(
  669. FACES[Type.enumIndex(Front)],
  670. STENCIL_OP[Stencil.getFrontSTfail(opBits)],
  671. STENCIL_OP[Stencil.getFrontDPfail(opBits)],
  672. STENCIL_OP[Stencil.getFrontPass(opBits)]);
  673. }
  674. if( diffOp & (Stencil.backSTfail_mask | Stencil.backDPfail_mask | Stencil.backPass_mask) != 0 ) {
  675. gl.stencilOpSeparate(
  676. FACES[Type.enumIndex(Back)],
  677. STENCIL_OP[Stencil.getBackSTfail(opBits)],
  678. STENCIL_OP[Stencil.getBackDPfail(opBits)],
  679. STENCIL_OP[Stencil.getBackPass(opBits)]);
  680. }
  681. if( (diffOp & Stencil.frontTest_mask) | (diffMask & (Stencil.reference_mask | Stencil.readMask_mask)) != 0 ) {
  682. gl.stencilFuncSeparate(
  683. FACES[Type.enumIndex(Front)],
  684. COMPARE[Stencil.getFrontTest(opBits)],
  685. Stencil.getReference(maskBits),
  686. Stencil.getReadMask(maskBits));
  687. }
  688. if( (diffOp & Stencil.backTest_mask) | (diffMask & (Stencil.reference_mask | Stencil.readMask_mask)) != 0 ) {
  689. gl.stencilFuncSeparate(
  690. FACES[Type.enumIndex(Back)],
  691. COMPARE[Stencil.getBackTest(opBits)],
  692. Stencil.getReference(maskBits),
  693. Stencil.getReadMask(maskBits));
  694. }
  695. if( diffMask & Stencil.writeMask_mask != 0 ) {
  696. var w = Stencil.getWriteMask(maskBits);
  697. gl.stencilMaskSeparate(FACES[Type.enumIndex(Front)], w);
  698. gl.stencilMaskSeparate(FACES[Type.enumIndex(Back)], w);
  699. }
  700. curStOpBits = opBits;
  701. curStMaskBits = maskBits;
  702. }
  703. override function clear( ?color : h3d.Vector, ?depth : Float, ?stencil : Int ) {
  704. var bits = 0;
  705. if( color != null ) {
  706. gl.colorMask(true, true, true, true);
  707. curColorMask = 15;
  708. #if hlsdl
  709. // clear does not take gamma correction into account in GL/Windows
  710. if( curTarget != null && curTarget.isSRGB() )
  711. gl.clearColor(Math.pow(color.r, 1/2.2), Math.pow(color.g, 1/2.2), Math.pow(color.b, 1/2.2), color.a);
  712. else
  713. #end
  714. gl.clearColor(color.r, color.g, color.b, color.a);
  715. bits |= GL.COLOR_BUFFER_BIT;
  716. }
  717. if( depth != null ) {
  718. gl.depthMask(true);
  719. if( curMatBits >= 0 ) curMatBits |= Pass.depthWrite_mask;
  720. gl.clearDepth(depth);
  721. bits |= GL.DEPTH_BUFFER_BIT;
  722. }
  723. if( stencil != null ) {
  724. // reset stencil mask when we allow to change it
  725. @:privateAccess selectStencilBits(defStencil.opBits, defStencil.maskBits);
  726. gl.clearStencil(stencil);
  727. bits |= GL.STENCIL_BUFFER_BIT;
  728. }
  729. if( bits != 0 ) gl.clear(bits);
  730. if( curTarget != null ) curTarget.flags.set(WasCleared);
  731. }
  732. override function resize(width, height) {
  733. #if js
  734. // prevent infinite grow if pixelRatio != 1
  735. if( canvas.style.width == "" ) {
  736. canvas.style.width = Std.int(width / js.Browser.window.devicePixelRatio)+"px";
  737. canvas.style.height = Std.int(height / js.Browser.window.devicePixelRatio)+"px";
  738. }
  739. canvas.width = width;
  740. canvas.height = height;
  741. #end
  742. bufferWidth = width;
  743. bufferHeight = height;
  744. gl.viewport(0, 0, width, height);
  745. @:privateAccess if( defaultDepth != null ) {
  746. disposeDepthBuffer(defaultDepth);
  747. defaultDepth.width = this.bufferWidth;
  748. defaultDepth.height = this.bufferHeight;
  749. defaultDepth.t = allocDepthBuffer(defaultDepth);
  750. }
  751. }
  752. function getChannels( t : Texture ) {
  753. return switch( t.internalFmt ) {
  754. case GL.RGBA32F, GL.RGBA16F: GL.RGBA;
  755. #if !js
  756. case GL.SRGB_ALPHA, GL.SRGB8_ALPHA: GL.RGBA;
  757. case GL.RGBA8: GL.BGRA;
  758. #end
  759. case GL.SRGB, GL.SRGB8: GL.RGB;
  760. case GL.RGBA: GL.RGBA;
  761. case GL.RGB: GL.RGB;
  762. case GL.R11F_G11F_B10F: GL.RGB;
  763. case GL.RGB10_A2: GL.RGBA;
  764. case GL.RED, GL.R8, GL.R16F, GL.R32F, 0x822A: GL.RED;
  765. case GL.RG, GL.RG8, GL.RG16F, GL.RG32F, 0x822C: GL.RG;
  766. case GL.RGB16F, GL.RGB32F, 0x8054, 0x8E8F: GL.RGB;
  767. case 0x83F1, 0x83F2, 0x83F3, 0x805B, 0x8E8C: GL.RGBA;
  768. default: throw "Invalid format " + t.internalFmt;
  769. }
  770. }
  771. override function isSupportedFormat( fmt : h3d.mat.Data.TextureFormat ) {
  772. return switch( fmt ) {
  773. case RGBA: true;
  774. case RGBA16F, RGBA32F: hasFeature(FloatTextures);
  775. case SRGB, SRGB_ALPHA: hasFeature(SRGBTextures);
  776. case R8, RG8, RGB8, R16F, RG16F, RGB16F, R32F, RG32F, RGB32F, RG11B10UF, RGB10A2: #if js glES >= 3 #else true #end;
  777. case S3TC(n): n <= maxCompressedTexturesSupport;
  778. default: false;
  779. }
  780. }
  781. function getBindType( t : h3d.mat.Texture ) {
  782. var isCube = t.flags.has(Cube);
  783. var isArray = t.flags.has(IsArray);
  784. return isCube ? GL.TEXTURE_CUBE_MAP : isArray ? GL.TEXTURE_2D_ARRAY : GL.TEXTURE_2D;
  785. }
  786. override function allocTexture( t : h3d.mat.Texture ) : Texture {
  787. discardError();
  788. var tt = gl.createTexture();
  789. var bind = getBindType(t);
  790. var tt : Texture = { t : tt, width : t.width, height : t.height, internalFmt : GL.RGBA, pixelFmt : GL.UNSIGNED_BYTE, bits : -1, bind : bind, bias : 0, startMip : t.startingMip #if multidriver, driver : this #end };
  791. switch( t.format ) {
  792. case RGBA:
  793. // default
  794. case RGBA32F if( hasFeature(FloatTextures) ):
  795. tt.internalFmt = GL.RGBA32F;
  796. tt.pixelFmt = GL.FLOAT;
  797. case RGBA16F if( hasFeature(FloatTextures) ):
  798. tt.pixelFmt = GL.HALF_FLOAT;
  799. tt.internalFmt = GL.RGBA16F;
  800. case BGRA:
  801. tt.internalFmt = GL.RGBA8;
  802. case SRGB:
  803. tt.internalFmt = GL.SRGB8;
  804. #if !js
  805. case SRGB_ALPHA:
  806. tt.internalFmt = GL.SRGB8_ALPHA;
  807. #end
  808. case RGB8:
  809. tt.internalFmt = GL.RGB;
  810. case R8:
  811. tt.internalFmt = GL.R8;
  812. case RG8:
  813. tt.internalFmt = GL.RG8;
  814. case R16F:
  815. tt.internalFmt = GL.R16F;
  816. tt.pixelFmt = GL.HALF_FLOAT;
  817. case RG16F:
  818. tt.internalFmt = GL.RG16F;
  819. tt.pixelFmt = GL.HALF_FLOAT;
  820. case R16U:
  821. tt.internalFmt = 0x822A; // GL.R16
  822. tt.pixelFmt = GL.UNSIGNED_SHORT;
  823. case RG16U:
  824. tt.internalFmt = 0x822C; // GL.RG16
  825. tt.pixelFmt = GL.UNSIGNED_SHORT;
  826. case RGB16U:
  827. tt.internalFmt = 0x8054; // GL.RGB16
  828. tt.pixelFmt = GL.UNSIGNED_SHORT;
  829. case RGBA16U:
  830. tt.internalFmt = 0x805B; // GL.RGBA16
  831. tt.pixelFmt = GL.UNSIGNED_SHORT;
  832. case R32F:
  833. tt.internalFmt = GL.R32F;
  834. tt.pixelFmt = GL.FLOAT;
  835. case RG32F:
  836. tt.internalFmt = GL.RG32F;
  837. tt.pixelFmt = GL.FLOAT;
  838. case RGB16F:
  839. tt.internalFmt = GL.RGB16F;
  840. tt.pixelFmt = GL.HALF_FLOAT;
  841. case RGB32F:
  842. tt.internalFmt = GL.RGB32F;
  843. tt.pixelFmt = GL.FLOAT;
  844. case RGB10A2:
  845. tt.internalFmt = GL.RGB10_A2;
  846. tt.pixelFmt = GL.UNSIGNED_INT_2_10_10_10_REV;
  847. case RG11B10UF:
  848. tt.internalFmt = GL.R11F_G11F_B10F;
  849. tt.pixelFmt = GL.UNSIGNED_INT_10F_11F_11F_REV;
  850. case S3TC(n) if( n <= maxCompressedTexturesSupport ):
  851. if( t.width&3 != 0 || t.height&3 != 0 )
  852. throw "Compressed texture "+t+" has size "+t.width+"x"+t.height+" - must be a multiple of 4";
  853. switch( n ) {
  854. case 1: tt.internalFmt = 0x83F1; // COMPRESSED_RGBA_S3TC_DXT1_EXT
  855. case 2: tt.internalFmt = 0x83F2; // COMPRESSED_RGBA_S3TC_DXT3_EXT
  856. case 3: tt.internalFmt = 0x83F3; // COMPRESSED_RGBA_S3TC_DXT5_EXT
  857. case 6: tt.internalFmt = 0x8E8F; // COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT
  858. case 7: tt.internalFmt = 0x8E8C; // COMPRESSED_RGBA_BPTC_UNORM
  859. default: throw "Unsupported texture format "+t.format;
  860. }
  861. default:
  862. throw "Unsupported texture format "+t.format;
  863. }
  864. #if js
  865. if( tt.pixelFmt == GL.UNSIGNED_SHORT && !has16Bits )
  866. throw "16 bit textures requires EXT_texture_norm16 extension";
  867. #end
  868. t.lastFrame = frame;
  869. t.flags.unset(WasCleared);
  870. gl.bindTexture(bind, tt.t);
  871. var outOfMem = false;
  872. inline function checkError() {
  873. if( !outOfMemoryCheck ) return false;
  874. var err = gl.getError();
  875. if( err == GL.OUT_OF_MEMORY ) {
  876. outOfMem = true;
  877. return true;
  878. }
  879. if( err != 0 ) throw "Failed to alloc texture "+t.format+"(error "+err+")";
  880. return false;
  881. }
  882. #if (js || (hlsdl >= version("1.12.0")))
  883. gl.texParameteri(bind, GL.TEXTURE_BASE_LEVEL, t.startingMip);
  884. gl.texParameteri(bind, GL.TEXTURE_MAX_LEVEL, t.mipLevels-1);
  885. #end
  886. #if js
  887. // Modern texture allocation that supports both compressed and uncompressed texture in WebGL
  888. // texStorate2D/3D is only defined in OpenGL 4.2 but is defined in openGL ES 3 which the js target targets
  889. // Patch RGBA to be RGBA8 because texStorage expect a "Sized Internal Format"
  890. var sizedFormat = tt.internalFmt == GL.RGBA ? GL.RGBA8 : tt.internalFmt;
  891. if( t.flags.has(IsArray) && !t.flags.has(Cube) ) {
  892. gl.texStorage3D(bind, t.mipLevels, sizedFormat, tt.width, tt.height, t.layerCount);
  893. checkError();
  894. } else {
  895. gl.texStorage2D(bind, t.mipLevels, sizedFormat, tt.width, tt.height);
  896. checkError();
  897. }
  898. #else
  899. for(mip in 0...t.mipLevels) {
  900. var w = hxd.Math.imax(1, tt.width >> mip);
  901. var h = hxd.Math.imax(1, tt.height >> mip);
  902. if( t.flags.has(Cube) ) {
  903. for( i in 0...6 ) {
  904. gl.texImage2D(CUBE_FACES[i], mip, tt.internalFmt, w, h, 0, getChannels(tt), tt.pixelFmt, null);
  905. if( checkError() ) break;
  906. }
  907. } else if( t.flags.has(IsArray) ) {
  908. gl.texImage3D(bind, mip, tt.internalFmt, w, h, t.layerCount, 0, getChannels(tt), tt.pixelFmt, null);
  909. checkError();
  910. } else {
  911. gl.texImage2D(bind, mip, tt.internalFmt, w, h, 0, getChannels(tt), tt.pixelFmt, null);
  912. checkError();
  913. }
  914. }
  915. #end
  916. restoreBind();
  917. if( outOfMem ) {
  918. gl.deleteTexture(tt.t);
  919. return null;
  920. }
  921. return tt;
  922. }
  923. function restoreBind() {
  924. var t = boundTextures[lastActiveIndex];
  925. if( t == null )
  926. gl.bindTexture(GL.TEXTURE_2D, null);
  927. else
  928. gl.bindTexture(t.bind, t.t);
  929. }
  930. override function allocDepthBuffer( t : h3d.mat.Texture ) : Texture {
  931. var tt = gl.createTexture();
  932. var tt : Texture = { t : tt, width : t.width, height : t.height, internalFmt : GL.RGBA, pixelFmt : GL.UNSIGNED_BYTE, bits : -1, bind : GL.TEXTURE_2D, bias : 0, startMip: 0 #if multidriver, driver : this #end };
  933. var fmt = GL.DEPTH_COMPONENT;
  934. switch( t.format ) {
  935. case Depth16:
  936. tt.internalFmt = GL.DEPTH_COMPONENT16;
  937. case Depth24 #if js if( glES >= 3 ) #end: tt.internalFmt = GL.DEPTH_COMPONENT;
  938. case Depth24Stencil8:
  939. tt.internalFmt = GL.DEPTH24_STENCIL8;
  940. tt.pixelFmt = GL.UNSIGNED_INT_24_8;
  941. fmt = GL.DEPTH_STENCIL;
  942. default:
  943. throw "Unsupported depth format "+ t.format;
  944. }
  945. t.lastFrame = frame;
  946. t.flags.unset(WasCleared);
  947. gl.bindTexture(tt.bind, tt.t);
  948. #if (js || (hlsdl >= version("1.12.0")))
  949. gl.texParameteri(tt.bind, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
  950. gl.texParameteri(tt.bind, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
  951. gl.texParameteri(tt.bind, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE);
  952. gl.texParameteri(tt.bind, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE);
  953. #end
  954. gl.texImage2D(tt.bind, 0, tt.internalFmt, tt.width, tt.height, 0, fmt, tt.pixelFmt, null);
  955. restoreBind();
  956. return tt;
  957. }
  958. override function disposeDepthBuffer( b : h3d.mat.Texture ) {
  959. @:privateAccess if( b.t != null && b.t.t != null ) {
  960. gl.deleteTexture(b.t.t);
  961. b.t = null;
  962. }
  963. }
  964. var defaultDepth : h3d.mat.Texture;
  965. override function getDefaultDepthBuffer() : h3d.mat.Texture {
  966. // Unfortunately there is no way to bind the depth buffer of the default frame buffer to a frame buffer object.
  967. if( defaultDepth != null )
  968. return defaultDepth;
  969. defaultDepth = new h3d.mat.Texture(0, 0, Depth24Stencil8);
  970. defaultDepth.name = "defaultDepthBuffer";
  971. @:privateAccess {
  972. defaultDepth.width = this.bufferWidth;
  973. defaultDepth.height = this.bufferHeight;
  974. defaultDepth.t = allocDepthBuffer(defaultDepth);
  975. }
  976. return defaultDepth;
  977. }
  978. inline function discardError() {
  979. if( outOfMemoryCheck ) gl.getError(); // make sure to reset error flag
  980. }
  981. override function allocBuffer( b : h3d.Buffer ) : GPUBuffer {
  982. discardError();
  983. var vb = gl.createBuffer();
  984. gl.bindBuffer(GL.ARRAY_BUFFER, vb);
  985. if( b.vertices * b.format.stride == 0 ) throw "assert";
  986. #if js
  987. gl.bufferData(GL.ARRAY_BUFFER, b.getMemSize(), b.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
  988. #elseif hl
  989. gl.bufferDataSize(GL.ARRAY_BUFFER, b.getMemSize(), b.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
  990. #else
  991. var tmp = new Uint8Array(b.getMemSize());
  992. gl.bufferData(GL.ARRAY_BUFFER, tmp, b.flags.has(Dynamic) ? GL.DYNAMIC_DRAW : GL.STATIC_DRAW);
  993. #end
  994. #if multidriver
  995. @:privateAccess if( b.engine.driver != this )
  996. throw "Invalid buffer context";
  997. #end
  998. var outOfMem = outOfMemoryCheck && gl.getError() == GL.OUT_OF_MEMORY;
  999. gl.bindBuffer(GL.ARRAY_BUFFER, null);
  1000. if( outOfMem ) {
  1001. gl.deleteBuffer(vb);
  1002. return null;
  1003. }
  1004. return vb;
  1005. }
  1006. override function allocIndexes( count : Int, is32 : Bool ) : IndexBuffer {
  1007. discardError();
  1008. var b = gl.createBuffer();
  1009. var size = is32 ? 4 : 2;
  1010. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, b);
  1011. #if js
  1012. gl.bufferData(GL.ELEMENT_ARRAY_BUFFER, count * size, GL.STATIC_DRAW);
  1013. #elseif hl
  1014. gl.bufferDataSize(GL.ELEMENT_ARRAY_BUFFER, count * size, GL.STATIC_DRAW);
  1015. #end
  1016. var outOfMem = outOfMemoryCheck && gl.getError() == GL.OUT_OF_MEMORY;
  1017. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, null);
  1018. curIndexBuffer = null;
  1019. if( outOfMem ) {
  1020. gl.deleteBuffer(b);
  1021. return null;
  1022. }
  1023. return { b : b, is32 : is32 };
  1024. }
  1025. override function disposeTexture( t : h3d.mat.Texture ) {
  1026. var tt = t.t;
  1027. if( tt == null ) return;
  1028. t.t = null;
  1029. for( i in 0...boundTextures.length )
  1030. if( boundTextures[i] == tt )
  1031. boundTextures[i] = null;
  1032. gl.deleteTexture(tt.t);
  1033. }
  1034. override function disposeIndexes( i : IndexBuffer ) {
  1035. gl.deleteBuffer(i.b);
  1036. }
  1037. override function disposeBuffer( b : h3d.Buffer ) {
  1038. gl.deleteBuffer(b.vbuf);
  1039. }
  1040. override function generateMipMaps( t : h3d.mat.Texture ) {
  1041. var bind = getBindType(t);
  1042. gl.bindTexture(bind, t.t.t);
  1043. gl.generateMipmap(bind);
  1044. restoreBind();
  1045. }
  1046. override function uploadTextureBitmap( t : h3d.mat.Texture, bmp : hxd.BitmapData, mipLevel : Int, side : Int ) {
  1047. #if hl
  1048. var pixels = bmp.getPixels();
  1049. uploadTexturePixels(t, pixels, mipLevel, side);
  1050. pixels.dispose();
  1051. #else
  1052. if( t.format != RGBA || t.layerCount != 1 ) {
  1053. var pixels = bmp.getPixels();
  1054. uploadTexturePixels(t, pixels, mipLevel, side);
  1055. pixels.dispose();
  1056. } else {
  1057. var img = bmp.toNative();
  1058. gl.bindTexture(GL.TEXTURE_2D, t.t.t);
  1059. gl.texSubImage2D(GL.TEXTURE_2D, mipLevel, 0, 0, getChannels(t.t), t.t.pixelFmt, img.getImageData(0, 0, bmp.width, bmp.height));
  1060. restoreBind();
  1061. }
  1062. #end
  1063. }
  1064. /*
  1065. GL async model create crashes if the GC free the memory that we send it.
  1066. Instead, we will copy the data into a temp location before uploading.
  1067. */
  1068. static inline var STREAM_POS = #if hl 0 #else 1 #end;
  1069. #if hl
  1070. var streamKeep : Array<{ f : Int, b : hl.Bytes }> = [];
  1071. var streamBytes : hl.Bytes;
  1072. var streamLen : Int;
  1073. var streamPos : Int;
  1074. function expandStream(needed:Int) {
  1075. GL.finish();
  1076. // too much data in our tmp buffer, let's flush it
  1077. if( streamPos > (needed >> 1) && needed > 16 << 20 ) {
  1078. needed -= streamPos;
  1079. streamPos = 0;
  1080. if( needed < streamLen )
  1081. return;
  1082. }
  1083. var newLen = streamLen == 0 ? 0x10000 : streamLen;
  1084. while( newLen < needed )
  1085. newLen = (newLen * 3) >> 1;
  1086. var newBytes = new hl.Bytes(newLen);
  1087. if( streamPos > 0 )
  1088. newBytes.blit(0, streamBytes, 0, streamPos);
  1089. streamLen = newLen;
  1090. if( streamBytes != null ) streamKeep.push({ f : frame, b : streamBytes });
  1091. streamBytes = newBytes;
  1092. }
  1093. #end
  1094. function resetStream() {
  1095. #if hl
  1096. streamPos = 0;
  1097. // keep during 2 frames
  1098. while( streamKeep.length > 0 && streamKeep[0].f < frame - 1 ) streamKeep.shift();
  1099. #end
  1100. }
  1101. inline function streamData(data, pos:Int, length:Int) {
  1102. #if hl
  1103. var needed = streamPos + length;
  1104. var total = (needed + 7) & ~7; // align on 8 bytes
  1105. var alen = total - streamPos;
  1106. if( total > streamLen ) expandStream(total);
  1107. streamBytes.blit(streamPos, data, pos, length);
  1108. data = streamBytes.offset(streamPos);
  1109. streamPos += alen;
  1110. #end
  1111. return data;
  1112. }
  1113. override function uploadTexturePixels( t : h3d.mat.Texture, pixels : hxd.Pixels, mipLevel : Int, side : Int ) {
  1114. var cubic = t.flags.has(Cube);
  1115. var face = cubic ? CUBE_FACES[side] : t.flags.has(IsArray) ? GL.TEXTURE_2D_ARRAY : GL.TEXTURE_2D;
  1116. var bind = getBindType(t);
  1117. gl.bindTexture(bind, t.t.t);
  1118. pixels.convert(t.format);
  1119. var dataLen = pixels.dataSize;
  1120. #if hl
  1121. var stream = streamData(pixels.bytes.getData(),pixels.offset,dataLen);
  1122. if( t.format.match(S3TC(_)) ) {
  1123. if( t.flags.has(IsArray) )
  1124. #if (hlsdl >= version("1.12.0"))
  1125. gl.compressedTexSubImage3D(face, mipLevel, 0, 0, side, pixels.width, pixels.height, 1, t.t.internalFmt, dataLen, stream);
  1126. #else throw "TextureArray support requires hlsdl 1.12+"; #end
  1127. else
  1128. gl.compressedTexImage2D(face, mipLevel, t.t.internalFmt, pixels.width, pixels.height, 0, dataLen, stream);
  1129. } else {
  1130. if( t.flags.has(IsArray) )
  1131. #if (hlsdl >= version("1.12.0"))
  1132. gl.texSubImage3D(face, mipLevel, 0, 0, side, pixels.width, pixels.height, 1, getChannels(t.t), t.t.pixelFmt, stream);
  1133. #else throw "TextureArray support requires hlsdl 1.12+"; #end
  1134. else
  1135. gl.texImage2D(face, mipLevel, t.t.internalFmt, pixels.width, pixels.height, 0, getChannels(t.t), t.t.pixelFmt, stream);
  1136. }
  1137. #elseif js
  1138. #if hxnodejs
  1139. if( (pixels:Dynamic).bytes.b.hxBytes != null ) {
  1140. // if the pixels are a nodejs buffer, their might be GC'ed while upload !
  1141. // might be some problem with Node/WebGL relation
  1142. // let's clone the pixels in order to have a fresh JS bytes buffer
  1143. pixels = pixels.clone();
  1144. }
  1145. #end
  1146. var buffer : ArrayBufferView = switch( t.format ) {
  1147. case RGBA32F, R32F, RG32F, RGB32F: new Float32Array(@:privateAccess pixels.bytes.b.buffer, pixels.offset, dataLen>>2);
  1148. case RGBA16F, R16F, RG16F, RGB16F, RGBA16U, R16U, RG16U, RGB16U: new Uint16Array(@:privateAccess pixels.bytes.b.buffer, pixels.offset, dataLen>>1);
  1149. case RGB10A2, RG11B10UF: new Uint32Array(@:privateAccess pixels.bytes.b.buffer, pixels.offset, dataLen>>2);
  1150. default: new Uint8Array(@:privateAccess pixels.bytes.b.buffer, pixels.offset, dataLen);
  1151. }
  1152. if( t.format.match(S3TC(_)) ) {
  1153. if( t.flags.has(IsArray) )
  1154. gl.compressedTexSubImage3D(face, mipLevel, 0, 0, side, pixels.width, pixels.height, 1, t.t.internalFmt, buffer);
  1155. else
  1156. gl.compressedTexSubImage2D(face, mipLevel, 0, 0, pixels.width, pixels.height, t.t.internalFmt, buffer);
  1157. } else {
  1158. if( t.flags.has(IsArray) )
  1159. gl.texSubImage3D(face, mipLevel, 0, 0, side, pixels.width, pixels.height, 1, getChannels(t.t), t.t.pixelFmt, buffer);
  1160. else
  1161. gl.texSubImage2D(face, mipLevel, 0, 0, pixels.width, pixels.height, getChannels(t.t), t.t.pixelFmt, buffer);
  1162. }
  1163. #else
  1164. throw "Not implemented";
  1165. #end
  1166. t.flags.set(WasCleared);
  1167. restoreBind();
  1168. }
  1169. override function uploadBufferData( b : h3d.Buffer, startVertex : Int, vertexCount : Int, buf : hxd.FloatBuffer, bufPos : Int ) {
  1170. var stride = b.format.strideBytes;
  1171. gl.bindBuffer(GL.ARRAY_BUFFER, b.vbuf);
  1172. #if hl
  1173. var data = #if hl hl.Bytes.getArray(buf.getNative()) #else buf.getNative() #end;
  1174. gl.bufferSubData(GL.ARRAY_BUFFER, startVertex * stride, streamData(data,bufPos * 4,vertexCount * stride), bufPos * 4 * STREAM_POS, vertexCount * stride);
  1175. #else
  1176. var buf : Float32Array = buf.getNative();
  1177. var sub = new Float32Array(buf.buffer, bufPos * 4, (vertexCount * stride) >> 2);
  1178. gl.bufferSubData(GL.ARRAY_BUFFER, startVertex * stride, sub);
  1179. #end
  1180. gl.bindBuffer(GL.ARRAY_BUFFER, null);
  1181. }
  1182. override function uploadBufferBytes( b : h3d.Buffer, startVertex : Int, vertexCount : Int, buf : haxe.io.Bytes, bufPos : Int ) {
  1183. var stride = b.format.strideBytes;
  1184. gl.bindBuffer(GL.ARRAY_BUFFER, b.vbuf);
  1185. #if hl
  1186. gl.bufferSubData(GL.ARRAY_BUFFER, startVertex * stride, streamData(buf.getData(),bufPos,vertexCount * stride), bufPos * STREAM_POS, vertexCount * stride);
  1187. #else
  1188. var sub = new Uint8Array(buf.getData(), bufPos, vertexCount * stride);
  1189. gl.bufferSubData(GL.ARRAY_BUFFER, startVertex * stride, sub);
  1190. #end
  1191. gl.bindBuffer(GL.ARRAY_BUFFER, null);
  1192. }
  1193. override function uploadIndexBuffer( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : hxd.IndexBuffer, bufPos : Int ) {
  1194. var bits = i.is32 ? 2 : 1;
  1195. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, i.b);
  1196. #if hl
  1197. var data = #if hl hl.Bytes.getArray(buf.getNative()) #else buf.getNative() #end;
  1198. gl.bufferSubData(GL.ELEMENT_ARRAY_BUFFER, startIndice << bits, streamData(data,bufPos << bits,indiceCount << bits), (bufPos << bits) * STREAM_POS, indiceCount << bits);
  1199. #else
  1200. var buf = new Uint16Array(buf.getNative());
  1201. var sub = new Uint16Array(buf.buffer, bufPos << bits, indiceCount);
  1202. gl.bufferSubData(GL.ELEMENT_ARRAY_BUFFER, startIndice << bits, sub);
  1203. #end
  1204. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, null);
  1205. curIndexBuffer = null;
  1206. }
  1207. override function uploadIndexBytes( i : IndexBuffer, startIndice : Int, indiceCount : Int, buf : haxe.io.Bytes , bufPos : Int ) {
  1208. var bits = i.is32 ? 2 : 1;
  1209. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, i.b);
  1210. #if hl
  1211. gl.bufferSubData(GL.ELEMENT_ARRAY_BUFFER, startIndice << bits, streamData(buf.getData(),bufPos << bits, indiceCount << bits), (bufPos << bits) * STREAM_POS, indiceCount << bits);
  1212. #else
  1213. var sub = new Uint8Array(buf.getData(), bufPos << bits, indiceCount << bits);
  1214. gl.bufferSubData(GL.ELEMENT_ARRAY_BUFFER, startIndice << bits, sub);
  1215. #end
  1216. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, null);
  1217. curIndexBuffer = null;
  1218. }
  1219. inline function updateDivisor( a : CompiledAttribute ) {
  1220. if( currentDivisor[a.index] != a.divisor ) {
  1221. currentDivisor[a.index] = a.divisor;
  1222. gl.vertexAttribDivisor(a.index, a.divisor);
  1223. }
  1224. }
  1225. override function selectBuffer( b : h3d.Buffer ) {
  1226. if( b == curBuffer )
  1227. return;
  1228. if( curShader == null )
  1229. throw "No shader selected";
  1230. #if multidriver
  1231. if( @:privateAccess b.engine.driver != this )
  1232. throw "Invalid buffer context";
  1233. #end
  1234. gl.bindBuffer(GL.ARRAY_BUFFER, b.vbuf);
  1235. curBuffer = b;
  1236. var strideBytes = b.format.strideBytes;
  1237. var map = b.format.resolveMapping(curShader.format);
  1238. for( i => a in curShader.attribs ) {
  1239. var inf = map[i];
  1240. var norm = false;
  1241. gl.vertexAttribPointer(a.index, a.size, switch( inf.precision ) {
  1242. case F32: a.type;
  1243. case F16: GL.HALF_FLOAT;
  1244. case S8: norm = true; GL.BYTE;
  1245. case U8: norm = true; GL.UNSIGNED_BYTE;
  1246. }, norm, strideBytes, inf.offset);
  1247. updateDivisor(a);
  1248. }
  1249. }
  1250. override function selectMultiBuffers( format : hxd.BufferFormat.MultiFormat, buffers : Array<h3d.Buffer> ) {
  1251. var map = format.resolveMapping(curShader.format);
  1252. for( i => a in curShader.attribs ) {
  1253. var inf = map[i];
  1254. var b = buffers[inf.bufferIndex];
  1255. if( curBuffer != b ) {
  1256. gl.bindBuffer(GL.ARRAY_BUFFER, b.vbuf);
  1257. curBuffer = b;
  1258. }
  1259. var norm = false;
  1260. gl.vertexAttribPointer(a.index, a.size, switch( inf.precision ) {
  1261. case F32: a.type;
  1262. case F16: GL.HALF_FLOAT;
  1263. case S8: norm = true; GL.BYTE;
  1264. case U8: norm = true; GL.UNSIGNED_BYTE;
  1265. }, norm, b.format.strideBytes, inf.offset);
  1266. updateDivisor(a);
  1267. }
  1268. }
  1269. override function draw( ibuf : IndexBuffer, startIndex : Int, ntriangles : Int ) {
  1270. if( ibuf != curIndexBuffer ) {
  1271. curIndexBuffer = ibuf;
  1272. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, ibuf.b);
  1273. }
  1274. if( ibuf.is32 )
  1275. gl.drawElements(drawMode, ntriangles * 3, GL.UNSIGNED_INT, startIndex * 4);
  1276. else
  1277. gl.drawElements(drawMode, ntriangles * 3, GL.UNSIGNED_SHORT, startIndex * 2);
  1278. }
  1279. override function allocInstanceBuffer( b : InstanceBuffer, bytes : haxe.io.Bytes ) {
  1280. #if hl
  1281. if( hasMultiIndirect ) {
  1282. var buf = gl.createBuffer();
  1283. gl.bindBuffer(GL.DRAW_INDIRECT_BUFFER, buf);
  1284. gl.bufferData(GL.DRAW_INDIRECT_BUFFER, b.commandCount * 20, streamData(bytes.getData(),0, b.commandCount * 20), GL.DYNAMIC_DRAW);
  1285. gl.bindBuffer(GL.DRAW_INDIRECT_BUFFER, null);
  1286. b.data = buf;
  1287. return;
  1288. }
  1289. #end
  1290. var data = [];
  1291. for( i in 0...b.commandCount ) {
  1292. var p = i * 5 * 4;
  1293. var indexCount = bytes.getInt32(p);
  1294. var instanceCount = bytes.getInt32(p+4);
  1295. var offIndex = bytes.getInt32(p+8);
  1296. var offVertex = bytes.getInt32(p+12);
  1297. var offInstance = bytes.getInt32(p+16);
  1298. if( offVertex != 0 || offInstance != 0 )
  1299. throw "baseVertex and baseInstance must be zero on this platform";
  1300. data.push(indexCount);
  1301. data.push(offIndex);
  1302. data.push(instanceCount);
  1303. }
  1304. b.data = data;
  1305. }
  1306. override function disposeInstanceBuffer(b:InstanceBuffer) {
  1307. b.data = null;
  1308. }
  1309. override function drawInstanced( ibuf : IndexBuffer, commands : InstanceBuffer ) {
  1310. if( ibuf != curIndexBuffer ) {
  1311. curIndexBuffer = ibuf;
  1312. gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, ibuf.b);
  1313. }
  1314. var kind, size;
  1315. if( ibuf.is32 ) {
  1316. kind = GL.UNSIGNED_INT;
  1317. size = 4;
  1318. } else {
  1319. kind = GL.UNSIGNED_SHORT;
  1320. size = 2;
  1321. }
  1322. #if !js
  1323. if( hasMultiIndirect && commands.data != null ) {
  1324. gl.bindBuffer(GL.DRAW_INDIRECT_BUFFER, commands.data);
  1325. gl.multiDrawElementsIndirect(drawMode, kind, null, commands.commandCount, 0);
  1326. gl.bindBuffer(GL.DRAW_INDIRECT_BUFFER, null);
  1327. return;
  1328. }
  1329. #end
  1330. var args : Array<Int> = commands.data;
  1331. if( args != null ) {
  1332. var p = 0;
  1333. for( i in 0...Std.int(args.length/3) )
  1334. gl.drawElementsInstanced(drawMode, args[p++], kind, args[p++]*size, args[p++]);
  1335. } else
  1336. gl.drawElementsInstanced(drawMode, commands.indexCount, kind, commands.startIndex*size, commands.commandCount);
  1337. }
  1338. override function end() {
  1339. // no gl finish or flush !
  1340. }
  1341. override function present() {
  1342. #if hlsdl
  1343. @:privateAccess hxd.Window.inst.window.present();
  1344. #elseif usesys
  1345. haxe.System.present();
  1346. #end
  1347. }
  1348. override function isDisposed() {
  1349. return gl.isContextLost();
  1350. }
  1351. override function setRenderZone( x : Int, y : Int, width : Int, height : Int ) {
  1352. if( x == 0 && y == 0 && width < 0 && height < 0 )
  1353. gl.disable(GL.SCISSOR_TEST);
  1354. else {
  1355. gl.enable(GL.SCISSOR_TEST);
  1356. if( curTarget == null )
  1357. y = bufferHeight - (y + height);
  1358. gl.scissor(x, y, width, height);
  1359. }
  1360. }
  1361. function setDrawBuffers( k : Int ) {
  1362. #if js
  1363. if( glES >= 3 )
  1364. gl.drawBuffers(CBUFFERS[k]);
  1365. else if( mrtExt != null )
  1366. mrtExt.drawBuffersWEBGL(CBUFFERS[k]);
  1367. #elseif (hlsdl || usegl)
  1368. gl.drawBuffers(k, CBUFFERS);
  1369. #end
  1370. }
  1371. function unbindTargets() {
  1372. if( curTarget != null && numTargets > 1 ) {
  1373. while( numTargets > 1 ) {
  1374. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0 + (--numTargets), GL.TEXTURE_2D, null, 0);
  1375. curTargets[numTargets] = null;
  1376. }
  1377. setDrawBuffers(1);
  1378. }
  1379. }
  1380. override function capturePixels(tex:h3d.mat.Texture, layer:Int, mipLevel:Int, ?region:h2d.col.IBounds) {
  1381. var pixels : hxd.Pixels;
  1382. var x : Int, y : Int, w : Int, h : Int;
  1383. if (region != null) {
  1384. if (region.xMax > tex.width) region.xMax = tex.width;
  1385. if (region.yMax > tex.height) region.yMax = tex.height;
  1386. if (region.xMin < 0) region.xMin = 0;
  1387. if (region.yMin < 0) region.yMin = 0;
  1388. w = region.width;
  1389. h = region.height;
  1390. x = region.xMin;
  1391. y = region.yMin;
  1392. } else {
  1393. w = tex.width;
  1394. h = tex.height;
  1395. x = 0;
  1396. y = 0;
  1397. }
  1398. w >>= mipLevel;
  1399. h >>= mipLevel;
  1400. if( w == 0 ) w = 1;
  1401. if( h == 0 ) h = 1;
  1402. pixels = hxd.Pixels.alloc(w, h, tex.format);
  1403. var old = curTarget;
  1404. var oldCount = numTargets;
  1405. var oldLayer = curTargetLayer;
  1406. var oldMip = curTargetMip;
  1407. if( oldCount > 1 ) {
  1408. numTargets = 1;
  1409. for( i in 1...oldCount )
  1410. if( curTargets[i] == tex )
  1411. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0+i,GL.TEXTURE_2D,null,0);
  1412. }
  1413. setRenderTarget(tex, layer, mipLevel);
  1414. captureSubRenderBuffer(pixels, x, y);
  1415. setRenderTarget(old, oldLayer, oldMip);
  1416. if( oldCount > 1 ) {
  1417. for( i in 1...oldCount )
  1418. if( curTargets[i] == tex )
  1419. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0+i,GL.TEXTURE_2D,tex.t.t,0);
  1420. setDrawBuffers(oldCount);
  1421. numTargets = oldCount;
  1422. }
  1423. return pixels;
  1424. }
  1425. override function setRenderTarget( tex : h3d.mat.Texture, layer = 0, mipLevel = 0, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
  1426. unbindTargets();
  1427. curTarget = tex;
  1428. if( tex == null ) {
  1429. gl.bindFramebuffer(GL.FRAMEBUFFER, null);
  1430. gl.viewport(0, 0, bufferWidth, bufferHeight);
  1431. return;
  1432. }
  1433. if( tex.depthBuffer != null && (tex.depthBuffer.width != tex.width || tex.depthBuffer.height != tex.height) )
  1434. throw "Invalid depth buffer size : does not match render target size";
  1435. if( mipLevel > 0 && glES == 1 ) throw "Cannot render to mipLevel in WebGL1, use upload() instead";
  1436. if( tex.t == null )
  1437. tex.alloc();
  1438. if( tex.flags.has(MipMapped) && !tex.flags.has(WasCleared) ) {
  1439. var bind = getBindType(tex);
  1440. gl.bindTexture(bind, tex.t.t);
  1441. gl.generateMipmap(bind);
  1442. restoreBind();
  1443. }
  1444. tex.lastFrame = frame;
  1445. curTargetLayer = layer;
  1446. curTargetMip = mipLevel;
  1447. #if multidriver
  1448. if( tex.t.driver != this )
  1449. throw "Invalid texture context";
  1450. #end
  1451. gl.bindFramebuffer(GL.FRAMEBUFFER, commonFB);
  1452. if( tex.flags.has(IsArray) )
  1453. gl.framebufferTextureLayer(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, tex.t.t, mipLevel, layer);
  1454. else
  1455. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, tex.flags.has(Cube) ? CUBE_FACES[layer] : GL.TEXTURE_2D, tex.t.t, mipLevel);
  1456. if( tex.depthBuffer != null && depthBinding != NotBound ) {
  1457. // Depthbuffer and stencilbuffer are combined in one buffer, created with GL.DEPTH_STENCIL
  1458. if(tex.depthBuffer.hasStencil() && tex.depthBuffer.format == Depth24Stencil8) {
  1459. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_STENCIL_ATTACHMENT, GL.TEXTURE_2D,@:privateAccess tex.depthBuffer.t.t, 0);
  1460. } else {
  1461. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_STENCIL_ATTACHMENT, GL.TEXTURE_2D,null,0);
  1462. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.TEXTURE_2D, @:privateAccess tex.depthBuffer.t.t,0);
  1463. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.STENCIL_ATTACHMENT, GL.TEXTURE_2D,tex.depthBuffer.hasStencil() ? @:privateAccess tex.depthBuffer.t.t : null,0);
  1464. }
  1465. } else {
  1466. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_STENCIL_ATTACHMENT, GL.TEXTURE_2D,null,0);
  1467. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.TEXTURE_2D, null,0);
  1468. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.STENCIL_ATTACHMENT, GL.TEXTURE_2D, null,0);
  1469. }
  1470. var w = tex.width >> mipLevel; if( w == 0 ) w = 1;
  1471. var h = tex.height >> mipLevel; if( h == 0 ) h = 1;
  1472. gl.viewport(0, 0, w, h);
  1473. for( i in 0...boundTextures.length )
  1474. boundTextures[i] = null;
  1475. if( !tex.flags.has(WasCleared) ) {
  1476. tex.flags.set(WasCleared); // once we draw to, do not clear again
  1477. clear(BLACK);
  1478. }
  1479. #if js
  1480. if( glDebug ) {
  1481. var code = gl.checkFramebufferStatus(GL.FRAMEBUFFER);
  1482. if( code != GL.FRAMEBUFFER_COMPLETE )
  1483. throw "Invalid frame buffer: "+code;
  1484. }
  1485. #end
  1486. }
  1487. override function setRenderTargets( textures : Array<h3d.mat.Texture>, depthBinding : h3d.Engine.DepthBinding = ReadWrite ) {
  1488. unbindTargets();
  1489. setRenderTarget(textures[0], depthBinding);
  1490. if( textures.length < 2 )
  1491. return;
  1492. numTargets = textures.length;
  1493. var needClear = false;
  1494. for( i in 1...textures.length ) {
  1495. var tex = textures[i];
  1496. if( tex.t == null )
  1497. tex.alloc();
  1498. #if multidriver
  1499. if( tex.t.driver != this )
  1500. throw "Invalid texture context";
  1501. #end
  1502. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0 + i, GL.TEXTURE_2D, tex.t.t, 0);
  1503. curTargets[i] = tex;
  1504. tex.lastFrame = frame;
  1505. if( !tex.flags.has(WasCleared) ) {
  1506. tex.flags.set(WasCleared); // once we draw to, do not clear again
  1507. needClear = true;
  1508. }
  1509. }
  1510. setDrawBuffers(textures.length);
  1511. if( needClear ) clear(BLACK);
  1512. }
  1513. override function setDepth( depthBuffer : h3d.mat.Texture ) {
  1514. unbindTargets();
  1515. curTarget = depthBuffer;
  1516. depthBuffer.lastFrame = frame;
  1517. curTargetLayer = 0;
  1518. curTargetMip = 0;
  1519. #if multidriver
  1520. if( depthBuffer.t.driver != this )
  1521. throw "Invalid texture context";
  1522. #end
  1523. gl.bindFramebuffer(GL.FRAMEBUFFER, commonFB);
  1524. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.COLOR_ATTACHMENT0, GL.TEXTURE_2D, null, 0);
  1525. if(depthBuffer.hasStencil() && depthBuffer.format == Depth24Stencil8) {
  1526. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_STENCIL_ATTACHMENT, GL.TEXTURE_2D,@:privateAccess depthBuffer.t.t, 0);
  1527. } else {
  1528. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_STENCIL_ATTACHMENT, GL.TEXTURE_2D,null,0);
  1529. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.DEPTH_ATTACHMENT, GL.TEXTURE_2D, @:privateAccess depthBuffer.t.t,0);
  1530. gl.framebufferTexture2D(GL.FRAMEBUFFER, GL.STENCIL_ATTACHMENT, GL.TEXTURE_2D,depthBuffer.hasStencil() ? @:privateAccess depthBuffer.t.t : null,0);
  1531. }
  1532. var w = depthBuffer.width; if( w == 0 ) w = 1;
  1533. var h = depthBuffer.height; if( h == 0 ) h = 1;
  1534. gl.viewport(0, 0, w, h);
  1535. for( i in 0...boundTextures.length )
  1536. boundTextures[i] = null;
  1537. // if( !tex.flags.has(WasCleared) ) {
  1538. // tex.flags.set(WasCleared); // once we draw to, do not clear again
  1539. // clear(BLACK);
  1540. // }
  1541. #if js
  1542. if( glDebug ) {
  1543. var code = gl.checkFramebufferStatus(GL.FRAMEBUFFER);
  1544. if( code != GL.FRAMEBUFFER_COMPLETE )
  1545. throw "Invalid frame buffer: "+code;
  1546. }
  1547. #end
  1548. }
  1549. override function init( onCreate : Bool -> Void, forceSoftware = false ) {
  1550. #if js
  1551. // wait until all assets have properly load
  1552. if( js.Browser.document.readyState == 'complete' )
  1553. haxe.Timer.delay(onCreate.bind(false), 1);
  1554. else {
  1555. function onLoad() {
  1556. js.Browser.window.removeEventListener("load", onLoad);
  1557. onCreate(false);
  1558. }
  1559. js.Browser.window.addEventListener("load", onLoad);
  1560. }
  1561. #else
  1562. haxe.Timer.delay(onCreate.bind(false), 1);
  1563. #end
  1564. }
  1565. override function hasFeature( f : Feature ) : Bool {
  1566. #if js
  1567. return features.get(f);
  1568. #else
  1569. return true;
  1570. #end
  1571. }
  1572. #if js
  1573. var features : Map<Feature,Bool> = new Map();
  1574. var has16Bits : Bool;
  1575. function makeFeatures() {
  1576. for( f in Type.allEnums(Feature) )
  1577. features.set(f,checkFeature(f));
  1578. if( gl.getExtension("WEBGL_compressed_texture_s3tc") != null ) {
  1579. maxCompressedTexturesSupport = 3;
  1580. if( gl.getExtension("EXT_texture_compression_bptc") != null )
  1581. maxCompressedTexturesSupport = 7;
  1582. }
  1583. if( glES < 3 )
  1584. gl.getExtension("WEBGL_depth_texture");
  1585. has16Bits = gl.getExtension("EXT_texture_norm16") != null; // 16 bit textures
  1586. }
  1587. function checkFeature( f : Feature ) {
  1588. return switch( f ) {
  1589. case HardwareAccelerated, AllocDepthBuffer, BottomLeftCoords, Wireframe:
  1590. true;
  1591. case StandardDerivatives, MultipleRenderTargets, SRGBTextures if( glES >= 3 ):
  1592. true;
  1593. case ShaderModel3 if( glES >= 3 ):
  1594. true;
  1595. case FloatTextures if( glES >= 3 ):
  1596. gl.getExtension('EXT_color_buffer_float') != null && gl.getExtension("OES_texture_float_linear") != null; // allow render to 16f/32f textures (not standard in webgl 2)
  1597. case StandardDerivatives:
  1598. gl.getExtension('OES_standard_derivatives') != null;
  1599. case FloatTextures:
  1600. gl.getExtension('OES_texture_float') != null && gl.getExtension('OES_texture_float_linear') != null &&
  1601. gl.getExtension('OES_texture_half_float') != null && gl.getExtension('OES_texture_half_float_linear') != null;
  1602. case SRGBTextures:
  1603. gl.getExtension('EXT_sRGB') != null;
  1604. case MultipleRenderTargets:
  1605. mrtExt != null || (mrtExt = gl.getExtension('WEBGL_draw_buffers')) != null;
  1606. case InstancedRendering:
  1607. return (glES >= 3) ? true : gl.getExtension("ANGLE_instanced_arrays") != null;
  1608. default:
  1609. false;
  1610. }
  1611. }
  1612. // Draws video element directly onto Texture. Used for video rendering.
  1613. private function uploadTextureVideoElement( t : h3d.mat.Texture, v : js.html.VideoElement, mipLevel : Int, side : Int ) {
  1614. var cubic = t.flags.has(Cube);
  1615. var bind = getBindType(t);
  1616. if( t.flags.has(IsArray) ) throw "TODO:texImage3D";
  1617. var face = cubic ? CUBE_FACES[side] : GL.TEXTURE_2D;
  1618. gl.bindTexture(bind, t.t.t);
  1619. gl.texSubImage2D(face, mipLevel, 0, 0, v.videoWidth, v.videoHeight, getChannels(t.t), t.t.pixelFmt, untyped v);
  1620. restoreBind();
  1621. }
  1622. #end
  1623. override function captureRenderBuffer( pixels : hxd.Pixels ) {
  1624. captureSubRenderBuffer(pixels, 0, 0);
  1625. }
  1626. function captureSubRenderBuffer( pixels : hxd.Pixels, x : Int, y : Int ) {
  1627. if( curTarget == null )
  1628. throw "Can't capture main render buffer in GL";
  1629. gl.getError(); // always discard
  1630. #if js
  1631. var buffer : ArrayBufferView = @:privateAccess pixels.bytes.b;
  1632. switch( curTarget.format ) {
  1633. case RGBA32F, R32F, RG32F, RGB32F: buffer = new Float32Array(buffer.buffer);
  1634. case RGBA16F, R16F, RG16F, RGB16F, RGBA16U, R16U, RG16U, RGB16U: buffer = new Uint16Array(buffer.buffer);
  1635. case RGB10A2, RG11B10UF: buffer = new Uint32Array(buffer.buffer);
  1636. default:
  1637. }
  1638. #else
  1639. var buffer = @:privateAccess pixels.bytes.b;
  1640. #end
  1641. #if (js || hl)
  1642. gl.readPixels(x, y, pixels.width, pixels.height, getChannels(curTarget.t), curTarget.t.pixelFmt, buffer);
  1643. var error = gl.getError();
  1644. if( error != 0 ) throw "Failed to capture pixels (error "+error+")";
  1645. @:privateAccess pixels.innerFormat = curTarget.format;
  1646. #end
  1647. }
  1648. #if hl
  1649. override function allocQuery(kind:QueryKind) {
  1650. return { q : GL.createQuery(), kind : kind };
  1651. }
  1652. override function deleteQuery( q : Query ) {
  1653. GL.deleteQuery(q.q);
  1654. q.q = null;
  1655. }
  1656. override function beginQuery( q : Query ) {
  1657. switch( q.kind ) {
  1658. case TimeStamp:
  1659. throw "use endQuery() for timestamp queries";
  1660. case Samples:
  1661. GL.beginQuery(GL.SAMPLES_PASSED, q.q);
  1662. }
  1663. }
  1664. override function endQuery( q : Query ) {
  1665. switch( q.kind ) {
  1666. case TimeStamp:
  1667. GL.queryCounter(q.q, GL.TIMESTAMP);
  1668. case Samples:
  1669. GL.endQuery(GL.SAMPLES_PASSED);
  1670. }
  1671. }
  1672. override function queryResultAvailable(q:Query) {
  1673. return GL.queryResultAvailable(q.q);
  1674. }
  1675. override function queryResult(q:Query) {
  1676. return GL.queryResult(q.q);
  1677. }
  1678. inline function debugCheckError() {
  1679. if(!debug) return;
  1680. var err = gl.getError();
  1681. if(err != GL.NO_ERROR) {
  1682. switch(err) {
  1683. case GL.INVALID_ENUM: throw "INVALID_ENUM";
  1684. case GL.INVALID_VALUE: throw "INVALID_VALUE";
  1685. case GL.INVALID_OPERATION: throw "INVALID_OPERATION";
  1686. case 1286: throw "INVALID_FRAMEBUFFER_OPERATION";
  1687. default: throw "Error: " + err;
  1688. }
  1689. }
  1690. }
  1691. #end
  1692. static var TFILTERS = [
  1693. [[GL.NEAREST,GL.NEAREST],[GL.LINEAR,GL.LINEAR]],
  1694. [[GL.NEAREST,GL.NEAREST_MIPMAP_NEAREST],[GL.LINEAR,GL.LINEAR_MIPMAP_NEAREST]],
  1695. [[GL.NEAREST,GL.NEAREST_MIPMAP_LINEAR],[GL.LINEAR,GL.LINEAR_MIPMAP_LINEAR]],
  1696. ];
  1697. static var TWRAP = [
  1698. GL.CLAMP_TO_EDGE,
  1699. GL.REPEAT,
  1700. ];
  1701. static var FACES = [
  1702. 0,
  1703. GL.FRONT,
  1704. GL.BACK,
  1705. GL.FRONT_AND_BACK,
  1706. ];
  1707. static var BLEND = [
  1708. GL.ONE,
  1709. GL.ZERO,
  1710. GL.SRC_ALPHA,
  1711. GL.SRC_COLOR,
  1712. GL.DST_ALPHA,
  1713. GL.DST_COLOR,
  1714. GL.ONE_MINUS_SRC_ALPHA,
  1715. GL.ONE_MINUS_SRC_COLOR,
  1716. GL.ONE_MINUS_DST_ALPHA,
  1717. GL.ONE_MINUS_DST_COLOR,
  1718. GL.CONSTANT_COLOR,
  1719. GL.CONSTANT_ALPHA,
  1720. GL.ONE_MINUS_CONSTANT_COLOR,
  1721. GL.ONE_MINUS_CONSTANT_ALPHA,
  1722. GL.SRC_ALPHA_SATURATE,
  1723. ];
  1724. static var COMPARE = [
  1725. GL.ALWAYS,
  1726. GL.NEVER,
  1727. GL.EQUAL,
  1728. GL.NOTEQUAL,
  1729. GL.GREATER,
  1730. GL.GEQUAL,
  1731. GL.LESS,
  1732. GL.LEQUAL,
  1733. ];
  1734. static var STENCIL_OP = [
  1735. GL.KEEP,
  1736. GL.ZERO,
  1737. GL.REPLACE,
  1738. GL.INCR,
  1739. GL.INCR_WRAP,
  1740. GL.DECR,
  1741. GL.DECR_WRAP,
  1742. GL.INVERT,
  1743. ];
  1744. static var OP = [
  1745. GL.FUNC_ADD,
  1746. GL.FUNC_SUBTRACT,
  1747. GL.FUNC_REVERSE_SUBTRACT,
  1748. #if js GL.MIN #else GL.FUNC_MIN #end,
  1749. #if js GL.MAX #else GL.FUNC_MAX #end,
  1750. ];
  1751. static var CUBE_FACES = [
  1752. GL.TEXTURE_CUBE_MAP_POSITIVE_X,
  1753. GL.TEXTURE_CUBE_MAP_NEGATIVE_X,
  1754. GL.TEXTURE_CUBE_MAP_POSITIVE_Y,
  1755. GL.TEXTURE_CUBE_MAP_NEGATIVE_Y,
  1756. GL.TEXTURE_CUBE_MAP_POSITIVE_Z,
  1757. GL.TEXTURE_CUBE_MAP_NEGATIVE_Z,
  1758. ];
  1759. static var CBUFFERS =
  1760. #if (hlsdl || usegl)
  1761. hl.Bytes.getArray([for( i in 0...32 ) GL.COLOR_ATTACHMENT0 + i]);
  1762. #elseif js
  1763. [for( i in 0...32 ) [for( k in 0...i ) GL.COLOR_ATTACHMENT0 + k]];
  1764. #else
  1765. null;
  1766. #end
  1767. }
  1768. #end