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.
EVDF_TEXTURE_MULTISAMPLE,
//! Support for 2D array textures.
EVDF_TEXTURE_2D_ARRAY,
//! Only used for counting the elements of this enum
EVDF_COUNT
};

View file

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

View file

@ -232,6 +232,15 @@ public:
information. */
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.
/** \param name A name for the texture. Later calls of getTexture() with this name will return this texture.
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)
{
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);
ITexture *t = 0;
if (checkImage(image)) {
t = createDeviceDependentTexture(name, image);
}
ITexture *t = addTexture(name, image);
image->drop();
if (t) {
addTexture(t);
t->drop();
}
return t;
}
@ -329,7 +313,8 @@ ITexture *CNullDriver::addTexture(const io::path &name, IImage *image)
ITexture *t = 0;
if (checkImage(image)) {
t = createDeviceDependentTexture(name, image);
std::vector tmp { image };
t = createDeviceDependentTexture(name, ETT_2D, tmp);
}
if (t) {
@ -340,6 +325,27 @@ ITexture *CNullDriver::addTexture(const io::path &name, IImage *image)
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,
IImage *imageNegY, IImage *imagePosZ, IImage *imageNegZ)
{
@ -357,7 +363,7 @@ ITexture *CNullDriver::addTextureCubemap(const io::path &name, IImage *imagePosX
imageArray.push_back(imageNegZ);
if (checkImage(imageArray)) {
t = createDeviceDependentTextureCubemap(name, imageArray);
t = createDeviceDependentTexture(name, ETT_CUBEMAP, imageArray);
}
if (t) {
@ -384,7 +390,7 @@ ITexture *CNullDriver::addTextureCubemap(const irr::u32 sideLen, const io::path
ITexture *t = 0;
if (checkImage(imageArray)) {
t = createDeviceDependentTextureCubemap(name, imageArray);
t = createDeviceDependentTexture(name, ETT_CUBEMAP, imageArray);
if (t) {
addTexture(t);
@ -479,7 +485,8 @@ video::ITexture *CNullDriver::loadTextureFromFile(io::IReadFile *file, const io:
return nullptr;
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)
os::Printer::log("Loaded texture", file->getFileName(), ELL_DEBUG);
}
@ -519,18 +526,16 @@ video::ITexture *CNullDriver::findTexture(const io::path &filename)
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);
dummy->setSize(image->getDimension());
if (type != ETT_2D && type != ETT_CUBEMAP)
return nullptr;
SDummyTexture *dummy = new SDummyTexture(name, type);
dummy->setSize(images[0]->getDimension());
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)
{
return false;
@ -883,6 +888,9 @@ bool CNullDriver::checkImage(const std::vector<IImage*> &image) const
auto lastSize = image[0]->getDimension();
for (size_t i = 0; i < image.size(); ++i) {
if (!image[i])
return false;
ECOLOR_FORMAT format = image[i]->getColorFormat();
auto size = image[i]->getDimension();

View file

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

View file

@ -39,7 +39,8 @@ public:
COGLESCoreExtensionHandler() :
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)
FeatureAvailable[i] = false;
@ -87,6 +88,7 @@ protected:
u8 MaxAnisotropy;
u32 MaxIndices;
u32 MaxTextureSize;
u32 MaxArrayTextureLayers;
f32 MaxTextureLODBias;
//! Minimal and maximal supported thickness for lines without smoothing
float DimAliasedLine[2];

View file

@ -110,7 +110,7 @@ public:
}
TEST_GL_ERROR(Driver);
initTexture();
initTexture(tmpImages->size());
for (size_t i = 0; i < tmpImages->size(); ++i)
uploadTexture(i, 0, (*tmpImages)[i]->getData());
@ -142,6 +142,7 @@ public:
MipLevelStored(0)
{
DriverType = Driver->getDriverType();
_IRR_DEBUG_BREAK_IF(Type == ETT_2D_ARRAY) // not supported by this constructor
TextureType = TextureTypeIrrToGL(Type);
HasMipMaps = false;
IsRenderTarget = true;
@ -208,7 +209,7 @@ public:
StatesCache.WrapW = ETC_CLAMP_TO_EDGE;
}
initTexture();
initTexture(0);
if (!name.empty())
Driver->irrGlObjectLabel(GL_TEXTURE, TextureName, name.c_str());
@ -265,7 +266,19 @@ public:
const bool use_gl_impl = Driver->Version.Spec != OpenGLSpec::ES;
#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;
@ -495,7 +508,7 @@ protected:
Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8;
}
void initTexture()
void initTexture(u32 layers)
{
// Compressed textures cannot be pre-allocated and are initialized on upload
if (IImage::isCompressedFormat(ColorFormat)) {
@ -554,6 +567,16 @@ protected:
TEST_GL_ERROR(Driver);
}
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:
_IRR_DEBUG_BREAK_IF(1)
break;
@ -591,12 +614,15 @@ protected:
case GL_TEXTURE_2D:
case GL_TEXTURE_CUBE_MAP:
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;
default:
_IRR_DEBUG_BREAK_IF(1)
break;
}
TEST_GL_ERROR(Driver);
delete tmpImage;
} else {
@ -606,12 +632,12 @@ protected:
case GL_TEXTURE_2D:
case GL_TEXTURE_CUBE_MAP:
Driver->irrGlCompressedTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, dataSize, data);
TEST_GL_ERROR(Driver);
break;
default:
_IRR_DEBUG_BREAK_IF(1)
break;
}
TEST_GL_ERROR(Driver);
}
}
@ -624,6 +650,8 @@ protected:
return GL_TEXTURE_2D_MULTISAMPLE;
case ETT_CUBEMAP:
return GL_TEXTURE_CUBE_MAP;
case ETT_2D_ARRAY:
return GL_TEXTURE_2D_ARRAY;
}
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;
}
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 };
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;
return new COpenGLTexture(name, images, ETT_2D, this);
}
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
bool genericDriverInit();
ITexture *createDeviceDependentTexture(const io::path &name, IImage *image) override;
ITexture *createDeviceDependentTextureCubemap(const io::path &name, const std::vector<IImage *> &image) override;
ITexture *createDeviceDependentTexture(const io::path &name, E_TEXTURE_TYPE type, const std::vector<IImage*> &images) override;
//! creates a transposed matrix in supplied GLfloat array to pass to OpenGL
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("MaxIndices", (s32)MaxIndices);
DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize);
DriverAttributes->setAttribute("MaxArrayTextureLayers", (s32)MaxArrayTextureLayers);
DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias);
DriverAttributes->setAttribute("Version", 100 * Version.Major + Version.Minor);
DriverAttributes->setAttribute("AntiAlias", AntiAlias);
@ -1072,20 +1073,9 @@ void COpenGL3DriverBase::endDraw(const VertexType &vertexType)
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 };
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;
return new COpenGL3Texture(name, images, type, this);
}
// Same as COpenGLDriver::TextureFlipMatrix

View file

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

View file

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

View file

@ -71,6 +71,7 @@ void COpenGL3Driver::initFeatures()
LODBiasSupported = true;
BlendMinMaxSupported = true;
TextureMultisampleSupported = true;
Texture2DArraySupported = Version.Major >= 3 || queryExtension("GL_EXT_texture_array");
KHRDebugSupported = isVersionAtLeast(4, 6) || queryExtension("GL_KHR_debug");
if (KHRDebugSupported)
MaxLabelLength = GetInteger(GL.MAX_LABEL_LENGTH);
@ -88,6 +89,8 @@ void COpenGL3Driver::initFeatures()
MaxAnisotropy = GetInteger(GL.MAX_TEXTURE_MAX_ANISOTROPY);
MaxIndices = GetInteger(GL_MAX_ELEMENTS_INDICES);
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_ALIASED_LINE_WIDTH_RANGE, DimAliasedLine);
DimAliasedPoint[0] = 1.0f;

View file

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