]> zoso.dev Git - libnemo.git/commitdiff
Get query version working by storing and reading the entire canvas as before, probabl...
authorChris Duncan <chris@zoso.dev>
Wed, 18 Dec 2024 16:42:15 +0000 (08:42 -0800)
committerChris Duncan <chris@zoso.dev>
Wed, 18 Dec 2024 16:42:15 +0000 (08:42 -0800)
src/lib/workers/pow.ts

index 3a6e359fe4748f48b9ab48b2594dcc9fcbe8cded..d3c34c1e80ca887cd2272c7e369899f6ca1541f7 100644 (file)
@@ -24,6 +24,7 @@ export class Pow {
        */
        // Vertex Shader
        static #vsSource = `#version 300 es
+#pragma vscode_glsllint_stage: vert
 precision highp float;
 layout (location=0) in vec4 position;
 layout (location=1) in vec2 uv;
@@ -37,6 +38,7 @@ void main() {
 
        // Fragment shader
        static #fsSource = `#version 300 es
+#pragma vscode_glsllint_stage: frag
 precision highp float;
 precision highp int;
 
@@ -189,20 +191,20 @@ void main() {
 
        // Pixel data is multipled by threshold test result (0 or 1)
        // First 4 bytes insignificant, only calculate digest of second 4 bytes
-       fragColor = mix(
-               fragColor,
-               vec4(
+       if ((BLAKE2B_IV32_1 ^ v[1] ^ v[17]) > threshold) {
+               fragColor = vec4(
                        float(x_index + 1u)/255., // +1 to distinguish from 0 (unsuccessful) pixels
                        float(y_index + 1u)/255., // Same as previous
                        float(x_pos)/255., // Return the 2 custom bytes used in work value
                        float(y_pos)/255.  // Second custom byte
-               ),
-               float((BLAKE2B_IV32_1 ^ v[1] ^ v[17]) > threshold)
-       );
+               );
+       } else {
+               discard;
+       }
 }`
 
        /** Used to set canvas size. Must be a multiple of 256. */
-       static #WORKLOAD: number = 256 * Math.max(1, Math.floor(navigator.hardwareConcurrency / 2))
+       static #WORKLOAD: number = 256 * Math.max(1, Math.floor(navigator.hardwareConcurrency))
 
        static #hexify (arr: number[] | Uint8Array): string {
                let out = ''
@@ -223,6 +225,9 @@ void main() {
        static #fragmentShader: WebGLShader | null
        static #positionBuffer: WebGLBuffer | null
        static #uvBuffer: WebGLBuffer | null
+       static #frameBuffer: WebGLFramebuffer | null
+       static #renderBuffer: WebGLRenderbuffer | null
+       static #query: WebGLQuery | null
        static #pixels: Uint8Array
        // Vertex Positions, 2 triangles
        static #positions = new Float32Array([
@@ -280,12 +285,28 @@ void main() {
                this.#gl.vertexAttribPointer(1, 2, this.#gl.FLOAT, false, 0, 0)
                this.#gl.enableVertexAttribArray(1)
 
+               this.#frameBuffer = this.#gl.createFramebuffer()
+               this.#gl.bindFramebuffer(this.#gl.FRAMEBUFFER, this.#frameBuffer)
+               this.#renderBuffer = this.#gl.createRenderbuffer()
+               this.#gl.bindRenderbuffer(this.#gl.RENDERBUFFER, this.#renderBuffer)
+               this.#gl.renderbufferStorage(this.#gl.RENDERBUFFER, this.#gl.RGBA8, this.#gl.drawingBufferWidth, this.#gl.drawingBufferHeight)
+               this.#gl.framebufferRenderbuffer(this.#gl.FRAMEBUFFER, this.#gl.COLOR_ATTACHMENT0, this.#gl.RENDERBUFFER, this.#renderBuffer)
+               if (this.#gl.checkFramebufferStatus(this.#gl.FRAMEBUFFER) !== this.#gl.FRAMEBUFFER_COMPLETE) {
+                       throw new Error('Framebuffer is not complete')
+               }
+               // this.#gl.viewport(0, 0, 1, 1)
+               // this.#pixels = new Uint8Array(4)
+               this.#pixels = new Uint8Array(this.#gl.drawingBufferWidth * this.#gl.drawingBufferHeight * 4)
+               this.#query = this.#gl.createQuery()
+               if (this.#query == null) {
+                       throw new Error('Failed to create query')
+               }
+
                this.#work0Location = this.#gl.getUniformLocation(this.#program, 'u_work0')
                this.#work1Location = this.#gl.getUniformLocation(this.#program, 'u_work1')
                this.#blockHashLocation = this.#gl.getUniformLocation(this.#program, "blockHash")
                this.#thresholdLocation = this.#gl.getUniformLocation(this.#program, "threshold")
                this.#workloadLocation = this.#gl.getUniformLocation(this.#program, "workload")
-               this.#pixels = new Uint8Array(this.#gl.drawingBufferWidth * this.#gl.drawingBufferHeight * 4)
        }
 
        static #calculate (hashHex: string, callback: (nonce: string | PromiseLike<string>) => any, threshold: number): void {
@@ -309,9 +330,11 @@ void main() {
                const draw = (): void => {
                        n++
                        if (Pow.#gl == null) throw new Error('WebGL 2 is required')
+                       if (Pow.#query == null) throw new Error('WebGL 2 is required to run queries')
                        performance.mark('start')
                        crypto.getRandomValues(work0)
                        crypto.getRandomValues(work1)
+                       Pow.#gl.clear(Pow.#gl.COLOR_BUFFER_BIT)
 
                        Pow.#gl.uniform4uiv(Pow.#work0Location, work0)
                        Pow.#gl.uniform4uiv(Pow.#work1Location, work1)
@@ -319,8 +342,35 @@ void main() {
                        Pow.#gl.uniform1ui(Pow.#thresholdLocation, threshold)
                        Pow.#gl.uniform1f(Pow.#workloadLocation, Pow.#WORKLOAD - 1)
 
-                       Pow.#gl.clear(Pow.#gl.COLOR_BUFFER_BIT)
+                       Pow.#gl.beginQuery(Pow.#gl.ANY_SAMPLES_PASSED_CONSERVATIVE, Pow.#query)
                        Pow.#gl.drawArrays(Pow.#gl.TRIANGLES, 0, 6)
+                       Pow.#gl.endQuery(Pow.#gl.ANY_SAMPLES_PASSED_CONSERVATIVE)
+
+                       requestAnimationFrame(checkQueryResult)
+               }
+
+               function checkQueryResult () {
+                       if (Pow.#gl == null) throw new Error('WebGL 2 is required to check query results')
+                       if (Pow.#query == null) throw new Error('Query not found')
+                       if (Pow.#gl.getQueryParameter(Pow.#query, Pow.#gl.QUERY_RESULT_AVAILABLE)) {
+                               const anySamplesPassed = Pow.#gl.getQueryParameter(Pow.#query, Pow.#gl.QUERY_RESULT)
+                               if (anySamplesPassed) {
+                                       // A valid nonce was found
+                                       readBackResult()
+                               } else {
+                                       performance.mark('end')
+                                       frameTimes.push(performance.measure('draw', 'start', 'end').duration)
+                                       performance.clearMarks()
+                                       // No valid nonce found, start the next draw call
+                                       requestAnimationFrame(draw)
+                               }
+                       } else {
+                               // Query result not yet available, check again in the next frame
+                               requestAnimationFrame(checkQueryResult)
+                       }
+               }
+               function readBackResult () {
+                       if (Pow.#gl == null) throw new Error('WebGL 2 is required to check read results')
                        Pow.#gl.readPixels(0, 0, Pow.#gl.drawingBufferWidth, Pow.#gl.drawingBufferHeight, Pow.#gl.RGBA, Pow.#gl.UNSIGNED_BYTE, Pow.#pixels)
                        // Check the pixels for any success
                        for (let i = 0; i < Pow.#pixels.length; i += 4) {
@@ -330,7 +380,7 @@ void main() {
                                        performance.clearMarks()
                                        console.log(`average frame time: ${(frameTimes.reduce((a, b) => a + b)) / frameTimes.length} ms`)
                                        console.log(`frames calculated: ${n}`)
-                                       const hex = this.#hexify(work1) + this.#hexify([
+                                       const hex = Pow.#hexify(work1) + Pow.#hexify([
                                                Pow.#pixels[i + 2],
                                                Pow.#pixels[i + 3],
                                                work0[2] ^ (Pow.#pixels[i] - 1),
@@ -341,15 +391,8 @@ void main() {
                                        return
                                }
                        }
-                       performance.mark('end')
-                       frameTimes.push(performance.measure('draw', 'start', 'end').duration)
-                       performance.clearMarks()
-                       // Nothing found yet, try again
-                       self.requestAnimationFrame(draw)
                }
-
-               // Begin generation
-               self.requestAnimationFrame(draw)
+               draw()
        }
 }