support depth/stencil buffer

This commit is contained in:
falsycat 2022-10-29 11:09:24 +09:00
parent 9fc39b986a
commit fa1a29c325
4 changed files with 169 additions and 66 deletions

View File

@ -2,6 +2,7 @@
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <unordered_map>
#include <GL/glew.h>
@ -85,6 +86,102 @@ inline uint8_t GetCompCount(ColorComp c) noexcept {
}
enum class InternalFormat : uint8_t {
R8 = 0x01,
RG8 = 0x02,
RGB8 = 0x03,
RGBA8 = 0x04,
RF32 = 0x11,
RGF32 = 0x12,
RGBF32 = 0x13,
RGBAF32 = 0x14,
Depth16 = 0x21,
Depth24 = 0x31,
DepthF32 = 0x41,
Depth24_Stencil8 = 0x22,
DepthF32_Stencil8 = 0x32,
};
template <>
struct EnumMeta<InternalFormat> {
static inline const std::unordered_map<InternalFormat, GLenum> glmap = {
{InternalFormat::R8, GL_R8},
{InternalFormat::RG8, GL_RG8},
{InternalFormat::RGB8, GL_RGB8},
{InternalFormat::RGBA8, GL_RGBA8},
{InternalFormat::RF32, GL_R32F},
{InternalFormat::RGF32, GL_RG32F},
{InternalFormat::RGBF32, GL_RGB32F},
{InternalFormat::RGBAF32, GL_RGBA32F},
{InternalFormat::Depth16, GL_DEPTH_COMPONENT16},
{InternalFormat::Depth24, GL_DEPTH_COMPONENT24},
{InternalFormat::DepthF32, GL_DEPTH_COMPONENT32F},
{InternalFormat::Depth24_Stencil8, GL_DEPTH24_STENCIL8},
{InternalFormat::DepthF32_Stencil8, GL_DEPTH32F_STENCIL8},
};
};
inline uint8_t GetByteSize(InternalFormat fmt) noexcept {
switch (fmt) {
case InternalFormat::R8: return 1;
case InternalFormat::RG8: return 2;
case InternalFormat::RGB8: return 3;
case InternalFormat::RGBA8: return 4;
case InternalFormat::RF32: return 4;
case InternalFormat::RGF32: return 8;
case InternalFormat::RGBF32: return 12;
case InternalFormat::RGBAF32: return 16;
case InternalFormat::Depth16: return 2;
case InternalFormat::Depth24: return 3;
case InternalFormat::DepthF32: return 4;
case InternalFormat::Depth24_Stencil8: return 4;
case InternalFormat::DepthF32_Stencil8: return 5;
}
std::abort();
}
inline ColorComp GetColorComp(InternalFormat fmt) {
switch (fmt) {
case InternalFormat::R8: return ColorComp::R;
case InternalFormat::RG8: return ColorComp::RG;
case InternalFormat::RGB8: return ColorComp::RGB;
case InternalFormat::RGBA8: return ColorComp::RGBA;
case InternalFormat::RF32: return ColorComp::R;
case InternalFormat::RGF32: return ColorComp::RG;
case InternalFormat::RGBF32: return ColorComp::RGB;
case InternalFormat::RGBAF32: return ColorComp::RGBA;
default: throw nf7::Exception {"does not have color component"};
}
}
inline NumericType GetNumericType(InternalFormat fmt) {
switch (fmt) {
case InternalFormat::R8:
case InternalFormat::RG8:
case InternalFormat::RGB8:
case InternalFormat::RGBA8:
return NumericType::U8;
case InternalFormat::RF32:
case InternalFormat::RGF32:
case InternalFormat::RGBF32:
case InternalFormat::RGBAF32:
return NumericType::F32;
default:
throw nf7::Exception {"does not have color component"};
}
}
inline bool IsColor(InternalFormat fmt) noexcept {
return (magic_enum::enum_integer(fmt) & 0xF0) <= 1;
}
inline bool HasDepth(InternalFormat fmt) noexcept {
return !IsColor(fmt);
}
inline bool HasStencil(InternalFormat fmt) noexcept {
return
fmt == InternalFormat::Depth24_Stencil8 ||
fmt == InternalFormat::DepthF32_Stencil8;
}
enum class BufferTarget {
Array,
ElementArray,
@ -138,31 +235,6 @@ struct EnumMeta<TextureTarget> {
inline uint8_t GetDimension(TextureTarget t) noexcept {
return magic_enum::enum_integer(t) & 0xF;
}
inline GLenum ToInternalFormat(NumericType n, ColorComp c) {
GLenum ret = 0;
switch (n) {
case NumericType::U8:
ret =
c == ColorComp::R? GL_R8:
c == ColorComp::RG? GL_RG8:
c == ColorComp::RGB? GL_RGB8:
c == ColorComp::RGBA? GL_RGBA8: 0;
break;
case NumericType::F32:
ret =
c == ColorComp::R? GL_R32F:
c == ColorComp::RG? GL_RG32F:
c == ColorComp::RGB? GL_RGB32F:
c == ColorComp::RGBA? GL_RGBA32F: 0;
break;
default:
break;
}
if (ret == 0) {
throw nf7::Exception {"invalid numtype and comp pair"};
}
return ret;
}
enum class ShaderType {

View File

@ -81,16 +81,20 @@ nf7::Future<std::shared_ptr<Obj<Obj_TextureMeta>>> Obj_TextureMeta::Create(
glTexParameteri(t, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(t, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(t, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
const auto ifmt = static_cast<GLint>(gl::ToEnum(format));
const GLenum fmt = gl::IsColor(format)? GL_RED: GL_DEPTH_COMPONENT;
switch (gl::GetDimension(target)) {
case 2:
glTexImage2D(t, 0, format, size[0], size[1], 0,
GL_RED, GL_UNSIGNED_BYTE, nullptr);
glTexImage2D(t, 0, ifmt, size[0], size[1], 0,
fmt, GL_UNSIGNED_BYTE, nullptr);
break;
default:
assert(false && "unknown texture target");
break;
}
glBindTexture(t, 0);
assert(0 == glGetError());
pro.Return(std::make_shared<Obj<Obj_TextureMeta>>(ctx, id, *this));
});

View File

@ -83,7 +83,7 @@ struct Obj_TextureMeta final {
const std::shared_ptr<nf7::Context>& ctx) const noexcept;
gl::TextureTarget target;
GLint format;
gl::InternalFormat format;
std::array<GLsizei, 3> size;
};
using Texture = Obj<Obj_TextureMeta>;

View File

@ -397,7 +397,7 @@ struct Texture {
Texture& operator=(Texture&&) = default;
void serialize(auto& ar) {
ar(target_, numtype_, comp_, size_);
ar(target_, ifmt_, size_);
}
std::string Stringify() noexcept {
@ -405,10 +405,8 @@ struct Texture {
st << YAML::BeginMap;
st << YAML::Key << "target";
st << YAML::Value << std::string {magic_enum::enum_name(target_)};
st << YAML::Key << "numtype";
st << YAML::Value << std::string {magic_enum::enum_name(numtype_)};
st << YAML::Key << "comp";
st << YAML::Value << std::string {magic_enum::enum_name(comp_)};
st << YAML::Key << "ifmt";
st << YAML::Value << std::string {magic_enum::enum_name(ifmt_)};
st << YAML::Key << "size";
st << YAML::Value << YAML::Flow;
st << YAML::BeginSeq;
@ -426,10 +424,8 @@ struct Texture {
const auto target = magic_enum::
enum_cast<gl::TextureTarget>(yaml["target"].as<std::string>()).value();
const auto numtype = magic_enum::
enum_cast<gl::NumericType>(yaml["numtype"].as<std::string>()).value();
const auto comp = magic_enum::
enum_cast<gl::ColorComp>(yaml["comp"].as<std::string>()).value();
const auto ifmt = magic_enum::
enum_cast<gl::InternalFormat>(yaml["ifmt"].as<std::string>()).value();
const auto size = yaml["size"].as<std::vector<uint32_t>>();
const auto dim = gl::GetDimension(target);
@ -439,8 +435,7 @@ struct Texture {
}
target_ = target;
numtype_ = numtype;
comp_ = comp;
ifmt_ = ifmt;
std::copy(size.begin(), size.begin()+dim, size_.begin());
std::fill(size_.begin()+dim, size_.end(), 1);
@ -454,7 +449,7 @@ struct Texture {
try {
Product::Meta meta {
.target = target_,
.format = static_cast<GLint>(gl::ToInternalFormat(numtype_, comp_)),
.format = ifmt_,
.size = {},
};
std::transform(size_.begin(), size_.end(), meta.size.begin(),
@ -489,13 +484,13 @@ struct Texture {
}
const auto texel = std::accumulate(size.begin(), size.end(), 1, std::multiplies<uint32_t> {});
const auto vecsz = texel*gl::GetCompCount(comp_)*gl::GetByteSize(numtype_);
const auto vecsz = texel*gl::GetByteSize(ifmt_);
if (vec->size() < static_cast<size_t>(vecsz)) {
throw nf7::Exception {"vector is too small"};
}
const auto fmt = gl::ToEnum(comp_);
const auto type = gl::ToEnum(numtype_);
const auto fmt = gl::ToEnum(gl::GetColorComp(ifmt_));
const auto type = gl::ToEnum(gl::GetNumericType(ifmt_));
p.la->env().ExecGL(p.la, [=, &tex]() {
const auto t = gl::ToEnum(tex.meta().target);
glBindTexture(t, tex.id());
@ -517,9 +512,10 @@ struct Texture {
assert(0 == glGetError());
});
return true;
} else if (p.in.name == "download") {
auto numtype = numtype_;
auto comp = comp_;
auto numtype = gl::GetNumericType(ifmt_);
auto comp = gl::GetColorComp(ifmt_);
try {
try {
numtype = magic_enum::enum_cast<
@ -543,7 +539,7 @@ struct Texture {
const auto& tex = **p.obj;
const auto size = tex.meta().size;
const auto texel = std::accumulate(size.begin(), size.end(), 1, std::multiplies<uint32_t> {});
const auto bsize = static_cast<size_t>(texel)*GetCompCount(comp)*GetByteSize(numtype);
const auto bsize = texel*gl::GetCompCount(comp)*gl::GetByteSize(numtype);
glBufferData(GL_PIXEL_PACK_BUFFER, static_cast<GLsizeiptr>(bsize), nullptr, GL_STREAM_READ);
const auto t = gl::ToEnum(tex.meta().target);
@ -559,7 +555,7 @@ struct Texture {
auto buf = std::make_shared<std::vector<uint8_t>>(bsize);
const auto ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
std::memcpy(buf->data(), ptr, bsize);
std::memcpy(buf->data(), ptr, static_cast<size_t>(bsize));
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
@ -585,17 +581,13 @@ struct Texture {
void UpdateTooltip(const std::shared_ptr<Product>& prod) noexcept {
const auto t = magic_enum::enum_name(target_);
ImGui::Text("target : %.*s", static_cast<int>(t.size()), t.data());
ImGui::Text("target: %.*s", static_cast<int>(t.size()), t.data());
const auto f = magic_enum::enum_name(numtype_);
ImGui::Text("numtype: %.*s", static_cast<int>(f.size()), f.data());
const auto c = magic_enum::enum_name(ifmt_);
ImGui::Text("ifmt : %.*s",
static_cast<int>(c.size()), c.data());
const auto c = magic_enum::enum_name(comp_);
ImGui::Text("comp : %.*s (%" PRIu8 " values)",
static_cast<int>(c.size()), c.data(),
magic_enum::enum_integer(comp_));
ImGui::Text("size : %" PRIu32 " x %" PRIu32 " x %" PRIu32, size_[0], size_[1], size_[2]);
ImGui::Text("size : %" PRIu32 " x %" PRIu32 " x %" PRIu32, size_[0], size_[1], size_[2]);
ImGui::Spacing();
if (prod) {
@ -613,9 +605,8 @@ struct Texture {
}
private:
gl::TextureTarget target_ = gl::TextureTarget::Rect;
gl::NumericType numtype_ = gl::NumericType::U8;
gl::ColorComp comp_ = gl::ColorComp::RGBA;
gl::TextureTarget target_ = gl::TextureTarget::Rect;
gl::InternalFormat ifmt_ = gl::InternalFormat::RGBA8;
std::array<uint32_t, 3> size_ = {256, 256, 1};
};
@ -1219,7 +1210,7 @@ struct Framebuffer {
Framebuffer& operator=(Framebuffer&&) = default;
void serialize(auto& ar) {
ar(colors_);
ar(colors_, depth_, stencil_);
}
std::string Stringify() noexcept {
@ -1234,6 +1225,14 @@ struct Framebuffer {
}
}
st << YAML::EndMap;
if (depth_) {
st << YAML::Key << "depth";
st << YAML::Value << depth_->path.Stringify();
}
if (stencil_) {
st << YAML::Key << "stencil";
st << YAML::Value << stencil_->path.Stringify();
}
st << YAML::EndMap;
return std::string {st.c_str(), st.size()};
}
@ -1242,16 +1241,26 @@ struct Framebuffer {
const auto yaml = YAML::Load(v);
const auto& yaml_colors = yaml["colors"];
std::array<std::optional<Attachment>, Product::Meta::kColorSlotCount> colors;
Framebuffer ret;
for (size_t i = 0; i < Product::Meta::kColorSlotCount; ++i) {
if (auto& yaml_color = yaml_colors[std::to_string(i)]) {
colors[i].emplace(Attachment {
ret.colors_[i].emplace(Attachment {
.path = nf7::File::Path::Parse(yaml_color.as<std::string>()),
});
}
}
if (const auto& yaml_depth = yaml["depth"]) {
ret.depth_.emplace(Attachment {
.path = nf7::File::Path::Parse(yaml_depth.as<std::string>()),
});
}
if (const auto& yaml_stencil = yaml["stencil"]) {
ret.stencil_.emplace(Attachment {
.path = nf7::File::Path::Parse(yaml_stencil.as<std::string>()),
});
}
colors_ = std::move(colors);
*this = std::move(ret);
} catch (std::bad_optional_access&) {
throw nf7::Exception {std::string {"invalid enum"}};
} catch (YAML::Exception& e) {
@ -1263,13 +1272,29 @@ struct Framebuffer {
auto& base = *p.file;
Product::Meta meta;
const auto resolveAndWatch = [&](const auto& path) {
const auto fid = base.ResolveOrThrow(path).id();
p.watch->Watch(fid);
return fid;
};
for (size_t i = 0; i < Product::Meta::kColorSlotCount; ++i) {
if (const auto& color = colors_[i]) {
const auto fid = base.ResolveOrThrow(color->path).id();
meta.colors[i].emplace(Product::Meta::Attachment { .tex = fid, });
p.watch->Watch(fid);
meta.colors[i].emplace(Product::Meta::Attachment {
.tex = resolveAndWatch(color->path),
});
}
}
if (depth_) {
meta.depth.emplace(Product::Meta::Attachment {
.tex = resolveAndWatch(depth_->path),
});
}
if (stencil_) {
meta.stencil.emplace(Product::Meta::Attachment {
.tex = resolveAndWatch(stencil_->path),
});
}
return meta.Create(p.ctx);
} catch (nf7::Exception&) {
return {std::current_exception()};
@ -1296,6 +1321,8 @@ struct Framebuffer {
private:
std::array<std::optional<Attachment>, Product::Meta::kColorSlotCount> colors_;
std::optional<Attachment> depth_;
std::optional<Attachment> stencil_;
};
template <>
struct ObjBase<Framebuffer>::TypeInfo final {