Skip to content

Commit

Permalink
rewriting render pipeline 3 WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
malytomas committed Jan 12, 2025
1 parent 446c9ed commit 2285291
Showing 1 changed file with 101 additions and 56 deletions.
157 changes: 101 additions & 56 deletions sources/libengine/graphics/renderPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ namespace cage
FontLayoutResult layout;
Holder<const Font> font;
Vec3 color;
sint32 renderLayer = 0;
};

struct RenderData : private Noncopyable
Expand Down Expand Up @@ -138,7 +139,7 @@ namespace cage

struct CameraData : private Noncopyable
{
std::map<Entity *, struct RenderPipelineImpl> shadowmaps;
std::map<Entity *, Holder<struct RenderPipelineImpl>> shadowmaps;
uint32 lightsCount = 0;
uint32 shadowedLightsCount = 0;
};
Expand Down Expand Up @@ -580,15 +581,17 @@ namespace cage
const auto armature = rm.skeletalAnimation->armature();
for (uint32 i = 0; i < armature.size(); i++)
{
RenderData pd;
RenderModel pm;
pm.mesh = modelBone.share();
pd.model = rd.model * Mat4(armature[i]);
pm.uni = initializeMeshUni(pd.model);
pm.uni.color = Vec4(colorGammaToLinear(colorHsvToRgb(Vec3(Real(i) / Real(armature.size()), 1, 1))), 1);
pm.uni.normalMat.data[2][3] = rm.uni.normalMat.data[2][3];
pd.data = std::move(pm);
renderData.push_back(std::move(pd));
RenderData d;
d.model = rd.model * Mat4(armature[i]);
d.e = rd.e;
d.depth = rd.depth;
RenderModel r;
r.mesh = modelBone.share();
r.uni = initializeMeshUni(d.model);
r.uni.color = Vec4(colorGammaToLinear(colorHsvToRgb(Vec3(Real(i) / Real(armature.size()), 1, 1))), 1);
r.uni.normalMat.data[2][3] = rm.uni.normalMat.data[2][3];
d.data = std::move(r);
renderData.push_back(std::move(d));
}
}

Expand Down Expand Up @@ -688,10 +691,10 @@ namespace cage
ps.reset();
}

rd.translucent = any(rm.mesh->flags & (MeshRenderFlags::Transparent | MeshRenderFlags::Fade)) || rm.render.opacity < 1;
rm.uni.normalMat.data[2][3] = any(rm.mesh->flags & MeshRenderFlags::Lighting) ? 1 : 0; // is lighting enabled
rm.uni.normalMat.data[1][3] = any(rm.mesh->flags & MeshRenderFlags::Fade) ? 1 : 0; // transparent mode is to fade
rd.depth = (rm.uni.mvpMat * Vec4(0, 0, 0, 1))[2];
rd.translucent = any(rm.mesh->flags & (MeshRenderFlags::Transparent | MeshRenderFlags::Fade)) || rm.render.opacity < 1;

if (rm.skeletalAnimation && cnfRenderSkeletonBones)
prepareModelBones(rd);
Expand All @@ -701,8 +704,10 @@ namespace cage

void prepareObject(const RenderData &rd, Holder<RenderObject> object)
{
CAGE_ASSERT(std::holds_alternative<std::monostate>(rd.data));
CAGE_ASSERT(object->lodsCount() > 0);
CAGE_ASSERT(std::holds_alternative<RenderModel>(rd.data));
const RenderModel &rm = std::get<RenderModel>(rd.data);
CAGE_ASSERT(!rm.mesh);

uint32 preferredLod = 0;
if (object->lodsCount() > 1)
Expand Down Expand Up @@ -746,18 +751,50 @@ namespace cage
// render selected lod
for (auto &it : models)
{
RenderModel rm;
rm.mesh = std::move(it);
RenderData pr;
pr.model = rd.model;
pr.depth = rd.depth;
pr.e = rd.e;
pr.translucent = rd.translucent;
pr.data = std::move(rm);
prepareModel(pr, +object);
RenderData d;
d.model = rd.model;
d.e = rd.e;
RenderModel r;
r.uni = rm.uni;
r.frustum = rm.frustum;
r.customShaderData = rm.customShaderData;
r.render = rm.render;
r.textureAnimation = rm.textureAnimation;
r.skeletalAnimation = rm.skeletalAnimation.share();
r.mesh = std::move(it);
d.data = std::move(r);
prepareModel(d, +object);
}
}

void prepareText(Entity *e, TextComponent tc)
{
if (!tc.font)
tc.font = detail::GuiTextFontDefault;
if (!tc.font)
tc.font = HashString("cage/font/ubuntu/regular.ttf");
RenderText rt;
rt.font = assets->get<AssetSchemeIndexFont, Font>(tc.font);
if (!rt.font)
return;
FontFormat format;
format.size = 1;
format.align = tc.align;
format.lineSpacing = tc.lineSpacing;
const String str = textsGet(tc.textId, tc.value);
rt.layout = rt.font->layout(str, format);
if (rt.layout.glyphs.empty())
return;
rt.color = colorGammaToLinear(tc.color) * tc.intensity;
rt.renderLayer = tc.renderLayer;
RenderData rd;
rd.model = modelTransform(e) * Mat4(Vec3(rt.layout.size * Vec2(-0.5, 0.5), 0));
rd.depth = (viewProj * rd.model * Vec4(0, 0, 0, 1))[2];
rd.translucent = true;
rd.data = std::move(rt);
renderData.push_back(std::move(rd));
}

void prepareEntities()
{
entitiesVisitor(
Expand All @@ -766,8 +803,8 @@ namespace cage
if ((rc.sceneMask & camera.sceneMask) == 0)
return;
RenderData rd;
rd.e = e;
rd.model = modelTransform(e);
rd.e = e;
RenderModel rm;
rm.uni = initializeMeshUni(rd.model);
rm.frustum = Frustum(rm.uni.mvpMat);
Expand Down Expand Up @@ -798,37 +835,41 @@ namespace cage
+scene, false);

entitiesVisitor(
[&](Entity *e, const TextComponent &tc_)
[&](Entity *e, const TextComponent &tc)
{
if ((tc_.sceneMask & camera.sceneMask) == 0)
return;
TextComponent tc = tc_;
RenderText rt;
if (!tc.font)
tc.font = detail::GuiTextFontDefault;
if (!tc.font)
tc.font = HashString("cage/font/ubuntu/regular.ttf");
rt.font = assets->get<AssetSchemeIndexFont, Font>(tc.font);
if (!rt.font)
if ((tc.sceneMask & camera.sceneMask) == 0)
return;
FontFormat format;
format.size = 1;
format.align = tc.align;
format.lineSpacing = tc.lineSpacing;
const String str = textsGet(tc.textId, tc.value);
rt.layout = rt.font->layout(str, format);
if (rt.layout.glyphs.empty())
return;
rt.color = colorGammaToLinear(tc.color) * tc.intensity;
RenderData rd;
rd.model = modelTransform(e) * Mat4(Vec3(rt.layout.size * Vec2(-0.5, 0.5), 0));
rd.data = std::move(rt);
rd.translucent = true;
renderData.push_back(std::move(rd));
prepareText(e, tc);
},
+scene, false);
}

void sortRenderData()
{
std::sort(renderData.begin(), renderData.end(),
[](const RenderData &a, const RenderData &b) -> bool
{
const auto &cmp = [](const RenderData &d)
{
// reduce switching shaders, then depth test/writes and other states, then meshes
const auto tmp = std::visit(
[](const auto &r) -> std::tuple<sint32, uint32, MeshRenderFlags, Model *, bool>
{
using T = std::decay_t<decltype(r)>;
if constexpr (std::is_same_v<T, RenderText>)
return { r.renderLayer, 0, MeshRenderFlags(), (Model *)nullptr, false };
if constexpr (std::is_same_v<T, RenderModel>)
return { r.render.renderLayer + r.mesh->layer, r.mesh->shaderName, r.mesh->flags, +r.mesh, !!r.skeletalAnimation };
return {};
},
d.data);
// opaque first, translucent last; translucent is ordered back-to-front, opaque is ordered front-to-back
return std::tuple{ d.translucent, -d.depth * d.translucent, tmp, d.depth * !d.translucent };
};
return cmp(a) < cmp(b);
});
}

void taskShadowmap()
{
CAGE_ASSERT(!data);
Expand All @@ -850,6 +891,7 @@ namespace cage
renderQueue->checkGlErrorDebug();

prepareEntities();
sortRenderData();
renderPass(RenderModeEnum::Shadowmap);

renderQueue->resetFrameBuffer();
Expand Down Expand Up @@ -892,8 +934,8 @@ namespace cage
texCube.reserve(CAGE_SHADER_MAX_SHADOWMAPSCUBE);
for (auto &[e, sh_] : data->shadowmaps)
{
CAGE_ASSERT(sh_.shadowmap);
ShadowmapData &sh = *sh_.shadowmap;
CAGE_ASSERT(sh_->shadowmap);
ShadowmapData &sh = *sh_->shadowmap;
if (sh.lightComponent.lightType == LightTypeEnum::Point)
{
if (texCube.size() == CAGE_SHADER_MAX_SHADOWMAPSCUBE)
Expand Down Expand Up @@ -933,6 +975,7 @@ namespace cage
view = inverse(model);
viewProj = projection * view;
prepareEntities();
sortRenderData();
prepareCameraLights();

TextureHandle colorTexture = provisionalGraphics->texture(Stringizer() + "colorTarget_" + name + "_" + resolution,
Expand Down Expand Up @@ -1154,10 +1197,13 @@ namespace cage
}
}

Holder<AsyncTask> prepareShadowmap(Entity *e, const LightComponent &lc, const ShadowmapComponent &sc) const
Holder<AsyncTask> prepareShadowmap(Entity *e, const LightComponent &lc, const ShadowmapComponent &sc)
{
Holder<RenderPipelineImpl> data = systemMemory().createHolder<RenderPipelineImpl>(this);
CAGE_ASSERT(e->id() != 0); // lights with shadowmap may not be anonymous

Holder<RenderPipelineImpl> data = systemMemory().createHolder<RenderPipelineImpl>(this);
this->data->shadowmaps[e] = data.share();

data->name = Stringizer() + name + "_shadowmap_" + e->id();
data->shadowmap = ShadowmapData();
ShadowmapData &shadowmap = *data->shadowmap;
Expand Down Expand Up @@ -1246,7 +1292,7 @@ namespace cage

// ensure that shadowmaps are rendered before the camera
for (auto &shm : data->shadowmaps)
queue->enqueue(std::move(shm.second.renderQueue));
queue->enqueue(std::move(shm.second->renderQueue));

queue->enqueue(std::move(renderQueue));
return queue;
Expand Down Expand Up @@ -1279,14 +1325,13 @@ namespace cage
}

// todo list:
// sort draw calls
// find consecutive instances
// renderLayer (mesh, RenderComponent, text)
// reduce size of RenderModel (remove frustum, possibly some more)
// opacity for text
// consider parallelizing frustum culling
// consider shadows for text
// vectors (meshes, armatures, customShaderData) should be reused
// assert std::holds_alternative in prepareObject
// interpolated camera transform
// shadowmaps currently broken
// reserve renderData
// shaderanim example: unknown shader variant
// mazetdBuildings example: asset name 0 or m

0 comments on commit 2285291

Please sign in to comment.