GlDriver.hx 66 KB

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