Files
FlaxEngine/Source/Engine/GraphicsDevice/OpenGL/GPUShaderProgramOGL.h
2020-12-07 23:40:54 +01:00

283 lines
7.0 KiB
C++

// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Serialization/ReadStream.h"
#include "Engine/Graphics/Shaders/GPUShaderProgram.h"
#include "../RenderToolsOGL.h"
#include "../GPUDeviceOGL.h"
#if GRAPHICS_API_OPENGL
/// <summary>
/// Shaders base class for OpenGL
/// </summary>
template<typename BaseType>
class GPUShaderProgramOGL : public BaseType
{
protected:
GLuint _handle;
GLenum _shaderType;
Array<byte> _shader;
#if GPU_OGL_KEEP_SHADER_SRC
const char* ShaderSource = nullptr;
#endif
public:
/// <summary>
/// Init
/// </summary>
/// <param name="shaderType">Type of the OpenGL shader</param>
/// <param name="shaderBytes">Bytes with an compiled shader</param>
/// <param name="shaderBytesSize">Size in bytes of the cached shader</param>
/// <param name="stream">Stream with data to read</param>
/// <param name="name">Shader function name</param>
GPUShaderProgramOGL(GLenum shaderType, byte* shaderBytes, uint32 shaderBytesSize, ReadStream& stream, const StringAnsi& name)
: _handle(0)
, _shaderType(shaderType)
{
_name = name;
// Cache shader source (it cannot be compiled on content loading thread) - because OpenGL sucks
// TODO: use shared context and compile shaders on a content threads instead of main thread
_shader.Set(shaderBytes, shaderBytesSize);
// Load meta
stream.ReadUint32(&_instructionsCount);
stream.ReadUint32(&_usedCBsMask);
stream.ReadUint32(&_usedSRsMask);
stream.ReadUint32(&_usedUAsMask);
}
/// <summary>
/// Destructor
/// </summary>
~GPUShaderProgramOGL()
{
#if GPU_OGL_KEEP_SHADER_SRC
Allocator::Free(ShaderSource);
#endif
if (_handle != 0)
{
glDeleteProgram(_handle);
VALIDATE_OPENGL_RESULT();
}
}
private:
static GLuint glCreateGPUShaderProgram(GLenum type, const char* source)
{
const GLuint shader = glCreateShader(type);
if (shader)
{
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
const GLuint program = glCreateProgram();
if (program)
{
GLint compiled = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
if (compiled)
{
glAttachShader(program, shader);
glLinkProgram(program);
glDetachShader(program, shader);
}
}
glDeleteShader(shader);
return program;
}
return 0;
}
public:
// Gets the OpenGL shader object handle. Performs compilation if shader has not been created yet.
GLuint GetHandle()
{
if (_handle == 0)
{
// Compile the shader
_handle = glCreateGPUShaderProgram(_shaderType, (const char*)_shader.Get());
VALIDATE_OPENGL_RESULT();
// Check the status and the messages
{
GLint linkCompileSuccess = 0;
glGetProgramiv(_handle, GL_LINK_STATUS, &linkCompileSuccess);
VALIDATE_OPENGL_RESULT();
if (!linkCompileSuccess && _handle > 0)
{
GLint infologLength = 0;
glGetProgramiv(_handle, GL_INFO_LOG_LENGTH, &infologLength);
VALIDATE_OPENGL_RESULT();
if (infologLength > 0)
{
GLint charsWritten = 0;
Array<GLchar> infoLog;
infoLog.Resize(infologLength);
glGetProgramInfoLog(_handle, infologLength, &charsWritten, infoLog.Get());
VALIDATE_OPENGL_RESULT();
LOG(Warning, "Compile and linker info log:");
LOG_STR(Warning, String(infoLog.Get()));
}
}
}
#if GPU_OGL_KEEP_SHADER_SRC
ShaderSource = Allocator::Allocate(_shader.Count());
Platform::MemoryCopy((void*)ShaderSource, (void*)_shader.Get(), _shader.Count() * sizeof(char));
#endif
// Cleanup source buffer
_shader.Resize(0);
}
return _handle;
}
public:
// [BaseType]
uint32 GetBufferSize() const override
{
return 0;
}
void* GetBufferHandle() const override
{
return (void*)_handle;
}
};
/// <summary>
/// Vertex Shader for OpenGL
/// </summary>
class GPUShaderProgramVSOGL : public GPUShaderProgramOGL<GPUShaderProgramVS>
{
public:
struct LayoutElement
{
int32 BufferSlot;
PixelFormat Format;
int32 Size;
int32 InstanceDataStepRate;
int32 InputIndex;
int32 RelativeOffset;
int32 TypeCount;
GLboolean Normalized;
GLenum GlType;
bool IsInteger;
};
private:
GPUDeviceOGL* _device;
public:
/// <summary>
/// Init
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="shaderBytes">Bytes with an compiled shader</param>
/// <param name="shaderBytesSize">Size in bytes of the cached shader</param>
/// <param name="stream">Stream with data to read</param>
/// <param name="name">Shader function name</param>
GPUShaderProgramVSOGL(GPUDeviceOGL* device, byte* shaderBytes, uint32 shaderBytesSize, ReadStream& stream, const StringAnsi& name);
/// <summary>
/// Destructor
/// </summary>
~GPUShaderProgramVSOGL()
{
_device->VAOCache.OnObjectRelease(this);
}
public:
Array<LayoutElement, FixedAllocation<VERTEX_SHADER_MAX_INPUT_ELEMENTS>> Layout;
public:
// [GPUShaderProgramOGL]
void* GetInputLayout() const override
{
return (void*)nullptr;
}
byte GetInputLayoutSize() const override
{
return Layout.Count();
}
};
/// <summary>
/// Geometry Shader for OpenGL
/// </summary>
class GPUShaderProgramGSOGL : public GPUShaderProgramOGL<GPUShaderProgramGS>
{
public:
/// <summary>
/// Init
/// </summary>
/// <param name="shaderBytes">Bytes with an compiled shader</param>
/// <param name="shaderBytesSize">Size in bytes of the cached shader</param>
/// <param name="stream">Stream with data to read</param>
/// <param name="name">Shader function name</param>
GPUShaderProgramGSOGL(byte* shaderBytes, uint32 shaderBytesSize, ReadStream& stream, const StringAnsi& name)
: GPUShaderProgramOGL(GL_GEOMETRY_SHADER, shaderBytes, shaderBytesSize, stream, name)
{
}
};
/// <summary>
/// Pixel Shader for OpenGL
/// </summary>
class GPUShaderProgramPSOGL : public GPUShaderProgramOGL<GPUShaderProgramPS>
{
public:
/// <summary>
/// Init
/// </summary>
/// <param name="shaderBytes">Bytes with an compiled shader</param>
/// <param name="shaderBytesSize">Size in bytes of the cached shader</param>
/// <param name="stream">Stream with data to read</param>
/// <param name="name">Shader function name</param>
GPUShaderProgramPSOGL(byte* shaderBytes, uint32 shaderBytesSize, ReadStream& stream, const StringAnsi& name)
: GPUShaderProgramOGL(GL_FRAGMENT_SHADER, shaderBytes, shaderBytesSize, stream, name)
{
}
};
/// <summary>
/// Compute Shader for OpenGL
/// </summary>
class GPUShaderProgramCSOGL : public GPUShaderProgramOGL<GPUShaderProgramCS>
{
public:
/// <summary>
/// Init
/// </summary>
/// <param name="shaderBytes">Bytes with an compiled shader</param>
/// <param name="shaderBytesSize">Size in bytes of the cached shader</param>
/// <param name="stream">Stream with data to read</param>
/// <param name="name">Shader function name</param>
GPUShaderProgramCSOGL(byte* shaderBytes, uint32 shaderBytesSize, ReadStream& stream, const StringAnsi& name)
: GPUShaderProgramOGL(GL_COMPUTE_SHADER, shaderBytes, shaderBytesSize, stream, name)
{
}
};
#endif