add GL/Framebuffer
This commit is contained in:
parent
38fc3b680a
commit
ca5dfb5933
@ -240,4 +240,95 @@ try {
|
||||
return { std::current_exception() };
|
||||
}
|
||||
|
||||
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_FramebufferMeta>>> Obj_FramebufferMeta::Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
std::vector<Attachment>&& atts) noexcept {
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_FramebufferMeta>>>::Promise pro {ctx};
|
||||
LockAttachments(ctx, atts).
|
||||
Chain(nf7::Env::kGL, ctx, pro, [ctx, atts = std::move(atts)](auto& texs) mutable {
|
||||
assert(atts.size() == texs.size());
|
||||
|
||||
GLuint id;
|
||||
glGenFramebuffers(1, &id);
|
||||
|
||||
const char* err = nullptr;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, id);
|
||||
for (size_t i = 0; i < atts.size() && !err; ++i) {
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, atts[i].slot, (*texs[i])->id(), 0);
|
||||
if (0 != glGetError()) {
|
||||
err = "failed to attach texture";
|
||||
}
|
||||
}
|
||||
const auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
assert(0 == glGetError());
|
||||
|
||||
const auto ret = std::make_shared<Obj<Obj_FramebufferMeta>>(ctx, id, std::move(atts));
|
||||
if (err) {
|
||||
throw nf7::Exception {err};
|
||||
}
|
||||
ThrowStatus(status);
|
||||
return ret;
|
||||
});
|
||||
return pro.future();
|
||||
}
|
||||
|
||||
nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Texture>>>>
|
||||
Obj_FramebufferMeta::LockAttachments(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
std::span<const Attachment> attachments) noexcept
|
||||
try {
|
||||
nf7::AggregatePromise apro {ctx};
|
||||
std::vector<nf7::Future<nf7::Mutex::Resource<std::shared_ptr<gl::Texture>>>> fus;
|
||||
|
||||
for (const auto& attachment : attachments) {
|
||||
nf7::Future<nf7::Mutex::Resource<std::shared_ptr<gl::Texture>>>::Promise pro {ctx};
|
||||
auto fu = ctx->env().GetFileOrThrow(attachment.tex).
|
||||
interfaceOrThrow<nf7::gl::TextureFactory>().Create().
|
||||
Chain(nf7::Env::kGL, ctx, pro, [](auto& tex) {
|
||||
if ((*tex)->meta().type != GL_TEXTURE_2D) {
|
||||
throw nf7::Exception {"only 2D texture is allowed"};
|
||||
}
|
||||
return tex;
|
||||
});
|
||||
|
||||
fus.push_back(fu);
|
||||
apro.Add(fu);
|
||||
}
|
||||
|
||||
nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Texture>>>>::Promise pro {ctx};
|
||||
apro.future().Chain(pro, [fus = std::move(fus)](auto&) {
|
||||
std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Texture>>> ret;
|
||||
for (auto& fu : fus) {
|
||||
ret.emplace_back(fu.value());
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
return pro.future();
|
||||
} catch (nf7::Exception&) {
|
||||
return { std::current_exception() };
|
||||
}
|
||||
|
||||
void Obj_FramebufferMeta::ThrowStatus(GLenum status) {
|
||||
switch (status) {
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
return;
|
||||
case GL_FRAMEBUFFER_UNDEFINED:
|
||||
throw nf7::Exception {"no framebuffer bound"};
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
throw nf7::Exception {"no framebuffer bound"};
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
throw nf7::Exception {"nothing attached"};
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
throw nf7::Exception {"no color attachments"};
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
throw nf7::Exception {"unsupported internal format"};
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||
throw nf7::Exception {"incomplete multisample"};
|
||||
default:
|
||||
throw nf7::Exception {"unknown framebuffer status"};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nf7::gl
|
||||
|
@ -21,7 +21,7 @@ class Obj final {
|
||||
public:
|
||||
using Meta = T;
|
||||
|
||||
// NOT thread-safe
|
||||
// must be called from main or sub task
|
||||
template <typename... Args>
|
||||
static nf7::Future<std::shared_ptr<Obj<T>>> Create(Args&&... args) noexcept {
|
||||
return Meta::Create(std::forward<Args>(args)...);
|
||||
@ -54,6 +54,7 @@ class Obj final {
|
||||
|
||||
struct Obj_BufferMeta final {
|
||||
public:
|
||||
// must be called from main or sub task
|
||||
static nf7::Future<std::shared_ptr<Obj<Obj_BufferMeta>>> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx, GLenum type) noexcept;
|
||||
|
||||
@ -99,6 +100,7 @@ using TextureFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Texture
|
||||
|
||||
struct Obj_ShaderMeta final {
|
||||
public:
|
||||
// must be called from main or sub task
|
||||
static nf7::Future<std::shared_ptr<Obj<Obj_ShaderMeta>>> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
GLenum type,
|
||||
@ -120,6 +122,7 @@ using ShaderFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Shader>>
|
||||
|
||||
struct Obj_ProgramMeta final {
|
||||
public:
|
||||
// must be called from main or sub task
|
||||
static nf7::Future<std::shared_ptr<Obj<Obj_ProgramMeta>>> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
const std::vector<nf7::File::Id>& shaders) noexcept;
|
||||
@ -147,6 +150,7 @@ struct Obj_VertexArrayMeta final {
|
||||
GLuint divisor;
|
||||
};
|
||||
|
||||
// must be called from main or sub task
|
||||
static nf7::Future<std::shared_ptr<Obj<Obj_VertexArrayMeta>>> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx, std::vector<Attr>&& attrs) noexcept;
|
||||
|
||||
@ -154,6 +158,7 @@ struct Obj_VertexArrayMeta final {
|
||||
glDeleteVertexArrays(1, &id);
|
||||
}
|
||||
|
||||
// must be called from main or sub task
|
||||
static nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Buffer>>>>
|
||||
LockBuffers(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
@ -173,4 +178,42 @@ struct Obj_VertexArrayMeta final {
|
||||
using VertexArray = Obj<Obj_VertexArrayMeta>;
|
||||
using VertexArrayFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<VertexArray>>>;
|
||||
|
||||
|
||||
struct Obj_FramebufferMeta final {
|
||||
public:
|
||||
struct Attachment {
|
||||
nf7::File::Id tex;
|
||||
GLenum slot;
|
||||
};
|
||||
|
||||
// must be called from main or sub task
|
||||
static nf7::Future<std::shared_ptr<Obj<Obj_FramebufferMeta>>> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
std::vector<Attachment>&& attachments) noexcept;
|
||||
|
||||
static void Delete(GLuint id) noexcept {
|
||||
glDeleteFramebuffers(1, &id);
|
||||
}
|
||||
|
||||
// must be called from main or sub task
|
||||
static nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Texture>>>> LockAttachments(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
std::span<const Attachment> attachments) noexcept;
|
||||
|
||||
// must be called on GL thread
|
||||
static void ThrowStatus(GLenum status);
|
||||
|
||||
Obj_FramebufferMeta(std::vector<Attachment>&& a) noexcept : attachments(std::move(a)) {
|
||||
}
|
||||
|
||||
nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Texture>>>> LockAttachments(
|
||||
const std::shared_ptr<nf7::Context>& ctx) noexcept {
|
||||
return LockAttachments(ctx, attachments);
|
||||
}
|
||||
|
||||
const std::vector<Attachment> attachments;
|
||||
};
|
||||
using Framebuffer = Obj<Obj_FramebufferMeta>;
|
||||
using FramebufferFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Framebuffer>>>;
|
||||
|
||||
} // namespace nf7::gl
|
||||
|
129
file/gl_obj.cc
129
file/gl_obj.cc
@ -815,7 +815,7 @@ struct VertexArray {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static void Validate(const std::vector<Attr>& attrs) {
|
||||
static void Validate(std::span<const Attr> attrs) {
|
||||
for (auto& attr : attrs) {
|
||||
if (const auto msg = attr.Validate()) {
|
||||
throw nf7::Exception {"invalid attribute: "s+msg};
|
||||
@ -955,6 +955,129 @@ struct ObjBase<VertexArray>::TypeInfo final {
|
||||
static inline const nf7::GenericTypeInfo<ObjBase<VertexArray>> kType = {"GL/VertexArray", {"nf7::DirItem"}};
|
||||
};
|
||||
|
||||
|
||||
struct Framebuffer {
|
||||
public:
|
||||
static void UpdateTypeTooltip() noexcept {
|
||||
ImGui::TextUnformatted("OpenGL Framebuffer Object");
|
||||
}
|
||||
|
||||
static inline const std::vector<std::string> kInputs = {
|
||||
};
|
||||
static inline const std::vector<std::string> kOutputs = {
|
||||
};
|
||||
|
||||
using Product = nf7::gl::Framebuffer;
|
||||
|
||||
enum class Slot {
|
||||
Color0, Color1, Color2, Color3, Color4, Color5, Color6, Color7,
|
||||
};
|
||||
struct Attachment {
|
||||
public:
|
||||
Slot slot;
|
||||
nf7::File::Path path;
|
||||
|
||||
void serialize(auto& ar) {
|
||||
ar(slot, path);
|
||||
}
|
||||
};
|
||||
|
||||
Framebuffer() = default;
|
||||
Framebuffer(const Framebuffer&) = default;
|
||||
Framebuffer(Framebuffer&&) = default;
|
||||
Framebuffer& operator=(const Framebuffer&) = default;
|
||||
Framebuffer& operator=(Framebuffer&&) = default;
|
||||
|
||||
void serialize(auto& ar) {
|
||||
ar(attachments_);
|
||||
}
|
||||
|
||||
std::string Stringify() noexcept {
|
||||
YAML::Emitter st;
|
||||
st << YAML::BeginMap;
|
||||
st << YAML::Key << "attachments";
|
||||
st << YAML::Value << YAML::BeginMap;
|
||||
for (const auto& attachment : attachments_) {
|
||||
st << YAML::Key << std::string {magic_enum::enum_name(attachment.slot)};
|
||||
st << YAML::Value << attachment.path.Stringify();
|
||||
}
|
||||
st << YAML::EndMap;
|
||||
st << YAML::EndMap;
|
||||
return std::string {st.c_str(), st.size()};
|
||||
}
|
||||
void Parse(const std::string& v)
|
||||
try {
|
||||
const auto yaml = YAML::Load(v);
|
||||
const auto& yaml_attachments = yaml["attachments"];
|
||||
std::vector<Attachment> attachments;
|
||||
for (auto [slot, name] : magic_enum::enum_entries<Slot>()) {
|
||||
if (const auto& yaml_attachment = yaml_attachments[std::string {name}]) {
|
||||
attachments.push_back({
|
||||
.slot = slot,
|
||||
.path = nf7::File::Path::Parse(yaml_attachment.as<std::string>()),
|
||||
});
|
||||
}
|
||||
}
|
||||
attachments_ = std::move(attachments);
|
||||
} catch (std::bad_optional_access&) {
|
||||
throw nf7::Exception {std::string {"invalid enum"}};
|
||||
} 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) noexcept
|
||||
try {
|
||||
auto& base = ctx->env().GetFileOrThrow(ctx->initiator());
|
||||
|
||||
std::vector<nf7::gl::Framebuffer::Meta::Attachment> attachments;
|
||||
for (auto& attachment : attachments_) {
|
||||
nf7::File::Id fid = 0;
|
||||
if (attachment.path.terms().size() > 0) {
|
||||
fid = base.ResolveOrThrow(attachment.path).id();
|
||||
}
|
||||
attachments.push_back({
|
||||
.tex = fid,
|
||||
.slot = ToSlot(attachment.slot),
|
||||
});
|
||||
}
|
||||
return Product::Create(ctx, std::move(attachments));
|
||||
} catch (nf7::Exception&) {
|
||||
return {std::current_exception()};
|
||||
}
|
||||
|
||||
bool Handle(const std::shared_ptr<nf7::Node::Lambda>&,
|
||||
const nf7::Mutex::Resource<std::shared_ptr<Product>>&,
|
||||
const nf7::Node::Lambda::Msg&) {
|
||||
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<Attachment> attachments_;
|
||||
|
||||
static GLenum ToSlot(Slot slot) {
|
||||
return
|
||||
slot == Slot::Color0? GL_COLOR_ATTACHMENT0:
|
||||
slot == Slot::Color1? GL_COLOR_ATTACHMENT0+1:
|
||||
slot == Slot::Color2? GL_COLOR_ATTACHMENT0+2:
|
||||
slot == Slot::Color3? GL_COLOR_ATTACHMENT0+3:
|
||||
slot == Slot::Color4? GL_COLOR_ATTACHMENT0+4:
|
||||
slot == Slot::Color5? GL_COLOR_ATTACHMENT0+5:
|
||||
slot == Slot::Color6? GL_COLOR_ATTACHMENT0+6:
|
||||
slot == Slot::Color7? GL_COLOR_ATTACHMENT0+7:
|
||||
throw 0;
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct ObjBase<Framebuffer>::TypeInfo final {
|
||||
static inline const nf7::GenericTypeInfo<ObjBase<Framebuffer>> kType = {"GL/Framebuffer", {"nf7::DirItem"}};
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace nf7
|
||||
|
||||
@ -970,4 +1093,8 @@ NF7_YAS_DEFINE_ENUM_SERIALIZER(nf7::Texture::Comp);
|
||||
|
||||
NF7_YAS_DEFINE_ENUM_SERIALIZER(nf7::Shader::Type);
|
||||
|
||||
NF7_YAS_DEFINE_ENUM_SERIALIZER(nf7::VertexArray::AttrType);
|
||||
|
||||
NF7_YAS_DEFINE_ENUM_SERIALIZER(nf7::Framebuffer::Slot);
|
||||
|
||||
} // namespace yas::detail
|
||||
|
Loading…
x
Reference in New Issue
Block a user