add GL/Program

This commit is contained in:
falsycat 2022-10-15 08:15:05 +09:00
parent 94615b3669
commit 451094c9fc
4 changed files with 153 additions and 51 deletions

View File

@ -78,7 +78,6 @@ target_sources(nf7
common/generic_memento.hh
common/generic_type_info.hh
common/generic_watcher.hh
common/gl_fence.hh
common/gl_obj.hh
common/gui_config.hh
common/gui_context.hh

View File

@ -1,46 +0,0 @@
#pragma once
#include <chrono>
#include <memory>
#include <GL/glew.h>
#include "nf7.hh"
#include "common/future.hh"
namespace nf7::gl {
inline void Await(const std::shared_ptr<nf7::Context>& ctx,
nf7::Future<std::monostate>::Promise& pro,
GLsync sync) noexcept {
GLsizei len;
GLint v;
glGetSynciv(sync, GL_SYNC_STATUS, sizeof(v), &len, &v);
assert(0 == glGetError());
if (v == GL_SIGNALED) {
glDeleteSync(sync);
pro.Return({});
} else {
ctx->env().ExecGL(ctx, [ctx, pro, sync]() mutable {
Await(ctx, pro, sync);
}, nf7::Env::Clock::now() + std::chrono::milliseconds(10));
}
}
// The returned future will be finalized on GL thread.
inline nf7::Future<std::monostate> ExecFenceSync(
const std::shared_ptr<nf7::Context>& ctx) noexcept {
nf7::Future<std::monostate>::Promise pro {ctx};
ctx->env().ExecGL(ctx, [ctx, pro]() mutable {
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
assert(0 == glGetError());
Await(ctx, pro, sync);
});
return pro.future();
}
} // namespace nf7::gl

View File

@ -18,7 +18,6 @@ namespace nf7::gl {
template <typename T>
class Obj final {
public:
Obj() = delete;
template <typename... Args>
Obj(const std::shared_ptr<nf7::Context>& ctx, GLuint id, Args&&... args) noexcept :
ctx_(ctx), meta_(std::forward<Args>(args)...), id_(id? id: meta_.Gen()) {
@ -109,4 +108,19 @@ struct Obj_ShaderMeta final {
using Shader = Obj<Obj_ShaderMeta>;
using ShaderFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Shader>>>;
struct Obj_ProgramMeta final {
public:
Obj_ProgramMeta() = default;
GLuint Gen() noexcept {
return glCreateProgram();
}
static void Delete(GLuint id) noexcept {
glDeleteProgram(id);
}
};
using Program = Obj<Obj_ProgramMeta>;
using ProgramFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Program>>>;
} // namespace nf7::gl

View File

@ -14,10 +14,13 @@
#include <yaml-cpp/yaml.h>
#include <yas/serialize.hpp>
#include <yas/types/std/string.hpp>
#include <yas/types/std/vector.hpp>
#include <yas/types/utility/usertype.hpp>
#include "nf7.hh"
#include "common/aggregate_promise.hh"
#include "common/dir_item.hh"
#include "common/factory.hh"
#include "common/file_base.hh"
@ -25,7 +28,6 @@
#include "common/generic_memento.hh"
#include "common/generic_type_info.hh"
#include "common/generic_watcher.hh"
#include "common/gl_fence.hh"
#include "common/gl_obj.hh"
#include "common/gui_config.hh"
#include "common/life.hh"
@ -48,6 +50,7 @@ class ObjBase : public nf7::FileBase,
using Resource = nf7::Mutex::Resource<Product>;
using ResourceFuture = nf7::Future<Resource>;
using ResourcePromise = typename ResourceFuture::Promise;
using ThisFactory = nf7::AsyncFactory<Resource>;
struct TypeInfo;
@ -154,8 +157,7 @@ class ObjBase : public nf7::FileBase,
nf7::File::Interface* interface(const std::type_info& t) noexcept override {
return nf7::InterfaceSelector<
nf7::DirItem, nf7::Memento, nf7::Node,
nf7::AsyncFactory<std::shared_ptr<T>>>(t).Select(this, &mem_);
nf7::DirItem, nf7::Memento, nf7::Node, ThisFactory>(t).Select(this, &mem_);
}
private:
@ -687,6 +689,139 @@ struct ObjBase<Shader>::TypeInfo final {
static inline const nf7::GenericTypeInfo<ObjBase<Shader>> kType = {"GL/Shader", {"nf7::DirItem"}};
};
struct Program {
public:
static void UpdateTypeTooltip() noexcept {
ImGui::TextUnformatted("OpenGL program");
}
static inline const std::vector<std::string> kInputs = {
"draw",
};
static inline const std::vector<std::string> kOutputs = {
"done",
};
using Product = nf7::gl::Program;
Program() = default;
Program(const Program&) = default;
Program(Program&&) = default;
Program& operator=(const Program&) = default;
Program& operator=(Program&&) = default;
void serialize(auto& ar) {
ar(shaders_);
}
std::string Stringify() noexcept {
YAML::Emitter st;
st << YAML::BeginMap;
st << YAML::Key << "shaders";
st << YAML::Value << YAML::BeginSeq;
for (const auto& shader : shaders_) {
st << shader.Stringify();
}
st << YAML::EndSeq;
st << YAML::EndMap;
return std::string {st.c_str(), st.size()};
}
void Parse(const std::string& v)
try {
const auto yaml = YAML::Load(v);
std::vector<nf7::File::Path> shaders;
for (const auto& shader : yaml["shaders"]) {
shaders.push_back(
nf7::File::Path::Parse(shader.as<std::string>()));
}
if (shaders.size() == 0) {
throw nf7::Exception {"no shader is attached"};
}
shaders_ = std::move(shaders);
} catch (YAML::Exception& e) {
throw nf7::Exception {std::string {"YAML error: "}+e.what()};
}
nf7::Future<std::shared_ptr<Product>> Create(
const std::shared_ptr<nf7::Context>& ctx, nf7::Env::Watcher&) noexcept
try {
// TODO: setup watcher
auto& base = ctx->env().GetFileOrThrow(ctx->initiator());
nf7::AggregatePromise sh_pro {ctx};
std::vector<
nf7::Future<
nf7::Mutex::Resource<
std::shared_ptr<nf7::gl::Shader>>>> sh;
for (auto& path : shaders_) {
sh.push_back(
base.ResolveOrThrow(path).
interfaceOrThrow<nf7::gl::ShaderFactory>().Create());
sh_pro.Add(sh.back());
}
nf7::Future<std::shared_ptr<Product>>::Promise pro {ctx};
sh_pro.future().Then([ctx, pro, shaders = std::move(sh)](auto&) mutable {
pro.Wrap([&]() {
std::vector<std::shared_ptr<nf7::gl::Shader>> sh;
for (auto& s : shaders) {
sh.push_back(*s.value());
}
return Link(ctx, sh);
});
});
return pro.future();
} catch (nf7::Exception&) {
return {std::current_exception()};
}
static std::shared_ptr<nf7::gl::Program> Link(
const std::shared_ptr<nf7::Context>& ctx,
const std::span<std::shared_ptr<nf7::gl::Shader>>& shaders) {
auto prog = std::make_shared<nf7::gl::Program>(ctx, GLuint {0});
assert(prog->id() > 0);
for (auto& sh : shaders) {
glAttachShader(prog->id(), sh->id());
}
glLinkProgram(prog->id());
GLint status;
glGetProgramiv(prog->id(), GL_LINK_STATUS, &status);
if (status == GL_TRUE) {
return prog;
} else {
GLint len;
glGetProgramiv(prog->id(), GL_INFO_LOG_LENGTH, &len);
std::string ret(static_cast<size_t>(len), ' ');
glGetProgramInfoLog(prog->id(), len, nullptr, ret.data());
throw nf7::Exception {std::move(ret)};
}
}
bool Handle(const std::shared_ptr<nf7::Node::Lambda>&,
const nf7::Mutex::Resource<std::shared_ptr<Product>>&,
const nf7::Node::Lambda::Msg&) {
// TODO
return false;
}
void UpdateTooltip(const std::shared_ptr<Product>& prod) noexcept {
if (prod) {
ImGui::Text("id : %zu", static_cast<size_t>(prod->id()));
}
}
private:
std::vector<nf7::File::Path> shaders_;
};
template <>
struct ObjBase<Program>::TypeInfo final {
static inline const nf7::GenericTypeInfo<ObjBase<Program>> kType = {"GL/Program", {"nf7::DirItem"}};
};
}
} // namespace nf7