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.
This commit is contained in:
Ben Richards 2024-07-30 18:09:56 +12:00
parent bfc7c8a417
commit 9454d1a11a
5 changed files with 88 additions and 85 deletions

View file

@ -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;
},

View file

@ -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
]);

View file

@ -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.
*

View file

@ -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;

View file

@ -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;
}
});