mirror of https://github.com/bjornbytes/lovr.git
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:
parent
48a9bb0384
commit
10c2c75482
|
@ -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[] = {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue