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 10 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; 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 */ /** @brief Number of supported light levels */
constexpr size_t NumLightingLevels = LightsMax + 1; 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, Lightmap::Lightmap(const uint8_t *outBuffer, uint16_t outPitch,
std::span<const uint8_t> lightmapBuffer, uint16_t lightmapPitch, 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) : outBuffer(outBuffer)
, outPitch(outPitch) , outPitch(outPitch)
, lightmapBuffer(lightmapBuffer) , lightmapBuffer(lightmapBuffer)
, lightmapPitch(lightmapPitch) , lightmapPitch(lightmapPitch)
, lightTables(lightTables) , lightTables(lightTables)
, lightTableSize(lightTableSize)
{ {
} }
Lightmap Lightmap::build(bool perPixelLighting, Point tilePosition, Point targetBufferPosition, Lightmap Lightmap::build(bool perPixelLighting, Point tilePosition, Point targetBufferPosition,
int viewportWidth, int viewportHeight, int rows, int columns, int viewportWidth, int viewportHeight, int rows, int columns,
const uint8_t *outBuffer, uint16_t outPitch, 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], const uint8_t tileLights[MAXDUNX][MAXDUNY],
uint_fast8_t microTileLen) uint_fast8_t microTileLen)
{ {
if (perPixelLighting) { if (perPixelLighting) {
BuildLightmap(tilePosition, targetBufferPosition, viewportWidth, viewportHeight, rows, columns, tileLights, microTileLen); 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) 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, return Lightmap(outBuffer, source.outPitch,
lightmapBuffer, lightmapPitch, lightmapBuffer, lightmapPitch,
source.lightTables, source.lightTableSize); source.lightTables);
} }
} // namespace devilution } // namespace devilution

18
Source/engine/render/light_render.hpp

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

3
Source/lighting.cpp

@ -15,6 +15,7 @@
#include "automap.h" #include "automap.h"
#include "engine/displacement.hpp" #include "engine/displacement.hpp"
#include "engine/lighting_defs.hpp"
#include "engine/load_file.hpp" #include "engine/load_file.hpp"
#include "engine/point.hpp" #include "engine/point.hpp"
#include "engine/points_in_rectangle_range.hpp" #include "engine/points_in_rectangle_range.hpp"
@ -34,7 +35,7 @@ Light VisionList[MAXVISION];
Light Lights[MAXLIGHTS]; Light Lights[MAXLIGHTS];
std::array<uint8_t, MAXLIGHTS> ActiveLights; std::array<uint8_t, MAXLIGHTS> ActiveLights;
int ActiveLightCount; 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 *FullyLitLightTable = nullptr;
uint8_t *FullyDarkLightTable = nullptr; uint8_t *FullyDarkLightTable = nullptr;
std::array<uint8_t, 256> InfravisionTable; 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 Light Lights[MAXLIGHTS];
extern std::array<uint8_t, MAXLIGHTS> ActiveLights; extern std::array<uint8_t, MAXLIGHTS> ActiveLights;
extern int ActiveLightCount; 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. */ /** @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; 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. */ /** @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 <cstddef>
#include <cstdint>
#include <span> #include <span>
#include <ankerl/unordered_dense.h> #include <ankerl/unordered_dense.h>
@ -8,6 +10,7 @@
#include "engine/assets.hpp" #include "engine/assets.hpp"
#include "engine/clx_sprite.hpp" #include "engine/clx_sprite.hpp"
#include "engine/displacement.hpp" #include "engine/displacement.hpp"
#include "engine/lighting_defs.hpp"
#include "engine/load_file.hpp" #include "engine/load_file.hpp"
#include "engine/render/dun_render.hpp" #include "engine/render/dun_render.hpp"
#include "engine/surface.hpp" #include "engine/surface.hpp"
@ -66,7 +69,8 @@ void InitOnce()
void RunForTileMaskLight(benchmark::State &state, TileType tileType, MaskType maskType, const uint8_t *lightTable) void RunForTileMaskLight(benchmark::State &state, TileType tileType, MaskType maskType, const uint8_t *lightTable)
{ {
Surface out = Surface(SdlSurface.get()); 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]; const std::span<const LevelCelBlock> tiles = Tiles[tileType];
for (auto _ : state) { for (auto _ : state) {
for (const LevelCelBlock &levelCelBlock : tiles) { 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"; const std::string benchmarkDataPath = paths::BasePath() + "test/fixtures/light_render_benchmark/dLight.dmp";
FILE *lightFile = std::fopen(benchmarkDataPath.c_str(), "rb"); FILE *lightFile = std::fopen(benchmarkDataPath.c_str(), "rb");
uint8_t dLight[MAXDUNX][MAXDUNY]; 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 (lightFile != nullptr) {
if (std::fread(&dLight[0][0], sizeof(uint8_t) * MAXDUNX * MAXDUNY, 1, lightFile) != 1) { if (std::fread(&dLight[0][0], sizeof(uint8_t) * MAXDUNX * MAXDUNY, 1, lightFile) != 1) {
std::perror("Failed to read dLight.dmp"); std::perror("Failed to read dLight.dmp");
@ -50,7 +50,7 @@ void BM_BuildLightmap(benchmark::State &state)
Lightmap lightmap = Lightmap::build(/*perPixelLighting=*/true, Lightmap lightmap = Lightmap::build(/*perPixelLighting=*/true,
tilePosition, targetBufferPosition, tilePosition, targetBufferPosition,
viewportWidth, viewportHeight, rows, columns, viewportWidth, viewportHeight, rows, columns,
outBuffer, outPitch, lightTables[0].data(), lightTables[0].size(), outBuffer, outPitch, lightTables,
dLight, /*microTileLen=*/10); dLight, /*microTileLen=*/10);
uint8_t lightLevel = *lightmap.getLightingAt(outBuffer + outPitch * 120 + 120); uint8_t lightLevel = *lightmap.getLightingAt(outBuffer + outPitch * 120 + 120);

Loading…
Cancel
Save