2024-09-05 16:40:28 +02:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2024 Collabora, Ltd.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
|
* a copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
|
* the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the
|
|
|
|
|
* next paragraph) shall be included in all copies or substantial
|
|
|
|
|
* portions of the Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
* SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include "shared/xalloc.h"
|
|
|
|
|
#include "gl-renderer.h"
|
|
|
|
|
#include "gl-renderer-internal.h"
|
|
|
|
|
|
2024-09-05 17:31:44 +02:00
|
|
|
/*
|
|
|
|
|
* Table 1: List of OpenGL ES 3 sized internal colour formats allowed for
|
|
|
|
|
* texture and FBO creation. Built from Table 3.13 in the OpenGL ES 3.0 and 3.1
|
|
|
|
|
* specs and from Table 8.10 in the OpenGL ES 3.2 spec.
|
|
|
|
|
*
|
|
|
|
|
* ┌─────────────────────┬─────┬─────┬─────┬─────────────────┬──────────────────────────────────┐
|
|
|
|
|
* │ Internal fmt¹ │ T² │ F³ │ R⁴ │ External fmt⁵ │ External type(s)⁵ │
|
|
|
|
|
* ╞═════════════════════╪═════╪═════╪═════╪═════════════════╪══════════════════════════════════╡
|
|
|
|
|
* │ GL_R8 │ 3.0 │ 3.0 │ 3.0 │ GL_RED │ GL_UNSIGNED_BYTE │
|
|
|
|
|
* │ GL_R8_SNORM │ 3.0 │ 3.0 │ │ GL_RED │ GL_BYTE │
|
|
|
|
|
* │ GL_R16F │ 3.0 │ 3.0 │ 3.2 │ GL_RED │ GL_HALF_FLOAT, │
|
|
|
|
|
* │ │ │ │ │ │ GL_FLOAT │
|
|
|
|
|
* │ GL_R32F │ 3.0 │ │ 3.2 │ GL_RED │ GL_FLOAT │
|
|
|
|
|
* │ GL_R8UI │ 3.0 │ │ 3.0 │ GL_RED_INTEGER │ GL_UNSIGNED_BYTE │
|
|
|
|
|
* │ GL_R8I │ 3.0 │ │ 3.0 │ GL_RED_INTEGER │ GL_BYTE │
|
|
|
|
|
* │ GL_R16UI │ 3.0 │ │ 3.0 │ GL_RED_INTEGER │ GL_UNSIGNED_SHORT │
|
|
|
|
|
* │ GL_R16I │ 3.0 │ │ 3.0 │ GL_RED_INTEGER │ GL_SHORT │
|
|
|
|
|
* │ GL_R32UI │ 3.0 │ │ 3.0 │ GL_RED_INTEGER │ GL_UNSIGNED_INT │
|
|
|
|
|
* │ GL_R32I │ 3.0 │ │ 3.0 │ GL_RED_INTEGER │ GL_INT │
|
|
|
|
|
* │ GL_RG8 │ 3.0 │ 3.0 │ 3.0 │ GL_RG │ GL_UNSIGNED_BYTE │
|
|
|
|
|
* │ GL_RG8_SNORM │ 3.0 │ 3.0 │ │ GL_RG │ GL_BYTE │
|
|
|
|
|
* │ GL_RG16F │ 3.0 │ 3.0 │ 3.2 │ GL_RG │ GL_HALF_FLOAT, │
|
|
|
|
|
* │ │ │ │ │ │ GL_FLOAT │
|
|
|
|
|
* │ GL_RG32F │ 3.0 │ │ 3.2 │ GL_RG │ GL_FLOAT │
|
|
|
|
|
* │ GL_RG8UI │ 3.0 │ │ 3.0 │ GL_RG_INTEGER │ GL_UNSIGNED_BYTE │
|
|
|
|
|
* │ GL_RG8I │ 3.0 │ │ 3.0 │ GL_RG_INTEGER │ GL_BYTE │
|
|
|
|
|
* │ GL_RG16UI │ 3.0 │ │ 3.0 │ GL_RG_INTEGER │ GL_UNSIGNED_SHORT │
|
|
|
|
|
* │ GL_RG16I │ 3.0 │ │ 3.0 │ GL_RG_INTEGER │ GL_SHORT │
|
|
|
|
|
* │ GL_RG32UI │ 3.0 │ │ 3.0 │ GL_RG_INTEGER │ GL_UNSIGNED_INT │
|
|
|
|
|
* │ GL_RG32I │ 3.0 │ │ 3.0 │ GL_RG_INTEGER │ GL_INT │
|
|
|
|
|
* │ GL_RGB8 │ 3.0 │ 3.0 │ 3.0 │ GL_RGB │ GL_UNSIGNED_BYTE │
|
|
|
|
|
* │ GL_SRGB8 │ 3.0 │ 3.0 │ │ GL_RGB │ GL_UNSIGNED_BYTE │
|
|
|
|
|
* │ GL_RGB565 │ 3.0 │ 3.0 │ 3.0 │ GL_RGB │ GL_UNSIGNED_BYTE, │
|
|
|
|
|
* │ │ │ │ │ │ GL_UNSIGNED_SHORT_5_6_5 │
|
|
|
|
|
* │ GL_RGB8_SNORM │ 3.0 │ 3.0 │ │ GL_RGB │ GL_BYTE │
|
|
|
|
|
* │ GL_R11F_G11F_B10F │ 3.0 │ 3.0 │ 3.2 │ GL_RGB │ GL_UNSIGNED_INT_10F_11F_11F_REV, │
|
|
|
|
|
* │ │ │ │ │ │ GL_HALF_FLOAT, │
|
|
|
|
|
* │ │ │ │ │ │ GL_FLOAT │
|
|
|
|
|
* │ GL_RGB9_E5 │ 3.0 │ 3.0 │ │ GL_RGB │ GL_UNSIGNED_INT_5_9_9_9_REV, │
|
|
|
|
|
* │ │ │ │ │ │ GL_HALF_FLOAT, │
|
|
|
|
|
* │ │ │ │ │ │ GL_FLOAT │
|
2024-09-12 15:52:39 +02:00
|
|
|
* │ GL_RGB16F │ 3.0 │ 3.0 │ E⁶ │ GL_RGB │ GL_HALF_FLOAT, │
|
2024-09-05 17:31:44 +02:00
|
|
|
* │ │ │ │ │ │ GL_FLOAT │
|
|
|
|
|
* │ GL_RGB32F │ 3.0 │ │ │ GL_RGB │ GL_FLOAT │
|
|
|
|
|
* │ GL_RGB8UI │ 3.0 │ │ │ GL_RGB_INTEGER │ GL_UNSIGNED_BYTE │
|
|
|
|
|
* │ GL_RGB8I │ 3.0 │ │ │ GL_RGB_INTEGER │ GL_BYTE │
|
|
|
|
|
* │ GL_RGB16UI │ 3.0 │ │ │ GL_RGB_INTEGER │ GL_UNSIGNED_SHORT │
|
|
|
|
|
* │ GL_RGB16I │ 3.0 │ │ │ GL_RGB_INTEGER │ GL_SHORT │
|
|
|
|
|
* │ GL_RGB32UI │ 3.0 │ │ │ GL_RGB_INTEGER │ GL_UNSIGNED_INT │
|
|
|
|
|
* │ GL_RGB32I │ 3.0 │ │ │ GL_RGB_INTEGER │ GL_INT │
|
|
|
|
|
* │ GL_RGBA8 │ 3.0 │ 3.0 │ 3.0 │ GL_RGBA │ GL_UNSIGNED_BYTE │
|
|
|
|
|
* │ GL_SRGB8_ALPHA8 │ 3.0 │ 3.0 │ 3.0 │ GL_RGBA │ GL_UNSIGNED_BYTE │
|
|
|
|
|
* │ GL_RGBA8_SNORM │ 3.0 │ 3.0 │ │ GL_RGBA │ GL_BYTE │
|
|
|
|
|
* │ GL_RGB5_A1 │ 3.0 │ 3.0 │ 3.0 │ GL_RGBA │ GL_UNSIGNED_BYTE, │
|
|
|
|
|
* │ │ │ │ │ │ GL_UNSIGNED_SHORT_5_5_5_1, │
|
|
|
|
|
* │ │ │ │ │ │ GL_UNSIGNED_INT_2_10_10_10_REV │
|
|
|
|
|
* │ GL_RGBA4 │ 3.0 │ 3.0 │ 3.0 │ GL_RGBA │ GL_UNSIGNED_BYTE, │
|
|
|
|
|
* │ │ │ │ │ │ GL_UNSIGNED_SHORT_4_4_4_4 │
|
|
|
|
|
* │ GL_RGB10_A2 │ 3.0 │ 3.0 │ 3.0 │ GL_RGBA │ GL_UNSIGNED_INT_2_10_10_10_REV │
|
|
|
|
|
* │ GL_RGBA16F │ 3.0 │ 3.0 │ 3.2 │ GL_RGBA │ GL_HALF_FLOAT, │
|
|
|
|
|
* │ │ │ │ │ │ GL_FLOAT │
|
|
|
|
|
* │ GL_RGBA32F │ 3.0 │ │ 3.2 │ GL_RGBA │ GL_FLOAT │
|
|
|
|
|
* │ GL_RGBA8UI │ 3.0 │ │ 3.0 │ GL_RGBA_INTEGER │ GL_UNSIGNED_BYTE │
|
|
|
|
|
* │ GL_RGBA8I │ 3.0 │ │ 3.0 │ GL_RGBA_INTEGER │ GL_BYTE │
|
|
|
|
|
* │ GL_RGB10_A2UI │ 3.0 │ │ 3.0 │ GL_RGBA_INTEGER │ GL_UNSIGNED_INT_2_10_10_10_REV │
|
|
|
|
|
* │ GL_RGBA16UI │ 3.0 │ │ 3.0 │ GL_RGBA_INTEGER │ GL_UNSIGNED_SHORT │
|
|
|
|
|
* │ GL_RGBA16I │ 3.0 │ │ 3.0 │ GL_RGBA_INTEGER │ GL_SHORT │
|
|
|
|
|
* │ GL_RGBA32I │ 3.0 │ │ 3.0 │ GL_RGBA_INTEGER │ GL_INT │
|
|
|
|
|
* │ GL_RGBA32UI │ 3.0 │ │ 3.0 │ GL_RGBA_INTEGER │ GL_UNSIGNED_INT │
|
|
|
|
|
* └─────────────────────┴─────┴─────┴─────┴─────────────────┴──────────────────────────────────┘
|
|
|
|
|
*
|
|
|
|
|
* ¹ Sized internal format.
|
|
|
|
|
* ² Texturable since.
|
|
|
|
|
* ³ Texture-filterable (GL_LINEAR support) since.
|
|
|
|
|
* ⁴ Renderable (FBO support) since.
|
|
|
|
|
* ⁵ External format and type combination(s).
|
2024-09-12 15:52:39 +02:00
|
|
|
* ⁶ Supported via extensions.
|
2024-09-05 17:31:44 +02:00
|
|
|
*/
|
|
|
|
|
|
2024-09-06 16:07:34 +02:00
|
|
|
#if !defined(NDEBUG)
|
|
|
|
|
|
|
|
|
|
/* Validate an external format for a given OpenGL ES 3 sized internal colour
|
|
|
|
|
* format. Based on Table 1 above.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
is_valid_format_es3(struct gl_renderer *gr,
|
|
|
|
|
GLenum internal_format,
|
|
|
|
|
GLenum external_format)
|
|
|
|
|
{
|
|
|
|
|
assert(gr->gl_version >= gl_version(3, 0));
|
|
|
|
|
|
|
|
|
|
switch (internal_format) {
|
|
|
|
|
case GL_R8I:
|
|
|
|
|
case GL_R8UI:
|
|
|
|
|
case GL_R16I:
|
|
|
|
|
case GL_R16UI:
|
|
|
|
|
case GL_R32I:
|
|
|
|
|
case GL_R32UI:
|
|
|
|
|
return external_format == GL_RED_INTEGER;
|
|
|
|
|
|
|
|
|
|
case GL_R8:
|
|
|
|
|
case GL_R8_SNORM:
|
|
|
|
|
case GL_R16F:
|
|
|
|
|
case GL_R32F:
|
|
|
|
|
return external_format == GL_RED;
|
|
|
|
|
|
|
|
|
|
case GL_RG8I:
|
|
|
|
|
case GL_RG8UI:
|
|
|
|
|
case GL_RG16I:
|
|
|
|
|
case GL_RG16UI:
|
|
|
|
|
case GL_RG32I:
|
|
|
|
|
case GL_RG32UI:
|
|
|
|
|
return external_format == GL_RG_INTEGER;
|
|
|
|
|
|
|
|
|
|
case GL_RG8:
|
|
|
|
|
case GL_RG8_SNORM:
|
|
|
|
|
case GL_RG16F:
|
|
|
|
|
case GL_RG32F:
|
|
|
|
|
return external_format == GL_RG;
|
|
|
|
|
|
|
|
|
|
case GL_RGB8I:
|
|
|
|
|
case GL_RGB8UI:
|
|
|
|
|
case GL_RGB16I:
|
|
|
|
|
case GL_RGB16UI:
|
|
|
|
|
case GL_RGB32I:
|
|
|
|
|
case GL_RGB32UI:
|
|
|
|
|
return external_format == GL_RGB_INTEGER;
|
|
|
|
|
|
|
|
|
|
case GL_RGB8:
|
|
|
|
|
case GL_RGB8_SNORM:
|
|
|
|
|
case GL_RGB16F:
|
|
|
|
|
case GL_RGB32F:
|
|
|
|
|
case GL_R11F_G11F_B10F:
|
|
|
|
|
case GL_RGB9_E5:
|
|
|
|
|
case GL_RGB565:
|
|
|
|
|
case GL_SRGB8:
|
|
|
|
|
return external_format == GL_RGB;
|
|
|
|
|
|
|
|
|
|
case GL_RGBA8I:
|
|
|
|
|
case GL_RGBA8UI:
|
|
|
|
|
case GL_RGBA16I:
|
|
|
|
|
case GL_RGBA16UI:
|
|
|
|
|
case GL_RGBA32I:
|
|
|
|
|
case GL_RGBA32UI:
|
|
|
|
|
case GL_RGB10_A2UI:
|
|
|
|
|
return external_format == GL_RGBA_INTEGER;
|
|
|
|
|
|
|
|
|
|
case GL_RGBA8:
|
|
|
|
|
case GL_RGBA8_SNORM:
|
|
|
|
|
case GL_RGBA16F:
|
|
|
|
|
case GL_RGBA32F:
|
|
|
|
|
case GL_RGB10_A2:
|
|
|
|
|
case GL_SRGB8_ALPHA8:
|
|
|
|
|
case GL_RGB5_A1:
|
|
|
|
|
case GL_RGBA4:
|
|
|
|
|
return external_format == GL_RGBA;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Validate an external type for a given OpenGL ES 3 sized internal colour
|
|
|
|
|
* format. Based on Table 1 above.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
is_valid_type_es3(struct gl_renderer *gr,
|
|
|
|
|
GLenum internal_format,
|
|
|
|
|
GLenum type)
|
|
|
|
|
{
|
|
|
|
|
assert(gr->gl_version >= gl_version(3, 0));
|
|
|
|
|
|
|
|
|
|
switch (internal_format) {
|
|
|
|
|
case GL_R8:
|
|
|
|
|
case GL_R8UI:
|
|
|
|
|
case GL_RG8:
|
|
|
|
|
case GL_RG8UI:
|
|
|
|
|
case GL_RGB8:
|
|
|
|
|
case GL_RGB8UI:
|
|
|
|
|
case GL_RGBA8:
|
|
|
|
|
case GL_RGBA8UI:
|
|
|
|
|
case GL_SRGB8:
|
|
|
|
|
case GL_SRGB8_ALPHA8:
|
|
|
|
|
return type == GL_UNSIGNED_BYTE;
|
|
|
|
|
|
|
|
|
|
case GL_R8I:
|
|
|
|
|
case GL_R8_SNORM:
|
|
|
|
|
case GL_RG8I:
|
|
|
|
|
case GL_RG8_SNORM:
|
|
|
|
|
case GL_RGB8I:
|
|
|
|
|
case GL_RGB8_SNORM:
|
|
|
|
|
case GL_RGBA8I:
|
|
|
|
|
case GL_RGBA8_SNORM:
|
|
|
|
|
return type == GL_BYTE;
|
|
|
|
|
|
|
|
|
|
case GL_R16UI:
|
|
|
|
|
case GL_RG16UI:
|
|
|
|
|
case GL_RGB16UI:
|
|
|
|
|
case GL_RGBA16UI:
|
|
|
|
|
return type == GL_UNSIGNED_SHORT;
|
|
|
|
|
|
|
|
|
|
case GL_R16I:
|
|
|
|
|
case GL_RG16I:
|
|
|
|
|
case GL_RGB16I:
|
|
|
|
|
case GL_RGBA16I:
|
|
|
|
|
return type == GL_SHORT;
|
|
|
|
|
|
|
|
|
|
case GL_R32UI:
|
|
|
|
|
case GL_RG32UI:
|
|
|
|
|
case GL_RGB32UI:
|
|
|
|
|
case GL_RGBA32UI:
|
|
|
|
|
return type == GL_UNSIGNED_INT;
|
|
|
|
|
|
|
|
|
|
case GL_RGB10_A2UI:
|
|
|
|
|
return type == GL_UNSIGNED_INT_2_10_10_10_REV;
|
|
|
|
|
|
|
|
|
|
case GL_R32I:
|
|
|
|
|
case GL_RG32I:
|
|
|
|
|
case GL_RGB32I:
|
|
|
|
|
case GL_RGBA32I:
|
|
|
|
|
return type == GL_INT;
|
|
|
|
|
|
|
|
|
|
case GL_R32F:
|
|
|
|
|
case GL_RG32F:
|
|
|
|
|
case GL_RGB32F:
|
|
|
|
|
case GL_RGBA32F:
|
|
|
|
|
return type == GL_FLOAT;
|
|
|
|
|
|
|
|
|
|
case GL_R16F:
|
|
|
|
|
case GL_RG16F:
|
|
|
|
|
case GL_RGB16F:
|
|
|
|
|
case GL_RGBA16F:
|
|
|
|
|
return type == GL_HALF_FLOAT ||
|
|
|
|
|
type == GL_FLOAT;
|
|
|
|
|
|
|
|
|
|
case GL_RGB565:
|
|
|
|
|
return type == GL_UNSIGNED_BYTE ||
|
|
|
|
|
type == GL_UNSIGNED_SHORT_5_6_5;
|
|
|
|
|
|
|
|
|
|
case GL_R11F_G11F_B10F:
|
|
|
|
|
return type == GL_UNSIGNED_INT_10F_11F_11F_REV ||
|
|
|
|
|
type == GL_HALF_FLOAT ||
|
|
|
|
|
type == GL_FLOAT;
|
|
|
|
|
|
|
|
|
|
case GL_RGB9_E5:
|
|
|
|
|
return type == GL_UNSIGNED_INT_5_9_9_9_REV ||
|
|
|
|
|
type == GL_HALF_FLOAT ||
|
|
|
|
|
type == GL_FLOAT;
|
|
|
|
|
|
|
|
|
|
case GL_RGB5_A1:
|
|
|
|
|
return type == GL_UNSIGNED_BYTE ||
|
|
|
|
|
type == GL_UNSIGNED_SHORT_5_5_5_1 ||
|
|
|
|
|
type == GL_UNSIGNED_INT_2_10_10_10_REV;
|
|
|
|
|
|
|
|
|
|
case GL_RGBA4:
|
|
|
|
|
return type == GL_UNSIGNED_BYTE ||
|
|
|
|
|
type == GL_UNSIGNED_SHORT_4_4_4_4;
|
|
|
|
|
|
|
|
|
|
case GL_RGB10_A2:
|
|
|
|
|
return type == GL_UNSIGNED_INT_2_10_10_10_REV;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Validate an external format and type combination for OpenGL ES 3.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
is_valid_combination_es3(struct gl_renderer *gr,
|
|
|
|
|
GLenum external_format,
|
|
|
|
|
GLenum type)
|
|
|
|
|
{
|
|
|
|
|
assert(gr->gl_version >= gl_version(3, 0));
|
|
|
|
|
|
|
|
|
|
switch (external_format) {
|
|
|
|
|
case GL_RED:
|
|
|
|
|
case GL_RG:
|
|
|
|
|
switch (type) {
|
|
|
|
|
case GL_UNSIGNED_BYTE:
|
|
|
|
|
case GL_BYTE:
|
|
|
|
|
case GL_HALF_FLOAT:
|
|
|
|
|
case GL_FLOAT:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case GL_RED_INTEGER:
|
|
|
|
|
case GL_RG_INTEGER:
|
|
|
|
|
case GL_RGB_INTEGER:
|
|
|
|
|
switch (type) {
|
|
|
|
|
case GL_UNSIGNED_BYTE:
|
|
|
|
|
case GL_BYTE:
|
|
|
|
|
case GL_UNSIGNED_SHORT:
|
|
|
|
|
case GL_SHORT:
|
|
|
|
|
case GL_UNSIGNED_INT:
|
|
|
|
|
case GL_INT:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case GL_RGB:
|
|
|
|
|
switch (type) {
|
|
|
|
|
case GL_UNSIGNED_BYTE:
|
|
|
|
|
case GL_BYTE:
|
|
|
|
|
case GL_UNSIGNED_SHORT_5_6_5:
|
|
|
|
|
case GL_UNSIGNED_INT_10F_11F_11F_REV:
|
|
|
|
|
case GL_UNSIGNED_INT_5_9_9_9_REV:
|
|
|
|
|
case GL_HALF_FLOAT:
|
|
|
|
|
case GL_FLOAT:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case GL_RGBA:
|
|
|
|
|
switch (type) {
|
|
|
|
|
case GL_UNSIGNED_BYTE:
|
|
|
|
|
case GL_BYTE:
|
|
|
|
|
case GL_UNSIGNED_SHORT_4_4_4_4:
|
|
|
|
|
case GL_UNSIGNED_SHORT_5_5_5_1:
|
|
|
|
|
case GL_UNSIGNED_INT_2_10_10_10_REV:
|
|
|
|
|
case GL_HALF_FLOAT:
|
|
|
|
|
case GL_FLOAT:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case GL_RGBA_INTEGER:
|
|
|
|
|
switch (type) {
|
|
|
|
|
case GL_UNSIGNED_BYTE:
|
|
|
|
|
case GL_BYTE:
|
|
|
|
|
case GL_UNSIGNED_SHORT:
|
|
|
|
|
case GL_SHORT:
|
|
|
|
|
case GL_UNSIGNED_INT:
|
|
|
|
|
case GL_INT:
|
|
|
|
|
case GL_UNSIGNED_INT_2_10_10_10_REV:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-08 21:52:01 +02:00
|
|
|
/* Validate an external format and type combination for OpenGL ES 2.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
is_valid_combination_es2(struct gl_renderer *gr,
|
|
|
|
|
GLenum external_format,
|
|
|
|
|
GLenum type)
|
|
|
|
|
{
|
|
|
|
|
assert(gr->gl_version == gl_version(2, 0));
|
|
|
|
|
|
|
|
|
|
switch (external_format) {
|
|
|
|
|
case GL_ALPHA:
|
|
|
|
|
case GL_LUMINANCE:
|
|
|
|
|
case GL_LUMINANCE_ALPHA:
|
2024-09-12 12:24:14 +02:00
|
|
|
switch (type) {
|
|
|
|
|
case GL_UNSIGNED_BYTE:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case GL_HALF_FLOAT_OES:
|
|
|
|
|
return gl_extensions_has(gr, EXTENSION_OES_TEXTURE_HALF_FLOAT);
|
|
|
|
|
|
2024-09-12 14:03:13 +02:00
|
|
|
case GL_FLOAT:
|
|
|
|
|
return gl_extensions_has(gr, EXTENSION_OES_TEXTURE_FLOAT);
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-09-08 21:52:01 +02:00
|
|
|
|
2024-09-12 09:10:54 +02:00
|
|
|
case GL_RED:
|
|
|
|
|
case GL_RG:
|
2024-09-12 12:24:14 +02:00
|
|
|
switch (type) {
|
|
|
|
|
case GL_UNSIGNED_BYTE:
|
|
|
|
|
return gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_RG);
|
|
|
|
|
|
|
|
|
|
case GL_HALF_FLOAT_OES:
|
|
|
|
|
return gl_extensions_has(gr, EXTENSION_OES_TEXTURE_HALF_FLOAT) &&
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_RG);
|
|
|
|
|
|
2024-09-12 14:03:13 +02:00
|
|
|
case GL_FLOAT:
|
|
|
|
|
return gl_extensions_has(gr, EXTENSION_OES_TEXTURE_FLOAT) &&
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_RG);
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-09-12 09:10:54 +02:00
|
|
|
|
2024-09-08 21:52:01 +02:00
|
|
|
case GL_RGB:
|
2024-09-12 12:24:14 +02:00
|
|
|
switch (type) {
|
|
|
|
|
case GL_UNSIGNED_BYTE:
|
|
|
|
|
case GL_UNSIGNED_SHORT_5_6_5:
|
|
|
|
|
return true;
|
|
|
|
|
|
2024-09-19 15:51:48 +02:00
|
|
|
case GL_UNSIGNED_INT_10F_11F_11F_REV:
|
2024-09-19 16:26:02 +02:00
|
|
|
return gl_extensions_has(gr, EXTENSION_NV_PACKED_FLOAT) ||
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_APPLE_TEXTURE_PACKED_FLOAT);
|
|
|
|
|
|
|
|
|
|
case GL_UNSIGNED_INT_5_9_9_9_REV:
|
|
|
|
|
return gl_extensions_has(gr, EXTENSION_APPLE_TEXTURE_PACKED_FLOAT);
|
2024-09-19 15:51:48 +02:00
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
case GL_HALF_FLOAT_OES:
|
|
|
|
|
return gl_extensions_has(gr, EXTENSION_OES_TEXTURE_HALF_FLOAT);
|
|
|
|
|
|
2024-09-12 14:03:13 +02:00
|
|
|
case GL_FLOAT:
|
|
|
|
|
return gl_extensions_has(gr, EXTENSION_OES_TEXTURE_FLOAT);
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-09-08 21:52:01 +02:00
|
|
|
|
|
|
|
|
case GL_RGBA:
|
2024-09-12 12:24:14 +02:00
|
|
|
switch (type) {
|
|
|
|
|
case GL_UNSIGNED_BYTE:
|
|
|
|
|
case GL_UNSIGNED_SHORT_4_4_4_4:
|
|
|
|
|
case GL_UNSIGNED_SHORT_5_5_5_1:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case GL_HALF_FLOAT_OES:
|
|
|
|
|
return gl_extensions_has(gr, EXTENSION_OES_TEXTURE_HALF_FLOAT);
|
|
|
|
|
|
2024-09-12 14:03:13 +02:00
|
|
|
case GL_FLOAT:
|
|
|
|
|
return gl_extensions_has(gr, EXTENSION_OES_TEXTURE_FLOAT);
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-09-08 21:52:01 +02:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-06 16:07:34 +02:00
|
|
|
#endif /* !defined(NDEBUG) */
|
|
|
|
|
|
|
|
|
|
/* Check whether gl_texture_2d_init() supports texture creation for a given
|
|
|
|
|
* coloured sized internal format or not.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
gl_texture_is_format_supported(struct gl_renderer *gr,
|
|
|
|
|
GLenum format)
|
|
|
|
|
{
|
|
|
|
|
switch (format) {
|
2024-09-08 21:52:01 +02:00
|
|
|
case GL_R8:
|
|
|
|
|
case GL_RG8:
|
|
|
|
|
case GL_RGB8:
|
|
|
|
|
case GL_RGB565:
|
|
|
|
|
case GL_RGBA8:
|
|
|
|
|
case GL_RGB5_A1:
|
|
|
|
|
case GL_RGBA4:
|
|
|
|
|
return true;
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
case GL_R16F:
|
|
|
|
|
case GL_RG16F:
|
|
|
|
|
case GL_RGB16F:
|
|
|
|
|
case GL_RGBA16F:
|
|
|
|
|
return gr->gl_version >= gl_version(3, 0) ||
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_OES_TEXTURE_HALF_FLOAT);
|
|
|
|
|
|
2024-09-12 14:03:13 +02:00
|
|
|
case GL_R32F:
|
|
|
|
|
case GL_RG32F:
|
|
|
|
|
case GL_RGB32F:
|
|
|
|
|
case GL_RGBA32F:
|
|
|
|
|
return gr->gl_version >= gl_version(3, 0) ||
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_OES_TEXTURE_FLOAT);
|
|
|
|
|
|
2024-09-19 15:51:48 +02:00
|
|
|
case GL_R11F_G11F_B10F:
|
|
|
|
|
return gr->gl_version >= gl_version(3, 0) ||
|
2024-09-19 16:26:02 +02:00
|
|
|
gl_extensions_has(gr, EXTENSION_NV_PACKED_FLOAT) ||
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_APPLE_TEXTURE_PACKED_FLOAT);
|
|
|
|
|
|
|
|
|
|
case GL_RGB9_E5:
|
|
|
|
|
return gr->gl_version >= gl_version(3, 0) ||
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_APPLE_TEXTURE_PACKED_FLOAT);
|
2024-09-19 15:51:48 +02:00
|
|
|
|
2024-09-06 16:07:34 +02:00
|
|
|
case GL_R8I:
|
|
|
|
|
case GL_R8UI:
|
|
|
|
|
case GL_R8_SNORM:
|
|
|
|
|
case GL_R16I:
|
|
|
|
|
case GL_R16UI:
|
|
|
|
|
case GL_R32I:
|
|
|
|
|
case GL_R32UI:
|
|
|
|
|
case GL_RG8I:
|
|
|
|
|
case GL_RG8UI:
|
|
|
|
|
case GL_RG8_SNORM:
|
|
|
|
|
case GL_RG16I:
|
|
|
|
|
case GL_RG16UI:
|
|
|
|
|
case GL_RG32I:
|
|
|
|
|
case GL_RG32UI:
|
|
|
|
|
case GL_RGB8I:
|
|
|
|
|
case GL_RGB8UI:
|
|
|
|
|
case GL_RGB8_SNORM:
|
|
|
|
|
case GL_RGB16I:
|
|
|
|
|
case GL_RGB16UI:
|
|
|
|
|
case GL_RGB32I:
|
|
|
|
|
case GL_RGB32UI:
|
|
|
|
|
case GL_SRGB8:
|
|
|
|
|
case GL_RGBA8I:
|
|
|
|
|
case GL_RGBA8UI:
|
|
|
|
|
case GL_RGBA8_SNORM:
|
|
|
|
|
case GL_RGBA16I:
|
|
|
|
|
case GL_RGBA16UI:
|
|
|
|
|
case GL_RGBA32I:
|
|
|
|
|
case GL_RGBA32UI:
|
|
|
|
|
case GL_RGB10_A2:
|
|
|
|
|
case GL_RGB10_A2UI:
|
|
|
|
|
case GL_SRGB8_ALPHA8:
|
|
|
|
|
return gr->gl_version >= gl_version(3, 0);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Unsupported sized internal format!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialise a 2D texture object. 'format' is a coloured sized internal format
|
|
|
|
|
* listed in Table 1 above with the Texturable column filled. The texture object
|
|
|
|
|
* is left bound on the 2D texture target of the current texture unit on
|
|
|
|
|
* success. No texture parameters are set. Use gl_texture_fini() to finalise.
|
|
|
|
|
*
|
2024-09-08 21:52:01 +02:00
|
|
|
* OpenGL ES 2 notes:
|
|
|
|
|
*
|
|
|
|
|
* Implementations support at least this subset of formats: GL_R8, GL_RG8,
|
2024-09-12 12:24:14 +02:00
|
|
|
* GL_RGB8, GL_RGB565, GL_RGBA8, GL_RGBA4 and GL_RGB5_A1. Additional formats are
|
2024-09-12 14:03:13 +02:00
|
|
|
* supported depending on extensions: GL_R16F, GL_RG16F, GL_RGB16F, GL_RGBA16F,
|
2024-09-19 16:26:02 +02:00
|
|
|
* GL_R32F, GL_RG32F, GL_RGB32F, GL_RGBA32F, GL_R11F_G11F_B10F and GL_RGB9_E5.
|
2024-09-08 21:52:01 +02:00
|
|
|
*
|
|
|
|
|
* This is implemented by implicitly converting 'format' into an external
|
2024-09-12 09:10:54 +02:00
|
|
|
* format. If the red and red-green texture formats aren't supported
|
|
|
|
|
* (FEATURE_TEXTURE_RG flag not set), GL_R8 is converted into a luminance format
|
|
|
|
|
* and GL_RG8 into a luminance alpha format. Care must be taken in the latter
|
|
|
|
|
* case in order to access the green component in the shader: "c.a" (or "c[3]")
|
|
|
|
|
* must be used instead of "c.g" (or "c[1]").
|
2024-09-08 21:52:01 +02:00
|
|
|
*
|
2024-09-06 16:07:34 +02:00
|
|
|
* See gl_texture_is_format_supported().
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
gl_texture_2d_init(struct gl_renderer *gr,
|
|
|
|
|
int levels,
|
|
|
|
|
GLenum format,
|
|
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
GLuint *tex_out)
|
|
|
|
|
{
|
|
|
|
|
GLuint tex;
|
|
|
|
|
|
|
|
|
|
assert(width > 0);
|
|
|
|
|
assert(height > 0);
|
|
|
|
|
assert(levels <= (int) log2(MAX(width, height)) + 1);
|
|
|
|
|
|
|
|
|
|
if (!gl_texture_is_format_supported(gr, format)) {
|
|
|
|
|
weston_log("Error: texture format not supported.\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glGenTextures(1, &tex);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex);
|
2024-09-08 21:52:01 +02:00
|
|
|
|
2024-09-09 19:00:23 +02:00
|
|
|
if (gl_features_has(gr, FEATURE_TEXTURE_IMMUTABILITY)) {
|
2024-09-12 09:10:54 +02:00
|
|
|
if (!gl_features_has(gr, FEATURE_TEXTURE_RG)) {
|
2024-09-12 12:24:14 +02:00
|
|
|
switch (format) {
|
|
|
|
|
case GL_R8:
|
2024-09-09 19:00:23 +02:00
|
|
|
format = GL_LUMINANCE8_EXT;
|
2024-09-12 12:24:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GL_R16F:
|
|
|
|
|
format = GL_LUMINANCE16F_EXT;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 14:03:13 +02:00
|
|
|
case GL_R32F:
|
|
|
|
|
format = GL_LUMINANCE32F_EXT;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
case GL_RG8:
|
2024-09-09 19:00:23 +02:00
|
|
|
format = GL_LUMINANCE8_ALPHA8_EXT;
|
2024-09-12 12:24:14 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GL_RG16F:
|
|
|
|
|
format = GL_LUMINANCE_ALPHA16F_EXT;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 14:03:13 +02:00
|
|
|
case GL_RG32F:
|
|
|
|
|
format = GL_LUMINANCE_ALPHA32F_EXT;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-09-09 19:00:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gr->tex_storage_2d(GL_TEXTURE_2D, levels, format, width,
|
|
|
|
|
height);
|
2024-09-08 21:52:01 +02:00
|
|
|
} else {
|
|
|
|
|
GLenum type;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* Implicit conversion to external format for supported
|
|
|
|
|
* subset. */
|
|
|
|
|
switch (format) {
|
|
|
|
|
case GL_R8:
|
2024-09-12 09:10:54 +02:00
|
|
|
format = gl_features_has(gr, FEATURE_TEXTURE_RG) ?
|
|
|
|
|
GL_RED : GL_LUMINANCE;
|
2024-09-08 21:52:01 +02:00
|
|
|
type = GL_UNSIGNED_BYTE;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
case GL_R16F:
|
|
|
|
|
format = gl_features_has(gr, FEATURE_TEXTURE_RG) ?
|
|
|
|
|
GL_RED : GL_LUMINANCE;
|
|
|
|
|
type = GL_HALF_FLOAT_OES;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 14:03:13 +02:00
|
|
|
case GL_R32F:
|
|
|
|
|
format = gl_features_has(gr, FEATURE_TEXTURE_RG) ?
|
|
|
|
|
GL_RED : GL_LUMINANCE;
|
|
|
|
|
type = GL_FLOAT;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-08 21:52:01 +02:00
|
|
|
case GL_RG8:
|
2024-09-12 09:10:54 +02:00
|
|
|
format = gl_features_has(gr, FEATURE_TEXTURE_RG) ?
|
|
|
|
|
GL_RG : GL_LUMINANCE_ALPHA;
|
2024-09-08 21:52:01 +02:00
|
|
|
type = GL_UNSIGNED_BYTE;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
case GL_RG16F:
|
|
|
|
|
format = gl_features_has(gr, FEATURE_TEXTURE_RG) ?
|
|
|
|
|
GL_RG : GL_LUMINANCE_ALPHA;
|
|
|
|
|
type = GL_HALF_FLOAT_OES;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 14:03:13 +02:00
|
|
|
case GL_RG32F:
|
|
|
|
|
format = gl_features_has(gr, FEATURE_TEXTURE_RG) ?
|
|
|
|
|
GL_RG : GL_LUMINANCE_ALPHA;
|
|
|
|
|
type = GL_FLOAT;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-08 21:52:01 +02:00
|
|
|
case GL_RGB8:
|
|
|
|
|
format = GL_RGB;
|
|
|
|
|
type = GL_UNSIGNED_BYTE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GL_RGB565:
|
|
|
|
|
format = GL_RGB;
|
|
|
|
|
type = GL_UNSIGNED_SHORT_5_6_5;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
case GL_RGB16F:
|
|
|
|
|
format = GL_RGB;
|
|
|
|
|
type = GL_HALF_FLOAT_OES;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 14:03:13 +02:00
|
|
|
case GL_RGB32F:
|
|
|
|
|
format = GL_RGB;
|
|
|
|
|
type = GL_FLOAT;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-19 15:51:48 +02:00
|
|
|
case GL_R11F_G11F_B10F:
|
|
|
|
|
format = GL_RGB;
|
|
|
|
|
type = GL_UNSIGNED_INT_10F_11F_11F_REV;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-19 16:26:02 +02:00
|
|
|
case GL_RGB9_E5:
|
|
|
|
|
format = GL_RGB;
|
|
|
|
|
type = GL_UNSIGNED_INT_5_9_9_9_REV;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-08 21:52:01 +02:00
|
|
|
case GL_RGBA8:
|
|
|
|
|
format = GL_RGBA;
|
|
|
|
|
type = GL_UNSIGNED_BYTE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GL_RGBA4:
|
|
|
|
|
format = GL_RGBA;
|
|
|
|
|
type = GL_UNSIGNED_SHORT_4_4_4_4;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GL_RGB5_A1:
|
|
|
|
|
format = GL_RGBA;
|
|
|
|
|
type = GL_UNSIGNED_SHORT_5_5_5_1;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
case GL_RGBA16F:
|
|
|
|
|
format = GL_RGBA;
|
|
|
|
|
type = GL_HALF_FLOAT_OES;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-12 14:03:13 +02:00
|
|
|
case GL_RGBA32F:
|
|
|
|
|
format = GL_RGBA;
|
|
|
|
|
type = GL_FLOAT;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-09-08 21:52:01 +02:00
|
|
|
default:
|
|
|
|
|
unreachable("Missing conversion to external format!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allocate storage. */
|
|
|
|
|
for (i = 0; i < levels; i++) {
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, i, format, width, height, 0,
|
|
|
|
|
format, type, NULL);
|
|
|
|
|
width = MAX(width / 2, 1);
|
|
|
|
|
height = MAX(height / 2, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-09-06 16:07:34 +02:00
|
|
|
|
|
|
|
|
*tex_out = tex;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Store data into the texture object bound to the 2D texture target of the
|
|
|
|
|
* current texture unit. 'format' and 'type' must be a valid external format and
|
|
|
|
|
* type combination for the internal format of the texture object as listed in
|
|
|
|
|
* Table 1 above. The texture object is left bound. No texture parameters are
|
|
|
|
|
* set.
|
|
|
|
|
*
|
2024-09-08 21:52:01 +02:00
|
|
|
* OpenGL ES 2 notes:
|
|
|
|
|
*
|
|
|
|
|
* Table 2: List of invalid external format and type combinations from Table 1
|
|
|
|
|
* for the supported subset of formats.
|
|
|
|
|
*
|
|
|
|
|
* ┌───────────────────────┬─────────────────┬────────────────────────────────┐
|
|
|
|
|
* │ Sized internal format │ External format │ Type(s) │
|
|
|
|
|
* ╞═══════════════════════╪═════════════════╪════════════════════════════════╡
|
|
|
|
|
* │ GL_RGB565 │ GL_RGB │ GL_UNSIGNED_BYTE │
|
2024-09-19 15:51:48 +02:00
|
|
|
* │ GL_R11F_G11F_B10F │ GL_RGB │ GL_HALF_FLOAT, │
|
|
|
|
|
* │ │ │ GL_FLOAT │
|
2024-09-19 16:26:02 +02:00
|
|
|
* │ GL_RGB9_E5 │ GL_RGB │ GL_HALF_FLOAT, │
|
|
|
|
|
* │ │ │ GL_FLOAT │
|
2024-09-08 21:52:01 +02:00
|
|
|
* │ GL_RGBA4 │ GL_RGBA │ GL_UNSIGNED_BYTE │
|
|
|
|
|
* │ GL_RGB5_A1 │ GL_RGBA │ GL_UNSIGNED_BYTE, │
|
|
|
|
|
* │ │ │ GL_UNSIGNED_INT_2_10_10_10_REV │
|
|
|
|
|
* └───────────────────────┴─────────────────┴────────────────────────────────┘
|
|
|
|
|
*
|
2024-09-06 16:07:34 +02:00
|
|
|
* See gl_texture_2d_init().
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gl_texture_2d_store(struct gl_renderer *gr,
|
|
|
|
|
int level,
|
|
|
|
|
int x,
|
|
|
|
|
int y,
|
|
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
GLenum format,
|
|
|
|
|
GLenum type,
|
|
|
|
|
const void *data)
|
|
|
|
|
{
|
|
|
|
|
#if !defined(NDEBUG)
|
|
|
|
|
GLint tex, tex_width, tex_height, tex_internal_format;
|
2024-09-08 21:52:01 +02:00
|
|
|
#endif
|
2024-09-06 16:07:34 +02:00
|
|
|
|
2024-09-12 09:10:54 +02:00
|
|
|
if (!gl_features_has(gr, FEATURE_TEXTURE_RG)) {
|
2024-09-08 21:52:01 +02:00
|
|
|
if (format == GL_RED)
|
|
|
|
|
format = GL_LUMINANCE;
|
|
|
|
|
else if (format == GL_RG)
|
|
|
|
|
format = GL_LUMINANCE_ALPHA;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-12 12:24:14 +02:00
|
|
|
if (type == GL_HALF_FLOAT && gr->gl_version == gl_version(2, 0))
|
|
|
|
|
type = GL_HALF_FLOAT_OES;
|
|
|
|
|
|
2024-09-08 21:52:01 +02:00
|
|
|
#if !defined(NDEBUG)
|
2024-09-06 16:07:34 +02:00
|
|
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex);
|
|
|
|
|
assert(tex != 0);
|
|
|
|
|
|
2024-09-08 21:52:01 +02:00
|
|
|
if (gr->gl_version == gl_version(2, 0)) {
|
|
|
|
|
assert(is_valid_combination_es2(gr, format, type));
|
|
|
|
|
} else if (gr->gl_version == gl_version(3, 0)) {
|
2024-09-06 16:07:34 +02:00
|
|
|
assert(is_valid_combination_es3(gr, format, type));
|
|
|
|
|
} else if (gr->gl_version >= gl_version(3, 1)) {
|
|
|
|
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
|
|
|
|
|
GL_TEXTURE_WIDTH, &tex_width);
|
|
|
|
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
|
|
|
|
|
GL_TEXTURE_HEIGHT, &tex_height);
|
|
|
|
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
|
|
|
|
|
GL_TEXTURE_INTERNAL_FORMAT,
|
|
|
|
|
&tex_internal_format);
|
|
|
|
|
assert(level >= 0);
|
|
|
|
|
assert(x >= 0);
|
|
|
|
|
assert(y >= 0);
|
|
|
|
|
assert(x + width <= tex_width);
|
|
|
|
|
assert(y + height <= tex_height);
|
|
|
|
|
assert(is_valid_format_es3(gr, tex_internal_format, format));
|
|
|
|
|
assert(is_valid_type_es3(gr, tex_internal_format, type));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, level, x, y, width, height, format, type,
|
|
|
|
|
data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finalise a texture object.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gl_texture_fini(GLuint *tex)
|
|
|
|
|
{
|
|
|
|
|
glDeleteTextures(1, tex);
|
|
|
|
|
*tex = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-16 16:52:11 +02:00
|
|
|
/* Check whether gl_fbo_init() supports FBO creation for a given
|
|
|
|
|
* colour-renderable sized internal 'format' or not.
|
2024-09-05 16:40:28 +02:00
|
|
|
*/
|
|
|
|
|
bool
|
2024-08-16 16:52:11 +02:00
|
|
|
gl_fbo_is_format_supported(struct gl_renderer *gr,
|
|
|
|
|
GLenum format)
|
|
|
|
|
{
|
|
|
|
|
switch (format) {
|
|
|
|
|
case GL_RGBA4:
|
|
|
|
|
case GL_RGB5_A1:
|
|
|
|
|
case GL_RGB565:
|
|
|
|
|
return true; /* From OpenGL ES 2.0 (Table 4.5 in spec). */
|
|
|
|
|
|
2024-09-12 09:10:54 +02:00
|
|
|
case GL_R8:
|
|
|
|
|
case GL_RG8:
|
|
|
|
|
return gr->gl_version >= gl_version(3, 0) ||
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_EXT_TEXTURE_RG);
|
|
|
|
|
|
2024-08-16 16:52:11 +02:00
|
|
|
case GL_RGB8:
|
|
|
|
|
case GL_RGBA8:
|
|
|
|
|
return gr->gl_version >= gl_version(3, 0) ||
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_OES_RGB8_RGBA8);
|
|
|
|
|
|
|
|
|
|
case GL_SRGB8_ALPHA8:
|
|
|
|
|
case GL_R8I:
|
|
|
|
|
case GL_R8UI:
|
|
|
|
|
case GL_R16I:
|
|
|
|
|
case GL_R16UI:
|
|
|
|
|
case GL_R32I:
|
|
|
|
|
case GL_R32UI:
|
|
|
|
|
case GL_RG8I:
|
|
|
|
|
case GL_RG8UI:
|
|
|
|
|
case GL_RG16I:
|
|
|
|
|
case GL_RG16UI:
|
|
|
|
|
case GL_RG32I:
|
|
|
|
|
case GL_RG32UI:
|
|
|
|
|
case GL_RGBA8I:
|
|
|
|
|
case GL_RGBA8UI:
|
|
|
|
|
case GL_RGBA16I:
|
|
|
|
|
case GL_RGBA16UI:
|
|
|
|
|
case GL_RGBA32I:
|
|
|
|
|
case GL_RGBA32UI:
|
|
|
|
|
case GL_RGB10_A2:
|
|
|
|
|
case GL_RGB10_A2UI:
|
|
|
|
|
return gr->gl_version >= gl_version(3, 0);
|
|
|
|
|
|
|
|
|
|
case GL_R16F:
|
|
|
|
|
case GL_RG16F:
|
|
|
|
|
case GL_RGBA16F:
|
2024-09-12 15:52:39 +02:00
|
|
|
return gr->gl_version >= gl_version(3, 2) ||
|
2024-09-12 16:22:16 +02:00
|
|
|
gl_extensions_has(gr, EXTENSION_EXT_COLOR_BUFFER_FLOAT) ||
|
2024-09-12 15:52:39 +02:00
|
|
|
gl_extensions_has(gr, EXTENSION_EXT_COLOR_BUFFER_HALF_FLOAT);
|
|
|
|
|
|
|
|
|
|
case GL_RGB16F:
|
|
|
|
|
return gl_extensions_has(gr, EXTENSION_EXT_COLOR_BUFFER_HALF_FLOAT);
|
|
|
|
|
|
2024-08-16 16:52:11 +02:00
|
|
|
case GL_R32F:
|
|
|
|
|
case GL_RG32F:
|
|
|
|
|
case GL_RGBA32F:
|
2024-09-12 16:22:16 +02:00
|
|
|
return gr->gl_version >= gl_version(3, 2) ||
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_EXT_COLOR_BUFFER_FLOAT);
|
2024-08-16 16:52:11 +02:00
|
|
|
|
2024-09-19 15:51:48 +02:00
|
|
|
case GL_R11F_G11F_B10F:
|
|
|
|
|
return gr->gl_version >= gl_version(3, 2) ||
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_EXT_COLOR_BUFFER_FLOAT) ||
|
|
|
|
|
(gl_extensions_has(gr, EXTENSION_NV_PACKED_FLOAT) &&
|
|
|
|
|
gl_extensions_has(gr, EXTENSION_EXT_COLOR_BUFFER_HALF_FLOAT));
|
|
|
|
|
|
2024-08-16 16:52:11 +02:00
|
|
|
case GL_R8_SNORM:
|
|
|
|
|
case GL_RG8_SNORM:
|
|
|
|
|
case GL_SRGB8:
|
|
|
|
|
case GL_RGB9_E5:
|
|
|
|
|
case GL_RGB32F:
|
|
|
|
|
case GL_RGB8_SNORM:
|
|
|
|
|
case GL_RGB8I:
|
|
|
|
|
case GL_RGB8UI:
|
|
|
|
|
case GL_RGB16I:
|
|
|
|
|
case GL_RGB16UI:
|
|
|
|
|
case GL_RGB32I:
|
|
|
|
|
case GL_RGB32UI:
|
|
|
|
|
case GL_RGBA8_SNORM:
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Unsupported sized internal format!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialise a pair of framebuffer and renderbuffer objects. 'format' is a
|
|
|
|
|
* colour-renderable sized internal format listed in Table 1 above with the
|
|
|
|
|
* Renderable column filled. The framebuffer object is left bound on success.
|
|
|
|
|
* Use gl_fbo_fini() to finalise.
|
|
|
|
|
*
|
|
|
|
|
* OpenGL ES 2 notes:
|
|
|
|
|
*
|
|
|
|
|
* Implementations support at least these formats: GL_RGBA4, GL_RGB5_A1 and
|
2024-09-12 09:10:54 +02:00
|
|
|
* GL_RGB565. Additional formats are supported depending on extensions: GL_R8,
|
2024-09-19 15:51:48 +02:00
|
|
|
* GL_RG8, GL_RGB8, GL_RGBA8, GL_R16F, GL_RG16F, GL_RGB16F, GL_RGBA16F and
|
|
|
|
|
* GL_R11F_G11F_B10F.
|
2024-08-16 16:52:11 +02:00
|
|
|
*
|
|
|
|
|
* See gl_fbo_is_format_supported().
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
gl_fbo_init(struct gl_renderer *gr,
|
|
|
|
|
GLenum format,
|
2024-09-05 16:40:28 +02:00
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
GLuint *fb_out,
|
|
|
|
|
GLuint *rb_out)
|
|
|
|
|
{
|
|
|
|
|
GLuint fb, rb;
|
|
|
|
|
GLenum status;
|
|
|
|
|
|
2024-08-16 16:52:11 +02:00
|
|
|
if (!gl_fbo_is_format_supported(gr, format)) {
|
|
|
|
|
weston_log("Error: FBO format not supported.\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-05 16:40:28 +02:00
|
|
|
glGenFramebuffers(1, &fb);
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fb);
|
|
|
|
|
glGenRenderbuffers(1, &rb);
|
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, rb);
|
2024-08-16 16:52:11 +02:00
|
|
|
glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
|
2024-09-05 16:40:28 +02:00
|
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
|
|
|
|
GL_RENDERBUFFER, rb);
|
|
|
|
|
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
|
|
|
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
|
|
|
|
weston_log("Error: FBO incomplete.\n");
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*fb_out = fb;
|
|
|
|
|
*rb_out = rb;
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
glDeleteFramebuffers(1, &fb);
|
|
|
|
|
glDeleteRenderbuffers(1, &rb);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finalise a pair of framebuffer and renderbuffer objects.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gl_fbo_fini(GLuint *fb,
|
|
|
|
|
GLuint *rb)
|
|
|
|
|
{
|
|
|
|
|
glDeleteFramebuffers(1, fb);
|
|
|
|
|
glDeleteRenderbuffers(1, rb);
|
|
|
|
|
*fb = 0;
|
|
|
|
|
*rb = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialise a pair of framebuffer and renderbuffer objects to render into an
|
|
|
|
|
* EGL image. The framebuffer object is left bound on success. Use gl_fbo_fini()
|
|
|
|
|
* to finalise.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
gl_fbo_image_init(struct gl_renderer *gr,
|
|
|
|
|
EGLImageKHR image,
|
|
|
|
|
GLuint *fb_out,
|
|
|
|
|
GLuint *rb_out)
|
|
|
|
|
{
|
|
|
|
|
GLuint fb, rb;
|
|
|
|
|
GLenum status;
|
|
|
|
|
|
2024-10-18 16:12:11 +02:00
|
|
|
if (!gl_extensions_has(gr, EXTENSION_OES_EGL_IMAGE)) {
|
|
|
|
|
weston_log("Error: FBO from EGLImage not supported.\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-05 16:40:28 +02:00
|
|
|
glGenFramebuffers(1, &fb);
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fb);
|
|
|
|
|
glGenRenderbuffers(1, &rb);
|
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, rb);
|
|
|
|
|
gr->image_target_renderbuffer_storage(GL_RENDERBUFFER, image);
|
|
|
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
|
|
|
|
GL_RENDERBUFFER, rb);
|
|
|
|
|
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
|
|
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
|
|
|
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
|
|
|
|
weston_log("Error: FBO incomplete.\n");
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*fb_out = fb;
|
|
|
|
|
*rb_out = rb;
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
glDeleteFramebuffers(1, &fb);
|
|
|
|
|
glDeleteRenderbuffers(1, &rb);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialise a pair of framebuffer and texture objects to render into a
|
|
|
|
|
* texture. The framebuffer object is left bound on success. Use
|
|
|
|
|
* gl_fbo_texture_fini() to finalise.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
gl_fbo_texture_init(GLenum internal_format,
|
|
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
GLenum format,
|
|
|
|
|
GLenum type,
|
|
|
|
|
GLuint *fb_out,
|
|
|
|
|
GLuint *tex_out)
|
|
|
|
|
{
|
|
|
|
|
GLenum status;
|
|
|
|
|
GLuint fb, tex;
|
|
|
|
|
|
|
|
|
|
glGenTextures(1, &tex);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex);
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0,
|
|
|
|
|
format, type, NULL);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
|
glGenFramebuffers(1, &fb);
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fb);
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
|
|
|
|
GL_TEXTURE_2D, tex, 0);
|
|
|
|
|
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
|
|
|
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
|
|
|
|
weston_log("Error: FBO incomplete.\n");
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*fb_out = fb;
|
|
|
|
|
*tex_out = tex;
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
glDeleteFramebuffers(1, &fb);
|
|
|
|
|
glDeleteTextures(1, &tex);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finalise a pair of framebuffer and texture objects.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gl_fbo_texture_fini(GLuint *fb,
|
|
|
|
|
GLuint *tex)
|
|
|
|
|
{
|
|
|
|
|
glDeleteFramebuffers(1, fb);
|
|
|
|
|
glDeleteTextures(1, tex);
|
|
|
|
|
*fb = 0;
|
|
|
|
|
*tex = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add extension flags to the bitfield that 'flags_out' points to. 'table'
|
|
|
|
|
* stores extension names and flags to check for and 'extensions' is the list
|
|
|
|
|
* usually returned by the EGL or GL implementation. New flags are stored using
|
|
|
|
|
* a binary OR in order to keep flags set from a previous call. Caller must
|
|
|
|
|
* ensure the bitfield is set to 0 at first call.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
gl_extensions_add(const struct gl_extension_table *table,
|
|
|
|
|
const char *extensions,
|
|
|
|
|
uint64_t *flags_out)
|
|
|
|
|
{
|
|
|
|
|
struct { const char *str; size_t len; } *map;
|
|
|
|
|
size_t i = 0, n = 0;
|
|
|
|
|
uint64_t flags = 0;
|
|
|
|
|
char prev_char = ' ';
|
|
|
|
|
|
|
|
|
|
/* Get number of extensions. */
|
|
|
|
|
while (extensions[i]) {
|
|
|
|
|
if (prev_char == ' ' && extensions[i] != ' ')
|
|
|
|
|
n++;
|
|
|
|
|
prev_char = extensions[i++];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Allocate data structure mapping each extension with their length. */
|
|
|
|
|
map = xmalloc(n * sizeof *map);
|
|
|
|
|
prev_char = ' ';
|
|
|
|
|
i = n = 0;
|
|
|
|
|
while (prev_char) {
|
|
|
|
|
if (extensions[i] != ' ' && extensions[i] != '\0') {
|
|
|
|
|
if (prev_char == ' ')
|
|
|
|
|
map[n].str = &extensions[i];
|
|
|
|
|
} else if (prev_char != ' ') {
|
|
|
|
|
map[n].len = &extensions[i] - map[n].str;
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
prev_char = extensions[i++];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Match extensions with table. */
|
|
|
|
|
for (; table->str; table++) {
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
|
if (table->len == map[i].len &&
|
|
|
|
|
!strncmp(table->str, map[i].str, table->len)) {
|
|
|
|
|
flags |= table->flag;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*flags_out |= flags;
|
|
|
|
|
free(map);
|
|
|
|
|
}
|