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:
parent
d5bf094f9a
commit
46db688cc8
14 changed files with 111 additions and 72 deletions
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue