compute shader implementation
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-09-18 17:14:53 -04:00
parent ab17254a02
commit 5eeb281e0b
12 changed files with 537 additions and 37 deletions

View File

@ -10,6 +10,7 @@ import org.lwjgl.opengl.GL45;
import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.buffer.UniformBlockBinding;
import electrosphere.renderer.shader.Shader;
import electrosphere.renderer.shader.ShaderProgram;
/**
@ -20,7 +21,7 @@ import electrosphere.renderer.shader.ShaderProgram;
public class OpenGLState {
//tracks whether caching should be used or not (to deduplicate opengl calls)
private static final boolean DISABLE_CACHING = false;
public static final boolean DISABLE_CACHING = false;
//the max texture allowed by the current environment
int MAX_TEXTURE_WIDTH;
@ -51,7 +52,7 @@ public class OpenGLState {
int framebufferPointer;
//active shader
ShaderProgram activeShader;
Shader activeShader;
//map of texture units and their corresponding texture pointers
Map<Integer,Integer> unitToPointerMap;
@ -228,16 +229,16 @@ public class OpenGLState {
* @param renderPipelineState The render pipeline state object
* @param program The shader program to bind
*/
public void setActiveShader(RenderPipelineState renderPipelineState, ShaderProgram program){
public void setActiveShader(RenderPipelineState renderPipelineState, Shader program){
if(DISABLE_CACHING || program != activeShader){
activeShader = program;
GL40.glUseProgram(activeShader.getShaderId());
GL40.glUseProgram(activeShader.getId());
int glErrorCode = Globals.renderingEngine.getError();
if(glErrorCode != 0){
LoggerInterface.loggerRenderer.DEBUG_LOOP(RenderingEngine.getErrorInEnglish(glErrorCode));
}
Globals.renderingEngine.checkError();
renderPipelineState.setCurrentShaderPointer(activeShader.getShaderId());
renderPipelineState.setCurrentShaderPointer(activeShader.getId());
}
}
@ -245,7 +246,7 @@ public class OpenGLState {
* Gets the active shader program
* @return The active shader
*/
public ShaderProgram getActiveShader(){
public Shader getActiveShader(){
return activeShader;
}

View File

@ -333,7 +333,7 @@ public class RenderingEngine {
//create light depth framebuffer/shader for shadowmapping
//
lightDepthShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/core/lightDepth/lightDepth.vs", "/Shaders/core/lightDepth/lightDepth.fs");
Globals.depthMapShaderProgramLoc = lightDepthShaderProgram.getShaderId();
Globals.depthMapShaderProgramLoc = lightDepthShaderProgram.getId();
try {
Framebuffer lightDepthBuffer = FramebufferUtils.generateDepthBuffer(openGLState);
RenderingEngine.lightDepthBuffer = lightDepthBuffer;

View File

@ -158,7 +158,7 @@ public class LightManager {
*/
public void bindBuffer(OpenGLState openGLState){
//get position of lights object in shader
int bufferIndex = GL31.glGetUniformBlockIndex(openGLState.getActiveShader().getShaderId(), "Lights");
int bufferIndex = GL31.glGetUniformBlockIndex(openGLState.getActiveShader().getId(), "Lights");
int glErrorCode = Globals.renderingEngine.getError();
if(glErrorCode != 0){
LoggerInterface.loggerRenderer.DEBUG_LOOP(RenderingEngine.getErrorInEnglish(glErrorCode));
@ -167,7 +167,7 @@ public class LightManager {
LoggerInterface.loggerRenderer.INFO("Tried to buffer light manager to shader that does not have it active.");
} else {
//bind that position to the slot '2'
GL31.glUniformBlockBinding(openGLState.getActiveShader().getShaderId(), bufferIndex, BIND_POINT);
GL31.glUniformBlockBinding(openGLState.getActiveShader().getId(), bufferIndex, BIND_POINT);
Globals.renderingEngine.checkError();
//bind our buffer to slot '2' as well
GL31.glBindBufferBase(GL_UNIFORM_BUFFER, BIND_POINT, uboIndex);

View File

@ -304,17 +304,17 @@ public class Mesh {
Object currentUniformRaw = uniforms.get(key);
if(currentUniformRaw instanceof Matrix4f){
Matrix4f currentUniform = (Matrix4f)currentUniformRaw;
glUniformMatrix4fv(glGetUniformLocation(openGLState.getActiveShader().getShaderId(), key), false, currentUniform.get(new float[16]));
glUniformMatrix4fv(glGetUniformLocation(openGLState.getActiveShader().getId(), key), false, currentUniform.get(new float[16]));
Globals.renderingEngine.checkError();
}
if(currentUniformRaw instanceof Vector3f){
Vector3f currentUniform = (Vector3f)currentUniformRaw;
glUniform3fv(glGetUniformLocation(openGLState.getActiveShader().getShaderId(), key), currentUniform.get(BufferUtils.createFloatBuffer(3)));
glUniform3fv(glGetUniformLocation(openGLState.getActiveShader().getId(), key), currentUniform.get(BufferUtils.createFloatBuffer(3)));
Globals.renderingEngine.checkError();
}
if(currentUniformRaw instanceof Integer){
int currentInform = (Integer)currentUniformRaw;
glUniform1i(glGetUniformLocation(openGLState.getActiveShader().getShaderId(), key), currentInform);
glUniform1i(glGetUniformLocation(openGLState.getActiveShader().getId(), key), currentInform);
Globals.renderingEngine.checkError();
}
}

View File

@ -75,7 +75,7 @@ public class RenderScreenPipeline implements RenderPipeline {
} break;
case 8: {
openGLState.setActiveShader(renderPipelineState, RenderingEngine.drawChannel);
GL40.glUniform1f(GL40.glGetUniformLocation(openGLState.getActiveShader().getShaderId(), "channel"),4);
GL40.glUniform1f(GL40.glGetUniformLocation(openGLState.getActiveShader().getId(), "channel"),4);
openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.screenTextureDepth.getTexturePointer());
} break;
}

View File

@ -42,12 +42,12 @@ public class VolumeBufferPipeline implements RenderPipeline {
GL40.glClear(GL40.GL_DEPTH_BUFFER_BIT);
openGLState.glActiveTexture(GL40.GL_TEXTURE0);
GL40.glUniformMatrix4fv(GL40.glGetUniformLocation(openGLState.getActiveShader().getShaderId(), "view"), false, Globals.viewMatrix.get(new float[16]));
GL40.glUniformMatrix4fv(GL40.glGetUniformLocation(openGLState.getActiveShader().getShaderId(), "projection"), false, RenderingEngine.nearVolumeProjectionMatrix.get(new float[16]));
GL40.glUniform1f(GL40.glGetUniformLocation(openGLState.getActiveShader().getShaderId(), "linearCoef"), RenderingEngine.volumeDepthLinearCoef);
GL40.glUniform1f(GL40.glGetUniformLocation(openGLState.getActiveShader().getShaderId(), "quadCoef"), RenderingEngine.volumeDepthQuadCoef);
GL40.glUniform1f(GL40.glGetUniformLocation(openGLState.getActiveShader().getShaderId(), "near"), 0.1f);
GL40.glUniform1f(GL40.glGetUniformLocation(openGLState.getActiveShader().getShaderId(), "far"), 100f);
GL40.glUniformMatrix4fv(GL40.glGetUniformLocation(openGLState.getActiveShader().getId(), "view"), false, Globals.viewMatrix.get(new float[16]));
GL40.glUniformMatrix4fv(GL40.glGetUniformLocation(openGLState.getActiveShader().getId(), "projection"), false, RenderingEngine.nearVolumeProjectionMatrix.get(new float[16]));
GL40.glUniform1f(GL40.glGetUniformLocation(openGLState.getActiveShader().getId(), "linearCoef"), RenderingEngine.volumeDepthLinearCoef);
GL40.glUniform1f(GL40.glGetUniformLocation(openGLState.getActiveShader().getId(), "quadCoef"), RenderingEngine.volumeDepthQuadCoef);
GL40.glUniform1f(GL40.glGetUniformLocation(openGLState.getActiveShader().getId(), "near"), 0.1f);
GL40.glUniform1f(GL40.glGetUniformLocation(openGLState.getActiveShader().getId(), "far"), 100f);
//
// Set render pipeline state

View File

@ -0,0 +1,195 @@
package electrosphere.renderer.shader;
import java.util.HashMap;
import java.util.Map;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL40;
import org.lwjgl.opengl.GL45;
import org.lwjgl.system.MemoryStack;
import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderingEngine;
/**
* A compute shader program (leaving object called "ComputeShader" because that's how most people refer to them)
*/
public class ComputeShader implements Shader {
/**
* The id for the shader
*/
int programId;
//Uniforms
public Map<Integer,Object> uniformMap = new HashMap<Integer,Object>();
//keeps track of programs that have already been compiled and returns them instead of recompiling from scratch
static Map<String,ShaderProgram> alreadyCompiledMap = new HashMap<String,ShaderProgram>();
/**
* Creates a compute shader
* @param source The source code for the shader
* @return The shader object
*/
public static ComputeShader create(String source){
ComputeShader rVal = new ComputeShader();
//create shader object
int shaderId = GL45.glCreateShader(GL45.GL_COMPUTE_SHADER);
Globals.renderingEngine.checkError();
//attach source
GL45.glShaderSource(shaderId, source);
Globals.renderingEngine.checkError();
//compile shader
GL45.glCompileShader(shaderId);
int success;
success = GL45.glGetShaderi(shaderId, GL45.GL_COMPILE_STATUS);
if (success != GL45.GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Compute Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL45.glGetShaderSource(shaderId));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL45.glGetShaderInfoLog(shaderId)));
}
//create program
rVal.programId = GL45.glCreateProgram();
Globals.renderingEngine.checkError();
//attach shader to program
GL45.glAttachShader(rVal.programId, shaderId);
Globals.renderingEngine.checkError();
//link
GL45.glLinkProgram(rVal.programId);
success = GL45.glGetProgrami(rVal.programId, GL45.GL_LINK_STATUS);
if (success != GL45.GL_TRUE) {
throw new RuntimeException(GL45.glGetProgramInfoLog(rVal.programId));
}
return rVal;
}
/**
* Dispatches the compute shader for execution
* @param x The X grid size
* @param y The Y grid size
* @param z The Z grid size
*/
public void dispatch(int x, int y, int z){
GL45.glDispatchCompute(x, y, z);
}
/**
* Sets the memory barrier value
* @param value The value
*/
public void memoryBarier(int value){
GL45.glMemoryBarrier(value);
}
/**
* Tries to set a uniform
* @param uniformName The name of the uniform
* @param value The value to set the uniform to
*/
public void setUniform(OpenGLState openGLState, String uniformName, Object value){
//
//Error checking
if(uniformName == null || uniformName.equals("")){
throw new IllegalArgumentException("Trying to set invalid uniform name");
}
if(this.getId() != openGLState.getActiveShader().getId()){
throw new IllegalStateException("Trying to set uniform on shader that is not active");
}
//
//get uniform location
int uniformLocation = GL40.glGetUniformLocation(this.getId(), uniformName);
int glErrorCode = Globals.renderingEngine.getError();
if(glErrorCode != 0){
LoggerInterface.loggerRenderer.DEBUG_LOOP(RenderingEngine.getErrorInEnglish(glErrorCode));
LoggerInterface.loggerRenderer.DEBUG_LOOP("Shader id: " + this.getId());
}
//
//set the uniform
if(uniformLocation == INVALID_UNIFORM_NAME){
LoggerInterface.loggerRenderer.DEBUG_LOOP("Searched for uniform in a shader that does not contain it. Uniform name: \"" + uniformName + "\"");
} else {
this.setUniform(openGLState, uniformLocation, value);
}
}
/**
* Sets the value of a uniform on this shader
* @param uniformLocation the uniform location
* @param value the value
*/
public void setUniform(OpenGLState openGLState, int uniformLocation, Object value){
if(
OpenGLState.DISABLE_CACHING ||
!uniformMap.containsKey(uniformLocation) ||
!uniformMap.get(uniformLocation).equals(value)
){
try(MemoryStack stack = MemoryStack.stackPush()){
//
//matrix4f
if(value instanceof Matrix4f){
Matrix4f currentUniform = (Matrix4f)value;
GL40.glUniformMatrix4fv(uniformLocation, false, currentUniform.get(new float[16]));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Matrix4f(currentUniform)); //create new matrix4f to break pointer-matching with equals on cache check
//
//matrix4d
} else if(value instanceof Matrix4d){
Matrix4d currentUniform = (Matrix4d)value;
GL40.glUniformMatrix4fv(uniformLocation, false, currentUniform.get(new float[16]));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Matrix4d(currentUniform)); //create new matrix4f to break pointer-matching with equals on cache check
//
//vector3f
} else if(value instanceof Vector3f){
Vector3f currentUniform = (Vector3f)value;
GL40.glUniform3fv(uniformLocation, currentUniform.get(BufferUtils.createFloatBuffer(3)));
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,new Vector3f(currentUniform)); //create new matrix4f to break pointer-matching with equals on cache check
//
//integer
} else if(value instanceof Integer){
GL40.glUniform1i(uniformLocation, (Integer)value);
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,(Integer)value);
//
//float
} else if(value instanceof Float){
GL40.glUniform1f(uniformLocation, (Float)value);
Globals.renderingEngine.checkError();
uniformMap.put(uniformLocation,(Float)value);
} else {
throw new UnsupportedOperationException("Tried to set uniform with unsupported type!");
}
}
}
}
@Override
public int getId() {
return programId;
}
}

View File

@ -0,0 +1,210 @@
package electrosphere.renderer.shader;
import org.lwjgl.opengl.GL45;
/**
* Memory barrier operations
*/
public class MemoryBarrier {
/**
* Types of memory barriers
*/
public static enum Barrier {
/**
* <p>
* Vertex data sources from buffer objects after the barrier will reflect data written by shaders prior to the barrier.
* </p>
* <p>
* The set of buffer objects affected by this bit is derived from the buffer object bindings used for generic vertex attributes derived from the GL_VERTEX_ATTRIB_ARRAY_BUFFER bindings.
* </p>
*/
GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT,
/**
* <p>
* Vertex array indices sourced from buffer objects after the barrier will reflect data written by shaders prior to the barrier.
* </p>
* <p>
* The buffer objects affected by this bit are derived from the GL_ELEMENT_ARRAY_BUFFER binding.
* </p>
*/
GL_ELEMENT_ARRAY_BARRIER_BIT,
/**
* <p>
* Shader uniforms sourced from buffer objects after the barrier will reflect data written by shaders prior to the barrier.
* </p>
*/
GL_UNIFORM_BARRIER_BIT,
/**
* <p>
* Texture fetches from shaders, including fetches from buffer object memory via buffer textures, after the barrier will reflect data written by shaders prior to the barrier.
* </p>
*/
GL_TEXTURE_FETCH_BARRIER_BIT,
/**
* <p>
* Memory accesses using shader image load, store, and atomic built-in functions issued after the barrier will reflect data written by shaders prior to the barrier.
* </p>
* <p>
* Additionally, image stores and atomics issued after the barrier will not execute until all memory accesses (e.g., loads, stores, texture fetches, vertex fetches) initiated prior to the barrier complete.
* </p>
*/
GL_SHADER_IMAGE_ACCESS_BARRIER_BIT,
/**
* <p>
* Command data sourced from buffer objects by Draw*Indirect commands after the barrier will reflect data written by shaders prior to the barrier.
* </p>
* <p>
* The buffer objects affected by this bit are derived from the GL_DRAW_INDIRECT_BUFFER binding.
* </p>
*/
GL_COMMAND_BARRIER_BIT,
/**
* <p>
* Reads and writes of buffer objects via the GL_PIXEL_PACK_BUFFER and GL_PIXEL_UNPACK_BUFFER bindings (via glReadPixels, glTexSubImage1D, etc.) after the barrier will reflect data written by shaders prior to the barrier.
* </p>
* <p>
* Additionally, buffer object writes issued after the barrier will wait on the completion of all shader writes initiated prior to the barrier.
* </p>
*/
GL_PIXEL_BUFFER_BARRIER_BIT,
/**
* <p>
* Writes to a texture via glTex(Sub)Image*, glCopyTex(Sub)Image*, glCompressedTex(Sub)Image*, and reads via glGetTexImage after the barrier will reflect data written by shaders prior to the barrier.
* </p>
* <p>
* Additionally, texture writes from these commands issued after the barrier will not execute until all shader writes initiated prior to the barrier complete.
* </p>
*/
GL_TEXTURE_UPDATE_BARRIER_BIT,
/**
* <p>
* Reads or writes via glBufferSubData, glCopyBufferSubData, or glGetBufferSubData, or to buffer object memory mapped by glMapBuffer or glMapBufferRange after the barrier will reflect data written by shaders prior to the barrier.
* </p>
* <p>
* Additionally, writes via these commands issued after the barrier will wait on the completion of any shader writes to the same memory initiated prior to the barrier.
* </p>
*/
GL_BUFFER_UPDATE_BARRIER_BIT,
/**
* <p>
* Access by the client to persistent mapped regions of buffer objects will reflect data written by shaders prior to the barrier.
* </p>
* <p>
* Note that this may cause additional synchronization operations.
* </p>
*/
GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT,
/**
* <p>
* Reads and writes via framebuffer object attachments after the barrier will reflect data written by shaders prior to the barrier.
* </p>
* <p>
* Additionally, framebuffer writes issued after the barrier will wait on the completion of all shader writes issued prior to the barrier.
* </p>
*/
GL_FRAMEBUFFER_BARRIER_BIT,
/**
* <p>
* Writes via transform feedback bindings after the barrier will reflect data written by shaders prior to the barrier.
* </p>
* <p>
* Additionally, transform feedback writes issued after the barrier will wait on the completion of all shader writes issued prior to the barrier.
* </p>
*/
GL_TRANSFORM_FEEDBACK_BARRIER_BIT,
/**
* <p>
* Accesses to atomic counters after the barrier will reflect writes prior to the barrier.
* </p>
*/
GL_ATOMIC_COUNTER_BARRIER_BIT,
/**
* <p>
* Accesses to shader storage blocks after the barrier will reflect writes prior to the barrier.
* </p>
*/
GL_SHADER_STORAGE_BARRIER_BIT,
/**
* <p>
* Writes of buffer objects via the GL_QUERY_BUFFER binding after the barrier will reflect data written by shaders prior to the barrier.
* </p>
* <p>
* Additionally, buffer object writes issued after the barrier will wait on the completion of all shader writes initiated prior to the barrier.
* </p>
*/
GL_QUERY_BUFFER_BARRIER_BIT,
}
/**
* Sets the memory barrier
* @param barrier The barrier to set
*/
public static void glMemoryBarrier(Barrier barrier){
int barrierVal = 0;
switch(barrier){
case GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT: {
barrierVal = GL45.GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
} break;
case GL_ELEMENT_ARRAY_BARRIER_BIT: {
barrierVal = GL45.GL_ELEMENT_ARRAY_BARRIER_BIT;
} break;
case GL_UNIFORM_BARRIER_BIT: {
barrierVal = GL45.GL_UNIFORM_BARRIER_BIT;
} break;
case GL_TEXTURE_FETCH_BARRIER_BIT: {
barrierVal = GL45.GL_TEXTURE_FETCH_BARRIER_BIT;
} break;
case GL_SHADER_IMAGE_ACCESS_BARRIER_BIT: {
barrierVal = GL45.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
} break;
case GL_COMMAND_BARRIER_BIT: {
barrierVal = GL45.GL_COMMAND_BARRIER_BIT;
} break;
case GL_PIXEL_BUFFER_BARRIER_BIT: {
barrierVal = GL45.GL_PIXEL_BUFFER_BARRIER_BIT;
} break;
case GL_TEXTURE_UPDATE_BARRIER_BIT: {
barrierVal = GL45.GL_TEXTURE_UPDATE_BARRIER_BIT;
} break;
case GL_BUFFER_UPDATE_BARRIER_BIT: {
barrierVal = GL45.GL_BUFFER_UPDATE_BARRIER_BIT;
} break;
case GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT: {
barrierVal = GL45.GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT;
} break;
case GL_FRAMEBUFFER_BARRIER_BIT: {
barrierVal = GL45.GL_FRAMEBUFFER_BARRIER_BIT;
} break;
case GL_TRANSFORM_FEEDBACK_BARRIER_BIT: {
barrierVal = GL45.GL_TRANSFORM_FEEDBACK_BARRIER_BIT;
} break;
case GL_ATOMIC_COUNTER_BARRIER_BIT: {
barrierVal = GL45.GL_ATOMIC_COUNTER_BARRIER_BIT;
} break;
case GL_SHADER_STORAGE_BARRIER_BIT: {
barrierVal = GL45.GL_SHADER_STORAGE_BARRIER_BIT;
} break;
case GL_QUERY_BUFFER_BARRIER_BIT: {
barrierVal = GL45.GL_QUERY_BUFFER_BARRIER_BIT;
} break;
}
GL45.glMemoryBarrier(barrierVal);
}
}

View File

@ -0,0 +1,29 @@
package electrosphere.renderer.shader;
import electrosphere.renderer.OpenGLState;
/**
* Interface for all shader types
*/
public interface Shader {
/**
* Returned if the uniform isn't found
*/
public static final int INVALID_UNIFORM_NAME = -1;
/**
* Gets the id for the shader program
* @return The id
*/
public int getId();
/**
* Sets the value of a uniform on the shader
* @param openGLState The opengl state object
* @param uniformName The uniform's name
* @param value The value of the uniform
*/
public void setUniform(OpenGLState openGLState, String uniformName, Object value);
}

View File

@ -44,10 +44,7 @@ import electrosphere.util.FileUtils;
/**
* A shader program
*/
public class ShaderProgram {
//tracks whether caching should be used or not (to deduplicate opengl calls)
private static final boolean DISABLE_CACHING = false;
public class ShaderProgram implements Shader {
//
//Program stuff
@ -677,7 +674,7 @@ public class ShaderProgram {
*/
public void setUniform(OpenGLState openGLState, int uniformLocation, Object value){
if(
DISABLE_CACHING ||
OpenGLState.DISABLE_CACHING ||
!uniformMap.containsKey(uniformLocation) ||
!uniformMap.get(uniformLocation).equals(value)
){
@ -728,9 +725,6 @@ public class ShaderProgram {
}
}
//returned if the uniform isn't found
public static final int INVALID_UNIFORM_NAME = -1;
/**
* Tries to set a uniform
* @param uniformName The name of the uniform
@ -742,17 +736,17 @@ public class ShaderProgram {
if(uniformName == null || uniformName.equals("")){
throw new IllegalArgumentException("Trying to set invalid uniform name");
}
if(this.getShaderId() != openGLState.getActiveShader().getShaderId()){
if(this.getId() != openGLState.getActiveShader().getId()){
throw new IllegalStateException("Trying to set uniform on shader that is not active");
}
//
//get uniform location
int uniformLocation = GL40.glGetUniformLocation(this.getShaderId(), uniformName);
int uniformLocation = GL40.glGetUniformLocation(this.getId(), uniformName);
int glErrorCode = Globals.renderingEngine.getError();
if(glErrorCode != 0){
LoggerInterface.loggerRenderer.DEBUG_LOOP(RenderingEngine.getErrorInEnglish(glErrorCode));
LoggerInterface.loggerRenderer.DEBUG_LOOP("Shader id: " + this.getShaderId());
LoggerInterface.loggerRenderer.DEBUG_LOOP("Shader id: " + this.getId());
}
//
@ -770,16 +764,13 @@ public class ShaderProgram {
* @return The location of the uniform
*/
public int getUniformLocation(String uniformName){
return GL40.glGetUniformLocation(this.getShaderId(), uniformName);
return GL40.glGetUniformLocation(this.getId(), uniformName);
}
/**
* Gets the id of the shader
* @return The shader id
*/
public int getShaderId(){
return shaderId;
@Override
public int getId() {
return this.shaderId;
}
}

View File

@ -0,0 +1,57 @@
package electrosphere.renderer.shader;
import static org.junit.jupiter.api.Assertions.*;
import electrosphere.test.annotations.IntegrationTest;
import electrosphere.test.template.RenderingTestTemplate;
/**
* Tests for compute shaders
*/
public class ComputeShaderTests extends RenderingTestTemplate {
/**
* A simple compute shader
*/
String simpleComputeShader = """
#version 430 core
layout (local_size_x = 10, local_size_y = 10, local_size_z = 1) in;
// ----------------------------------------------------------------------------
//
// uniforms
//
// ----------------------------------------------------------------------------
layout(rgba32f, binding = 0) uniform image2D imgOutput;
layout (location = 0) uniform float t; /** Time */
// ----------------------------------------------------------------------------
//
// functions
//
// ----------------------------------------------------------------------------
void main() {
vec4 value = vec4(0.0, 0.0, 0.0, 1.0);
ivec2 texelCoord = ivec2(gl_GlobalInvocationID.xy);
float speed = 100;
// the width of the texture
float width = 1000;
value.x = mod(float(texelCoord.x) + t * speed, width) / (gl_NumWorkGroups.x * gl_WorkGroupSize.x);
value.y = float(texelCoord.y)/(gl_NumWorkGroups.y*gl_WorkGroupSize.y);
imageStore(imgOutput, texelCoord, value);
}
""";
@IntegrationTest
public void testCreation(){
assertDoesNotThrow(() -> {
ComputeShader.create(simpleComputeShader);
});
}
}

View File

@ -0,0 +1,17 @@
package electrosphere.renderer.shader;
import electrosphere.renderer.shader.MemoryBarrier.Barrier;
import electrosphere.test.annotations.IntegrationTest;
import electrosphere.test.template.RenderingTestTemplate;
/**
* Tests for memory barrier operations
*/
public class MemoryBarrierTests extends RenderingTestTemplate {
@IntegrationTest
public void testGLMemoryBarrier(){
MemoryBarrier.glMemoryBarrier(Barrier.GL_COMMAND_BARRIER_BIT);
}
}