Home Reference Source

cables_dev/cables/src/core/cgp/cgp_binding.js

  1. import { Logger } from "cables-shared-client";
  2. import GPUBuffer from "./cgp_gpubuffer.js";
  3.  
  4. export default class Binding
  5. {
  6. /**
  7. * Description
  8. * @param {any} cgp
  9. * @param {any} idx
  10. * @param {string} name
  11. * @param {any} options={}
  12. */
  13. constructor(cgp, name, options = {})
  14. {
  15. if (typeof options != "object") this._log.error("binding options is not an object");
  16. this._index = -1;
  17.  
  18. this._name = name;
  19. this._cgp = cgp;
  20. this._log = new Logger("cgp_binding");
  21. this.uniforms = [];
  22. this.cGpuBuffers = [];
  23. this._options = options;
  24. this.shader = null;
  25. this.bindingInstances = [];
  26. this.stageStr = options.stage;
  27. this.bindingType = options.bindingType || "uniform"; // "uniform", "storage", "read-only-storage",
  28.  
  29. if (this.stageStr == "frag") this.stage = GPUShaderStage.FRAGMENT;
  30. else this.stage = GPUShaderStage.VERTEX;
  31. if (options.hasOwnProperty("index")) this._index = options.index;
  32.  
  33. if (options.shader) this.shader = options.shader;
  34.  
  35. this._buffer = null;
  36. this.isValid = true;
  37. this.changed = 0;
  38.  
  39. if (this.shader)
  40. {
  41. if (this.stageStr == "frag") this.shader.bindingsFrag.push(this);
  42. if (this.stageStr == "vert") this.shader.bindingsVert.push(this);
  43. if (this._index == -1) this._index = this.shader.getNewBindingIndex();
  44. }
  45.  
  46. if (this._index == -1) this._log.warn("binding could not get an index", this._name);
  47.  
  48. this._cgp.on("deviceChange", () =>
  49. {
  50. // this.reInit();
  51. });
  52. }
  53.  
  54. isStruct()
  55. {
  56. if (this.uniforms.length == 0) return false;
  57.  
  58. if (this.uniforms.length == 1)
  59. {
  60. if (this.uniforms[0].type == "t" || this.uniforms[0].type == "sampler") return false;
  61. if (this.bindingType != "uniform") return false;
  62. }
  63.  
  64. return true;
  65. }
  66.  
  67. copy(newShader)
  68. {
  69. console.log("copy binding...");
  70. const options = {};
  71.  
  72. for (const i in this._options)
  73. options[i] = this._options[i];
  74.  
  75. options.shader = newShader;
  76.  
  77. let binding = new Binding(this._cgp, this._name, options);
  78.  
  79. for (let i = 0; i < this.uniforms.length; i++)
  80. {
  81. binding.addUniform(newShader.getUniform(this.uniforms[i].name)); // .copy(newShader)
  82. }
  83.  
  84.  
  85.  
  86.  
  87. return binding;
  88. }
  89.  
  90. addUniform(uni)
  91. {
  92. this.uniforms.push(uni);
  93. }
  94.  
  95. getSizeBytes()
  96. {
  97. let size = 0;
  98. for (let i = 0; i < this.uniforms.length; i++)
  99. {
  100. // console.log("UNIFORM!!!", i, this.uniforms[i], this.uniforms[i].getSizeBytes());
  101. // console.log("getSizeBytes", this.uniforms[i], this.uniforms[i].getSizeBytes);
  102. size += this.uniforms[i].getSizeBytes();
  103. }
  104. // if (this.uniforms.length == 0)console.log("NO UNIFORMS!!!");
  105. return size;
  106. }
  107.  
  108. getShaderHeaderCode()
  109. {
  110. let str = "";
  111.  
  112. let typeStr = "strct_" + this._name;
  113. let name = this._name;
  114.  
  115. if (this.uniforms.length === 0) return "// no uniforms in bindinggroup...?\n";
  116.  
  117.  
  118. str += "// " + this.uniforms.length + " uniforms\n";
  119.  
  120. if (this.isStruct())
  121. {
  122. str += "struct " + typeStr + "\n";
  123. str += "{\n";
  124. for (let i = 0; i < this.uniforms.length; i++)
  125. {
  126. str += " " + this.uniforms[i].name + ": " + this.uniforms[i].getWgslTypeStr();
  127. if (i != this.uniforms.length - 1)str += ",";
  128. str += "\n";
  129. }
  130. str += "};\n";
  131. }
  132. else
  133. {
  134. typeStr = this.uniforms[0].getWgslTypeStr();
  135. name = this.uniforms[0].name;
  136. }
  137.  
  138. str += "@group(0) ";
  139. str += "@binding(" + this._index + ") ";
  140.  
  141. if (this.isStruct())
  142. {
  143. str += "var<" + this.bindingType + "> ";
  144. }
  145. else if (this.bindingType == "read-only-storage")str += "var<storage,read> ";
  146. else str += "var ";
  147.  
  148. str += name + ": " + typeStr + ";\n";
  149.  
  150. return str;
  151. }
  152.  
  153.  
  154. getBindingGroupLayoutEntry()
  155. {
  156. let label = "layout " + this._name + " [";
  157. for (let i = 0; i < this.uniforms.length; i++) label += this.uniforms[i].getName() + ",";
  158. label += "]";
  159.  
  160. const o = {
  161. "label": label,
  162. "binding": this._index,
  163. "visibility": this.stage,
  164. "size": this.getSizeBytes()
  165. };
  166.  
  167. if (this.uniforms.length == 1 && this.uniforms[0].getType() == "t")
  168. {
  169. o.texture = {};
  170. }
  171. else if (this.uniforms.length == 1 && this.uniforms[0].getType() == "sampler")
  172. {
  173. o.sampler = {};
  174. }
  175. else
  176. {
  177. o.buffer = {};
  178. o.buffer.type = this.bindingType;
  179. }
  180.  
  181. return o;
  182. }
  183.  
  184. getBindingGroupEntry(gpuDevice, inst)
  185. {
  186. this.isValid = false;
  187.  
  188. const o = {
  189. "label": this._name + " binding",
  190. "binding": this._index,
  191. "size": this.getSizeBytes(),
  192. "visibility": this.stage,
  193. };
  194.  
  195. if (this.uniforms.length == 0)
  196. {
  197. console.log("binding uniforms length 0");
  198. return;
  199. }
  200.  
  201. if (this.uniforms.length == 1 && this.uniforms[0].getType() == "t")
  202. {
  203. if (this.uniforms[0].getValue() && this.uniforms[0].getValue().gpuTexture) o.resource = this.uniforms[0].getValue().gpuTexture.createView();
  204. else o.resource = this._cgp.getEmptyTexture().createView();// CABLES.emptyCglTexture.createView();
  205. }
  206. else if (this.uniforms.length == 1 && this.uniforms[0].getType() == "sampler")
  207. {
  208. let smplDesc = {
  209. "addressModeU": "mirror-repeat",
  210. "addressModeV": "mirror-repeat",
  211. "magFilter": "linear",
  212. "minFilter": "linear",
  213. "mipmapFilter": "linear",
  214. };
  215.  
  216. if (this.uniforms[0].getValue()) smplDesc = this.uniforms[0].getValue().getSampler();
  217.  
  218. const sampler = this.uniforms[0]._cgp.device.createSampler(smplDesc);
  219. o.resource = sampler;
  220. }
  221. else
  222. {
  223. this._createCgpuBuffer(inst);
  224.  
  225. o.resource = {
  226. "buffer": this.cGpuBuffers[inst].gpuBuffer,
  227. "minBindingSize": this.getSizeBytes(),
  228. "hasDynamicOffset": 0
  229. };
  230. }
  231.  
  232. this.isValid = true;
  233. this.bindingInstances[inst] = o;
  234.  
  235. return o;
  236. }
  237.  
  238. _createCgpuBuffer(inst)
  239. {
  240. let buffCfg = {
  241. "label": this._name,
  242. "size": this.getSizeBytes(),
  243. "usage": GPUBufferUsage.COPY_DST | GPUBufferUsage.UNIFORM,
  244. };
  245.  
  246. if (this.bindingType == "read-only-storage" || this.bindingType == "storage") buffCfg.usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;
  247.  
  248. if (this.cGpuBuffers[inst]) this.cGpuBuffers[inst].dispose();
  249. this.cGpuBuffers[inst] = new GPUBuffer(this._cgp, this._name + " buff", null, { "buffCfg": buffCfg });
  250.  
  251. if (this.uniforms.length > 0 && this.uniforms[0].gpuBuffer) this.cGpuBuffers[inst] = this.uniforms[0].gpuBuffer;
  252. }
  253.  
  254.  
  255.  
  256. update(cgp, inst)
  257. {
  258. let b = this.bindingInstances[inst];
  259. if (!b) b = this.getBindingGroupEntry(cgp.device, inst);
  260.  
  261. if (this.uniforms.length == 1 && this.uniforms[0].gpuBuffer)
  262. {
  263. if (this.uniforms[0].gpuBuffer != this.cGpuBuffers[inst])
  264. {
  265. console.log("changed?!");
  266. this.shader._needsRecompile = true; // TODO this should actually just rebuild the bindinggroup i guess ?
  267. }
  268.  
  269. if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("extern uni bind", [this.uniforms[0].getName(), this.cGpuBuffers[inst].floatArr]);
  270. if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();
  271. }
  272. else
  273. if (this.uniforms.length == 1 && this.uniforms[0].getType() == "t")
  274. {
  275. if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("uni texture");
  276. if (this.uniforms[0].getValue())
  277. if (this.uniforms[0].getValue().gpuTexture)
  278. {
  279. this.bindingInstances[inst] = this.getBindingGroupEntry(this.uniforms[0]._cgp.device, inst);
  280. }
  281. else
  282. {
  283. console.log("uni t has no gputexture");
  284. b.resource = this._cgp.getErrorTexture().createView();
  285. }
  286.  
  287. if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();
  288. }
  289. else if (this.uniforms.length == 1 && this.uniforms[0].getType() == "sampler")
  290. {
  291. if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("uni sampler");
  292. b.resource = this.uniforms[0].getValue();
  293. if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();
  294. }
  295. else
  296. {
  297. let info = ["stage " + this.stageStr + " / inst " + inst];
  298.  
  299. // console.log("B",this.);
  300. // update uniform values to buffer
  301. const s = this.getSizeBytes() / 4;
  302.  
  303. // if (!this.cGpuBuffers[inst])
  304. // this._createCgpuBuffer(inst);
  305. // this.cGpuBuffers[inst] = new GPUBuffer(this._cgp, "buff", null, { "buffCfg": buffCfg });
  306.  
  307. this.cGpuBuffers[inst].setLength(s);
  308.  
  309. let off = 0;
  310. for (let i = 0; i < this.uniforms.length; i++)
  311. {
  312. info.push(this.uniforms[i].getName() + " " + this.uniforms[i].getValue());
  313. this.uniforms[i].copyToBuffer(this.cGpuBuffers[inst].floatArr, off); // todo: check if uniform changed?
  314.  
  315. // if (isNaN(this.cGpuBuffers[inst].floatArr[0]))
  316. // {
  317. // console.log("shitttttttt", this.cGpuBuffers[inst].floatArr[0], this.uniforms[i].getName(), this.cGpuBuffers[inst].name, this.uniforms[i]);
  318. // }
  319.  
  320. off += this.uniforms[i].getSizeBytes() / 4;
  321. }
  322. if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("uni buff", info);
  323.  
  324. // console.log("upodate", inst);
  325.  
  326. this.cGpuBuffers[inst].updateGpuBuffer();
  327. // todo: only if changed...
  328. // cgp.device.queue.writeBuffer(
  329. // b.resource.buffer,
  330. // 0,
  331. // this._buffer.buffer,
  332. // this._buffer.byteOffset,
  333. // this._buffer.byteLength
  334. // );
  335.  
  336. if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();
  337. }
  338. }
  339. }