summaryrefslogtreecommitdiffstats
path: root/src/GalOgl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/GalOgl.cpp')
-rw-r--r--src/GalOgl.cpp339
1 files changed, 263 insertions, 76 deletions
diff --git a/src/GalOgl.cpp b/src/GalOgl.cpp
index 052c68a..b046d4b 100644
--- a/src/GalOgl.cpp
+++ b/src/GalOgl.cpp
@@ -7,76 +7,13 @@
#include "Utility.hpp"
-enum class GlResourceType {
- Vbo,
- Vao,
- Texture,
- Fbo,
- Program,
- None,
-};
-
-class GlResource {
- GlResourceType type = GlResourceType::None;
- GLuint res = 0;
-public:
- GlResource() = default;
-
- GlResource(GLuint resource, GlResourceType resType) noexcept : res(resource), type(resType) {}
-
- GlResource(const GlResource&) = delete;
-
- GlResource(GlResource&& rhs) noexcept {
- std::swap(this->res, rhs.res);
- std::swap(this->type, rhs.type);
- }
-
- GlResource& operator=(const GlResource&) = delete;
-
- GlResource& operator=(GlResource&& rhs) noexcept {
- std::swap(this->res, rhs.res);
- std::swap(this->type, rhs.type);
- return *this;
- }
-
- ~GlResource() {
- switch (type) {
- case GlResourceType::Vbo:
- glDeleteBuffers(1, &res);
- break;
- case GlResourceType::Vao:
- glDeleteVertexArrays(1, &res);
- break;
- case GlResourceType::Texture:
- glDeleteTextures(1, &res);
- break;
- case GlResourceType::Fbo:
- glDeleteFramebuffers(1, &res);
- break;
- case GlResourceType::Program:
- glDeleteProgram(res);
- break;
- case GlResourceType::None:
- default:
- break;
- }
- }
-
- operator GLuint() const noexcept {
- return res;
- }
-
- GLuint Get() const noexcept {
- return res;
- }
-};
-
using namespace Gal;
-class ImplOgl;
-class ShaderOgl;
-class FramebufferOgl;
+struct ImplOgl;
+struct ShaderOgl;
+struct FramebufferOgl;
+struct ShaderParametersBufferOgl;
class OglState {
GLuint activeFbo = 0;
@@ -88,6 +25,7 @@ class OglState {
GLuint activeTextureUnit = 0;
GLint vpX = 0, vpY = 0;
GLsizei vpW = 0, vpH = 0;
+ bool blending = false;
public:
@@ -137,6 +75,7 @@ public:
if (activeTexture[textureUnit] != texture) {
SetTextureUnit(textureUnit);
glBindTexture(type, texture);
+ activeTexture[textureUnit] = texture;
}
glCheckError();
}
@@ -160,10 +99,119 @@ public:
glCheckError();
}
+ void EnableBlending(bool enable) {
+ if (enable != blending) {
+ blending = enable;
+ if (blending)
+ glEnable(GL_BLEND);
+ else
+ glDisable(GL_BLEND);
+ }
+ }
+
+ void ReleaseFbo(GLuint vao) {
+ if (activeVao == vao)
+ activeVao = 0;
+ }
+
+ void ReleaseVao(GLuint fbo) {
+ if (activeFbo == fbo)
+ activeEbo = 0;
+ }
+
+ void ReleaseVbo(GLuint vbo) {
+ if (activeVbo == vbo)
+ activeVbo = 0;
+ if (activeEbo == vbo)
+ activeEbo = 0;
+ }
+
+ void ReleaseProgram(GLuint program) {
+ if (activeProgram == program)
+ activeProgram = 0;
+ }
+
+ void ReleaseTexture(GLuint texture) {
+ for (auto& activeTex : activeTexture) {
+ if (activeTex == texture)
+ activeTex = 0;
+ }
+ }
+
} oglState;
+enum class GlResourceType {
+ Vbo,
+ Vao,
+ Texture,
+ Fbo,
+ Program,
+ None,
+};
+
+class GlResource {
+ GlResourceType type = GlResourceType::None;
+ GLuint res = 0;
+public:
+ GlResource() = default;
+
+ GlResource(GLuint resource, GlResourceType resType) noexcept : res(resource), type(resType) {}
+
+ GlResource(const GlResource&) = delete;
+
+ GlResource(GlResource&& rhs) noexcept {
+ std::swap(this->res, rhs.res);
+ std::swap(this->type, rhs.type);
+ }
+
+ GlResource& operator=(const GlResource&) = delete;
+
+ GlResource& operator=(GlResource&& rhs) noexcept {
+ std::swap(this->res, rhs.res);
+ std::swap(this->type, rhs.type);
+ return *this;
+ }
+
+ ~GlResource() {
+ switch (type) {
+ case GlResourceType::Vbo:
+ oglState.ReleaseVbo(res);
+ glDeleteBuffers(1, &res);
+ break;
+ case GlResourceType::Vao:
+ oglState.ReleaseVao(res);
+ glDeleteVertexArrays(1, &res);
+ break;
+ case GlResourceType::Texture:
+ oglState.ReleaseTexture(res);
+ glDeleteTextures(1, &res);
+ break;
+ case GlResourceType::Fbo:
+ oglState.ReleaseFbo(res);
+ glDeleteFramebuffers(1, &res);
+ break;
+ case GlResourceType::Program:
+ oglState.ReleaseProgram(res);
+ glDeleteProgram(res);
+ break;
+ case GlResourceType::None:
+ default:
+ break;
+ }
+ }
+
+ operator GLuint() const noexcept {
+ return res;
+ }
+
+ GLuint Get() const noexcept {
+ return res;
+ }
+};
+
std::unique_ptr<ImplOgl> impl;
std::shared_ptr<FramebufferOgl> fbDefault;
+std::shared_ptr<ShaderParametersBufferOgl> spbDefault;
size_t GalTypeGetComponents(Gal::Type type) {
switch (type) {
@@ -308,24 +356,64 @@ GLenum GalTypeGetComponentGlType(Gal::Type type) {
size_t GalFormatGetSize(Format format) {
switch (format) {
+ case Format::D24S8:
+ return 4;
+ case Format::R8:
+ return 1;
+ case Format::R8G8:
+ return 2;
case Format::R8G8B8:
return 3;
+ case Format::R8G8B8SN:
+ return 3;
case Format::R8G8B8A8:
return 4;
+ case Format::R32G32B32A32F:
+ return 16;
default:
return 0;
}
return 0;
}
-GLenum GalFormatGetGlInternalFormat(Format format) {
+GLenum GalFormatGetGlLinearInternalFormat(Format format) {
switch (format) {
case Format::D24S8:
return GL_DEPTH24_STENCIL8;
+ case Format::R8:
+ return GL_R8;
+ case Format::R8G8:
+ return GL_RG8;
case Format::R8G8B8:
return GL_RGB8;
+ case Format::R8G8B8SN:
+ return GL_RGB8_SNORM;
case Format::R8G8B8A8:
return GL_RGBA8;
+ case Format::R32G32B32A32F:
+ return GL_RGBA32F;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+GLenum GalFormatGetGlInternalFormat(Format format) {
+ switch (format) {
+ case Format::D24S8:
+ return 0;
+ case Format::R8:
+ return 0;
+ case Format::R8G8:
+ return 0;
+ case Format::R8G8B8:
+ return GL_SRGB;
+ case Format::R8G8B8SN:
+ return 0;
+ case Format::R8G8B8A8:
+ return GL_SRGB_ALPHA;
+ case Format::R32G32B32A32F:
+ return 0;
default:
return 0;
}
@@ -336,10 +424,18 @@ GLenum GalFormatGetGlFormat(Format format) {
switch (format) {
case Format::D24S8:
return GL_DEPTH_STENCIL;
+ case Format::R8:
+ return GL_RED;
+ case Format::R8G8:
+ return GL_RG;
case Format::R8G8B8:
return GL_RGB;
+ case Format::R8G8B8SN:
+ return GL_RGB;
case Format::R8G8B8A8:
return GL_RGBA;
+ case Format::R32G32B32A32F:
+ return GL_RGBA;
default:
return 0;
}
@@ -350,10 +446,18 @@ GLenum GalFormatGetGlType(Format format) {
switch (format) {
case Format::D24S8:
return GL_UNSIGNED_INT_24_8;
+ case Format::R8:
+ return GL_UNSIGNED_BYTE;
+ case Format::R8G8:
+ return GL_UNSIGNED_BYTE;
case Format::R8G8B8:
return GL_UNSIGNED_BYTE;
+ case Format::R8G8B8SN:
+ return GL_BYTE;
case Format::R8G8B8A8:
return GL_UNSIGNED_BYTE;
+ case Format::R32G32B32A32F:
+ return GL_FLOAT;
default:
return 0;
}
@@ -577,6 +681,7 @@ struct TextureConfigOgl : public TextureConfig {
Format format;
size_t width = 1, height = 1, depth = 1;
bool interpolateLayers = false;
+ bool linear = true;
GLenum type;
Filtering min = Filtering::Nearest, max = Filtering::Nearest;
@@ -594,6 +699,10 @@ struct TextureConfigOgl : public TextureConfig {
wrap = wrapping;
}
+ virtual void SetLinear(bool isLinear) override {
+ linear = isLinear;
+ }
+
};
struct TextureOgl : public Texture {
@@ -602,12 +711,19 @@ struct TextureOgl : public Texture {
GlResource texture;
Format format;
size_t width, height, depth;
+ bool linear;
+
+ virtual std::tuple<size_t, size_t, size_t> GetSize() override {
+ return { width, height, depth };
+ }
virtual void SetData(std::vector<std::byte>&& data, size_t mipLevel = 0) override {
size_t expectedSize = width * height * depth * GalFormatGetSize(format);
if (data.size() != expectedSize && !data.empty())
throw std::logic_error("Size of data is not valid for this texture");
+ GLenum internalFormat = linear ? GalFormatGetGlLinearInternalFormat(format) : GalFormatGetGlInternalFormat(format);
+
oglState.BindTexture(type, texture);
switch (type) {
@@ -627,13 +743,13 @@ struct TextureOgl : public Texture {
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
case GL_PROXY_TEXTURE_CUBE_MAP:
- glTexImage2D(type, mipLevel, GalFormatGetGlInternalFormat(format), width, height, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.empty() ? nullptr : data.data());
+ glTexImage2D(type, mipLevel, internalFormat, width, height, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.empty() ? nullptr : data.data());
break;
case GL_TEXTURE_3D:
case GL_PROXY_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
case GL_PROXY_TEXTURE_2D_ARRAY:
- glTexImage3D(type, mipLevel, GalFormatGetGlInternalFormat(format), width, height, depth, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.empty() ? nullptr : data.data());
+ glTexImage3D(type, mipLevel, internalFormat, width, height, depth, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.empty() ? nullptr : data.data());
break;
default:
throw std::runtime_error("Unknown texture type");
@@ -690,6 +806,7 @@ struct FramebufferOgl : public Framebuffer {
size_t vpX = 0, vpY = 0, vpW = 1, vpH = 1;
std::shared_ptr<TextureOgl> depthStencil;
std::vector<std::shared_ptr<TextureOgl>> colors;
+ std::vector<GLenum> attachments;
GlResource fbo;
@@ -729,6 +846,22 @@ struct FramebufferConfigOgl : public FramebufferConfig {
}
};
+struct ShaderParametersBufferOgl : public ShaderParametersBuffer {
+ std::shared_ptr<BufferOgl> buffer;
+ bool dirty = true;
+ std::vector<std::byte> data;
+
+ virtual std::byte* GetDataPtr() override {
+ dirty = true;
+ return data.data();
+ }
+
+ virtual void Resize(size_t newSize) override {
+ dirty = true;
+ data.resize(newSize);
+ }
+};
+
struct PipelineConfigOgl : public PipelineConfig {
std::shared_ptr<ShaderOgl> vertexShader, pixelShader;
@@ -737,6 +870,7 @@ struct PipelineConfigOgl : public PipelineConfig {
std::shared_ptr<FramebufferOgl> targetFb;
std::vector<std::vector<VertexAttribute>> vertexBuffers;
Primitive vertexPrimitive = Primitive::Triangle;
+ Blending blending = Blending::Opaque;
virtual void SetVertexShader(std::shared_ptr<Shader> shader) override {
vertexShader = std::static_pointer_cast<ShaderOgl,Shader>(shader);
@@ -764,6 +898,10 @@ struct PipelineConfigOgl : public PipelineConfig {
vertexPrimitive = primitive;
}
+ virtual void SetBlending(Blending blendingMode) override {
+ blending = blendingMode;
+ }
+
virtual std::shared_ptr<BufferBinding> BindVertexBuffer(std::vector<VertexAttribute> &&bufferLayout) override {
auto binding = std::make_shared<BufferBindingOgl>(vertexBuffers.size());
vertexBuffers.push_back(bufferLayout);
@@ -832,7 +970,7 @@ struct PipelineInstanceOgl : public PipelineInstance {
};
struct PipelineOgl : public Pipeline {
-
+ std::vector<std::shared_ptr<ShaderParametersBufferOgl>> spbs;
std::map<std::string, size_t> shaderParameters;
std::vector<std::shared_ptr<TextureOgl>> staticTextures;
GlResource program;
@@ -847,16 +985,27 @@ struct PipelineOgl : public Pipeline {
};
std::vector<VertexBindingCommand> vertexBindCmds;
Primitive primitive;
+ Blending blending;
std::shared_ptr<FramebufferOgl> target;
virtual void Activate() override {
oglState.UseProgram(program);
oglState.BindFbo(target->fbo);
oglState.SetViewport(target->vpX, target->vpY, target->vpW, target->vpH);
+ oglState.EnableBlending(blending == Blending::Additive);
+ if (target->fbo)
+ glDrawBuffers(target->attachments.size(), target->attachments.data());
for (size_t i = 0; i < staticTextures.size(); i++) {
oglState.BindTexture(staticTextures[i]->type, staticTextures[i]->texture, i);
}
+
+ for (auto& spb : spbs) {
+ if (spb->dirty) {
+ spb->buffer->SetData(std::vector<std::byte>(spb->data));
+ spb->dirty = false;
+ }
+ }
}
virtual void SetDynamicTexture(std::string_view name, std::shared_ptr<Texture> texture) override {
@@ -1013,13 +1162,15 @@ struct ImplOgl : public Impl {
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
- glEnable(GL_BLEND);
+ oglState.EnableBlending(true);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glCheckError();
if (glActiveTexture == nullptr) {
throw std::runtime_error("GLEW initialization failed with unknown reason");
}
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
GLint flags;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
@@ -1055,6 +1206,10 @@ struct ImplOgl : public Impl {
glCheckError();
}
+ virtual void SetWireframe(bool enabled) override {
+ glPolygonMode(GL_FRONT_AND_BACK, enabled ? GL_LINE : GL_FILL);
+ }
+
virtual std::shared_ptr<Buffer> CreateBuffer() override {
auto buff = std::make_shared<BufferOgl>();
@@ -1101,6 +1256,7 @@ struct ImplOgl : public Impl {
texture->width = texConfig->width;
texture->height = texConfig->height;
texture->depth = texConfig->depth;
+ texture->linear = texConfig->linear;
GLuint newTex;
glGenTextures(1, &newTex);
@@ -1131,6 +1287,7 @@ struct ImplOgl : public Impl {
auto config = std::static_pointer_cast<PipelineConfigOgl, PipelineConfig>(pipelineConfig);
pipeline->primitive = config->vertexPrimitive;
+ pipeline->blending = config->blending;
pipeline->target = config->targetFb;
if (!pipeline->target)
@@ -1198,6 +1355,23 @@ struct ImplOgl : public Impl {
/*
+ * Shader parameters buffers
+ */
+ constexpr auto spbGlobalsName = "Globals";
+ size_t spbGlobalsBind = 0;
+ size_t spbIndex = glGetUniformBlockIndex(program, spbGlobalsName);
+ if (spbIndex != GL_INVALID_VALUE) {
+ glUniformBlockBinding(program, spbIndex, spbGlobalsBind);
+ auto spbGlobals = std::static_pointer_cast<ShaderParametersBufferOgl, ShaderParametersBuffer>(GetGlobalShaderParameters());
+ glBindBufferBase(GL_UNIFORM_BUFFER, spbGlobalsBind, spbGlobals->buffer->vbo);
+ pipeline->spbs.emplace_back(spbGlobals);
+ }
+ else
+ LOG(ERROR) << "Cannot bind Globals UBO to shader. Maybe uniform block Globals missing?";
+ glCheckError();
+
+
+ /*
* Shader parameters
*/
for (auto&& [name, type] : config->shaderParameters) {
@@ -1222,6 +1396,7 @@ struct ImplOgl : public Impl {
glUniform1i(location, usedTextureBlocks);
pipeline->staticTextures.push_back(texture);
+ usedTextureBlocks++;
}
glCheckError();
@@ -1247,6 +1422,11 @@ struct ImplOgl : public Impl {
size_t attribSize = GalTypeGetSize(type);
for (size_t i = 0; i < count; i++) {
+ if (location < 0) {
+ vertexSize += attribSize;
+ continue;
+ }
+
pipeline->vertexBindCmds.push_back({
bufferId,
static_cast<size_t>(location + i),
@@ -1295,6 +1475,7 @@ struct ImplOgl : public Impl {
for (auto&& [location, texture] : conf->colors) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + location, texture->type, texture->texture, 0);
fb->colors.emplace_back(std::move(texture));
+ fb->attachments.push_back(GL_COLOR_ATTACHMENT0 + location);
}
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
@@ -1308,15 +1489,21 @@ struct ImplOgl : public Impl {
}
virtual std::shared_ptr<Framebuffer> GetDefaultFramebuffer() override {
- if (!fbDefault)
+ if (!fbDefault) {
fbDefault = std::make_shared<FramebufferOgl>();
- fbDefault->fbo = GlResource(0, GlResourceType::None);
+ fbDefault->fbo = GlResource(0, GlResourceType::None);
+ fbDefault->attachments.push_back(GL_COLOR_ATTACHMENT0);
+ }
return std::static_pointer_cast<Framebuffer, FramebufferOgl>(fbDefault);
}
- virtual std::shared_ptr<ShaderParameters> GetGlobalShaderParameters() override {
- return nullptr;
+ virtual std::shared_ptr<ShaderParametersBuffer> GetGlobalShaderParameters() override {
+ if (!spbDefault) {
+ spbDefault = std::make_shared<ShaderParametersBufferOgl>();
+ spbDefault->buffer = std::static_pointer_cast<BufferOgl, Buffer>(GetImplementation()->CreateBuffer());
+ }
+ return spbDefault;
}
virtual std::shared_ptr<Shader> LoadVertexShader(std::string_view code) override {