vulkan pipeline
This commit is contained in:
parent
162c660fb9
commit
c93ed0fd77
@ -7,7 +7,6 @@
|
||||
#include "imgui_internal.h"
|
||||
#include "filesystem/stb_image.h"
|
||||
#include "rhi/texture.h"
|
||||
#include "rhi/opengl/renderer_opengl.h"
|
||||
#include "rhi/vulkan/renderer_vk.h"
|
||||
#include "spdlog/async.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
@ -21,7 +20,7 @@ static void glfw_error_callback(int error, const char* description) {
|
||||
spdlog::error("Glfw Error {}: {}", error, description);
|
||||
}
|
||||
|
||||
void application::init(window_params in_window_params, int argc, char** argv) {
|
||||
void application::init(const window_params& in_window_params, int argc, char** argv) {
|
||||
try {
|
||||
async_spdlog_ = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/log.txt");
|
||||
} catch (const spdlog::spdlog_ex& ex) {
|
||||
|
@ -3,9 +3,9 @@
|
||||
#include "imgui.h"
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
class renderer_vk;
|
||||
class pixel_shader_drawer;
|
||||
class render_target;
|
||||
class renderer;
|
||||
class texture;
|
||||
class application;
|
||||
|
||||
@ -42,7 +42,7 @@ public:
|
||||
return g_app_instance;
|
||||
}
|
||||
|
||||
virtual void init(window_params in_window_params, int argc, char** argv);
|
||||
virtual void init(const window_params& in_window_params, int argc, char** argv);
|
||||
|
||||
virtual int run();
|
||||
|
||||
@ -67,16 +67,16 @@ public:
|
||||
|
||||
[[nodiscard]] virtual const char* get_draw_ps_vertex_shader_entry() const = 0; // Vertex Shader used for drawing ps
|
||||
|
||||
[[nodiscard]] renderer* get_renderer() const { return renderer_; }
|
||||
[[nodiscard]] renderer_vk* get_renderer() const { return renderer_; }
|
||||
[[nodiscard]] GLFWwindow* get_window() const { return window_; }
|
||||
|
||||
protected:
|
||||
renderer* renderer_ = nullptr;
|
||||
renderer_vk* renderer_ = nullptr;
|
||||
GLFWwindow* window_ = nullptr;
|
||||
std::shared_ptr<spdlog::logger> async_spdlog_;
|
||||
|
||||
private:
|
||||
void init_glfw();
|
||||
static void init_glfw();
|
||||
|
||||
void init_imgui();
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define CHECK_GL_ERRORS \
|
||||
{\
|
||||
GLenum Error = glGetError();\
|
||||
if (Error != 0)\
|
||||
spdlog::critical("GL error: 0x{:x}", Error);\
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
#include "pixel_shader_drawer_opengl.h"
|
||||
|
||||
#include "application/application.h"
|
||||
#include "rhi/renderer.h"
|
||||
#include "shader/shader_ps_opengl.h"
|
||||
#include "shader/shader_vs_opengl.h"
|
||||
|
||||
void ps_opengl_compute_callback(const ImDrawList* parent_list, const ImDrawCmd* cmd) {
|
||||
const auto data = static_cast<pixel_shader_drawer_opengl*>(cmd->UserCallbackData);
|
||||
const std::shared_ptr<render_target_opengl>& rt = data->rt;
|
||||
const auto program = data->program;
|
||||
program->use_program();
|
||||
|
||||
// do on callback
|
||||
float x = 0;
|
||||
float width = rt->get_width();
|
||||
float y = 0;
|
||||
float height = rt->get_height();
|
||||
|
||||
const float ortho_projection[4][4] =
|
||||
{
|
||||
{2.0f / (width - x), 0.0f, 0.0f, 0.0f},
|
||||
{0.0f, 2.0f / (y - height), 0.0f, 0.0f},
|
||||
{0.0f, 0.0f, -1.0f, 0.0f},
|
||||
{(width + x) / (x - width), (y + height) / (height - y), 0.0f, 1.0f},
|
||||
};
|
||||
// glUseProgram(bd->ShaderHandle);
|
||||
// glUniform1i(bd->AttribLocationTex, 0);
|
||||
// glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||
program->set_uniform("viewMatrix", ortho_projection);
|
||||
|
||||
// ImVec2 clip_min(x, y);
|
||||
// ImVec2 clip_max(width, height);
|
||||
glViewport(0, 0, width, height);
|
||||
|
||||
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
|
||||
glScissor(0, 0, width, height);
|
||||
// glScissor((int)clip_min.x, (int)(0 - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
|
||||
|
||||
ImDrawVert& vert1 = data->vtx_buffer[0];
|
||||
ImDrawVert& vert2 = data->vtx_buffer[1];
|
||||
ImDrawVert& vert3 = data->vtx_buffer[2];
|
||||
ImDrawVert& vert4 = data->vtx_buffer[3];
|
||||
vert1.pos = ImVec2(0, 0);
|
||||
vert2.pos = ImVec2(width, 0);
|
||||
vert3.pos = ImVec2(width, height);
|
||||
vert4.pos = ImVec2(0, height);
|
||||
vert1.uv = ImVec2(0, 0);
|
||||
vert2.uv = ImVec2(1, 0);
|
||||
vert3.uv = ImVec2(1, 1);
|
||||
vert4.uv = ImVec2(0, 1);
|
||||
vert1.col = 0xFFFFFFFF;
|
||||
vert2.col = 0xFFFFFFFF;
|
||||
vert3.col = 0xFFFFFFFF;
|
||||
vert4.col = 0xFFFFFFFF;
|
||||
|
||||
|
||||
const size_t vtx_size = data->vtx_buffer.size() * sizeof(ImDrawVert);
|
||||
const size_t idx_size = data->idx_buffer.size() * sizeof(ImDrawIdx);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_size, data->vtx_buffer.data());
|
||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_size, data->idx_buffer.data());
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, data->vbo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data->ibo);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, rt->get_fbo());
|
||||
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, 6, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, 0, 0);
|
||||
// glDrawElements(GL_TRIANGLES, 6, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, 0);
|
||||
|
||||
program->unuse_program();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
|
||||
pixel_shader_drawer_opengl::~pixel_shader_drawer_opengl() {
|
||||
if (vbo)
|
||||
glDeleteBuffers(1, &vbo);
|
||||
if (ibo)
|
||||
glDeleteBuffers(1, &ibo);
|
||||
}
|
||||
|
||||
void pixel_shader_drawer_opengl::init(int width, int height, std::shared_ptr<shader> in_pixel_shader,
|
||||
std::shared_ptr<shader> in_vertex_shader) {
|
||||
if (!in_vertex_shader) {
|
||||
in_vertex_shader = application::get()->get_renderer()->get_pixel_shader_render_default_vs();
|
||||
}
|
||||
|
||||
const auto gl_ps = std::static_pointer_cast<shader_ps_opengl>(in_pixel_shader);
|
||||
const auto gl_vs = std::static_pointer_cast<shader_vs_opengl>(in_vertex_shader);
|
||||
vertex_shader = gl_vs;
|
||||
pixel_shader = gl_ps;
|
||||
rt = std::static_pointer_cast<render_target_opengl>(
|
||||
application::get()->create_render_target(width, height, texture_format::RGBA32_FLOAT));
|
||||
program = std::make_shared<shader_program_opengl>();
|
||||
program->create_program(gl_ps, gl_vs);
|
||||
|
||||
idx_buffer = {0, 1, 2, 0, 2, 3};
|
||||
vtx_buffer.resize(4);
|
||||
|
||||
glGenBuffers(1, &vbo);
|
||||
glGenBuffers(1, &ibo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
const size_t vtx_size = vtx_buffer.size() * sizeof(ImDrawVert);
|
||||
glBufferData(GL_ARRAY_BUFFER, vtx_size, vtx_buffer.data(), GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
const size_t idx_size = idx_buffer.size() * sizeof(ImDrawIdx);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_size, idx_buffer.data(), GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void pixel_shader_drawer_opengl::resize(int width, int height) {
|
||||
rt->resize(width, height);
|
||||
}
|
||||
|
||||
void pixel_shader_drawer_opengl::draw() {
|
||||
#if _DEBUG
|
||||
assert(!(pixel_shader.expired() || vertex_shader.expired()));
|
||||
#endif
|
||||
ImGui::GetWindowDrawList()->AddCallback(ps_opengl_compute_callback, this);
|
||||
ImGui::GetWindowDrawList()->AddCallback(ImDrawCallback_ResetRenderState, nullptr);
|
||||
rt->draw();
|
||||
}
|
||||
|
||||
void pixel_shader_drawer_opengl::set_vertex_shader(std::shared_ptr<shader> in_vertex_shader) {
|
||||
#if _DEBUG
|
||||
assert(!(pixel_shader.expired() || vertex_shader.expired()));
|
||||
#endif
|
||||
program->create_program(pixel_shader.lock(), vertex_shader.lock());
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
#include "render_target_opengl.h"
|
||||
#include "rhi/pixel_shader_drawer.h"
|
||||
#include "shader/shader_program_opengl.h"
|
||||
|
||||
class shader_ps_opengl;
|
||||
class shader_vs_opengl;
|
||||
|
||||
class pixel_shader_drawer_opengl : public pixel_shader_drawer {
|
||||
public:
|
||||
pixel_shader_drawer_opengl() = default;
|
||||
|
||||
~pixel_shader_drawer_opengl() override;
|
||||
|
||||
void init(int width, int height, std::shared_ptr<shader> in_pixel_shader,
|
||||
std::shared_ptr<shader> in_vertex_shader) override;
|
||||
|
||||
void resize(int width, int height) override;
|
||||
|
||||
void draw() override;
|
||||
|
||||
void set_vertex_shader(std::shared_ptr<shader> in_vertex_shader) override;
|
||||
|
||||
std::shared_ptr<render_target_opengl> rt;
|
||||
std::shared_ptr<shader_program_opengl> program;
|
||||
std::vector<ImDrawVert> vtx_buffer;
|
||||
std::vector<ImDrawIdx> idx_buffer;
|
||||
GLuint vbo = 0;
|
||||
GLuint ibo = 0;
|
||||
|
||||
std::weak_ptr<shader_vs_opengl> vertex_shader;
|
||||
std::weak_ptr<shader_ps_opengl> pixel_shader;
|
||||
};
|
@ -1,182 +0,0 @@
|
||||
#include "render_target_opengl.h"
|
||||
|
||||
#include "opengl_def.h"
|
||||
|
||||
GLint to_internal_format(texture_format format) {
|
||||
switch (format) {
|
||||
case texture_format::RGBA8:
|
||||
return GL_RGBA8;
|
||||
case texture_format::RGBA16_FLOAT:
|
||||
return GL_RGBA16F;
|
||||
case texture_format::RGBA32_FLOAT:
|
||||
return GL_RGBA32F;
|
||||
case texture_format::R32_FLOAT:
|
||||
return GL_R32F;
|
||||
case texture_format::RG32_FLOAT:
|
||||
return GL_RG32F;
|
||||
case texture_format::R11F_G11F_B10F:
|
||||
return GL_R11F_G11F_B10F;
|
||||
case texture_format::R16_FLOAT:
|
||||
return GL_R16F;
|
||||
case texture_format::RGBA16:
|
||||
return GL_RGBA16;
|
||||
case texture_format::RGB10_A2:
|
||||
return GL_RGB10_A2;
|
||||
case texture_format::RG16:
|
||||
return GL_RG16;
|
||||
case texture_format::RG8:
|
||||
return GL_RG8;
|
||||
case texture_format::R16:
|
||||
return GL_R16;
|
||||
case texture_format::R8:
|
||||
return GL_R8;
|
||||
case texture_format::RG16_SNORM:
|
||||
return GL_RG16_SNORM;
|
||||
case texture_format::RG8_SNORM:
|
||||
return GL_RG8_SNORM;
|
||||
case texture_format::R16_SNORM:
|
||||
return GL_R16_SNORM;
|
||||
case texture_format::R8_SNORM:
|
||||
return GL_R8_SNORM;
|
||||
case texture_format::R32I:
|
||||
return GL_R32I;
|
||||
case texture_format::R32UI:
|
||||
return GL_R32UI;
|
||||
case texture_format::R8I:
|
||||
return GL_R8I;
|
||||
case texture_format::R16I:
|
||||
return GL_R16I;
|
||||
case texture_format::R32F:
|
||||
return GL_R32F;
|
||||
case texture_format::R8UI:
|
||||
return GL_R8UI;
|
||||
case texture_format::R16UI:
|
||||
return GL_R16UI;
|
||||
case texture_format::RG32I:
|
||||
return GL_RG32I;
|
||||
case texture_format::RG32UI:
|
||||
return GL_RG32UI;
|
||||
case texture_format::RG8I:
|
||||
return GL_RG8I;
|
||||
case texture_format::RG16I:
|
||||
return GL_RG16I;
|
||||
case texture_format::RGB10_A2UI:
|
||||
return GL_RGB10_A2UI;
|
||||
case texture_format::RG16UI:
|
||||
return GL_RG16UI;
|
||||
default:
|
||||
return GL_RGBA8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void render_target_opengl::on_init(int width, int height, texture_format format) {
|
||||
glGenFramebuffers(1, &fbo_);
|
||||
CHECK_GL_ERRORS
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
|
||||
CHECK_GL_ERRORS
|
||||
|
||||
#if defined(__APPLE__)
|
||||
LockGLContext([NSOpenGLContext currentContext]);
|
||||
#endif
|
||||
|
||||
// Create a new OpenGL texture
|
||||
glGenTextures(1, &texture_);
|
||||
CHECK_GL_ERRORS
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture_);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
internal_format_ = to_internal_format(format);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format_, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
CHECK_GL_ERRORS
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
|
||||
|
||||
CHECK_GL_ERRORS
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
UnlockGLContext([NSOpenGLContext currentContext]);
|
||||
#endif
|
||||
}
|
||||
|
||||
render_target_opengl::~render_target_opengl() {
|
||||
glDeleteFramebuffers(1, &fbo_);
|
||||
glDeleteTextures(1, &texture_);
|
||||
}
|
||||
|
||||
void* render_target_opengl::lock(lock_state state) {
|
||||
locked_texture_ = malloc(width_ * height_ * 4);
|
||||
switch (state) {
|
||||
case lock_state::READ:
|
||||
case lock_state::READ_WRITE: {
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, locked_texture_);
|
||||
}
|
||||
break;
|
||||
case lock_state::WRITE:
|
||||
break;
|
||||
case lock_state::NONE:
|
||||
break;
|
||||
}
|
||||
return locked_texture_;
|
||||
}
|
||||
|
||||
void render_target_opengl::unlock() {
|
||||
#if defined(__APPLE__)
|
||||
LockGLContext([NSOpenGLContext currentContext]);
|
||||
#endif
|
||||
// Ensure texturing is enabled before setting texture properties
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture_);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, locked_texture_);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
UnlockGLContext([NSOpenGLContext currentContext]);
|
||||
#endif
|
||||
|
||||
free(locked_texture_);
|
||||
locked_texture_ = nullptr;
|
||||
}
|
||||
|
||||
void render_target_opengl::on_resize(int width, int height) {
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
glDeleteTextures(1, &texture_);
|
||||
glDeleteFramebuffers(1, &fbo_);
|
||||
texture_ = 0;
|
||||
fbo_ = 0;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
LockGLContext([NSOpenGLContext currentContext]);
|
||||
#endif
|
||||
glGenTextures(1, &texture_);
|
||||
CHECK_GL_ERRORS
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture_);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
CHECK_GL_ERRORS
|
||||
|
||||
glGenFramebuffers(1, &fbo_);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
|
||||
|
||||
CHECK_GL_ERRORS
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
UnlockGLContext([NSOpenGLContext currentContext]);
|
||||
#endif
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "rhi/render_target.h"
|
||||
|
||||
class render_target_opengl : public render_target {
|
||||
public:
|
||||
|
||||
~render_target_opengl() override;
|
||||
|
||||
ImTextureID get_texture_id() override { return (void*) static_cast<intptr_t>(texture_); }
|
||||
[[nodiscard]] GLuint get_fbo() const { return fbo_; }
|
||||
[[nodiscard]] GLuint get_texture() const { return texture_; }
|
||||
[[nodiscard]] GLint get_internal_format() const { return internal_format_; }
|
||||
|
||||
void* lock(lock_state state) override;
|
||||
|
||||
void unlock() override;
|
||||
|
||||
protected:
|
||||
void on_init(int width, int height, texture_format format) override;
|
||||
void on_resize(int width, int height) override;
|
||||
|
||||
private:
|
||||
GLuint fbo_ = 0;
|
||||
GLuint texture_ = 0;
|
||||
GLint internal_format_ = 0;
|
||||
void* locked_texture_ = nullptr;
|
||||
};
|
@ -1,132 +0,0 @@
|
||||
#include "renderer_opengl.h"
|
||||
|
||||
#include "imgui_impl_glfw.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include "imgui_impl_sdl3.h"
|
||||
#include "pixel_shader_drawer_opengl.h"
|
||||
#include "render_target_opengl.h"
|
||||
#include "texture_opengl.h"
|
||||
#include "application/application.h"
|
||||
#include "rhi/shader.h"
|
||||
#include "shader/shader_cs_opengl.h"
|
||||
#include "shader/shader_gs_opengl.h"
|
||||
#include "shader/shader_ps_opengl.h"
|
||||
#include "shader/shader_vs_opengl.h"
|
||||
|
||||
void renderer_opengl::pre_init() {
|
||||
// Decide GL+GLSL versions
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
// GL ES 2.0 + GLSL 100
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
||||
#elif defined(__APPLE__)
|
||||
// GL 3.2 + GLSL 150
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
|
||||
#else
|
||||
// GL 3.0 + GLSL 130
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
|
||||
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
||||
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only
|
||||
#endif
|
||||
}
|
||||
|
||||
bool renderer_opengl::init(GLFWwindow* window_handle) {
|
||||
if (has_initialized_)
|
||||
return true;
|
||||
|
||||
glfwMakeContextCurrent(window_handle);
|
||||
if (gladLoadGL() == 0) {
|
||||
spdlog::error("Failed to initialize OpenGL loader!");
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwSwapInterval(1); // Enable vsync
|
||||
|
||||
const auto glsl_version = "#version 460";
|
||||
// Setup Platform/Renderer backends
|
||||
ImGui_ImplGlfw_InitForOpenGL(window_handle, false);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback("#canvas");
|
||||
#endif
|
||||
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||
|
||||
has_initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void renderer_opengl::shutdown() {
|
||||
renderer::shutdown();
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EMSCRIPTEN_MAINLOOP_END;
|
||||
#endif
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
}
|
||||
|
||||
void renderer_opengl::post_shutdown() {
|
||||
renderer::post_shutdown();
|
||||
}
|
||||
|
||||
std::shared_ptr<shader> renderer_opengl::load_shader(const std::string& entry_name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<pixel_shader_drawer> renderer_opengl::create_pixel_shader_drawer() {
|
||||
return std::make_shared<pixel_shader_drawer_opengl>();
|
||||
}
|
||||
|
||||
void renderer_opengl::new_frame(GLFWwindow* window_handle) {
|
||||
// Start the Dear ImGui frame
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
void renderer_opengl::end_frame(GLFWwindow* window_handle) {
|
||||
const ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Rendering
|
||||
ImGui::Render();
|
||||
int display_w, display_h;
|
||||
glfwGetFramebufferSize(window_handle, &display_w, &display_h);
|
||||
glViewport(0, 0, display_w, display_h);
|
||||
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w,
|
||||
clear_color.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
// Update and Render additional Platform Windows
|
||||
// (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
|
||||
// For this specific demo app we could also call glfwMakeContextCurrent(window) directly)
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
GLFWwindow* backup_current_context = glfwGetCurrentContext();
|
||||
ImGui::UpdatePlatformWindows();
|
||||
ImGui::RenderPlatformWindowsDefault();
|
||||
glfwMakeContextCurrent(backup_current_context);
|
||||
}
|
||||
|
||||
glfwSwapBuffers(window_handle);
|
||||
}
|
||||
|
||||
void renderer_opengl::resize(int width, int height) {
|
||||
}
|
||||
|
||||
std::shared_ptr<texture> renderer_opengl::create_texture(const unsigned char* data, int width, int height) {
|
||||
auto out = std::make_shared<texture_opengl>();
|
||||
if (!out->init_data(data, width, height)) {
|
||||
out = nullptr;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::shared_ptr<render_target> renderer_opengl::create_render_target(int width, int height, texture_format format) {
|
||||
const auto target_dx11 = std::make_shared<render_target_opengl>();
|
||||
target_dx11->init(width, height, format);
|
||||
return target_dx11;
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
#include "rhi/renderer.h"
|
||||
|
||||
class renderer_opengl : public renderer {
|
||||
public:
|
||||
void pre_init() override;
|
||||
|
||||
bool init(GLFWwindow* window_handle) override;
|
||||
|
||||
void shutdown() override;
|
||||
|
||||
void post_shutdown() override;
|
||||
|
||||
std::shared_ptr<shader> load_shader(const std::string& entry_name) override;
|
||||
|
||||
std::shared_ptr<pixel_shader_drawer> create_pixel_shader_drawer() override;
|
||||
|
||||
void new_frame(GLFWwindow* window_handle) override;
|
||||
|
||||
void end_frame(GLFWwindow* window_handle) override;
|
||||
|
||||
void resize(int width, int height) override;
|
||||
|
||||
std::shared_ptr<texture> create_texture(const unsigned char* data, int width, int height) override;
|
||||
|
||||
std::shared_ptr<render_target> create_render_target(int width, int height, texture_format format) override;
|
||||
|
||||
private:
|
||||
bool has_initialized_ = false;
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
#include "shader_cs_opengl.h"
|
||||
|
||||
#include "shader_program_opengl.h"
|
||||
|
||||
|
||||
shader_cs_opengl::shader_cs_opengl(): shader_opengl() {
|
||||
}
|
||||
|
||||
bool shader_cs_opengl::init() {
|
||||
if (!shader_opengl::init())
|
||||
return false;
|
||||
program_ = std::make_shared<shader_program_opengl>();
|
||||
std::shared_ptr<shader_opengl> in_compute_shader = std::static_pointer_cast<shader_opengl>(shared_from_this());
|
||||
program_->create_program(in_compute_shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
void shader_cs_opengl::compute(int x, int y, int z) {
|
||||
program_->use_program();
|
||||
glDispatchCompute(x, y, z);
|
||||
program_->unuse_program();
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
#include "shader_opengl.h"
|
||||
|
||||
class shader_cs_opengl : public shader_opengl {
|
||||
public:
|
||||
explicit shader_cs_opengl();
|
||||
|
||||
bool init() override;
|
||||
|
||||
[[nodiscard]] GLenum get_shader_type() const override { return GL_COMPUTE_SHADER; }
|
||||
|
||||
void compute(int x, int y, int z) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<shader_program_opengl> program_;
|
||||
};
|
@ -1 +0,0 @@
|
||||
#include "shader_gs_opengl.h"
|
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
#include "shader_opengl.h"
|
||||
#include "rhi/opengl/opengl_def.h"
|
||||
|
||||
class shader_gs_opengl : public shader_opengl {
|
||||
public:
|
||||
shader_gs_opengl() : shader_opengl() {
|
||||
}
|
||||
|
||||
[[nodiscard]] GLenum get_shader_type() const override { return GL_GEOMETRY_SHADER; }
|
||||
};
|
@ -1,63 +0,0 @@
|
||||
#include "shader_opengl.h"
|
||||
|
||||
#include "shader_program_opengl.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
bool shader_opengl::init() {
|
||||
shader_id_ = glCreateShader(get_shader_type());
|
||||
if (shader_id_ == 0) {
|
||||
spdlog::error("Failed to create shader");
|
||||
return false;
|
||||
}
|
||||
// const auto code_blob = handle_->get_entry_point_code();
|
||||
// const auto code_array = static_cast<const char*>(code_blob->getBufferPointer());
|
||||
// const GLint code_size = static_cast<GLint>(code_blob->getBufferSize());
|
||||
// glShaderSource(shader_id_, 1, &code_array, &code_size);
|
||||
|
||||
// opengl_get_refletion_data(code_array, uniform_map_, texture_map_); // slow
|
||||
|
||||
glCompileShader(shader_id_);
|
||||
GLint compile_status = GL_FALSE;
|
||||
glGetShaderiv(shader_id_, GL_COMPILE_STATUS, &compile_status);
|
||||
if (compile_status == GL_FALSE) {
|
||||
GLint log_length = 0;
|
||||
glGetShaderiv(shader_id_, GL_INFO_LOG_LENGTH, &log_length);
|
||||
std::vector<GLchar> log(log_length);
|
||||
glGetShaderInfoLog(shader_id_, log_length, nullptr, log.data());
|
||||
spdlog::error("Failed to compile shader: {}", log.data());
|
||||
|
||||
glDeleteShader(shader_id_);
|
||||
shader_id_ = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void shader_opengl::set_using_program(std::shared_ptr<shader_program_opengl> in_program) {
|
||||
if (using_program_.lock()) {
|
||||
spdlog::error("Shader is already used by another program");
|
||||
return;
|
||||
}
|
||||
using_program_ = in_program;
|
||||
}
|
||||
|
||||
void shader_opengl::set_cbuffer(const char* name, void* buffer, int size) {
|
||||
if (const auto program = using_program_.lock())
|
||||
program->set_uniform(name, buffer, size);
|
||||
}
|
||||
|
||||
void shader_opengl::set_uav_buffer(const char* name, void* buffer, int size, int element_size) {
|
||||
if (const auto program = using_program_.lock())
|
||||
program->set_ssbo(name, buffer, size, element_size);
|
||||
}
|
||||
|
||||
void shader_opengl::set_render_target(const char* name, std::shared_ptr<render_target> in_render_target) {
|
||||
if (const auto program = using_program_.lock())
|
||||
program->set_render_target(name, in_render_target);
|
||||
}
|
||||
|
||||
void shader_opengl::set_texture(const char* name, std::shared_ptr<texture> in_texture) {
|
||||
if (const auto program = using_program_.lock())
|
||||
program->set_texture(name, in_texture);
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
|
||||
#include "rhi/shader.h"
|
||||
|
||||
class shader_program_opengl;
|
||||
|
||||
struct opengl_uniform_data {
|
||||
std::string type_name;
|
||||
std::string name;
|
||||
GLuint location = 0;
|
||||
GLuint binding = 0;
|
||||
GLint format = 0;
|
||||
};
|
||||
|
||||
struct opengl_texture_data {
|
||||
std::string sampler_name;
|
||||
GLuint binding = 0;
|
||||
GLint format = 0;
|
||||
};
|
||||
|
||||
class shader_opengl : public shader {
|
||||
public:
|
||||
explicit shader_opengl() : shader(), shader_id_(0) {
|
||||
}
|
||||
|
||||
bool init() override;
|
||||
|
||||
[[nodiscard]] bool is_initialized() const override { return shader_id_ != 0; }
|
||||
|
||||
void bind() override {
|
||||
}
|
||||
|
||||
void unbind() override {
|
||||
}
|
||||
|
||||
void set_using_program(std::shared_ptr<shader_program_opengl> in_program);
|
||||
|
||||
void set_cbuffer(const char* name, void* buffer, int size) override;
|
||||
|
||||
void set_uav_buffer(const char* name, void* buffer, int size, int element_size) override;
|
||||
|
||||
void set_render_target(const char* name, std::shared_ptr<render_target> in_render_target) override;
|
||||
|
||||
void set_texture(const char* name, std::shared_ptr<texture> in_texture) override;
|
||||
|
||||
[[nodiscard]] virtual GLenum get_shader_type() const = 0;
|
||||
|
||||
[[nodiscard]] GLuint get_shader_id() const { return shader_id_; }
|
||||
|
||||
[[nodiscard]] const std::map<std::string, opengl_uniform_data>& get_uniform_map() const { return uniform_map_; }
|
||||
[[nodiscard]] const std::map<std::string, opengl_texture_data>& get_texture_map() const { return texture_map_; }
|
||||
|
||||
protected:
|
||||
GLuint shader_id_;
|
||||
std::weak_ptr<shader_program_opengl> using_program_;
|
||||
std::map<std::string, opengl_uniform_data> uniform_map_;
|
||||
std::map<std::string, opengl_texture_data> texture_map_;
|
||||
};
|
@ -1,196 +0,0 @@
|
||||
#include "shader_program_opengl.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "shader_opengl.h"
|
||||
#include "rhi/opengl/render_target_opengl.h"
|
||||
#include "rhi/opengl/texture_opengl.h"
|
||||
|
||||
bool shader_program_opengl::create_program(std::shared_ptr<shader_opengl> in_pixel_shader,
|
||||
std::shared_ptr<shader_opengl> in_vertex_shader) {
|
||||
if (program_id_) {
|
||||
destroy_program();
|
||||
}
|
||||
if (!in_pixel_shader || !in_pixel_shader->is_initialized()) {
|
||||
spdlog::error("Pixel shader is not initialized");
|
||||
return false;
|
||||
}
|
||||
if (!in_vertex_shader || !in_vertex_shader->is_initialized()) {
|
||||
spdlog::error("Vertex shader is not initialized");
|
||||
return false;
|
||||
}
|
||||
const GLuint pixel_id = in_pixel_shader->get_shader_id();
|
||||
const GLuint vertex_id = in_vertex_shader->get_shader_id();
|
||||
|
||||
program_id_ = glCreateProgram();
|
||||
if (program_id_ == 0) {
|
||||
spdlog::error("Failed to create program");
|
||||
return false;
|
||||
}
|
||||
|
||||
glAttachShader(program_id_, vertex_id);
|
||||
glAttachShader(program_id_, pixel_id);
|
||||
|
||||
glLinkProgram(program_id_);
|
||||
GLint link_status = GL_FALSE;
|
||||
glGetProgramiv(program_id_, GL_LINK_STATUS, &link_status);
|
||||
if (link_status == GL_FALSE) {
|
||||
GLint log_length = 0;
|
||||
glGetProgramiv(program_id_, GL_INFO_LOG_LENGTH, &log_length);
|
||||
std::vector<GLchar> log(log_length);
|
||||
glGetProgramInfoLog(program_id_, log_length, nullptr, log.data());
|
||||
spdlog::error("Failed to link program: {}", log.data());
|
||||
|
||||
glDeleteProgram(program_id_);
|
||||
program_id_ = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
glDetachShader(program_id_, vertex_id);
|
||||
glDetachShader(program_id_, pixel_id);
|
||||
|
||||
pixel_shader_ = in_pixel_shader;
|
||||
vertex_shader_ = in_vertex_shader;
|
||||
in_pixel_shader->set_using_program(shared_from_this());
|
||||
in_vertex_shader->set_using_program(shared_from_this());
|
||||
|
||||
uniform_map_.clear();
|
||||
texture_map_.clear();
|
||||
update_param_map(in_pixel_shader);
|
||||
update_param_map(in_vertex_shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool shader_program_opengl::create_program(std::shared_ptr<shader_opengl> in_compute_shader) {
|
||||
if (program_id_) {
|
||||
destroy_program();
|
||||
}
|
||||
if (!in_compute_shader || !in_compute_shader->is_initialized()) {
|
||||
spdlog::error("Compute shader is not initialized");
|
||||
return false;
|
||||
}
|
||||
const GLuint compute_id = in_compute_shader->get_shader_id();
|
||||
|
||||
program_id_ = glCreateProgram();
|
||||
if (program_id_ == 0) {
|
||||
spdlog::error("Failed to create program");
|
||||
return false;
|
||||
}
|
||||
|
||||
glAttachShader(program_id_, compute_id);
|
||||
|
||||
glLinkProgram(program_id_);
|
||||
GLint link_status = GL_FALSE;
|
||||
glGetProgramiv(program_id_, GL_LINK_STATUS, &link_status);
|
||||
if (link_status == GL_FALSE) {
|
||||
GLint log_length = 0;
|
||||
glGetProgramiv(program_id_, GL_INFO_LOG_LENGTH, &log_length);
|
||||
std::vector<GLchar> log(log_length);
|
||||
glGetProgramInfoLog(program_id_, log_length, nullptr, log.data());
|
||||
spdlog::error("Failed to link program: {}", log.data());
|
||||
|
||||
glDeleteProgram(program_id_);
|
||||
program_id_ = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
glDetachShader(program_id_, compute_id);
|
||||
compute_shader_ = in_compute_shader;
|
||||
in_compute_shader->set_using_program(shared_from_this());
|
||||
|
||||
uniform_map_.clear();
|
||||
texture_map_.clear();
|
||||
update_param_map(in_compute_shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
void shader_program_opengl::destroy_program() {
|
||||
for (const auto& val: ubo_map_ | std::views::values)
|
||||
glDeleteBuffers(1, &val);
|
||||
|
||||
if (const auto shader = pixel_shader_.lock())
|
||||
shader->set_using_program(nullptr);
|
||||
if (const auto shader = vertex_shader_.lock())
|
||||
shader->set_using_program(nullptr);
|
||||
if (const auto shader = compute_shader_.lock())
|
||||
shader->set_using_program(nullptr);
|
||||
if (!program_id_)
|
||||
return;
|
||||
glDeleteProgram(program_id_);
|
||||
program_id_ = 0;
|
||||
ubo_map_.clear();
|
||||
uniform_map_.clear();
|
||||
texture_map_.clear();
|
||||
}
|
||||
|
||||
void shader_program_opengl::set_uniform(const char* slang_name, void* buffer, int size) {
|
||||
const auto& uniform_name = uniform_map_.find(slang_name);
|
||||
if (uniform_name == uniform_map_.end())
|
||||
return;
|
||||
|
||||
const auto& uniform_data = uniform_name->second;
|
||||
GLuint using_bind_point = uniform_data.binding;
|
||||
const auto find_ubo = ubo_map_.find(using_bind_point);
|
||||
if (find_ubo != ubo_map_.end()) {
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, find_ubo->second);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, size, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
const GLint block_index = glGetUniformBlockIndex(program_id_, uniform_data.type_name.c_str());
|
||||
glUniformBlockBinding(program_id_, block_index, uniform_data.binding);
|
||||
|
||||
// Create a buffer and copy the projection matrix to it.
|
||||
GLuint ubo = 0;
|
||||
glGenBuffers(1, &ubo);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, ubo);
|
||||
glBufferData(GL_UNIFORM_BUFFER, size, buffer, GL_STATIC_DRAW);
|
||||
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, using_bind_point, ubo);
|
||||
|
||||
ubo_map_.insert(std::pair(using_bind_point, ubo));
|
||||
}
|
||||
|
||||
void shader_program_opengl::set_ssbo(const char* slang_name, void* buffer, int size, int element_size) {
|
||||
const auto& uniform_name = uniform_map_.find(slang_name);
|
||||
if (uniform_name == uniform_map_.end())
|
||||
return;
|
||||
const auto& uniform_data = uniform_name->second;
|
||||
const GLint location = glGetProgramResourceIndex(program_id_, GL_SHADER_STORAGE_BLOCK, uniform_data.name.c_str());
|
||||
if (location == -1) {
|
||||
spdlog::error("Failed to find ssbo: {}", slang_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void shader_program_opengl::set_render_target(const char* name, std::shared_ptr<render_target> in_render_target) {
|
||||
const auto& texture_name = texture_map_.find(name);
|
||||
if (texture_name == texture_map_.end())
|
||||
return;
|
||||
|
||||
std::shared_ptr<render_target_opengl> rt = std::static_pointer_cast<render_target_opengl>(in_render_target);
|
||||
const opengl_texture_data& texture_data = texture_name->second;
|
||||
if (texture_data.format != rt->get_internal_format())
|
||||
spdlog::error("Mismatched texture format: {}, need{}, yours {}", name, texture_data.format,
|
||||
rt->get_internal_format());
|
||||
glBindImageTexture(texture_data.binding, rt->get_texture(), 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
|
||||
}
|
||||
|
||||
void shader_program_opengl::set_texture(const char* name, std::shared_ptr<texture> in_texture) {
|
||||
const auto& texture_name = texture_map_.find(name);
|
||||
if (texture_name == texture_map_.end())
|
||||
return;
|
||||
|
||||
std::shared_ptr<texture_opengl> t = std::static_pointer_cast<texture_opengl>(in_texture);
|
||||
const opengl_texture_data& texture_data = texture_name->second;
|
||||
glBindImageTexture(texture_data.binding, t->get_texture(), 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
|
||||
}
|
||||
|
||||
void shader_program_opengl::update_param_map(std::shared_ptr<shader_opengl> in_shader) {
|
||||
const auto& uniform_pairs = in_shader->get_uniform_map();
|
||||
const auto& texture_pairs = in_shader->get_texture_map();
|
||||
|
||||
uniform_map_.insert(uniform_pairs.begin(), uniform_pairs.end());
|
||||
texture_map_.insert(texture_pairs.begin(), texture_pairs.end());
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "shader_opengl.h"
|
||||
|
||||
class texture;
|
||||
class render_target;
|
||||
class shader;
|
||||
class shader_opengl;
|
||||
|
||||
class shader_program_opengl : public std::enable_shared_from_this<shader_program_opengl> {
|
||||
public:
|
||||
~shader_program_opengl() {
|
||||
destroy_program();
|
||||
}
|
||||
|
||||
void use_program() {
|
||||
GLint prev_program_id = 0;
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &prev_program_id);
|
||||
prev_program_id_ = prev_program_id;
|
||||
glUseProgram(program_id_);
|
||||
}
|
||||
|
||||
void unuse_program() const {
|
||||
glUseProgram(prev_program_id_);
|
||||
}
|
||||
|
||||
[[nodiscard]] GLuint get_program_id() const { return program_id_; }
|
||||
|
||||
bool create_program(std::shared_ptr<shader_opengl> in_pixel_shader,
|
||||
std::shared_ptr<shader_opengl> in_vertex_shader);
|
||||
|
||||
bool create_program(std::shared_ptr<shader_opengl> in_compute_shader);
|
||||
|
||||
void destroy_program();
|
||||
|
||||
void set_uniform(const char* slang_name, void* buffer, int size);
|
||||
|
||||
void set_ssbo(const char* slang_name, void* buffer, int size, int element_size);
|
||||
|
||||
void set_render_target(const char* name, std::shared_ptr<render_target> in_render_target);
|
||||
|
||||
void set_texture(const char* name, std::shared_ptr<texture> in_texture);
|
||||
|
||||
template<typename T>
|
||||
void set_uniform(const char* name, const T& buffer) {
|
||||
set_uniform(name, (void*) &buffer, sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set_uniform(const char* name, const std::vector<T>& buffer) {
|
||||
set_uniform(name, (void*) buffer.data(), sizeof(T) * buffer.size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set_ssbo(const char* name, const T& buffer) {
|
||||
set_ssbo(name, (void*) &buffer, sizeof(T), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set_ssbo(const char* name, const std::vector<T>& buffer) {
|
||||
set_ssbo(name, (void*) buffer.data(), sizeof(T) * buffer.size(), sizeof(T));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_initialized() const { return program_id_ != 0; }
|
||||
|
||||
private:
|
||||
void update_param_map(std::shared_ptr<shader_opengl> in_shader);
|
||||
|
||||
|
||||
std::map<std::string, opengl_uniform_data> uniform_map_; // slang_name -> uniform_data
|
||||
std::map<std::string, opengl_texture_data> texture_map_; // slang_name -> uniform_data
|
||||
std::map<GLuint, GLuint> ubo_map_; // binding -> ubo
|
||||
|
||||
GLuint program_id_ = 0;
|
||||
GLuint prev_program_id_ = 0;
|
||||
|
||||
std::weak_ptr<shader_opengl> pixel_shader_;
|
||||
std::weak_ptr<shader_opengl> vertex_shader_;
|
||||
std::weak_ptr<shader_opengl> compute_shader_;
|
||||
};
|
@ -1 +0,0 @@
|
||||
#include "shader_ps_opengl.h"
|
@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
#include "shader_opengl.h"
|
||||
#include "rhi/opengl/render_target_opengl.h"
|
||||
|
||||
class shader_vs_opengl;
|
||||
|
||||
class shader_ps_opengl : public shader_opengl {
|
||||
public:
|
||||
explicit shader_ps_opengl() : shader_opengl() {
|
||||
}
|
||||
|
||||
[[nodiscard]] GLenum get_shader_type() const override { return GL_FRAGMENT_SHADER; }
|
||||
};
|
@ -1 +0,0 @@
|
||||
#include "shader_vs_opengl.h"
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include "shader_opengl.h"
|
||||
|
||||
class shader_vs_opengl : public shader_opengl {
|
||||
public:
|
||||
shader_vs_opengl() : shader_opengl() {
|
||||
}
|
||||
|
||||
[[nodiscard]] GLenum get_shader_type() const override { return GL_VERTEX_SHADER; }
|
||||
};
|
@ -1,34 +0,0 @@
|
||||
#include "texture_opengl.h"
|
||||
|
||||
#include "opengl_def.h"
|
||||
|
||||
texture_opengl::~texture_opengl() {
|
||||
if (texture_id_ != 0) {
|
||||
glDeleteTextures(1, &texture_id_);
|
||||
}
|
||||
}
|
||||
|
||||
bool texture_opengl::init_data(const unsigned char* data, int width, int height) {
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
LockGLContext([NSOpenGLContext currentContext]);
|
||||
#endif
|
||||
|
||||
// Create a new OpenGL texture
|
||||
glGenTextures(1, &texture_id_);
|
||||
CHECK_GL_ERRORS
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture_id_);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
CHECK_GL_ERRORS
|
||||
#if defined(__APPLE__)
|
||||
UnlockGLContext([NSOpenGLContext currentContext]);
|
||||
#endif
|
||||
return true;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "rhi/texture.h"
|
||||
|
||||
class texture_opengl : public texture {
|
||||
public:
|
||||
~texture_opengl() override;
|
||||
|
||||
ImTextureID get_texture_id() override { return (void*) static_cast<intptr_t>(texture_id_); }
|
||||
GLuint get_texture() const { return texture_id_; }
|
||||
|
||||
bool init_data(const unsigned char* data, int width, int height) override;
|
||||
|
||||
[[nodiscard]] bool is_valid() const override { return texture_id_ != 0; }
|
||||
|
||||
private:
|
||||
GLuint texture_id_ = 0;
|
||||
};
|
@ -1 +0,0 @@
|
||||
#include "pixel_shader_drawer.h"
|
@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
class shader;
|
||||
class render_target;
|
||||
|
||||
class pixel_shader_drawer {
|
||||
public:
|
||||
virtual ~pixel_shader_drawer() = default;
|
||||
|
||||
virtual void init(int width, int height, std::shared_ptr<shader> in_pixel_shader,
|
||||
std::shared_ptr<shader> in_vertex_shader = nullptr) = 0;
|
||||
|
||||
virtual void resize(int width, int height) = 0;
|
||||
|
||||
virtual void draw() = 0;
|
||||
|
||||
virtual void set_vertex_shader(std::shared_ptr<shader> in_vertex_shader) {
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<render_target> rt_;
|
||||
};
|
48
core/rhi/vulkan/compute_pipeline.cpp
Normal file
48
core/rhi/vulkan/compute_pipeline.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include "compute_pipeline.h"
|
||||
|
||||
#include "application/application.h"
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "renderer_vk.h"
|
||||
|
||||
void compute_pipeline::add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, const vk::Sampler* immutable_samplers) {
|
||||
const vk::ShaderStageFlags flag = vk::ShaderStageFlagBits::eCompute;
|
||||
|
||||
vk::DescriptorSetLayoutBinding descriptor_set_layout_binding;
|
||||
descriptor_set_layout_binding.setBinding(binding);
|
||||
descriptor_set_layout_binding.setDescriptorType(descriptor_type);
|
||||
descriptor_set_layout_binding.setDescriptorCount(descriptor_count);
|
||||
descriptor_set_layout_binding.setStageFlags(flag);
|
||||
descriptor_set_layout_binding.setPImmutableSamplers(immutable_samplers);
|
||||
descriptor_set_layout_bindings_.push_back(descriptor_set_layout_binding);
|
||||
}
|
||||
|
||||
void compute_pipeline::create() {
|
||||
const auto renderer_vk = application::get()->get_renderer();
|
||||
auto device = renderer_vk->device;
|
||||
|
||||
vk::PipelineCacheCreateInfo pipeline_cache_create_info;
|
||||
pipeline_cache_create_info.setInitialDataSize(0);
|
||||
pipeline_cache_ = device.createPipelineCache(pipeline_cache_create_info);
|
||||
|
||||
create_pipeline_layout();
|
||||
|
||||
vk::ComputePipelineCreateInfo compute_pipeline_create_info;
|
||||
compute_pipeline_create_info.setLayout(pipeline_layout_);
|
||||
const auto pipeline_result = device.createComputePipeline(pipeline_cache_, compute_pipeline_create_info);
|
||||
check_vk_result(pipeline_result.result);
|
||||
pipeline_ = pipeline_result.value;
|
||||
}
|
||||
|
||||
void compute_pipeline::destroy() {
|
||||
const auto renderer_vk = application::get()->get_renderer();
|
||||
auto device = renderer_vk->device;
|
||||
|
||||
device.destroyPipeline(pipeline_);
|
||||
device.destroyPipelineCache(pipeline_cache_);
|
||||
device.destroyPipelineLayout(pipeline_layout_);
|
||||
}
|
||||
|
||||
void compute_pipeline::bind(vk::CommandBuffer command_buffer) const {
|
||||
command_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline_);
|
||||
}
|
14
core/rhi/vulkan/compute_pipeline.h
Normal file
14
core/rhi/vulkan/compute_pipeline.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "pipeline.h"
|
||||
|
||||
class compute_pipeline : pipeline {
|
||||
public:
|
||||
void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, const vk::Sampler* immutable_samplers) override;
|
||||
void create() override;
|
||||
void destroy() override;
|
||||
void bind(vk::CommandBuffer command_buffer) const override;
|
||||
|
||||
void set_shader(const std::string& file_path) {
|
||||
|
||||
}
|
||||
};
|
46
core/rhi/vulkan/pipeline.cpp
Normal file
46
core/rhi/vulkan/pipeline.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include "pipeline.h"
|
||||
|
||||
#include "renderer_vk.h"
|
||||
#include "application/application.h"
|
||||
|
||||
void pipeline::create_pipeline_layout() {
|
||||
const auto renderer = application::get()->get_renderer();
|
||||
const auto device = renderer->device;
|
||||
|
||||
vk::DescriptorSetLayoutCreateInfo descriptor_set_layout_create_info;
|
||||
descriptor_set_layout_create_info.setBindings(descriptor_set_layout_bindings_);
|
||||
vk::DescriptorSetLayout descriptor_set_layout = device.createDescriptorSetLayout(descriptor_set_layout_create_info);
|
||||
|
||||
vk::PipelineLayoutCreateInfo pipeline_layout_create_info;
|
||||
pipeline_layout_create_info.setSetLayouts(descriptor_set_layout);
|
||||
pipeline_layout_ = device.createPipelineLayout(pipeline_layout_create_info);
|
||||
}
|
||||
|
||||
void pipeline::create_pipeline_command() const {
|
||||
const auto renderer = application::get()->get_renderer();
|
||||
const auto device = renderer->device;
|
||||
const auto command_pool = renderer->command_pool;
|
||||
|
||||
vk::CommandBufferAllocateInfo command_buffer_allocate_info;
|
||||
command_buffer_allocate_info.setCommandPool(command_pool);
|
||||
command_buffer_allocate_info.setLevel(vk::CommandBufferLevel::ePrimary);
|
||||
command_buffer_allocate_info.setCommandBufferCount(1);
|
||||
const vk::CommandBuffer command_buffer = device.allocateCommandBuffers(command_buffer_allocate_info)[0];
|
||||
|
||||
vk::CommandBufferBeginInfo command_buffer_begin_info;
|
||||
command_buffer_begin_info.setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
|
||||
command_buffer.begin(command_buffer_begin_info);
|
||||
|
||||
bind(command_buffer);
|
||||
|
||||
command_buffer.end();
|
||||
|
||||
vk::SubmitInfo submit_info;
|
||||
submit_info.setCommandBufferCount(1);
|
||||
submit_info.setPCommandBuffers(&command_buffer);
|
||||
renderer->queue.submit(submit_info, nullptr);
|
||||
renderer->queue.waitIdle();
|
||||
|
||||
device.freeCommandBuffers(command_pool, command_buffer);
|
||||
device.destroyCommandPool(command_pool);
|
||||
}
|
43
core/rhi/vulkan/pipeline.h
Normal file
43
core/rhi/vulkan/pipeline.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
class pipeline {
|
||||
public:
|
||||
virtual ~pipeline() = default;
|
||||
|
||||
virtual void add_binding(uint32_t binding, vk::DescriptorType descriptor_type, uint32_t descriptor_count, const vk::Sampler* immutable_samplers) = 0;
|
||||
|
||||
void add_uniform_buffer(uint32_t binding, uint32_t descriptor_count = 1) {
|
||||
add_binding(binding, vk::DescriptorType::eUniformBuffer, descriptor_count, nullptr);
|
||||
}
|
||||
void add_storage_buffer(uint32_t binding, uint32_t descriptor_count = 1) {
|
||||
add_binding(binding, vk::DescriptorType::eStorageBuffer, descriptor_count, nullptr);
|
||||
}
|
||||
void add_sampled_image(uint32_t binding, uint32_t descriptor_count = 1, const vk::Sampler* immutable_samplers = nullptr) {
|
||||
add_binding(binding, vk::DescriptorType::eSampledImage, descriptor_count, immutable_samplers);
|
||||
}
|
||||
void add_storage_image(uint32_t binding, uint32_t descriptor_count = 1) {
|
||||
add_binding(binding, vk::DescriptorType::eStorageImage, descriptor_count, nullptr);
|
||||
}
|
||||
void add_input_attachment(uint32_t binding, uint32_t descriptor_count = 1) {
|
||||
add_binding(binding, vk::DescriptorType::eInputAttachment, descriptor_count, nullptr);
|
||||
}
|
||||
void add_sampler(uint32_t binding, uint32_t descriptor_count = 1, const vk::Sampler* immutable_samplers = nullptr) {
|
||||
add_binding(binding, vk::DescriptorType::eSampler, descriptor_count, immutable_samplers);
|
||||
}
|
||||
void add_combined_image_sampler(uint32_t binding, uint32_t descriptor_count = 1, const vk::Sampler* immutable_samplers = nullptr) {
|
||||
add_binding(binding, vk::DescriptorType::eCombinedImageSampler, descriptor_count, immutable_samplers);
|
||||
}
|
||||
|
||||
void create_pipeline_layout();
|
||||
|
||||
virtual void create() = 0;
|
||||
virtual void destroy() = 0;
|
||||
virtual void bind(vk::CommandBuffer command_buffer) const = 0;
|
||||
void create_pipeline_command() const;
|
||||
|
||||
vk::Pipeline pipeline_;
|
||||
vk::PipelineCache pipeline_cache_;
|
||||
vk::PipelineLayout pipeline_layout_;
|
||||
std::vector<vk::DescriptorSetLayoutBinding> descriptor_set_layout_bindings_;
|
||||
};
|
1
core/rhi/vulkan/render_target_vk.cpp
Normal file
1
core/rhi/vulkan/render_target_vk.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "render_target_vk.h"
|
8
core/rhi/vulkan/render_target_vk.h
Normal file
8
core/rhi/vulkan/render_target_vk.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "rhi/render_target.h"
|
||||
|
||||
|
||||
class render_target_vk : public render_target {
|
||||
|
||||
};
|
@ -2,23 +2,7 @@
|
||||
|
||||
#include "imgui_impl_glfw.h"
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
static void check_vk_result(vk::Result err) {
|
||||
if (err == vk::Result::eSuccess)
|
||||
return;
|
||||
|
||||
spdlog::error("[vulkan] Error: VkResult = {}", vk::to_string(err));
|
||||
abort();
|
||||
}
|
||||
|
||||
static void check_vk_result(VkResult err) {
|
||||
if (err == VK_SUCCESS)
|
||||
return;
|
||||
if (err < 0) {
|
||||
spdlog::error("[vulkan] Error: VkResult = {}", err);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
static bool is_extension_available(const std::vector<vk::ExtensionProperties>& properties, const char* extension) {
|
||||
return std::ranges::any_of(properties, [extension](const vk::ExtensionProperties& p) {
|
||||
@ -34,9 +18,7 @@ vk::PhysicalDevice renderer_vk::setup_vulkan_select_physical_device() const {
|
||||
// most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple
|
||||
// dedicated GPUs) is out of scope of this sample.
|
||||
for (auto& device: gpus) {
|
||||
auto properties = device.getProperties();
|
||||
|
||||
if (properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu)
|
||||
if (const auto properties = device.getProperties(); properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu)
|
||||
return device;
|
||||
}
|
||||
|
||||
@ -76,7 +58,7 @@ void renderer_vk::setup_vulkan(ImVector<const char*> instance_extensions) {
|
||||
|
||||
// Select graphics queue family
|
||||
{
|
||||
auto queues = physical_device.getQueueFamilyProperties();
|
||||
const auto queues = physical_device.getQueueFamilyProperties();
|
||||
for (uint32_t i = 0; i < queues.size(); i++) {
|
||||
if (queues[i].queueFlags & vk::QueueFlagBits::eGraphics) {
|
||||
queue_family = i;
|
||||
@ -117,6 +99,14 @@ void renderer_vk::setup_vulkan(ImVector<const char*> instance_extensions) {
|
||||
|
||||
descriptor_pool = device.createDescriptorPool(descriptor_pool_create_info);
|
||||
}
|
||||
|
||||
// Create Command Pool
|
||||
{
|
||||
vk::CommandPoolCreateInfo cmd_pool_info;
|
||||
cmd_pool_info.setQueueFamilyIndex(queue_family);
|
||||
cmd_pool_info.setFlags(vk::CommandPoolCreateFlagBits::eResetCommandBuffer);
|
||||
command_pool = device.createCommandPool(cmd_pool_info);
|
||||
}
|
||||
}
|
||||
|
||||
// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo.
|
||||
@ -377,7 +367,7 @@ void renderer_vk::init_vulkan(GLFWwindow* window_handle) {
|
||||
init_info.Device = device;
|
||||
init_info.QueueFamily = queue_family;
|
||||
init_info.Queue = queue;
|
||||
init_info.PipelineCache = pipeline_cache;
|
||||
init_info.PipelineCache = VK_NULL_HANDLE;
|
||||
init_info.DescriptorPool = descriptor_pool;
|
||||
init_info.RenderPass = main_window_data.RenderPass;
|
||||
init_info.Subpass = 0;
|
||||
|
@ -8,6 +8,22 @@
|
||||
#include "imgui_impl_vulkan.h"
|
||||
#include "rhi/renderer.h"
|
||||
|
||||
static void check_vk_result(vk::Result err) {
|
||||
if (err == vk::Result::eSuccess)
|
||||
return;
|
||||
|
||||
spdlog::error("[vulkan] Error: VkResult = {}", vk::to_string(err));
|
||||
abort();
|
||||
}
|
||||
|
||||
static void check_vk_result(VkResult err) {
|
||||
if (err == VK_SUCCESS)
|
||||
return;
|
||||
if (err < 0) {
|
||||
spdlog::error("[vulkan] Error: VkResult = {}", err);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
class renderer_vk : public renderer {
|
||||
public:
|
||||
@ -38,8 +54,8 @@ public:
|
||||
vk::Device device = VK_NULL_HANDLE;
|
||||
uint32_t queue_family = (uint32_t)-1;
|
||||
vk::Queue queue = VK_NULL_HANDLE;
|
||||
vk::PipelineCache pipeline_cache = VK_NULL_HANDLE;
|
||||
vk::DescriptorPool descriptor_pool = VK_NULL_HANDLE;
|
||||
vk::CommandPool command_pool = VK_NULL_HANDLE;
|
||||
|
||||
ImGui_ImplVulkanH_Window main_window_data;
|
||||
int min_image_count = 2;
|
||||
|
51
core/rhi/vulkan/texture_vk.cpp
Normal file
51
core/rhi/vulkan/texture_vk.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "texture_vk.h"
|
||||
|
||||
#include "renderer_vk.h"
|
||||
#include "application/application.h"
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
bool texture_vk::init_data(const unsigned char* data, int width, int height) {
|
||||
auto vk_rder = static_cast<renderer_vk*>(application::get()->get_renderer());
|
||||
auto& device = vk_rder->device;
|
||||
|
||||
vk::ImageCreateInfo image_info;
|
||||
image_info.setFormat(vk::Format::eR8G8B8A8Srgb);
|
||||
image_info.setImageType(vk::ImageType::e2D);
|
||||
image_info.setExtent({static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1});
|
||||
image_info.setMipLevels(1);
|
||||
image_info.setArrayLayers(1);
|
||||
image_info.setSamples(vk::SampleCountFlagBits::e1);
|
||||
image_ = device.createImage(image_info);
|
||||
|
||||
vk::ImageViewCreateInfo view_info;
|
||||
view_info.setImage(image_);
|
||||
view_info.setViewType(vk::ImageViewType::e2D);
|
||||
view_info.setFormat(vk::Format::eR8G8B8A8Srgb);
|
||||
view_info.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
|
||||
image_view_ = device.createImageView(view_info);
|
||||
|
||||
vk::SamplerCreateInfo sampler_info;
|
||||
sampler_info.setMagFilter(vk::Filter::eLinear);
|
||||
sampler_info.setMinFilter(vk::Filter::eLinear);
|
||||
sampler_info.setAddressModeU(vk::SamplerAddressMode::eClampToEdge);
|
||||
sampler_info.setAddressModeV(vk::SamplerAddressMode::eClampToEdge);
|
||||
sampler_info.setAddressModeW(vk::SamplerAddressMode::eClampToEdge);
|
||||
sampler_info.setAnisotropyEnable(VK_FALSE);
|
||||
sampler_info.setMaxAnisotropy(1);
|
||||
sampler_info.setBorderColor(vk::BorderColor::eFloatOpaqueWhite);
|
||||
sampler_info.setUnnormalizedCoordinates(VK_FALSE);
|
||||
sampler_info.setCompareEnable(VK_FALSE);
|
||||
sampler_info.setCompareOp(vk::CompareOp::eAlways);
|
||||
sampler_info.setMipmapMode(vk::SamplerMipmapMode::eLinear);
|
||||
sampler_ = device.createSampler(sampler_info);
|
||||
|
||||
vk::BufferCreateInfo buffer_info;
|
||||
buffer_info.setSize(width * height * 4);
|
||||
buffer_info.setUsage(vk::BufferUsageFlagBits::eTransferSrc);
|
||||
buffer_info.setSharingMode(vk::SharingMode::eExclusive);
|
||||
buffer_ = device.createBuffer(buffer_info);
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
17
core/rhi/vulkan/texture_vk.h
Normal file
17
core/rhi/vulkan/texture_vk.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "rhi/texture.h"
|
||||
|
||||
|
||||
class texture_vk : public texture {
|
||||
public:
|
||||
bool init_data(const unsigned char* data, int width, int height) override;
|
||||
bool is_valid() const override { return image_view_; }
|
||||
ImTextureID get_texture_id() override { return static_cast<VkImageView>(image_view_); }
|
||||
private:
|
||||
vk::Image image_;
|
||||
vk::ImageView image_view_;
|
||||
vk::Sampler sampler_;
|
||||
vk::Buffer buffer_;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user