Skip to content

Commit

Permalink
Populate command buffer inside each manager.
Browse files Browse the repository at this point in the history
This fixes the issue with reflected entities flickering inside puddles.
  • Loading branch information
afritz1 committed Aug 3, 2024
1 parent 0ea3eed commit 8fd40b1
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 74 deletions.
39 changes: 7 additions & 32 deletions OpenTESArena/src/Interface/GameWorldPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,8 @@ void GameWorldPanel::initUiDrawCalls()

bool GameWorldPanel::gameWorldRenderCallback(Game &game)
{
RenderCommandBuffer commandBuffer;
static RenderCommandBuffer commandBuffer;
commandBuffer.clear();

// Draw game world onto the native frame buffer. The game world buffer might not completely fill
// up the native buffer (bottom corners), so clearing the native buffer beforehand is still necessary.
Expand All @@ -813,41 +814,17 @@ bool GameWorldPanel::gameWorldRenderCallback(Game &game)

const SceneManager &sceneManager = game.getSceneManager();
const RenderSkyManager &renderSkyManager = sceneManager.renderSkyManager;
const BufferView<const RenderDrawCall> skyObjectDrawCalls = renderSkyManager.getObjectDrawCalls();
const RenderDrawCall &skyBgDrawCall = renderSkyManager.getBgDrawCall();
commandBuffer.addDrawCalls(BufferView<const RenderDrawCall>(&skyBgDrawCall, 1));
commandBuffer.addDrawCalls(skyObjectDrawCalls);
renderSkyManager.populateCommandBuffer(commandBuffer);

const RenderVoxelChunkManager &renderVoxelChunkManager = sceneManager.renderVoxelChunkManager;
const BufferView<const RenderDrawCall> voxelDrawCalls = renderVoxelChunkManager.getDrawCalls();
commandBuffer.addDrawCalls(voxelDrawCalls);
renderVoxelChunkManager.populateCommandBuffer(commandBuffer);

const RenderEntityChunkManager &renderEntityChunkManager = sceneManager.renderEntityChunkManager;
const BufferView<const RenderDrawCall> entityDrawCalls = renderEntityChunkManager.getDrawCalls();
commandBuffer.addDrawCalls(entityDrawCalls);
renderEntityChunkManager.populateCommandBuffer(commandBuffer);

const RenderWeatherManager &renderWeatherManager = sceneManager.renderWeatherManager;
const bool isFoggy = gameState.isFogActive();
if (activeWeatherInst.hasFog())
{
if (isFoggy)
{
const RenderDrawCall &fogDrawCall = renderWeatherManager.getFogDrawCall();
commandBuffer.addDrawCalls(BufferView<const RenderDrawCall>(&fogDrawCall, 1));
}
}

if (activeWeatherInst.hasRain())
{
const BufferView<const RenderDrawCall> rainDrawCalls = renderWeatherManager.getRainDrawCalls();
commandBuffer.addDrawCalls(rainDrawCalls);
}

if (activeWeatherInst.hasSnow())
{
const BufferView<const RenderDrawCall> snowDrawCalls = renderWeatherManager.getSnowDrawCalls();
commandBuffer.addDrawCalls(snowDrawCalls);
}
renderWeatherManager.populateCommandBuffer(commandBuffer, activeWeatherInst, isFoggy);

const MapType activeMapType = activeMapDef.getMapType();
const double ambientPercent = ArenaRenderUtils::getAmbientPercent(gameState.getClock(), activeMapType, isFoggy);
Expand Down Expand Up @@ -879,10 +856,8 @@ bool GameWorldPanel::gameWorldRenderCallback(Game &game)
lightTableTextureID = sceneManager.normalLightTableNightTextureRef.get();
}

const ObjectTextureID skyBgTextureID = skyBgDrawCall.textureIDs[0];
const DitheringMode ditheringMode = static_cast<DitheringMode>(options.getGraphics_DitheringMode());

renderer.submitFrame(renderCamera, commandBuffer, ambientPercent, paletteTextureID, lightTableTextureID, skyBgTextureID,
renderer.submitFrame(renderCamera, commandBuffer, ambientPercent, paletteTextureID, lightTableTextureID, renderSkyManager.getBgTextureID(),
options.getGraphics_RenderThreadsMode(), ditheringMode);

return true;
Expand Down
2 changes: 1 addition & 1 deletion OpenTESArena/src/Rendering/RenderCommandBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void RenderCommandBuffer::addDrawCalls(BufferView<const RenderDrawCall> drawCall
{
if (this->entryCount >= static_cast<int>(std::size(this->entries)))
{
DebugLogError("Too many entries in command buffer.");
DebugLogError("Too many entries in command buffer, can't add range of " + std::to_string(drawCalls.getCount()) + " draw call(s).");
return;
}

Expand Down
8 changes: 4 additions & 4 deletions OpenTESArena/src/Rendering/RenderCommandBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@

struct RenderCommandBuffer
{
static constexpr int MAX_ENTRIES = 8;
static constexpr int MAX_ENTRIES = 4096; // Allowing a lot more than usual for large view distance involving puddles.

// One per category of draw calls (voxels, entities, weather, sky, etc). Each draw call range starts execution
// once the previous set is complete, ensuring correctness in the final image. Meant for proper rendering of
// more involved effects like screen-space reflections that impact the renderer's ability to multi-task.
// One per range of draw calls (voxels, entities, weather, sky, etc). Each range starts execution once the previous one
// is complete, ensuring correctness in the final image. Meant for proper rendering of more involved effects like
// screen-space reflections that impact the renderer's ability to multi-task.
BufferView<const RenderDrawCall> entries[MAX_ENTRIES];
int entryCount;

Expand Down
40 changes: 35 additions & 5 deletions OpenTESArena/src/Rendering/RenderEntityChunkManager.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <algorithm>
#include <array>

#include "RenderCommandBuffer.h"
#include "RenderEntityChunkManager.h"
#include "Renderer.h"
#include "RenderLightChunkManager.h"
Expand Down Expand Up @@ -238,11 +239,6 @@ ObjectTextureID RenderEntityChunkManager::getTextureID(EntityInstanceID entityIn
return textureRefs.get(linearizedKeyframeIndex).get();
}

BufferView<const RenderDrawCall> RenderEntityChunkManager::getDrawCalls() const
{
return this->drawCallsCache;
}

void RenderEntityChunkManager::loadTextures(const EntityChunk &entityChunk, const EntityChunkManager &entityChunkManager,
TextureManager &textureManager, Renderer &renderer)
{
Expand Down Expand Up @@ -407,6 +403,40 @@ void RenderEntityChunkManager::rebuildDrawCallsList()
}
}

void RenderEntityChunkManager::populateCommandBuffer(RenderCommandBuffer &commandBuffer) const
{
// Need to have barriers around puddle draw calls to avoid artifacts with reflected entities.
int currentStartIndex = 0;
int currentCount = 0;

const int drawCallCount = static_cast<int>(this->drawCallsCache.size());
for (int i = 0; i < drawCallCount; i++)
{
const RenderDrawCall &drawCall = this->drawCallsCache[i];
const bool isPuddle = drawCall.pixelShaderType == PixelShaderType::AlphaTestedWithHorizonMirror;
if (isPuddle)
{
if (currentCount > 0)
{
commandBuffer.addDrawCalls(BufferView<const RenderDrawCall>(this->drawCallsCache.data() + currentStartIndex, currentCount));
currentCount = 0;
}

commandBuffer.addDrawCalls(BufferView<const RenderDrawCall>(this->drawCallsCache.data() + i, 1));
currentStartIndex = i + 1;
continue;
}

currentCount++;
}

if (currentCount > 0)
{
// Add one last draw call range.
commandBuffer.addDrawCalls(BufferView<const RenderDrawCall>(this->drawCallsCache.data() + currentStartIndex, currentCount));
}
}

void RenderEntityChunkManager::updateActiveChunks(BufferView<const ChunkInt2> newChunkPositions, BufferView<const ChunkInt2> freedChunkPositions,
const VoxelChunkManager &voxelChunkManager, Renderer &renderer)
{
Expand Down
3 changes: 2 additions & 1 deletion OpenTESArena/src/Rendering/RenderEntityChunkManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class VoxelChunkManager;
struct EntityAnimationInstance;
struct EntityVisibilityChunk;
struct RenderCamera;
struct RenderCommandBuffer;

class RenderEntityChunkManager final : public SpecializedChunkManager<RenderEntityChunk>
{
Expand Down Expand Up @@ -71,7 +72,7 @@ class RenderEntityChunkManager final : public SpecializedChunkManager<RenderEnti
void init(Renderer &renderer);
void shutdown(Renderer &renderer);

BufferView<const RenderDrawCall> getDrawCalls() const;
void populateCommandBuffer(RenderCommandBuffer &commandBuffer) const;

// Chunk allocating/freeing update function, called before entity resources are updated.
void updateActiveChunks(BufferView<const ChunkInt2> newChunkPositions, BufferView<const ChunkInt2> freedChunkPositions,
Expand Down
22 changes: 12 additions & 10 deletions OpenTESArena/src/Rendering/RenderSkyManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <vector>

#include "ArenaRenderUtils.h"
#include "RenderCommandBuffer.h"
#include "Renderer.h"
#include "RenderSkyManager.h"
#include "RenderTransform.h"
Expand Down Expand Up @@ -474,16 +475,6 @@ void RenderSkyManager::freeObjectBuffers(Renderer &renderer)
this->smallStarTextures.clear();
}

const RenderDrawCall &RenderSkyManager::getBgDrawCall() const
{
return this->bgDrawCall;
}

BufferView<const RenderDrawCall> RenderSkyManager::getObjectDrawCalls() const
{
return this->objectDrawCalls;
}

void RenderSkyManager::loadScene(const SkyInstance &skyInst, const SkyInfoDefinition &skyInfoDef, TextureManager &textureManager, Renderer &renderer)
{
auto tryLoadTextureAsset = [this, &textureManager, &renderer](const TextureAsset &textureAsset)
Expand Down Expand Up @@ -630,6 +621,17 @@ void RenderSkyManager::loadScene(const SkyInstance &skyInst, const SkyInfoDefini
}
}

ObjectTextureID RenderSkyManager::getBgTextureID() const
{
return this->bgDrawCall.textureIDs[0];
}

void RenderSkyManager::populateCommandBuffer(RenderCommandBuffer &commandBuffer) const
{
commandBuffer.addDrawCalls(BufferView<const RenderDrawCall>(&this->bgDrawCall, 1));
commandBuffer.addDrawCalls(this->objectDrawCalls);
}

void RenderSkyManager::update(const SkyInstance &skyInst, const SkyVisibilityManager &skyVisManager, const WeatherInstance &weatherInst,
const CoordDouble3 &cameraCoord, bool isInterior, double daytimePercent, bool isFoggy, double distantAmbientPercent,
Renderer &renderer)
Expand Down
6 changes: 4 additions & 2 deletions OpenTESArena/src/Rendering/RenderSkyManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ class WeatherInstance;

enum class WeatherType;

struct RenderCommandBuffer;

class RenderSkyManager
{
private:
Expand Down Expand Up @@ -71,8 +73,8 @@ class RenderSkyManager
void init(const ExeData &exeData, TextureManager &textureManager, Renderer &renderer);
void shutdown(Renderer &renderer);

const RenderDrawCall &getBgDrawCall() const;
BufferView<const RenderDrawCall> getObjectDrawCalls() const;
ObjectTextureID getBgTextureID() const;
void populateCommandBuffer(RenderCommandBuffer &commandBuffer) const;

void loadScene(const SkyInstance &skyInst, const SkyInfoDefinition &skyInfoDef, TextureManager &textureManager, Renderer &renderer);
void update(const SkyInstance &skyInst, const SkyVisibilityManager &skyVisManager, const WeatherInstance &weatherInst,
Expand Down
11 changes: 6 additions & 5 deletions OpenTESArena/src/Rendering/RenderVoxelChunkManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <numeric>
#include <optional>

#include "RenderCommandBuffer.h"
#include "RenderLightChunkManager.h"
#include "RenderVoxelChunkManager.h"
#include "Renderer.h"
Expand Down Expand Up @@ -490,11 +491,6 @@ ObjectTextureID RenderVoxelChunkManager::getChasmWallTextureID(const ChunkInt2 &
return objectTextureRef.get();
}

BufferView<const RenderDrawCall> RenderVoxelChunkManager::getDrawCalls() const
{
return BufferView<const RenderDrawCall>(this->drawCallsCache);
}

void RenderVoxelChunkManager::loadTextures(const VoxelChunk &voxelChunk, TextureManager &textureManager, Renderer &renderer)
{
for (int i = 0; i < voxelChunk.getTextureDefCount(); i++)
Expand Down Expand Up @@ -1288,6 +1284,11 @@ void RenderVoxelChunkManager::rebuildDrawCallsList(const VoxelVisibilityChunkMan
}
}

void RenderVoxelChunkManager::populateCommandBuffer(RenderCommandBuffer &commandBuffer) const
{
commandBuffer.addDrawCalls(this->drawCallsCache);
}

void RenderVoxelChunkManager::updateActiveChunks(BufferView<const ChunkInt2> newChunkPositions, BufferView<const ChunkInt2> freedChunkPositions,
const VoxelChunkManager &voxelChunkManager, Renderer &renderer)
{
Expand Down
3 changes: 2 additions & 1 deletion OpenTESArena/src/Rendering/RenderVoxelChunkManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class VoxelChunkManager;
class VoxelVisibilityChunkManager;

struct RenderCamera;
struct RenderCommandBuffer;
struct VoxelVisibilityChunk;

class RenderVoxelChunkManager final : public SpecializedChunkManager<RenderVoxelChunk>
Expand Down Expand Up @@ -98,7 +99,7 @@ class RenderVoxelChunkManager final : public SpecializedChunkManager<RenderVoxel
void init(Renderer &renderer);
void shutdown(Renderer &renderer);

BufferView<const RenderDrawCall> getDrawCalls() const;
void populateCommandBuffer(RenderCommandBuffer &commandBuffer) const;

// Chunk allocating/freeing update function, called before voxel resources are updated.
void updateActiveChunks(BufferView<const ChunkInt2> newChunkPositions, BufferView<const ChunkInt2> freedChunkPositions,
Expand Down
24 changes: 14 additions & 10 deletions OpenTESArena/src/Rendering/RenderWeatherManager.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <algorithm>

#include "RenderCamera.h"
#include "RenderCommandBuffer.h"
#include "RenderTransform.h"
#include "Renderer.h"
#include "RendererUtils.h"
Expand Down Expand Up @@ -462,19 +463,22 @@ void RenderWeatherManager::shutdown(Renderer &renderer)
this->fogDrawCall.clear();
}

BufferView<const RenderDrawCall> RenderWeatherManager::getRainDrawCalls() const
void RenderWeatherManager::populateCommandBuffer(RenderCommandBuffer &commandBuffer, const WeatherInstance &weatherInst, bool isFoggy) const
{
return this->rainDrawCalls;
}
if (weatherInst.hasFog() && isFoggy)
{
commandBuffer.addDrawCalls(BufferView<const RenderDrawCall>(&this->fogDrawCall, 1));
}

BufferView<const RenderDrawCall> RenderWeatherManager::getSnowDrawCalls() const
{
return this->snowDrawCalls;
}
if (weatherInst.hasRain())
{
commandBuffer.addDrawCalls(this->rainDrawCalls);
}

const RenderDrawCall &RenderWeatherManager::getFogDrawCall() const
{
return this->fogDrawCall;
if (weatherInst.hasSnow())
{
commandBuffer.addDrawCalls(this->snowDrawCalls);
}
}

void RenderWeatherManager::freeParticleBuffers(Renderer &renderer)
Expand Down
5 changes: 2 additions & 3 deletions OpenTESArena/src/Rendering/RenderWeatherManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
class WeatherInstance;

struct RenderCamera;
struct RenderCommandBuffer;

class RenderWeatherManager
{
Expand Down Expand Up @@ -47,9 +48,7 @@ class RenderWeatherManager
bool init(Renderer &renderer);
void shutdown(Renderer &renderer);

BufferView<const RenderDrawCall> getRainDrawCalls() const;
BufferView<const RenderDrawCall> getSnowDrawCalls() const;
const RenderDrawCall &getFogDrawCall() const;
void populateCommandBuffer(RenderCommandBuffer &commandBuffer, const WeatherInstance &weatherInst, bool isFoggy) const;

void loadScene();
void update(const WeatherInstance &weatherInst, const RenderCamera &camera, Renderer &renderer);
Expand Down

0 comments on commit 8fd40b1

Please sign in to comment.