From 9454d1a11ae392215ebe126b5f69e030dadae7fb Mon Sep 17 00:00:00 2001 From: Ben Richards Date: Tue, 30 Jul 2024 18:09:56 +1200 Subject: [PATCH] Rearrange shader attribute connection. The VertexBuffer doesn't need to know about the Program to complete its internal layout. But the VAO does need data from the Program to connect attributes. So completion logic has been moved from Program to VertexBuffer, and connection logic has been moved from Program to VAO. --- src/renderer/webgl/WebGLRenderer.js | 5 +- .../webgl/renderNodes/BatchHandler.js | 3 +- .../webgl/wrappers/WebGLProgramWrapper.js | 68 ------------------ .../webgl/wrappers/WebGLVAOWrapper.js | 27 ++++++- .../WebGLVertexBufferLayoutWrapper.js | 70 +++++++++++++++---- 5 files changed, 88 insertions(+), 85 deletions(-) diff --git a/src/renderer/webgl/WebGLRenderer.js b/src/renderer/webgl/WebGLRenderer.js index 74373d75a..cfc6dfa4f 100644 --- a/src/renderer/webgl/WebGLRenderer.js +++ b/src/renderer/webgl/WebGLRenderer.js @@ -2523,12 +2523,13 @@ var WebGLRenderer = new Class({ * * @method Phaser.Renderer.WebGL.WebGLRenderer#createVAO * @since 3.90.0 + * @param {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper} program - The program to bind the VAO to. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper} indexBuffer - The index buffer. * @param {Phaser.Types.Renderer.WebGL.WebGLAttributeBufferLayout[]} attributeBufferLayouts - The attribute buffer layouts. */ - createVAO: function (indexBuffer, attributeBufferLayouts) + createVAO: function (program, indexBuffer, attributeBufferLayouts) { - var vao = new WebGLVAOWrapper(this, indexBuffer, attributeBufferLayouts); + var vao = new WebGLVAOWrapper(this, program, indexBuffer, attributeBufferLayouts); this.glVAOWrappers.push(vao); return vao; }, diff --git a/src/renderer/webgl/renderNodes/BatchHandler.js b/src/renderer/webgl/renderNodes/BatchHandler.js index e34344257..bdcbc1ba3 100644 --- a/src/renderer/webgl/renderNodes/BatchHandler.js +++ b/src/renderer/webgl/renderNodes/BatchHandler.js @@ -187,7 +187,6 @@ var BatchHandler = new Class({ */ this.vertexBufferLayout = new WebGLVertexBufferLayoutWrapper( renderer, - this.program, partialLayout, config.createOwnVertexBuffer ? null : renderer.genericVertexBuffer ); @@ -199,7 +198,7 @@ var BatchHandler = new Class({ * @type {Phaser.Renderer.WebGL.Wrappers.WebGLVAOWrapper} * @since 3.90.0 */ - this.vao = renderer.createVAO(this.indexBuffer, [ + this.vao = renderer.createVAO(this.program, this.indexBuffer, [ this.vertexBufferLayout ]); diff --git a/src/renderer/webgl/wrappers/WebGLProgramWrapper.js b/src/renderer/webgl/wrappers/WebGLProgramWrapper.js index 22b58dd4a..2db8cc8b4 100644 --- a/src/renderer/webgl/wrappers/WebGLProgramWrapper.js +++ b/src/renderer/webgl/wrappers/WebGLProgramWrapper.js @@ -315,74 +315,6 @@ var WebGLProgramWrapper = new Class({ this.uniformRequests.set(name, value); }, - /** - * Complete the layout of the provided attribute buffer layout. - * This will fill in the stride, locations, byte counts, and offsets. - * In addition, it will convert any GLenums specified as strings - * to their numeric values. - * This mutates the layout. - * - * The order of attributes within the layout forms the order of the buffer. - * - * This is necessary to connect the attributes to the buffer. - * - * @method Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#completeLayout - * @since 3.90.0 - * @param {Phaser.Types.Renderer.WebGL.WebGLAttributeBufferLayout} attributeBufferLayout - The layout to complete. - */ - completeLayout: function (attributeBufferLayout) - { - var gl = this.renderer.gl; - var layout = attributeBufferLayout.layout; - var glAttributes = this.glAttributes; - var glAttributeNames = this.glAttributeNames; - var constants = this.renderer.shaderSetters.constants; - - if (typeof attributeBufferLayout.usage === 'string') - { - attributeBufferLayout.usage = gl[attributeBufferLayout.usage]; - } - - var offset = 0; - - for (var i = 0; i < layout.length; i++) - { - var attribute = layout[i]; - var size = attribute.size; - var columns = attribute.columns || 1; - - // First, append the current offset. - attribute.offset = offset; - - // Convert the type to a GLenum if it is a string. - if (typeof attribute.type === 'string') - { - attribute.type = gl[attribute.type]; - } - - var typeData = constants[attribute.type]; - var baseSize = typeData.size; - var baseBytes = typeData.bytes; - - // Append the bytes per attribute element. - attribute.bytes = baseBytes; - - offset += size * columns * baseBytes * baseSize; - - // Assign attribute location. - var attributeIndex = glAttributeNames.get(attribute.name); - if (attributeIndex === undefined) - { - throw new Error('Attribute not found: ' + attribute.name); - } - var attributeInfo = glAttributes[attributeIndex]; - attribute.location = attributeInfo.location; - } - - // Now that we know the total stride, we can set it. - attributeBufferLayout.stride = offset; - }, - /** * Set this program as the active program in the WebGL context. * diff --git a/src/renderer/webgl/wrappers/WebGLVAOWrapper.js b/src/renderer/webgl/wrappers/WebGLVAOWrapper.js index 392ec2f4b..84ba0f314 100644 --- a/src/renderer/webgl/wrappers/WebGLVAOWrapper.js +++ b/src/renderer/webgl/wrappers/WebGLVAOWrapper.js @@ -19,11 +19,12 @@ var Class = require('../../../utils/Class'); * @constructor * @since 3.90.0 * @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - The WebGLRenderer instance that owns this wrapper. + * @param {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper} program - The shader program that this VAO is associated with. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper} [indexBuffer] - The index buffer used in this VAO, if any. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLVertexBufferLayoutWrapper[]} attributeBufferLayouts - The vertex buffers containing attribute data for this VAO, alongside the relevant attribute layout. */ var WebGLVAOWrapper = new Class({ - initialize: function WebGLVAOWrapper (renderer, indexBuffer, attributeBufferLayouts) + initialize: function WebGLVAOWrapper (renderer, program, indexBuffer, attributeBufferLayouts) { /** * The WebGLRenderer instance that owns this wrapper. @@ -34,6 +35,15 @@ var WebGLVAOWrapper = new Class({ */ this.renderer = renderer; + /** + * The shader program that this VAO is associated with. + * + * @name Phaser.Renderer.WebGL.Wrappers.WebGLVAOWrapper#program + * @type {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper} + * @since 3.90.0 + */ + this.program = program; + /** * The WebGLVertexArrayObject being wrapped by this class. * @@ -113,6 +123,10 @@ var WebGLVAOWrapper = new Class({ this.indexBuffer.bind(); } + var program = this.program; + var glAttributes = program.glAttributes; + var glAttributeNames = program.glAttributeNames; + for (var i = 0; i < this.attributeBufferLayouts.length; i++) { var attributeBufferLayout = this.attributeBufferLayouts[i]; @@ -125,6 +139,17 @@ var WebGLVAOWrapper = new Class({ { var layout = attributeBufferLayout.layout.layout[j]; + // Connect attribute locations from program. + var attributeIndex = glAttributeNames.get(layout.name); + if (attributeIndex === undefined) + { + throw new Error('Attribute not found: ' + layout.name); + } + var attributeInfo = glAttributes[attributeIndex]; + layout.location = attributeInfo.location; + + // Create attribute pointers. + var location = layout.location; var bytes = layout.bytes || 4; diff --git a/src/renderer/webgl/wrappers/WebGLVertexBufferLayoutWrapper.js b/src/renderer/webgl/wrappers/WebGLVertexBufferLayoutWrapper.js index 7d5cc2571..4131cab9c 100644 --- a/src/renderer/webgl/wrappers/WebGLVertexBufferLayoutWrapper.js +++ b/src/renderer/webgl/wrappers/WebGLVertexBufferLayoutWrapper.js @@ -23,7 +23,7 @@ var Class = require('../../../utils/Class'); * @throws {Error} If the buffer is too small for the layout. */ var WebGLVertexBufferLayoutWrapper = new Class({ - initialize: function WebGLVertexBufferLayoutWrapper (renderer, program, layout, buffer) + initialize: function WebGLVertexBufferLayoutWrapper (renderer, layout, buffer) { /** * The WebGLRenderer instance that owns this wrapper. @@ -34,15 +34,6 @@ var WebGLVertexBufferLayoutWrapper = new Class({ */ this.renderer = renderer; - /** - * The program that this layout is associated with. - * - * @name Phaser.Renderer.WebGL.Wrappers.WebGLVertexBufferLayoutWrapper#program - * @type {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper} - * @since 3.90.0 - */ - this.program = program; - /** * The layout of the buffer. * @@ -53,8 +44,8 @@ var WebGLVertexBufferLayoutWrapper = new Class({ this.layout = layout; // Fill in the layout with the stride - // and per-attribute location, bytes, and offset. - program.completeLayout(layout); + // and per-attribute bytes and offset. + this.completeLayout(layout); var bufferSize = layout.stride * layout.count; if (buffer && buffer.byteLength < bufferSize) @@ -70,6 +61,61 @@ var WebGLVertexBufferLayoutWrapper = new Class({ * @since 3.90.0 */ this.buffer = buffer || renderer.createVertexBuffer(new ArrayBuffer(bufferSize), layout.usage); + }, + + /** + * Complete the layout of the provided attribute buffer layout. + * This will fill in the stride, byte counts, and offsets. + * In addition, it will convert any GLenums specified as strings + * to their numeric values. + * This mutates the layout. + * + * The order of attributes within the layout forms the order of the buffer. + * + * @method Phaser.Renderer.WebGL.Wrappers.WebGLVertexBufferLayoutWrapper#completeLayout + * @since 3.90.0 + * @param {Phaser.Types.Renderer.WebGL.WebGLAttributeBufferLayout} attributeBufferLayout - The layout to complete. + */ + completeLayout: function (attributeBufferLayout) + { + var gl = this.renderer.gl; + var layout = attributeBufferLayout.layout; + var constants = this.renderer.shaderSetters.constants; + + if (typeof attributeBufferLayout.usage === 'string') + { + attributeBufferLayout.usage = gl[attributeBufferLayout.usage]; + } + + var offset = 0; + + for (var i = 0; i < layout.length; i++) + { + var attribute = layout[i]; + var size = attribute.size; + var columns = attribute.columns || 1; + + // First, append the current offset. + attribute.offset = offset; + + // Convert the type to a GLenum if it is a string. + if (typeof attribute.type === 'string') + { + attribute.type = gl[attribute.type]; + } + + var typeData = constants[attribute.type]; + var baseSize = typeData.size; + var baseBytes = typeData.bytes; + + // Append the bytes per attribute element. + attribute.bytes = baseBytes; + + offset += size * columns * baseBytes * baseSize; + } + + // Now that we know the total stride, we can set it. + attributeBufferLayout.stride = offset; } });