From ff6e3c025658a5fa1affd094f220b623e7e1b24b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 22:38:23 +0200 Subject: Adding upstream version 6.338.2. Signed-off-by: Daniel Baumann --- src/opengl/formats.c | 485 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 485 insertions(+) create mode 100644 src/opengl/formats.c (limited to 'src/opengl/formats.c') diff --git a/src/opengl/formats.c b/src/opengl/formats.c new file mode 100644 index 0000000..6604835 --- /dev/null +++ b/src/opengl/formats.c @@ -0,0 +1,485 @@ +/* + * This file is part of libplacebo. + * + * libplacebo is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libplacebo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libplacebo. If not, see . + */ + +#include "gpu.h" +#include "common.h" +#include "formats.h" +#include "utils.h" + +#ifdef PL_HAVE_UNIX +static bool supported_fourcc(struct pl_gl *p, EGLint fourcc) +{ + for (int i = 0; i < p->egl_formats.num; ++i) + if (fourcc == p->egl_formats.elem[i]) + return true; + return false; +} +#endif + +#define FMT(_name, bits, ftype, _caps) \ + (struct pl_fmt_t) { \ + .name = _name, \ + .type = PL_FMT_##ftype, \ + .caps = (enum pl_fmt_caps) (_caps), \ + .sample_order = {0, 1, 2, 3}, \ + .component_depth = {bits, bits, bits, bits}, \ + } + +// Convenience to make the names simpler +enum { + // Type aliases + U8 = GL_UNSIGNED_BYTE, + U16 = GL_UNSIGNED_SHORT, + U32 = GL_UNSIGNED_INT, + I8 = GL_BYTE, + I16 = GL_SHORT, + I32 = GL_INT, + FLT = GL_FLOAT, + + // Component aliases + R = GL_RED, + RG = GL_RG, + RGB = GL_RGB, + RGBA = GL_RGBA, + BGRA = GL_BGRA, + RI = GL_RED_INTEGER, + RGI = GL_RG_INTEGER, + RGBI = GL_RGB_INTEGER, + RGBAI = GL_RGBA_INTEGER, + + // Capability aliases + S = PL_FMT_CAP_SAMPLEABLE, + L = PL_FMT_CAP_LINEAR, + F = PL_FMT_CAP_RENDERABLE | PL_FMT_CAP_BLITTABLE, // FBO support + V = PL_FMT_CAP_VERTEX, +}; + +// Basic 8-bit formats +const struct gl_format formats_norm8[] = { + {GL_R8, R, U8, FMT("r8", 8, UNORM, S|L|F|V)}, + {GL_RG8, RG, U8, FMT("rg8", 8, UNORM, S|L|F|V)}, + {GL_RGB8, RGB, U8, FMT("rgb8", 8, UNORM, S|L|F|V)}, + {GL_RGBA8, RGBA, U8, FMT("rgba8", 8, UNORM, S|L|F|V)}, +}; + +// Signed variants +/* TODO: these are broken in mesa +const struct gl_format formats_snorm8[] = { + {GL_R8_SNORM, R, I8, FMT("r8s", 8, SNORM, S|L|F|V)}, + {GL_RG8_SNORM, RG, I8, FMT("rg8s", 8, SNORM, S|L|F|V)}, + {GL_RGB8_SNORM, RGB, I8, FMT("rgb8s", 8, SNORM, S|L|F|V)}, + {GL_RGBA8_SNORM, RGBA, I8, FMT("rgba8s", 8, SNORM, S|L|F|V)}, +}; +*/ + +// BGRA 8-bit +const struct gl_format formats_bgra8[] = { + {GL_RGBA8, BGRA, U8, { + .name = "bgra8", + .type = PL_FMT_UNORM, + .caps = S|L|F|V, + .sample_order = {2, 1, 0, 3}, + .component_depth = {8, 8, 8, 8}, + }}, +}; + +// Basic 16-bit formats, excluding rgb16 (special cased below) +const struct gl_format formats_norm16[] = { + {GL_R16, R, U16, FMT("r16", 16, UNORM, S|L|F|V)}, + {GL_RG16, RG, U16, FMT("rg16", 16, UNORM, S|L|F|V)}, + {GL_RGBA16, RGBA, U16, FMT("rgba16", 16, UNORM, S|L|F|V)}, +}; + +// Renderable version of rgb16 +const struct gl_format formats_rgb16_fbo[] = { + {GL_RGB16, RGB, U16, FMT("rgb16", 16, UNORM, S|L|F|V)}, +}; + +// Non-renderable version of rgb16 +const struct gl_format formats_rgb16_fallback[] = { + {GL_RGB16, RGB, U16, FMT("rgb16", 16, UNORM, S|L|V)}, +}; + +// Signed 16-bit variants +/* TODO: these are broken in mesa and nvidia +const struct gl_format formats_snorm16[] = { + {GL_R16_SNORM, R, I16, FMT("r16s", 16, SNORM, S|L|F|V)}, + {GL_RG16_SNORM, RG, I16, FMT("rg16s", 16, SNORM, S|L|F|V)}, + {GL_RGB16_SNORM, RGB, I16, FMT("rgb16s", 16, SNORM, S|L|F|V)}, + {GL_RGBA16_SNORM, RGBA, I16, FMT("rgba16s", 16, SNORM, S|L|F|V)}, +}; +*/ + +// Floating point texture formats +const struct gl_format formats_float[] = { + {GL_R16F, R, FLT, FMT("r16f", 16, FLOAT, S|L|F)}, + {GL_RG16F, RG, FLT, FMT("rg16f", 16, FLOAT, S|L|F)}, + {GL_RGB16F, RGB, FLT, FMT("rgb16f", 16, FLOAT, S|L|F)}, + {GL_RGBA16F, RGBA, FLT, FMT("rgba16f", 16, FLOAT, S|L|F)}, + {GL_R32F, R, FLT, FMT("r32f", 32, FLOAT, S|L|F|V)}, + {GL_RG32F, RG, FLT, FMT("rg32f", 32, FLOAT, S|L|F|V)}, + {GL_RGB32F, RGB, FLT, FMT("rgb32f", 32, FLOAT, S|L|F|V)}, + {GL_RGBA32F, RGBA, FLT, FMT("rgba32f", 32, FLOAT, S|L|F|V)}, +}; + +// Renderable 16-bit float formats (excluding rgb16f) +const struct gl_format formats_float16_fbo[] = { + {GL_R16F, R, FLT, FMT("r16f", 16, FLOAT, S|L|F)}, + {GL_RG16F, RG, FLT, FMT("rg16f", 16, FLOAT, S|L|F)}, + {GL_RGB16F, RGB, FLT, FMT("rgb16f", 16, FLOAT, S|L)}, + {GL_RGBA16F, RGBA, FLT, FMT("rgba16f", 16, FLOAT, S|L|F)}, +}; + +// Non-renderable 16-bit float formats +const struct gl_format formats_float16_fallback[] = { + {GL_R16F, R, FLT, FMT("r16f", 16, FLOAT, S|L)}, + {GL_RG16F, RG, FLT, FMT("rg16f", 16, FLOAT, S|L)}, + {GL_RGB16F, RGB, FLT, FMT("rgb16f", 16, FLOAT, S|L)}, + {GL_RGBA16F, RGBA, FLT, FMT("rgba16f", 16, FLOAT, S|L)}, +}; + +// (Unsigned) integer formats +const struct gl_format formats_uint[] = { + {GL_R8UI, RI, U8, FMT("r8u", 8, UINT, S|F|V)}, + {GL_RG8UI, RGI, U8, FMT("rg8u", 8, UINT, S|F|V)}, + {GL_RGB8UI, RGBI, U8, FMT("rgb8u", 8, UINT, S|V)}, + {GL_RGBA8UI, RGBAI, U8, FMT("rgba8u", 8, UINT, S|F|V)}, + {GL_R16UI, RI, U16, FMT("r16u", 16, UINT, S|F|V)}, + {GL_RG16UI, RGI, U16, FMT("rg16u", 16, UINT, S|F|V)}, + {GL_RGB16UI, RGBI, U16, FMT("rgb16u", 16, UINT, S|V)}, + {GL_RGBA16UI, RGBAI, U16, FMT("rgba16u", 16, UINT, S|F|V)}, +}; + +/* TODO + {GL_R32UI, RI, U32, FMT("r32u", 32, UINT)}, + {GL_RG32UI, RGI, U32, FMT("rg32u", 32, UINT)}, + {GL_RGB32UI, RGBI, U32, FMT("rgb32u", 32, UINT)}, + {GL_RGBA32UI, RGBAI, U32, FMT("rgba32u", 32, UINT)}, + + {GL_R8I, RI, I8, FMT("r8i", 8, SINT)}, + {GL_RG8I, RGI, I8, FMT("rg8i", 8, SINT)}, + {GL_RGB8I, RGBI, I8, FMT("rgb8i", 8, SINT)}, + {GL_RGBA8I, RGBAI, I8, FMT("rgba8i", 8, SINT)}, + {GL_R16I, RI, I16, FMT("r16i", 16, SINT)}, + {GL_RG16I, RGI, I16, FMT("rg16i", 16, SINT)}, + {GL_RGB16I, RGBI, I16, FMT("rgb16i", 16, SINT)}, + {GL_RGBA16I, RGBAI, I16, FMT("rgba16i", 16, SINT)}, + {GL_R32I, RI, I32, FMT("r32i", 32, SINT)}, + {GL_RG32I, RGI, I32, FMT("rg32i", 32, SINT)}, + {GL_RGB32I, RGBI, I32, FMT("rgb32i", 32, SINT)}, + {GL_RGBA32I, RGBAI, I32, FMT("rgba32i", 32, SINT)}, +*/ + +// GL2 legacy formats +const struct gl_format formats_legacy_gl2[] = { + {GL_RGB8, RGB, U8, FMT("rgb8", 8, UNORM, S|L|V)}, + {GL_RGBA8, RGBA, U8, FMT("rgba8", 8, UNORM, S|L|V)}, + {GL_RGB16, RGB, U16, FMT("rgb16", 16, UNORM, S|L|V)}, + {GL_RGBA16, RGBA, U16, FMT("rgba16", 16, UNORM, S|L|V)}, +}; + +// GLES2 legacy formats +const struct gl_format formats_legacy_gles2[] = { + {GL_RGB, RGB, U8, FMT("rgb", 8, UNORM, S|L)}, + {GL_RGBA, RGBA, U8, FMT("rgba", 8, UNORM, S|L)}, +}; + +// GLES BGRA +const struct gl_format formats_bgra_gles[] = { + {GL_BGRA, BGRA, U8, { + .name = "bgra8", + .type = PL_FMT_UNORM, + .caps = S|L|F|V, + .sample_order = {2, 1, 0, 3}, + .component_depth = {8, 8, 8, 8}, + }}, +}; + +// Fallback for vertex-only formats, as a last resort +const struct gl_format formats_basic_vertex[] = { + {GL_R32F, R, FLT, FMT("r32f", 32, FLOAT, V)}, + {GL_RG32F, RG, FLT, FMT("rg32f", 32, FLOAT, V)}, + {GL_RGB32F, RGB, FLT, FMT("rgb32f", 32, FLOAT, V)}, + {GL_RGBA32F, RGBA, FLT, FMT("rgba32f", 32, FLOAT, V)}, +}; + +static void add_format(pl_gpu pgpu, const struct gl_format *gl_fmt) +{ + struct pl_gpu_t *gpu = (struct pl_gpu_t *) pgpu; + struct pl_gl *p = PL_PRIV(gpu); + + struct pl_fmt_t *fmt = pl_alloc_obj(gpu, fmt, gl_fmt); + const struct gl_format **fmtp = PL_PRIV(fmt); + *fmt = gl_fmt->tmpl; + *fmtp = gl_fmt; + + // Calculate the host size and number of components + switch (gl_fmt->fmt) { + case GL_RED: + case GL_RED_INTEGER: + fmt->num_components = 1; + break; + case GL_RG: + case GL_RG_INTEGER: + fmt->num_components = 2; + break; + case GL_RGB: + case GL_RGB_INTEGER: + fmt->num_components = 3; + break; + case GL_RGBA: + case GL_RGBA_INTEGER: + case GL_BGRA: + fmt->num_components = 4; + break; + default: + pl_unreachable(); + } + + int size; + switch (gl_fmt->type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + size = 1; + break; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + size = 2; + break; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + size = 4; + break; + default: + pl_unreachable(); + } + + // Host visible representation + fmt->texel_size = fmt->num_components * size; + fmt->texel_align = 1; + for (int i = 0; i < fmt->num_components; i++) + fmt->host_bits[i] = size * 8; + + // Compute internal size by summing up the depth + int ibits = 0; + for (int i = 0; i < fmt->num_components; i++) + ibits += fmt->component_depth[i]; + fmt->internal_size = (ibits + 7) / 8; + + // We're not the ones actually emulating these texture format - the + // driver is - but we might as well set the hint. + fmt->emulated = fmt->texel_size != fmt->internal_size; + + // 3-component formats are almost surely also emulated + if (fmt->num_components == 3) + fmt->emulated = true; + + // Older OpenGL most likely emulates 32-bit float formats as well + if (p->gl_ver < 30 && fmt->component_depth[0] >= 32) + fmt->emulated = true; + + // For sanity, clear the superfluous fields + for (int i = fmt->num_components; i < 4; i++) { + fmt->component_depth[i] = 0; + fmt->sample_order[i] = 0; + fmt->host_bits[i] = 0; + } + + fmt->glsl_type = pl_var_glsl_type_name(pl_var_from_fmt(fmt, "")); + fmt->glsl_format = pl_fmt_glsl_format(fmt, fmt->num_components); + fmt->fourcc = pl_fmt_fourcc(fmt); + pl_assert(fmt->glsl_type); + +#ifdef PL_HAVE_UNIX + if (p->has_modifiers && fmt->fourcc && supported_fourcc(p, fmt->fourcc)) { + int num_mods = 0; + bool ok = eglQueryDmaBufModifiersEXT(p->egl_dpy, fmt->fourcc, + 0, NULL, NULL, &num_mods); + if (ok && num_mods) { + // On my system eglQueryDmaBufModifiersEXT seems to never return + // MOD_INVALID even though eglExportDMABUFImageQueryMESA happily + // returns such modifiers. Since we handle INVALID by not + // requiring modifiers at all, always add this value to the + // list of supported modifiers. May result in duplicates, but + // whatever. + uint64_t *mods = pl_calloc(fmt, num_mods + 1, sizeof(uint64_t)); + mods[0] = DRM_FORMAT_MOD_INVALID; + ok = eglQueryDmaBufModifiersEXT(p->egl_dpy, fmt->fourcc, num_mods, + &mods[1], NULL, &num_mods); + + if (ok) { + fmt->modifiers = mods; + fmt->num_modifiers = num_mods + 1; + } else { + pl_free(mods); + } + } + + eglGetError(); // ignore probing errors + } + + if (!fmt->num_modifiers) { + // Hacky fallback for older drivers that don't support properly + // querying modifiers + static const uint64_t static_mods[] = { + DRM_FORMAT_MOD_INVALID, + DRM_FORMAT_MOD_LINEAR, + }; + + fmt->num_modifiers = PL_ARRAY_SIZE(static_mods); + fmt->modifiers = static_mods; + } +#endif + + // Gathering requires checking the format type (and extension presence) + if (fmt->caps & PL_FMT_CAP_SAMPLEABLE) + fmt->gatherable = p->gather_comps >= fmt->num_components; + + // Reading from textures on GLES requires FBO support for this fmt + if (p->has_readback && (p->gl_ver || (fmt->caps & PL_FMT_CAP_RENDERABLE))) + fmt->caps |= PL_FMT_CAP_HOST_READABLE; + + if (gpu->glsl.compute && fmt->glsl_format && p->has_storage) + fmt->caps |= PL_FMT_CAP_STORABLE | PL_FMT_CAP_READWRITE; + + // Only float-type formats are considered blendable in OpenGL + switch (fmt->type) { + case PL_FMT_UNKNOWN: + case PL_FMT_UINT: + case PL_FMT_SINT: + break; + case PL_FMT_FLOAT: + case PL_FMT_UNORM: + case PL_FMT_SNORM: + if (fmt->caps & PL_FMT_CAP_RENDERABLE) + fmt->caps |= PL_FMT_CAP_BLENDABLE; + break; + case PL_FMT_TYPE_COUNT: + pl_unreachable(); + } + + // TODO: Texel buffers + + PL_ARRAY_APPEND_RAW(gpu, gpu->formats, gpu->num_formats, fmt); +} + +#define DO_FORMATS(formats) \ + do { \ + for (int i = 0; i < PL_ARRAY_SIZE(formats); i++) \ + add_format(gpu, &formats[i]); \ + } while (0) + +bool gl_setup_formats(struct pl_gpu_t *gpu) +{ + struct pl_gl *p = PL_PRIV(gpu); + +#ifdef PL_HAVE_UNIX + if (p->has_modifiers) { + EGLint num_formats = 0; + bool ok = eglQueryDmaBufFormatsEXT(p->egl_dpy, 0, NULL, + &num_formats); + if (ok && num_formats) { + p->egl_formats.elem = pl_calloc(gpu, num_formats, sizeof(EGLint)); + p->egl_formats.num = num_formats; + ok = eglQueryDmaBufFormatsEXT(p->egl_dpy, num_formats, + p->egl_formats.elem, &num_formats); + pl_assert(ok); + + PL_DEBUG(gpu, "EGL formats supported:"); + for (int i = 0; i < num_formats; ++i) { + PL_DEBUG(gpu, " 0x%08x(%.4s)", p->egl_formats.elem[i], + PRINT_FOURCC(p->egl_formats.elem[i])); + } + } + } +#endif + + if (p->gl_ver >= 30) { + // Desktop GL3+ has everything + DO_FORMATS(formats_norm8); + DO_FORMATS(formats_bgra8); + DO_FORMATS(formats_norm16); + DO_FORMATS(formats_rgb16_fbo); + DO_FORMATS(formats_float); + DO_FORMATS(formats_uint); + goto done; + } + + if (p->gl_ver >= 21) { + // If we have a reasonable set of extensions, we can enable most + // things. Otherwise, pick simple fallback formats + if (pl_opengl_has_ext(p->gl, "GL_ARB_texture_float") && + pl_opengl_has_ext(p->gl, "GL_ARB_texture_rg") && + pl_opengl_has_ext(p->gl, "GL_ARB_framebuffer_object")) + { + DO_FORMATS(formats_norm8); + DO_FORMATS(formats_bgra8); + DO_FORMATS(formats_norm16); + DO_FORMATS(formats_rgb16_fbo); + DO_FORMATS(formats_float); + } else { + // Fallback for GL2 + DO_FORMATS(formats_legacy_gl2); + DO_FORMATS(formats_basic_vertex); + } + goto done; + } + + if (p->gles_ver >= 30) { + // GLES 3.0 has some basic formats, with framebuffers for float16 + // depending on GL_EXT_color_buffer_(half_)float support + DO_FORMATS(formats_norm8); + if (pl_opengl_has_ext(p->gl, "GL_EXT_texture_norm16")) { + DO_FORMATS(formats_norm16); + DO_FORMATS(formats_rgb16_fallback); + } + if (pl_opengl_has_ext(p->gl, "GL_EXT_texture_format_BGRA8888")) + DO_FORMATS(formats_bgra_gles); + if (pl_opengl_has_ext(p->gl, "GL_EXT_texture_integer")) + DO_FORMATS(formats_uint); + DO_FORMATS(formats_basic_vertex); + if (p->gles_ver >= 32 || pl_opengl_has_ext(p->gl, "GL_EXT_color_buffer_half_float") + || pl_opengl_has_ext(p->gl, "GL_EXT_color_buffer_float")) { + DO_FORMATS(formats_float16_fbo); + } else { + DO_FORMATS(formats_float16_fallback); + } + goto done; + } + + if (p->gles_ver >= 20) { + // GLES 2.0 only has some legacy fallback formats, with support for + // float16 depending on GL_EXT_texture_norm16 being present + DO_FORMATS(formats_legacy_gles2); + DO_FORMATS(formats_basic_vertex); + if (pl_opengl_has_ext(p->gl, "GL_EXT_texture_rg")) { + DO_FORMATS(formats_norm8); + } + if (pl_opengl_has_ext(p->gl, "GL_EXT_texture_format_BGRA8888")) { + DO_FORMATS(formats_bgra_gles); + } + goto done; + } + + // Last resort fallback. Probably not very useful + DO_FORMATS(formats_basic_vertex); + goto done; + +done: + return gl_check_err(gpu, "gl_setup_formats"); +} -- cgit v1.2.3