WIP blend shape compute dispatch;

This commit is contained in:
bjorn 2023-03-16 00:22:01 -07:00
parent 086aef1a79
commit 530db8c7f8
3 changed files with 139 additions and 17 deletions

View File

@ -9,6 +9,7 @@
#include "shaders/fill_array.frag.h"
#include "shaders/fill_layer.frag.h"
#include "shaders/animator.comp.h"
#include "shaders/blender.comp.h"
#include "shaders/timewizard.comp.h"
#include "shaders/logo.frag.h"

37
etc/shaders/blender.comp Normal file
View File

@ -0,0 +1,37 @@
#version 460
#extension GL_GOOGLE_include_directive : require
#include "lovr.glsl"
layout(local_size_x = 32, local_size_x_id = 0) in;
layout(push_constant) uniform PushConstants {
uint baseVertex;
uint vertexCount;
uint blendShapeIndex;
uint blendShapeCount;
uint baseBlendShapeVertex;
};
struct ModelVertex {
float px, py, pz;
float nx, ny, nz;
float u, v;
uint color;
float tx, ty, tz;
};
struct BlendVertex {
float px, py, pz;
float nx, ny, nz;
float tx, ty, tz;
};
layout(set = 0, binding = 0) buffer restrict readonly VertexIn { ModelVertex vertexIn[]; };
layout(set = 0, binding = 1) buffer restrict writeonly VertexOut { ModelVertex vertexOut[]; };
layout(set = 0, binding = 2) buffer restrict readonly BlendVertices { BlendVertex blendVertex[]; };
layout(set = 0, binding = 3) uniform Weights { vec4 weights[32]; };
void lovrmain() {
//
}

View File

@ -210,10 +210,12 @@ struct Model {
NodeTransform* localTransforms;
float* globalTransforms;
bool transformsDirty;
bool blendShapesDirty;
float* blendShapeWeights;
BlendGroup* blendGroups;
uint32_t blendGroupCount;
uint32_t lastReskin;
uint32_t lastReblend;
};
struct Readback {
@ -279,6 +281,12 @@ typedef struct {
struct { float x, y, z; } tangent;
} ModelVertex;
typedef struct {
struct { float x, y, z; } position;
struct { float x, y, z; } normal;
struct { float x, y, z; } tangent;
} BlendVertex;
enum {
SHAPE_PLANE,
SHAPE_BOX,
@ -387,7 +395,7 @@ static struct {
bool hasTextureUpload;
bool hasMaterialUpload;
bool hasGlyphUpload;
bool hasReskin;
bool hasVertexAnimation;
float background[4];
TextureFormat depthFormat;
Texture* window;
@ -397,6 +405,7 @@ static struct {
Texture* defaultTexture;
Sampler* defaultSamplers[2];
Shader* animator;
Shader* blender;
Shader* timeWizard;
Shader* defaultShaders[DEFAULT_SHADER_COUNT];
gpu_vertex_format vertexFormats[VERTEX_FORMAX];
@ -705,6 +714,7 @@ void lovrGraphicsDestroy() {
lovrRelease(state.defaultSamplers[0], lovrSamplerDestroy);
lovrRelease(state.defaultSamplers[1], lovrSamplerDestroy);
lovrRelease(state.animator, lovrShaderDestroy);
lovrRelease(state.blender, lovrShaderDestroy);
lovrRelease(state.timeWizard, lovrShaderDestroy);
for (size_t i = 0; i < COUNTOF(state.defaultShaders); i++) {
lovrRelease(state.defaultShaders[i], lovrShaderDestroy);
@ -888,12 +898,12 @@ void lovrGraphicsSubmit(Pass** passes, uint32_t count) {
state.hasGlyphUpload = false;
}
if (state.hasReskin) {
if (state.hasVertexAnimation) {
barriers[0].prev |= GPU_PHASE_SHADER_COMPUTE;
barriers[0].next |= GPU_PHASE_INPUT_VERTEX;
barriers[0].flush |= GPU_CACHE_STORAGE_WRITE;
barriers[0].clear |= GPU_CACHE_VERTEX;
state.hasReskin = false;
state.hasVertexAnimation = false;
}
// Finish passes
@ -2857,9 +2867,9 @@ Model* lovrModelCreate(const ModelInfo* info) {
if (data->blendShapeVertexCount > 0) {
BufferField blendFormat[] = {
{ .length = data->blendShapeVertexCount, .stride = 9 * sizeof(float) },
{ .type = FIELD_F32x3, .offset = 0 },
{ .type = FIELD_F32x3, .offset = 12 },
{ .type = FIELD_F32x3, .offset = 24 }
{ .type = FIELD_F32x3, .offset = offsetof(BlendVertex, position) },
{ .type = FIELD_F32x3, .offset = offsetof(BlendVertex, normal) },
{ .type = FIELD_F32x3, .offset = offsetof(BlendVertex, tangent) }
};
blendFormat[0].children = blendFormat + 1;
@ -3017,13 +3027,13 @@ Model* lovrModelCreate(const ModelInfo* info) {
for (uint32_t p = 0; p < node->primitiveCount; p++) {
ModelPrimitive* primitive = &data->primitives[node->primitiveIndex + p];
uint32_t vertexCount = primitive->attributes[ATTR_POSITION]->count;
size_t stride = 9 * sizeof(float);
size_t stride = sizeof(BlendVertex);
for (uint32_t b = 0; b < primitive->blendShapeCount; b++) {
ModelBlendData* blendShape = &primitive->blendShapes[b];
lovrModelDataCopyAttribute(data, blendShape->positions, blendData + 0, F32, 3, false, vertexCount, stride, 0);
lovrModelDataCopyAttribute(data, blendShape->normals, blendData + 12, F32, 3, false, vertexCount, stride, 0);
lovrModelDataCopyAttribute(data, blendShape->tangents, blendData + 24, F32, 3, false, vertexCount, stride, 0);
lovrModelDataCopyAttribute(data, blendShape->positions, blendData + offsetof(BlendVertex, position), F32, 3, false, vertexCount, stride, 0);
lovrModelDataCopyAttribute(data, blendShape->normals, blendData + offsetof(BlendVertex, normal), F32, 3, false, vertexCount, stride, 0);
lovrModelDataCopyAttribute(data, blendShape->tangents, blendData + offsetof(BlendVertex, tangent), F32, 3, false, vertexCount, stride, 0);
blendData += vertexCount * stride;
}
@ -3040,6 +3050,8 @@ Model* lovrModelCreate(const ModelInfo* info) {
model->blendShapeWeights[i] = blendShape->weight;
}
model->blendShapesDirty = true;
}
// Transforms
@ -3201,9 +3213,14 @@ void lovrModelAnimate(Model* model, uint32_t animationIndex, float time, float a
}
}
float* dst = channel->property == PROP_WEIGHTS ?
&model->blendShapeWeights[data->nodes[node].blendShapeIndex] :
transform->properties[channel->property];
float* dst;
if (channel->property == PROP_WEIGHTS) {
dst = &model->blendShapeWeights[data->nodes[node].blendShapeIndex];
model->blendShapesDirty = true;
} else {
dst = transform->properties[channel->property];
model->transformsDirty = true;
}
if (alpha >= 1.f) {
memcpy(dst, property, n * sizeof(float));
@ -3215,8 +3232,6 @@ void lovrModelAnimate(Model* model, uint32_t animationIndex, float time, float a
}
tempPop(stack);
model->transformsDirty = true;
}
float lovrModelGetBlendShapeWeight(Model* model, uint32_t index) {
@ -3225,6 +3240,7 @@ float lovrModelGetBlendShapeWeight(Model* model, uint32_t index) {
void lovrModelSetBlendShapeWeight(Model* model, uint32_t index, float weight) {
model->blendShapeWeights[index] = weight;
model->blendShapesDirty = true;
}
void lovrModelGetNodeTransform(Model* model, uint32_t node, float position[4], float scale[4], float rotation[4], OriginType origin) {
@ -3299,7 +3315,7 @@ static void lovrModelReskin(Model* model) {
}
Shader* shader = state.animator;
gpu_layout* layout = state.layouts.data[state.animator->layout].gpu;
gpu_layout* layout = state.layouts.data[shader->layout].gpu;
gpu_buffer* joints = tempAlloc(gpu_sizeof_buffer());
uint32_t count = data->skinnedVertexCount;
@ -3343,7 +3359,71 @@ static void lovrModelReskin(Model* model) {
gpu_compute_end(state.stream);
model->lastReskin = state.tick;
state.hasReskin = true;
state.hasVertexAnimation = true;
}
static void lovrModelReblend(Model* model) {
if (model->blendGroupCount == 0 || model->lastReblend == state.tick || !model->blendShapesDirty) {
return;
}
if (!state.blender) {
state.blender = lovrShaderCreate(&(ShaderInfo) {
.type = SHADER_COMPUTE,
.source[0] = { lovr_shader_blender_comp, sizeof(lovr_shader_blender_comp) },
.flags = &(ShaderFlag) { NULL, 0, state.device.subgroupSize },
.flagCount = 1,
.label = "blender"
});
}
Shader* shader = state.blender;
gpu_layout* layout = state.layouts.data[shader->layout].gpu;
gpu_buffer* weightBuffer = tempAlloc(gpu_sizeof_buffer());
uint32_t vertexCount = model->info.data->dynamicVertexCount;
uint32_t blendBufferCursor = 0;
uint32_t chunkSize = 128;
gpu_binding bindings[] = {
{ 0, GPU_SLOT_STORAGE_BUFFER, .buffer = { model->rawVertexBuffer->gpu, 0, vertexCount * sizeof(ModelVertex) } },
{ 1, GPU_SLOT_STORAGE_BUFFER, .buffer = { model->vertexBuffer->gpu, 0, vertexCount * sizeof(ModelVertex) } },
{ 2, GPU_SLOT_STORAGE_BUFFER, .buffer = { model->blendBuffer->gpu, 0, model->blendBuffer->size } },
{ 3, GPU_SLOT_UNIFORM_BUFFER, .buffer = { weightBuffer, 0, chunkSize * sizeof(float) } }
};
gpu_compute_begin(state.stream);
gpu_bind_pipeline(state.stream, shader->computePipeline, GPU_PIPELINE_COMPUTE);
for (uint32_t i = 0; i < model->blendGroupCount; i++) {
BlendGroup* group = &model->blendGroups[i];
for (uint32_t j = 0; j < group->count; j += chunkSize) {
uint32_t count = MIN(group->count - j, chunkSize);
float* weights = gpu_map(weightBuffer, chunkSize * sizeof(float), state.limits.uniformBufferAlign, GPU_MAP_STREAM);
memcpy(weights, model->blendShapeWeights + group->index + j, count * sizeof(float));
gpu_bundle* bundle = getBundle(state.blender->layout);
gpu_bundle_info bundleInfo = { layout, bindings, COUNTOF(bindings) };
gpu_bundle_write(&bundle, &bundleInfo, 1);
uint32_t constants[] = { group->vertexIndex, group->vertexCount, j, count, blendBufferCursor };
uint32_t subgroupSize = state.device.subgroupSize;
gpu_push_constants(state.stream, shader->gpu, constants, sizeof(constants));
gpu_bind_bundles(state.stream, shader->gpu, &bundle, 0, 1, NULL, 0);
gpu_compute(state.stream, (group->vertexCount + subgroupSize - 1) / subgroupSize, 1, 1);
// TODO barrier if there's more to do
blendBufferCursor += group->vertexCount * count;
}
}
gpu_compute_end(state.stream);
model->lastReblend = state.tick;
model->blendShapesDirty = false;
state.hasVertexAnimation = true;
}
// Readback
@ -5648,6 +5728,10 @@ static void renderNode(Pass* pass, Model* model, uint32_t index, bool recurse, u
}
void lovrPassDrawModel(Pass* pass, Model* model, float* transform, uint32_t node, bool recurse, uint32_t instances) {
if (model->blendShapesDirty) {
lovrModelReblend(model);
}
if (model->transformsDirty) {
updateModelTransforms(model, model->info.data->rootNode, (float[]) MAT4_IDENTITY);
lovrModelReskin(model);