Vertex and attribute compression to reduce the size of the vertex format.

This allows Godot to automatically compress meshes to save a lot of bandwidth.

In general, this requires no interaction from the user and should result in
no noticable quality loss.

This scheme is not backwards compatible, so we have provided an upgrade
mechanism, and a mesh versioning mechanism.

Existing meshes can still be used as a result, but users can get a
performance boost by reimporting assets.
This commit is contained in:
clayjohn
2023-08-29 21:04:32 +02:00
parent d31794c4a2
commit 51ed3aef63
59 changed files with 1752 additions and 670 deletions

View File

@ -1383,7 +1383,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
GLuint vertex_array_gl = 0;
GLuint index_array_gl = 0;
uint32_t input_mask = 0; // 2D meshes always use the same vertex format
uint64_t input_mask = 0; // 2D meshes always use the same vertex format.
if (mesh_instance.is_valid()) {
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array_gl);
} else {

View File

@ -2908,6 +2908,18 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, spec_constants);
{
GLES3::Mesh::Surface *s = reinterpret_cast<GLES3::Mesh::Surface *>(surf->surface);
if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::COMPRESSED_AABB_POSITION, s->aabb.position, shader->version, instance_variant, spec_constants);
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::COMPRESSED_AABB_SIZE, s->aabb.size, shader->version, instance_variant, spec_constants);
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::UV_SCALE, s->uv_scale, shader->version, instance_variant, spec_constants);
} else {
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::COMPRESSED_AABB_POSITION, Vector3(0.0, 0.0, 0.0), shader->version, instance_variant, spec_constants);
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::COMPRESSED_AABB_SIZE, Vector3(1.0, 1.0, 1.0), shader->version, instance_variant, spec_constants);
material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::UV_SCALE, Vector4(0.0, 0.0, 0.0, 0.0), shader->version, instance_variant, spec_constants);
}
}
// Can be index count or vertex count
uint32_t count = 0;

View File

@ -52,8 +52,8 @@ ADDITIVE_SPOT = false
/*
from RenderingServer:
ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit)
ARRAY_NORMAL = 1, // RG16 octahedral compression
ARRAY_VERTEX = 0, // RGB32F or RGBA16
ARRAY_NORMAL = 1, // RG16 octahedral compression or RGBA16 normal + angle
ARRAY_TANGENT = 2, // RG16 octahedral compression, sign stored in sign of G
ARRAY_COLOR = 3, // RGBA8
ARRAY_TEX_UV = 4, // RG32F
@ -68,16 +68,16 @@ ARRAY_WEIGHTS = 11, // RGBA16UNORM (x2 if 8 weights)
/* INPUT ATTRIBS */
layout(location = 0) in highp vec3 vertex_attrib;
// Always contains vertex position in XYZ, can contain tangent angle in W.
layout(location = 0) in highp vec4 vertex_angle_attrib;
/* clang-format on */
#ifdef NORMAL_USED
layout(location = 1) in vec2 normal_attrib;
// Contains Normal/Axis in RG, can contain tangent in BA.
layout(location = 1) in vec4 axis_tangent_attrib;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
layout(location = 2) in vec2 tangent_attrib;
#endif
// location 2 is unused.
#if defined(COLOR_USED)
layout(location = 3) in vec4 color_attrib;
@ -122,6 +122,16 @@ vec3 oct_to_vec3(vec2 e) {
return normalize(v);
}
void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) {
float c = cos(angle);
float s = sin(angle);
vec3 omc_axis = (1.0 - c) * axis;
vec3 s_axis = s * axis;
tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y);
binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x);
normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c);
}
#ifdef USE_INSTANCING
layout(location = 12) in highp vec4 instance_xform0;
layout(location = 13) in highp vec4 instance_xform1;
@ -228,10 +238,9 @@ multiview_data;
#endif
uniform highp mat4 world_transform;
#ifdef USE_LIGHTMAP
uniform highp vec4 lightmap_uv_rect;
#endif
uniform highp vec3 compressed_aabb_position;
uniform highp vec3 compressed_aabb_size;
uniform highp vec4 uv_scale;
/* Varyings */
@ -248,12 +257,8 @@ out vec4 color_interp;
out vec2 uv_interp;
#endif
#if defined(UV2_USED)
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
out vec2 uv2_interp;
#else
#ifdef USE_LIGHTMAP
out vec2 uv2_interp;
#endif
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
@ -294,7 +299,7 @@ layout(std140) uniform MaterialUniforms { // ubo:3
invariant gl_Position;
void main() {
highp vec3 vertex = vertex_attrib;
highp vec3 vertex = vertex_angle_attrib.xyz * compressed_aabb_size + compressed_aabb_position;
highp mat4 model_matrix = world_transform;
#ifdef USE_INSTANCING
@ -303,15 +308,30 @@ void main() {
#endif
#ifdef NORMAL_USED
vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0);
vec3 normal = oct_to_vec3(axis_tangent_attrib.xy * 2.0 - 1.0);
#endif
highp mat3 model_normal_matrix = mat3(model_matrix);
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0;
vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
float binormalf = sign(signed_tangent_attrib.y);
vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
vec3 binormal;
float binormal_sign;
vec3 tangent;
if (axis_tangent_attrib.z > 0.0 || axis_tangent_attrib.w < 1.0) {
// Uncompressed format.
vec2 signed_tangent_attrib = axis_tangent_attrib.zw * 2.0 - 1.0;
tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
binormal_sign = sign(signed_tangent_attrib.y);
binormal = normalize(cross(normal, tangent) * binormal_sign);
} else {
// Compressed format.
float angle = vertex_angle_attrib.w;
binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller.
angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably.
vec3 axis = normal;
axis_angle_to_tbn(axis, angle, tangent, binormal, normal);
binormal *= binormal_sign;
}
#endif
#if defined(COLOR_USED)
@ -326,13 +346,18 @@ void main() {
uv_interp = uv_attrib;
#endif
#ifdef USE_LIGHTMAP
uv2_interp = lightmap_uv_rect.zw * uv2_attrib + lightmap_uv_rect.xy;
#else
#if defined(UV2_USED)
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
uv2_interp = uv2_attrib;
#endif
if (uv_scale != vec4(0.0)) { // Compression enabled
#ifdef UV_USED
uv_interp = (uv_interp - 0.5) * uv_scale.xy;
#endif
#if defined(UV2_USED) || defined(USE_LIGHTMAP)
uv2_interp = (uv2_interp - 0.5) * uv_scale.zw;
#endif
}
#if defined(OVERRIDE_POSITION)
highp vec4 position;

View File

@ -2944,7 +2944,7 @@ void SceneShaderData::set_code(const String &p_code) {
cull_mode = Cull(cull_modei);
blend_mode = BlendMode(blend_modei);
alpha_antialiasing_mode = AlphaAntiAliasing(alpha_antialiasing_modei);
vertex_input_mask = uint32_t(uses_normal);
vertex_input_mask = uint64_t(uses_normal);
vertex_input_mask |= uses_tangent << 1;
vertex_input_mask |= uses_color << 2;
vertex_input_mask |= uses_uv << 3;

View File

@ -316,7 +316,7 @@ struct SceneShaderData : public ShaderData {
bool uses_bones;
bool uses_weights;
uint32_t vertex_input_mask = 0;
uint64_t vertex_input_mask = 0;
uint64_t last_pass = 0;
uint32_t index = 0;

View File

@ -117,34 +117,40 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
uint32_t skin_stride = 0;
for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) {
if ((p_surface.format & (1 << i))) {
if ((p_surface.format & (1ULL << i))) {
switch (i) {
case RS::ARRAY_VERTEX: {
if (p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
if ((p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) || (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
stride += sizeof(float) * 2;
} else {
stride += sizeof(float) * 3;
}
} break;
case RS::ARRAY_NORMAL: {
stride += sizeof(uint16_t) * 2;
} break;
case RS::ARRAY_TANGENT: {
stride += sizeof(uint16_t) * 2;
if (!(p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
stride += sizeof(uint16_t) * 2;
}
} break;
case RS::ARRAY_COLOR: {
attrib_stride += sizeof(uint32_t);
} break;
case RS::ARRAY_TEX_UV: {
attrib_stride += sizeof(float) * 2;
if (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
attrib_stride += sizeof(uint16_t) * 2;
} else {
attrib_stride += sizeof(float) * 2;
}
} break;
case RS::ARRAY_TEX_UV2: {
attrib_stride += sizeof(float) * 2;
if (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
attrib_stride += sizeof(uint16_t) * 2;
} else {
attrib_stride += sizeof(float) * 2;
}
} break;
case RS::ARRAY_CUSTOM0:
case RS::ARRAY_CUSTOM1:
@ -183,94 +189,123 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
}
#endif
uint64_t surface_version = p_surface.format & (uint64_t(RS::ARRAY_FLAG_FORMAT_VERSION_MASK) << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT);
RS::SurfaceData new_surface = p_surface;
#ifdef DISABLE_DEPRECATED
ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, "Surface version provided (" + itos(int(surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT)) + ") does not match current version (" + itos(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) + ")");
#else
if (surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION)) {
RS::_fix_surface_compatibility(new_surface);
surface_version = new_surface.format & (uint64_t(RS::ARRAY_FLAG_FORMAT_VERSION_MASK) << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT);
ERR_FAIL_COND_MSG(surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION),
"Surface version provided (" +
itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) +
") does not match current version (" +
itos((uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION) >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) +
")");
}
#endif
Mesh::Surface *s = memnew(Mesh::Surface);
s->format = p_surface.format;
s->primitive = p_surface.primitive;
s->format = new_surface.format;
s->primitive = new_surface.primitive;
if (p_surface.vertex_data.size()) {
if (new_surface.vertex_data.size()) {
glGenBuffers(1, &s->vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, p_surface.vertex_data.size(), p_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer");
s->vertex_buffer_size = p_surface.vertex_data.size();
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, new_surface.vertex_data.size(), new_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer");
s->vertex_buffer_size = new_surface.vertex_data.size();
}
if (p_surface.attribute_data.size()) {
if (new_surface.attribute_data.size()) {
glGenBuffers(1, &s->attribute_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s->attribute_buffer);
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->attribute_buffer, p_surface.attribute_data.size(), p_surface.attribute_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh attribute buffer");
s->attribute_buffer_size = p_surface.attribute_data.size();
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->attribute_buffer, new_surface.attribute_data.size(), new_surface.attribute_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh attribute buffer");
s->attribute_buffer_size = new_surface.attribute_data.size();
}
if (p_surface.skin_data.size()) {
if (new_surface.skin_data.size()) {
glGenBuffers(1, &s->skin_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s->skin_buffer);
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->skin_buffer, p_surface.skin_data.size(), p_surface.skin_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh skin buffer");
s->skin_buffer_size = p_surface.skin_data.size();
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->skin_buffer, new_surface.skin_data.size(), new_surface.skin_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh skin buffer");
s->skin_buffer_size = new_surface.skin_data.size();
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
s->vertex_count = p_surface.vertex_count;
s->vertex_count = new_surface.vertex_count;
if (p_surface.format & RS::ARRAY_FORMAT_BONES) {
if (new_surface.format & RS::ARRAY_FORMAT_BONES) {
mesh->has_bone_weights = true;
}
if (p_surface.index_count) {
bool is_index_16 = p_surface.vertex_count <= 65536 && p_surface.vertex_count > 0;
if (new_surface.index_count) {
bool is_index_16 = new_surface.vertex_count <= 65536 && new_surface.vertex_count > 0;
glGenBuffers(1, &s->index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer);
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer, p_surface.index_data.size(), p_surface.index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer");
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer, new_surface.index_data.size(), new_surface.index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer");
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
s->index_count = p_surface.index_count;
s->index_buffer_size = p_surface.index_data.size();
s->index_count = new_surface.index_count;
s->index_buffer_size = new_surface.index_data.size();
if (p_surface.lods.size()) {
s->lods = memnew_arr(Mesh::Surface::LOD, p_surface.lods.size());
s->lod_count = p_surface.lods.size();
if (new_surface.lods.size()) {
s->lods = memnew_arr(Mesh::Surface::LOD, new_surface.lods.size());
s->lod_count = new_surface.lods.size();
for (int i = 0; i < p_surface.lods.size(); i++) {
for (int i = 0; i < new_surface.lods.size(); i++) {
glGenBuffers(1, &s->lods[i].index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->lods[i].index_buffer);
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->lods[i].index_buffer, p_surface.lods[i].index_data.size(), p_surface.lods[i].index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer LOD[" + itos(i) + "]");
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->lods[i].index_buffer, new_surface.lods[i].index_data.size(), new_surface.lods[i].index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer LOD[" + itos(i) + "]");
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
s->lods[i].edge_length = p_surface.lods[i].edge_length;
s->lods[i].index_count = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
s->lods[i].index_buffer_size = p_surface.lods[i].index_data.size();
s->lods[i].edge_length = new_surface.lods[i].edge_length;
s->lods[i].index_count = new_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4);
s->lods[i].index_buffer_size = new_surface.lods[i].index_data.size();
}
}
}
ERR_FAIL_COND_MSG(!p_surface.index_count && !p_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both");
ERR_FAIL_COND_MSG(!new_surface.index_count && !new_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both");
s->aabb = p_surface.aabb;
s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
s->aabb = new_surface.aabb;
s->bone_aabbs = new_surface.bone_aabbs; //only really useful for returning them.
if (p_surface.skin_data.size() || mesh->blend_shape_count > 0) {
s->uv_scale = new_surface.uv_scale;
if (new_surface.skin_data.size() || mesh->blend_shape_count > 0) {
// Size must match the size of the vertex array.
int size = p_surface.vertex_data.size();
int size = new_surface.vertex_data.size();
int vertex_size = 0;
int stride = 0;
int position_stride = 0;
int normal_tangent_stride = 0;
int normal_offset = 0;
int tangent_offset = 0;
if ((p_surface.format & (1 << RS::ARRAY_VERTEX))) {
if (p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
if ((new_surface.format & (1ULL << RS::ARRAY_VERTEX))) {
if (new_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
vertex_size = 2;
position_stride = sizeof(float) * vertex_size;
} else {
vertex_size = 3;
if (new_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
vertex_size = 4;
position_stride = sizeof(uint16_t) * vertex_size;
} else {
vertex_size = 3;
position_stride = sizeof(float) * vertex_size;
}
}
stride = sizeof(float) * vertex_size;
}
if ((p_surface.format & (1 << RS::ARRAY_NORMAL))) {
normal_offset = stride;
stride += sizeof(uint16_t) * 2;
if ((new_surface.format & (1ULL << RS::ARRAY_NORMAL))) {
normal_offset = position_stride * s->vertex_count;
normal_tangent_stride += sizeof(uint16_t) * 2;
}
if ((p_surface.format & (1 << RS::ARRAY_TANGENT))) {
tangent_offset = stride;
stride += sizeof(uint16_t) * 2;
if ((new_surface.format & (1ULL << RS::ARRAY_TANGENT))) {
tangent_offset = normal_offset + normal_tangent_stride;
normal_tangent_stride += sizeof(uint16_t) * 2;
}
if (mesh->blend_shape_count > 0) {
@ -282,54 +317,38 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
glBindVertexArray(s->blend_shapes[i].vertex_array);
glGenBuffers(1, &s->blend_shapes[i].vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s->blend_shapes[i].vertex_buffer);
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->blend_shapes[i].vertex_buffer, size, p_surface.blend_shape_data.ptr() + i * size, (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh blend shape buffer");
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->blend_shapes[i].vertex_buffer, size, new_surface.blend_shape_data.ptr() + i * size, (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh blend shape buffer");
if ((p_surface.format & (1 << RS::ARRAY_VERTEX))) {
if ((new_surface.format & (1ULL << RS::ARRAY_VERTEX))) {
glEnableVertexAttribArray(RS::ARRAY_VERTEX + 3);
glVertexAttribPointer(RS::ARRAY_VERTEX + 3, vertex_size, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0));
glVertexAttribPointer(RS::ARRAY_VERTEX + 3, vertex_size, GL_FLOAT, GL_FALSE, position_stride, CAST_INT_TO_UCHAR_PTR(0));
}
if ((p_surface.format & (1 << RS::ARRAY_NORMAL))) {
if ((new_surface.format & (1ULL << RS::ARRAY_NORMAL))) {
// Normal and tangent are packed into the same attribute.
glEnableVertexAttribArray(RS::ARRAY_NORMAL + 3);
glVertexAttribPointer(RS::ARRAY_NORMAL + 3, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(normal_offset));
glVertexAttribPointer(RS::ARRAY_NORMAL + 3, 2, GL_UNSIGNED_SHORT, GL_TRUE, normal_tangent_stride, CAST_INT_TO_UCHAR_PTR(normal_offset));
}
if ((p_surface.format & (1 << RS::ARRAY_TANGENT))) {
if ((p_surface.format & (1ULL << RS::ARRAY_TANGENT))) {
glEnableVertexAttribArray(RS::ARRAY_TANGENT + 3);
glVertexAttribPointer(RS::ARRAY_TANGENT + 3, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(tangent_offset));
glVertexAttribPointer(RS::ARRAY_TANGENT + 3, 2, GL_UNSIGNED_SHORT, GL_TRUE, normal_tangent_stride, CAST_INT_TO_UCHAR_PTR(tangent_offset));
}
}
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// Create a vertex array to use for skeleton/blend shapes.
glGenVertexArrays(1, &s->skeleton_vertex_array);
glBindVertexArray(s->skeleton_vertex_array);
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
if ((p_surface.format & (1 << RS::ARRAY_VERTEX))) {
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
glVertexAttribPointer(RS::ARRAY_VERTEX, vertex_size, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0));
}
if ((p_surface.format & (1 << RS::ARRAY_NORMAL))) {
glEnableVertexAttribArray(RS::ARRAY_NORMAL);
glVertexAttribPointer(RS::ARRAY_NORMAL, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(normal_offset));
}
if ((p_surface.format & (1 << RS::ARRAY_TANGENT))) {
glEnableVertexAttribArray(RS::ARRAY_TANGENT);
glVertexAttribPointer(RS::ARRAY_TANGENT, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(tangent_offset));
}
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
if (mesh->surface_count == 0) {
mesh->aabb = p_surface.aabb;
mesh->aabb = new_surface.aabb;
} else {
mesh->aabb.merge_with(p_surface.aabb);
mesh->aabb.merge_with(new_surface.aabb);
}
mesh->skeleton_aabb_version = 0;
s->material = p_surface.material;
s->material = new_surface.material;
mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1));
mesh->surfaces[mesh->surface_count] = s;
@ -479,6 +498,8 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
}
}
sd.uv_scale = s.uv_scale;
return sd;
}
@ -696,10 +717,6 @@ void MeshStorage::mesh_clear(RID p_mesh) {
}
memdelete_arr(s.blend_shapes);
}
if (s.skeleton_vertex_array != 0) {
glDeleteVertexArrays(1, &s.skeleton_vertex_array);
s.skeleton_vertex_array = 0;
}
memdelete(mesh->surfaces[i]);
}
@ -720,15 +737,16 @@ void MeshStorage::mesh_clear(RID p_mesh) {
}
}
void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis) {
void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, MeshInstance::Surface *mis) {
Mesh::Surface::Attrib attribs[RS::ARRAY_MAX];
int position_stride = 0; // Vertex position only.
int normal_tangent_stride = 0;
int attributes_stride = 0;
int vertex_stride = 0;
int skin_stride = 0;
for (int i = 0; i < RS::ARRAY_INDEX; i++) {
if (!(s->format & (1 << i))) {
if (!(s->format & (1ULL << i))) {
attribs[i].enabled = false;
attribs[i].integer = false;
continue;
@ -739,29 +757,55 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
switch (i) {
case RS::ARRAY_VERTEX: {
attribs[i].offset = vertex_stride;
attribs[i].offset = 0;
attribs[i].type = GL_FLOAT;
attribs[i].normalized = GL_FALSE;
if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
attribs[i].size = 2;
position_stride = attribs[i].size * sizeof(float);
} else {
attribs[i].size = 3;
if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
attribs[i].size = 4;
position_stride = attribs[i].size * sizeof(uint16_t);
attribs[i].type = GL_UNSIGNED_SHORT;
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].size = 3;
position_stride = attribs[i].size * sizeof(float);
}
}
attribs[i].type = GL_FLOAT;
vertex_stride += attribs[i].size * sizeof(float);
attribs[i].normalized = GL_FALSE;
} break;
case RS::ARRAY_NORMAL: {
attribs[i].offset = vertex_stride;
attribs[i].size = 2;
if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
attribs[i].size = 2;
normal_tangent_stride += 2 * attribs[i].size;
} else {
attribs[i].size = 4;
// A small trick here: if we are uncompressed and we have normals, but no tangents. We need
// the shader to think there are 4 components to "axis_tangent_attrib". So we give a size of 4,
// but a stride based on only having 2 elements.
if (!(s->format & RS::ARRAY_FORMAT_TANGENT)) {
normal_tangent_stride += (mis ? sizeof(float) : sizeof(uint16_t)) * 2;
} else {
normal_tangent_stride += (mis ? sizeof(float) : sizeof(uint16_t)) * 4;
}
}
if (mis) {
// Transform feedback has interleave all or no attributes. It can't mix interleaving.
attribs[i].offset = position_stride;
normal_tangent_stride += position_stride;
position_stride = normal_tangent_stride;
} else {
attribs[i].offset = position_stride * s->vertex_count;
}
attribs[i].type = (mis ? GL_FLOAT : GL_UNSIGNED_SHORT);
vertex_stride += sizeof(uint16_t) * 2 * (mis ? 2 : 1);
attribs[i].normalized = GL_TRUE;
} break;
case RS::ARRAY_TANGENT: {
attribs[i].offset = vertex_stride;
attribs[i].size = 2;
attribs[i].type = (mis ? GL_FLOAT : GL_UNSIGNED_SHORT);
vertex_stride += sizeof(uint16_t) * 2 * (mis ? 2 : 1);
attribs[i].normalized = GL_TRUE;
// We never use the tangent attribute. It is always packed in ARRAY_NORMAL, or ARRAY_VERTEX.
attribs[i].enabled = false;
attribs[i].integer = false;
} break;
case RS::ARRAY_COLOR: {
attribs[i].offset = attributes_stride;
@ -773,16 +817,28 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
case RS::ARRAY_TEX_UV: {
attribs[i].offset = attributes_stride;
attribs[i].size = 2;
attribs[i].type = GL_FLOAT;
attributes_stride += 2 * sizeof(float);
attribs[i].normalized = GL_FALSE;
if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
attribs[i].type = GL_UNSIGNED_SHORT;
attributes_stride += 2 * sizeof(uint16_t);
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
attributes_stride += 2 * sizeof(float);
attribs[i].normalized = GL_FALSE;
}
} break;
case RS::ARRAY_TEX_UV2: {
attribs[i].offset = attributes_stride;
attribs[i].size = 2;
attribs[i].type = GL_FLOAT;
attributes_stride += 2 * sizeof(float);
attribs[i].normalized = GL_FALSE;
if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
attribs[i].type = GL_UNSIGNED_SHORT;
attributes_stride += 2 * sizeof(uint16_t);
attribs[i].normalized = GL_TRUE;
} else {
attribs[i].type = GL_FLOAT;
attributes_stride += 2 * sizeof(float);
attribs[i].normalized = GL_FALSE;
}
} break;
case RS::ARRAY_CUSTOM0:
case RS::ARRAY_CUSTOM1:
@ -828,7 +884,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
continue;
}
if (i <= RS::ARRAY_TANGENT) {
attribs[i].stride = vertex_stride;
attribs[i].stride = (i == RS::ARRAY_VERTEX) ? position_stride : normal_tangent_stride;
if (mis) {
glBindBuffer(GL_ARRAY_BUFFER, mis->vertex_buffer);
} else {
@ -946,7 +1002,7 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3
if ((mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) && mesh->surfaces[p_surface]->vertex_buffer_size > 0) {
// Cache surface properties
s.format_cache = mesh->surfaces[p_surface]->format;
if ((s.format_cache & (1 << RS::ARRAY_VERTEX))) {
if ((s.format_cache & (1ULL << RS::ARRAY_VERTEX))) {
if (s.format_cache & RS::ARRAY_FLAG_USE_2D_VERTICES) {
s.vertex_size_cache = 2;
} else {
@ -954,25 +1010,27 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3
}
s.vertex_stride_cache = sizeof(float) * s.vertex_size_cache;
}
if ((s.format_cache & (1 << RS::ARRAY_NORMAL))) {
if ((s.format_cache & (1ULL << RS::ARRAY_NORMAL))) {
s.vertex_normal_offset_cache = s.vertex_stride_cache;
s.vertex_stride_cache += sizeof(uint32_t) * 2;
}
if ((s.format_cache & (1 << RS::ARRAY_TANGENT))) {
if ((s.format_cache & (1ULL << RS::ARRAY_TANGENT))) {
s.vertex_tangent_offset_cache = s.vertex_stride_cache;
s.vertex_stride_cache += sizeof(uint32_t) * 2;
}
int buffer_size = s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count;
// Buffer to be used for rendering. Final output of skeleton and blend shapes.
glGenBuffers(1, &s.vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffer);
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffer, s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW, "MeshInstance vertex buffer");
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffer, buffer_size, nullptr, GL_DYNAMIC_DRAW, "MeshInstance vertex buffer");
if (mesh->blend_shape_count > 0) {
// Ping-Pong buffers for processing blendshapes.
glGenBuffers(2, s.vertex_buffers);
for (uint32_t i = 0; i < 2; i++) {
glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffers[i]);
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffers[i], s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW, "MeshInstance process buffer[" + itos(i) + "]");
GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffers[i], buffer_size, nullptr, GL_DYNAMIC_DRAW, "MeshInstance process buffer[" + itos(i) + "]");
}
}
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
@ -1011,19 +1069,19 @@ void MeshStorage::mesh_instance_set_canvas_item_transform(RID p_mesh_instance, c
void MeshStorage::_blend_shape_bind_mesh_instance_buffer(MeshInstance *p_mi, uint32_t p_surface) {
glBindBuffer(GL_ARRAY_BUFFER, p_mi->surfaces[p_surface].vertex_buffers[0]);
if ((p_mi->surfaces[p_surface].format_cache & (1 << RS::ARRAY_VERTEX))) {
if ((p_mi->surfaces[p_surface].format_cache & (1ULL << RS::ARRAY_VERTEX))) {
glEnableVertexAttribArray(RS::ARRAY_VERTEX);
glVertexAttribPointer(RS::ARRAY_VERTEX, p_mi->surfaces[p_surface].vertex_size_cache, GL_FLOAT, GL_FALSE, p_mi->surfaces[p_surface].vertex_stride_cache, CAST_INT_TO_UCHAR_PTR(0));
} else {
glDisableVertexAttribArray(RS::ARRAY_VERTEX);
}
if ((p_mi->surfaces[p_surface].format_cache & (1 << RS::ARRAY_NORMAL))) {
if ((p_mi->surfaces[p_surface].format_cache & (1ULL << RS::ARRAY_NORMAL))) {
glEnableVertexAttribArray(RS::ARRAY_NORMAL);
glVertexAttribIPointer(RS::ARRAY_NORMAL, 2, GL_UNSIGNED_INT, p_mi->surfaces[p_surface].vertex_stride_cache, CAST_INT_TO_UCHAR_PTR(p_mi->surfaces[p_surface].vertex_normal_offset_cache));
} else {
glDisableVertexAttribArray(RS::ARRAY_NORMAL);
}
if ((p_mi->surfaces[p_surface].format_cache & (1 << RS::ARRAY_TANGENT))) {
if ((p_mi->surfaces[p_surface].format_cache & (1ULL << RS::ARRAY_TANGENT))) {
glEnableVertexAttribArray(RS::ARRAY_TANGENT);
glVertexAttribIPointer(RS::ARRAY_TANGENT, 2, GL_UNSIGNED_INT, p_mi->surfaces[p_surface].vertex_stride_cache, CAST_INT_TO_UCHAR_PTR(p_mi->surfaces[p_surface].vertex_tangent_offset_cache));
} else {
@ -1091,7 +1149,7 @@ void MeshStorage::update_mesh_instances() {
}
for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
if (mi->surfaces[i].vertex_buffer == 0 || mi->mesh->surfaces[i]->skeleton_vertex_array == 0) {
if (mi->surfaces[i].vertex_buffer == 0) {
continue;
}
@ -1106,10 +1164,10 @@ void MeshStorage::update_mesh_instances() {
specialization |= array_is_2d ? SkeletonShaderGLES3::MODE_2D : 0;
specialization |= SkeletonShaderGLES3::USE_BLEND_SHAPES;
if (!array_is_2d) {
if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_NORMAL))) {
if ((mi->surfaces[i].format_cache & (1ULL << RS::ARRAY_NORMAL))) {
specialization |= SkeletonShaderGLES3::USE_NORMAL;
}
if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_TANGENT))) {
if ((mi->surfaces[i].format_cache & (1ULL << RS::ARRAY_TANGENT))) {
specialization |= SkeletonShaderGLES3::USE_TANGENT;
}
}
@ -1123,7 +1181,12 @@ void MeshStorage::update_mesh_instances() {
skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_SHAPE_COUNT, float(mi->mesh->blend_shape_count), skeleton_shader.shader_version, variant, specialization);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(mi->mesh->surfaces[i]->skeleton_vertex_array);
GLuint vertex_array_gl = 0;
uint64_t mask = ((1 << 10) - 1) << 3; // Mask from ARRAY_FORMAT_COLOR to ARRAY_FORMAT_INDEX.
mask = ~mask;
uint64_t format = mi->surfaces[i].format_cache & mask; // Format should only have vertex, normal, tangent (as necessary) + compressions.
mesh_surface_get_vertex_arrays_and_format(mi->mesh->surfaces[i], format, vertex_array_gl);
glBindVertexArray(vertex_array_gl);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].vertex_buffers[0]);
glBeginTransformFeedback(GL_POINTS);
glDrawArrays(GL_POINTS, 0, mi->mesh->surfaces[i]->vertex_count);
@ -1210,10 +1273,10 @@ void MeshStorage::update_mesh_instances() {
specialization |= SkeletonShaderGLES3::FINAL_PASS;
specialization |= use_8_weights ? SkeletonShaderGLES3::USE_EIGHT_WEIGHTS : 0;
if (!array_is_2d) {
if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_NORMAL))) {
if ((mi->surfaces[i].format_cache & (1ULL << RS::ARRAY_NORMAL))) {
specialization |= SkeletonShaderGLES3::USE_NORMAL;
}
if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_TANGENT))) {
if ((mi->surfaces[i].format_cache & (1ULL << RS::ARRAY_TANGENT))) {
specialization |= SkeletonShaderGLES3::USE_TANGENT;
}
}
@ -1233,7 +1296,12 @@ void MeshStorage::update_mesh_instances() {
skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::INVERSE_TRANSFORM_Y, inverse_transform[1], skeleton_shader.shader_version, variant, specialization);
skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::INVERSE_TRANSFORM_OFFSET, inverse_transform[2], skeleton_shader.shader_version, variant, specialization);
glBindVertexArray(mi->mesh->surfaces[i]->skeleton_vertex_array);
GLuint vertex_array_gl = 0;
uint64_t mask = ((1 << 10) - 1) << 3; // Mask from ARRAY_FORMAT_COLOR to ARRAY_FORMAT_INDEX.
mask = ~mask;
uint64_t format = mi->surfaces[i].format_cache & mask; // Format should only have vertex, normal, tangent (as necessary) + compressions.
mesh_surface_get_vertex_arrays_and_format(mi->mesh->surfaces[i], format, vertex_array_gl);
glBindVertexArray(vertex_array_gl);
_compute_skeleton(mi, sk, i);
}
}

View File

@ -58,7 +58,7 @@ struct Mesh {
uint32_t offset;
};
RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
uint32_t format = 0;
uint64_t format = 0;
GLuint vertex_buffer = 0;
GLuint attribute_buffer = 0;
@ -98,6 +98,8 @@ struct Mesh {
Vector<AABB> bone_aabbs;
Vector4 uv_scale;
struct BlendShape {
GLuint vertex_buffer = 0;
GLuint vertex_array = 0;
@ -144,7 +146,7 @@ struct MeshInstance {
int vertex_size_cache = 0;
int vertex_normal_offset_cache = 0;
int vertex_tangent_offset_cache = 0;
uint32_t format_cache = 0;
uint64_t format_cache = 0;
Mesh::Surface::Version *versions = nullptr; //allocated on demand
uint32_t version_count = 0;
@ -221,7 +223,7 @@ private:
mutable RID_Owner<Mesh, true> mesh_owner;
void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis = nullptr);
void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, MeshInstance::Surface *mis = nullptr);
/* Mesh Instance API */
@ -381,18 +383,18 @@ public:
}
// Use this to cache Vertex Array Objects so they are only generated once
_FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, GLuint &r_vertex_array_gl) {
_FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint64_t p_input_mask, GLuint &r_vertex_array_gl) {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
s->version_lock.lock();
//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
// There will never be more than 3 or 4 versions, so iterating is the fastest way.
for (uint32_t i = 0; i < s->version_count; i++) {
if (s->versions[i].input_mask != p_input_mask) {
continue;
}
//we have this version, hooray
// We have this version, hooray.
r_vertex_array_gl = s->versions[i].vertex_array;
s->version_lock.unlock();
return;
@ -424,7 +426,7 @@ public:
// TODO: considering hashing versions with multimesh buffer RID.
// Doing so would allow us to avoid specifying multimesh buffer pointers every frame and may improve performance.
_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, GLuint &r_vertex_array_gl) {
_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint64_t p_input_mask, GLuint &r_vertex_array_gl) {
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
ERR_FAIL_NULL(mi);
Mesh *mesh = mi->mesh;

View File

@ -4499,6 +4499,7 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo
if (atf.frequency == VERTEX_FREQUENCY_VERTEX) {
// Validate size for regular drawing.
uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size;
ERR_FAIL_COND_V_MSG(total_size > buffer->size, RID(),
"Attachment (" + itos(i) + ") will read past the end of the buffer.");
@ -4665,7 +4666,7 @@ struct RenderingDeviceVulkanShaderBinarySpecializationConstant {
};
struct RenderingDeviceVulkanShaderBinaryData {
uint32_t vertex_input_mask;
uint64_t vertex_input_mask;
uint32_t fragment_output_mask;
uint32_t specialization_constants_count;
uint32_t is_compute;
@ -4881,7 +4882,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
push_constant.size = binary_data.push_constant_size;
push_constant.vk_stages_mask = binary_data.push_constant_vk_stages_mask;
uint32_t vertex_input_mask = binary_data.vertex_input_mask;
uint64_t vertex_input_mask = binary_data.vertex_input_mask;
uint32_t fragment_output_mask = binary_data.fragment_output_mask;
@ -5209,7 +5210,7 @@ RID RenderingDeviceVulkan::shader_create_placeholder() {
return shader_owner.make_rid(shader);
}
uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) {
uint64_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) {
_THREAD_SAFE_METHOD_
const Shader *shader = shader_owner.get_or_null(p_shader);
@ -6152,8 +6153,8 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
pipeline_vertex_input_state_create_info = vd.create_info;
// Validate with inputs.
for (uint32_t i = 0; i < 32; i++) {
if (!(shader->vertex_input_mask & (1UL << i))) {
for (uint64_t i = 0; i < 64; i++) {
if (!(shader->vertex_input_mask & (1ULL << i))) {
continue;
}
bool found = false;

View File

@ -621,7 +621,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE;
};
uint32_t vertex_input_mask = 0; // Inputs used, this is mostly for validation.
uint64_t vertex_input_mask = 0; // Inputs used, this is mostly for validation.
uint32_t fragment_output_mask = 0;
struct PushConstant {
@ -1140,7 +1140,7 @@ public:
virtual RID shader_create_from_bytecode(const Vector<uint8_t> &p_shader_binary, RID p_placeholder = RID());
virtual RID shader_create_placeholder();
virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader);
virtual uint64_t shader_get_vertex_input_attribute_mask(RID p_shader);
/*****************/
/**** UNIFORM ****/