Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added CPU blendshapes for GLES2 #48480

Merged
merged 1 commit into from
May 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
256 changes: 252 additions & 4 deletions drivers/gles2/rasterizer_scene_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1385,21 +1385,269 @@ bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m
return shader_rebind;
}

void static _calculate_blend_shape_buffer(RasterizerSceneGLES2::RenderList::Element *p_element, PoolVector<float> &transform_buffer) {
RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry);
if (!s->blend_shape_data.empty()) {
if (transform_buffer.size() < s->array_byte_size) {
transform_buffer.resize(s->array_byte_size);
}
for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
if (s->attribs[i].enabled) {
const float *p_weights = p_element->instance->blend_values.ptr();

PoolVector<float>::Write write = transform_buffer.write();
PoolVector<uint8_t>::Read read = s->data.read();
float attrib_array[4] = { 0.0 };

// Read all attributes
for (int j = 0; j < s->array_len; j++) {
size_t offset = s->attribs[i].offset + (j * s->attribs[i].stride);
float base_weight = 1.0;

if (s->mesh->blend_shape_mode == VS::BLEND_SHAPE_MODE_NORMALIZED) {
for (int ti = 0; ti < s->blend_shape_data.size(); ti++) {
base_weight -= p_weights[ti];
}
}

// Set the base
switch (i) {
case VS::ARRAY_VERTEX: {
if (s->format & VS::ARRAY_COMPRESS_VERTEX) {
const uint16_t *v = (const uint16_t *)(read.ptr() + offset);
attrib_array[0] = Math::halfptr_to_float(&v[0]) * base_weight;
attrib_array[1] = Math::halfptr_to_float(&v[1]) * base_weight;
attrib_array[2] = Math::halfptr_to_float(&v[2]) * base_weight;
} else {
const float *v = (const float *)(read.ptr() + offset);
attrib_array[0] = v[0] * base_weight;
attrib_array[1] = v[1] * base_weight;
attrib_array[2] = v[2] * base_weight;
}
} break;
case VS::ARRAY_NORMAL: {
if (s->format & VS::ARRAY_COMPRESS_NORMAL) {
const int8_t *v = (const int8_t *)(read.ptr() + offset);
attrib_array[0] = (v[0] / 127.0) * base_weight;
attrib_array[1] = (v[1] / 127.0) * base_weight;
attrib_array[2] = (v[2] / 127.0) * base_weight;
} else {
const float *v = (const float *)(read.ptr() + offset);
attrib_array[0] = v[0] * base_weight;
attrib_array[1] = v[1] * base_weight;
attrib_array[2] = v[2] * base_weight;
}
} break;
case VS::ARRAY_TANGENT: {
if (s->format & VS::ARRAY_COMPRESS_TANGENT) {
const int8_t *v = (const int8_t *)(read.ptr() + offset);
attrib_array[0] = (v[0] / 127.0) * base_weight;
attrib_array[1] = (v[1] / 127.0) * base_weight;
attrib_array[2] = (v[2] / 127.0) * base_weight;
attrib_array[3] = (v[3] / 127.0) * base_weight;
} else {
const float *v = (const float *)(read.ptr() + offset);
attrib_array[0] = v[0] * base_weight;
attrib_array[1] = v[1] * base_weight;
attrib_array[2] = v[2] * base_weight;
attrib_array[3] = v[3] * base_weight;
}
} break;
case VS::ARRAY_COLOR: {
if (s->format & VS::ARRAY_COMPRESS_COLOR) {
const uint8_t *v = (const uint8_t *)(read.ptr() + offset);
attrib_array[0] = (v[0] / 255.0) * base_weight;
attrib_array[1] = (v[1] / 255.0) * base_weight;
attrib_array[2] = (v[2] / 255.0) * base_weight;
attrib_array[3] = (v[3] / 255.0) * base_weight;
} else {
const float *v = (const float *)(read.ptr() + offset);
attrib_array[0] = v[0] * base_weight;
attrib_array[1] = v[1] * base_weight;
attrib_array[2] = v[2] * base_weight;
attrib_array[3] = v[3] * base_weight;
}
} break;
case VS::ARRAY_TEX_UV: {
if (s->format & VS::ARRAY_COMPRESS_TEX_UV) {
const uint16_t *v = (const uint16_t *)(read.ptr() + offset);
attrib_array[0] = Math::halfptr_to_float(&v[0]) * base_weight;
attrib_array[1] = Math::halfptr_to_float(&v[1]) * base_weight;
} else {
const float *v = (const float *)(read.ptr() + offset);
attrib_array[0] = v[0] * base_weight;
attrib_array[1] = v[1] * base_weight;
}
} break;
case VS::ARRAY_TEX_UV2: {
if (s->format & VS::ARRAY_COMPRESS_TEX_UV2) {
const uint16_t *v = (const uint16_t *)(read.ptr() + offset);
attrib_array[0] = Math::halfptr_to_float(&v[0]) * base_weight;
attrib_array[1] = Math::halfptr_to_float(&v[1]) * base_weight;
} else {
const float *v = (const float *)(read.ptr() + offset);
attrib_array[0] = v[0] * base_weight;
attrib_array[1] = v[1] * base_weight;
}
} break;
clayjohn marked this conversation as resolved.
Show resolved Hide resolved
case VS::ARRAY_WEIGHTS: {
if (s->format & VS::ARRAY_COMPRESS_WEIGHTS) {
const uint16_t *v = (const uint16_t *)(read.ptr() + offset);
attrib_array[0] = (v[0] / 65535.0) * base_weight;
attrib_array[1] = (v[1] / 65535.0) * base_weight;
attrib_array[2] = (v[2] / 65535.0) * base_weight;
attrib_array[3] = (v[3] / 65535.0) * base_weight;
} else {
const float *v = (const float *)(read.ptr() + offset);
attrib_array[0] = v[0] * base_weight;
attrib_array[1] = v[1] * base_weight;
attrib_array[2] = v[2] * base_weight;
attrib_array[3] = v[3] * base_weight;
}
} break;
}

// Add all blend shapes
for (int ti = 0; ti < s->blend_shape_data.size(); ti++) {
PoolVector<uint8_t>::Read blend = s->blend_shape_data[ti].read();
float weight = p_weights[ti];
if (Math::is_zero_approx(weight)) {
continue;
}

switch (i) {
case VS::ARRAY_VERTEX: {
if (s->format & VS::ARRAY_COMPRESS_VERTEX) {
const uint16_t *v = (const uint16_t *)(blend.ptr() + offset);
attrib_array[0] += Math::halfptr_to_float(&v[0]) * weight;
attrib_array[1] += Math::halfptr_to_float(&v[1]) * weight;
attrib_array[2] += Math::halfptr_to_float(&v[2]) * weight;
} else {
const float *v = (const float *)(blend.ptr() + offset);
attrib_array[0] += v[0] * weight;
attrib_array[1] += v[1] * weight;
attrib_array[2] += v[2] * weight;
}
} break;
case VS::ARRAY_NORMAL: {
if (s->format & VS::ARRAY_COMPRESS_NORMAL) {
const int8_t *v = (const int8_t *)(blend.ptr() + offset);
attrib_array[0] += (float(v[0]) / 127.0) * weight;
attrib_array[1] += (float(v[1]) / 127.0) * weight;
attrib_array[2] += (float(v[2]) / 127.0) * weight;
} else {
const float *v = (const float *)(blend.ptr() + offset);
attrib_array[0] += v[0] * weight;
attrib_array[1] += v[1] * weight;
attrib_array[2] += v[2] * weight;
}
} break;
case VS::ARRAY_TANGENT: {
if (s->format & VS::ARRAY_COMPRESS_TANGENT) {
const int8_t *v = (const int8_t *)(read.ptr() + offset);
attrib_array[0] += (float(v[0]) / 127.0) * weight;
attrib_array[1] += (float(v[1]) / 127.0) * weight;
attrib_array[2] += (float(v[2]) / 127.0) * weight;
attrib_array[3] = (float(v[3]) / 127.0);
} else {
const float *v = (const float *)(read.ptr() + offset);
attrib_array[0] += v[0] * weight;
attrib_array[1] += v[1] * weight;
attrib_array[2] += v[2] * weight;
attrib_array[3] = v[3];
}
} break;
case VS::ARRAY_COLOR: {
if (s->format & VS::ARRAY_COMPRESS_COLOR) {
const uint8_t *v = (const uint8_t *)(blend.ptr() + offset);
attrib_array[0] += (v[0] / 255.0) * weight;
attrib_array[1] += (v[1] / 255.0) * weight;
attrib_array[2] += (v[2] / 255.0) * weight;
attrib_array[3] += (v[3] / 255.0) * weight;
} else {
const float *v = (const float *)(blend.ptr() + offset);
attrib_array[0] += v[0] * weight;
attrib_array[1] += v[1] * weight;
attrib_array[2] += v[2] * weight;
attrib_array[3] += v[3] * weight;
}
} break;
case VS::ARRAY_TEX_UV: {
if (s->format & VS::ARRAY_COMPRESS_TEX_UV) {
const uint16_t *v = (const uint16_t *)(blend.ptr() + offset);
attrib_array[0] += Math::halfptr_to_float(&v[0]) * weight;
attrib_array[1] += Math::halfptr_to_float(&v[1]) * weight;
} else {
const float *v = (const float *)(blend.ptr() + offset);
attrib_array[0] += v[0] * weight;
attrib_array[1] += v[1] * weight;
}
} break;
case VS::ARRAY_TEX_UV2: {
if (s->format & VS::ARRAY_COMPRESS_TEX_UV2) {
const uint16_t *v = (const uint16_t *)(blend.ptr() + offset);
attrib_array[0] += Math::halfptr_to_float(&v[0]) * weight;
attrib_array[1] += Math::halfptr_to_float(&v[1]) * weight;
} else {
const float *v = (const float *)(blend.ptr() + offset);
attrib_array[0] += v[0] * weight;
attrib_array[1] += v[1] * weight;
}
} break;
case VS::ARRAY_WEIGHTS: {
if (s->format & VS::ARRAY_COMPRESS_WEIGHTS) {
const uint16_t *v = (const uint16_t *)(blend.ptr() + offset);
attrib_array[0] += (v[0] / 65535.0) * weight;
attrib_array[1] += (v[1] / 65535.0) * weight;
attrib_array[2] += (v[2] / 65535.0) * weight;
attrib_array[3] += (v[3] / 65535.0) * weight;
} else {
const float *v = (const float *)(blend.ptr() + offset);
attrib_array[0] += v[0] * weight;
attrib_array[1] += v[1] * weight;
attrib_array[2] += v[2] * weight;
attrib_array[3] += v[3] * weight;
}
} break;
}
}
memcpy(&write[offset], attrib_array, sizeof(float) * s->attribs[i].size);
}
}
}
}
}

void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton) {
switch (p_element->instance->base_type) {
case VS::INSTANCE_MESH: {
RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry);

glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id);

if (s->index_array_len > 0) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id);
}

if (!s->blend_shape_data.empty()) {
_calculate_blend_shape_buffer(p_element, storage->resources.blend_shapes_transform_cpu_buffer);
storage->_update_blend_shape_transform_buffer(storage->resources.blend_shapes_transform_cpu_buffer, s->array_byte_size);
}

for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
if (s->attribs[i].enabled) {
glEnableVertexAttribArray(i);
glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[i].offset));
if (!s->blend_shape_data.empty() && (i != VS::ARRAY_BONES)) {
glBindBuffer(GL_ARRAY_BUFFER, storage->resources.blend_shape_transform_buffer);

glEnableVertexAttribArray(i);

glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, GL_FLOAT, GL_FALSE, s->attribs[i].stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(s->attribs[i].offset * sizeof(float)));

} else {
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id);

glEnableVertexAttribArray(i);

glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[i].offset));
}
} else {
glDisableVertexAttribArray(i);
switch (i) {
Expand Down
32 changes: 24 additions & 8 deletions drivers/gles2/rasterizer_storage_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2464,12 +2464,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:

surface->aabb = p_aabb;
surface->max_bone = p_bone_aabbs.size();
#ifdef TOOLS_ENABLED
surface->blend_shape_data = p_blend_shapes;
if (surface->blend_shape_data.size()) {
ERR_PRINT_ONCE("Blend shapes are not supported in OpenGL ES 2.0");
}
#endif

surface->data = array;
surface->index_data = p_index_array;
Expand Down Expand Up @@ -2674,9 +2669,6 @@ Vector<PoolVector<uint8_t>> RasterizerStorageGLES2::mesh_surface_get_blend_shape
const Mesh *mesh = mesh_owner.getornull(p_mesh);
ERR_FAIL_COND_V(!mesh, Vector<PoolVector<uint8_t>>());
ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<PoolVector<uint8_t>>());
#ifndef TOOLS_ENABLED
ERR_PRINT("OpenGL ES 2.0 does not allow retrieving blend shape data");
#endif

return mesh->surfaces[p_surface]->blend_shape_data;
}
Expand Down Expand Up @@ -3688,6 +3680,25 @@ void RasterizerStorageGLES2::skeleton_set_base_transform_2d(RID p_skeleton, cons
skeleton->base_transform_2d = p_base_transform;
}

void RasterizerStorageGLES2::_update_blend_shape_transform_buffer(const PoolVector<float> &p_data, size_t p_size) {
glBindBuffer(GL_ARRAY_BUFFER, resources.blend_shape_transform_buffer);

uint32_t buffer_size = p_size * sizeof(float);

if (p_size > resources.blend_shape_transform_buffer_size) {
// new requested buffer is bigger, so resizing the GPU buffer

resources.blend_shape_transform_buffer_size = p_size;

glBufferData(GL_ARRAY_BUFFER, buffer_size, p_data.read().ptr(), GL_DYNAMIC_DRAW);
} else {
// this may not be best, it could be better to use glBufferData in both cases.
buffer_orphan_and_upload(resources.blend_shape_transform_buffer_size, 0, buffer_size, p_data.read().ptr(), GL_ARRAY_BUFFER, true);
}

glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void RasterizerStorageGLES2::_update_skeleton_transform_buffer(const PoolVector<float> &p_data, size_t p_size) {
glBindBuffer(GL_ARRAY_BUFFER, resources.skeleton_transform_buffer);

Expand Down Expand Up @@ -6148,6 +6159,11 @@ void RasterizerStorageGLES2::initialize() {
resources.skeleton_transform_buffer_size = 0;
glGenBuffers(1, &resources.skeleton_transform_buffer);
}
// blend shape buffer
{
resources.blend_shape_transform_buffer_size = 0;
glGenBuffers(1, &resources.blend_shape_transform_buffer);
}

// radical inverse vdc cache texture
// used for cubemap filtering
Expand Down
5 changes: 5 additions & 0 deletions drivers/gles2/rasterizer_storage_gles2.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ class RasterizerStorageGLES2 : public RasterizerStorage {
GLuint skeleton_transform_buffer;
PoolVector<float> skeleton_transform_cpu_buffer;

size_t blend_shape_transform_buffer_size;
GLuint blend_shape_transform_buffer;
PoolVector<float> blend_shapes_transform_cpu_buffer;

} resources;

mutable struct Shaders {
Expand Down Expand Up @@ -908,6 +912,7 @@ class RasterizerStorageGLES2 : public RasterizerStorage {
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const;
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform);

void _update_blend_shape_transform_buffer(const PoolVector<float> &p_data, size_t p_size);
void _update_skeleton_transform_buffer(const PoolVector<float> &p_data, size_t p_size);

/* Light API */
Expand Down