runtime.js 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  1. class WebGLInterface {
  2. constructor(wasmMemoryInterface, canvasElement, contextSettings) {
  3. this.wasmMemoryInterface = wasmMemoryInterface;
  4. this.ctx = null;
  5. this.ctx_version = 1;
  6. this.counter = 1;
  7. this.lastError = 0;
  8. this.buffers = [];
  9. this.mappedBuffers = {};
  10. this.programs = [];
  11. this.framebuffers = [];
  12. this.renderbuffers = [];
  13. this.textures = [];
  14. this.uniforms = [];
  15. this.shaders = [];
  16. this.vaos = [];
  17. this.contexts = [];
  18. this.currentContext = null;
  19. this.offscreenCanvases = {};
  20. this.timerQueriesEXT = [];
  21. this.queries = [];
  22. this.samplers = [];
  23. this.transformFeedbacks = [];
  24. this.syncs = [];
  25. this.programInfos = {};
  26. if (contextSettings === undefined) {
  27. contextSettings = {antialias: false};
  28. }
  29. this.ctx = canvasElement.getContext("webgl2", contextSettings) || canvasElement.getContext("webgl", contextSettings);
  30. if (!this.ctx) {
  31. return;
  32. }
  33. if (this.ctx.getParameter(0x1F02).indexOf("WebGL 2.0") !== -1) {
  34. this.ctx_version = 2.0;
  35. } else {
  36. this.ctx_version = 1.0;
  37. }
  38. }
  39. get mem() {
  40. return this.wasmMemoryInterface
  41. }
  42. assertWebGL2() {
  43. if (this.ctx_version < 2) {
  44. throw new Error("WebGL2 procedure called in a canvas without a WebGL2 context");
  45. }
  46. }
  47. getNewId(table) {
  48. for (var ret = this.counter++, i = table.length; i < ret; i++) {
  49. table[i] = null;
  50. }
  51. return ret;
  52. }
  53. recordError(errorCode) {
  54. this.lastError || (this.lastError = errorCode);
  55. }
  56. populateUniformTable(program) {
  57. let p = this.programs[program];
  58. this.programInfos[program] = {
  59. uniforms: {},
  60. maxUniformLength: 0,
  61. maxAttributeLength: -1,
  62. maxUniformBlockNameLength: -1,
  63. };
  64. for (let ptable = this.programInfos[program], utable = ptable.uniforms, numUniforms = this.ctx.getProgramParameter(p, this.ctx.ACTIVE_UNIFORMS), i = 0; i < numUniforms; ++i) {
  65. let u = this.ctx.getActiveUniform(p, i);
  66. let name = u.name;
  67. if (ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name.length + 1), name.indexOf("]", name.length - 1) !== -1) {
  68. name = name.slice(0, name.lastIndexOf("["));
  69. }
  70. let loc = this.ctx.getUniformLocation(p, name);
  71. if (loc !== null) {
  72. let id = this.getNewId(this.uniforms);
  73. utable[name] = [u.size, id], this.uniforms[id] = loc;
  74. for (let j = 1; j < u.size; ++j) {
  75. let n = name + "[" + j + "]";
  76. let loc = this.ctx.getUniformLocation(p, n);
  77. let id = this.getNewId(this.uniforms);
  78. this.uniforms[id] = loc;
  79. }
  80. }
  81. }
  82. }
  83. getSource(shader, strings_ptr, strings_length) {
  84. const STRING_SIZE = 2*4;
  85. let source = "";
  86. for (let i = 0; i < strings_length; i++) {
  87. let ptr = this.mem.loadPtr(strings_ptr + i*STRING_SIZE);
  88. let len = this.mem.loadPtr(strings_ptr + i*STRING_SIZE + 4);
  89. let str = this.mem.loadString(ptr, len);
  90. source += str;
  91. }
  92. return source;
  93. }
  94. getWebGL1Interface() {
  95. return {
  96. DrawingBufferWidth: () => this.ctx.drawingBufferWidth,
  97. DrawingBufferHeight: () => this.ctx.drawingBufferHeight,
  98. IsExtensionSupported: (name_ptr, name_len) => {
  99. let name = this.mem.loadString(name_ptr, name_len);
  100. let extensions = this.ctx.getSupportedExtensions();
  101. return extensions.indexOf(name) !== -1
  102. },
  103. GetError: () => {
  104. let err = this.lastError;
  105. this.recordError(0);
  106. if (err) {
  107. return err;
  108. }
  109. return this.ctx.getError();
  110. },
  111. GetWebGLVersion: (major_ptr, minor_ptr) => {
  112. let version = this.ctx.getParameter(0x1F02);
  113. if (version.indexOf("WebGL 2.0") !== -1) {
  114. this.mem.storeI32(major_ptr, 2);
  115. this.mem.storeI32(minor_ptr, 0);
  116. return;
  117. }
  118. this.mem.storeI32(major_ptr, 1);
  119. this.mem.storeI32(minor_ptr, 0);
  120. },
  121. GetESVersion: (major_ptr, minor_ptr) => {
  122. let version = this.ctx.getParameter(0x1F02);
  123. if (version.indexOf("OpenGL ES 3.0") !== -1) {
  124. this.mem.storeI32(major_ptr, 3);
  125. this.mem.storeI32(minor_ptr, 0);
  126. return;
  127. }
  128. this.mem.storeI32(major_ptr, 2);
  129. this.mem.storeI32(minor_ptr, 0);
  130. },
  131. ActiveTexture: (x) => {
  132. this.ctx.activeTexture(x);
  133. },
  134. AttachShader: (program, shader) => {
  135. this.ctx.attachShader(this.programs[program], this.shaders[shader]);
  136. },
  137. BindAttribLocation: (program, index, name_ptr, name_len) => {
  138. let name = this.mem.loadString(name_ptr, name_len);
  139. this.ctx.bindAttribLocation(this.programs[program], index, name)
  140. },
  141. BindBuffer: (target, buffer) => {
  142. let bufferObj = buffer ? this.buffers[buffer] : null;
  143. if (target == 35051) {
  144. this.ctx.currentPixelPackBufferBinding = buffer;
  145. } else {
  146. if (target == 35052) {
  147. this.ctx.currentPixelUnpackBufferBinding = buffer;
  148. }
  149. this.ctx.bindBuffer(target, bufferObj)
  150. }
  151. },
  152. BindFramebuffer: (target, buffer) => {
  153. // TODO: BindFramebuffer
  154. },
  155. BindTexture: (target, texture) => {
  156. this.ctx.bindTexture(target, texture ? this.textures[texture] : null)
  157. },
  158. BlendColor: (red, green, blue, alpha) => {
  159. this.ctx.blendColor(red, green, blue, alpha);
  160. },
  161. BlendEquation: (mode) => {
  162. this.ctx.blendEquation(mode);
  163. },
  164. BlendFunc: (sfactor, dfactor) => {
  165. this.ctx.blendFunc(sfactor, dfactor);
  166. },
  167. BlendFuncSeparate: (srcRGB, dstRGB, srcAlpha, dstAlpha) => {
  168. this.ctx.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
  169. },
  170. BufferData: (target, size, data, usage) => {
  171. if (data) {
  172. this.ctx.bufferData(target, this.mem.loadBytes(data, size), usage);
  173. } else {
  174. this.ctx.bufferData(target, size, usage);
  175. }
  176. },
  177. BufferSubData: (target, offset, size, data) => {
  178. if (data) {
  179. this.ctx.bufferSubData(target, offset, this.mem.loadBytes(data, size));
  180. } else {
  181. this.ctx.bufferSubData(target, offset, null);
  182. }
  183. },
  184. Clear: (x) => {
  185. this.ctx.clear(x);
  186. },
  187. ClearColor: (r, g, b, a) => {
  188. this.ctx.clearColor(r, g, b, a);
  189. },
  190. ClearDepth: (x) => {
  191. this.ctx.clearDepth(x);
  192. },
  193. ClearStencil: (x) => {
  194. this.ctx.clearStencil(x);
  195. },
  196. ColorMask: (r, g, b, a) => {
  197. this.ctx.colorMask(!!r, !!g, !!b, !!a);
  198. },
  199. CompileShader: (shader) => {
  200. this.ctx.compileShader(this.shaders[shader]);
  201. },
  202. CompressedTexImage2D: (target, level, internalformat, width, height, border, imageSize, data) => {
  203. if (data) {
  204. this.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, this.mem.loadBytes(data, imageSize));
  205. } else {
  206. this.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, null);
  207. }
  208. },
  209. CompressedTexSubImage2D: (target, level, xoffset, yoffset, width, height, format, imageSize, data) => {
  210. if (data) {
  211. this.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, this.mem.loadBytes(data, imageSize));
  212. } else {
  213. this.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, null);
  214. }
  215. },
  216. CopyTexImage2D: (target, level, internalformat, x, y, width, height, border) => {
  217. this.ctx.copyTexImage2D(target, level, internalformat, x, y, width, height, border);
  218. },
  219. CopyTexSubImage2D: (target, level, xoffset, yoffset, x, y, width, height) => {
  220. this.ctx.copyTexImage2D(target, level, xoffset, yoffset, x, y, width, height);
  221. },
  222. CreateBuffer: () => {
  223. let buffer = this.ctx.createBuffer();
  224. if (!buffer) {
  225. this.recordError(1282);
  226. return 0;
  227. }
  228. let id = this.getNewId(this.buffers);
  229. buffer.name = id
  230. this.buffers[id] = buffer;
  231. return id;
  232. },
  233. CreateFramebuffer: () => {
  234. let buffer = this.ctx.createFramebuffer();
  235. let id = this.getNewId(this.framebuffers);
  236. buffer.name = id
  237. this.framebuffers[id] = buffer;
  238. return id;
  239. },
  240. CreateProgram: () => {
  241. let program = this.ctx.createProgram();
  242. let id = this.getNewId(this.programs);
  243. program.name = id;
  244. this.programs[id] = program;
  245. return id;
  246. },
  247. CreateRenderbuffer: () => {
  248. let buffer = this.ctx.createRenderbuffer();
  249. let id = this.getNewId(this.renderbuffers);
  250. buffer.name = id;
  251. this.renderbuffers[id] = buffer;
  252. return id;
  253. },
  254. CreateShader: (shaderType) => {
  255. let shader = this.ctx.createShader(shaderType);
  256. let id = this.getNewId(this.shaders);
  257. shader.name = id;
  258. this.shaders[id] = shader;
  259. return id;
  260. },
  261. CreateTexture: () => {
  262. let texture = this.ctx.createTexture();
  263. if (!texture) {
  264. this.recordError(1282)
  265. return 0;
  266. }
  267. let id = this.getNewId(this.textures);
  268. texture.name = id;
  269. this.textures[id] = texture;
  270. return id;
  271. },
  272. CullFace: (mode) => {
  273. this.ctx.cullFace(mode);
  274. },
  275. DeleteBuffer: (id) => {
  276. let obj = this.buffers[id];
  277. if (obj && id != 0) {
  278. this.ctx.deleteBuffer(obj);
  279. this.buffers[id] = null;
  280. }
  281. },
  282. DeleteFramebuffer: (id) => {
  283. let obj = this.framebuffers[id];
  284. if (obj && id != 0) {
  285. this.ctx.deleteFramebuffer(obj);
  286. this.framebuffers[id] = null;
  287. }
  288. },
  289. DeleteProgram: (id) => {
  290. let obj = this.programs[id];
  291. if (obj && id != 0) {
  292. this.ctx.deleteProgram(obj);
  293. this.programs[id] = null;
  294. }
  295. },
  296. DeleteRenderbuffer: (id) => {
  297. let obj = this.renderbuffers[id];
  298. if (obj && id != 0) {
  299. this.ctx.deleteRenderbuffer(obj);
  300. this.renderbuffers[id] = null;
  301. }
  302. },
  303. DeleteShader: (id) => {
  304. let obj = this.shaders[id];
  305. if (obj && id != 0) {
  306. this.ctx.deleteShader(obj);
  307. this.shaders[id] = null;
  308. }
  309. },
  310. DeleteTexture: (id) => {
  311. let obj = this.textures[id];
  312. if (obj && id != 0) {
  313. this.ctx.deleteTexture(obj);
  314. this.textures[id] = null;
  315. }
  316. },
  317. DepthFunc: (func) => {
  318. this.ctx.depthFunc(func);
  319. },
  320. DepthMask: (flag) => {
  321. this.ctx.depthMask(!!flag);
  322. },
  323. DepthRange: (zNear, zFar) => {
  324. this.ctx.depthRange(zNear, zFar);
  325. },
  326. DetachShader: (program, shader) => {
  327. this.ctx.detachShader(this.programs[program], this.shaders[shader]);
  328. },
  329. Disable: (cap) => {
  330. this.ctx.disable(cap);
  331. },
  332. DisableVertexAttribArray: (index) => {
  333. this.ctx.disableVertexAttribArray(index);
  334. },
  335. DrawArrays: (mode, first, count) => {
  336. this.ctx.drawArrays(mode, first, count);
  337. },
  338. DrawElements: (mode, count, type, indices) => {
  339. this.ctx.drawElements(mode, count, type, indices);
  340. },
  341. Enable: (cap) => {
  342. this.ctx.enable(cap);
  343. },
  344. EnableVertexAttribArray: (index) => {
  345. this.ctx.enableVertexAttribArray(index);
  346. },
  347. Finish: () => {
  348. this.ctx.finish();
  349. },
  350. Flush: () => {
  351. this.ctx.flush();
  352. },
  353. FramebufferRenderBuffer: (target, attachment, renderbuffertarget, renderbuffer) => {
  354. this.ctx.framebufferRenderBuffer(target, attachment, renderbuffertarget, this.renderbuffers[renderbuffer]);
  355. },
  356. FramebufferTexture2D: (target, attachment, textarget, texture, level) => {
  357. this.ctx.framebufferTexture2D(target, attachment, textarget, this.textures[texture], level);
  358. },
  359. FrontFace: (mode) => {
  360. this.ctx.frontFace(mode);
  361. },
  362. GenerateMipmap: (target) => {
  363. this.ctx.generateMipmap(target);
  364. },
  365. GetAttribLocation: (program, name_ptr, name_len) => {
  366. let name = this.mem.loadString(name_ptr, name_len);
  367. return this.ctx.getAttribLocation(this.programs[program], name);
  368. },
  369. GetProgramParameter: (program, pname) => {
  370. return this.ctx.getProgramParameter(this.programs[program], pname)
  371. },
  372. GetProgramInfoLog: (program, buf_ptr, buf_len, length_ptr) => {
  373. let log = this.ctx.getProgramInfoLog(this.programs[program]);
  374. if (log === null) {
  375. log = "(unknown error)";
  376. }
  377. if (buf_len > 0 && buf_ptr) {
  378. let n = Math.min(buf_len, log.length);
  379. log = log.substring(0, n);
  380. this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log))
  381. this.mem.storeInt(length_ptr, n);
  382. }
  383. },
  384. GetShaderInfoLog: (shader, buf_ptr, buf_len, length_ptr) => {
  385. let log = this.ctx.getShaderInfoLog(this.shaders[shader]);
  386. if (log === null) {
  387. log = "(unknown error)";
  388. }
  389. if (buf_len > 0 && buf_ptr) {
  390. let n = Math.min(buf_len, log.length);
  391. log = log.substring(0, n);
  392. this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log))
  393. this.mem.storeInt(length_ptr, n);
  394. }
  395. },
  396. GetShaderiv: (shader, pname, p) => {
  397. if (p) {
  398. if (pname == 35716) {
  399. let log = this.ctx.getShaderInfoLog(this.shaders[shader]);
  400. if (log === null) {
  401. log = "(unknown error)";
  402. }
  403. this.mem.storeInt(p, log.length+1);
  404. } else if (pname == 35720) {
  405. let source = this.ctx.getShaderSource(this.shaders[shader]);
  406. let sourceLength = (source === null || source.length == 0) ? 0 : source.length+1;
  407. this.mem.storeInt(p, sourceLength);
  408. } else {
  409. let param = this.ctx.getShaderParameter(this.shaders[shader], pname);
  410. this.mem.storeI32(p, param);
  411. }
  412. } else {
  413. this.recordError(1281);
  414. }
  415. },
  416. GetUniformLocation: (program, name_ptr, name_len) => {
  417. let name = this.mem.loadString(name_ptr, name_len);
  418. let arrayOffset = 0;
  419. if (name.indexOf("]", name.length - 1) !== -1) {
  420. let ls = name.lastIndexOf("["),
  421. arrayIndex = name.slice(ls + 1, -1);
  422. if (arrayIndex.length > 0 && (arrayOffset = parseInt(arrayIndex)) < 0) {
  423. return -1;
  424. }
  425. name = name.slice(0, ls)
  426. }
  427. var ptable = this.programInfos[program];
  428. if (!ptable) {
  429. return -1;
  430. }
  431. var uniformInfo = ptable.uniforms[name];
  432. return (uniformInfo && arrayOffset < uniformInfo[0]) ? uniformInfo[1] + arrayOffset : -1
  433. },
  434. GetVertexAttribOffset: (index, pname) => {
  435. return this.ctx.getVertexAttribOffset(index, pname);
  436. },
  437. Hint: (target, mode) => {
  438. this.ctx.hint(target, mode);
  439. },
  440. IsBuffer: (buffer) => this.ctx.isBuffer(this.buffers[buffer]),
  441. IsEnabled: (enabled) => this.ctx.isEnabled(this.enableds[enabled]),
  442. IsFramebuffer: (framebuffer) => this.ctx.isFramebuffer(this.framebuffers[framebuffer]),
  443. IsProgram: (program) => this.ctx.isProgram(this.programs[program]),
  444. IsRenderbuffer: (renderbuffer) => this.ctx.isRenderbuffer(this.renderbuffers[renderbuffer]),
  445. IsShader: (shader) => this.ctx.isShader(this.shaders[shader]),
  446. IsTexture: (texture) => this.ctx.isTexture(this.textures[texture]),
  447. LineWidth: (width) => {
  448. this.ctx.lineWidth(width);
  449. },
  450. LinkProgram: (program) => {
  451. this.ctx.linkProgram(this.programs[program]);
  452. this.programInfos[program] = null;
  453. this.populateUniformTable(program);
  454. },
  455. PixelStorei: (pname, param) => {
  456. this.ctx.pixelStorei(pname, param);
  457. },
  458. PolygonOffset: (factor, units) => {
  459. this.ctx.polygonOffset(factor, units);
  460. },
  461. ReadnPixels: (x, y, width, height, format, type, bufSize, data) => {
  462. this.ctx.readPixels(x, y, width, format, type, this.mem.loadBytes(data, bufSize));
  463. },
  464. RenderbufferStorage: (target, internalformat, width, height) => {
  465. this.ctx.renderbufferStorage(target, internalformat, width, height);
  466. },
  467. SampleCoverage: (value, invert) => {
  468. this.ctx.sampleCoverage(value, !!invert);
  469. },
  470. Scissor: (x, y, width, height) => {
  471. this.ctx.scissor(x, y, width, height);
  472. },
  473. ShaderSource: (shader, strings_ptr, strings_length) => {
  474. let source = this.getSource(shader, strings_ptr, strings_length);
  475. this.ctx.shaderSource(this.shaders[shader], source);
  476. },
  477. StencilFunc: (func, ref, mask) => {
  478. this.ctx.stencilFunc(func, ref, mask);
  479. },
  480. StencilFuncSeparate: (face, func, ref, mask) => {
  481. this.ctx.stencilFuncSeparate(face, func, ref, mask);
  482. },
  483. StencilMask: (mask) => {
  484. this.ctx.stencilMask(mask);
  485. },
  486. StencilMaskSeparate: (face, mask) => {
  487. this.ctx.stencilMaskSeparate(face, mask);
  488. },
  489. StencilOp: (fail, zfail, zpass) => {
  490. this.ctx.stencilOp(fail, zfail, zpass);
  491. },
  492. StencilOpSeparate: (face, fail, zfail, zpass) => {
  493. this.ctx.stencilOpSeparate(face, fail, zfail, zpass);
  494. },
  495. TexImage2D: (target, level, internalformat, width, height, border, format, type, size, data) => {
  496. if (data) {
  497. this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, this.mem.loadBytes(data, size));
  498. } else {
  499. this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, null);
  500. }
  501. },
  502. TexParameterf: (target, pname, param) => {
  503. this.ctx.texParameterf(target, pname, param);
  504. },
  505. TexParameteri: (target, pname, param) => {
  506. this.ctx.texParameteri(target, pname, param);
  507. },
  508. TexSubImage2D: (target, level, xoffset, yoffset, width, height, format, type, size, data) => {
  509. this.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, this.mem.loadBytes(data, size));
  510. },
  511. Uniform1f: (location, v0) => { this.ctx.uniform1f(this.uniforms[location], v0); },
  512. Uniform2f: (location, v0, v1) => { this.ctx.uniform2f(this.uniforms[location], v0, v1); },
  513. Uniform3f: (location, v0, v1, v2) => { this.ctx.uniform3f(this.uniforms[location], v0, v1, v2); },
  514. Uniform4f: (location, v0, v1, v2, v3) => { this.ctx.uniform4f(this.uniforms[location], v0, v1, v2, v3); },
  515. Uniform1i: (location, v0) => { this.ctx.uniform1i(this.uniforms[location], v0); },
  516. Uniform2i: (location, v0, v1) => { this.ctx.uniform2i(this.uniforms[location], v0, v1); },
  517. Uniform3i: (location, v0, v1, v2) => { this.ctx.uniform3i(this.uniforms[location], v0, v1, v2); },
  518. Uniform4i: (location, v0, v1, v2, v3) => { this.ctx.uniform4i(this.uniforms[location], v0, v1, v2, v3); },
  519. UniformMatrix2fv: (location, addr) => {
  520. let array = this.mem.loadF32Array(addr, 2*2);
  521. this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
  522. },
  523. UniformMatrix3fv: (location, addr) => {
  524. let array = this.mem.loadF32Array(addr, 3*3);
  525. this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
  526. },
  527. UniformMatrix4fv: (location, addr) => {
  528. let array = this.mem.loadF32Array(addr, 4*4);
  529. this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
  530. },
  531. UseProgram: (program) => {
  532. this.ctx.useProgram(this.programs[program]);
  533. },
  534. ValidateProgram: (program) => {
  535. this.ctx.validateProgram(this.programs[program]);
  536. },
  537. VertexAttrib1f: (index, x) => {
  538. this.ctx.vertexAttrib1f(index, x);
  539. },
  540. VertexAttrib2f: (index, x, y) => {
  541. this.ctx.vertexAttrib2f(index, x, y);
  542. },
  543. VertexAttrib3f: (index, x, y, z) => {
  544. this.ctx.vertexAttrib3f(index, x, y, z);
  545. },
  546. VertexAttrib4f: (index, x, y, z, w) => {
  547. this.ctx.vertexAttrib4f(index, x, y, z, w);
  548. },
  549. VertexAttribPointer: (index, size, type, normalized, stride, ptr) => {
  550. this.ctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr);
  551. },
  552. Viewport: (x, y, w, h) => {
  553. this.ctx.viewport(x, y, w, h);
  554. },
  555. };
  556. }
  557. getWebGL2Interface() {
  558. return {
  559. /* Buffer objects */
  560. CopyBufferSubData: (readTarget, writeTarget, readOffset, writeOffset, size) => {
  561. this.assertWebGL2();
  562. this.ctx.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
  563. },
  564. GetBufferSubData: (target, srcByteOffset, dst_buffer_ptr, dst_buffer_len, dstOffset, length) => {
  565. this.assertWebGL2();
  566. this.ctx.getBufferSubData(target, srcByteOffset, this.mem.loadBytes(dst_buffer_ptr, dst_buffer_len), dstOffset, length);
  567. },
  568. /* Framebuffer objects */
  569. BlitFramebuffer: (srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) => {
  570. this.assertWebGL2();
  571. this.ctx.glitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
  572. },
  573. FramebufferTextureLayer: (target, attachment, texture, level, layer) => {
  574. this.assertWebGL2();
  575. this.ctx.framebufferTextureLayer(target, attachment, this.textures[texture], level, layer);
  576. },
  577. InvalidateFramebuffer: (target, attachments_ptr, attachments_len) => {
  578. this.assertWebGL2();
  579. let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
  580. this.ctx.invalidateFramebuffer(target, attachments);
  581. },
  582. InvalidateSubFramebuffer: (target, attachments_ptr, attachments_len, x, y, width, height) => {
  583. this.assertWebGL2();
  584. let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
  585. this.ctx.invalidateSubFramebuffer(target, attachments, x, y, width, height);
  586. },
  587. ReadBuffer: (src) => {
  588. this.assertWebGL2();
  589. this.ctx.readBuffer(src);
  590. },
  591. /* Renderbuffer objects */
  592. RenderbufferStorageMultisample: (target, samples, internalformat, width, height) => {
  593. this.assertWebGL2();
  594. this.ctx.renderbufferStorageMultisample(target, samples, internalformat, width, height);
  595. },
  596. /* Texture objects */
  597. TexStorage3D: (target, levels, internalformat, width, height, depth) => {
  598. this.assertWebGL2();
  599. this.ctx.texStorage3D(target, level, internalformat, width, heigh, depth);
  600. },
  601. TexImage3D: (target, level, internalformat, width, height, depth, border, format, type, size, data) => {
  602. this.assertWebGL2();
  603. if (data) {
  604. this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, this.mem.loadBytes(data, size));
  605. } else {
  606. this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, null);
  607. }
  608. },
  609. TexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, size, data) => {
  610. this.assertWebGL2();
  611. this.ctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, this.mem.loadBytes(data, size));
  612. },
  613. CompressedTexImage3D: (target, level, internalformat, width, height, depth, border, imageSize, data) => {
  614. this.assertWebGL2();
  615. if (data) {
  616. this.ctx.compressedTexImage3D(target, level, internalformat, width, height, depth, border, this.mem.loadBytes(data, imageSize));
  617. } else {
  618. this.ctx.compressedTexImage3D(target, level, internalformat, width, height, depth, border, null);
  619. }
  620. },
  621. CompressedTexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) => {
  622. this.assertWebGL2();
  623. if (data) {
  624. this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, this.mem.loadBytes(data, imageSize));
  625. } else {
  626. this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, null);
  627. }
  628. },
  629. CopyTexSubImage3D: (target, level, xoffset, yoffset, zoffset, x, y, width, height) => {
  630. this.assertWebGL2();
  631. this.ctx.copyTexImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
  632. },
  633. /* Programs and shaders */
  634. GetFragDataLocation: (program, name_ptr, name_len) => {
  635. this.assertWebGL2();
  636. return this.ctx.getFragDataLocation(this.programs[program], this.mem.loadString(name_ptr, name_len));
  637. },
  638. /* Uniforms */
  639. Uniform1ui: (location, v0) => {
  640. this.assertWebGL2();
  641. this.ctx.uniform1ui(this.uniforms[location], v0);
  642. },
  643. Uniform2ui: (location, v0, v1) => {
  644. this.assertWebGL2();
  645. this.ctx.uniform2ui(this.uniforms[location], v0, v1);
  646. },
  647. Uniform3ui: (location, v0, v1, v2) => {
  648. this.assertWebGL2();
  649. this.ctx.uniform3ui(this.uniforms[location], v0, v1, v2);
  650. },
  651. Uniform4ui: (location, v0, v1, v2, v3) => {
  652. this.assertWebGL2();
  653. this.ctx.uniform4ui(this.uniforms[location], v0, v1, v2, v3);
  654. },
  655. UniformMatrix3x2fv: (location, addr) => {
  656. this.assertWebGL2();
  657. let array = this.mem.loadF32Array(addr, 3*2);
  658. this.ctx.uniformMatrix3x2fv(this.uniforms[location], false, array);
  659. },
  660. UniformMatrix4x2fv: (location, addr) => {
  661. this.assertWebGL2();
  662. let array = this.mem.loadF32Array(addr, 4*2);
  663. this.ctx.uniformMatrix4x2fv(this.uniforms[location], false, array);
  664. },
  665. UniformMatrix2x3fv: (location, addr) => {
  666. this.assertWebGL2();
  667. let array = this.mem.loadF32Array(addr, 2*3);
  668. this.ctx.uniformMatrix2x3fv(this.uniforms[location], false, array);
  669. },
  670. UniformMatrix4x3fv: (location, addr) => {
  671. this.assertWebGL2();
  672. let array = this.mem.loadF32Array(addr, 4*3);
  673. this.ctx.uniformMatrix4x3fv(this.uniforms[location], false, array);
  674. },
  675. UniformMatrix2x4fv: (location, addr) => {
  676. this.assertWebGL2();
  677. let array = this.mem.loadF32Array(addr, 2*4);
  678. this.ctx.uniformMatrix2x4fv(this.uniforms[location], false, array);
  679. },
  680. UniformMatrix3x4fv: (location, addr) => {
  681. this.assertWebGL2();
  682. let array = this.mem.loadF32Array(addr, 3*4);
  683. this.ctx.uniformMatrix3x4fv(this.uniforms[location], false, array);
  684. },
  685. /* Vertex attribs */
  686. VertexAttribI4i: (index, x, y, z, w) => {
  687. this.assertWebGL2();
  688. this.ctx.vertexAttribI4i(index, x, y, z, w);
  689. },
  690. VertexAttribI4ui: (index, x, y, z, w) => {
  691. this.assertWebGL2();
  692. this.ctx.vertexAttribI4ui(index, x, y, z, w);
  693. },
  694. VertexAttribIPointer: (index, size, type, stride, offset) => {
  695. this.assertWebGL2();
  696. this.ctx.vertexAttribIPointer(index, size, type, stride, offset);
  697. },
  698. /* Writing to the drawing buffer */
  699. VertexAttribDivisor: (index, divisor) => {
  700. this.assertWebGL2();
  701. this.ctx.vertexAttribDivisor(index, divisor);
  702. },
  703. DrawArraysInstanced: (mode, first, count, instanceCount) => {
  704. this.assertWebGL2();
  705. this.ctx.drawArraysInstanced(mode, first, count, instanceCount);
  706. },
  707. DrawElementsInstanced: (mode, count, type, offset, instanceCount) => {
  708. this.assertWebGL2();
  709. this.ctx.drawElementsInstanced(mode, count, type, offset, instanceCount);
  710. },
  711. DrawRangeElements: (mode, start, end, count, type, offset) => {
  712. this.assertWebGL2();
  713. this.ctx.drawRangeElements(mode, start, end, count, type, offset);
  714. },
  715. /* Multiple Render Targets */
  716. DrawBuffers: (buffers_ptr, buffers_len) => {
  717. this.assertWebGL2();
  718. let array = this.mem.loadU32Array(buffers_ptr, buffers_len);
  719. this.ctx.drawBuffers(array);
  720. },
  721. ClearBufferfv: (buffer, drawbuffer, values_ptr, values_len) => {
  722. this.assertWebGL2();
  723. let array = this.mem.loadF32Array(values_ptr, values_len);
  724. this.ctx.clearBufferfv(buffer, drawbuffer, array);
  725. },
  726. ClearBufferiv: (buffer, drawbuffer, values_ptr, values_len) => {
  727. this.assertWebGL2();
  728. let array = this.mem.loadI32Array(values_ptr, values_len);
  729. this.ctx.clearBufferiv(buffer, drawbuffer, array);
  730. },
  731. ClearBufferuiv: (buffer, drawbuffer, values_ptr, values_len) => {
  732. this.assertWebGL2();
  733. let array = this.mem.loadU32Array(values_ptr, values_len);
  734. this.ctx.clearBufferuiv(buffer, drawbuffer, array);
  735. },
  736. ClearBufferfi: (buffer, drawbuffer, depth, stencil) => {
  737. this.assertWebGL2();
  738. this.ctx.clearBufferfi(buffer, drawbuffer, depth, stencil);
  739. },
  740. /* Query Objects */
  741. CreateQuery: () => {
  742. this.assertWebGL2();
  743. let query = this.ctx.createQuery();
  744. let id = this.getNewId(this.queries);
  745. query.name = id;
  746. this.queries[id] = query;
  747. return id;
  748. },
  749. DeleteQuery: (id) => {
  750. this.assertWebGL2();
  751. let obj = this.querys[id];
  752. if (obj && id != 0) {
  753. this.ctx.deleteQuery(obj);
  754. this.querys[id] = null;
  755. }
  756. },
  757. IsQuery: (query) => {
  758. this.assertWebGL2();
  759. return this.ctx.isQuery(this.queries[query]);
  760. },
  761. BeginQuery: (target, query) => {
  762. this.assertWebGL2();
  763. this.ctx.beginQuery(target, this.queries[query])
  764. },
  765. EndQuery: (target) => {
  766. this.assertWebGL2();
  767. this.ctx.endQuery(target);
  768. },
  769. GetQuery: (target, pname) => {
  770. this.assertWebGL2();
  771. let query = this.ctx.getQuery(target, pname);
  772. if (!query) {
  773. return 0;
  774. }
  775. if (this.queries.indexOf(query) !== -1) {
  776. return query.name;
  777. }
  778. let id = this.getNewId(this.queries);
  779. query.name = id;
  780. this.queries[id] = query;
  781. return id;
  782. },
  783. /* Sampler Objects */
  784. CreateSampler: () => {
  785. this.assertWebGL2();
  786. let sampler = this.ctx.createSampler();
  787. let id = this.getNewId(this.samplers);
  788. sampler.name = id;
  789. this.samplers[id] = sampler;
  790. return id;
  791. },
  792. DeleteSampler: (id) => {
  793. this.assertWebGL2();
  794. let obj = this.samplers[id];
  795. if (obj && id != 0) {
  796. this.ctx.deleteSampler(obj);
  797. this.samplers[id] = null;
  798. }
  799. },
  800. IsSampler: (sampler) => {
  801. this.assertWebGL2();
  802. return this.ctx.isSampler(this.samplers[sampler]);
  803. },
  804. BindSampler: (unit, sampler) => {
  805. this.assertWebGL2();
  806. this.ctx.bindSampler(unit, this.samplers[Sampler]);
  807. },
  808. SamplerParameteri: (sampler, pname, param) => {
  809. this.assertWebGL2();
  810. this.ctx.samplerParameteri(this.samplers[sampler], pname, param);
  811. },
  812. SamplerParameterf: (sampler, pname, param) => {
  813. this.assertWebGL2();
  814. this.ctx.samplerParameterf(this.samplers[sampler], pname, param);
  815. },
  816. /* Sync objects */
  817. FenceSync: (condition, flags) => {
  818. this.assertWebGL2();
  819. let sync = this.ctx.fenceSync(condition, flags);
  820. let id = this.getNewId(this.syncs);
  821. sync.name = id;
  822. this.syncs[id] = sync;
  823. return id;
  824. },
  825. IsSync: (sync) => {
  826. this.assertWebGL2();
  827. return this.ctx.isSync(this.syncs[sync]);
  828. },
  829. DeleteSync: (id) => {
  830. this.assertWebGL2();
  831. let obj = this.syncs[id];
  832. if (obj && id != 0) {
  833. this.ctx.deleteSampler(obj);
  834. this.syncs[id] = null;
  835. }
  836. },
  837. ClientWaitSync: (sync, flags, timeout) => {
  838. this.assertWebGL2();
  839. return this.ctx.clientWaitSync(this.syncs[sync], flags, timeout);
  840. },
  841. WaitSync: (sync, flags, timeout) => {
  842. this.assertWebGL2();
  843. this.ctx.waitSync(this.syncs[sync], flags, timeout) ;
  844. },
  845. /* Transform Feedback */
  846. CreateTransformFeedback: () => {
  847. this.assertWebGL2();
  848. let transformFeedback = this.ctx.createtransformFeedback();
  849. let id = this.getNewId(this.transformFeedbacks);
  850. transformFeedback.name = id;
  851. this.transformFeedbacks[id] = transformFeedback;
  852. return id;
  853. },
  854. DeleteTransformFeedback: (id) => {
  855. this.assertWebGL2();
  856. let obj = this.transformFeedbacks[id];
  857. if (obj && id != 0) {
  858. this.ctx.deleteTransformFeedback(obj);
  859. this.transformFeedbacks[id] = null;
  860. }
  861. },
  862. IsTransformFeedback: (tf) => {
  863. this.assertWebGL2();
  864. return this.ctx.isTransformFeedback(this.transformFeedbacks[tf]);
  865. },
  866. BindTransformFeedback: (target, tf) => {
  867. this.assertWebGL2();
  868. this.ctx.bindTransformFeedback(target, this.transformFeedbacks[tf]);
  869. },
  870. BeginTransformFeedback: (primitiveMode) => {
  871. this.assertWebGL2();
  872. this.ctx.beginTransformFeedback(primitiveMode);
  873. },
  874. EndTransformFeedback: () => {
  875. this.assertWebGL2();
  876. this.ctx.endTransformFeedback();
  877. },
  878. TransformFeedbackVaryings: (program, varyings_ptr, varyings_len, bufferMode) => {
  879. this.assertWebGL2();
  880. let varyings = [];
  881. for (let i = 0; i < varyings_len; i++) {
  882. let ptr = this.mem.loadPtr(varyings_ptr + i*STRING_SIZE + 0*4);
  883. let len = this.mem.loadPtr(varyings_ptr + i*STRING_SIZE + 1*4);
  884. varyings.push(this.mem.loadString(ptr, len));
  885. }
  886. this.ctx.transformFeedbackVaryings(this.programs[program], varyings, bufferMode);
  887. },
  888. PauseTransformFeedback: () => {
  889. this.assertWebGL2();
  890. this.ctx.pauseTransformFeedback();
  891. },
  892. ResumeTransformFeedback: () => {
  893. this.assertWebGL2();
  894. this.ctx.resumeTransformFeedback();
  895. },
  896. /* Uniform Buffer Objects and Transform Feedback Buffers */
  897. BindBufferBase: (target, index, buffer) => {
  898. this.assertWebGL2();
  899. this.ctx.bindBufferBase(target, index, this.buffers[buffer]);
  900. },
  901. BindBufferRange: (target, index, buffer, offset, size) => {
  902. this.assertWebGL2();
  903. this.ctx.bindBufferRange(target, index, this.buffers[buffer], offset, size);
  904. },
  905. GetUniformBlockIndex: (program, uniformBlockName_ptr, uniformBlockName_len) => {
  906. this.assertWebGL2();
  907. return this.ctx.getUniformBlockIndex(this.programs[program], this.mem.loadString(uniformBlockName_ptr, uniformBlockName_len));
  908. },
  909. // any getActiveUniformBlockParameter(WebGLProgram program, GLuint uniformBlockIndex, GLenum pname);
  910. GetActiveUniformBlockName: (program, uniformBlockIndex, buf_ptr, buf_len, length_ptr) => {
  911. this.assertWebGL2();
  912. let name = this.ctx.getActiveUniformBlockName(this.programs[program], uniformBlockIndex);
  913. let n = Math.min(buf_len, name.length);
  914. name = name.substring(0, n);
  915. this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(name))
  916. this.mem.storeInt(length_ptr, n);
  917. },
  918. UniformBlockBinding: (program, uniformBlockIndex, uniformBlockBinding) => {
  919. this.assertWebGL2();
  920. this.ctx.uniformBlockBinding(this.programs[program], uniformBlockIndex, uniformBlockBinding);
  921. },
  922. /* Vertex Array Objects */
  923. CreateVertexArray: () => {
  924. this.assertWebGL2();
  925. let vao = this.ctx.createVertexArray();
  926. let id = this.getNewId(this.vaos);
  927. vao.name = id;
  928. this.vaos[id] = vao;
  929. return id;
  930. },
  931. DeleteVertexArray: (id) => {
  932. this.assertWebGL2();
  933. let obj = this.vaos[id];
  934. if (obj && id != 0) {
  935. this.ctx.deleteVertexArray(obj);
  936. this.vaos[id] = null;
  937. }
  938. },
  939. IsVertexArray: (vertexArray) => {
  940. this.assertWebGL2();
  941. return this.ctx.isVertexArray(this.vaos[vertexArray]);
  942. },
  943. BindVertexArray: (vertexArray) => {
  944. this.assertWebGL2();
  945. this.ctx.bindVertexArray(this.vaos[vertexArray]);
  946. },
  947. };
  948. }
  949. };
  950. export {WebGLInterface};