This commit is contained in:
L-Nafaryus 2022-10-05 21:10:51 +05:00
parent 0aabe8ffac
commit f43b2f4b44
22 changed files with 623 additions and 41 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ build/
.ccls-cache/
compile_commands.json
.cache/
temp/

View File

@ -17,6 +17,8 @@ if(WITH_GTESTS)
include(GoogleTest)
endif()
include(${CMAKE_SOURCE_DIR}/cmake/glad.cmake)
add_definitions(-DPRECISION_FLOAT)
add_subdirectory(source)

9
cmake/glad.cmake Normal file
View File

@ -0,0 +1,9 @@
include(${CMAKE_CURRENT_LIST_DIR}/CPM.cmake)
CPMAddPackage(
NAME glad
GIT_REPOSITORY https://github.com/Dav1dde/glad.git
VERSION 0.1.36
GIT_PROGRESS TRUE
OPTIONS "GLAD_EXPORT ON" "GLAD_INSTALL ON"
)

View File

@ -0,0 +1,39 @@
include_directories(
../hyplib
)
add_library(hyporo-gpu STATIC
# Source files
buffer.cpp
context.cpp
shader.cpp
opengl/buffer.cpp
opengl/context.cpp
opengl/shader.cpp
opengl/texture.cpp
opengl/device.cpp
opengl/shader_program.cpp
texture.cpp
device.cpp
shader_program.cpp
# Header files
context.hpp
shader.hpp
shader_program.hpp
buffer.hpp
device.hpp
texture.hpp
opengl/context.hpp
opengl/shader.hpp
opengl/shader_program.hpp
opengl/buffer.hpp
opengl/device.hpp
opengl/texture.hpp
)
target_link_libraries(hyporo-gpu
glad
hyporo-hyplib
)

View File

@ -22,7 +22,14 @@ Buffer::Buffer(DeviceAPI api) :
Buffer::~Buffer()
{}
const BufferType Buffer::type() const
// Member functions
int Buffer::size() const
{
return p_size;
}
Buffer::BufferType Buffer::type() const
{
return p_type;
}

View File

@ -10,6 +10,7 @@ namespace hpr::gpu
class Buffer : public Context
{
friend class Device;
public:
@ -39,9 +40,9 @@ public:
// Member functions
const int size() const;
int size() const;
const BufferType type() const;
BufferType type() const;
};
} // end namespace hpr::gpu

View File

@ -6,29 +6,147 @@
namespace hpr::gpu
{
Device::Device() :
Context {DeviceAPI::Unknown}
{}
Device::Device() :
Context {DeviceAPI::Unknown},
p_currentVertexBuffer {nullptr},
p_currentIndexBuffer {nullptr},
p_currentShaderProgram {nullptr}
{}
Device::Device(DeviceAPI api) :
Context {api}
{}
Device::Device(DeviceAPI api) :
Context {api},
p_currentVertexBuffer {nullptr},
p_currentIndexBuffer {nullptr},
p_currentShaderProgram {nullptr}
{}
Device::~Device()
{}
Device::~Device()
{}
void Device::create(Device **device, DeviceAPI api)
// Global functions
void Device::create(Device** device, DeviceAPI api)
{
if (device == nullptr)
throw "Invalid parameter";
if (api == DeviceAPI::Unknown)
throw "Invalid parameter";
*device = nullptr;
if (api == DeviceAPI::OpenGL)
*device = new opengl::Device;
else
throw "Unsupported device";
}
// Buffers
void Device::useVertexBuffer(Buffer* buffer, int stride, int offset)
{
if (buffer)
{
if (device == nullptr)
throw "Invalid parameter";
if (api == DeviceAPI::Unknown)
throw "Invalid parameter";
*device = nullptr;
if (api == DeviceAPI::OpenGL)
*device = new opengl::Device;
if (buffer->p_type == Buffer::BufferType::Vertex)
{
p_currentVertexBuffer = buffer;
p_currentVertexBuffer->p_stride = stride;
}
else
throw "Unsupported device";
throw "Incompatible buffer";
}
else
p_currentVertexBuffer = nullptr;
}
void Device::useIndexBuffer(Buffer* buffer, int offset)
{
if (buffer)
{
if (buffer->p_type == Buffer::BufferType::Index)
{
p_currentIndexBuffer = buffer;
}
else
throw "Incompatible buffer";
}
else
p_currentIndexBuffer = nullptr;
}
void Device::destroyBuffer(Buffer*& buffer)
{
if (!buffer)
throw "Invalid parameter";
for (auto iter = p_buffers.begin(); iter != p_buffers.end(); ++iter)
if (&*iter == &*buffer)
p_buffers.erase(iter);
buffer = nullptr;
}
// Shaders
void Device::destroyShader(Shader *&shader)
{
if (shader == nullptr)
throw "Invalid parameter";
for (auto iter = p_shaders.begin(); iter != p_shaders.end(); ++iter)
if (&*iter == &*shader)
p_shaders.erase(iter);
shader = nullptr;
}
// Shader programs
void Device::attachShader(ShaderProgram *program, Shader *shader)
{
if (program == nullptr || shader == nullptr)
throw "Invalid parameter";
if (program->p_isLinked)
throw "Shader program already linked";
program->p_slots[(int)shader->p_type] = shader;
}
void Device::linkProgram(ShaderProgram *program)
{
if (program == nullptr)
throw "Invalid parameter";
if (program->p_isLinked)
throw "Shader program already linked";
program->p_isLinked = true;
}
void Device::useShaderProgram(ShaderProgram *program)
{
if (program != nullptr)
if (!program->p_isLinked)
throw "Shader program is not linked";
p_currentShaderProgram = program;
}
void Device::destroyShaderProgram(ShaderProgram *&program, bool withShaders)
{
if (program == p_currentShaderProgram)
useShaderProgram(nullptr);
if (withShaders)
for (size_t n = 0; n < (size_t)Shader::ShaderType::ShaderTypeCount; n++)
destroyShader(program->p_slots[n]);
program = nullptr;
}
// Textures
void Device::destroyTexture(Texture *&texture)
{
for (auto iter = p_textures.begin(); iter != p_textures.end(); ++iter)
if (&*iter == &*texture)
p_textures.erase(iter);
texture = nullptr;
}
}

View File

@ -21,6 +21,7 @@ public:
{
Front,
Back,
FrontAndBack,
None
};
@ -31,6 +32,10 @@ protected:
std::vector<ShaderProgram> p_shaderPrograms;
std::vector<Texture> p_textures;
Buffer* p_currentVertexBuffer;
Buffer* p_currentIndexBuffer;
ShaderProgram* p_currentShaderProgram;
protected:
// Constructors
@ -64,14 +69,14 @@ public:
virtual void createIndexBuffer(Buffer **buffer, int size, char* data) = 0;
virtual void useVertexBuffer(Buffer* buffer, int stride, int offset);
virtual void useIndexBuffer(Buffer* buffer, int offset);
virtual bool destroyBuffer(Buffer*& buffer);
virtual void destroyBuffer(Buffer*& buffer);
// Shaders
virtual void createVertexShader(Shader** shader, const std::string& filename, const std::string& label) = 0;
virtual void createFragmentShader(Shader** shader, const std::string& filename, const std::string& label) = 0;
virtual void createGeometryShader(Shader** shader, const std::string& filename, const std::string& label) = 0;
virtual bool destroyShader(Shader*& shader);
virtual void destroyShader(Shader*& shader);
// Shader programs
@ -84,7 +89,7 @@ public:
// Textures
virtual void createTexture(Texture** texture, const std::string& filename) = 0;
virtual void useTexture(Texture* texture, int slot);
virtual void useTexture(Texture* texture, int slot) = 0;
virtual void destroyTexture(Texture*& texture);
};

View File

@ -1,6 +1,8 @@
#include "buffer.hpp"
#include <glad/glad.h>
namespace hpr::gpu::opengl
{
@ -14,14 +16,16 @@ Buffer::Buffer() :
Buffer::~Buffer()
{}
const int Buffer::target() const
int Buffer::target() const
{
switch (p_type)
{
case BufferType::Vertex:
return GL_ARRAY_BUFFER;
case BufferType::Index:
return GL_ELEMENT_INDEX_BUFFER;
return GL_ELEMENT_ARRAY_BUFFER;
default:
return GL_NONE;
}
}

View File

@ -24,7 +24,7 @@ public:
// Member functions
const int target() const;
int target() const;
};
}

View File

@ -1,10 +1,15 @@
#include "device.hpp"
#include "buffer.hpp
#include "buffer.hpp"
#include "shader.hpp"
#include "shader_program.hpp"
#include "texture.hpp"
#include "io/io.hpp"
#include <glad/glad.h>
#include <stdexcept>
namespace hpr::gpu::opengl
{
@ -17,5 +22,187 @@ Device::Device() :
Device::~Device()
{}
// Setup
bool Device::initialize()
{
return p_isInitialized = true;
}
bool Device::destroy()
{
return p_isInitialized = false;
}
// State
void Device::faceCulling(bool enableFaceCulling, CullMode faceCullingMode)
{
if (enableFaceCulling)
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
switch (faceCullingMode)
{
case CullMode::Front:
glCullFace(GL_FRONT);
break;
case CullMode::Back:
glCullFace(GL_BACK);
break;
case CullMode::FrontAndBack:
glCullFace(GL_FRONT_AND_BACK);
break;
case CullMode::None:
glCullFace(GL_NONE);
break;
}
}
void Device::createVertexBuffer(gpu::Buffer **buffer, int size, char *data)
{
if (buffer == nullptr)
throw std::invalid_argument("Invalid parameter");
*buffer = nullptr;
p_buffers.emplace_back(opengl::Buffer());
opengl::Buffer* newBuffer = dynamic_cast<opengl::Buffer*>(&p_buffers.back());
newBuffer->p_type = Buffer::BufferType::Vertex;
newBuffer->p_size = size;
glGenVertexArrays(1, &newBuffer->p_vertexArrayIndex);
glBindVertexArray(newBuffer->p_vertexArrayIndex);
glGenBuffers(1, &newBuffer->p_bufferIndex);
glBindBuffer(GL_ARRAY_BUFFER, newBuffer->p_bufferIndex);
glBufferData(GL_ARRAY_BUFFER, size, (void*)data, GL_STATIC_DRAW);
*buffer = static_cast<gpu::Buffer*>(newBuffer);
}
void Device::createIndexBuffer(gpu::Buffer **buffer, int size, char *data)
{
if (buffer == nullptr)
throw std::invalid_argument("Invalid parameter");
*buffer = nullptr;
p_buffers.emplace_back(opengl::Buffer());
opengl::Buffer* newBuffer = dynamic_cast<opengl::Buffer*>(&p_buffers.back());
newBuffer->p_type = Buffer::BufferType::Vertex;
newBuffer->p_size = size;
glGenVertexArrays(1, &newBuffer->p_vertexArrayIndex);
glBindVertexArray(newBuffer->p_vertexArrayIndex);
glGenBuffers(1, &newBuffer->p_bufferIndex);
glBindBuffer(GL_UNIFORM_BUFFER, newBuffer->p_bufferIndex);
glBufferData(GL_UNIFORM_BUFFER, size, (void*)data, GL_STATIC_DRAW);
*buffer = static_cast<gpu::Buffer*>(newBuffer);
}
void Device::useVertexBuffer(gpu::Buffer *buffer, int stride, int offset)
{
if (buffer == nullptr)
{
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
opengl::Buffer* curBuffer = dynamic_cast<opengl::Buffer*>(buffer);
if (curBuffer->p_type == Buffer::BufferType::Vertex && p_currentVertexBuffer != buffer)
{
glBindVertexArray(curBuffer->p_vertexArrayIndex);
glBindBuffer(GL_ARRAY_BUFFER, curBuffer->p_bufferIndex);
opengl::Buffer* curIndexBuffer = dynamic_cast<opengl::Buffer*>(p_currentIndexBuffer);
if (curIndexBuffer != nullptr)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, curIndexBuffer->p_bufferIndex);
}
}
gpu::Device::useVertexBuffer(buffer, stride, offset);
}
void Device::useIndexBuffer(gpu::Buffer *buffer, int offset)
{
if (buffer == nullptr)
{
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
else
{
opengl::Buffer* curBuffer = dynamic_cast<opengl::Buffer*>(buffer);
if (curBuffer->p_type == Buffer::BufferType::Index && p_currentVertexBuffer != buffer)
{
glBindVertexArray(curBuffer->p_vertexArrayIndex);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, curBuffer->p_bufferIndex);
}
}
gpu::Device::useIndexBuffer(buffer, offset);
}
void Device::destroyBuffer(gpu::Buffer *&buffer)
{
if (buffer == nullptr)
throw std::invalid_argument("Invalid parameter");
opengl::Buffer* curBuffer = dynamic_cast<opengl::Buffer*>(buffer);
glDeleteBuffers(1, &curBuffer->p_bufferIndex);
if (curBuffer->p_type == Buffer::BufferType::Vertex)
glDeleteVertexArrays(1, &curBuffer->p_vertexArrayIndex);
gpu::Device::destroyBuffer(buffer);
}
// Shaders
void Device::createVertexShader(gpu::Shader **shader, const std::string &filename, const std::string &label)
{
if (shader == nullptr)
throw std::invalid_argument("Invalid parameter");
*shader = nullptr;
unsigned int shaderIndex = glCreateShader(GL_VERTEX_SHADER);
if (shaderIndex == 0)
throw std::runtime_error("Could not create shader");
File file;
file.open(filename, File::Binary | File::Read);
std::string content = file.read().str();
const char* shaderSource = content.c_str();
glShaderSource(shaderIndex, 1, &shaderSource, nullptr);
GLenum result = glGetError();
glCompileShader(shaderIndex);
int shaderStatus;
glGetShaderiv(shaderIndex, GL_COMPILE_STATUS, &shaderStatus);
if (!shaderStatus)
{
char error[2048 + 1];
glGetShaderInfoLog(shaderIndex, 2048, nullptr, error);
throw std::runtime_error(error);
}
p_shaders.emplace_back(opengl::Shader());
opengl::Shader* newShader = dynamic_cast<opengl::Shader*>(&p_shaders.back());
newShader->p_type = Shader::ShaderType::Vertex;
newShader->p_filename = filename;
newShader->p_shaderIndex = shaderIndex;
newShader->p_label = "VertexShader";
*shader = static_cast<Shader*>(newShader);
}
}

View File

@ -22,6 +22,45 @@ public:
~Device();
// Member functions
// Setup
bool initialize() override;
bool destroy() override;
// State
void faceCulling(bool enableFaceCulling, CullMode faceCullingMode = CullMode::None) override;
// Buffers
void createVertexBuffer(Buffer **buffer, int size, char* data) override;
void createIndexBuffer(Buffer **buffer, int size, char* data) override;
void useVertexBuffer(Buffer* buffer, int stride, int offset) override;
void useIndexBuffer(Buffer* buffer, int offset) override;
void destroyBuffer(Buffer*& buffer) override;
// Shaders
void createVertexShader(Shader** shader, const std::string& filename, const std::string& label) override;
void createFragmentShader(Shader** shader, const std::string& filename, const std::string& label) override;
void createGeometryShader(Shader** shader, const std::string& filename, const std::string& label) override;
void destroyShader(Shader*& shader) override;
// Shader programs
virtual void createShaderProgram(ShaderProgram** program);
virtual void attachShader(ShaderProgram* program, Shader* shader);
virtual void linkProgram(ShaderProgram* program);
virtual void useShaderProgram(ShaderProgram* program);
virtual void destroyShaderProgram(ShaderProgram*& program, bool withShaders = false);
// Textures
virtual void createTexture(Texture** texture, const std::string& filename);
virtual void useTexture(Texture* texture, int slot);
virtual void destroyTexture(Texture*& texture);
};
}

View File

@ -7,17 +7,34 @@ namespace hpr::gpu
Shader::Shader() :
Context {DeviceAPI::Unknown},
p_filename {},
p_label {}
p_filename {"\0"},
p_label {"\0"},
p_type {ShaderType::Vertex}
{}
Shader::Shader(DeviceAPI api) :
Context {api},
p_filename {},
p_label {}
p_filename {"\0"},
p_label {"\0"},
p_type {ShaderType::Vertex}
{}
Shader::~Shader()
{}
const std::string Shader::filename() const
{
return p_filename;
}
const std::string Shader::label() const
{
return p_label;
}
const Shader::ShaderType Shader::type() const
{
return p_type;
}
}

View File

@ -10,10 +10,7 @@ namespace hpr::gpu
class Shader : public Context
{
protected:
std::string p_filename;
std::string p_label;
friend class Device;
public:
@ -25,6 +22,14 @@ public:
ShaderTypeCount
};
protected:
std::string p_filename;
std::string p_label;
ShaderType p_type;
public:
// Constructors
Shader();
@ -39,7 +44,7 @@ public:
const std::string label() const;
const ShaderType shaderType() const;
const ShaderType type() const;
};
} // end namespace hpr::gpu

View File

@ -11,6 +11,7 @@ namespace hpr::gpu
class ShaderProgram : public Context
{
friend class Device;
protected:

View File

@ -23,4 +23,19 @@ Texture::Texture(DeviceAPI api) :
Texture::~Texture()
{}
std::string Texture::filename() const
{
return p_filename;
}
int Texture::width() const
{
return p_width;
}
int Texture::height() const
{
return p_height;
}
}

View File

@ -28,11 +28,11 @@ public:
// Member functions
const std::string filename() const();
std::string filename() const;
const int width() const;
int width() const;
const int height() const;
int height() const;
};
} // end namespace hpr::gpu

View File

@ -15,9 +15,12 @@ add_library(hyporo-hyplib STATIC
vector/vector.hpp
matrix/MatrixSpace.hpp
matrix/matrix.hpp
io/file.hpp
io/io.hpp
# Source files
scalar/scalar.cpp
io/file.cpp
)
if(WITH_GTESTS)

View File

@ -0,0 +1,70 @@
#include "file.hpp"
namespace hpr
{
File::File() :
p_name {"\0"},
p_mode {File::Read}
{}
File::File(const std::string &filename) :
p_name {filename},
p_mode {File::Read}
{}
File::File(const char *filename) :
p_name {filename},
p_mode {File::Read}
{}
File::~File()
{
if (p_file.is_open())
p_file.close();
}
void File::open(const std::string &filename, unsigned int filemode)
{
std::ios::openmode mode = filemode & File::Read ? std::ios::in : std::ios::out;
if (filemode & File::Binary)
mode |= std::ios::binary;
p_file.open(filename, mode);
if (!p_file.is_open())
throw std::ios::failure("Could not open file");
}
void File::close()
{
if (p_file.is_open())
p_file.close();
}
size_t File::length()
{
std::streampos size = 0;
std::streampos oldPos = p_file.tellg();
p_file.seekg(0, std::ios::beg);
size = p_file.tellg();
p_file.seekg(0, std::ios::end);
size = p_file.tellg() - size;
p_file.seekg(oldPos, std::ios::beg);
return (size_t)size;
}
std::stringstream File::read()
{
std::stringstream content;
content << p_file.rdbuf();
return content;
}
}

View File

@ -0,0 +1,53 @@
#pragma once
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
namespace hpr
{
class File
{
public:
enum FileMode
{
Write = std::ios::out,
Read = std::ios::in,
Binary = std::ios::binary,
Append = std::ios::app
};
protected:
std::string p_name;
unsigned int p_mode;
std::fstream p_file;
public:
// Constructors
File();
File(const std::string& filename);
File(const char* filename);
~File();
// Member functions
void open(const std::string& filename, unsigned int filemode = File::Read);
void close();
size_t length();
std::stringstream read();
};
}

View File

@ -0,0 +1,4 @@
#pragma once
#include "file.hpp"

View File

@ -1,3 +1,5 @@
#pragma once
#include "scalar.hpp"
#include "VectorSpace.hpp"