Browse Source

Poormans profiler

w98-profile
Anders Jenbo 3 years ago
parent
commit
098e9a34ca
  1. 1
      Source/CMakeLists.txt
  2. 10
      Source/diablo.cpp
  3. 6
      Source/engine/render/clx_render.cpp
  4. 7
      Source/engine/render/dun_render.cpp
  5. 39
      Source/engine/render/scrollrt.cpp
  6. 1
      Source/engine/render/scrollrt.h
  7. 7
      Source/engine/render/text_render.cpp
  8. 59
      Source/utils/profiler.cpp
  9. 22
      Source/utils/profiler.h

1
Source/CMakeLists.txt

@ -167,6 +167,7 @@ set(libdevilutionx_SRCS
utils/str_cat.cpp utils/str_cat.cpp
utils/str_case.cpp utils/str_case.cpp
utils/surface_to_clx.cpp utils/surface_to_clx.cpp
utils/profiler.cpp
utils/timer.cpp utils/timer.cpp
utils/utf8.cpp) utils/utf8.cpp)

10
Source/diablo.cpp

@ -8,6 +8,7 @@
#include <string_view> #include <string_view>
#include <fmt/format.h> #include <fmt/format.h>
#include <utils/profiler.h>
#include <config.h> #include <config.h>
@ -697,6 +698,7 @@ bool HandleTextInput(std::string_view text)
void GameEventHandler(const SDL_Event &event, uint16_t modState) void GameEventHandler(const SDL_Event &event, uint16_t modState)
{ {
FunctionProfiler profiler(__func__);
StaticVector<ControllerButtonEvent, 4> ctrlEvents = ToControllerButtonEvents(event); StaticVector<ControllerButtonEvent, 4> ctrlEvents = ToControllerButtonEvents(event);
for (ControllerButtonEvent ctrlEvent : ctrlEvents) { for (ControllerButtonEvent ctrlEvent : ctrlEvents) {
GameAction action; GameAction action;
@ -825,6 +827,7 @@ void RunGameLoop(interface_mode uMsg)
unsigned run_game_iteration = 0; unsigned run_game_iteration = 0;
#endif #endif
FunctionProfiler profiler(__func__);
while (gbRunGame) { while (gbRunGame) {
#ifdef _DEBUG #ifdef _DEBUG
@ -2454,6 +2457,12 @@ int DiabloMain(int argc, char **argv)
DiabloSplash(); DiabloSplash();
mainmenu_loop(); mainmenu_loop();
for (const auto &timing : FunctionProfiler::Dump()) {
fmt::print("{}: {}ms ({} calls)\n", timing.name, timing.ms, timing.count);
}
fmt::print("\n");
DiabloDeinit(); DiabloDeinit();
return 0; return 0;
@ -3002,6 +3011,7 @@ void LoadGameLevel(bool firstflag, lvl_entry lvldir)
bool game_loop(bool bStartup) bool game_loop(bool bStartup)
{ {
FunctionProfiler profiler(__func__);
uint16_t wait = bStartup ? sgGameInitInfo.nTickRate * 3 : 3; uint16_t wait = bStartup ? sgGameInitInfo.nTickRate * 3 : 3;
for (unsigned i = 0; i < wait; i++) { for (unsigned i = 0; i < wait; i++) {

6
Source/engine/render/clx_render.cpp

@ -12,6 +12,7 @@
#include "engine/render/scrollrt.h" #include "engine/render/scrollrt.h"
#include "utils/attributes.h" #include "utils/attributes.h"
#include "utils/clx_decode.hpp" #include "utils/clx_decode.hpp"
#include "utils/profiler.h"
#ifdef DEBUG_CLX #ifdef DEBUG_CLX
#include <fmt/format.h> #include <fmt/format.h>
@ -194,6 +195,7 @@ void DoRenderBackwards(
const Surface &out, Point position, const uint8_t *src, size_t srcSize, const Surface &out, Point position, const uint8_t *src, size_t srcSize,
unsigned srcWidth, unsigned srcHeight, BlitFn &&blitFn) unsigned srcWidth, unsigned srcHeight, BlitFn &&blitFn)
{ {
FunctionProfiler profiler(__func__);
if (position.y < 0 || position.y + 1 >= static_cast<int>(out.h() + srcHeight)) if (position.y < 0 || position.y + 1 >= static_cast<int>(out.h() + srcHeight))
return; return;
const ClipX clipX = CalculateClipX(position.x, srcWidth, out); const ClipX clipX = CalculateClipX(position.x, srcWidth, out);
@ -615,6 +617,7 @@ template <bool SkipColorIndexZero>
void RenderClxOutline(const Surface &out, Point position, const uint8_t *src, std::size_t srcSize, void RenderClxOutline(const Surface &out, Point position, const uint8_t *src, std::size_t srcSize,
std::size_t srcWidth, uint8_t color) std::size_t srcWidth, uint8_t color)
{ {
FunctionProfiler profiler(__func__);
RenderSrc srcForBackwards { src, src + srcSize, static_cast<uint_fast16_t>(srcWidth) }; RenderSrc srcForBackwards { src, src + srcSize, static_cast<uint_fast16_t>(srcWidth) };
if (position.x > 0 && position.x + static_cast<int>(srcWidth) < static_cast<int>(out.w())) { if (position.x > 0 && position.x + static_cast<int>(srcWidth) < static_cast<int>(out.w())) {
RenderClxOutlineClippedY<SkipColorIndexZero>(out, position, srcForBackwards, color); RenderClxOutlineClippedY<SkipColorIndexZero>(out, position, srcForBackwards, color);
@ -625,6 +628,7 @@ void RenderClxOutline(const Surface &out, Point position, const uint8_t *src, st
void ClxApplyTrans(ClxSprite sprite, const uint8_t *trn) void ClxApplyTrans(ClxSprite sprite, const uint8_t *trn)
{ {
FunctionProfiler profiler(__func__);
// A bit of a hack but this is the only place in the code where we need mutable sprites. // A bit of a hack but this is the only place in the code where we need mutable sprites.
auto *dst = const_cast<uint8_t *>(sprite.pixelData()); auto *dst = const_cast<uint8_t *>(sprite.pixelData());
uint16_t remaining = sprite.pixelDataSize(); uint16_t remaining = sprite.pixelDataSize();
@ -666,6 +670,7 @@ void ClxApplyTrans(ClxSpriteSheet sheet, const uint8_t *trn)
bool IsPointWithinClx(Point position, ClxSprite clx) bool IsPointWithinClx(Point position, ClxSprite clx)
{ {
FunctionProfiler profiler(__func__);
const uint8_t *src = clx.pixelData(); const uint8_t *src = clx.pixelData();
const uint8_t *end = src + clx.pixelDataSize(); const uint8_t *end = src + clx.pixelDataSize();
const uint16_t width = clx.width(); const uint16_t width = clx.width();
@ -719,6 +724,7 @@ bool IsPointWithinClx(Point position, ClxSprite clx)
std::pair<int, int> ClxMeasureSolidHorizontalBounds(ClxSprite clx) std::pair<int, int> ClxMeasureSolidHorizontalBounds(ClxSprite clx)
{ {
FunctionProfiler profiler(__func__);
const uint8_t *src = clx.pixelData(); const uint8_t *src = clx.pixelData();
const uint8_t *end = src + clx.pixelDataSize(); const uint8_t *end = src + clx.pixelDataSize();
const uint16_t width = clx.width(); const uint16_t width = clx.width();

7
Source/engine/render/dun_render.cpp

@ -18,6 +18,7 @@
#include <climits> #include <climits>
#include <cstdint> #include <cstdint>
#include "utils/profiler.h"
#include "engine/render/blit_impl.hpp" #include "engine/render/blit_impl.hpp"
#include "lighting.h" #include "lighting.h"
#include "options.h" #include "options.h"
@ -922,6 +923,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderTileType(TileType tile, uint8_t *
template <bool OpaquePrefix, int8_t PrefixIncrement> template <bool OpaquePrefix, int8_t PrefixIncrement>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderTransparentSquareDispatch(uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip) DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderTransparentSquareDispatch(uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip)
{ {
FunctionProfiler profiler(__func__);
if (tbl == LightTables[LightsMax].data()) { if (tbl == LightTables[LightsMax].data()) {
RenderTransparentSquare<LightType::FullyDark, OpaquePrefix, PrefixIncrement>(dst, dstPitch, src, tbl, clip); RenderTransparentSquare<LightType::FullyDark, OpaquePrefix, PrefixIncrement>(dst, dstPitch, src, tbl, clip);
} else if (tbl == LightTables[0].data()) { } else if (tbl == LightTables[0].data()) {
@ -964,6 +966,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderRightTrapezoidOrTransparentSquare
template <bool OpaquePrefix, int8_t PrefixIncrement> template <bool OpaquePrefix, int8_t PrefixIncrement>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderLeftTrapezoidOrTransparentSquareDispatch(TileType tile, uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip) DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderLeftTrapezoidOrTransparentSquareDispatch(TileType tile, uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip)
{ {
FunctionProfiler profiler(__func__);
if (tbl == LightTables[LightsMax].data()) { if (tbl == LightTables[LightsMax].data()) {
RenderLeftTrapezoidOrTransparentSquare<LightType::FullyDark, OpaquePrefix, PrefixIncrement>(tile, dst, dstPitch, src, tbl, clip); RenderLeftTrapezoidOrTransparentSquare<LightType::FullyDark, OpaquePrefix, PrefixIncrement>(tile, dst, dstPitch, src, tbl, clip);
} else if (tbl == LightTables[0].data()) { } else if (tbl == LightTables[0].data()) {
@ -976,6 +979,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderLeftTrapezoidOrTransparentSquareD
template <bool OpaquePrefix, int8_t PrefixIncrement> template <bool OpaquePrefix, int8_t PrefixIncrement>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderRightTrapezoidOrTransparentSquareDispatch(TileType tile, uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip) DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderRightTrapezoidOrTransparentSquareDispatch(TileType tile, uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip)
{ {
FunctionProfiler profiler(__func__);
if (tbl == LightTables[LightsMax].data()) { if (tbl == LightTables[LightsMax].data()) {
RenderRightTrapezoidOrTransparentSquare<LightType::FullyDark, OpaquePrefix, PrefixIncrement>(tile, dst, dstPitch, src, tbl, clip); RenderRightTrapezoidOrTransparentSquare<LightType::FullyDark, OpaquePrefix, PrefixIncrement>(tile, dst, dstPitch, src, tbl, clip);
} else if (tbl == LightTables[0].data()) { } else if (tbl == LightTables[0].data()) {
@ -988,6 +992,7 @@ DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderRightTrapezoidOrTransparentSquare
template <bool Transparent> template <bool Transparent>
DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderTileDispatch(TileType tile, uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip) DVL_ALWAYS_INLINE DVL_ATTRIBUTE_HOT void RenderTileDispatch(TileType tile, uint8_t *DVL_RESTRICT dst, uint16_t dstPitch, const uint8_t *DVL_RESTRICT src, const uint8_t *DVL_RESTRICT tbl, Clip clip)
{ {
FunctionProfiler profiler(__func__);
if (tbl == LightTables[LightsMax].data()) { if (tbl == LightTables[LightsMax].data()) {
RenderTileType<LightType::FullyDark, Transparent>(tile, dst, dstPitch, src, tbl, clip); RenderTileType<LightType::FullyDark, Transparent>(tile, dst, dstPitch, src, tbl, clip);
} else if (tbl == LightTables[0].data()) { } else if (tbl == LightTables[0].data()) {
@ -1126,6 +1131,7 @@ std::string_view MaskTypeToString(MaskType maskType)
void RenderTile(const Surface &out, Point position, void RenderTile(const Surface &out, Point position,
LevelCelBlock levelCelBlock, MaskType maskType, const uint8_t *tbl) LevelCelBlock levelCelBlock, MaskType maskType, const uint8_t *tbl)
{ {
FunctionProfiler profiler(__func__);
const TileType tile = levelCelBlock.type(); const TileType tile = levelCelBlock.type();
#ifdef DEBUG_RENDER_OFFSET_X #ifdef DEBUG_RENDER_OFFSET_X
@ -1180,6 +1186,7 @@ void RenderTile(const Surface &out, Point position,
void world_draw_black_tile(const Surface &out, int sx, int sy) void world_draw_black_tile(const Surface &out, int sx, int sy)
{ {
FunctionProfiler profiler(__func__);
#ifdef DEBUG_RENDER_OFFSET_X #ifdef DEBUG_RENDER_OFFSET_X
sx += DEBUG_RENDER_OFFSET_X; sx += DEBUG_RENDER_OFFSET_X;
#endif #endif

39
Source/engine/render/scrollrt.cpp

@ -86,6 +86,7 @@ std::unordered_multimap<WorldTilePosition, Missile *> MissilesAtRenderingTile;
*/ */
bool CouldMissileCollide(Point tile, bool checkPlayerAndMonster) bool CouldMissileCollide(Point tile, bool checkPlayerAndMonster)
{ {
FunctionProfiler profiler(__func__);
if (!InDungeonBounds(tile)) if (!InDungeonBounds(tile))
return true; return true;
if (checkPlayerAndMonster) { if (checkPlayerAndMonster) {
@ -100,6 +101,7 @@ bool CouldMissileCollide(Point tile, bool checkPlayerAndMonster)
void UpdateMissilePositionForRendering(Missile &m, int progress) void UpdateMissilePositionForRendering(Missile &m, int progress)
{ {
FunctionProfiler profiler(__func__);
DisplacementOf<int64_t> velocity = m.position.velocity; DisplacementOf<int64_t> velocity = m.position.velocity;
velocity *= progress; velocity *= progress;
velocity /= AnimationInfo::baseValueFraction; velocity /= AnimationInfo::baseValueFraction;
@ -113,6 +115,7 @@ void UpdateMissilePositionForRendering(Missile &m, int progress)
void UpdateMissileRendererData(Missile &m) void UpdateMissileRendererData(Missile &m)
{ {
FunctionProfiler profiler(__func__);
m.position.tileForRendering = m.position.tile; m.position.tileForRendering = m.position.tile;
m.position.offsetForRendering = m.position.offset; m.position.offsetForRendering = m.position.offset;
@ -155,6 +158,7 @@ void UpdateMissileRendererData(Missile &m)
void UpdateMissilesRendererData() void UpdateMissilesRendererData()
{ {
FunctionProfiler profiler(__func__);
MissilesAtRenderingTile.clear(); MissilesAtRenderingTile.clear();
for (auto &m : Missiles) { for (auto &m : Missiles) {
@ -174,6 +178,7 @@ Rectangle PrevCursorRect;
void BlitCursor(uint8_t *dst, uint32_t dstPitch, uint8_t *src, uint32_t srcPitch, uint32_t srcWidth, uint32_t srcHeight) void BlitCursor(uint8_t *dst, uint32_t dstPitch, uint8_t *src, uint32_t srcPitch, uint32_t srcWidth, uint32_t srcHeight)
{ {
FunctionProfiler profiler(__func__);
for (std::uint32_t i = 0; i < srcHeight; ++i, src += srcPitch, dst += dstPitch) { for (std::uint32_t i = 0; i < srcHeight; ++i, src += srcPitch, dst += dstPitch) {
memcpy(dst, src, srcWidth); memcpy(dst, src, srcWidth);
} }
@ -184,6 +189,7 @@ void BlitCursor(uint8_t *dst, uint32_t dstPitch, uint8_t *src, uint32_t srcPitch
*/ */
void UndrawCursor(const Surface &out) void UndrawCursor(const Surface &out)
{ {
FunctionProfiler profiler(__func__);
DrawnCursor &cursor = GetDrawnCursor(); DrawnCursor &cursor = GetDrawnCursor();
BlitCursor(&out[cursor.rect.position], out.pitch(), cursor.behindBuffer, cursor.rect.size.width, cursor.rect.size.width, cursor.rect.size.height); BlitCursor(&out[cursor.rect.position], out.pitch(), cursor.behindBuffer, cursor.rect.size.width, cursor.rect.size.width, cursor.rect.size.height);
PrevCursorRect = cursor.rect; PrevCursorRect = cursor.rect;
@ -191,6 +197,7 @@ void UndrawCursor(const Surface &out)
bool ShouldShowCursor() bool ShouldShowCursor()
{ {
FunctionProfiler profiler(__func__);
if (ControlMode == ControlTypes::KeyboardAndMouse) if (ControlMode == ControlTypes::KeyboardAndMouse)
return true; return true;
if (pcurs == CURSOR_TELEPORT) if (pcurs == CURSOR_TELEPORT)
@ -208,6 +215,7 @@ bool ShouldShowCursor()
*/ */
void DrawCursor(const Surface &out) void DrawCursor(const Surface &out)
{ {
FunctionProfiler profiler(__func__);
DrawnCursor &cursor = GetDrawnCursor(); DrawnCursor &cursor = GetDrawnCursor();
if (IsHardwareCursor()) { if (IsHardwareCursor()) {
SetHardwareCursorVisible(ShouldShowCursor()); SetHardwareCursorVisible(ShouldShowCursor());
@ -268,6 +276,7 @@ void DrawCursor(const Surface &out)
*/ */
void DrawMissilePrivate(const Surface &out, const Missile &missile, Point targetBufferPosition, bool pre) void DrawMissilePrivate(const Surface &out, const Missile &missile, Point targetBufferPosition, bool pre)
{ {
FunctionProfiler profiler(__func__);
if (missile._miPreFlag != pre || !missile._miDrawFlag) if (missile._miPreFlag != pre || !missile._miDrawFlag)
return; return;
@ -290,6 +299,7 @@ void DrawMissilePrivate(const Surface &out, const Missile &missile, Point target
*/ */
void DrawMissile(const Surface &out, WorldTilePosition tilePosition, Point targetBufferPosition, bool pre) void DrawMissile(const Surface &out, WorldTilePosition tilePosition, Point targetBufferPosition, bool pre)
{ {
FunctionProfiler profiler(__func__);
const auto [begin, end] = MissilesAtRenderingTile.equal_range(tilePosition); const auto [begin, end] = MissilesAtRenderingTile.equal_range(tilePosition);
for (auto it = begin; it != end; ++it) { for (auto it = begin; it != end; ++it) {
DrawMissilePrivate(out, *it->second, targetBufferPosition, pre); DrawMissilePrivate(out, *it->second, targetBufferPosition, pre);
@ -305,6 +315,7 @@ void DrawMissile(const Surface &out, WorldTilePosition tilePosition, Point targe
*/ */
void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosition, const Monster &monster) void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosition, const Monster &monster)
{ {
FunctionProfiler profiler(__func__);
if (!monster.animInfo.sprites) { if (!monster.animInfo.sprites) {
Log("Draw Monster \"{}\": NULL Cel Buffer", monster.name()); Log("Draw Monster \"{}\": NULL Cel Buffer", monster.name());
return; return;
@ -334,6 +345,7 @@ void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosit
*/ */
void DrawPlayerIconHelper(const Surface &out, MissileGraphicID missileGraphicId, Point position, const Player &player, bool infraVision) void DrawPlayerIconHelper(const Surface &out, MissileGraphicID missileGraphicId, Point position, const Player &player, bool infraVision)
{ {
FunctionProfiler profiler(__func__);
bool lighting = &player != MyPlayer; bool lighting = &player != MyPlayer;
if (player.isWalking()) if (player.isWalking())
@ -365,6 +377,7 @@ void DrawPlayerIconHelper(const Surface &out, MissileGraphicID missileGraphicId,
*/ */
void DrawPlayerIcons(const Surface &out, const Player &player, Point position, bool infraVision) void DrawPlayerIcons(const Surface &out, const Player &player, Point position, bool infraVision)
{ {
FunctionProfiler profiler(__func__);
if (player.pManaShield) if (player.pManaShield)
DrawPlayerIconHelper(out, MissileGraphicID::ManaShield, position, player, infraVision); DrawPlayerIconHelper(out, MissileGraphicID::ManaShield, position, player, infraVision);
if (player.wReflections > 0) if (player.wReflections > 0)
@ -380,6 +393,7 @@ void DrawPlayerIcons(const Surface &out, const Player &player, Point position, b
*/ */
void DrawPlayer(const Surface &out, const Player &player, Point tilePosition, Point targetBufferPosition) void DrawPlayer(const Surface &out, const Player &player, Point tilePosition, Point targetBufferPosition)
{ {
FunctionProfiler profiler(__func__);
if (!IsTileLit(tilePosition) && !MyPlayer->_pInfraFlag && !MyPlayer->isOnArenaLevel() && leveltype != DTYPE_TOWN) { if (!IsTileLit(tilePosition) && !MyPlayer->_pInfraFlag && !MyPlayer->isOnArenaLevel() && leveltype != DTYPE_TOWN) {
return; return;
} }
@ -422,6 +436,7 @@ void DrawPlayer(const Surface &out, const Player &player, Point tilePosition, Po
*/ */
void DrawDeadPlayer(const Surface &out, Point tilePosition, Point targetBufferPosition) void DrawDeadPlayer(const Surface &out, Point tilePosition, Point targetBufferPosition)
{ {
FunctionProfiler profiler(__func__);
dFlags[tilePosition.x][tilePosition.y] &= ~DungeonFlag::DeadPlayer; dFlags[tilePosition.x][tilePosition.y] &= ~DungeonFlag::DeadPlayer;
for (Player &player : Players) { for (Player &player : Players) {
@ -442,6 +457,7 @@ void DrawDeadPlayer(const Surface &out, Point tilePosition, Point targetBufferPo
*/ */
void DrawObject(const Surface &out, Point tilePosition, Point targetBufferPosition, bool pre) void DrawObject(const Surface &out, Point tilePosition, Point targetBufferPosition, bool pre)
{ {
FunctionProfiler profiler(__func__);
if (LightTableIndex >= LightsMax) { if (LightTableIndex >= LightsMax) {
return; return;
} }
@ -480,6 +496,7 @@ static void DrawDungeon(const Surface & /*out*/, Point /*tilePosition*/, Point /
*/ */
void DrawCell(const Surface &out, Point tilePosition, Point targetBufferPosition) void DrawCell(const Surface &out, Point tilePosition, Point targetBufferPosition)
{ {
FunctionProfiler profiler(__func__);
const uint16_t levelPieceId = dPiece[tilePosition.x][tilePosition.y]; const uint16_t levelPieceId = dPiece[tilePosition.x][tilePosition.y];
const MICROS *pMap = &DPieceMicros[levelPieceId]; const MICROS *pMap = &DPieceMicros[levelPieceId];
@ -593,6 +610,7 @@ void DrawCell(const Surface &out, Point tilePosition, Point targetBufferPosition
*/ */
void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPosition) void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPosition)
{ {
FunctionProfiler profiler(__func__);
LightTableIndex = dLight[tilePosition.x][tilePosition.y]; LightTableIndex = dLight[tilePosition.x][tilePosition.y];
const uint8_t *tbl = LightTables[LightTableIndex].data(); const uint8_t *tbl = LightTables[LightTableIndex].data();
@ -627,6 +645,7 @@ void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPositio
*/ */
void DrawItem(const Surface &out, Point tilePosition, Point targetBufferPosition, bool pre) void DrawItem(const Surface &out, Point tilePosition, Point targetBufferPosition, bool pre)
{ {
FunctionProfiler profiler(__func__);
int8_t bItem = dItem[tilePosition.x][tilePosition.y]; int8_t bItem = dItem[tilePosition.x][tilePosition.y];
if (bItem <= 0) if (bItem <= 0)
@ -654,6 +673,7 @@ void DrawItem(const Surface &out, Point tilePosition, Point targetBufferPosition
*/ */
void DrawMonsterHelper(const Surface &out, Point tilePosition, Point targetBufferPosition) void DrawMonsterHelper(const Surface &out, Point tilePosition, Point targetBufferPosition)
{ {
FunctionProfiler profiler(__func__);
int mi = dMonster[tilePosition.x][tilePosition.y]; int mi = dMonster[tilePosition.x][tilePosition.y];
bool isNegativeMonster = mi < 0; bool isNegativeMonster = mi < 0;
mi = std::abs(mi) - 1; mi = std::abs(mi) - 1;
@ -715,6 +735,7 @@ void DrawMonsterHelper(const Surface &out, Point tilePosition, Point targetBuffe
*/ */
void DrawPlayerHelper(const Surface &out, const Player &player, Point tilePosition, Point targetBufferPosition) void DrawPlayerHelper(const Surface &out, const Player &player, Point tilePosition, Point targetBufferPosition)
{ {
FunctionProfiler profiler(__func__);
DrawPlayer(out, player, tilePosition, targetBufferPosition); DrawPlayer(out, player, tilePosition, targetBufferPosition);
} }
@ -726,6 +747,7 @@ void DrawPlayerHelper(const Surface &out, const Player &player, Point tilePositi
*/ */
void DrawDungeon(const Surface &out, Point tilePosition, Point targetBufferPosition) void DrawDungeon(const Surface &out, Point tilePosition, Point targetBufferPosition)
{ {
FunctionProfiler profiler(__func__);
assert(InDungeonBounds(tilePosition)); assert(InDungeonBounds(tilePosition));
if (dRendered.test(tilePosition.x, tilePosition.y)) if (dRendered.test(tilePosition.x, tilePosition.y))
@ -814,6 +836,7 @@ void DrawDungeon(const Surface &out, Point tilePosition, Point targetBufferPosit
*/ */
void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPosition, int rows, int columns) void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPosition, int rows, int columns)
{ {
FunctionProfiler profiler(__func__);
for (int i = 0; i < rows; i++) { for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) { for (int j = 0; j < columns; j++) {
if (InDungeonBounds(tilePosition)) { if (InDungeonBounds(tilePosition)) {
@ -845,6 +868,7 @@ void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPositio
bool IsWall(Point position) bool IsWall(Point position)
{ {
FunctionProfiler profiler(__func__);
return TileHasAny(dPiece[position.x][position.y], TileProperties::Solid) || dSpecial[position.x][position.y] != 0; return TileHasAny(dPiece[position.x][position.y], TileProperties::Solid) || dSpecial[position.x][position.y] != 0;
} }
@ -858,6 +882,7 @@ bool IsWall(Point position)
*/ */
void DrawTileContent(const Surface &out, Point tilePosition, Point targetBufferPosition, int rows, int columns) void DrawTileContent(const Surface &out, Point tilePosition, Point targetBufferPosition, int rows, int columns)
{ {
FunctionProfiler profiler(__func__);
// Keep evaluating until MicroTiles can't affect screen // Keep evaluating until MicroTiles can't affect screen
rows += MicroTileLen; rows += MicroTileLen;
dRendered.reset(); dRendered.reset();
@ -907,6 +932,7 @@ void DrawTileContent(const Surface &out, Point tilePosition, Point targetBufferP
*/ */
void Zoom(const Surface &out) void Zoom(const Surface &out)
{ {
FunctionProfiler profiler(__func__);
int viewportWidth = out.w(); int viewportWidth = out.w();
int viewportOffsetX = 0; int viewportOffsetX = 0;
if (CanPanelsCoverView()) { if (CanPanelsCoverView()) {
@ -964,6 +990,7 @@ int tileRows;
void CalcFirstTilePosition(Point &position, Displacement &offset) void CalcFirstTilePosition(Point &position, Displacement &offset)
{ {
FunctionProfiler profiler(__func__);
// Adjust by player offset and tile grid alignment // Adjust by player offset and tile grid alignment
Player &myPlayer = *MyPlayer; Player &myPlayer = *MyPlayer;
offset = tileOffset; offset = tileOffset;
@ -1015,6 +1042,7 @@ void CalcFirstTilePosition(Point &position, Displacement &offset)
*/ */
void DrawGame(const Surface &fullOut, Point position, Displacement offset) void DrawGame(const Surface &fullOut, Point position, Displacement offset)
{ {
FunctionProfiler profiler(__func__);
// Limit rendering to the view area // Limit rendering to the view area
const Surface &out = !*sgOptions.Graphics.zoom const Surface &out = !*sgOptions.Graphics.zoom
? fullOut.subregionY(0, gnViewportHeight) ? fullOut.subregionY(0, gnViewportHeight)
@ -1093,6 +1121,7 @@ void DrawGame(const Surface &fullOut, Point position, Displacement offset)
*/ */
void DrawView(const Surface &out, Point startPosition) void DrawView(const Surface &out, Point startPosition)
{ {
FunctionProfiler profiler(__func__);
#ifdef _DEBUG #ifdef _DEBUG
DebugCoordsMap.clear(); DebugCoordsMap.clear();
#endif #endif
@ -1263,6 +1292,7 @@ void DrawFPS(const Surface &out)
*/ */
void DoBlitScreen(int x, int y, int w, int h) void DoBlitScreen(int x, int y, int w, int h)
{ {
FunctionProfiler profiler(__func__);
#ifdef DEBUG_DO_BLIT_SCREEN #ifdef DEBUG_DO_BLIT_SCREEN
const Surface &out = GlobalBackBuffer(); const Surface &out = GlobalBackBuffer();
const uint8_t debugColor = PAL8_RED; const uint8_t debugColor = PAL8_RED;
@ -1291,6 +1321,7 @@ void DrawMain(const Surface &out, int dwHgt, bool drawDesc, bool drawHp, bool dr
if (!gbActive || RenderDirectlyToOutputSurface) { if (!gbActive || RenderDirectlyToOutputSurface) {
return; return;
} }
FunctionProfiler profiler(__func__);
assert(dwHgt >= 0 && dwHgt <= gnScreenHeight); assert(dwHgt >= 0 && dwHgt <= gnScreenHeight);
@ -1339,6 +1370,7 @@ void DrawMain(const Surface &out, int dwHgt, bool drawDesc, bool drawHp, bool dr
Displacement GetOffsetForWalking(const AnimationInfo &animationInfo, const Direction dir, bool cameraMode /*= false*/) Displacement GetOffsetForWalking(const AnimationInfo &animationInfo, const Direction dir, bool cameraMode /*= false*/)
{ {
FunctionProfiler profiler(__func__);
// clang-format off // clang-format off
// South, SouthWest, West, NorthWest, North, NorthEast, East, SouthEast, // South, SouthWest, West, NorthWest, North, NorthEast, East, SouthEast,
constexpr Displacement StartOffset[8] = { { 0, -32 }, { 32, -16 }, { 64, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { -64, 0 }, { -32, -16 } }; constexpr Displacement StartOffset[8] = { { 0, -32 }, { 32, -16 }, { 64, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { -64, 0 }, { -32, -16 } };
@ -1372,6 +1404,7 @@ void ShiftGrid(int *x, int *y, int horizontal, int vertical)
int RowsCoveredByPanel() int RowsCoveredByPanel()
{ {
FunctionProfiler profiler(__func__);
auto &mainPanelSize = GetMainPanel().size; auto &mainPanelSize = GetMainPanel().size;
if (GetScreenWidth() <= mainPanelSize.width) { if (GetScreenWidth() <= mainPanelSize.width) {
return 0; return 0;
@ -1387,6 +1420,7 @@ int RowsCoveredByPanel()
void CalcTileOffset(int *offsetX, int *offsetY) void CalcTileOffset(int *offsetX, int *offsetY)
{ {
FunctionProfiler profiler(__func__);
uint16_t screenWidth = GetScreenWidth(); uint16_t screenWidth = GetScreenWidth();
uint16_t viewportHeight = GetViewportHeight(); uint16_t viewportHeight = GetViewportHeight();
@ -1412,6 +1446,7 @@ void CalcTileOffset(int *offsetX, int *offsetY)
void TilesInView(int *rcolumns, int *rrows) void TilesInView(int *rcolumns, int *rrows)
{ {
FunctionProfiler profiler(__func__);
uint16_t screenWidth = GetScreenWidth(); uint16_t screenWidth = GetScreenWidth();
uint16_t viewportHeight = GetViewportHeight(); uint16_t viewportHeight = GetViewportHeight();
@ -1489,6 +1524,7 @@ void CalcViewportGeometry()
Point GetScreenPosition(Point tile) Point GetScreenPosition(Point tile)
{ {
FunctionProfiler profiler(__func__);
Point firstTile = ViewPosition; Point firstTile = ViewPosition;
Displacement offset = {}; Displacement offset = {};
CalcFirstTilePosition(firstTile, offset); CalcFirstTilePosition(firstTile, offset);
@ -1507,6 +1543,7 @@ void ClearScreenBuffer()
{ {
if (HeadlessMode) if (HeadlessMode)
return; return;
FunctionProfiler profiler(__func__);
assert(PalSurface != nullptr); assert(PalSurface != nullptr);
SDL_FillRect(PalSurface, nullptr, 0); SDL_FillRect(PalSurface, nullptr, 0);
@ -1583,6 +1620,7 @@ void scrollrt_draw_game_screen()
{ {
if (HeadlessMode) if (HeadlessMode)
return; return;
FunctionProfiler profiler(__func__);
int hgt = 0; int hgt = 0;
@ -1604,6 +1642,7 @@ void DrawAndBlit()
if (!gbRunGame || HeadlessMode) { if (!gbRunGame || HeadlessMode) {
return; return;
} }
FunctionProfiler profiler(__func__);
int hgt = 0; int hgt = 0;
bool drawHealth = IsRedrawComponent(PanelDrawComponent::Health); bool drawHealth = IsRedrawComponent(PanelDrawComponent::Health);

1
Source/engine/render/scrollrt.h

@ -7,6 +7,7 @@
#include <cstdint> #include <cstdint>
#include <utils/profiler.h>
#include "engine.h" #include "engine.h"
#include "engine/animationinfo.h" #include "engine/animationinfo.h"
#include "engine/point.hpp" #include "engine/point.hpp"

7
Source/engine/render/text_render.cpp

@ -15,6 +15,7 @@
#include <fmt/core.h> #include <fmt/core.h>
#include "utils/profiler.h"
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
#include "DiabloUI/ui_item.h" #include "DiabloUI/ui_item.h"
#include "engine.h" #include "engine.h"
@ -469,6 +470,7 @@ void UnloadFonts()
int GetLineWidth(std::string_view text, GameFontTables size, int spacing, int *charactersInLine) int GetLineWidth(std::string_view text, GameFontTables size, int spacing, int *charactersInLine)
{ {
FunctionProfiler profiler(__func__);
int lineWidth = 0; int lineWidth = 0;
CurrentFont currentFont; CurrentFont currentFont;
uint32_t codepoints = 0; uint32_t codepoints = 0;
@ -502,6 +504,7 @@ int GetLineWidth(std::string_view text, GameFontTables size, int spacing, int *c
int GetLineWidth(std::string_view fmt, DrawStringFormatArg *args, std::size_t argsLen, size_t argsOffset, GameFontTables size, int spacing, int *charactersInLine) int GetLineWidth(std::string_view fmt, DrawStringFormatArg *args, std::size_t argsLen, size_t argsOffset, GameFontTables size, int spacing, int *charactersInLine)
{ {
FunctionProfiler profiler(__func__);
int lineWidth = 0; int lineWidth = 0;
CurrentFont currentFont; CurrentFont currentFont;
@ -555,6 +558,7 @@ int GetLineWidth(std::string_view fmt, DrawStringFormatArg *args, std::size_t ar
int GetLineHeight(std::string_view text, GameFontTables fontIndex) int GetLineHeight(std::string_view text, GameFontTables fontIndex)
{ {
FunctionProfiler profiler(__func__);
if (fontIndex == GameFont12 && IsSmallFontTall() && ContainsSmallFontTallCodepoints(text)) { if (fontIndex == GameFont12 && IsSmallFontTall() && ContainsSmallFontTallCodepoints(text)) {
return SmallFontTallLineHeight; return SmallFontTallLineHeight;
} }
@ -574,6 +578,7 @@ int AdjustSpacingToFitHorizontally(int &lineWidth, int maxSpacing, int character
std::string WordWrapString(std::string_view text, unsigned width, GameFontTables size, int spacing) std::string WordWrapString(std::string_view text, unsigned width, GameFontTables size, int spacing)
{ {
FunctionProfiler profiler(__func__);
std::string output; std::string output;
if (text.empty() || text[0] == '\0') if (text.empty() || text[0] == '\0')
return output; return output;
@ -660,6 +665,7 @@ std::string WordWrapString(std::string_view text, unsigned width, GameFontTables
*/ */
uint32_t DrawString(const Surface &out, std::string_view text, const Rectangle &rect, UiFlags flags, int spacing, int lineHeight) uint32_t DrawString(const Surface &out, std::string_view text, const Rectangle &rect, UiFlags flags, int spacing, int lineHeight)
{ {
FunctionProfiler profiler(__func__);
GameFontTables size = GetSizeFromFlags(flags); GameFontTables size = GetSizeFromFlags(flags);
text_color color = GetColorFromFlags(flags); text_color color = GetColorFromFlags(flags);
@ -710,6 +716,7 @@ uint32_t DrawString(const Surface &out, std::string_view text, const Rectangle &
void DrawStringWithColors(const Surface &out, std::string_view fmt, DrawStringFormatArg *args, std::size_t argsLen, const Rectangle &rect, UiFlags flags, int spacing, int lineHeight) void DrawStringWithColors(const Surface &out, std::string_view fmt, DrawStringFormatArg *args, std::size_t argsLen, const Rectangle &rect, UiFlags flags, int spacing, int lineHeight)
{ {
FunctionProfiler profiler(__func__);
GameFontTables size = GetSizeFromFlags(flags); GameFontTables size = GetSizeFromFlags(flags);
text_color color = GetColorFromFlags(flags); text_color color = GetColorFromFlags(flags);

59
Source/utils/profiler.cpp

@ -0,0 +1,59 @@
#include <utils/profiler.h>
#include <algorithm>
#include <unordered_map>
#include <windows.h>
#include <SDL.h>
std::unordered_map<std::string, TimingInfo> timings;
FunctionProfiler::FunctionProfiler(std::string name)
: _name(name)
{
LARGE_INTEGER frequency;
if (QueryPerformanceFrequency(&frequency)) {
_frequency = frequency.QuadPart;
} else {
_frequency = 1000;
}
LARGE_INTEGER ticks;
if (QueryPerformanceCounter(&ticks)) {
_start = ticks.QuadPart;
} else {
_start = SDL_GetTicks() * _frequency / 1000;
}
}
FunctionProfiler::~FunctionProfiler()
{
LARGE_INTEGER ticks;
uint64_t now;
if (QueryPerformanceCounter(&ticks)) {
now = ticks.QuadPart;
} else {
now = SDL_GetTicks() * _frequency / 1000;
}
double ms = (double)(now - _start) * 1000.0 / (double)_frequency;
TimingInfo &timing = timings[_name];
timing.ms += ms;
timing.count++;
}
static bool CompareTiming(const TimingInfo &a, const TimingInfo &b)
{
return a.ms > b.ms;
}
std::vector<TimingInfo> FunctionProfiler::Dump()
{
std::vector<TimingInfo> timingList;
for (auto it = timings.begin(); it != timings.end(); ++it) {
it->second.name = it->first;
timingList.push_back(it->second);
}
std::sort(timingList.begin(), timingList.end(), CompareTiming);
return timingList;
}

22
Source/utils/profiler.h

@ -0,0 +1,22 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
struct TimingInfo {
std::string name;
double ms;
int count;
};
class FunctionProfiler {
public:
FunctionProfiler(std::string name);
~FunctionProfiler();
static std::vector<TimingInfo> Dump();
private:
std::string _name;
uint64_t _frequency;
uint64_t _start;
};
Loading…
Cancel
Save