GPUTexture: Use immutable storage
This means textures need to have the number of mipmap levels specified upfront. It does not mean the data is immutable. There is fallback code for OpenGL < 4.2. Immutable storage will enables texture views in the future.
This commit is contained in:
@@ -626,11 +626,6 @@ static void dof_reduce_pass_init(EEVEE_FramebufferList *fbl,
|
|||||||
"dof_reduced_color", UNPACK2(res), mip_count, GPU_RGBA16F, NULL);
|
"dof_reduced_color", UNPACK2(res), mip_count, GPU_RGBA16F, NULL);
|
||||||
txl->dof_reduced_coc = GPU_texture_create_2d(
|
txl->dof_reduced_coc = GPU_texture_create_2d(
|
||||||
"dof_reduced_coc", UNPACK2(res), mip_count, GPU_R16F, NULL);
|
"dof_reduced_coc", UNPACK2(res), mip_count, GPU_R16F, NULL);
|
||||||
|
|
||||||
/* TODO(@fclem): Remove once we have immutable storage or when mips are generated on creation.
|
|
||||||
*/
|
|
||||||
GPU_texture_generate_mipmap(txl->dof_reduced_color);
|
|
||||||
GPU_texture_generate_mipmap(txl->dof_reduced_coc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU_framebuffer_ensure_config(&fbl->dof_reduce_fb,
|
GPU_framebuffer_ensure_config(&fbl->dof_reduce_fb,
|
||||||
|
|||||||
@@ -641,11 +641,6 @@ class Texture : NonCopyable {
|
|||||||
}
|
}
|
||||||
if (tx_ == nullptr) {
|
if (tx_ == nullptr) {
|
||||||
tx_ = create(w, h, d, mips, format, data, layered, cubemap);
|
tx_ = create(w, h, d, mips, format, data, layered, cubemap);
|
||||||
if (mips > 1) {
|
|
||||||
/* TODO(@fclem): Remove once we have immutable storage or when mips are
|
|
||||||
* generated on creation. */
|
|
||||||
GPU_texture_generate_mipmap(tx_);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -77,8 +77,9 @@ void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state,
|
|||||||
* filtering results. Mipmaps can be used to get better results (i.e. #GL_LINEAR_MIPMAP_LINEAR),
|
* filtering results. Mipmaps can be used to get better results (i.e. #GL_LINEAR_MIPMAP_LINEAR),
|
||||||
* so always use mipmaps when filtering. */
|
* so always use mipmaps when filtering. */
|
||||||
const bool use_mipmap = use_filter && ((draw_width < img_w) || (draw_height < img_h));
|
const bool use_mipmap = use_filter && ((draw_width < img_w) || (draw_height < img_h));
|
||||||
|
const int mips = use_mipmap ? 9999 : 1;
|
||||||
|
|
||||||
GPUTexture *tex = GPU_texture_create_2d("immDrawPixels", img_w, img_h, 1, gpu_format, NULL);
|
GPUTexture *tex = GPU_texture_create_2d("immDrawPixels", img_w, img_h, mips, gpu_format, NULL);
|
||||||
|
|
||||||
const bool use_float_data = ELEM(gpu_format, GPU_RGBA16F, GPU_RGB16F, GPU_R16F);
|
const bool use_float_data = ELEM(gpu_format, GPU_RGBA16F, GPU_RGB16F, GPU_R16F);
|
||||||
eGPUDataFormat gpu_data_format = (use_float_data) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
|
eGPUDataFormat gpu_data_format = (use_float_data) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
|
||||||
|
|||||||
@@ -52,11 +52,13 @@ Texture::~Texture()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Texture::init_1D(int w, int layers, eGPUTextureFormat format)
|
bool Texture::init_1D(int w, int layers, int mips, eGPUTextureFormat format)
|
||||||
{
|
{
|
||||||
w_ = w;
|
w_ = w;
|
||||||
h_ = layers;
|
h_ = layers;
|
||||||
d_ = 0;
|
d_ = 0;
|
||||||
|
int mips_max = 1 + floorf(log2f(w));
|
||||||
|
mipmaps_ = min_ii(mips, mips_max);
|
||||||
format_ = format;
|
format_ = format;
|
||||||
format_flag_ = to_format_flag(format);
|
format_flag_ = to_format_flag(format);
|
||||||
type_ = (layers > 0) ? GPU_TEXTURE_1D_ARRAY : GPU_TEXTURE_1D;
|
type_ = (layers > 0) ? GPU_TEXTURE_1D_ARRAY : GPU_TEXTURE_1D;
|
||||||
@@ -66,11 +68,13 @@ bool Texture::init_1D(int w, int layers, eGPUTextureFormat format)
|
|||||||
return this->init_internal();
|
return this->init_internal();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Texture::init_2D(int w, int h, int layers, eGPUTextureFormat format)
|
bool Texture::init_2D(int w, int h, int layers, int mips, eGPUTextureFormat format)
|
||||||
{
|
{
|
||||||
w_ = w;
|
w_ = w;
|
||||||
h_ = h;
|
h_ = h;
|
||||||
d_ = layers;
|
d_ = layers;
|
||||||
|
int mips_max = 1 + floorf(log2f(max_ii(w, h)));
|
||||||
|
mipmaps_ = min_ii(mips, mips_max);
|
||||||
format_ = format;
|
format_ = format;
|
||||||
format_flag_ = to_format_flag(format);
|
format_flag_ = to_format_flag(format);
|
||||||
type_ = (layers > 0) ? GPU_TEXTURE_2D_ARRAY : GPU_TEXTURE_2D;
|
type_ = (layers > 0) ? GPU_TEXTURE_2D_ARRAY : GPU_TEXTURE_2D;
|
||||||
@@ -80,11 +84,13 @@ bool Texture::init_2D(int w, int h, int layers, eGPUTextureFormat format)
|
|||||||
return this->init_internal();
|
return this->init_internal();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Texture::init_3D(int w, int h, int d, eGPUTextureFormat format)
|
bool Texture::init_3D(int w, int h, int d, int mips, eGPUTextureFormat format)
|
||||||
{
|
{
|
||||||
w_ = w;
|
w_ = w;
|
||||||
h_ = h;
|
h_ = h;
|
||||||
d_ = d;
|
d_ = d;
|
||||||
|
int mips_max = 1 + floorf(log2f(max_iii(w, h, d)));
|
||||||
|
mipmaps_ = min_ii(mips, mips_max);
|
||||||
format_ = format;
|
format_ = format;
|
||||||
format_flag_ = to_format_flag(format);
|
format_flag_ = to_format_flag(format);
|
||||||
type_ = GPU_TEXTURE_3D;
|
type_ = GPU_TEXTURE_3D;
|
||||||
@@ -94,11 +100,13 @@ bool Texture::init_3D(int w, int h, int d, eGPUTextureFormat format)
|
|||||||
return this->init_internal();
|
return this->init_internal();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Texture::init_cubemap(int w, int layers, eGPUTextureFormat format)
|
bool Texture::init_cubemap(int w, int layers, int mips, eGPUTextureFormat format)
|
||||||
{
|
{
|
||||||
w_ = w;
|
w_ = w;
|
||||||
h_ = w;
|
h_ = w;
|
||||||
d_ = max_ii(1, layers) * 6;
|
d_ = max_ii(1, layers) * 6;
|
||||||
|
int mips_max = 1 + floorf(log2f(w));
|
||||||
|
mipmaps_ = min_ii(mips, mips_max);
|
||||||
format_ = format;
|
format_ = format;
|
||||||
format_flag_ = to_format_flag(format);
|
format_flag_ = to_format_flag(format);
|
||||||
type_ = (layers > 0) ? GPU_TEXTURE_CUBE_ARRAY : GPU_TEXTURE_CUBE;
|
type_ = (layers > 0) ? GPU_TEXTURE_CUBE_ARRAY : GPU_TEXTURE_CUBE;
|
||||||
@@ -198,18 +206,18 @@ static inline GPUTexture *gpu_texture_create(const char *name,
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case GPU_TEXTURE_1D:
|
case GPU_TEXTURE_1D:
|
||||||
case GPU_TEXTURE_1D_ARRAY:
|
case GPU_TEXTURE_1D_ARRAY:
|
||||||
success = tex->init_1D(w, h, tex_format);
|
success = tex->init_1D(w, h, mips, tex_format);
|
||||||
break;
|
break;
|
||||||
case GPU_TEXTURE_2D:
|
case GPU_TEXTURE_2D:
|
||||||
case GPU_TEXTURE_2D_ARRAY:
|
case GPU_TEXTURE_2D_ARRAY:
|
||||||
success = tex->init_2D(w, h, d, tex_format);
|
success = tex->init_2D(w, h, d, mips, tex_format);
|
||||||
break;
|
break;
|
||||||
case GPU_TEXTURE_3D:
|
case GPU_TEXTURE_3D:
|
||||||
success = tex->init_3D(w, h, d, tex_format);
|
success = tex->init_3D(w, h, d, mips, tex_format);
|
||||||
break;
|
break;
|
||||||
case GPU_TEXTURE_CUBE:
|
case GPU_TEXTURE_CUBE:
|
||||||
case GPU_TEXTURE_CUBE_ARRAY:
|
case GPU_TEXTURE_CUBE_ARRAY:
|
||||||
success = tex->init_cubemap(w, d, tex_format);
|
success = tex->init_cubemap(w, d, mips, tex_format);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -287,7 +295,7 @@ GPUTexture *GPU_texture_create_compressed_2d(
|
|||||||
const char *name, int w, int h, int miplen, eGPUTextureFormat tex_format, const void *data)
|
const char *name, int w, int h, int miplen, eGPUTextureFormat tex_format, const void *data)
|
||||||
{
|
{
|
||||||
Texture *tex = GPUBackend::get()->texture_alloc(name);
|
Texture *tex = GPUBackend::get()->texture_alloc(name);
|
||||||
bool success = tex->init_2D(w, h, 0, tex_format);
|
bool success = tex->init_2D(w, h, 0, miplen, tex_format);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
delete tex;
|
delete tex;
|
||||||
|
|||||||
@@ -101,10 +101,10 @@ class Texture {
|
|||||||
virtual ~Texture();
|
virtual ~Texture();
|
||||||
|
|
||||||
/* Return true on success. */
|
/* Return true on success. */
|
||||||
bool init_1D(int w, int layers, eGPUTextureFormat format);
|
bool init_1D(int w, int layers, int mips, eGPUTextureFormat format);
|
||||||
bool init_2D(int w, int h, int layers, eGPUTextureFormat format);
|
bool init_2D(int w, int h, int layers, int mips, eGPUTextureFormat format);
|
||||||
bool init_3D(int w, int h, int d, eGPUTextureFormat format);
|
bool init_3D(int w, int h, int d, int mips, eGPUTextureFormat format);
|
||||||
bool init_cubemap(int w, int layers, eGPUTextureFormat format);
|
bool init_cubemap(int w, int layers, int mips, eGPUTextureFormat format);
|
||||||
bool init_buffer(GPUVertBuf *vbo, eGPUTextureFormat format);
|
bool init_buffer(GPUVertBuf *vbo, eGPUTextureFormat format);
|
||||||
|
|
||||||
virtual void generate_mipmap() = 0;
|
virtual void generate_mipmap() = 0;
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ static void detect_workarounds()
|
|||||||
GLContext::texture_cube_map_array_support = false;
|
GLContext::texture_cube_map_array_support = false;
|
||||||
GLContext::texture_filter_anisotropic_support = false;
|
GLContext::texture_filter_anisotropic_support = false;
|
||||||
GLContext::texture_gather_support = false;
|
GLContext::texture_gather_support = false;
|
||||||
|
GLContext::texture_storage_support = false;
|
||||||
GLContext::vertex_attrib_binding_support = false;
|
GLContext::vertex_attrib_binding_support = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -439,6 +440,7 @@ bool GLContext::shader_draw_parameters_support = false;
|
|||||||
bool GLContext::texture_cube_map_array_support = false;
|
bool GLContext::texture_cube_map_array_support = false;
|
||||||
bool GLContext::texture_filter_anisotropic_support = false;
|
bool GLContext::texture_filter_anisotropic_support = false;
|
||||||
bool GLContext::texture_gather_support = false;
|
bool GLContext::texture_gather_support = false;
|
||||||
|
bool GLContext::texture_storage_support = false;
|
||||||
bool GLContext::vertex_attrib_binding_support = false;
|
bool GLContext::vertex_attrib_binding_support = false;
|
||||||
|
|
||||||
/** Workarounds. */
|
/** Workarounds. */
|
||||||
@@ -501,6 +503,7 @@ void GLBackend::capabilities_init()
|
|||||||
GLContext::texture_cube_map_array_support = GLEW_ARB_texture_cube_map_array;
|
GLContext::texture_cube_map_array_support = GLEW_ARB_texture_cube_map_array;
|
||||||
GLContext::texture_filter_anisotropic_support = GLEW_EXT_texture_filter_anisotropic;
|
GLContext::texture_filter_anisotropic_support = GLEW_EXT_texture_filter_anisotropic;
|
||||||
GLContext::texture_gather_support = GLEW_ARB_texture_gather;
|
GLContext::texture_gather_support = GLEW_ARB_texture_gather;
|
||||||
|
GLContext::texture_storage_support = GLEW_VERSION_4_3;
|
||||||
GLContext::vertex_attrib_binding_support = GLEW_ARB_vertex_attrib_binding;
|
GLContext::vertex_attrib_binding_support = GLEW_ARB_vertex_attrib_binding;
|
||||||
|
|
||||||
detect_workarounds();
|
detect_workarounds();
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ class GLContext : public Context {
|
|||||||
static bool texture_cube_map_array_support;
|
static bool texture_cube_map_array_support;
|
||||||
static bool texture_filter_anisotropic_support;
|
static bool texture_filter_anisotropic_support;
|
||||||
static bool texture_gather_support;
|
static bool texture_gather_support;
|
||||||
|
static bool texture_storage_support;
|
||||||
static bool vertex_attrib_binding_support;
|
static bool vertex_attrib_binding_support;
|
||||||
|
|
||||||
/** Workarounds. */
|
/** Workarounds. */
|
||||||
|
|||||||
@@ -69,9 +69,79 @@ bool GLTexture::init_internal()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->ensure_mipmaps(0);
|
GLenum internal_format = to_gl_internal_format(format_);
|
||||||
|
const bool is_cubemap = bool(type_ == GPU_TEXTURE_CUBE);
|
||||||
|
const bool is_layered = bool(type_ & GPU_TEXTURE_ARRAY);
|
||||||
|
const bool is_compressed = bool(format_flag_ & GPU_TEXTURE_ARRAY);
|
||||||
|
const int dimensions = (is_cubemap) ? 2 : this->dimensions_count();
|
||||||
|
GLenum gl_format = to_gl_data_format(format_);
|
||||||
|
GLenum gl_type = to_gl(to_data_format(format_));
|
||||||
|
|
||||||
/* Avoid issue with incomplete textures. */
|
auto mip_size = [&](int h, int w = 1, int d = 1) -> size_t {
|
||||||
|
return divide_ceil_u(w, 4) * divide_ceil_u(h, 4) * divide_ceil_u(d, 4) *
|
||||||
|
to_block_size(format_);
|
||||||
|
};
|
||||||
|
switch (dimensions) {
|
||||||
|
default:
|
||||||
|
case 1:
|
||||||
|
if (GLContext::texture_storage_support) {
|
||||||
|
glTexStorage1D(target_, mipmaps_, internal_format, w_);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0, w = w_; i < mipmaps_; i++) {
|
||||||
|
if (is_compressed) {
|
||||||
|
glCompressedTexImage1D(target_, i, internal_format, w, 0, mip_size(w), nullptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glTexImage1D(target_, i, internal_format, w, 0, gl_format, gl_type, nullptr);
|
||||||
|
}
|
||||||
|
w = max_ii(1, (w / 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (GLContext::texture_storage_support) {
|
||||||
|
glTexStorage2D(target_, mipmaps_, internal_format, w_, h_);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0, w = w_, h = h_; i < mipmaps_; i++) {
|
||||||
|
for (int f = 0; f < (is_cubemap ? 6 : 1); f++) {
|
||||||
|
GLenum target = (is_cubemap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + f : target_;
|
||||||
|
if (is_compressed) {
|
||||||
|
glCompressedTexImage2D(target, i, internal_format, w, h, 0, mip_size(w, h), nullptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glTexImage2D(target, i, internal_format, w, h, 0, gl_format, gl_type, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w = max_ii(1, (w / 2));
|
||||||
|
h = is_layered ? h_ : max_ii(1, (h / 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (GLContext::texture_storage_support) {
|
||||||
|
glTexStorage3D(target_, mipmaps_, internal_format, w_, h_, d_);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0, w = w_, h = h_, d = d_; i < mipmaps_; i++) {
|
||||||
|
if (is_compressed) {
|
||||||
|
glCompressedTexImage3D(
|
||||||
|
target_, i, internal_format, w, h, d, 0, mip_size(w, h, d), nullptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glTexImage3D(target_, i, internal_format, w, h, d, 0, gl_format, gl_type, nullptr);
|
||||||
|
}
|
||||||
|
w = max_ii(1, (w / 2));
|
||||||
|
h = max_ii(1, (h / 2));
|
||||||
|
d = is_layered ? d_ : max_ii(1, (d / 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->mip_range_set(0, mipmaps_ - 1);
|
||||||
|
|
||||||
|
/* Avoid issue with formats not supporting filtering. Nearest by default. */
|
||||||
if (GLContext::direct_state_access_support) {
|
if (GLContext::direct_state_access_support) {
|
||||||
glTextureParameteri(tex_id_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTextureParameteri(tex_id_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
}
|
}
|
||||||
@@ -105,67 +175,6 @@ bool GLTexture::init_internal(GPUVertBuf *vbo)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLTexture::ensure_mipmaps(int miplvl)
|
|
||||||
{
|
|
||||||
int effective_h = (type_ == GPU_TEXTURE_1D_ARRAY) ? 0 : h_;
|
|
||||||
int effective_d = (type_ != GPU_TEXTURE_3D) ? 0 : d_;
|
|
||||||
int max_dimension = max_iii(w_, effective_h, effective_d);
|
|
||||||
int max_miplvl = floor(log2(max_dimension));
|
|
||||||
miplvl = min_ii(miplvl, max_miplvl);
|
|
||||||
|
|
||||||
while (mipmaps_ < miplvl) {
|
|
||||||
int mip = ++mipmaps_;
|
|
||||||
const int dimensions = this->dimensions_count();
|
|
||||||
|
|
||||||
int w = mip_width_get(mip);
|
|
||||||
int h = mip_height_get(mip);
|
|
||||||
int d = mip_depth_get(mip);
|
|
||||||
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_));
|
|
||||||
|
|
||||||
GLContext::state_manager_active_get()->texture_bind_temp(this);
|
|
||||||
|
|
||||||
if (type_ == GPU_TEXTURE_CUBE) {
|
|
||||||
for (int i = 0; i < d; i++) {
|
|
||||||
GLenum target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
|
|
||||||
glTexImage2D(target, mip, internal_format, w, h, 0, gl_format, gl_type, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (format_flag_ & GPU_FORMAT_COMPRESSED) {
|
|
||||||
size_t size = ((w + 3) / 4) * ((h + 3) / 4) * to_block_size(format_);
|
|
||||||
switch (dimensions) {
|
|
||||||
default:
|
|
||||||
case 1:
|
|
||||||
glCompressedTexImage1D(target_, mip, internal_format, w, 0, size, nullptr);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
glCompressedTexImage2D(target_, mip, internal_format, w, h, 0, size, nullptr);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
glCompressedTexImage3D(target_, mip, internal_format, w, h, d, 0, size, nullptr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
switch (dimensions) {
|
|
||||||
default:
|
|
||||||
case 1:
|
|
||||||
glTexImage1D(target_, mip, internal_format, w, 0, gl_format, gl_type, nullptr);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
glTexImage2D(target_, mip, internal_format, w, h, 0, gl_format, gl_type, nullptr);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
glTexImage3D(target_, mip, internal_format, w, h, d, 0, gl_format, gl_type, nullptr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->mip_range_set(0, mipmaps_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
@@ -216,9 +225,7 @@ void GLTexture::update_sub(
|
|||||||
BLI_assert(validate_data_format(format_, type));
|
BLI_assert(validate_data_format(format_, type));
|
||||||
BLI_assert(data != nullptr);
|
BLI_assert(data != nullptr);
|
||||||
|
|
||||||
this->ensure_mipmaps(mip);
|
if (mip >= mipmaps_) {
|
||||||
|
|
||||||
if (mip > mipmaps_) {
|
|
||||||
debug::raise_gl_error("Updating a miplvl on a texture too small to have this many levels.");
|
debug::raise_gl_error("Updating a miplvl on a texture too small to have this many levels.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -283,7 +290,6 @@ void GLTexture::update_sub(
|
|||||||
*/
|
*/
|
||||||
void GLTexture::generate_mipmap()
|
void GLTexture::generate_mipmap()
|
||||||
{
|
{
|
||||||
this->ensure_mipmaps(9999);
|
|
||||||
/* Some drivers have bugs when using #glGenerateMipmap with depth textures (see T56789).
|
/* Some drivers have bugs when using #glGenerateMipmap with depth textures (see T56789).
|
||||||
* In this case we just create a complete texture with mipmaps manually without
|
* In this case we just create a complete texture with mipmaps manually without
|
||||||
* down-sampling. You must initialize the texture levels using other methods like
|
* down-sampling. You must initialize the texture levels using other methods like
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ class GLTexture : public Texture {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool proxy_check(int mip);
|
bool proxy_check(int mip);
|
||||||
/** Will create enough mipmaps up to get to the given level. */
|
|
||||||
void ensure_mipmaps(int mip);
|
|
||||||
void update_sub_direct_state_access(
|
void update_sub_direct_state_access(
|
||||||
int mip, int offset[3], int extent[3], GLenum gl_format, GLenum gl_type, const void *data);
|
int mip, int offset[3], int extent[3], GLenum gl_format, GLenum gl_type, const void *data);
|
||||||
GPUFrameBuffer *framebuffer_get();
|
GPUFrameBuffer *framebuffer_get();
|
||||||
|
|||||||
Reference in New Issue
Block a user