diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 8bf6f020..bb460aa3 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1790,6 +1790,11 @@ Remove warnings for fast loading Work on debugging framebuffers Work to unify opengl error reporting +(05/15/2025) +Explicitly scream if trying to bind a shader that is invalid +Support for freeing shaders +Utilities to free all of a type of resource + diff --git a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java index 8b1ff991..8200ef9f 100644 --- a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java +++ b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java @@ -57,6 +57,7 @@ public class AssetManager { List audioInQueue = new LinkedList(); Map shadersLoadedIntoMemory = new HashMap(); + List shadersInDeleteQueue = new LinkedList(); List shadersInQueue = new LinkedList(); // @@ -270,6 +271,7 @@ public class AssetManager { this.deleteModelsInDeleteQueue(); this.deletePoseModelsInDeleteQueue(); this.deleteTexturesInDeleteQueue(); + this.deleteShadersInDeleteQueue(); lock.unlock(); } @@ -400,6 +402,17 @@ public class AssetManager { lock.unlock(); } + /** + * Queues all models for deletion + */ + public void queueAllModelsForDeletion(){ + lock.lock(); + for(String modelPath : this.modelsLoadedIntoMemory.keySet()){ + this.queueModelForDeletion(modelPath); + } + lock.unlock(); + } + @@ -580,6 +593,17 @@ public class AssetManager { } lock.unlock(); } + + /** + * Queues all textures for deletion + */ + public void queueAllTexturesForDeletion(){ + lock.lock(); + for(String texturePath : this.texturesLoadedIntoMemory.keySet()){ + this.queueTextureForDeletion(texturePath); + } + lock.unlock(); + } @@ -670,6 +694,40 @@ public class AssetManager { lock.unlock(); } + /** + * Queues a shader for deletion + * @param shaderPath The path to the shader + */ + public void queueShaderForDeletion(String shaderPath){ + lock.lock(); + shadersInDeleteQueue.add(shaderPath); + lock.unlock(); + } + + /** + * Queues all shaders for deletion + */ + public void queueAllShadersForDeletion(){ + lock.lock(); + for(String shaderKey : this.shadersLoadedIntoMemory.keySet()){ + this.queueShaderForDeletion(shaderKey); + } + lock.unlock(); + } + + /** + * Deletes all shaders in the delete queue + */ + public void deleteShadersInDeleteQueue(){ + lock.lock(); + for(String shaderKey : this.shadersInDeleteQueue){ + VisualShader shader = this.shadersLoadedIntoMemory.remove(shaderKey); + shader.free(); + } + this.shadersInDeleteQueue.clear(); + lock.unlock(); + } + // //SHADERS // diff --git a/src/main/java/electrosphere/renderer/OpenGLState.java b/src/main/java/electrosphere/renderer/OpenGLState.java index 3aaa091f..48a40858 100644 --- a/src/main/java/electrosphere/renderer/OpenGLState.java +++ b/src/main/java/electrosphere/renderer/OpenGLState.java @@ -234,6 +234,9 @@ public class OpenGLState { public void setActiveShader(RenderPipelineState renderPipelineState, Shader program){ if(DISABLE_CACHING || program != activeShader){ activeShader = program; + if(!GL40.glIsProgram(activeShader.getId()) && activeShader.getId() != Shader.UNBIND_SHADER_ID){ + throw new Error("Tried to bind shader that is not an active program! " + activeShader.getId()); + } GL40.glUseProgram(activeShader.getId()); int glErrorCode = Globals.renderingEngine.getError(); if(glErrorCode != 0){ diff --git a/src/main/java/electrosphere/renderer/shader/Shader.java b/src/main/java/electrosphere/renderer/shader/Shader.java index 13839f14..c65f2d06 100644 --- a/src/main/java/electrosphere/renderer/shader/Shader.java +++ b/src/main/java/electrosphere/renderer/shader/Shader.java @@ -7,6 +7,11 @@ import electrosphere.renderer.OpenGLState; */ public interface Shader { + /** + * ID to unbind a shader + */ + public static final int UNBIND_SHADER_ID = 0; + /** * Returned if the uniform isn't found */ diff --git a/src/main/java/electrosphere/renderer/shader/VisualShader.java b/src/main/java/electrosphere/renderer/shader/VisualShader.java index 3bcdd64f..34b8dbb2 100644 --- a/src/main/java/electrosphere/renderer/shader/VisualShader.java +++ b/src/main/java/electrosphere/renderer/shader/VisualShader.java @@ -15,7 +15,6 @@ import javax.management.RuntimeErrorException; import org.lwjgl.opengl.GL40; import electrosphere.engine.Globals; -import electrosphere.engine.assetmanager.AssetDataStrings; import electrosphere.logger.LoggerInterface; import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderingEngine; @@ -261,74 +260,6 @@ public class VisualShader implements Shader { return rVal; } - - - /** - * Loads the default shader program - * @return The default shader - */ - public static VisualShader loadDefaultShaderProgram(){ - - - // - //Create ShaderProgram object - // - VisualShader rVal = new VisualShader(); - // - //Read in shader programs - // - String vertexShaderSource = VisualShader.recursivelyPreprocessFile(AssetDataStrings.SHADER_DEFAULT_VERT); - String fragmentShaderSource = VisualShader.recursivelyPreprocessFile(AssetDataStrings.SHADER_DEFAULT_FRAG); - //Creates a new shader object and assigns its 'pointer' to the integer "vertexShader" - rVal.vertexShader = GL40.glCreateShader(GL40.GL_VERTEX_SHADER); - //This alerts openGL to the presence of a vertex shader and points the shader at its source - GL40.glShaderSource(rVal.vertexShader, vertexShaderSource); - //Compiles the source for the vertex shader object - GL40.glCompileShader(rVal.vertexShader); - //The following tests if the vertex shader compiles successfully - int success; - success = GL40.glGetShaderi(rVal.vertexShader, GL40.GL_COMPILE_STATUS); - if (success != GL40.GL_TRUE) { - LoggerInterface.loggerRenderer.WARNING("Vertex Shader failed to compile!"); - LoggerInterface.loggerRenderer.WARNING("Source is: "); - LoggerInterface.loggerRenderer.WARNING(GL40.glGetShaderSource(rVal.vertexShader)); - LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL40.glGetShaderInfoLog(rVal.vertexShader))); - } - //Creates and opengl object for a fragment shader and assigns its 'pointer' to the integer fragmentShader - rVal.fragmentShader = GL40.glCreateShader(GL40.GL_FRAGMENT_SHADER); - //This points the opengl shadder object to its proper source - GL40.glShaderSource(rVal.fragmentShader, fragmentShaderSource); - //This compiles the shader object - GL40.glCompileShader(rVal.fragmentShader); - //This tests for the success of the compile attempt - success = GL40.glGetShaderi(rVal.fragmentShader, GL40.GL_COMPILE_STATUS); - if (success != GL40.GL_TRUE) { - LoggerInterface.loggerRenderer.WARNING("Fragment Shader failed to compile!"); - LoggerInterface.loggerRenderer.WARNING("Source is: "); - LoggerInterface.loggerRenderer.WARNING(GL40.glGetShaderSource(rVal.fragmentShader)); - LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL40.glGetShaderInfoLog(rVal.fragmentShader))); - } - //This creates a shader program opengl object and assigns its 'pointer' to the integer shaderProgram - rVal.shaderId = GL40.glCreateProgram(); - //This attaches the vertex and fragment shaders to the program - GL40.glAttachShader(rVal.shaderId, rVal.vertexShader); - GL40.glAttachShader(rVal.shaderId, rVal.fragmentShader); - //This links the program to the GPU (I think its to the GPU anyway) - GL40.glLinkProgram(rVal.shaderId); - //Tests for the success of the shader program creation - success = GL40.glGetProgrami(rVal.shaderId, GL40.GL_LINK_STATUS); - if (success != GL40.GL_TRUE) { - throw new RuntimeException(GL40.glGetProgramInfoLog(rVal.shaderId)); - } - - //Deletes the individual shader objects to free up memory - GL40.glDeleteShader(rVal.vertexShader); - GL40.glDeleteShader(rVal.fragmentShader); - - - - return rVal; - } /** * Loads a specific shader @@ -543,5 +474,14 @@ public class VisualShader implements Shader { public int getId() { return this.shaderId; } + + + /** + * Frees the shader + */ + public void free(){ + GL40.glDeleteShader(this.getId()); + this.shaderId = VisualShader.INVALID_UNIFORM_NAME; + } }