separate initialization codes of GL objects
This commit is contained in:
parent
0a55250f52
commit
96fd71df07
@ -308,8 +308,10 @@ class Future final {
|
||||
}
|
||||
|
||||
// Finalizes the other promise on finalize of this future.
|
||||
ThisFuture& Chain(auto& pro, auto&& func) noexcept {
|
||||
return Then([pro, func = std::move(func)](auto& fu) mutable {
|
||||
ThisFuture& Chain(nf7::Env::Executor exec,
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
auto& pro, auto&& func) noexcept {
|
||||
return Then(exec, ctx, [pro, func = std::move(func)](auto& fu) mutable {
|
||||
try {
|
||||
pro.Return(func(fu.value()));
|
||||
} catch (...) {
|
||||
@ -317,6 +319,12 @@ class Future final {
|
||||
}
|
||||
});
|
||||
}
|
||||
ThisFuture& Chain(const std::shared_ptr<nf7::Context>& ctx, auto& pro, auto&& func) noexcept {
|
||||
return Chain(nf7::Env::kSub, ctx, pro, std::move(func));
|
||||
}
|
||||
ThisFuture& Chain(auto& pro, auto&& func) noexcept {
|
||||
return Chain(nullptr, pro, std::move(func));
|
||||
}
|
||||
|
||||
const auto& value() const {
|
||||
if (imm_) {
|
||||
|
198
common/gl_obj.cc
198
common/gl_obj.cc
@ -12,18 +12,194 @@
|
||||
|
||||
namespace nf7::gl {
|
||||
|
||||
nf7::Future<std::vector<std::shared_ptr<nf7::Mutex::Lock>>>
|
||||
Obj_VertexArrayMeta::LockBuffers(
|
||||
const std::shared_ptr<nf7::Context>& ctx, size_t vcnt, size_t icnt) const noexcept
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_BufferMeta>>> Obj_BufferMeta::Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx, GLenum type) noexcept {
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_BufferMeta>>>::Promise pro {ctx};
|
||||
ctx->env().ExecGL(ctx, [ctx, type, pro]() mutable {
|
||||
GLuint id;
|
||||
glGenBuffers(1, &id);
|
||||
pro.Return(std::make_shared<Obj<Obj_BufferMeta>>(ctx, id, type));
|
||||
});
|
||||
return pro.future();
|
||||
}
|
||||
|
||||
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_TextureMeta>>> Obj_TextureMeta::Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx, GLenum type) noexcept {
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_TextureMeta>>>::Promise pro {ctx};
|
||||
ctx->env().ExecGL(ctx, [ctx, type, pro]() mutable {
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
pro.Return(std::make_shared<Obj<Obj_TextureMeta>>(ctx, id, type));
|
||||
});
|
||||
return pro.future();
|
||||
}
|
||||
|
||||
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_ShaderMeta>>> Obj_ShaderMeta::Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
GLenum type,
|
||||
const std::string& src) noexcept {
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_ShaderMeta>>>::Promise pro {ctx};
|
||||
ctx->env().ExecGL(ctx, [ctx, type, src, pro]() mutable {
|
||||
const auto id = glCreateShader(type);
|
||||
if (id == 0) {
|
||||
pro.Throw<nf7::Exception>("failed to allocate new shader");
|
||||
return;
|
||||
}
|
||||
|
||||
const GLchar* str = src.c_str();
|
||||
glShaderSource(id, 1, &str, nullptr);
|
||||
glCompileShader(id);
|
||||
assert(0 == glGetError());
|
||||
|
||||
GLint status;
|
||||
glGetShaderiv(id, GL_COMPILE_STATUS, &status);
|
||||
if (status == GL_TRUE) {
|
||||
pro.Return(std::make_shared<Obj<Obj_ShaderMeta>>(ctx, id, type));
|
||||
} else {
|
||||
GLint len;
|
||||
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &len);
|
||||
|
||||
std::string ret(static_cast<size_t>(len), ' ');
|
||||
glGetShaderInfoLog(id, len, nullptr, ret.data());
|
||||
|
||||
pro.Throw<nf7::Exception>(std::move(ret));
|
||||
}
|
||||
});
|
||||
return pro.future();
|
||||
}
|
||||
|
||||
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_ProgramMeta>>> Obj_ProgramMeta::Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
const std::vector<nf7::File::Id>& shaders) noexcept {
|
||||
nf7::AggregatePromise apro {ctx};
|
||||
std::vector<nf7::Future<nf7::Mutex::Resource<std::shared_ptr<gl::Shader>>>> shs;
|
||||
for (auto shader : shaders) {
|
||||
shs.emplace_back(ctx->env().GetFileOrThrow(shader).
|
||||
interfaceOrThrow<nf7::gl::ShaderFactory>().Create());
|
||||
apro.Add(shs.back());
|
||||
}
|
||||
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_ProgramMeta>>>::Promise pro {ctx};
|
||||
apro.future().Chain(nf7::Env::kGL, ctx, pro, [ctx, shs = std::move(shs)](auto&) {
|
||||
// check all shaders
|
||||
for (auto& sh : shs) { sh.value(); }
|
||||
|
||||
// create program
|
||||
const auto id = glCreateProgram();
|
||||
if (id == 0) {
|
||||
throw nf7::Exception {"failed to allocate new program"};
|
||||
}
|
||||
|
||||
// attach shaders
|
||||
for (auto& sh : shs) {
|
||||
glAttachShader(id, (*sh.value())->id());
|
||||
}
|
||||
glLinkProgram(id);
|
||||
|
||||
// check status
|
||||
GLint status;
|
||||
glGetProgramiv(id, GL_LINK_STATUS, &status);
|
||||
if (status == GL_TRUE) {
|
||||
return std::make_shared<Obj<Obj_ProgramMeta>>(ctx, id);
|
||||
} else {
|
||||
GLint len;
|
||||
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &len);
|
||||
|
||||
std::string ret(static_cast<size_t>(len), ' ');
|
||||
glGetProgramInfoLog(id, len, nullptr, ret.data());
|
||||
throw nf7::Exception {std::move(ret)};
|
||||
}
|
||||
});
|
||||
return pro.future();
|
||||
}
|
||||
|
||||
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_VertexArrayMeta>>> Obj_VertexArrayMeta::Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx, std::vector<Attr>&& attrs) noexcept
|
||||
try {
|
||||
nf7::Future<std::shared_ptr<Obj<Obj_VertexArrayMeta>>>::Promise pro {ctx};
|
||||
LockBuffers(ctx, attrs).Chain(
|
||||
nf7::Env::kGL, ctx, pro,
|
||||
[ctx, attrs = std::move(attrs), pro](auto& bufs) mutable {
|
||||
// check all buffers
|
||||
assert(attrs.size() == bufs.size());
|
||||
for (auto& buf : bufs) {
|
||||
if ((*buf.value()).meta().type != GL_ARRAY_BUFFER) {
|
||||
throw nf7::Exception {"buffer is not Array"};
|
||||
}
|
||||
}
|
||||
|
||||
GLuint id;
|
||||
glGenVertexArrays(1, &id);
|
||||
glBindVertexArray(id);
|
||||
for (size_t i = 0; i < attrs.size(); ++i) {
|
||||
const auto& attr = attrs[i];
|
||||
const auto& buf = *bufs[i].value();
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buf.id());
|
||||
glEnableVertexAttribArray(attr.index);
|
||||
glVertexAttribDivisor(attr.index, attr.divisor);
|
||||
glVertexAttribPointer(
|
||||
attr.index,
|
||||
attr.size,
|
||||
attr.type,
|
||||
attr.normalize,
|
||||
attr.stride,
|
||||
reinterpret_cast<GLvoid*>(static_cast<GLintptr>(attr.offset)));
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
assert(0 == glGetError());
|
||||
|
||||
return std::make_shared<Obj<Obj_VertexArrayMeta>>(ctx, id, std::move(attrs));
|
||||
});
|
||||
return pro.future();
|
||||
} catch (nf7::Exception&) {
|
||||
return {std::current_exception()};
|
||||
}
|
||||
|
||||
nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Buffer>>>> Obj_VertexArrayMeta::LockBuffers(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
const std::vector<Attr>& attrs,
|
||||
size_t vcnt, size_t icnt) noexcept
|
||||
try {
|
||||
std::vector<nf7::gl::BufferFactory::Product> fus;
|
||||
|
||||
nf7::AggregatePromise lock_pro {ctx};
|
||||
nf7::AggregatePromise apro {ctx};
|
||||
for (const auto& attr : attrs) {
|
||||
auto& f = ctx->env().GetFileOrThrow(attr.id);
|
||||
nf7::File& f = ctx->env().GetFileOrThrow(attr.buffer);
|
||||
|
||||
// calculate size required to the buffer
|
||||
const auto required = std::max(attr.size_per_vertex*vcnt, attr.size_per_instance*icnt);
|
||||
size_t required = 0;
|
||||
if (attr.divisor == 0 && vcnt > 0) {
|
||||
required = static_cast<size_t>(attr.size)*vcnt;
|
||||
switch (attr.type) {
|
||||
case GL_UNSIGNED_BYTE:
|
||||
case GL_BYTE:
|
||||
required *= 1;
|
||||
break;
|
||||
case GL_UNSIGNED_SHORT:
|
||||
case GL_SHORT:
|
||||
case GL_HALF_FLOAT:
|
||||
required *= 2;
|
||||
break;
|
||||
case GL_UNSIGNED_INT:
|
||||
case GL_INT:
|
||||
case GL_FLOAT:
|
||||
required *= 4;
|
||||
break;
|
||||
case GL_DOUBLE:
|
||||
required *= 8;
|
||||
break;
|
||||
default:
|
||||
throw nf7::Exception {"unknown attribute type"};
|
||||
}
|
||||
} else if (attr.divisor > 0 && icnt > 0) {
|
||||
required = static_cast<size_t>(attr.stride)*(icnt-1) + attr.offset;
|
||||
}
|
||||
|
||||
// validation after the lock
|
||||
nf7::Future<nf7::Mutex::Resource<std::shared_ptr<nf7::gl::Buffer>>>::Promise pro {ctx};
|
||||
@ -36,16 +212,16 @@ try {
|
||||
});
|
||||
|
||||
// register a future of the validation
|
||||
lock_pro.Add(pro.future());
|
||||
apro.Add(pro.future());
|
||||
fus.emplace_back(pro.future());
|
||||
}
|
||||
|
||||
// wait for all registered futures
|
||||
nf7::Future<std::vector<std::shared_ptr<nf7::Mutex::Lock>>>::Promise pro {ctx};
|
||||
lock_pro.future().Chain(pro, [fus = std::move(fus)](auto&) {
|
||||
std::vector<std::shared_ptr<nf7::Mutex::Lock>> ret;
|
||||
nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Buffer>>>>::Promise pro {ctx};
|
||||
apro.future().Chain(pro, [fus = std::move(fus)](auto&) {
|
||||
std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Buffer>>> ret;
|
||||
for (auto& fu : fus) {
|
||||
ret.emplace_back(fu.value().lock());
|
||||
ret.emplace_back(fu.value());
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
|
105
common/gl_obj.hh
105
common/gl_obj.hh
@ -21,9 +21,15 @@ class Obj final {
|
||||
public:
|
||||
using Meta = T;
|
||||
|
||||
// NOT thread-safe
|
||||
template <typename... Args>
|
||||
static nf7::Future<std::shared_ptr<Obj<T>>> Create(Args&&... args) noexcept {
|
||||
return Meta::Create(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
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()) {
|
||||
ctx_(ctx), meta_(std::forward<Args>(args)...), id_(id) {
|
||||
}
|
||||
~Obj() noexcept {
|
||||
ctx_->env().ExecGL(ctx_, [id = id_]() { T::Delete(id); });
|
||||
@ -48,6 +54,13 @@ class Obj final {
|
||||
|
||||
struct Obj_BufferMeta final {
|
||||
public:
|
||||
static nf7::Future<std::shared_ptr<Obj<Obj_BufferMeta>>> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx, GLenum type) noexcept;
|
||||
|
||||
static void Delete(GLuint id) noexcept {
|
||||
glDeleteBuffers(1, &id);
|
||||
}
|
||||
|
||||
Obj_BufferMeta() = delete;
|
||||
Obj_BufferMeta(GLenum t) noexcept : type(t) {
|
||||
}
|
||||
@ -55,15 +68,6 @@ struct Obj_BufferMeta final {
|
||||
const GLenum type;
|
||||
|
||||
size_t size = 0;
|
||||
|
||||
static GLuint Gen() noexcept {
|
||||
GLuint id;
|
||||
glGenBuffers(1, &id);
|
||||
return id;
|
||||
}
|
||||
static void Delete(GLuint id) noexcept {
|
||||
glDeleteBuffers(1, &id);
|
||||
}
|
||||
};
|
||||
using Buffer = Obj<Obj_BufferMeta>;
|
||||
using BufferFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Buffer>>>;
|
||||
@ -71,6 +75,13 @@ using BufferFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Buffer>>
|
||||
|
||||
struct Obj_TextureMeta final {
|
||||
public:
|
||||
static nf7::Future<std::shared_ptr<Obj<Obj_TextureMeta>>> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx, GLenum type) noexcept;
|
||||
|
||||
static void Delete(GLuint id) noexcept {
|
||||
glDeleteTextures(1, &id);
|
||||
}
|
||||
|
||||
Obj_TextureMeta() = delete;
|
||||
Obj_TextureMeta(GLenum t) noexcept : type(t) {
|
||||
}
|
||||
@ -79,15 +90,6 @@ struct Obj_TextureMeta final {
|
||||
|
||||
GLint format = 0;
|
||||
uint32_t w = 0, h = 0, d = 0;
|
||||
|
||||
static GLuint Gen() noexcept {
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
return id;
|
||||
}
|
||||
static void Delete(GLuint id) noexcept {
|
||||
glDeleteTextures(1, &id);
|
||||
}
|
||||
};
|
||||
using Texture = Obj<Obj_TextureMeta>;
|
||||
using TextureFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Texture>>>;
|
||||
@ -95,18 +97,20 @@ using TextureFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Texture
|
||||
|
||||
struct Obj_ShaderMeta final {
|
||||
public:
|
||||
static nf7::Future<std::shared_ptr<Obj<Obj_ShaderMeta>>> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
GLenum type,
|
||||
const std::string& src) noexcept;
|
||||
|
||||
static void Delete(GLuint id) noexcept {
|
||||
glDeleteShader(id);
|
||||
}
|
||||
|
||||
Obj_ShaderMeta() = delete;
|
||||
Obj_ShaderMeta(GLenum t) noexcept : type(t) {
|
||||
}
|
||||
|
||||
const GLenum type;
|
||||
|
||||
GLuint Gen() noexcept {
|
||||
return glCreateShader(type);
|
||||
}
|
||||
static void Delete(GLuint id) noexcept {
|
||||
glDeleteShader(id);
|
||||
}
|
||||
};
|
||||
using Shader = Obj<Obj_ShaderMeta>;
|
||||
using ShaderFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Shader>>>;
|
||||
@ -114,14 +118,15 @@ using ShaderFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Shader>>
|
||||
|
||||
struct Obj_ProgramMeta final {
|
||||
public:
|
||||
Obj_ProgramMeta() = default;
|
||||
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;
|
||||
|
||||
GLuint Gen() noexcept {
|
||||
return glCreateProgram();
|
||||
}
|
||||
static void Delete(GLuint id) noexcept {
|
||||
glDeleteProgram(id);
|
||||
}
|
||||
|
||||
Obj_ProgramMeta() = default;
|
||||
};
|
||||
using Program = Obj<Obj_ProgramMeta>;
|
||||
using ProgramFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Program>>>;
|
||||
@ -130,26 +135,38 @@ using ProgramFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Program
|
||||
struct Obj_VertexArrayMeta final {
|
||||
public:
|
||||
struct Attr {
|
||||
nf7::File::Id id = 0;
|
||||
size_t size_per_vertex = 0;
|
||||
size_t size_per_instance = 0;
|
||||
nf7::File::Id buffer;
|
||||
GLuint index;
|
||||
GLint size;
|
||||
GLenum type;
|
||||
bool normalize;
|
||||
GLsizei stride;
|
||||
uint64_t offset;
|
||||
GLuint divisor;
|
||||
};
|
||||
Obj_VertexArrayMeta(std::vector<Attr>&& a) noexcept : attrs(std::move(a)) {
|
||||
}
|
||||
|
||||
const std::vector<Attr> attrs;
|
||||
static nf7::Future<std::shared_ptr<Obj<Obj_VertexArrayMeta>>> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx, std::vector<Attr>&& attrs) noexcept;
|
||||
|
||||
nf7::Future<std::vector<std::shared_ptr<nf7::Mutex::Lock>>> LockBuffers(
|
||||
const std::shared_ptr<nf7::Context>& ctx, size_t vcnt, size_t icnt) const noexcept;
|
||||
|
||||
static GLuint Gen() noexcept {
|
||||
GLuint id;
|
||||
glGenVertexArrays(1, &id);
|
||||
return id;
|
||||
}
|
||||
static void Delete(GLuint id) noexcept {
|
||||
glDeleteVertexArrays(1, &id);
|
||||
}
|
||||
|
||||
static nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Buffer>>>>
|
||||
LockBuffers(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
const std::vector<Attr>& attrs,
|
||||
size_t vcnt = 0, size_t icnt = 0) noexcept;
|
||||
|
||||
Obj_VertexArrayMeta(std::vector<Attr>&& a) noexcept : attrs(std::move(a)) {
|
||||
}
|
||||
|
||||
nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Buffer>>>> LockBuffers(
|
||||
const std::shared_ptr<nf7::Context>& ctx, size_t vcnt = 0, size_t icnt = 0) const noexcept {
|
||||
return LockBuffers(ctx, attrs, vcnt, icnt);
|
||||
}
|
||||
|
||||
const std::vector<Attr> attrs;
|
||||
};
|
||||
using VertexArray = Obj<Obj_VertexArrayMeta>;
|
||||
using VertexArrayFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<VertexArray>>>;
|
||||
|
201
file/gl_obj.cc
201
file/gl_obj.cc
@ -102,7 +102,7 @@ class ObjBase : public nf7::FileBase,
|
||||
mtx_.AcquireLock(ctx, ex).ThenIf([this, ctx, pro](auto& k) mutable {
|
||||
if (!fu_) {
|
||||
watcher_.emplace(env());
|
||||
fu_ = mem_->Create(ctx, *watcher_);
|
||||
fu_ = mem_->Create(ctx);
|
||||
watcher_->AddHandler(nf7::File::Event::kUpdate, [this](auto&) { Drop(); });
|
||||
}
|
||||
fu_->Chain(pro, [k](auto& obj) { return Resource {k, obj}; });
|
||||
@ -282,13 +282,8 @@ struct Buffer {
|
||||
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 {
|
||||
nf7::Future<std::shared_ptr<Product>>::Promise pro {ctx};
|
||||
ctx->env().ExecGL(ctx, [ctx, pro, t = type_]() mutable {
|
||||
pro.Return(std::make_shared<Product>(ctx, GLuint {0}, FromType(t)));
|
||||
});
|
||||
return pro.future();
|
||||
nf7::Future<std::shared_ptr<Product>> Create(const std::shared_ptr<nf7::Context>& ctx) noexcept {
|
||||
return Product::Create(ctx, FromType(type_));
|
||||
}
|
||||
|
||||
bool Handle(const std::shared_ptr<nf7::Node::Lambda>& handler,
|
||||
@ -433,13 +428,8 @@ struct Texture {
|
||||
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 {
|
||||
nf7::Future<std::shared_ptr<Product>>::Promise pro {ctx};
|
||||
ctx->env().ExecGL(ctx, [ctx, pro, t = type_]() mutable {
|
||||
pro.Return(std::make_shared<Product>(ctx, GLuint {0}, FromType(t)));
|
||||
});
|
||||
return pro.future();
|
||||
nf7::Future<std::shared_ptr<Product>> Create(const std::shared_ptr<nf7::Context>& ctx) noexcept {
|
||||
return Product::Create(ctx, FromType(type_));
|
||||
}
|
||||
|
||||
bool Handle(const std::shared_ptr<nf7::Node::Lambda>& handler,
|
||||
@ -633,32 +623,9 @@ struct Shader {
|
||||
}
|
||||
|
||||
nf7::Future<std::shared_ptr<Product>> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx, nf7::Env::Watcher&) noexcept {
|
||||
const std::shared_ptr<nf7::Context>& ctx) noexcept {
|
||||
// TODO: preprocessing GLSL source
|
||||
|
||||
nf7::Future<std::shared_ptr<Product>>::Promise pro {ctx};
|
||||
ctx->env().ExecGL(ctx, [ctx, pro, type = type_, src = src_]() mutable {
|
||||
auto sh = std::make_shared<Product>(ctx, GLuint {0}, FromType(type));
|
||||
const GLchar* str = src.c_str();
|
||||
glShaderSource(sh->id(), 1, &str, nullptr);
|
||||
glCompileShader(sh->id());
|
||||
assert(0 == glGetError());
|
||||
|
||||
GLint status;
|
||||
glGetShaderiv(sh->id(), GL_COMPILE_STATUS, &status);
|
||||
if (status == GL_TRUE) {
|
||||
pro.Return(sh);
|
||||
} else {
|
||||
GLint len;
|
||||
glGetShaderiv(sh->id(), GL_INFO_LOG_LENGTH, &len);
|
||||
|
||||
std::string ret(static_cast<size_t>(len), ' ');
|
||||
glGetShaderInfoLog(sh->id(), len, nullptr, ret.data());
|
||||
|
||||
pro.Throw<nf7::Exception>(std::move(ret));
|
||||
}
|
||||
});
|
||||
return pro.future();
|
||||
return Product::Create(ctx, FromType(type_), src_);
|
||||
}
|
||||
|
||||
bool Handle(const std::shared_ptr<nf7::Node::Lambda>&,
|
||||
@ -747,61 +714,18 @@ struct Program {
|
||||
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
|
||||
nf7::Future<std::shared_ptr<Product>> Create(const std::shared_ptr<nf7::Context>& ctx) noexcept
|
||||
try {
|
||||
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());
|
||||
// TODO: setup watcher
|
||||
std::vector<nf7::File::Id> shaders;
|
||||
for (const auto& path : shaders_) {
|
||||
shaders.push_back(base.ResolveOrThrow(path).id());
|
||||
}
|
||||
|
||||
nf7::Future<std::shared_ptr<Product>>::Promise pro {ctx};
|
||||
sh_pro.future().Then(nf7::Env::kGL, ctx, [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();
|
||||
return Product::Create(ctx, shaders);
|
||||
} catch (nf7::Exception&) {
|
||||
return {std::current_exception()};
|
||||
}
|
||||
static std::shared_ptr<nf7::gl::Program> Link(
|
||||
const std::shared_ptr<nf7::Context>& ctx,
|
||||
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>>&,
|
||||
@ -961,94 +885,27 @@ struct VertexArray {
|
||||
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
|
||||
nf7::Future<std::shared_ptr<Product>> Create(const std::shared_ptr<nf7::Context>& ctx) noexcept
|
||||
try {
|
||||
auto& base = ctx->env().GetFileOrThrow(ctx->initiator());
|
||||
auto attrs = attrs_; // copy it
|
||||
auto& base = ctx->env().GetFileOrThrow(ctx->initiator());
|
||||
|
||||
nf7::AggregatePromise buf_pro {ctx};
|
||||
std::vector<
|
||||
std::pair<
|
||||
nf7::File::Id,
|
||||
nf7::Future<
|
||||
nf7::Mutex::Resource<
|
||||
std::shared_ptr<nf7::gl::Buffer>>>>> bufs;
|
||||
for (auto& attr : attrs) {
|
||||
auto& f = base.ResolveOrThrow(attr.buffer);
|
||||
auto fu = f.interfaceOrThrow<nf7::gl::BufferFactory>().Create();
|
||||
bufs.emplace_back(f.id(), fu);
|
||||
buf_pro.Add(fu);
|
||||
// TODO: setup watcher
|
||||
}
|
||||
|
||||
nf7::Future<std::shared_ptr<Product>>::Promise pro {ctx};
|
||||
buf_pro.future().Then(
|
||||
nf7::Env::kGL, ctx,
|
||||
[ctx, pro, attrs = std::move(attrs), bufs = std::move(bufs)](auto&) mutable {
|
||||
pro.Wrap([&]() { return Create(ctx, attrs, bufs); });
|
||||
});
|
||||
return pro.future();
|
||||
} catch (nf7::Exception&) {
|
||||
return {std::current_exception()};
|
||||
}
|
||||
static std::shared_ptr<nf7::gl::VertexArray> Create(
|
||||
const std::shared_ptr<nf7::Context>& ctx, auto& attrs, auto& bufs) {
|
||||
assert(attrs.size() == bufs.size());
|
||||
|
||||
std::vector<GLuint> bufids;
|
||||
bufids.reserve(attrs.size());
|
||||
|
||||
// build metadata of new VAO
|
||||
std::vector<nf7::gl::VertexArray::Meta::Attr> meta_attrs;
|
||||
meta_attrs.reserve(attrs.size());
|
||||
for (size_t i = 0; i < attrs.size(); ++i) {
|
||||
const auto& attr = attrs[i];
|
||||
const auto& buf = **bufs[i].second.value();
|
||||
bufids.push_back(buf.id());
|
||||
|
||||
// check buffer type
|
||||
if (buf.meta().type != GL_ARRAY_BUFFER) {
|
||||
throw nf7::Exception {
|
||||
"buffer ("+std::to_string(i)+") is not GL_ARRAY_BUFFER"
|
||||
};
|
||||
}
|
||||
|
||||
// calculate meta data
|
||||
const auto size = attr.size*(magic_enum::enum_integer(attr.type) & 0xF);
|
||||
const auto stride = attr.stride?
|
||||
static_cast<size_t>(attr.stride):
|
||||
static_cast<size_t>(size);
|
||||
meta_attrs.push_back({
|
||||
.id = bufs[i].first,
|
||||
.size_per_vertex = attr.divisor == 0? stride: 0,
|
||||
.size_per_instance = attr.divisor >= 1? stride: 0,
|
||||
std::vector<Product::Meta::Attr> attrs;
|
||||
attrs.reserve(attrs_.size());
|
||||
for (auto& attr : attrs_) {
|
||||
attrs.push_back({
|
||||
.buffer = base.ResolveOrThrow(attr.buffer).id(),
|
||||
.index = attr.index,
|
||||
.size = attr.size,
|
||||
.type = ToAttrType(attr.type),
|
||||
.normalize = attr.normalize,
|
||||
.stride = attr.stride,
|
||||
.offset = attr.offset,
|
||||
.divisor = attr.divisor,
|
||||
});
|
||||
}
|
||||
|
||||
// setup VAO
|
||||
auto vao = std::make_shared<nf7::gl::VertexArray>(ctx, GLuint {0}, std::move(meta_attrs));
|
||||
glBindVertexArray(vao->id());
|
||||
for (size_t i = 0; i < attrs.size(); ++i) {
|
||||
const auto& attr = attrs[i];
|
||||
|
||||
// attach buffer
|
||||
glBindBuffer(GL_ARRAY_BUFFER, bufids[i]);
|
||||
glEnableVertexAttribArray(attr.index);
|
||||
glVertexAttribDivisor(attr.index, attr.divisor);
|
||||
glVertexAttribPointer(
|
||||
attr.index,
|
||||
attr.size,
|
||||
ToAttrType(attr.type),
|
||||
attr.normalize,
|
||||
attr.stride,
|
||||
reinterpret_cast<GLvoid*>(static_cast<GLintptr>(attr.offset)));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
glBindVertexArray(0);
|
||||
|
||||
assert(0 == glGetError());
|
||||
return vao;
|
||||
return Product::Create(ctx, std::move(attrs));
|
||||
} catch (nf7::Exception&) {
|
||||
return {std::current_exception()};
|
||||
}
|
||||
|
||||
bool Handle(const std::shared_ptr<nf7::Node::Lambda>&,
|
||||
|
Loading…
x
Reference in New Issue
Block a user