Frustum culling;

- Adds Pass:setViewCull to enable/disable frustum culling.
- Renames Pass:setCullMode to Pass:setFaceCull (with backcompat).

Some stuff currently missing:

- Text is not culled, but should be.
- VR view frusta are not merged yet.
This commit is contained in:
bjorn 2023-06-23 14:41:39 -07:00
parent 48a9bb0384
commit 10c2c75482
7 changed files with 214 additions and 74 deletions

View File

@ -1,4 +1,4 @@
float monkey_size[3] = { 1.367188f, 0.984375f, 0.851563f };
float monkey_bounds[6] = { 0.000000f, 0.000000f, 0.000000f, 0.683594f, 0.492188f, 0.425781f };
float monkey_offset[3] = { -0.683594f, -0.492188f, -0.425781f };
uint8_t monkey_vertices[] = {

View File

@ -11,14 +11,16 @@ for i = 1, model:getMeshVertexCount(1) do
max.x, max.y, max.z = math.max(x, max.x), math.max(y, max.y), math.max(z, max.z)
end
local size = lovr.math.newVec3(max - min)
local scale = .5
min:mul(scale)
max:mul(scale)
size:mul(scale)
io.write(('float monkey_size[3] = { %ff, %ff, %ff };\n'):format(size:unpack()))
local center = Vec3(max + min):mul(.5)
local extent = Vec3(max - min)
local halfExtent = extent / 2
local bounds = { center[1], center[2], center[3], halfExtent[1], halfExtent[2], halfExtent[3] }
io.write(('float monkey_bounds[6] = { %ff, %ff, %ff, %ff, %ff, %ff };\n'):format(unpack(bounds)))
io.write(('float monkey_offset[3] = { %ff, %ff, %ff };\n'):format(min:unpack()))
io.write('\n')
@ -28,7 +30,7 @@ for i = 1, model:getMeshVertexCount(1) do
local position = vec3(x, y, z):mul(scale)
local normal = vec3(nx, ny, nz)
local qx, qy, qz = ((position - min) / size * 255 + .5):unpack()
local qx, qy, qz = ((position - min) / extent * 255 + .5):unpack()
local qnx, qny, qnz = ((normal / 2 + .5) * 255 + .5):unpack()
qx, qy, qz = math.floor(qx), math.floor(qy), math.floor(qz)

View File

@ -26,7 +26,7 @@ function lovr.draw(pass)
local titlePosition = 1.5 - padding
local subtitlePosition = titlePosition - font:getHeight() * .25 - padding
pass:setCullMode('back')
pass:setFaceCull(true)
pass:setShader(logo)
pass:plane(0, 2, -3)
pass:setShader()

View File

@ -22,15 +22,15 @@ static int l_lovrPassAppend(lua_State* L) {
static int l_lovrPassGetStats(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
PassStats stats;
lovrPassGetStats(pass, &stats);
const PassStats* stats = lovrPassGetStats(pass);
lua_newtable(L);
lua_pushinteger(L, stats.draws), lua_setfield(L, -2, "draws");
lua_pushinteger(L, stats.computes), lua_setfield(L, -2, "computes");
lua_pushinteger(L, stats.memoryReserved), lua_setfield(L, -2, "memoryReserved");
lua_pushinteger(L, stats.memoryUsed), lua_setfield(L, -2, "memoryUsed");
lua_pushnumber(L, stats.submitTime), lua_setfield(L, -2, "submitTime");
lua_pushnumber(L, stats.gpuTime), lua_setfield(L, -2, "gpuTime");
lua_pushinteger(L, stats->draws), lua_setfield(L, -2, "draws");
lua_pushinteger(L, stats->computes), lua_setfield(L, -2, "computes");
lua_pushinteger(L, stats->drawsCulled), lua_setfield(L, -2, "drawsCulled");
lua_pushinteger(L, stats->memoryReserved), lua_setfield(L, -2, "memoryReserved");
lua_pushinteger(L, stats->memoryUsed), lua_setfield(L, -2, "memoryUsed");
lua_pushnumber(L, stats->submitTime), lua_setfield(L, -2, "submitTime");
lua_pushnumber(L, stats->gpuTime), lua_setfield(L, -2, "gpuTime");
return 1;
}
@ -493,13 +493,6 @@ static int l_lovrPassSetColorWrite(lua_State* L) {
return 0;
}
static int l_lovrPassSetCullMode(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
CullMode mode = luax_checkenum(L, 2, CullMode, "none");
lovrPassSetCullMode(pass, mode);
return 0;
}
static int l_lovrPassSetDepthTest(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
CompareMode test = luax_checkcomparemode(L, 2);
@ -529,6 +522,18 @@ static int l_lovrPassSetDepthClamp(lua_State* L) {
return 0;
}
static int l_lovrPassSetFaceCull(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
CullMode mode;
if (lua_type(L, 2) == LUA_TBOOLEAN) {
mode = lua_toboolean(L, 2) ? CULL_BACK : CULL_NONE;
} else {
mode = luax_checkenum(L, 2, CullMode, "none");
}
lovrPassSetFaceCull(pass, mode);
return 0;
}
static int l_lovrPassSetFont(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
Font* font = luax_totype(L, 2, Font);
@ -616,6 +621,13 @@ static int l_lovrPassSetStencilWrite(lua_State* L) {
return 0;
}
static int l_lovrPassSetViewCull(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
bool enable = lua_toboolean(L, 2);
lovrPassSetViewCull(pass, enable);
return 0;
}
static int l_lovrPassSetWinding(lua_State* L) {
Pass* pass = luax_checktype(L, 1, Pass);
Winding winding = luax_checkenum(L, 2, Winding, NULL);
@ -1086,11 +1098,11 @@ const luaL_Reg lovrPass[] = {
{ "setBlendMode", l_lovrPassSetBlendMode },
{ "setColor", l_lovrPassSetColor },
{ "setColorWrite", l_lovrPassSetColorWrite },
{ "setCullMode", l_lovrPassSetCullMode },
{ "setDepthTest", l_lovrPassSetDepthTest },
{ "setDepthWrite", l_lovrPassSetDepthWrite },
{ "setDepthOffset", l_lovrPassSetDepthOffset },
{ "setDepthClamp", l_lovrPassSetDepthClamp },
{ "setFaceCull", l_lovrPassSetFaceCull },
{ "setFont", l_lovrPassSetFont },
{ "setMaterial", l_lovrPassSetMaterial },
{ "setMeshMode", l_lovrPassSetMeshMode },
@ -1098,6 +1110,7 @@ const luaL_Reg lovrPass[] = {
{ "setShader", l_lovrPassSetShader },
{ "setStencilTest", l_lovrPassSetStencilTest },
{ "setStencilWrite", l_lovrPassSetStencilWrite },
{ "setViewCull", l_lovrPassSetViewCull },
{ "setWinding", l_lovrPassSetWinding },
{ "setWireframe", l_lovrPassSetWireframe },
@ -1135,6 +1148,7 @@ const luaL_Reg lovrPass[] = {
{ "getType", l_lovrPassGetType },
{ "getTarget", l_lovrPassGetCanvas },
{ "getSampleCount", l_lovrPassGetSampleCount },
{ "setCullMode", l_lovrPassSetFaceCull },
{ NULL, NULL }
};

View File

@ -98,6 +98,14 @@ MAF vec3 vec3_lerp(vec3 v, const vec3 u, float t) {
return v;
}
MAF vec3 vec3_abs(vec3 v) {
v[0] = fabsf(v[0]);
v[1] = fabsf(v[1]);
v[2] = fabsf(v[2]);
v[3] = fabsf(v[3]);
return v;
}
MAF float vec3_angle(const vec3 v, const vec3 u) {
float denom = vec3_length(v) * vec3_length(u);
if (denom == 0.f) {

View File

@ -195,6 +195,7 @@ typedef struct {
DefaultShader shader;
Material* material;
float* transform;
float* bounds;
struct {
Buffer* buffer;
VertexFormat format;
@ -237,6 +238,7 @@ struct Model {
Material** materials;
NodeTransform* localTransforms;
float* globalTransforms;
float* boundingBoxes;
bool transformsDirty;
bool blendShapesDirty;
float* blendShapeWeights;
@ -325,7 +327,8 @@ enum {
enum {
DIRTY_BINDINGS = (1 << 0),
DIRTY_CONSTANTS = (1 << 1),
DIRTY_CAMERA = (1 << 2)
DIRTY_CAMERA = (1 << 2),
NEEDS_VIEW_CULL = (1 << 3)
};
typedef struct {
@ -388,6 +391,7 @@ typedef struct {
typedef struct {
bool dirty;
bool viewCull;
MeshMode mode;
float color[4];
Buffer* lastVertexBuffer;
@ -425,7 +429,8 @@ typedef struct {
enum {
DRAW_INDIRECT = (1 << 0),
DRAW_INDEX32 = (1 << 1),
DRAW_INLINE_MESH = (1 << 2)
DRAW_INLINE_MESH = (1 << 2),
DRAW_HAS_BOUNDS = (1 << 3)
};
typedef struct {
@ -457,6 +462,7 @@ typedef struct {
};
float transform[16];
float color[4];
float bounds[6];
} Draw;
typedef struct {
@ -498,8 +504,7 @@ struct Pass {
Compute* computes;
Draw** draws;
Draw* lastDraw;
double submitTime;
double gpuTime;
PassStats stats;
};
typedef struct {
@ -1025,7 +1030,7 @@ void lovrGraphicsSetTimingEnabled(bool enable) {
state.timingEnabled = enable;
}
static void submitComputes(Pass* pass, gpu_stream* stream) {
static void recordComputePass(Pass* pass, gpu_stream* stream) {
if (pass->computeCount == 0) {
return;
}
@ -1075,7 +1080,7 @@ static void submitComputes(Pass* pass, gpu_stream* stream) {
gpu_compute_end(stream);
}
static void submitDraws(Pass* pass, gpu_stream* stream) {
static void recordRenderPass(Pass* pass, gpu_stream* stream) {
Canvas* canvas = &pass->canvas;
if (canvas->count == 0 && !canvas->depth.texture) {
@ -1114,7 +1119,95 @@ static void submitDraws(Pass* pass, gpu_stream* stream) {
};
}
if (pass->drawCount == 0) {
// Cameras
Camera* camera = pass->cameras;
for (uint32_t c = 0; c < pass->cameraCount; c++) {
for (uint32_t v = 0; v < canvas->views; v++, camera++) {
mat4_init(camera->viewProjection, camera->projection);
mat4_init(camera->inverseProjection, camera->projection);
mat4_mul(camera->viewProjection, camera->viewMatrix);
mat4_invert(camera->inverseProjection);
}
}
// Frustum Culling
uint32_t activeDrawCount = 0;
uint16_t* activeDraws = tempAlloc(&state.allocator, pass->drawCount * sizeof(uint16_t));
if (pass->flags & NEEDS_VIEW_CULL) {
typedef struct { float planes[6][4]; } Frustum;
Frustum* frusta = tempAlloc(&state.allocator, canvas->views * sizeof(Frustum));
uint32_t drawIndex = 0;
for (uint32_t c = 0; c < pass->cameraCount; c++) {
for (uint32_t v = 0; v < canvas->views; v++) {
float* m = pass->cameras[c * canvas->views + v].viewProjection;
memcpy(frusta[v].planes, (float[6][4]) {
{ (m[3] + m[0]), (m[7] + m[4]), (m[11] + m[8]), (m[15] + m[12]) }, // Left
{ (m[3] - m[0]), (m[7] - m[4]), (m[11] - m[8]), (m[15] - m[12]) }, // Right
{ (m[3] + m[1]), (m[7] + m[5]), (m[11] + m[9]), (m[15] + m[13]) }, // Bottom
{ (m[3] - m[1]), (m[7] - m[5]), (m[11] - m[9]), (m[15] - m[13]) }, // Top
{ m[2], m[6], m[10], m[14] }, // Near
{ (m[3] - m[2]), (m[7] - m[6]), (m[11] - m[10]), (m[15] - m[14]) } // Far
}, sizeof(Frustum));
}
while (drawIndex < pass->drawCount) {
Draw* draw = &pass->draws[drawIndex >> 8][drawIndex & 0xff];
if (draw->camera != c) {
break;
}
if (~draw->flags & DRAW_HAS_BOUNDS) {
activeDraws[activeDrawCount++] = drawIndex++;
continue;
}
float center[4] = { draw->bounds[0], draw->bounds[1], draw->bounds[2], 1.f };
float extent[4] = { draw->bounds[3], draw->bounds[4], draw->bounds[5], 0.f };
mat4_mulVec4(draw->transform, center);
mat4_transformDirection(draw->transform, extent);
vec3_abs(extent);
uint32_t visible = canvas->views;
for (uint32_t v = 0; v < canvas->views; v++) {
for (uint32_t p = 0; p < 6; p++) {
float* plane = frusta[v].planes[p];
float absPlane[4];
vec3_init(absPlane, plane);
vec3_abs(absPlane);
bool inside = vec3_dot(center, plane) + vec3_dot(extent, absPlane) > -plane[3];
if (!inside) {
visible--;
break;
}
}
}
if (visible) {
activeDraws[activeDrawCount++] = drawIndex;
}
drawIndex++;
}
}
} else {
for (uint32_t i = 0; i < pass->drawCount; i++) {
activeDraws[activeDrawCount++] = i;
}
}
pass->stats.drawsCulled = pass->drawCount - activeDrawCount;
if (activeDrawCount == 0) {
gpu_render_begin(stream, &target);
gpu_render_end(stream);
return;
@ -1151,32 +1244,20 @@ static void submitDraws(Pass* pass, gpu_stream* stream) {
global->resolution[1] = canvas->height;
global->time = lovrHeadsetInterface ? lovrHeadsetInterface->getDisplayTime() : os_get_time();
// Cameras
Camera* camera = pass->cameras;
for (uint32_t i = 0; i < pass->cameraCount; i++) {
for (uint32_t j = 0; j < canvas->views; j++, camera++) {
mat4_init(camera->viewProjection, camera->projection);
mat4_init(camera->inverseProjection, camera->projection);
mat4_mul(camera->viewProjection, camera->viewMatrix);
mat4_invert(camera->inverseProjection);
}
}
mapped = mapBuffer(&state.streamBuffers, pass->cameraCount * canvas->views * sizeof(Camera), align);
builtins[1].buffer = (gpu_buffer_binding) { mapped.buffer, mapped.offset, mapped.extent };
memcpy(mapped.pointer, pass->cameras, pass->cameraCount * canvas->views * sizeof(Camera));
// DrawData
uint32_t drawPageCount = (pass->drawCount + 255) / 256;
uint32_t drawPageCount = (activeDrawCount + 255) / 256;
uint32_t drawPageSize = (uint32_t) ALIGN(256 * sizeof(DrawData), align);
mapped = mapBuffer(&state.streamBuffers, drawPageCount * drawPageSize, align);
builtins[2].buffer = (gpu_buffer_binding) { mapped.buffer, mapped.offset, drawPageSize };
DrawData* data = mapped.pointer;
for (uint32_t i = 0; i < pass->drawCount; i++, data++) {
Draw* draw = &pass->draws[i >> 8][i & 0xff];
for (uint32_t i = 0; i < activeDrawCount; i++, data++) {
Draw* draw = &pass->draws[activeDraws[i] >> 8][activeDraws[i] & 0xff];
if ((i & 0xff) == 0) {
data = (DrawData*) ALIGN(data, align);
@ -1234,8 +1315,8 @@ static void submitDraws(Pass* pass, gpu_stream* stream) {
// Bundles
Draw* prev = NULL;
for (uint32_t i = 0; i < pass->drawCount; i++) {
Draw* draw = &pass->draws[i >> 8][i & 0xff];
for (uint32_t i = 0; i < activeDrawCount; i++) {
Draw* draw = &pass->draws[activeDraws[i] >> 8][activeDraws[i] & 0xff];
if (i > 0 && draw->bundleInfo == prev->bundleInfo) {
draw->bundle = prev->bundle;
@ -1302,8 +1383,8 @@ static void submitDraws(Pass* pass, gpu_stream* stream) {
gpu_bind_vertex_buffers(stream, &state.defaultBuffer->gpu, NULL, 1, 1);
for (uint32_t i = 0; i < pass->drawCount; i++) {
Draw* draw = &pass->draws[i >> 8][i & 0xff];
for (uint32_t i = 0; i < activeDrawCount; i++) {
Draw* draw = &pass->draws[activeDraws[i] >> 8][activeDraws[i] & 0xff];
bool constantsDirty = draw->constants != constants;
if (draw->tally != tally) {
@ -1585,10 +1666,10 @@ void lovrGraphicsSubmit(Pass** passes, uint32_t count) {
gpu_tally_mark(stream, state.timestamps, 2 * i + 0);
}
submitComputes(passes[i], stream);
recordComputePass(passes[i], stream);
if (i < barrierCount) gpu_sync(stream, &computeBarriers[i], 1);
submitDraws(passes[i], stream);
recordRenderPass(passes[i], stream);
if (i < barrierCount) gpu_sync(stream, &renderBarriers[i], 1);
if (state.timingEnabled) {
@ -3698,9 +3779,11 @@ Model* lovrModelCreate(const ModelInfo* info) {
// Draws
model->draws = calloc(data->primitiveCount, sizeof(DrawInfo));
lovrAssert(model->draws, "Out of memory");
model->boundingBoxes = malloc(data->primitiveCount * 6 * sizeof(float));
lovrAssert(model->draws && model->boundingBoxes, "Out of memory");
for (uint32_t i = 0, vertexCursor = 0, indexCursor = 0; i < data->primitiveCount; i++) {
ModelPrimitive* primitive = &data->primitives[primitiveOrder[i] & ~0u];
ModelAttribute* position = primitive->attributes[ATTR_POSITION];
DrawInfo* draw = &model->draws[primitiveOrder[i] & ~0u];
switch (primitive->mode) {
@ -3721,11 +3804,19 @@ Model* lovrModelCreate(const ModelInfo* info) {
indexCursor += draw->count;
} else {
draw->start = vertexCursor;
draw->count = primitive->attributes[ATTR_POSITION]->count;
draw->count = position->count;
}
draw->bounds = model->boundingBoxes + i * 6;
draw->bounds[0] = (position->min[0] + position->max[0]) / 2.f;
draw->bounds[1] = (position->min[1] + position->max[1]) / 2.f;
draw->bounds[2] = (position->min[2] + position->max[2]) / 2.f;
draw->bounds[3] = (position->max[0] - position->min[0]) / 2.f;
draw->bounds[4] = (position->max[1] - position->min[1]) / 2.f;
draw->bounds[5] = (position->max[2] - position->min[2]) / 2.f;
baseVertex[i] = vertexCursor;
vertexCursor += primitive->attributes[ATTR_POSITION]->count;
vertexCursor += position->count;
}
// Vertices
@ -3898,6 +3989,7 @@ void lovrModelDestroy(void* ref) {
lovrRelease(model->info.data, lovrModelDataDestroy);
free(model->localTransforms);
free(model->globalTransforms);
free(model->boundingBoxes);
free(model->blendShapeWeights);
free(model->blendGroups);
free(model->draws);
@ -4777,13 +4869,12 @@ void lovrPassAppend(Pass* pass, Pass* other) {
pass->flags &= ~DIRTY_CAMERA;
}
void lovrPassGetStats(Pass* pass, PassStats* stats) {
stats->draws = pass->drawCount;
stats->computes = pass->computeCount;
stats->memoryReserved = pass->allocator.length;
stats->memoryUsed = pass->allocator.cursor;
stats->submitTime = pass->submitTime;
stats->gpuTime = pass->gpuTime;
const PassStats* lovrPassGetStats(Pass* pass) {
pass->stats.draws = pass->drawCount;
pass->stats.computes = pass->computeCount;
pass->stats.memoryReserved = pass->allocator.length;
pass->stats.memoryUsed = pass->allocator.cursor;
return &pass->stats;
}
void lovrPassGetCanvas(Pass* pass, Texture* textures[4], Texture** depthTexture, uint32_t* depthFormat, uint32_t* samples) {
@ -5110,11 +5201,6 @@ void lovrPassSetColorWrite(Pass* pass, uint32_t index, bool r, bool g, bool b, b
pass->pipeline->info.color[index].mask = mask;
}
void lovrPassSetCullMode(Pass* pass, CullMode mode) {
pass->pipeline->dirty |= pass->pipeline->info.rasterizer.cullMode != (gpu_cull_mode) mode;
pass->pipeline->info.rasterizer.cullMode = (gpu_cull_mode) mode;
}
void lovrPassSetDepthTest(Pass* pass, CompareMode test) {
pass->pipeline->dirty |= pass->pipeline->info.depth.test != (gpu_compare_mode) test;
pass->pipeline->info.depth.test = (gpu_compare_mode) test;
@ -5138,6 +5224,11 @@ void lovrPassSetDepthClamp(Pass* pass, bool clamp) {
}
}
void lovrPassSetFaceCull(Pass* pass, CullMode mode) {
pass->pipeline->dirty |= pass->pipeline->info.rasterizer.cullMode != (gpu_cull_mode) mode;
pass->pipeline->info.rasterizer.cullMode = (gpu_cull_mode) mode;
}
void lovrPassSetFont(Pass* pass, Font* font) {
if (pass->pipeline->font != font) {
lovrRetain(font);
@ -5292,6 +5383,10 @@ void lovrPassSetStencilWrite(Pass* pass, StencilAction actions[3], uint8_t value
pass->pipeline->dirty = true;
}
void lovrPassSetViewCull(Pass* pass, bool enable) {
pass->pipeline->viewCull = enable;
}
void lovrPassSetWinding(Pass* pass, Winding winding) {
pass->pipeline->dirty |= pass->pipeline->info.rasterizer.winding != (gpu_winding) winding;
pass->pipeline->info.rasterizer.winding = (gpu_winding) winding;
@ -5616,6 +5711,12 @@ void lovrPassDraw(Pass* pass, DrawInfo* info) {
draw->bundleInfo = lovrPassResolveBindings(pass, draw->shader, pass->lastDraw ? pass->lastDraw->bundleInfo : NULL);
draw->constants = lovrPassResolveConstants(pass, draw->shader, pass->lastDraw ? pass->lastDraw->constants : NULL);
if (pass->pipeline->viewCull && info->bounds) {
memcpy(draw->bounds, info->bounds, sizeof(draw->bounds));
draw->flags |= DRAW_HAS_BOUNDS;
pass->flags |= NEEDS_VIEW_CULL;
}
mat4_init(draw->transform, pass->transform);
if (info->transform) mat4_mul(draw->transform, info->transform);
memcpy(draw->color, pass->pipeline->color, 4 * sizeof(float));
@ -5667,6 +5768,7 @@ void lovrPassPlane(Pass* pass, float* transform, DrawStyle style, uint32_t cols,
.hash = hash64(key, sizeof(key)),
.mode = MESH_LINES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, .5f, .5f, 0.f },
.vertex.pointer = (void**) &vertices,
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
@ -5679,6 +5781,7 @@ void lovrPassPlane(Pass* pass, float* transform, DrawStyle style, uint32_t cols,
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, .5f, .5f, 0.f },
.vertex.pointer = (void**) &vertices,
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
@ -5764,6 +5867,7 @@ void lovrPassRoundrect(Pass* pass, float* transform, float r, uint32_t segments)
lovrPassDraw(pass, &(DrawInfo) {
.mode = MESH_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, .5f, .5f, .5f },
.vertex.pointer = (void**) &vertices,
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
@ -5892,6 +5996,7 @@ void lovrPassBox(Pass* pass, float* transform, DrawStyle style) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_LINES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, .5f, .5f, .5f },
.vertex.pointer = (void**) &vertices,
.vertex.count = COUNTOF(vertexData),
.index.pointer = (void**) &indices,
@ -5943,6 +6048,7 @@ void lovrPassBox(Pass* pass, float* transform, DrawStyle style) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, .5f, .5f, .5f },
.vertex.pointer = (void**) &vertices,
.vertex.count = COUNTOF(vertexData),
.index.pointer = (void**) &indices,
@ -5974,6 +6080,7 @@ void lovrPassCircle(Pass* pass, float* transform, DrawStyle style, float angle1,
.hash = hash64(key, sizeof(key)),
.mode = MESH_LINES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, 1.f, 1.f, 0.f },
.vertex.pointer = (void**) &vertices,
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
@ -5991,6 +6098,7 @@ void lovrPassCircle(Pass* pass, float* transform, DrawStyle style, float angle1,
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, 1.f, 1.f, 0.f },
.vertex.pointer = (void**) &vertices,
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
@ -6040,6 +6148,7 @@ void lovrPassSphere(Pass* pass, float* transform, uint32_t segmentsH, uint32_t s
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, 1.f, 1.f, 1.f },
.vertex.pointer = (void**) &vertices,
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
@ -6125,6 +6234,7 @@ void lovrPassCylinder(Pass* pass, float* transform, bool capped, float angle1, f
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, 1.f, 1.f, .5f },
.vertex.pointer = (void**) &vertices,
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
@ -6197,6 +6307,7 @@ void lovrPassCone(Pass* pass, float* transform, uint32_t segments) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.0f, 0.f, -.5f, 1.f, 1.f, .5f },
.vertex.pointer = (void**) &vertices,
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
@ -6261,6 +6372,7 @@ void lovrPassCapsule(Pass* pass, float* transform, uint32_t segments) {
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, radius, radius, length + radius },
.vertex.pointer = (void**) &vertices,
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
@ -6353,6 +6465,7 @@ void lovrPassTorus(Pass* pass, float* transform, uint32_t segmentsT, uint32_t se
.hash = hash64(key, sizeof(key)),
.mode = MESH_TRIANGLES,
.transform = transform,
.bounds = (float[6]) { 0.f, 0.f, 0.f, radius + thickness, radius + thickness, thickness },
.vertex.pointer = (void**) &vertices,
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
@ -6476,7 +6589,8 @@ void lovrPassMonkey(Pass* pass, float* transform) {
.vertex.count = vertexCount,
.index.pointer = (void**) &indices,
.index.count = COUNTOF(monkey_indices),
.transform = transform
.transform = transform,
.bounds = monkey_bounds
});
if (!vertices) {
@ -6486,9 +6600,9 @@ void lovrPassMonkey(Pass* pass, float* transform) {
// Manual vertex format conversion to avoid another format (and sn8x3 isn't always supported)
for (uint32_t i = 0; i < vertexCount; i++) {
vertices[i] = (ShapeVertex) {
.position.x = monkey_vertices[6 * i + 0] / 255.f * monkey_size[0] + monkey_offset[0],
.position.y = monkey_vertices[6 * i + 1] / 255.f * monkey_size[1] + monkey_offset[1],
.position.z = monkey_vertices[6 * i + 2] / 255.f * monkey_size[2] + monkey_offset[2],
.position.x = monkey_vertices[6 * i + 0] / 255.f * monkey_bounds[3] * 2.f + monkey_offset[0],
.position.y = monkey_vertices[6 * i + 1] / 255.f * monkey_bounds[4] * 2.f + monkey_offset[1],
.position.z = monkey_vertices[6 * i + 2] / 255.f * monkey_bounds[5] * 2.f + monkey_offset[2],
.normal.x = monkey_vertices[6 * i + 3] / 255.f * 2.f - 1.f,
.normal.y = monkey_vertices[6 * i + 4] / 255.f * 2.f - 1.f,
.normal.z = monkey_vertices[6 * i + 5] / 255.f * 2.f - 1.f,
@ -6858,8 +6972,8 @@ static void processReadbacks(void) {
uint32_t* timestamps = readback->mapped.pointer;
for (uint32_t i = 0; i < readback->count; i++) {
Pass* pass = readback->times[i].pass;
pass->submitTime = readback->times[i].cpuTime;
pass->gpuTime = (timestamps[2 * i + 1] - timestamps[2 * i + 0]) * state.limits.timestampPeriod / 1e9;
pass->stats.submitTime = readback->times[i].cpuTime;
pass->stats.gpuTime = (timestamps[2 * i + 1] - timestamps[2 * i + 0]) * state.limits.timestampPeriod / 1e9;
}
break;
default: break;

View File

@ -478,6 +478,7 @@ struct Image* lovrReadbackGetImage(Readback* readback);
typedef struct {
uint32_t draws;
uint32_t computes;
uint32_t drawsCulled;
size_t memoryReserved;
size_t memoryUsed;
double submitTime;
@ -544,7 +545,7 @@ Pass* lovrPassCreate(void);
void lovrPassDestroy(void* ref);
void lovrPassReset(Pass* pass);
void lovrPassAppend(Pass* pass, Pass* other);
void lovrPassGetStats(Pass* pass, PassStats* stats);
const PassStats* lovrPassGetStats(Pass* pass);
void lovrPassGetCanvas(Pass* pass, Texture* color[4], Texture** depthTexture, uint32_t* depthFormat, uint32_t* samples);
void lovrPassSetCanvas(Pass* pass, Texture* color[4], Texture* depthTexture, uint32_t depthFormat, uint32_t samples);
@ -576,11 +577,11 @@ void lovrPassSetAlphaToCoverage(Pass* pass, bool enabled);
void lovrPassSetBlendMode(Pass* pass, uint32_t index, BlendMode mode, BlendAlphaMode alphaMode);
void lovrPassSetColor(Pass* pass, float color[4]);
void lovrPassSetColorWrite(Pass* pass, uint32_t index, bool r, bool g, bool b, bool a);
void lovrPassSetCullMode(Pass* pass, CullMode mode);
void lovrPassSetDepthTest(Pass* pass, CompareMode test);
void lovrPassSetDepthWrite(Pass* pass, bool write);
void lovrPassSetDepthOffset(Pass* pass, float offset, float sloped);
void lovrPassSetDepthClamp(Pass* pass, bool clamp);
void lovrPassSetFaceCull(Pass* pass, CullMode mode);
void lovrPassSetFont(Pass* pass, Font* font);
void lovrPassSetMaterial(Pass* pass, Material* material, Texture* texture);
void lovrPassSetMeshMode(Pass* pass, MeshMode mode);
@ -588,6 +589,7 @@ void lovrPassSetSampler(Pass* pass, Sampler* sampler);
void lovrPassSetShader(Pass* pass, Shader* shader);
void lovrPassSetStencilTest(Pass* pass, CompareMode test, uint8_t value, uint8_t mask);
void lovrPassSetStencilWrite(Pass* pass, StencilAction actions[3], uint8_t value, uint8_t mask);
void lovrPassSetViewCull(Pass* pass, bool enable);
void lovrPassSetWinding(Pass* pass, Winding winding);
void lovrPassSetWireframe(Pass* pass, bool wireframe);