add GL/Buffer
This commit is contained in:
27
common/factory.hh
Normal file
27
common/factory.hh
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
#include "common/future.hh"
|
||||
|
||||
|
||||
namespace nf7 {
|
||||
|
||||
template <typename T>
|
||||
class Factory : public nf7::File::Interface {
|
||||
public:
|
||||
using Product = T;
|
||||
|
||||
Factory() = default;
|
||||
Factory(const Factory&) = delete;
|
||||
Factory(Factory&&) = delete;
|
||||
Factory& operator=(const Factory&) = delete;
|
||||
Factory& operator=(Factory&&) = delete;
|
||||
|
||||
virtual Product Create() noexcept = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using AsyncFactory = Factory<nf7::Future<T>>;
|
||||
|
||||
} // namespace nf7
|
||||
@@ -39,6 +39,7 @@ class Future final {
|
||||
class Promise;
|
||||
class Coro;
|
||||
|
||||
using Product = T;
|
||||
using ThisFuture = nf7::Future<T>;
|
||||
using Handle = std::coroutine_handle<Promise>;
|
||||
using Imm = std::variant<T, std::exception_ptr>;
|
||||
|
||||
46
common/gl_fence.hh
Normal file
46
common/gl_fence.hh
Normal file
@@ -0,0 +1,46 @@
|
||||
#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
|
||||
89
common/gl_obj.hh
Normal file
89
common/gl_obj.hh
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
#include "common/factory.hh"
|
||||
#include "common/future.hh"
|
||||
#include "common/mutex.hh"
|
||||
|
||||
|
||||
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), id_(id? id: T::Gen()), meta_(std::forward<Args>(args)...) {
|
||||
}
|
||||
~Obj() noexcept {
|
||||
ctx_->env().ExecGL(ctx_, [id = id_]() { T::Delete(id); });
|
||||
}
|
||||
Obj(const Obj&) = delete;
|
||||
Obj(Obj&&) = delete;
|
||||
Obj& operator=(const Obj&) = delete;
|
||||
Obj& operator=(Obj&&) = delete;
|
||||
|
||||
GLuint id() const noexcept { return id_; }
|
||||
|
||||
T& meta() noexcept { return meta_; }
|
||||
const T& meta() const noexcept { return meta_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<nf7::Context> ctx_;
|
||||
|
||||
GLuint id_;
|
||||
T meta_;
|
||||
};
|
||||
|
||||
|
||||
struct Obj_BufferMeta final {
|
||||
public:
|
||||
Obj_BufferMeta() = delete;
|
||||
Obj_BufferMeta(GLenum t) noexcept : type(t) {
|
||||
}
|
||||
|
||||
const GLenum type;
|
||||
|
||||
size_t size = 0;
|
||||
uint8_t* ptr = nullptr; // address returned by glMapBuffer or nullptr
|
||||
|
||||
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>>>;
|
||||
|
||||
|
||||
struct Obj_TextureMeta final {
|
||||
public:
|
||||
GLenum type;
|
||||
GLenum format;
|
||||
uint32_t w, h, d;
|
||||
|
||||
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>>>;
|
||||
|
||||
} // namespace nf7::gl
|
||||
@@ -12,7 +12,45 @@ namespace nf7 {
|
||||
template <typename T>
|
||||
class Life final {
|
||||
public:
|
||||
class Ref;
|
||||
struct Data final {
|
||||
std::atomic<T*> ptr;
|
||||
};
|
||||
class Ref final {
|
||||
public:
|
||||
Ref() = default;
|
||||
Ref(const Life& life) noexcept {
|
||||
if (!life.data_) {
|
||||
auto& l = const_cast<Life&>(life);
|
||||
l.data_ = std::make_shared<Data>();
|
||||
l.data_->ptr = l.ptr_;
|
||||
}
|
||||
data_ = life.data_;
|
||||
}
|
||||
Ref(const Ref&) = default;
|
||||
Ref(Ref&&) = default;
|
||||
Ref& operator=(const Ref&) = default;
|
||||
Ref& operator=(Ref&&) = default;
|
||||
|
||||
void EnforceAlive() const {
|
||||
if (!data_->ptr) {
|
||||
throw nf7::ExpiredException {"target expired"};
|
||||
}
|
||||
}
|
||||
|
||||
operator bool() const noexcept {
|
||||
return !!data_->ptr;
|
||||
}
|
||||
T& operator*() const noexcept {
|
||||
assert(data_->ptr);
|
||||
return *data_->ptr;
|
||||
}
|
||||
T* operator->() const noexcept {
|
||||
return &**this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Data> data_;
|
||||
};
|
||||
|
||||
Life() = delete;
|
||||
Life(T& target) noexcept : ptr_(&target) {
|
||||
@@ -25,52 +63,14 @@ class Life final {
|
||||
Life& operator=(const Life&) = delete;
|
||||
Life& operator=(Life&&) = delete;
|
||||
|
||||
Ref ref() const noexcept { return *this; }
|
||||
|
||||
private:
|
||||
T* const ptr_;
|
||||
|
||||
struct Data final {
|
||||
std::atomic<T*> ptr;
|
||||
};
|
||||
std::shared_ptr<Data> data_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Life<T>::Ref final {
|
||||
public:
|
||||
Ref() = default;
|
||||
Ref(const Life& life) noexcept {
|
||||
if (!life.data_) {
|
||||
auto& l = const_cast<Life&>(life);
|
||||
l.data_ = std::make_shared<Data>();
|
||||
l.data_->ptr = l.ptr_;
|
||||
}
|
||||
data_ = life.data_;
|
||||
}
|
||||
Ref(const Ref&) = default;
|
||||
Ref(Ref&&) = default;
|
||||
Ref& operator=(const Ref&) = default;
|
||||
Ref& operator=(Ref&&) = default;
|
||||
|
||||
void EnforceAlive() const {
|
||||
if (!data_->ptr) {
|
||||
throw nf7::ExpiredException {"target expired"};
|
||||
}
|
||||
}
|
||||
|
||||
operator bool() const noexcept {
|
||||
return !!data_->ptr;
|
||||
}
|
||||
T& operator*() const noexcept {
|
||||
assert(data_->ptr);
|
||||
return *data_->ptr;
|
||||
}
|
||||
T* operator->() const noexcept {
|
||||
return &**this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Data> data_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace nf7
|
||||
|
||||
Reference in New Issue
Block a user