compute shader implementation
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
ab17254a02
commit
5eeb281e0b
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
195
src/main/java/electrosphere/renderer/shader/ComputeShader.java
Normal file
195
src/main/java/electrosphere/renderer/shader/ComputeShader.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
210
src/main/java/electrosphere/renderer/shader/MemoryBarrier.java
Normal file
210
src/main/java/electrosphere/renderer/shader/MemoryBarrier.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
29
src/main/java/electrosphere/renderer/shader/Shader.java
Normal file
29
src/main/java/electrosphere/renderer/shader/Shader.java
Normal 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);
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user