GLTexture: Add back texture proxy check

Cleanup the feature itself:
- Check 3D textures size against the correct limit.
- Add check for compressed textures.
This commit is contained in:
Clément Foucault 2020-09-04 02:36:56 +02:00
parent 31c77a14af
commit b100b77fda
5 changed files with 157 additions and 2 deletions

View File

@ -30,6 +30,7 @@ extern "C" {
/* GPU extensions support */
int GPU_max_texture_size(void);
int GPU_max_texture_3d_size(void);
int GPU_max_texture_layers(void);
int GPU_max_textures(void);
int GPU_max_textures_vert(void);

View File

@ -62,6 +62,7 @@
static struct GPUGlobal {
GLint maxtexsize;
GLint maxtex3dsize;
GLint maxtexlayers;
GLint maxcubemapsize;
GLint maxtextures;
@ -137,6 +138,11 @@ int GPU_max_texture_size(void)
return GG.maxtexsize;
}
int GPU_max_texture_3d_size(void)
{
return GG.maxtex3dsize;
}
int GPU_max_texture_layers(void)
{
return GG.maxtexlayers;
@ -249,6 +255,7 @@ void gpu_extensions_init(void)
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &GG.maxtextures);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GG.maxtexsize);
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &GG.maxtex3dsize);
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &GG.maxtexlayers);
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GG.maxcubemapsize);

View File

@ -188,6 +188,19 @@ class Texture {
return 3;
}
}
/* Return number of array layer (or face layer) for texture array or 1 for the others. */
int layer_count(void) const
{
switch (type_) {
case GPU_TEXTURE_1D_ARRAY:
return h_;
case GPU_TEXTURE_2D_ARRAY:
case GPU_TEXTURE_CUBE_ARRAY:
return d_;
default:
return 1;
}
}
eGPUTextureFormat format_get(void) const
{

View File

@ -27,6 +27,7 @@
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_platform.h"
#include "gl_backend.hh"
#include "gl_debug.hh"
@ -76,7 +77,9 @@ bool GLTexture::init_internal(void)
target_ = to_gl_target(type_);
/* TODO(fclem) Proxy check. */
if (!this->proxy_check(0)) {
return false;
}
this->ensure_mipmaps(0);
@ -497,6 +500,112 @@ void GLTexture::samplers_free(void)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Proxy texture
*
* Dummy texture to see if the implementation supports the requested size.
* \{ */
/* NOTE: This only checks if this mipmap is valid / supported.
* TODO(fclem) make the check cover the whole mipmap chain. */
bool GLTexture::proxy_check(int mip)
{
/* Manual validation first, since some implementation have issues with proxy creation. */
int max_size = GPU_max_texture_size();
int max_3d_size = GPU_max_texture_3d_size();
int max_cube_size = GPU_max_cube_map_size();
int size[3] = {1, 1, 1};
this->mip_size_get(mip, size);
if (type_ & GPU_TEXTURE_ARRAY) {
if (this->layer_count() > GPU_max_texture_layers()) {
return false;
}
}
if (type_ == GPU_TEXTURE_3D) {
if (size[0] > max_3d_size || size[1] > max_3d_size || size[2] > max_3d_size) {
return false;
}
}
else if ((type_ & ~GPU_TEXTURE_ARRAY) == GPU_TEXTURE_2D) {
if (size[0] > max_size || size[1] > max_size) {
return false;
}
}
else if ((type_ & ~GPU_TEXTURE_ARRAY) == GPU_TEXTURE_1D) {
if (size[0] > max_size) {
return false;
}
}
else if ((type_ & ~GPU_TEXTURE_ARRAY) == GPU_TEXTURE_CUBE) {
if (size[0] > max_cube_size) {
return false;
}
}
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_ANY) ||
GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_MAC, GPU_DRIVER_OFFICIAL) ||
GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OFFICIAL)) {
/* Some AMD drivers have a faulty `GL_PROXY_TEXTURE_..` check.
* (see T55888, T56185, T59351).
* Checking with `GL_PROXY_TEXTURE_..` doesn't prevent `Out Of Memory` issue,
* it just states that the OGL implementation can support the texture.
* So we already manually check the maximum size and maximum number of layers.
* Same thing happens on Nvidia/macOS 10.15 (T78175). */
return true;
}
if ((type_ == GPU_TEXTURE_CUBE_ARRAY) &&
GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY)) {
/* Special fix for T79703. */
return true;
}
GLenum gl_proxy = to_gl_proxy(type_);
GLenum internal_format = to_gl_internal_format(format_);
GLenum gl_format = to_gl_data_format(format_);
GLenum gl_type = to_gl(to_data_format(format_));
/* Small exception. */
int dimensions = (type_ == GPU_TEXTURE_CUBE) ? 2 : this->dimensions_count();
if (format_flag_ & GPU_FORMAT_COMPRESSED) {
size_t img_size = ((size[0] + 3) / 4) * ((size[1] + 3) / 4) * to_block_size(format_);
switch (dimensions) {
default:
case 1:
glCompressedTexImage1D(gl_proxy, mip, size[0], 0, gl_format, img_size, NULL);
break;
case 2:
glCompressedTexImage2D(gl_proxy, mip, UNPACK2(size), 0, gl_format, img_size, NULL);
break;
case 3:
glCompressedTexImage3D(gl_proxy, mip, UNPACK3(size), 0, gl_format, img_size, NULL);
break;
}
}
else {
switch (dimensions) {
default:
case 1:
glTexImage1D(gl_proxy, mip, internal_format, size[0], 0, gl_format, gl_type, NULL);
break;
case 2:
glTexImage2D(gl_proxy, mip, internal_format, UNPACK2(size), 0, gl_format, gl_type, NULL);
break;
case 3:
glTexImage3D(gl_proxy, mip, internal_format, UNPACK3(size), 0, gl_format, gl_type, NULL);
break;
}
}
int width = 0;
glGetTexLevelParameteriv(gl_proxy, 0, GL_TEXTURE_WIDTH, &width);
return (width > 0);
}
/** \} */
/* TODO(fclem) Legacy. Should be removed at some point. */
uint GLTexture::gl_bindcode_get(void) const
{

View File

@ -97,7 +97,8 @@ class GLTexture : public Texture {
bool init_internal(GPUVertBuf *vbo) override;
private:
void ensure_mipmaps(int miplvl);
bool proxy_check(int mip);
void ensure_mipmaps(int mip);
GPUFrameBuffer *framebuffer_get(void);
MEM_CXX_CLASS_ALLOC_FUNCS("GLTexture")
@ -232,6 +233,30 @@ inline GLenum to_gl_target(eGPUTextureType type)
}
}
inline GLenum to_gl_proxy(eGPUTextureType type)
{
switch (type) {
case GPU_TEXTURE_1D:
return GL_PROXY_TEXTURE_1D;
case GPU_TEXTURE_1D_ARRAY:
return GL_PROXY_TEXTURE_1D_ARRAY;
case GPU_TEXTURE_2D:
return GL_PROXY_TEXTURE_2D;
case GPU_TEXTURE_2D_ARRAY:
return GL_PROXY_TEXTURE_2D_ARRAY;
case GPU_TEXTURE_3D:
return GL_PROXY_TEXTURE_3D;
case GPU_TEXTURE_CUBE:
return GL_PROXY_TEXTURE_CUBE_MAP;
case GPU_TEXTURE_CUBE_ARRAY:
return GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB;
case GPU_TEXTURE_BUFFER:
default:
BLI_assert(0);
return GL_TEXTURE_1D;
}
}
inline GLenum swizzle_to_gl(const char swizzle)
{
switch (swizzle) {