Files
panopainter/src/renderer_gl/opengl_capabilities.cpp

440 lines
13 KiB
C++

#include "renderer_gl/opengl_capabilities.h"
#include <array>
namespace pp::renderer::gl {
namespace {
constexpr std::uint32_t gl_unsigned_byte = 0x1401U;
constexpr std::uint32_t gl_unsigned_short = 0x1403U;
constexpr std::uint32_t gl_unsigned_int = 0x1405U;
constexpr std::uint32_t gl_float = 0x1406U;
constexpr std::uint32_t gl_half_float = 0x140BU;
constexpr std::uint32_t gl_false = 0U;
constexpr std::uint32_t gl_points = 0x0000U;
constexpr std::uint32_t gl_lines = 0x0001U;
constexpr std::uint32_t gl_triangles = 0x0004U;
constexpr std::uint32_t gl_array_buffer = 0x8892U;
constexpr std::uint32_t gl_element_array_buffer = 0x8893U;
constexpr std::uint32_t gl_static_draw = 0x88E4U;
constexpr std::uint32_t gl_red = 0x1903U;
constexpr std::uint32_t gl_rgb = 0x1907U;
constexpr std::uint32_t gl_rgba = 0x1908U;
constexpr std::uint32_t gl_rg = 0x8227U;
constexpr std::uint32_t gl_r8 = 0x8229U;
constexpr std::uint32_t gl_rg8 = 0x822BU;
constexpr std::uint32_t gl_rgb8 = 0x8051U;
constexpr std::uint32_t gl_rgba8 = 0x8058U;
constexpr std::uint32_t gl_rgba32f = 0x8814U;
constexpr std::uint32_t gl_rgba16f = 0x881AU;
constexpr std::uint32_t gl_texture_2d = 0x0DE1U;
constexpr std::uint32_t gl_renderbuffer = 0x8D41U;
constexpr std::uint32_t gl_depth_component24 = 0x81A6U;
constexpr std::uint32_t gl_framebuffer = 0x8D40U;
constexpr std::uint32_t gl_read_framebuffer = 0x8CA8U;
constexpr std::uint32_t gl_draw_framebuffer = 0x8CA9U;
constexpr std::uint32_t gl_draw_framebuffer_binding = 0x8CA6U;
constexpr std::uint32_t gl_read_framebuffer_binding = 0x8CAAU;
constexpr std::uint32_t gl_color_attachment0 = 0x8CE0U;
constexpr std::uint32_t gl_depth_attachment = 0x8D00U;
constexpr std::uint32_t gl_framebuffer_complete = 0x8CD5U;
constexpr std::uint32_t gl_framebuffer_incomplete_attachment = 0x8CD6U;
constexpr std::uint32_t gl_framebuffer_incomplete_missing_attachment = 0x8CD7U;
constexpr std::uint32_t gl_framebuffer_incomplete_draw_buffer = 0x8CDBU;
constexpr std::uint32_t gl_framebuffer_incomplete_read_buffer = 0x8CDCU;
constexpr std::uint32_t gl_framebuffer_unsupported = 0x8CDDU;
constexpr std::uint32_t gl_framebuffer_undefined = 0x8219U;
constexpr std::uint32_t gl_framebuffer_incomplete_multisample = 0x8D56U;
constexpr std::uint32_t gl_color_buffer_bit = 0x00004000U;
constexpr std::uint32_t gl_depth_buffer_bit = 0x00000100U;
constexpr std::uint32_t gl_color_writemask = 0x0C23U;
constexpr std::uint32_t gl_texture_cube_map = 0x8513U;
constexpr std::uint32_t gl_texture_cube_map_positive_x = 0x8515U;
constexpr std::uint32_t gl_texture_cube_map_negative_x = 0x8516U;
constexpr std::uint32_t gl_texture_cube_map_positive_y = 0x8517U;
constexpr std::uint32_t gl_texture_cube_map_negative_y = 0x8518U;
constexpr std::uint32_t gl_texture_cube_map_positive_z = 0x8519U;
constexpr std::uint32_t gl_texture_cube_map_negative_z = 0x851AU;
constexpr std::uint32_t gl_linear = 0x2601U;
constexpr std::uint32_t gl_nearest = 0x2600U;
constexpr std::uint32_t gl_texture_mag_filter = 0x2800U;
constexpr std::uint32_t gl_texture_min_filter = 0x2801U;
constexpr std::uint32_t gl_texture_wrap_s = 0x2802U;
constexpr std::uint32_t gl_texture_wrap_t = 0x2803U;
constexpr std::uint32_t gl_texture_wrap_r = 0x8072U;
constexpr std::uint32_t gl_texture_border_color = 0x1004U;
constexpr std::uint32_t gl_clamp_to_edge = 0x812FU;
constexpr std::uint32_t gl_pixel_pack_buffer = 0x88EBU;
constexpr std::uint32_t gl_pixel_unpack_buffer = 0x88ECU;
constexpr std::uint32_t gl_stream_read = 0x88E1U;
constexpr std::uint32_t gl_map_read_bit = 0x0001U;
[[nodiscard]] bool contains(std::string_view text, std::string_view needle) noexcept
{
return text.find(needle) != std::string_view::npos;
}
}
OpenGlCapabilities detect_opengl_capabilities(
std::span<const std::string_view> extensions,
OpenGlRuntime runtime) noexcept
{
OpenGlCapabilities capabilities;
if (runtime.desktop_gl) {
capabilities.float32_textures = true;
capabilities.float32_linear = true;
capabilities.float16_textures = true;
}
for (const auto extension : extensions) {
if (contains(extension, "shader_framebuffer_fetch")) {
capabilities.framebuffer_fetch = true;
}
if (contains(extension, "map_buffer_alignment")) {
capabilities.map_buffer_alignment = true;
}
if (runtime.gles && !runtime.web) {
if (contains(extension, "texture_float") || contains(extension, "color_buffer_float")) {
capabilities.float32_textures = true;
}
if (contains(extension, "texture_float_linear")) {
capabilities.float32_linear = true;
}
if (contains(extension, "texture_half_float") || contains(extension, "color_buffer_half_float")) {
capabilities.float16_textures = true;
}
}
}
return capabilities;
}
std::uint32_t texture_upload_type_for_internal_format(std::uint32_t internal_format) noexcept
{
switch (internal_format) {
case gl_rgba32f:
return gl_float;
case gl_rgba16f:
return gl_half_float;
default:
return gl_unsigned_byte;
}
}
std::uint32_t unsigned_byte_component_type() noexcept
{
return gl_unsigned_byte;
}
std::uint32_t rgba_pixel_format() noexcept
{
return gl_rgba;
}
OpenGlPixelFormat texture_format_for_channel_count(std::uint32_t channel_count) noexcept
{
switch (channel_count) {
case 1:
return OpenGlPixelFormat { .internal_format = gl_r8, .pixel_format = gl_red, .channel_count = 1 };
case 2:
return OpenGlPixelFormat { .internal_format = gl_rg8, .pixel_format = gl_rg, .channel_count = 2 };
case 3:
return OpenGlPixelFormat { .internal_format = gl_rgb8, .pixel_format = gl_rgb, .channel_count = 3 };
case 4:
return OpenGlPixelFormat { .internal_format = gl_rgba8, .pixel_format = gl_rgba, .channel_count = 4 };
default:
return OpenGlPixelFormat {};
}
}
OpenGlReadbackFormat rgba8_readback_format() noexcept
{
return OpenGlReadbackFormat {
.pixel_format = gl_rgba,
.component_type = gl_unsigned_byte,
.bytes_per_pixel = 4U,
};
}
OpenGlReadbackFormat rgba32f_readback_format() noexcept
{
return OpenGlReadbackFormat {
.pixel_format = gl_rgba,
.component_type = gl_float,
.bytes_per_pixel = 16U,
};
}
std::uint64_t readback_byte_count(
OpenGlReadbackFormat format,
std::uint32_t width,
std::uint32_t height) noexcept
{
return static_cast<std::uint64_t>(width) * height * format.bytes_per_pixel;
}
std::uint32_t pixel_pack_buffer_target() noexcept
{
return gl_pixel_pack_buffer;
}
std::uint32_t pixel_unpack_buffer_target() noexcept
{
return gl_pixel_unpack_buffer;
}
std::uint32_t pixel_buffer_stream_read_usage() noexcept
{
return gl_stream_read;
}
std::uint32_t pixel_buffer_map_read_access() noexcept
{
return gl_map_read_bit;
}
std::uint32_t texture_2d_target() noexcept
{
return gl_texture_2d;
}
std::uint32_t renderbuffer_target() noexcept
{
return gl_renderbuffer;
}
std::uint32_t depth_component24_format() noexcept
{
return gl_depth_component24;
}
std::uint32_t framebuffer_target() noexcept
{
return gl_framebuffer;
}
std::uint32_t draw_framebuffer_target() noexcept
{
return gl_draw_framebuffer;
}
std::uint32_t read_framebuffer_target() noexcept
{
return gl_read_framebuffer;
}
std::uint32_t draw_framebuffer_binding_query() noexcept
{
return gl_draw_framebuffer_binding;
}
std::uint32_t read_framebuffer_binding_query() noexcept
{
return gl_read_framebuffer_binding;
}
std::uint32_t framebuffer_color_attachment() noexcept
{
return gl_color_attachment0;
}
std::uint32_t framebuffer_depth_attachment() noexcept
{
return gl_depth_attachment;
}
std::uint32_t framebuffer_complete_status() noexcept
{
return gl_framebuffer_complete;
}
const char* framebuffer_status_name(std::uint32_t status) noexcept
{
switch (status) {
case gl_framebuffer_complete:
return "GL_FRAMEBUFFER_COMPLETE";
case gl_framebuffer_undefined:
return "GL_FRAMEBUFFER_UNDEFINED";
case gl_framebuffer_incomplete_attachment:
return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
case gl_framebuffer_incomplete_missing_attachment:
return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
case gl_framebuffer_incomplete_draw_buffer:
return "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER";
case gl_framebuffer_incomplete_read_buffer:
return "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER";
case gl_framebuffer_unsupported:
return "GL_FRAMEBUFFER_UNSUPPORTED";
case gl_framebuffer_incomplete_multisample:
return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
default:
return "UNKNOWN";
}
}
std::uint32_t framebuffer_color_buffer_mask() noexcept
{
return gl_color_buffer_bit;
}
std::uint32_t framebuffer_depth_buffer_mask() noexcept
{
return gl_depth_buffer_bit;
}
std::uint32_t color_write_mask_query() noexcept
{
return gl_color_writemask;
}
std::uint32_t framebuffer_blit_filter(bool linear) noexcept
{
return linear ? gl_linear : gl_nearest;
}
std::uint32_t index_type_for_index_size(std::uint32_t index_size_bytes) noexcept
{
switch (index_size_bytes) {
case 2:
return gl_unsigned_short;
case 4:
return gl_unsigned_int;
default:
return 0U;
}
}
std::uint32_t primitive_mode_for_fill_count(std::uint32_t vertex_or_index_count) noexcept
{
if (vertex_or_index_count == 1U) {
return gl_points;
}
if (vertex_or_index_count == 2U) {
return gl_lines;
}
return gl_triangles;
}
std::uint32_t primitive_mode_for_stroke_count(std::uint32_t vertex_or_index_count) noexcept
{
if (vertex_or_index_count == 1U) {
return gl_points;
}
return gl_lines;
}
std::uint32_t array_buffer_target() noexcept
{
return gl_array_buffer;
}
std::uint32_t element_array_buffer_target() noexcept
{
return gl_element_array_buffer;
}
std::uint32_t static_draw_buffer_usage() noexcept
{
return gl_static_draw;
}
std::uint32_t vertex_attribute_float_component_type() noexcept
{
return gl_float;
}
std::uint32_t vertex_attribute_not_normalized() noexcept
{
return gl_false;
}
std::uint32_t texture_cube_map_target() noexcept
{
return gl_texture_cube_map;
}
std::uint32_t cube_map_allocation_face_texture_target(std::uint32_t face_index) noexcept
{
if (face_index >= 6U) {
return 0U;
}
return gl_texture_cube_map_positive_x + face_index;
}
std::span<const std::uint32_t> panopainter_cube_face_texture_targets() noexcept
{
static constexpr std::array<std::uint32_t, 6> targets {
gl_texture_cube_map_negative_z, // front
gl_texture_cube_map_negative_x, // right
gl_texture_cube_map_positive_z, // back
gl_texture_cube_map_positive_x, // left
gl_texture_cube_map_negative_y, // top
gl_texture_cube_map_positive_y, // bottom
};
return targets;
}
std::uint32_t cube_face_texture_target(std::uint32_t face_index) noexcept
{
const auto targets = panopainter_cube_face_texture_targets();
if (face_index >= targets.size()) {
return 0U;
}
return targets[face_index];
}
std::span<const OpenGlTextureParameter> default_render_target_texture_parameters() noexcept
{
static constexpr std::array<OpenGlTextureParameter, 4> parameters {
OpenGlTextureParameter { .name = gl_texture_mag_filter, .value = gl_linear },
OpenGlTextureParameter { .name = gl_texture_min_filter, .value = gl_linear },
OpenGlTextureParameter { .name = gl_texture_wrap_s, .value = gl_clamp_to_edge },
OpenGlTextureParameter { .name = gl_texture_wrap_t, .value = gl_clamp_to_edge },
};
return parameters;
}
std::array<OpenGlTextureParameter, 5> sampler_parameters_for_filter_wrap(
std::uint32_t filter,
std::uint32_t wrap) noexcept
{
return {
OpenGlTextureParameter { .name = gl_texture_wrap_s, .value = wrap },
OpenGlTextureParameter { .name = gl_texture_wrap_t, .value = wrap },
OpenGlTextureParameter { .name = gl_texture_wrap_r, .value = wrap },
OpenGlTextureParameter { .name = gl_texture_min_filter, .value = filter },
OpenGlTextureParameter { .name = gl_texture_mag_filter, .value = filter },
};
}
std::array<OpenGlTextureParameter, 2> sampler_filter_parameters(
std::uint32_t filter_min,
std::uint32_t filter_mag) noexcept
{
return {
OpenGlTextureParameter { .name = gl_texture_min_filter, .value = filter_min },
OpenGlTextureParameter { .name = gl_texture_mag_filter, .value = filter_mag },
};
}
std::uint32_t sampler_border_color_parameter_name() noexcept
{
return gl_texture_border_color;
}
}