Skip to content

Commit

Permalink
Extract render stats and fix any lingering resources
Browse files Browse the repository at this point in the history
  • Loading branch information
ultraq committed May 24, 2024
1 parent fb8ccb2 commit 4d0c067
Show file tree
Hide file tree
Showing 11 changed files with 129 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ class Application implements EventTarget {
private ApplicationEventHandler applicationStop
private boolean applicationStopping
private Semaphore applicationStoppingSemaphore = new Semaphore(1)
private DebugOverlay debugOverlay

/**
* Add the audio system to this application. The audio system will run on its
* own thread.
*/
Application addAudioSystem(AudioConfiguration config = new AudioConfiguration()) {

engine << new AudioSystem(config)
var audioSystem = new AudioSystem(config)
engine << audioSystem
return this
}

Expand All @@ -99,15 +99,9 @@ class Application implements EventTarget {
inputEventStream.addInputSource(event.window)
}
graphicsSystem.on(SystemReadyEvent) { event ->
var audioSystem = engine.systems.find { it instanceof AudioSystem } as AudioSystem
debugOverlay = new DebugOverlay(config.debug)
.addAudioRenderer(audioSystem.renderer)
.addGraphicsRenderer(graphicsSystem.renderer)
.toggleWith(inputEventStream, GLFW_KEY_D)
graphicsSystem.imGuiLayer.addOverlay(debugOverlay)
graphicsSystem.imGuiLayer.addOverlay(new DebugOverlay(config.debug).toggleWith(inputEventStream, GLFW_KEY_D))
graphicsSystem.imGuiLayer.addOverlay(new ControlsOverlay(inputEventStream).toggleWith(inputEventStream, GLFW_KEY_C))
graphicsSystem.imGuiLayer.addUiElement(new LogPanel(config.debug))

uiElements.each { overlayRenderPass ->
graphicsSystem.imGuiLayer.addUiElement(overlayRenderPass)
}
Expand Down Expand Up @@ -176,11 +170,12 @@ class Application implements EventTarget {
logger.warn("Not all ${resourceName} closed, {} remaining", resourceCount)
}
}
check(debugOverlay.activeFramebuffers.get(), 'framebuffers')
check(debugOverlay.activeMeshes.get(), 'meshes')
check(debugOverlay.activeTextures.get(), 'textures')
check(debugOverlay.activeSources.get(), 'sources')
check(debugOverlay.activeBuffers.get(), 'buffers')
var engineStats = EngineStats.instance
check(engineStats.activeFramebuffers.get(), 'framebuffers')
check(engineStats.activeMeshes.get(), 'meshes')
check(engineStats.activeTextures.get(), 'textures')
check(engineStats.activeSources.get(), 'sources')
check(engineStats.activeBuffers.get(), 'buffers')
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2024, Emanuel Rabina (http://www.ultraq.net.nz/)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package nz.net.ultraq.redhorizon.engine

import nz.net.ultraq.redhorizon.engine.audio.AudioRenderer
import nz.net.ultraq.redhorizon.engine.audio.AudioRendererEvent
import nz.net.ultraq.redhorizon.engine.audio.BufferCreatedEvent
import nz.net.ultraq.redhorizon.engine.audio.BufferDeletedEvent
import nz.net.ultraq.redhorizon.engine.audio.SourceCreatedEvent
import nz.net.ultraq.redhorizon.engine.audio.SourceDeletedEvent
import nz.net.ultraq.redhorizon.engine.graphics.DrawEvent
import nz.net.ultraq.redhorizon.engine.graphics.FramebufferCreatedEvent
import nz.net.ultraq.redhorizon.engine.graphics.FramebufferDeletedEvent
import nz.net.ultraq.redhorizon.engine.graphics.GraphicsRenderer
import nz.net.ultraq.redhorizon.engine.graphics.GraphicsRendererEvent
import nz.net.ultraq.redhorizon.engine.graphics.MeshCreatedEvent
import nz.net.ultraq.redhorizon.engine.graphics.MeshDeletedEvent
import nz.net.ultraq.redhorizon.engine.graphics.TextureCreatedEvent
import nz.net.ultraq.redhorizon.engine.graphics.TextureDeletedEvent

import java.util.concurrent.atomic.AtomicInteger

/**
* A record of several stats that we want to track for debugging purposes.
*
* @author Emanuel Rabina
*/
@Singleton
class EngineStats {

final AtomicInteger drawCalls = new AtomicInteger()
final AtomicInteger activeFramebuffers = new AtomicInteger()
final AtomicInteger activeMeshes = new AtomicInteger()
final AtomicInteger activeTextures = new AtomicInteger()

final AtomicInteger activeSources = new AtomicInteger()
final AtomicInteger activeBuffers = new AtomicInteger()

/**
* Add the audio renderer to get stats on audio sources, buffers, etc.
*/
EngineStats attachAudioRenderer(AudioRenderer audioRenderer) {

audioRenderer.on(AudioRendererEvent) { event ->
switch (event) {
case BufferCreatedEvent -> activeBuffers.incrementAndGet()
case BufferDeletedEvent -> activeBuffers.decrementAndGet()
case SourceCreatedEvent -> activeSources.incrementAndGet()
case SourceDeletedEvent -> activeSources.decrementAndGet()
}
}
return this
}

/**
* Add the graphics renderer to get stats on draws, textures, etc.
*/
EngineStats attachGraphicsRenderer(GraphicsRenderer graphicsRenderer) {

graphicsRenderer.on(GraphicsRendererEvent) { event ->
switch (event) {
case DrawEvent -> drawCalls.incrementAndGet()
case FramebufferCreatedEvent -> activeFramebuffers.incrementAndGet()
case FramebufferDeletedEvent -> activeFramebuffers.decrementAndGet()
case MeshCreatedEvent -> activeMeshes.incrementAndGet()
case MeshDeletedEvent -> activeMeshes.decrementAndGet()
case TextureCreatedEvent -> activeTextures.incrementAndGet()
case TextureDeletedEvent -> activeTextures.decrementAndGet()
}
}
return this
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package nz.net.ultraq.redhorizon.engine.audio

import nz.net.ultraq.redhorizon.engine.EngineStats
import nz.net.ultraq.redhorizon.engine.EngineSystem
import nz.net.ultraq.redhorizon.engine.SystemReadyEvent
import nz.net.ultraq.redhorizon.engine.SystemStoppedEvent
Expand Down Expand Up @@ -144,6 +145,7 @@ class AudioSystem extends EngineSystem implements AudioRequests {
context.withCurrent { ->
renderer = new OpenALRenderer(config)
logger.debug(renderer.toString())
EngineStats.instance.attachAudioRenderer(renderer)

listener = new OpenALListener(config.volume)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package nz.net.ultraq.redhorizon.engine.graphics

import nz.net.ultraq.redhorizon.engine.EngineStats
import nz.net.ultraq.redhorizon.engine.EngineSystem
import nz.net.ultraq.redhorizon.engine.SystemReadyEvent
import nz.net.ultraq.redhorizon.engine.SystemStoppedEvent
Expand Down Expand Up @@ -118,14 +119,6 @@ class GraphicsSystem extends EngineSystem implements GraphicsRequests {
return renderer
}

/**
* Return the rendering pipeline.
*/
RenderPipeline getRenderPipeline() {

return renderPipeline
}

/**
* Run through and complete any registered deletions, returning whether or not
* there were items to process.
Expand Down Expand Up @@ -230,6 +223,7 @@ class GraphicsSystem extends EngineSystem implements GraphicsRequests {

renderer = new OpenGLRenderer(config, window)
renderer.withCloseable { renderer ->
EngineStats.instance.attachGraphicsRenderer(renderer)

camera = new OpenGLCamera(window.renderResolution)
camera.withCloseable { camera ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,13 @@

package nz.net.ultraq.redhorizon.engine.graphics.imgui

import nz.net.ultraq.redhorizon.engine.audio.AudioRenderer
import nz.net.ultraq.redhorizon.engine.audio.AudioRendererEvent
import nz.net.ultraq.redhorizon.engine.audio.BufferCreatedEvent
import nz.net.ultraq.redhorizon.engine.audio.BufferDeletedEvent
import nz.net.ultraq.redhorizon.engine.audio.SourceCreatedEvent
import nz.net.ultraq.redhorizon.engine.audio.SourceDeletedEvent
import nz.net.ultraq.redhorizon.engine.graphics.DrawEvent
import nz.net.ultraq.redhorizon.engine.EngineStats
import nz.net.ultraq.redhorizon.engine.graphics.Framebuffer
import nz.net.ultraq.redhorizon.engine.graphics.FramebufferCreatedEvent
import nz.net.ultraq.redhorizon.engine.graphics.FramebufferDeletedEvent
import nz.net.ultraq.redhorizon.engine.graphics.GraphicsRenderer
import nz.net.ultraq.redhorizon.engine.graphics.GraphicsRendererEvent
import nz.net.ultraq.redhorizon.engine.graphics.MeshCreatedEvent
import nz.net.ultraq.redhorizon.engine.graphics.MeshDeletedEvent
import nz.net.ultraq.redhorizon.engine.graphics.TextureCreatedEvent
import nz.net.ultraq.redhorizon.engine.graphics.TextureDeletedEvent

import imgui.ImGui
import imgui.type.ImBoolean
import static imgui.flag.ImGuiWindowFlags.*

import java.util.concurrent.atomic.AtomicInteger

/**
* An overlay rendering pass for displaying debug information about the game.
*
Expand All @@ -48,16 +32,9 @@ class DebugOverlay implements ImGuiElement<DebugOverlay> {

// Debug information
private final Map<String, String> persistentLines = [:]
private AtomicInteger drawCalls = new AtomicInteger()
private int debugWindowSizeX = 350
private int debugWindowSizeY = 200

// TODO: These stats can probably live outside of this object?
final AtomicInteger activeFramebuffers = new AtomicInteger()
final AtomicInteger activeMeshes = new AtomicInteger()
final AtomicInteger activeTextures = new AtomicInteger()
final AtomicInteger activeSources = new AtomicInteger()
final AtomicInteger activeBuffers = new AtomicInteger()
private final EngineStats engineStats

/**
* Constructor, create a new blank overlay. This is made more useful by
Expand All @@ -71,45 +48,11 @@ class DebugOverlay implements ImGuiElement<DebugOverlay> {
persistentLines[event.persistentKey] = event.message
}
}
engineStats = EngineStats.instance

this.enabled = enabled
}

/**
* Add the audio renderer to get stats on audio sources, buffers, etc.
*/
DebugOverlay addAudioRenderer(AudioRenderer audioRenderer) {

audioRenderer.on(AudioRendererEvent) { event ->
switch (event) {
case BufferCreatedEvent -> activeBuffers.incrementAndGet()
case BufferDeletedEvent -> activeBuffers.decrementAndGet()
case SourceCreatedEvent -> activeSources.incrementAndGet()
case SourceDeletedEvent -> activeSources.decrementAndGet()
}
}
return this
}

/**
* Add the graphics renderer to get status on draws, textures, etc.
*/
DebugOverlay addGraphicsRenderer(GraphicsRenderer graphicsRenderer) {

graphicsRenderer.on(GraphicsRendererEvent) { event ->
switch (event) {
case DrawEvent -> drawCalls.incrementAndGet()
case FramebufferCreatedEvent -> activeFramebuffers.incrementAndGet()
case FramebufferDeletedEvent -> activeFramebuffers.decrementAndGet()
case MeshCreatedEvent -> activeMeshes.incrementAndGet()
case MeshDeletedEvent -> activeMeshes.decrementAndGet()
case TextureCreatedEvent -> activeTextures.incrementAndGet()
case TextureDeletedEvent -> activeTextures.decrementAndGet()
}
}
return this
}

@Override
void render(int dockspaceId, Framebuffer sceneFramebufferResult) {

Expand All @@ -123,13 +66,13 @@ class DebugOverlay implements ImGuiElement<DebugOverlay> {
debugWindowSizeY = ImGui.getWindowSizeY() as int

ImGui.text("Framerate: ${sprintf('%.1f', ImGui.getIO().framerate)}fps, Frametime: ${sprintf('%.1f', 1000 / ImGui.getIO().framerate)}ms")
ImGui.text("Draw calls: ${drawCalls}")
ImGui.text("Active meshes: ${activeMeshes}")
ImGui.text("Active textures: ${activeTextures}")
ImGui.text("Active framebuffers: ${activeFramebuffers}")
ImGui.text("Active sources: ${activeSources}")
ImGui.text("Active buffers: ${activeBuffers}")
drawCalls.set(0)
ImGui.text("Draw calls: ${engineStats.drawCalls}")
ImGui.text("Active meshes: ${engineStats.activeMeshes}")
ImGui.text("Active textures: ${engineStats.activeTextures}")
ImGui.text("Active framebuffers: ${engineStats.activeFramebuffers}")
ImGui.text("Active sources: ${engineStats.activeSources}")
ImGui.text("Active buffers: ${engineStats.activeBuffers}")
engineStats.drawCalls.set(0)

ImGui.separator()
persistentLines.keySet().sort().each { key ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,10 @@ class OpenGLRenderer implements GraphicsRenderer {
if (resource) {
resource.close()
switch (resource) {
case Framebuffer -> trigger(new FramebufferDeletedEvent(resource))
case Framebuffer -> {
trigger(new TextureDeletedEvent(resource.texture))
trigger(new FramebufferDeletedEvent(resource))
}
case Mesh -> trigger(new MeshDeletedEvent(resource))
case Texture -> trigger(new TextureDeletedEvent(resource))
case SpriteSheet -> trigger(new TextureDeletedEvent(resource.texture))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,16 @@ import nz.net.ultraq.redhorizon.engine.graphics.Switch
* The expected type of input data from a prior rendering pass.
* @author Emanuel Rabina
*/
interface RenderPass<T> extends Switch<RenderPass<T>> {

/**
* Perform any cleanup for this render pass.
*
* @param renderer
*/
default void delete(GraphicsRenderer renderer) {
}
interface RenderPass<T> extends Switch<RenderPass<T>>, AutoCloseable {

/**
* Return the target framebuffer for this rendering pass.
*
* @return
*/
Framebuffer getFramebuffer()

/**
* Perform the render pass, using the expected result of any previous render
* pass.
*
* @param renderer
* @param previous
*/
void render(GraphicsRenderer renderer, T previous)
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class RenderPipeline implements Closeable {
@Override
void close() {

renderPasses*.delete(renderer)
renderPasses*.close()
renderer.delete(fullScreenQuad)
}

Expand Down Expand Up @@ -179,6 +179,12 @@ class RenderPipeline implements Closeable {
this.enabled = true
}

@Override
void close() {

renderer.delete(framebuffer)
}

@Override
void render(GraphicsRenderer renderer, Void unused) {

Expand Down Expand Up @@ -225,7 +231,7 @@ class RenderPipeline implements Closeable {
}

@Override
void delete(GraphicsRenderer renderer) {
void close() {

renderer.delete(framebuffer)
}
Expand Down Expand Up @@ -287,7 +293,7 @@ class RenderPipeline implements Closeable {
}

@Override
void delete(GraphicsRenderer renderer) {
void close() {
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class Node<T extends Node> implements SceneEvents, Scriptable<T>, Visitable {
*/
protected Vector3f getGlobalPosition() {

return globalTransform.getTranslation(globalPosition)
return getGlobalTransform().getTranslation(globalPosition)
}

/**
Expand Down
Loading

0 comments on commit 4d0c067

Please sign in to comment.