Skip to content

Commit

Permalink
Performance|Renderer: Improved sprite rendering performance
Browse files Browse the repository at this point in the history
Keep frequently needed state available in a quick lookup table.
  • Loading branch information
skyjake committed Oct 30, 2016
1 parent 202a51c commit 95e4f37
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 38 deletions.
14 changes: 11 additions & 3 deletions doomsday/apps/client/include/render/rend_main.h
Expand Up @@ -37,10 +37,13 @@ class Lumobj;
class Sector;
struct VectorLightData;
class ClientMaterial;
namespace de { class LightGrid; }
class MaterialAnimator;
namespace de {
class LightGrid;
}
namespace world {
class ConvexSubspace;
class Subsector;
class ConvexSubspace;
class Subsector;
}

// Multiplicative blending for dynamic lights?
Expand Down Expand Up @@ -142,6 +145,9 @@ void Rend_Register();

void Rend_Reset();

/// Reset any cached state that gets normally reused between frames.
void Rend_ResetLookups();

/// @return @c true iff multitexturing is currently enabled for lights.
bool Rend_IsMTexLights();

Expand Down Expand Up @@ -259,6 +265,8 @@ de::duint Rend_CollectAffectingLights(de::Vector3d const &point,

void Rend_DrawVectorLight(VectorLightData const &vlight, de::dfloat alpha);

MaterialAnimator *Rend_SpriteMaterialAnimator(de::Record const &spriteDef);

/**
* Returns the radius of the given @a sprite, as it would visually appear to be.
*
Expand Down
3 changes: 3 additions & 0 deletions doomsday/apps/client/src/clientapp.cpp
Expand Up @@ -63,6 +63,7 @@
#include "network/net_main.h"
#include "network/serverlink.h"
#include "render/r_draw.h"
#include "render/rend_main.h"
#include "render/rend_particle.h"
#include "render/rendersystem.h"
#include "sys_system.h"
Expand Down Expand Up @@ -877,6 +878,8 @@ void ClientApp::reset()
{
DoomsdayApp::reset();

Rend_ResetLookups();

if (App_GameLoaded())
{
d->inputSys->initAllDevices();
Expand Down
1 change: 1 addition & 0 deletions doomsday/apps/client/src/dd_main.cpp
Expand Up @@ -1442,6 +1442,7 @@ void DD_UpdateEngineState()
BusyMode_FreezeGameForBusyMode();
GL_SetFilter(false);
Demo_StopPlayback();
Rend_ResetLookups();
#endif

//App_FileSystem().resetFileIds();
Expand Down
2 changes: 1 addition & 1 deletion doomsday/apps/client/src/render/billboard.cpp
Expand Up @@ -388,7 +388,7 @@ void Rend_DrawPSprite(rendpspriteparams_t const &parms)
MaterialVariantSpec const &Rend_SpriteMaterialSpec(dint tclass, dint tmap)
{
return App_Resources().materialSpec(SpriteContext, 0, 1, tclass, tmap, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE,
1, -2, -1, true, true, true, false);
1, -2, -1, true, true, true, false);
}

void Rend_DrawSprite(vissprite_t const &spr)
Expand Down
4 changes: 2 additions & 2 deletions doomsday/apps/client/src/render/rend_fakeradio.cpp
Expand Up @@ -765,7 +765,7 @@ static void drawWallShadow(Vector3f const *posCoords, WallEdge const &leftEdge,
{
duint const numVerts = 3 + rightEdge.divisionCount();
duint const base = buffer.allocateVertices(numVerts);
if (indices.size() < numVerts) indices.resize(numVerts);
if (indices.size() < int(numVerts)) indices.resize(numVerts);
for(duint i = 0; i < numVerts; ++i)
{
indices[i] = base + i;
Expand Down Expand Up @@ -805,7 +805,7 @@ static void drawWallShadow(Vector3f const *posCoords, WallEdge const &leftEdge,
{
duint const numVerts = 3 + leftEdge .divisionCount();
duint const base = buffer.allocateVertices(numVerts);
if (indices.size() < numVerts) indices.resize(numVerts);
if (indices.size() < int(numVerts)) indices.resize(numVerts);
for(duint i = 0; i < numVerts; ++i)
{
indices[i] = base + i;
Expand Down
84 changes: 61 additions & 23 deletions doomsday/apps/client/src/render/rend_main.cpp
Expand Up @@ -315,6 +315,16 @@ static Vector3f curSectorLightColor;
static dfloat curSectorLightLevel;
static bool firstSubspace; ///< No range checking for the first one.

// State lookup (for speed):
static MaterialVariantSpec const *lookupMapSurfaceMaterialSpec = nullptr;
static QHash<Record const *, MaterialAnimator *> lookupSpriteMaterialAnimators;

void Rend_ResetLookups()
{
lookupMapSurfaceMaterialSpec = nullptr;
lookupSpriteMaterialAnimators.clear();
}

static void reportWallDrawn(Line &line)
{
// Already been here?
Expand Down Expand Up @@ -3730,44 +3740,68 @@ static void generateDecorationFlares(Map &map)
});
}

ddouble Rend_VisualRadius(Record const &spriteRec)
MaterialAnimator *Rend_SpriteMaterialAnimator(Record const &spriteDef)
{
defn::Sprite const sprite(spriteRec);
de::Uri const &viewMaterial = sprite.viewMaterial(0);
if(!viewMaterial.isEmpty())
MaterialAnimator *matAnimator = nullptr;

// Check the cache first.
auto found = lookupSpriteMaterialAnimators.constFind(&spriteDef);
if (found != lookupSpriteMaterialAnimators.constEnd())
{
if(world::Material *mat = world::Materials::get().materialPtr(viewMaterial))
matAnimator = found.value();
}
else
{
// Look it up...
defn::Sprite const sprite(spriteDef);
de::Uri const &viewMaterial = sprite.viewMaterial(0);
if (!viewMaterial.isEmpty())
{
MaterialAnimator &matAnimator = mat->as<ClientMaterial>().getAnimator(Rend_SpriteMaterialSpec());
matAnimator.prepare(); // Ensure we've up to date info.
return matAnimator.dimensions().x / 2;
if(world::Material *mat = world::Materials::get().materialPtr(viewMaterial))
{
matAnimator = &mat->as<ClientMaterial>().getAnimator(Rend_SpriteMaterialSpec());
}
}
lookupSpriteMaterialAnimators.insert(&spriteDef, matAnimator);
}
return matAnimator;
}

ddouble Rend_VisualRadius(Record const &spriteDef)
{
if (auto *anim = Rend_SpriteMaterialAnimator(spriteDef))
{
anim->prepare(); // Ensure we've up to date info.
return anim->dimensions().x / 2;
}
return 0;
}

Lumobj *Rend_MakeLumobj(Record const &spriteRec)
Lumobj *Rend_MakeLumobj(Record const &spriteDef)
{
LOG_AS("Rend_MakeLumobj");

defn::Sprite const sprite(spriteRec);
de::Uri const &viewMaterial = sprite.viewMaterial(0);
//defn::Sprite const sprite(spriteRec);
//de::Uri const &viewMaterial = sprite.viewMaterial(0);

// Always use the front view.
/// @todo We could do better here...
if(viewMaterial.isEmpty()) return nullptr;
//if(viewMaterial.isEmpty()) return nullptr;

//world::Material *mat = world::Materials::get().materialPtr(viewMaterial);
//if(!mat) return nullptr;

world::Material *mat = world::Materials::get().materialPtr(viewMaterial);
if(!mat) return nullptr;
MaterialAnimator *matAnimator = Rend_SpriteMaterialAnimator(spriteDef); //mat->as<ClientMaterial>().getAnimator(Rend_SpriteMaterialSpec());
if (!matAnimator) return nullptr;

MaterialAnimator &matAnimator = mat->as<ClientMaterial>().getAnimator(Rend_SpriteMaterialSpec());
matAnimator.prepare(); // Ensure we have up-to-date info.
matAnimator->prepare(); // Ensure we have up-to-date info.

TextureVariant *texture = matAnimator.texUnit(MaterialAnimator::TU_LAYER0).texture;
if(!texture) return nullptr; // Unloadable texture?
TextureVariant *texture = matAnimator->texUnit(MaterialAnimator::TU_LAYER0).texture;
if (!texture) return nullptr; // Unloadable texture?

auto const *pl = (pointlight_analysis_t const *)texture->base().analysisDataPointer(res::Texture::BrightPointAnalysis);
if(!pl)
auto const *pl = (pointlight_analysis_t const *)
texture->base().analysisDataPointer(res::Texture::BrightPointAnalysis);
if (!pl)
{
LOGDEV_RES_WARNING("Texture \"%s\" has no BrightPointAnalysis")
<< texture->base().manifest().composeUri();
Expand All @@ -3776,7 +3810,7 @@ Lumobj *Rend_MakeLumobj(Record const &spriteRec)

// Apply the auto-calculated color.
return &(new Lumobj(Vector3d(), pl->brightMul, pl->color.rgb))
->setZOffset(-texture->base().origin().y - pl->originY * matAnimator.dimensions().y);
->setZOffset(-texture->base().origin().y - pl->originY * matAnimator->dimensions().y);
}

/**
Expand Down Expand Up @@ -6106,12 +6140,16 @@ void Rend_LightGridVisual(LightGrid &lg)
MaterialVariantSpec const &Rend_MapSurfaceMaterialSpec(dint wrapS, dint wrapT)
{
return ClientApp::resources().materialSpec(MapSurfaceContext, 0, 0, 0, 0, wrapS, wrapT,
-1, -1, -1, true, true, false, false);
-1, -1, -1, true, true, false, false);
}

MaterialVariantSpec const &Rend_MapSurfaceMaterialSpec()
{
return Rend_MapSurfaceMaterialSpec(GL_REPEAT, GL_REPEAT);
if (!lookupMapSurfaceMaterialSpec)
{
lookupMapSurfaceMaterialSpec = &Rend_MapSurfaceMaterialSpec(GL_REPEAT, GL_REPEAT);
}
return *lookupMapSurfaceMaterialSpec;
}

/// Returns the texture variant specification for lightmaps.
Expand Down
19 changes: 10 additions & 9 deletions doomsday/apps/client/src/world/base/p_mobj.cpp
Expand Up @@ -472,30 +472,31 @@ void Mobj_GenerateLumobjs(mobj_t *mob)
// Always use the front view of the Sprite when determining light properties.
Record *spriteRec = Mobj_SpritePtr(*mob);
if (!spriteRec) return;
defn::Sprite sprite(*spriteRec);
if (!sprite.hasView(0)) return;
//defn::Sprite sprite(*spriteRec);
//if (!sprite.hasView(0)) return;

// Lookup the Material for the Sprite and prepare the animator.
Material *sprMat = world::Materials::get().materialPtr(sprite.viewMaterial(0));
if (!sprMat) return;
MaterialAnimator &matAnimator = sprMat->as<ClientMaterial>().getAnimator(Rend_SpriteMaterialSpec());
matAnimator.prepare(); // Ensure we have up-to-date info.
//Material *sprMat = world::Materials::get().materialPtr(sprite.viewMaterial(0));
//if (!sprMat) return;
MaterialAnimator *matAnimator = Rend_SpriteMaterialAnimator(*spriteRec) ;//sprMat->as<ClientMaterial>().getAnimator(Rend_SpriteMaterialSpec());
if (!matAnimator) return;
matAnimator->prepare(); // Ensure we have up-to-date info.

TextureVariant *tex = matAnimator.texUnit(MaterialAnimator::TU_LAYER0).texture;
TextureVariant *tex = matAnimator->texUnit(MaterialAnimator::TU_LAYER0).texture;
if (!tex) return; // Unloadable texture?
Vector2i const &texOrigin = tex->base().origin();

// Will the visual be allowed to go inside the floor?
/// @todo Handle this as occlusion so that the halo fades smoothly.
coord_t impacted = mob->origin[2] + -texOrigin.y - matAnimator.dimensions().y
coord_t impacted = mob->origin[2] + -texOrigin.y - matAnimator->dimensions().y
- subsec.visFloor().heightSmoothed();

// If the floor is a visual plane then no light should be emitted.
if (impacted < 0 && &subsec.visFloor() != &subsec.sector().floor())
return;

// Attempt to generate luminous object from the sprite.
std::unique_ptr<Lumobj> lum(Rend_MakeLumobj(sprite.def()));
std::unique_ptr<Lumobj> lum(Rend_MakeLumobj(*spriteRec));
if (!lum) return;

lum->setSourceMobj(mob);
Expand Down

0 comments on commit 95e4f37

Please sign in to comment.