- Continued Texture Implementation

- Began reorganizing the planning document into /planning/
This commit is contained in:
2025-08-04 21:11:22 -04:00
parent ff4d6efedc
commit 4a3639ecb4
14 changed files with 674 additions and 31 deletions

View File

@@ -44,8 +44,8 @@ namespace fennec
///
/// \details
/// | Property | Value |
/// |----------|-------------------------|
/// | stable | \emoji heavy_check_mark |
/// |:--------:|:-----------------------:|
/// | stable | |
/// | access | \f$O(1)\f$ |
/// | space | \f$O(N)\f$ |
///

View File

@@ -32,7 +32,7 @@
#ifndef FENNEC_MEMORY_ALLOCATOR_H
#define FENNEC_MEMORY_ALLOCATOR_H
#include <fennec/memory/ptr_traits.h>
#include <fennec/memory/pointer_traits.h>
#include <fennec/memory/new.h>
#include <fennec/lang/conditional_types.h>
@@ -85,7 +85,7 @@ private:
// __diff is substituted using only two template arguments. That one uses 'type = typename AllocT::diff_t'
// however, if it fails, the compiler moves on to the original definition. __size works in the same manner.
template<typename AllocT, typename PtrT, typename = void>
struct __diff { using type = typename ptr_traits<PtrT>::diff_t; };
struct __diff { using type = typename pointer_traits<PtrT>::diff_t; };
template<typename AllocT, typename PtrT>
struct __diff<AllocT, PtrT, void_t<typename AllocT::diff_t>> { using type = typename AllocT::diff_t; };

View File

@@ -29,12 +29,12 @@ namespace fennec
/// \brief Class for retrieving the traits of Pointer-like types
/// \tparam ClassT The Pointer class type
template<typename ClassT>
struct ptr_traits
struct pointer_traits
: detail::_ptr_traits_impl<ClassT, detail::_ptr_get_element<ClassT>> {};
// overload for C-Style Pointers
template<typename ElemT>
struct ptr_traits<ElemT*> : detail::_ptr_traits_ptr_to<ElemT*, ElemT>
struct pointer_traits<ElemT*> : detail::_ptr_traits_ptr_to<ElemT*, ElemT>
{
using pointer_t = ElemT*;
using element_t = ElemT;

View File

@@ -24,11 +24,13 @@
* https://registry.khronos.org/OpenGL/specs/es/3.2/es_spec_3.2.pdf
*
* Requires the following:
* OpenGL ES 3.2 / OpenGL 4.3 OR
* - EXT_texture_array
* OpenGL ES 3.2 / OpenGL 4.3 OR
* - ARB_compute_shader
* - ARB_shader_image_load_store
* - ARB_shader_storage_buffer_object
* - ARB_texture_cube_map_array
* - ARB_texture_storage
* - EXT_texture_array
*
* This will support all mobile devices since 2012
*/

View File

@@ -29,7 +29,23 @@ namespace fennec
namespace gl
{
template<GLenum TypeV, GLbitfield FlagsV, GLboolean ImmutableV = false>
template<GLbitfield FlagsV, GLboolean ImmutableV> using vertex_buffer = buffer<VERTEX, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using element_buffer = buffer<ELEMENT, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using uniform_buffer = buffer<UNIFORM, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using shader_storage_buffer = buffer<SHADER_STORAGE, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using query_buffer = buffer<QUERY, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using texture_buffer = buffer<TEXTURE, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using transform_feedback_buffer = buffer<TRANSFORM_FEEDBACK, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using atomic_counter_buffer = buffer<ATOMIC_COUNTER, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using parameter_buffer = buffer<PARAMETER, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using indirect_draw_buffer = buffer<INDIRECT_DRAW, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using indirect_dispatch_buffer = buffer<INDIRECT_DISPATCH, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using copy_read_buffer = buffer<COPY_READ, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using copy_write_buffer = buffer<COPY_WRITE, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using pixel_pack_buffer = buffer<PIXEL_PACK, FlagsV, ImmutableV>;
template<GLbitfield FlagsV, GLboolean ImmutableV> using pixel_unpack_buffer = buffer<PIXEL_UNPACK, FlagsV, ImmutableV>;
template<GLenum TypeV, GLbitfield FlagsV, GLboolean ImmutableV>
class buffer {
// HELPER FUNCTIONS ====================================================================================================
@@ -66,6 +82,7 @@ public:
static constexpr GLenum type = TypeV;
static constexpr GLboolean immutable = ImmutableV;
static constexpr GLbitfield flags = FlagsV;
static constexpr GLboolean indexed = type == ATOMIC_COUNTER or type == SHADER_STORAGE or type == TRANSFORM_FEEDBACK or type == UNIFORM;
static constexpr GLboolean map_read = flags & READ;
static constexpr GLboolean map_write = flags & WRITE;
static constexpr GLboolean mapped = map_read or map_write;
@@ -91,7 +108,6 @@ public:
} else {
glBufferData(type, _size, data, usage);
}
end();
}
constexpr buffer(buffer&& buff) noexcept
@@ -100,8 +116,6 @@ public:
, _mapping(nullptr) {
}
constexpr buffer(const buffer&) = delete;
constexpr buffer& operator=(buffer&& buff) noexcept {
glDeleteBuffers(1, &_handle);
_handle = buff._handle;
@@ -109,6 +123,9 @@ public:
return *this;
}
constexpr buffer(const buffer&) = delete;
constexpr buffer& operator=(const buffer&) = delete;
// OBJECT FUNCTIONS ====================================================================================================
@@ -131,6 +148,11 @@ public:
// BASIC BUFFER FUNCTIONS ==============================================================================================
constexpr void resize(GLsizei size) requires not immutable {
unmap();
glBufferData(type, _size = size, nullptr, usage);
}
constexpr void* map(GLbitfield access, GLsizeiptr size, GLintptr offset = 0) {
if (_mapping) {
return _mapping;

View File

@@ -22,4 +22,18 @@
#include <GL/glew.h>
#include <GL/gl.h>
namespace fennec
{
namespace gl
{
template<GLenum TypeV, GLbitfield FlagsV, GLboolean ImmutableV = false> class buffer;
template<GLenum TypeV, GLint FormatV, GLboolean ImmutableV> class texture;
}
}
#endif // FENNEC_RENDERERS_OPENGL_LIB_FWD_H

View File

@@ -19,6 +19,34 @@
#ifndef FENNEC_RENDERERS_OPENGL_LIB_TEXTURE_H
#define FENNEC_RENDERERS_OPENGL_LIB_TEXTURE_H
/* Because our implementation targets minimum OpenGL ES 3.2,
* we are guaranteed to have the following relevant extensions (Starting from OpenGL ES 3.0):
*
* OES_texture_compression_astc
* EXT_texture_border_clamp
* OES_EGL_image_external_essl3
* ARB_shader_image_load_store
* ARB_stencil_texturing
* ARG_shader_image_size
* ARB_texture_multisample
* ARB_texture_storage_multisample
* ARB_sample_locations
* OES_texture_view
* NV_image_formats
* EXT_render_snorm
* EXT_render_norm16
* EXT_color_buffer_float
* OES_copy_image
* OES_shader_image_atomic
* OES_texture_border_clamp
* OES_texture_buffer
* OES_texture_cube_map_array
* OES_texture_stencil8
* OES_texture_storage_multisample_2d_array
*/
#include <fennec/math/common.h>
#include <fennec/renderers/opengl/lib/fwd.h>
#include <fennec/renderers/opengl/lib/enum.h>
@@ -28,35 +56,229 @@ namespace fennec
namespace gl
{
template<GLint FormatV, GLboolean ImmutableV> using texture1d = texture<TEX_1D, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture1dv = texture<TEX_1D_V, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2d = texture<TEX_2D, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2dv = texture<TEX_2D_V, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture_rect = texture<TEX_RECT, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2d_ms = texture<TEX_2D_MS, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2dv_ms = texture<TEX_2D_MS_V, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using cubemap = texture<TEX_CUBEMAP, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using cubemapv = texture<TEX_CUBEMAP_V, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture3d = texture<TEX_3D, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using buffer_texture = texture<TEX_BUFFER, FormatV, ImmutableV>;
///
/// \brief Wrapper for OpenGL Texture Objects
/// \tparam TypeV The type of the texture
/// \tparam FormatV The internal format of the texels
/// \tparam ImmutableV Whether the texture is immutable, i.e. cannot be resized after creation
///
/// \details Immutable textures require EXT_texture_storage or ARB_texture_storage
/// Immutable multisample textures require ARB_texture_storage_multisample of OES_texture_storage_multisample_2d_array
template<GLenum TypeV, GLint FormatV, GLboolean ImmutableV>
class texture {
public:
static constexpr GLenum type = TypeV;
static constexpr GLint format = FormatV;
static constexpr bool immutable = ImmutableV;
static constexpr bool sampled = TypeV == TEX_2D_MS or TypeV == TEX_2D_MS_V;
static constexpr bool is_rect = TypeV == TEX_RECT;
static constexpr bool is_buffered = TypeV == TEX_BUFFER;
static constexpr bool is_2d = sampled or is_rect or TypeV == TEX_2D or TypeV == TEX_2D_V;
static constexpr bool is_1d = TypeV == TEX_1D or TypeV == TEX_1D_V;
static constexpr bool is_array = TypeV == TEX_1D_V or TypeV == TEX_2D_V or TypeV == TEX_2D_MS_V or TypeV == TEX_CUBEMAP_V;
static constexpr bool has_mipmaps = not(sampled or is_rect or is_buffered);
texture(GLsizei width, GLint mips, void* data) requires is_1d and not is_array
// Constants ===========================================================================================================
public:
static constexpr GLenum type = TypeV;
static constexpr GLint format = FormatV;
static constexpr GLboolean immutable = ImmutableV;
static constexpr GLboolean is_rect = type == TEX_RECT;
static constexpr GLboolean is_buffered = type == TEX_BUFFER;
static constexpr GLboolean sampled = type == TEX_2D_MS or type == TEX_2D_MS_V;
static constexpr GLboolean cubemap = type == TEX_CUBEMAP or type == TEX_CUBEMAP_V;
static constexpr GLboolean is_1d = type == TEX_1D or type == TEX_1D_V;
static constexpr GLboolean is_2d = sampled or is_rect or type == TEX_2D or type == TEX_2D_V or cubemap;
static constexpr GLboolean is_array = TypeV == TEX_1D_V or TypeV == TEX_2D_V or type == TEX_2D_MS_V or type == TEX_CUBEMAP_V;
static constexpr GLboolean is_3d = TypeV == TEX_3D;
static constexpr GLboolean has_mipmaps = not(sampled or is_rect or is_buffered);
static constexpr GLboolean use_1d = is_1d and not is_array;
static constexpr GLboolean use_2d = (is_2d and not is_array) or (is_1d and is_array) and not sampled;
static constexpr GLboolean use_3d = is_3d or (is_2d and is_array) and not sampled and not cubemap;
static constexpr GLint cubemap_faces = 6;
static constexpr GLenum base_cubemap_face = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
static constexpr GLboolean compressed = type == RGB_DXT1 or type == RGBA_DXT1 or type == RGBA_DXT3 or type == RGBA_DXT5
or type == SRGB_DXT1 or type == SRGBA_DXT1 or type == SRGBA_DXT3 or type == SRGBA_DXT5;
// Constructors ========================================================================================================
///
/// \brief 1D Texture Constructor
/// \param width The width of the texture
/// \param mips The number of mipmap levels
/// \param data A pointer to a buffer containing pixel values, used as an offset if a PIXEL_UNPACK_BUFFER is bound.
/// \param component The type of each component
/// \param layout The layout of components in each pixel
texture(GLsizei width, GLint mips,
void* data = nullptr, GLenum component = BYTE, GLenum layout = R, GLsizei size = 0) requires use_1d
: _handle(NULL)
, _width(width), _height(1), _depth(1)
, _samples(1)
, _mips(mips) {
, _samples(1), _mips(mips) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage1D(type, _mips, format, _width);
glTexSubImage1D(type, 0, 0, _width, layout, component, data);
} else if constexpr(compressed) {
glCompressedTexImage1D(type, 0, format, _width, 0, size, data);
} else {
glTexImage1D(type, 0, format, _width, 0, layout, component, data);
}
genmips();
}
texture(GLsizei width, GLsizei height, GLint mips) requires is_2d and not (is_array or sampled) or (is_1d and is_array)
///
/// \brief 2D Texture Constructor
/// \param width The width of the texture
/// \param height The height of the texture, or number of layers for arrays
/// \param mips The number of mipmap levels
/// \param data A pointer to a buffer containing pixel values, used as an offset if a PIXEL_UNPACK_BUFFER is bound.
/// \param component The type of each component
/// \param layout The layout of components in each pixel
texture(GLsizei width, GLsizei height, GLint mips,
void* data = nullptr, GLenum component = BYTE, GLenum layout = R, GLsizei size = 0) requires use_2d and not cubemap
: _handle(NULL)
, _width(width), _height(height), _depth(1)
, _samples(1)
, _mips(mips) {
, _samples(1), _mips(mips) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage2D(type, _mips, format, _width, _height);
glTexSubImage2D(type, 0, 0, 0, _width, _height, layout, component, data);
} else if constexpr(compressed) {
glCompressedTexImage2D(type, 0, format, _width, _height, 0, size, data);
} else {
glTexImage2D(type, 0, format, _width, _height, 0, layout, component, data);
}
}
///
/// \brief 2D Texture Constructor
/// \param width The width of the texture
/// \param height The height of the texture
/// \param depth The depth of the texture, or number of layers for arrays
/// \param mips The number of mipmap levels
/// \param data A pointer to a buffer containing pixel values, used as an offset if a PIXEL_UNPACK_BUFFER is bound.
/// \param component The type of each component
/// \param layout The layout of components in each pixel
texture(GLsizei width, GLsizei height, GLsizei depth, GLsizei mips,
void* data = nullptr, GLenum component = BYTE, GLenum layout = R, GLsizei size = 0) requires use_3d and not cubemap
: _handle(NULL)
, _width(width), _height(height), _depth(depth)
, _samples(1), _mips(mips) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage3D(type, _mips, format, _width, _height, _depth);
glTexSubImage3D(type, 0, 0, 0, 0, _width, _height, _depth, layout, component, data);
} else if constexpr(compressed) {
glCompressedTexImage3D(type, 0, format, _width, _height, _depth, 0, size, data);
} else {
glTexImage3D(type, 0, format, _width, _height, _depth, 0, layout, component, data);
}
}
///
/// \brief 2D Multisample Texture Constructor
/// \param width The width of the texture
/// \param height The height of the texture
/// \param samples The number of samples per pixel
/// \param fixed When true, a fixed set of sample locations is used
texture(GLsizei width, GLsizei height, GLsizei samples, GLboolean fixed = true) requires sampled and not is_array
: _handle(NULL)
, _width(width), _height(height), _depth(1)
, _samples(samples), _mips(0) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage2DMultisample(type, _samples, format, _width, _height, fixed);
} else {
glTexImage2DMultisample(type, _samples, format, _width, _height, fixed);
}
}
///
/// \brief 2D Multisample Array Texture Constructor
/// \param width The width of the texture
/// \param height The height of the texture
/// \param depth The number of layers in the array
/// \param samples The number of samples per pixel
/// \param fixed When true, a fixed set of sample locations is used
texture(GLsizei width, GLsizei height, GLsizei depth, GLsizei samples, GLboolean fixed = true) requires sampled and is_array
: _handle(NULL)
, _width(width), _height(height), _depth(depth)
, _samples(samples), _mips(0) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage3DMultisample(type, _samples, format, _width, _height, _depth, fixed);
} else {
glTexImage3DMultisample(type, _samples, format, _width, _height, _depth, fixed);
}
}
///
/// \brief Cubemap Constructor
/// \param size The size of each face texture
/// \param mips The number of mipmap layers
/// \param faces An array of pointers to textures containing pixel data for each face
/// \param component The component type of the data
/// \param layout The layout of the components in the pixel
texture(GLsizei size, GLsizei mips,
const void* faces[6], GLenum component = BYTE, GLenum layout = R, GLsizei size = 0) requires is_2d and cubemap
: _handle(NULL)
, _width(size), _height(size), _depth(1)
, _samples(1), _mips(mips) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage2D(type, _mips, format, _width, _height);
for (int i = 0; i < cubemap_faces; ++i) {
glTexSubImage2D(base_cubemap_face + i, 0, 0, 0, _width, _height, layout, component, faces[i]);
}
} else if constexpr(compressed) {
} else {
for (int i = 0; i < cubemap_faces; ++i) {
glTexImage2D(base_cubemap_face + i, 0, format, _width, _height, 0, layout, component, faces[i]);
}
}
}
///
/// \brief Cubemap Array Constructor
/// \param size The size of each face texture
/// \param depth The number of layers in the array
/// \param mips The number of mipmap layers
/// \param data A pointer to a buffer containing image data
/// \param component The component type of the data
/// \param layout The layout of the components in the pixel
///
/// \details Requires OES_texture_cube_map_array
texture(GLsizei size, GLsizei depth, GLsizei mips,
const void* data, GLenum component = BYTE, GLenum layout = R, GLsizei size = 0) requires is_2d and cubemap
: _handle(NULL)
, _width(size), _height(size), _depth(depth)
, _samples(1), _mips(mips) {
glGenTextures(1, &_handle);
start();
if constexpr(immutable) {
glTexStorage3D(type, _mips, format, _width, _height, _depth * 6);
glTexSubImage3D(type, 0, 0, 0, 0, _width, _height, _depth * 6, layout, component, data);
} else if constexpr(compressed) {
} else {
glTexImage3D(type, 0, format, _width, _height, _depth * 6, 0, layout, component, data);
}
}
// Basic Functions =====================================================================================================
void start() {
glBindTexture(type, _handle);
}
@@ -70,6 +292,10 @@ public:
start();
}
void genmips() {
glGenerateMipmap(type);
}
private:
GLuint _handle;
GLsizei _width;
@@ -83,4 +309,4 @@ private:
}
#endif // FENNEC_RENDERERS_OPENGL_TEXTURE_H
#endif // FENNEC_RENDERERS_OPENGL_LIB_TEXTURE_H