Browse Source

light_render: Use an std::span for light tables

1. There is no need to store the light table width as it is always 256.
2. Use a fixed-extent `std::span` rather than a pointer for readability.
   This should optimize to the exact same code.
pull/8064/head
Gleb Mazovetskiy 9 months ago
parent
commit
54e30ff210
  1. 3
      Source/engine/lighting_defs.hpp
  2. 9
      Source/engine/render/light_render.cpp
  3. 18
      Source/engine/render/light_render.hpp
  4. 2
      Source/engine/render/scrollrt.cpp
  5. 3
      Source/lighting.cpp
  6. 2
      Source/lighting.h
  7. 6
      test/dun_render_benchmark.cpp
  8. 4
      test/light_render_benchmark.cpp

3
Source/engine/lighting_defs.hpp

@ -10,6 +10,9 @@ namespace devilution {
constexpr char LightsMax = 15;
/** @brief A light table maps palette indices, so its size is the same as the palette size. */
constexpr size_t LightTableSize = 256;
/** @brief Number of supported light levels */
constexpr size_t NumLightingLevels = LightsMax + 1;

9
Source/engine/render/light_render.cpp

@ -491,27 +491,26 @@ void BuildLightmap(Point tilePosition, Point targetBufferPosition, uint16_t view
Lightmap::Lightmap(const uint8_t *outBuffer, uint16_t outPitch,
std::span<const uint8_t> lightmapBuffer, uint16_t lightmapPitch,
const uint8_t *lightTables, size_t lightTableSize)
std::span<const std::array<uint8_t, LightTableSize>, NumLightingLevels> lightTables)
: outBuffer(outBuffer)
, outPitch(outPitch)
, lightmapBuffer(lightmapBuffer)
, lightmapPitch(lightmapPitch)
, lightTables(lightTables)
, lightTableSize(lightTableSize)
{
}
Lightmap Lightmap::build(bool perPixelLighting, Point tilePosition, Point targetBufferPosition,
int viewportWidth, int viewportHeight, int rows, int columns,
const uint8_t *outBuffer, uint16_t outPitch,
const uint8_t *lightTables, size_t lightTableSize,
std::span<const std::array<uint8_t, LightTableSize>, NumLightingLevels> lightTables,
const uint8_t tileLights[MAXDUNX][MAXDUNY],
uint_fast8_t microTileLen)
{
if (perPixelLighting) {
BuildLightmap(tilePosition, targetBufferPosition, viewportWidth, viewportHeight, rows, columns, tileLights, microTileLen);
}
return Lightmap(outBuffer, outPitch, LightmapBuffer, viewportWidth, lightTables, lightTableSize);
return Lightmap(outBuffer, outPitch, LightmapBuffer, viewportWidth, lightTables);
}
Lightmap Lightmap::bleedUp(bool perPixelLighting, const Lightmap &source, Point targetBufferPosition, std::span<uint8_t> lightmapBuffer)
@ -566,7 +565,7 @@ Lightmap Lightmap::bleedUp(bool perPixelLighting, const Lightmap &source, Point
return Lightmap(outBuffer, source.outPitch,
lightmapBuffer, lightmapPitch,
source.lightTables, source.lightTableSize);
source.lightTables);
}
} // namespace devilution

18
Source/engine/render/light_render.hpp

@ -1,9 +1,11 @@
#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
#include <span>
#include "engine/lighting_defs.hpp"
#include "engine/point.hpp"
#include "levels/gendung_defs.hpp"
@ -11,19 +13,18 @@ namespace devilution {
class Lightmap {
public:
explicit Lightmap(const uint8_t *outBuffer, std::span<const uint8_t> lightmapBuffer, uint16_t pitch, const uint8_t *lightTables, size_t lightTableSize)
: Lightmap(outBuffer, pitch, lightmapBuffer, pitch, lightTables, lightTableSize)
explicit Lightmap(const uint8_t *outBuffer, std::span<const uint8_t> lightmapBuffer, uint16_t pitch, std::span<const std::array<uint8_t, LightTableSize>, NumLightingLevels> lightTables)
: Lightmap(outBuffer, pitch, lightmapBuffer, pitch, lightTables)
{
}
explicit Lightmap(const uint8_t *outBuffer, uint16_t outPitch,
std::span<const uint8_t> lightmapBuffer, uint16_t lightmapPitch,
const uint8_t *lightTables, size_t lightTableSize);
std::span<const std::array<uint8_t, LightTableSize>, NumLightingLevels> lightTables);
uint8_t adjustColor(uint8_t color, uint8_t lightLevel) const
[[nodiscard]] uint8_t adjustColor(uint8_t color, uint8_t lightLevel) const
{
size_t offset = lightLevel * lightTableSize + color;
return lightTables[offset];
return lightTables[lightLevel][color];
}
const uint8_t *getLightingAt(const uint8_t *outLoc) const
@ -45,7 +46,7 @@ public:
static Lightmap build(bool perPixelLighting, Point tilePosition, Point targetBufferPosition,
int viewportWidth, int viewportHeight, int rows, int columns,
const uint8_t *outBuffer, uint16_t outPitch,
const uint8_t *lightTables, size_t lightTableSize,
std::span<const std::array<uint8_t, LightTableSize>, NumLightingLevels> lightTables,
const uint8_t tileLights[MAXDUNX][MAXDUNY],
uint_fast8_t microTileLen);
@ -58,8 +59,7 @@ private:
std::span<const uint8_t> lightmapBuffer;
const uint16_t lightmapPitch;
const uint8_t *lightTables;
const size_t lightTableSize;
std::span<const std::array<uint8_t, LightTableSize>, NumLightingLevels> lightTables;
};
} // namespace devilution

2
Source/engine/render/scrollrt.cpp

@ -1133,7 +1133,7 @@ void DrawGame(const Surface &fullOut, Point position, Displacement offset)
Lightmap lightmap = Lightmap::build(*GetOptions().Graphics.perPixelLighting, position, Point {} + offset,
gnScreenWidth, gnViewportHeight, rows, columns,
out.at(0, 0), out.pitch(), LightTables[0].data(), LightTables[0].size(),
out.at(0, 0), out.pitch(), LightTables,
dLight, MicroTileLen);
DrawFloor(out, lightmap, position, Point {} + offset, rows, columns);

3
Source/lighting.cpp

@ -15,6 +15,7 @@
#include "automap.h"
#include "engine/displacement.hpp"
#include "engine/lighting_defs.hpp"
#include "engine/load_file.hpp"
#include "engine/point.hpp"
#include "engine/points_in_rectangle_range.hpp"
@ -34,7 +35,7 @@ Light VisionList[MAXVISION];
Light Lights[MAXLIGHTS];
std::array<uint8_t, MAXLIGHTS> ActiveLights;
int ActiveLightCount;
std::array<std::array<uint8_t, 256>, NumLightingLevels> LightTables;
std::array<std::array<uint8_t, LightTableSize>, NumLightingLevels> LightTables;
uint8_t *FullyLitLightTable = nullptr;
uint8_t *FullyDarkLightTable = nullptr;
std::array<uint8_t, 256> InfravisionTable;

2
Source/lighting.h

@ -40,7 +40,7 @@ extern std::array<bool, MAXVISION> VisionActive;
extern Light Lights[MAXLIGHTS];
extern std::array<uint8_t, MAXLIGHTS> ActiveLights;
extern int ActiveLightCount;
extern DVL_API_FOR_TEST std::array<std::array<uint8_t, 256>, NumLightingLevels> LightTables;
extern DVL_API_FOR_TEST std::array<std::array<uint8_t, LightTableSize>, NumLightingLevels> LightTables;
/** @brief Contains a pointer to a light table that is fully lit (no color mapping is required). Can be null in hell. */
extern DVL_API_FOR_TEST uint8_t *FullyLitLightTable;
/** @brief Contains a pointer to a light table that is fully dark (every color result to 0/black). Can be null in hellfire levels. */

6
test/dun_render_benchmark.cpp

@ -1,4 +1,6 @@
#include <array>
#include <cstddef>
#include <cstdint>
#include <span>
#include <ankerl/unordered_dense.h>
@ -8,6 +10,7 @@
#include "engine/assets.hpp"
#include "engine/clx_sprite.hpp"
#include "engine/displacement.hpp"
#include "engine/lighting_defs.hpp"
#include "engine/load_file.hpp"
#include "engine/render/dun_render.hpp"
#include "engine/surface.hpp"
@ -66,7 +69,8 @@ void InitOnce()
void RunForTileMaskLight(benchmark::State &state, TileType tileType, MaskType maskType, const uint8_t *lightTable)
{
Surface out = Surface(SdlSurface.get());
Lightmap lightmap(nullptr, {}, 1, nullptr, 0);
std::array<std::array<uint8_t, LightTableSize>, NumLightingLevels> lightTables;
Lightmap lightmap(/*outBuffer=*/nullptr, /*lightmapBuffer=*/ {}, /*pitch=*/1, lightTables);
const std::span<const LevelCelBlock> tiles = Tiles[tileType];
for (auto _ : state) {
for (const LevelCelBlock &levelCelBlock : tiles) {

4
test/light_render_benchmark.cpp

@ -20,7 +20,7 @@ void BM_BuildLightmap(benchmark::State &state)
const std::string benchmarkDataPath = paths::BasePath() + "test/fixtures/light_render_benchmark/dLight.dmp";
FILE *lightFile = std::fopen(benchmarkDataPath.c_str(), "rb");
uint8_t dLight[MAXDUNX][MAXDUNY];
std::array<std::array<uint8_t, 256>, LightsMax> lightTables;
std::array<std::array<uint8_t, LightTableSize>, NumLightingLevels> lightTables;
if (lightFile != nullptr) {
if (std::fread(&dLight[0][0], sizeof(uint8_t) * MAXDUNX * MAXDUNY, 1, lightFile) != 1) {
std::perror("Failed to read dLight.dmp");
@ -50,7 +50,7 @@ void BM_BuildLightmap(benchmark::State &state)
Lightmap lightmap = Lightmap::build(/*perPixelLighting=*/true,
tilePosition, targetBufferPosition,
viewportWidth, viewportHeight, rows, columns,
outBuffer, outPitch, lightTables[0].data(), lightTables[0].size(),
outBuffer, outPitch, lightTables,
dLight, /*microTileLen=*/10);
uint8_t lightLevel = *lightmap.getLightingAt(outBuffer + outPitch * 120 + 120);

Loading…
Cancel
Save