1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

Implement support for array textures in GL driver

note: feature detection was not implemented in the legacy driver, but the code itself probably works.
This commit is contained in:
sfan5 2025-04-06 22:16:17 +02:00
parent d5bf094f9a
commit 46db688cc8
14 changed files with 111 additions and 72 deletions

View file

@ -132,6 +132,9 @@ enum E_VIDEO_DRIVER_FEATURE
//! Support for multisample textures. //! Support for multisample textures.
EVDF_TEXTURE_MULTISAMPLE, EVDF_TEXTURE_MULTISAMPLE,
//! Support for 2D array textures.
EVDF_TEXTURE_2D_ARRAY,
//! Only used for counting the elements of this enum //! Only used for counting the elements of this enum
EVDF_COUNT EVDF_COUNT
}; };

View file

@ -129,7 +129,10 @@ enum E_TEXTURE_TYPE
ETT_2D_MS, ETT_2D_MS,
//! Cubemap texture. //! Cubemap texture.
ETT_CUBEMAP ETT_CUBEMAP,
//! 2D array texture
ETT_2D_ARRAY
}; };
//! Interface of a Video Driver dependent Texture. //! Interface of a Video Driver dependent Texture.

View file

@ -232,6 +232,15 @@ public:
information. */ information. */
virtual ITexture *addTexture(const io::path &name, IImage *image) = 0; virtual ITexture *addTexture(const io::path &name, IImage *image) = 0;
/**
* Creates an array texture from IImages.
* @param name A name for the texture.
* @param images Pointer to array of images
* @param count Number of images (must be at least 1)
* @return Pointer to the newly created texture
*/
virtual ITexture *addArrayTexture(const io::path &name, IImage **images, u32 count) = 0;
//! Creates a cubemap texture from loaded IImages. //! Creates a cubemap texture from loaded IImages.
/** \param name A name for the texture. Later calls of getTexture() with this name will return this texture. /** \param name A name for the texture. Later calls of getTexture() with this name will return this texture.
The name can _not_ be empty. The name can _not_ be empty.

View file

@ -294,25 +294,9 @@ u32 CNullDriver::getTextureCount() const
ITexture *CNullDriver::addTexture(const core::dimension2d<u32> &size, const io::path &name, ECOLOR_FORMAT format) ITexture *CNullDriver::addTexture(const core::dimension2d<u32> &size, const io::path &name, ECOLOR_FORMAT format)
{ {
if (0 == name.size()) {
os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);
return 0;
}
IImage *image = new CImage(format, size); IImage *image = new CImage(format, size);
ITexture *t = 0; ITexture *t = addTexture(name, image);
if (checkImage(image)) {
t = createDeviceDependentTexture(name, image);
}
image->drop(); image->drop();
if (t) {
addTexture(t);
t->drop();
}
return t; return t;
} }
@ -329,7 +313,8 @@ ITexture *CNullDriver::addTexture(const io::path &name, IImage *image)
ITexture *t = 0; ITexture *t = 0;
if (checkImage(image)) { if (checkImage(image)) {
t = createDeviceDependentTexture(name, image); std::vector tmp { image };
t = createDeviceDependentTexture(name, ETT_2D, tmp);
} }
if (t) { if (t) {
@ -340,6 +325,27 @@ ITexture *CNullDriver::addTexture(const io::path &name, IImage *image)
return t; return t;
} }
ITexture *CNullDriver::addArrayTexture(const io::path &name, IImage **images, u32 count)
{
if (0 == name.size()) {
os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);
return 0;
}
// this is stupid but who cares
std::vector<IImage*> tmp(images, images + count);
ITexture *t = nullptr;
if (checkImage(tmp)) {
t = createDeviceDependentTexture(name, ETT_2D_ARRAY, tmp);
}
if (t) {
addTexture(t);
t->drop();
}
return t;
}
ITexture *CNullDriver::addTextureCubemap(const io::path &name, IImage *imagePosX, IImage *imageNegX, IImage *imagePosY, ITexture *CNullDriver::addTextureCubemap(const io::path &name, IImage *imagePosX, IImage *imageNegX, IImage *imagePosY,
IImage *imageNegY, IImage *imagePosZ, IImage *imageNegZ) IImage *imageNegY, IImage *imagePosZ, IImage *imageNegZ)
{ {
@ -357,7 +363,7 @@ ITexture *CNullDriver::addTextureCubemap(const io::path &name, IImage *imagePosX
imageArray.push_back(imageNegZ); imageArray.push_back(imageNegZ);
if (checkImage(imageArray)) { if (checkImage(imageArray)) {
t = createDeviceDependentTextureCubemap(name, imageArray); t = createDeviceDependentTexture(name, ETT_CUBEMAP, imageArray);
} }
if (t) { if (t) {
@ -384,7 +390,7 @@ ITexture *CNullDriver::addTextureCubemap(const irr::u32 sideLen, const io::path
ITexture *t = 0; ITexture *t = 0;
if (checkImage(imageArray)) { if (checkImage(imageArray)) {
t = createDeviceDependentTextureCubemap(name, imageArray); t = createDeviceDependentTexture(name, ETT_CUBEMAP, imageArray);
if (t) { if (t) {
addTexture(t); addTexture(t);
@ -479,7 +485,8 @@ video::ITexture *CNullDriver::loadTextureFromFile(io::IReadFile *file, const io:
return nullptr; return nullptr;
if (checkImage(image)) { if (checkImage(image)) {
texture = createDeviceDependentTexture(hashName.size() ? hashName : file->getFileName(), image); std::vector tmp { image };
texture = createDeviceDependentTexture(hashName.size() ? hashName : file->getFileName(), ETT_2D, tmp);
if (texture) if (texture)
os::Printer::log("Loaded texture", file->getFileName(), ELL_DEBUG); os::Printer::log("Loaded texture", file->getFileName(), ELL_DEBUG);
} }
@ -519,18 +526,16 @@ video::ITexture *CNullDriver::findTexture(const io::path &filename)
return 0; return 0;
} }
ITexture *CNullDriver::createDeviceDependentTexture(const io::path &name, IImage *image) ITexture *CNullDriver::createDeviceDependentTexture(const io::path &name, E_TEXTURE_TYPE type,
const std::vector<IImage*> &images)
{ {
SDummyTexture *dummy = new SDummyTexture(name, ETT_2D); if (type != ETT_2D && type != ETT_CUBEMAP)
dummy->setSize(image->getDimension()); return nullptr;
SDummyTexture *dummy = new SDummyTexture(name, type);
dummy->setSize(images[0]->getDimension());
return dummy; return dummy;
} }
ITexture *CNullDriver::createDeviceDependentTextureCubemap(const io::path &name, const std::vector<IImage*> &image)
{
return new SDummyTexture(name, ETT_CUBEMAP);
}
bool CNullDriver::setRenderTargetEx(IRenderTarget *target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil) bool CNullDriver::setRenderTargetEx(IRenderTarget *target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
{ {
return false; return false;
@ -883,6 +888,9 @@ bool CNullDriver::checkImage(const std::vector<IImage*> &image) const
auto lastSize = image[0]->getDimension(); auto lastSize = image[0]->getDimension();
for (size_t i = 0; i < image.size(); ++i) { for (size_t i = 0; i < image.size(); ++i) {
if (!image[i])
return false;
ECOLOR_FORMAT format = image[i]->getColorFormat(); ECOLOR_FORMAT format = image[i]->getColorFormat();
auto size = image[i]->getDimension(); auto size = image[i]->getDimension();

View file

@ -84,6 +84,8 @@ public:
ITexture *addTexture(const io::path &name, IImage *image) override; ITexture *addTexture(const io::path &name, IImage *image) override;
ITexture *addArrayTexture(const io::path &name, IImage **images, u32 count) override;
virtual ITexture *addTextureCubemap(const io::path &name, IImage *imagePosX, IImage *imageNegX, IImage *imagePosY, virtual ITexture *addTextureCubemap(const io::path &name, IImage *imagePosX, IImage *imageNegX, IImage *imagePosY,
IImage *imageNegY, IImage *imagePosZ, IImage *imageNegZ) override; IImage *imageNegY, IImage *imagePosZ, IImage *imageNegZ) override;
@ -549,9 +551,8 @@ protected:
//! adds a surface, not loaded or created by the Irrlicht Engine //! adds a surface, not loaded or created by the Irrlicht Engine
void addTexture(ITexture *surface); void addTexture(ITexture *surface);
virtual ITexture *createDeviceDependentTexture(const io::path &name, IImage *image); virtual ITexture *createDeviceDependentTexture(const io::path &name, E_TEXTURE_TYPE type,
const std::vector<IImage*> &images);
virtual ITexture *createDeviceDependentTextureCubemap(const io::path &name, const std::vector<IImage*> &image);
//! checks triangle count and print warning if wrong //! checks triangle count and print warning if wrong
bool checkPrimitiveCount(u32 prmcnt) const; bool checkPrimitiveCount(u32 prmcnt) const;

View file

@ -39,7 +39,8 @@ public:
COGLESCoreExtensionHandler() : COGLESCoreExtensionHandler() :
MaxAnisotropy(1), MaxIndices(0xffff), MaxAnisotropy(1), MaxIndices(0xffff),
MaxTextureSize(1), MaxTextureLODBias(0.f), StencilBuffer(false) MaxTextureSize(1), MaxArrayTextureLayers(1),
MaxTextureLODBias(0.f), StencilBuffer(false)
{ {
for (u32 i = 0; i < IRR_OGLES_Feature_Count; ++i) for (u32 i = 0; i < IRR_OGLES_Feature_Count; ++i)
FeatureAvailable[i] = false; FeatureAvailable[i] = false;
@ -87,6 +88,7 @@ protected:
u8 MaxAnisotropy; u8 MaxAnisotropy;
u32 MaxIndices; u32 MaxIndices;
u32 MaxTextureSize; u32 MaxTextureSize;
u32 MaxArrayTextureLayers;
f32 MaxTextureLODBias; f32 MaxTextureLODBias;
//! Minimal and maximal supported thickness for lines without smoothing //! Minimal and maximal supported thickness for lines without smoothing
float DimAliasedLine[2]; float DimAliasedLine[2];

View file

@ -110,7 +110,7 @@ public:
} }
TEST_GL_ERROR(Driver); TEST_GL_ERROR(Driver);
initTexture(); initTexture(tmpImages->size());
for (size_t i = 0; i < tmpImages->size(); ++i) for (size_t i = 0; i < tmpImages->size(); ++i)
uploadTexture(i, 0, (*tmpImages)[i]->getData()); uploadTexture(i, 0, (*tmpImages)[i]->getData());
@ -142,6 +142,7 @@ public:
MipLevelStored(0) MipLevelStored(0)
{ {
DriverType = Driver->getDriverType(); DriverType = Driver->getDriverType();
_IRR_DEBUG_BREAK_IF(Type == ETT_2D_ARRAY) // not supported by this constructor
TextureType = TextureTypeIrrToGL(Type); TextureType = TextureTypeIrrToGL(Type);
HasMipMaps = false; HasMipMaps = false;
IsRenderTarget = true; IsRenderTarget = true;
@ -208,7 +209,7 @@ public:
StatesCache.WrapW = ETC_CLAMP_TO_EDGE; StatesCache.WrapW = ETC_CLAMP_TO_EDGE;
} }
initTexture(); initTexture(0);
if (!name.empty()) if (!name.empty())
Driver->irrGlObjectLabel(GL_TEXTURE, TextureName, name.c_str()); Driver->irrGlObjectLabel(GL_TEXTURE, TextureName, name.c_str());
@ -265,7 +266,19 @@ public:
const bool use_gl_impl = Driver->Version.Spec != OpenGLSpec::ES; const bool use_gl_impl = Driver->Version.Spec != OpenGLSpec::ES;
#endif #endif
if (use_gl_impl) { if (Type == ETT_2D_ARRAY) {
// For OpenGL an array texture is basically just a 3D texture internally.
// So if we call glGetTexImage() we would download the entire array,
// except the caller only wants a single layer.
// To do this properly we could have to use glGetTextureSubImage() [4.5]
// or some trickery with glTextureView() [4.3].
// Also neither of those will work on GLES.
os::Printer::log("lock: read or read/write unimplemented for ETT_2D_ARRAY", ELL_WARNING);
passed = false;
} else if (use_gl_impl) {
IImage *tmpImage = LockImage; IImage *tmpImage = LockImage;
@ -495,7 +508,7 @@ protected:
Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8; Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8;
} }
void initTexture() void initTexture(u32 layers)
{ {
// Compressed textures cannot be pre-allocated and are initialized on upload // Compressed textures cannot be pre-allocated and are initialized on upload
if (IImage::isCompressedFormat(ColorFormat)) { if (IImage::isCompressedFormat(ColorFormat)) {
@ -554,6 +567,16 @@ protected:
TEST_GL_ERROR(Driver); TEST_GL_ERROR(Driver);
} }
break; break;
case ETT_2D_ARRAY:
if (Driver->getFeature().TexStorage) {
GL.TexStorage3D(TextureType, levels, InternalFormat,
Size.Width, Size.Height, layers);
} else {
GL.TexImage3D(TextureType, 0, InternalFormat,
Size.Width, Size.Height, layers, 0, PixelFormat, PixelType, 0);
}
TEST_GL_ERROR(Driver);
break;
default: default:
_IRR_DEBUG_BREAK_IF(1) _IRR_DEBUG_BREAK_IF(1)
break; break;
@ -591,12 +614,15 @@ protected:
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_CUBE_MAP:
GL.TexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, PixelType, tmpData); GL.TexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, PixelType, tmpData);
TEST_GL_ERROR(Driver); break;
case GL_TEXTURE_2D_ARRAY:
GL.TexSubImage3D(tmpTextureType, level, 0, 0, layer, width, height, 1, PixelFormat, PixelType, tmpData);
break; break;
default: default:
_IRR_DEBUG_BREAK_IF(1) _IRR_DEBUG_BREAK_IF(1)
break; break;
} }
TEST_GL_ERROR(Driver);
delete tmpImage; delete tmpImage;
} else { } else {
@ -606,12 +632,12 @@ protected:
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_CUBE_MAP:
Driver->irrGlCompressedTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, dataSize, data); Driver->irrGlCompressedTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, dataSize, data);
TEST_GL_ERROR(Driver);
break; break;
default: default:
_IRR_DEBUG_BREAK_IF(1) _IRR_DEBUG_BREAK_IF(1)
break; break;
} }
TEST_GL_ERROR(Driver);
} }
} }
@ -624,6 +650,8 @@ protected:
return GL_TEXTURE_2D_MULTISAMPLE; return GL_TEXTURE_2D_MULTISAMPLE;
case ETT_CUBEMAP: case ETT_CUBEMAP:
return GL_TEXTURE_CUBE_MAP; return GL_TEXTURE_CUBE_MAP;
case ETT_2D_ARRAY:
return GL_TEXTURE_2D_ARRAY;
} }
os::Printer::log("COpenGLCoreTexture::TextureTypeIrrToGL unknown texture type", ELL_WARNING); os::Printer::log("COpenGLCoreTexture::TextureTypeIrrToGL unknown texture type", ELL_WARNING);

View file

@ -1609,20 +1609,9 @@ inline void COpenGLDriver::getGLTextureMatrix(GLfloat *o, const core::matrix4 &m
o[15] = 1.f; o[15] = 1.f;
} }
ITexture *COpenGLDriver::createDeviceDependentTexture(const io::path &name, IImage *image) ITexture *COpenGLDriver::createDeviceDependentTexture(const io::path &name, E_TEXTURE_TYPE type, const std::vector<IImage*> &images)
{ {
std::vector tmp { image }; return new COpenGLTexture(name, images, ETT_2D, this);
COpenGLTexture *texture = new COpenGLTexture(name, tmp, ETT_2D, this);
return texture;
}
ITexture *COpenGLDriver::createDeviceDependentTextureCubemap(const io::path &name, const std::vector<IImage *> &image)
{
COpenGLTexture *texture = new COpenGLTexture(name, image, ETT_CUBEMAP, this);
return texture;
} }
void COpenGLDriver::disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag) void COpenGLDriver::disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag)

View file

@ -326,9 +326,7 @@ private:
//! inits the parts of the open gl driver used on all platforms //! inits the parts of the open gl driver used on all platforms
bool genericDriverInit(); bool genericDriverInit();
ITexture *createDeviceDependentTexture(const io::path &name, IImage *image) override; ITexture *createDeviceDependentTexture(const io::path &name, E_TEXTURE_TYPE type, const std::vector<IImage*> &images) override;
ITexture *createDeviceDependentTextureCubemap(const io::path &name, const std::vector<IImage *> &image) override;
//! creates a transposed matrix in supplied GLfloat array to pass to OpenGL //! creates a transposed matrix in supplied GLfloat array to pass to OpenGL
inline void getGLMatrix(GLfloat gl_matrix[16], const core::matrix4 &m); inline void getGLMatrix(GLfloat gl_matrix[16], const core::matrix4 &m);

View file

@ -267,6 +267,7 @@ bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d<u32> &screenS
DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy); DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy);
DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices); DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices);
DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize); DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize);
DriverAttributes->setAttribute("MaxArrayTextureLayers", (s32)MaxArrayTextureLayers);
DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias); DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias);
DriverAttributes->setAttribute("Version", 100 * Version.Major + Version.Minor); DriverAttributes->setAttribute("Version", 100 * Version.Major + Version.Minor);
DriverAttributes->setAttribute("AntiAlias", AntiAlias); DriverAttributes->setAttribute("AntiAlias", AntiAlias);
@ -1072,20 +1073,9 @@ void COpenGL3DriverBase::endDraw(const VertexType &vertexType)
GL.DisableVertexAttribArray(attr.Index); GL.DisableVertexAttribArray(attr.Index);
} }
ITexture *COpenGL3DriverBase::createDeviceDependentTexture(const io::path &name, IImage *image) ITexture *COpenGL3DriverBase::createDeviceDependentTexture(const io::path &name, E_TEXTURE_TYPE type, const std::vector<IImage*> &images)
{ {
std::vector<IImage*> tmp { image }; return new COpenGL3Texture(name, images, type, this);
COpenGL3Texture *texture = new COpenGL3Texture(name, tmp, ETT_2D, this);
return texture;
}
ITexture *COpenGL3DriverBase::createDeviceDependentTextureCubemap(const io::path &name, const std::vector<IImage*> &image)
{
COpenGL3Texture *texture = new COpenGL3Texture(name, image, ETT_CUBEMAP, this);
return texture;
} }
// Same as COpenGLDriver::TextureFlipMatrix // Same as COpenGLDriver::TextureFlipMatrix

View file

@ -267,9 +267,8 @@ protected:
void chooseMaterial2D(); void chooseMaterial2D();
ITexture *createDeviceDependentTexture(const io::path &name, IImage *image) override; ITexture *createDeviceDependentTexture(const io::path &name, E_TEXTURE_TYPE type,
const std::vector<IImage*> &images) override;
ITexture *createDeviceDependentTextureCubemap(const io::path &name, const std::vector<IImage*> &image) override;
//! Map Irrlicht wrap mode to OpenGL enum //! Map Irrlicht wrap mode to OpenGL enum
GLint getTextureWrapMode(u8 clamp) const; GLint getTextureWrapMode(u8 clamp) const;

View file

@ -76,6 +76,8 @@ public:
return StencilBuffer; return StencilBuffer;
case EVDF_TEXTURE_MULTISAMPLE: case EVDF_TEXTURE_MULTISAMPLE:
return TextureMultisampleSupported; return TextureMultisampleSupported;
case EVDF_TEXTURE_2D_ARRAY:
return Texture2DArraySupported;
default: default:
return false; return false;
}; };
@ -176,6 +178,7 @@ public:
bool AnisotropicFilterSupported = false; bool AnisotropicFilterSupported = false;
bool BlendMinMaxSupported = false; bool BlendMinMaxSupported = false;
bool TextureMultisampleSupported = false; bool TextureMultisampleSupported = false;
bool Texture2DArraySupported = false;
bool KHRDebugSupported = false; bool KHRDebugSupported = false;
u32 MaxLabelLength = 0; u32 MaxLabelLength = 0;
}; };

View file

@ -71,6 +71,7 @@ void COpenGL3Driver::initFeatures()
LODBiasSupported = true; LODBiasSupported = true;
BlendMinMaxSupported = true; BlendMinMaxSupported = true;
TextureMultisampleSupported = true; TextureMultisampleSupported = true;
Texture2DArraySupported = Version.Major >= 3 || queryExtension("GL_EXT_texture_array");
KHRDebugSupported = isVersionAtLeast(4, 6) || queryExtension("GL_KHR_debug"); KHRDebugSupported = isVersionAtLeast(4, 6) || queryExtension("GL_KHR_debug");
if (KHRDebugSupported) if (KHRDebugSupported)
MaxLabelLength = GetInteger(GL.MAX_LABEL_LENGTH); MaxLabelLength = GetInteger(GL.MAX_LABEL_LENGTH);
@ -88,6 +89,8 @@ void COpenGL3Driver::initFeatures()
MaxAnisotropy = GetInteger(GL.MAX_TEXTURE_MAX_ANISOTROPY); MaxAnisotropy = GetInteger(GL.MAX_TEXTURE_MAX_ANISOTROPY);
MaxIndices = GetInteger(GL_MAX_ELEMENTS_INDICES); MaxIndices = GetInteger(GL_MAX_ELEMENTS_INDICES);
MaxTextureSize = GetInteger(GL_MAX_TEXTURE_SIZE); MaxTextureSize = GetInteger(GL_MAX_TEXTURE_SIZE);
if (Texture2DArraySupported)
MaxArrayTextureLayers = GetInteger(GL_MAX_ARRAY_TEXTURE_LAYERS);
GL.GetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &MaxTextureLODBias); GL.GetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &MaxTextureLODBias);
GL.GetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, DimAliasedLine); GL.GetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, DimAliasedLine);
DimAliasedPoint[0] = 1.0f; DimAliasedPoint[0] = 1.0f;

View file

@ -124,6 +124,7 @@ void COpenGLES2Driver::initFeatures()
AnisotropicFilterSupported = queryExtension("GL_EXT_texture_filter_anisotropic"); AnisotropicFilterSupported = queryExtension("GL_EXT_texture_filter_anisotropic");
BlendMinMaxSupported = (Version.Major >= 3) || FeatureAvailable[IRR_GL_EXT_blend_minmax]; BlendMinMaxSupported = (Version.Major >= 3) || FeatureAvailable[IRR_GL_EXT_blend_minmax];
TextureMultisampleSupported = isVersionAtLeast(3, 1); TextureMultisampleSupported = isVersionAtLeast(3, 1);
Texture2DArraySupported = Version.Major >= 3 || queryExtension("GL_EXT_texture_array");
KHRDebugSupported = queryExtension("GL_KHR_debug"); KHRDebugSupported = queryExtension("GL_KHR_debug");
if (KHRDebugSupported) if (KHRDebugSupported)
MaxLabelLength = GetInteger(GL.MAX_LABEL_LENGTH); MaxLabelLength = GetInteger(GL.MAX_LABEL_LENGTH);
@ -145,6 +146,8 @@ void COpenGLES2Driver::initFeatures()
if (Version.Major >= 3 || queryExtension("GL_EXT_draw_range_elements")) if (Version.Major >= 3 || queryExtension("GL_EXT_draw_range_elements"))
MaxIndices = GetInteger(GL_MAX_ELEMENTS_INDICES); MaxIndices = GetInteger(GL_MAX_ELEMENTS_INDICES);
MaxTextureSize = GetInteger(GL_MAX_TEXTURE_SIZE); MaxTextureSize = GetInteger(GL_MAX_TEXTURE_SIZE);
if (Texture2DArraySupported)
MaxArrayTextureLayers = GetInteger(GL_MAX_ARRAY_TEXTURE_LAYERS);
if (LODBiasSupported) if (LODBiasSupported)
GL.GetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &MaxTextureLODBias); GL.GetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &MaxTextureLODBias);
GL.GetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, DimAliasedLine); GL.GetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, DimAliasedLine);