From 1c7aea8d509cc2e8200eaa649fc92ca1417119d9 Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Wed, 15 May 2013 15:03:08 -0700 Subject: [PATCH] Implemented new quality setting, "siren_reverb_max_length". Optimizations to Impulse Response Reverb convolution algorithm to speed up FFT's and reduce memory consumption. GL_EXT_texture_storage extension now functioning for cube maps. --- KREngine/kraken/KRAudioManager.cpp | 49 +++++++++++++++------- KREngine/kraken/KRAudioManager.h | 8 +++- KREngine/kraken/KREngine.mm | 23 ++++++---- KREngine/kraken/KRRenderSettings.cpp | 2 + KREngine/kraken/KRRenderSettings.h | 1 + KREngine/kraken/KRScene.cpp | 1 + KREngine/kraken/KRTexture2D.cpp | 3 +- KREngine/kraken/KRTextureCube.cpp | 62 ++++++++++++++++++--------- KREngine/kraken/KRTexturePVR.cpp | 63 ++++++++++++++-------------- 9 files changed, 134 insertions(+), 78 deletions(-) diff --git a/KREngine/kraken/KRAudioManager.cpp b/KREngine/kraken/KRAudioManager.cpp index 6c2c860..428cb2b 100644 --- a/KREngine/kraken/KRAudioManager.cpp +++ b/KREngine/kraken/KRAudioManager.cpp @@ -47,6 +47,7 @@ KRAudioManager::KRAudioManager(KRContext &context) : KRContextObject(context) m_enable_audio = true; m_enable_hrtf = true; m_enable_reverb = true; + m_reverb_max_length = 8.0f; m_anticlick_block = true; mach_timebase_info(&m_timebase_info); @@ -73,7 +74,9 @@ KRAudioManager::KRAudioManager(KRContext &context) : KRContextObject(context) m_output_sample = 0; - m_fft_setup = NULL; + for(int i=KRENGINE_AUDIO_BLOCK_LOG2N; i <= KRENGINE_REVERB_MAX_FFT_LOG2; i++) { + m_fft_setup[i - KRENGINE_AUDIO_BLOCK_LOG2N] = NULL; + } m_reverb_input_samples = NULL; m_reverb_input_next_sample = 0; @@ -132,11 +135,21 @@ bool KRAudioManager::getEnableReverb() return m_enable_reverb; } +float KRAudioManager::getReverbMaxLength() +{ + return m_reverb_max_length; +} + void KRAudioManager::setEnableReverb(bool enable) { m_enable_reverb = enable; } +void KRAudioManager::setReverbMaxLength(float max_length) +{ + m_reverb_max_length = max_length; +} + KRScene *KRAudioManager::getListenerScene() { return m_listener_scene; @@ -242,7 +255,7 @@ void KRAudioManager::renderReverbImpulseResponse(int impulse_response_offset, in memset(reverb_sample_data_complex.realp + frame_count, 0, frame_count * sizeof(float)); memset(reverb_sample_data_complex.imagp, 0, fft_size * sizeof(float)); - vDSP_fft_zip(m_fft_setup, &reverb_sample_data_complex, 1, fft_size_log2, kFFTDirection_Forward); + vDSP_fft_zip(m_fft_setup[fft_size_log2 - KRENGINE_AUDIO_BLOCK_LOG2N], &reverb_sample_data_complex, 1, fft_size_log2, kFFTDirection_Forward); float scale = 0.5f / fft_size; @@ -252,7 +265,7 @@ void KRAudioManager::renderReverbImpulseResponse(int impulse_response_offset, in for(unordered_map::iterator zone_itr=m_reverb_zone_weights.begin(); zone_itr != m_reverb_zone_weights.end(); zone_itr++) { siren_reverb_zone_weight_info zi = (*zone_itr).second; if(zi.reverb_sample) { - if(impulse_response_offset < zi.reverb_sample->getFrameCount()) { // Optimization - when mixing multiple impulse responses (i.e. fading between reverb zones), do not process blocks past the end of a shorter impulse response sample when they differ in length + if(impulse_response_offset < KRMIN(zi.reverb_sample->getFrameCount(), m_reverb_max_length * 44100)) { // Optimization - when mixing multiple impulse responses (i.e. fading between reverb zones), do not process blocks past the end of a shorter impulse response sample when they differ in length if(first_sample) { // If this is the first or only sample, write directly to the first half of the FFT input buffer first_sample = false; @@ -269,9 +282,11 @@ void KRAudioManager::renderReverbImpulseResponse(int impulse_response_offset, in memset(impulse_block_data_complex.realp + frame_count, 0, frame_count * sizeof(float)); memset(impulse_block_data_complex.imagp, 0, fft_size * sizeof(float)); - vDSP_fft_zip(m_fft_setup, &impulse_block_data_complex, 1, fft_size_log2, kFFTDirection_Forward); + + + vDSP_fft_zip(m_fft_setup[fft_size_log2 - KRENGINE_AUDIO_BLOCK_LOG2N], &impulse_block_data_complex, 1, fft_size_log2, kFFTDirection_Forward); vDSP_zvmul(&reverb_sample_data_complex, 1, &impulse_block_data_complex, 1, &conv_data_complex, 1, fft_size, 1); - vDSP_fft_zip(m_fft_setup, &conv_data_complex, 1, fft_size_log2, kFFTDirection_Inverse); + vDSP_fft_zip(m_fft_setup[fft_size_log2 - KRENGINE_AUDIO_BLOCK_LOG2N], &conv_data_complex, 1, fft_size_log2, kFFTDirection_Inverse); vDSP_vsmul(conv_data_complex.realp, 1, &scale, conv_data_complex.realp, 1, fft_size); @@ -323,7 +338,7 @@ void KRAudioManager::renderReverb() for(unordered_map::iterator zone_itr=m_reverb_zone_weights.begin(); zone_itr != m_reverb_zone_weights.end(); zone_itr++) { siren_reverb_zone_weight_info zi = (*zone_itr).second; if(zi.reverb_sample) { - int zone_sample_blocks = zi.reverb_sample->getFrameCount() / KRENGINE_AUDIO_BLOCK_LENGTH + 1; + int zone_sample_blocks = KRMIN(zi.reverb_sample->getFrameCount(), m_reverb_max_length * 44100) / KRENGINE_AUDIO_BLOCK_LENGTH + 1; impulse_response_blocks = KRMAX(impulse_response_blocks, zone_sample_blocks); } } @@ -815,7 +830,7 @@ void KRAudioManager::initHRTF() sample->sample(0, 128, channel, spectral.realp, 1.0f, false); memset(spectral.realp + 128, 0, sizeof(float) * 128); memset(spectral.imagp, 0, sizeof(float) * 256); - vDSP_fft_zip(m_fft_setup, &spectral, 1, 8, kFFTDirection_Forward); + vDSP_fft_zip(m_fft_setup[8 - KRENGINE_AUDIO_BLOCK_LOG2N], &spectral, 1, 8, kFFTDirection_Forward); m_hrtf_spectral[channel][pos] = spectral; } sample_index++; @@ -1021,9 +1036,10 @@ void KRAudioManager::initSiren() m_workspace[2].imagp = m_workspace_data + KRENGINE_REVERB_WORKSPACE_SIZE * 5; m_reverb_sequence = 0; - - m_fft_setup = vDSP_create_fftsetup( KRENGINE_REVERB_MAX_FFT_LOG2, kFFTRadix2); - + for(int i=KRENGINE_AUDIO_BLOCK_LOG2N; i <= KRENGINE_REVERB_MAX_FFT_LOG2; i++) { + m_fft_setup[i - KRENGINE_AUDIO_BLOCK_LOG2N] = vDSP_create_fftsetup( KRENGINE_REVERB_MAX_FFT_LOG2, kFFTRadix2); + } + // ----====---- Initialize Core Audio Objects ----====---- OSDEBUG(NewAUGraph(&m_auGraph)); @@ -1178,9 +1194,11 @@ void KRAudioManager::cleanupSiren() m_reverb_impulse_responses_weight[i] = 0.0f; } - if(m_fft_setup) { - vDSP_destroy_fftsetup(m_fft_setup); - m_fft_setup = NULL; + for(int i=KRENGINE_AUDIO_BLOCK_LOG2N; i <= KRENGINE_REVERB_MAX_FFT_LOG2; i++) { + if(m_fft_setup[i - KRENGINE_AUDIO_BLOCK_LOG2N]) { + vDSP_destroy_fftsetup(m_fft_setup[i - KRENGINE_AUDIO_BLOCK_LOG2N]); + m_fft_setup[i - KRENGINE_AUDIO_BLOCK_LOG2N] = NULL; + } } } @@ -1737,9 +1755,10 @@ void KRAudioManager::renderHRTF() } float scale = 0.5f / fft_size; - vDSP_fft_zip(m_fft_setup, hrtf_sample, 1, fft_size_log2, kFFTDirection_Forward); + + vDSP_fft_zip(m_fft_setup[fft_size_log2 - KRENGINE_AUDIO_BLOCK_LOG2N], hrtf_sample, 1, fft_size_log2, kFFTDirection_Forward); vDSP_zvmul(hrtf_sample, 1, &hrtf_spectral, 1, hrtf_convolved, 1, fft_size, 1); - vDSP_fft_zip(m_fft_setup, hrtf_convolved, 1, fft_size_log2, kFFTDirection_Inverse); + vDSP_fft_zip(m_fft_setup[fft_size_log2 - KRENGINE_AUDIO_BLOCK_LOG2N], hrtf_convolved, 1, fft_size_log2, kFFTDirection_Inverse); vDSP_vsmul(hrtf_convolved->realp, 1, &scale, hrtf_convolved->realp, 1, fft_size); int output_offset = (m_output_accumulation_block_start) % (KRENGINE_REVERB_MAX_SAMPLES * KRENGINE_MAX_OUTPUT_CHANNELS); diff --git a/KREngine/kraken/KRAudioManager.h b/KREngine/kraken/KRAudioManager.h index 157c73a..e3d0474 100644 --- a/KREngine/kraken/KRAudioManager.h +++ b/KREngine/kraken/KRAudioManager.h @@ -47,7 +47,7 @@ const int KRENGINE_AUDIO_BUFFERS_PER_SOURCE = 3; const int KRENGINE_AUDIO_BLOCK_LENGTH = 128; // Length of one block to process. Determines the latency of the audio system and sets size for FFT's used in HRTF convolution const int KRENGINE_AUDIO_BLOCK_LOG2N = 7; // 2 ^ KRENGINE_AUDIO_BLOCK_LOG2N = KRENGINE_AUDIO_BLOCK_LENGTH -const int KRENGINE_REVERB_MAX_FFT_LOG2 = 17; +const int KRENGINE_REVERB_MAX_FFT_LOG2 = 15; const int KRENGINE_REVERB_WORKSPACE_SIZE = 1 << KRENGINE_REVERB_MAX_FFT_LOG2; const float KRENGINE_AUDIO_CUTOFF = 0.02f; // Cutoff gain level, to cull out processing of very quiet sounds @@ -139,10 +139,14 @@ public: bool getEnableReverb(); void setEnableReverb(bool enable); + float getReverbMaxLength(); + void setReverbMaxLength(float max_length); + private: bool m_enable_audio; bool m_enable_hrtf; bool m_enable_reverb; + float m_reverb_max_length; KRScene *m_listener_scene; // For now, only one scene is allowed to have active audio at once @@ -198,7 +202,7 @@ private: int m_output_accumulation_block_start; int m_output_sample; - FFTSetup m_fft_setup; + FFTSetup m_fft_setup[KRENGINE_REVERB_MAX_FFT_LOG2 - KRENGINE_AUDIO_BLOCK_LOG2N + 1]; float *m_workspace_data; DSPSplitComplex m_workspace[3]; diff --git a/KREngine/kraken/KREngine.mm b/KREngine/kraken/KREngine.mm index d772443..5bd8759 100644 --- a/KREngine/kraken/KREngine.mm +++ b/KREngine/kraken/KREngine.mm @@ -196,7 +196,8 @@ void kraken::set_parameter(const std::string ¶meter_name, float parameter_va @"siren_enable" : @49, @"siren_enable_reverb" : @50, @"siren_enable_hrtf" : @51, - @"max_anisotropy" : @52 + @"siren_reverb_max_length" : @52, + @"max_anisotropy" : @53 } copy]; [self loadShaders]; @@ -285,7 +286,7 @@ void kraken::set_parameter(const std::string ¶meter_name, float parameter_va -(NSString *)getParameterLabelWithIndex: (int)i { - NSString *parameter_labels[53] = { + NSString *parameter_labels[54] = { @"Camera FOV", @"Shadow Quality (0 - 2)", @"Enable per-pixel lighting", @@ -338,13 +339,14 @@ void kraken::set_parameter(const std::string ¶meter_name, float parameter_va @"Siren - Enable Audio", @"Siren - Enable Reverb", @"Siren - Enable HRTF", + @"Siren - Max Reverb Len", @"Anisotropic Filtering" }; return parameter_labels[i]; } -(KREngineParameterType)getParameterTypeWithIndex: (int)i { - KREngineParameterType types[53] = { + KREngineParameterType types[54] = { KRENGINE_PARAMETER_FLOAT, KRENGINE_PARAMETER_INT, @@ -398,13 +400,14 @@ void kraken::set_parameter(const std::string ¶meter_name, float parameter_va KRENGINE_PARAMETER_BOOL, KRENGINE_PARAMETER_BOOL, KRENGINE_PARAMETER_BOOL, + KRENGINE_PARAMETER_FLOAT, KRENGINE_PARAMETER_FLOAT }; return types[i]; } -(float)getParameterValueWithIndex: (int)i { - float values[53] = { + float values[54] = { _settings.perspective_fov, (float)_settings.m_cShadowBuffers, _settings.bEnablePerPixel ? 1.0f : 0.0f, @@ -457,6 +460,7 @@ void kraken::set_parameter(const std::string ¶meter_name, float parameter_va _settings.siren_enable, _settings.siren_enable_reverb, _settings.siren_enable_hrtf, + _settings.siren_reverb_max_length, _settings.max_anisotropy }; return values[i]; @@ -659,6 +663,9 @@ void kraken::set_parameter(const std::string ¶meter_name, float parameter_va _settings.siren_enable_hrtf = bNewBoolVal; break; case 52: + _settings.siren_reverb_max_length = v; + break; + case 53: _settings.max_anisotropy = v; break; } @@ -666,13 +673,13 @@ void kraken::set_parameter(const std::string ¶meter_name, float parameter_va -(float)getParameterMinWithIndex: (int)i { - float minValues[53] = { + float minValues[54] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.01f, 50.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -10.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f + 0.0f, 0.0f, 0.0f, 0.05f, 1.0f }; return minValues[i]; @@ -680,13 +687,13 @@ void kraken::set_parameter(const std::string ¶meter_name, float parameter_va -(float)getParameterMaxWithIndex: (int)i { - float maxValues[53] = { + float maxValues[54] = { PI, 3.0f, 1.0f, 1.0, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 10.0f, 1.0f, 10.0f, 2.0f, 1.0f, 1.0f, 1.0f, 5.0f, 1.0f, 0.5f, 1.0f, 2.0f, 2.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 10.0f, 1000.0f, 1.0f, 5.0f, 1000.0f, 1.0f, 5.0f, 3.0f, 1000.0f, 1000.0f, 0.01f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 10.0f, 1.0f, (float)(KRRenderSettings::KRENGINE_DEBUG_DISPLAY_NUMBER - 1), - 1.0f, 1.0f, 1.0f, 8.0f + 1.0f, 1.0f, 1.0f, 10.0f, 8.0f }; return maxValues[i]; diff --git a/KREngine/kraken/KRRenderSettings.cpp b/KREngine/kraken/KRRenderSettings.cpp index c8f912b..6c9efe8 100644 --- a/KREngine/kraken/KRRenderSettings.cpp +++ b/KREngine/kraken/KRRenderSettings.cpp @@ -13,6 +13,7 @@ KRRenderSettings::KRRenderSettings() siren_enable = true; siren_enable_reverb = true; siren_enable_hrtf = true; + siren_reverb_max_length = 2.0f; m_enable_realtime_occlusion = true; bShowShadowBuffer = false; @@ -92,6 +93,7 @@ KRRenderSettings& KRRenderSettings::operator=(const KRRenderSettings &s) siren_enable = s.siren_enable; siren_enable_reverb = s.siren_enable_reverb; siren_enable_hrtf = s.siren_enable_hrtf; + siren_reverb_max_length = s.siren_reverb_max_length; bEnablePerPixel = s.bEnablePerPixel; bEnableDiffuseMap = s.bEnableDiffuseMap; diff --git a/KREngine/kraken/KRRenderSettings.h b/KREngine/kraken/KRRenderSettings.h index 0b8174e..1cfff0e 100644 --- a/KREngine/kraken/KRRenderSettings.h +++ b/KREngine/kraken/KRRenderSettings.h @@ -105,6 +105,7 @@ public: bool siren_enable; bool siren_enable_reverb; bool siren_enable_hrtf; + float siren_reverb_max_length; float max_anisotropy; diff --git a/KREngine/kraken/KRScene.cpp b/KREngine/kraken/KRScene.cpp index b5b815a..90ee2d7 100644 --- a/KREngine/kraken/KRScene.cpp +++ b/KREngine/kraken/KRScene.cpp @@ -73,6 +73,7 @@ void KRScene::renderFrame(float deltaTime, int width, int height) { getContext().getAudioManager()->setEnableAudio(camera->settings.siren_enable); getContext().getAudioManager()->setEnableHRTF(camera->settings.siren_enable_hrtf); getContext().getAudioManager()->setEnableReverb(camera->settings.siren_enable_reverb); + getContext().getAudioManager()->setReverbMaxLength(camera->settings.siren_reverb_max_length); getContext().getTextureManager()->setMaxAnisotropy(camera->settings.max_anisotropy); camera->renderFrame(deltaTime, width, height); diff --git a/KREngine/kraken/KRTexture2D.cpp b/KREngine/kraken/KRTexture2D.cpp index 61b75a4..da79d62 100644 --- a/KREngine/kraken/KRTexture2D.cpp +++ b/KREngine/kraken/KRTexture2D.cpp @@ -56,11 +56,10 @@ bool KRTexture2D::createGLTexture(int lod_max_dim) { m_textureMemUsed = 0; prev_lod_max_dim = m_current_lod_max_dim; } - - #else releaseHandle(); #endif + m_current_lod_max_dim = 0; GLDEBUG(glGenTextures(1, &m_iHandle)); diff --git a/KREngine/kraken/KRTextureCube.cpp b/KREngine/kraken/KRTextureCube.cpp index b7e9e43..a9e532d 100644 --- a/KREngine/kraken/KRTextureCube.cpp +++ b/KREngine/kraken/KRTextureCube.cpp @@ -55,35 +55,59 @@ KRTextureCube::~KRTextureCube() bool KRTextureCube::createGLTexture(int lod_max_dim) { + bool success = true; + GLuint prev_handle = 0; + int prev_lod_max_dim = 0; + long prev_mem_size = 0; +#if GL_APPLE_copy_texture_levels && GL_EXT_texture_storage + + if(m_iHandle != 0) { + prev_handle = m_iHandle; + prev_mem_size = getMemSize(); + m_iHandle = 0; + m_textureMemUsed = 0; + prev_lod_max_dim = m_current_lod_max_dim; + } + + +#else releaseHandle(); +#endif m_current_lod_max_dim = 0; GLDEBUG(glGenTextures(1, &m_iHandle)); if(m_iHandle == 0) { - return false; - } - - GLDEBUG(glBindTexture(GL_TEXTURE_CUBE_MAP, m_iHandle)); - - bool bMipMaps = false; + success = false; + } else { + + GLDEBUG(glBindTexture(GL_TEXTURE_CUBE_MAP, m_iHandle)); + + bool bMipMaps = false; - for(int i=0; i<6; i++) { - std::string faceName = getName() + SUFFIXES[i]; - KRTexture2D *faceTexture = (KRTexture2D *)getContext().getTextureManager()->getTexture(faceName); - if(faceTexture) { - if(faceTexture->hasMipmaps()) bMipMaps = true; - faceTexture->uploadTexture(TARGETS[i], lod_max_dim, m_current_lod_max_dim, m_textureMemUsed, 0, 0); + for(int i=0; i<6; i++) { + std::string faceName = getName() + SUFFIXES[i]; + KRTexture2D *faceTexture = (KRTexture2D *)getContext().getTextureManager()->getTexture(faceName); + if(faceTexture) { + if(faceTexture->hasMipmaps()) bMipMaps = true; + faceTexture->uploadTexture(TARGETS[i], lod_max_dim, m_current_lod_max_dim, m_textureMemUsed, prev_lod_max_dim, prev_handle); + } + } + + if(bMipMaps) { + GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); + } else { + // GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); + GLDEBUG(glGenerateMipmap(GL_TEXTURE_CUBE_MAP)); } } - if(bMipMaps) { - GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); - } else { - // GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); - GLDEBUG(glGenerateMipmap(GL_TEXTURE_CUBE_MAP)); + if(prev_handle != 0) { + getContext().getTextureManager()->memoryChanged(-prev_mem_size); + GLDEBUG(glDeleteTextures(1, &prev_handle)); } - return true; + + return success; } long KRTextureCube::getMemRequiredForSize(int max_dim) diff --git a/KREngine/kraken/KRTexturePVR.cpp b/KREngine/kraken/KRTexturePVR.cpp index 67a5897..97addbf 100644 --- a/KREngine/kraken/KRTexturePVR.cpp +++ b/KREngine/kraken/KRTexturePVR.cpp @@ -190,41 +190,40 @@ bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo #if GL_EXT_texture_storage - //void TexStorage2DEXT(enum target, sizei levels, enum internalformat, sizei width, sizei height); - //TexStorage2DEXT(target, ) - - int level_count=0; - int max_lod_width=0; - int max_lod_height=0; - for(std::list::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) { - if(width <= target_dim && height <= target_dim) { - if(max_lod_width == 0) { - max_lod_width = width; - max_lod_height = height; - } - if(width > current_lod_max_dim) { - current_lod_max_dim = width; - } - if(height > current_lod_max_dim) { - current_lod_max_dim = height; - } - level_count++; + if(target == GL_TEXTURE_CUBE_MAP_POSITIVE_X || target == GL_TEXTURE_2D) { + // Call glTexStorage2DEXT only for the first uploadTexture used when creating a texture + int level_count=0; + int max_lod_width=0; + int max_lod_height=0; + for(std::list::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) { + if(width <= target_dim && height <= target_dim) { + if(max_lod_width == 0) { + max_lod_width = width; + max_lod_height = height; + } + + level_count++; + } + + width = width >> 1; + if(width < 1) { + width = 1; + } + height = height >> 1; + if(height < 1) { + height = 1; + } } - - width = width >> 1; - if(width < 1) { - width = 1; + width = m_iWidth; + height = m_iHeight; + + if(target == GL_TEXTURE_CUBE_MAP_POSITIVE_X) { + glTexStorage2DEXT(GL_TEXTURE_CUBE_MAP, level_count, m_internalFormat, max_lod_width, max_lod_height); + } else if(target == GL_TEXTURE_2D) { + glTexStorage2DEXT(target, level_count, m_internalFormat, max_lod_width, max_lod_height); } - height = height >> 1; - if(height < 1) { - height = 1; - } - } - width = m_iWidth; - height = m_iHeight; - - glTexStorage2DEXT(target, level_count, m_internalFormat, max_lod_width, max_lod_height); + } #endif // Upload texture data