#define STB_IMAGE_IMPLEMENTATION #include "HydraTextureBufferManager.h" #include "../scheduler/HydraTaskScheduler.h" #include "../task/buffer/HydraCreateTextureTask.hpp" void HydraTextureBufferManager::Intialise() { m_textures.resize(MAX_TEXTURES); m_bindless_texture_ids.resize(MAX_TEXTURES); for (uint32_t tex_idx = 0; tex_idx < MAX_TEXTURES; tex_idx++) { m_available_texture_ids.push(tex_idx); m_bindless_texture_ids[tex_idx] = 0; } } void HydraTextureBufferManager::Shutdown() { for (uint32_t tex_idx = 0; tex_idx < MAX_TEXTURES; tex_idx++) { if (m_textures[tex_idx].texture_id != INVALID_HYDRA_ID) { DeleteTexture(tex_idx); } } } HydraID HydraTextureBufferManager::LoadTexture(std::string texture_filename) { HydraID texture_id = FindTexture(texture_filename); if (texture_id != INVALID_HYDRA_ID) { return texture_id; } void *data = nullptr; int width = 0; int height = 0; int channels = 0; //stbi_set_flip_vertically_on_load(true); data = stbi_load(texture_filename.c_str(), &width, &height, &channels, 0); if (data == nullptr) { return INVALID_HYDRA_ID; } uint32_t format = GL_RGBA; if (channels == 3) { format = GL_RGB; } HydraTaskScheduler *scheduler = GetEngine()->TaskScheduler(); HydraID create_tex_id = scheduler->CreateTask(HydraThreadAffinity::Render); HydraCreateTextureTask *create_tex_task = static_cast(scheduler->GetTask(create_tex_id)); HydraID tex_id = INVALID_HYDRA_ID; create_tex_task->Initialise(texture_filename, width, height, GL_RGBA8, format, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR, GL_UNSIGNED_BYTE, 5, data, &tex_id); scheduler->WaitForTask(create_tex_id); return tex_id; } HydraID HydraTextureBufferManager::FindTexture(std::string texture_name) { if (m_texture_lookup.find(texture_name) == m_texture_lookup.end()) { return INVALID_HYDRA_ID; } return m_texture_lookup.find(texture_name)->second; } void *HydraTextureBufferManager::GetTextureBuffer() { return &m_bindless_texture_ids[0]; } const HydraTextureBuffer &HydraTextureBufferManager::GetTexture(HydraID texture_id) { return m_textures[texture_id]; } HydraID HydraTextureBufferManager::_GetTextureID() { std::lock_guard lock(m_mutex); if (m_available_texture_ids.size() == 0) { return INVALID_HYDRA_ID; } HydraID id = m_available_texture_ids.front(); m_available_texture_ids.pop(); return id; } HydraID HydraTextureBufferManager::CreateTextureArray(std::string texture_name, uint32_t width, uint32_t height, uint32_t internal_format, uint32_t min_filter, uint32_t mag_filter, uint32_t levels ) { uint32_t gl_tex_id = 0; glCreateTextures(GL_TEXTURE_2D_ARRAY, 1, &gl_tex_id); glBindTexture(GL_TEXTURE_2D_ARRAY, gl_tex_id); glTextureStorage3D(gl_tex_id, 1, internal_format, width, height, levels); glTextureParameteri(gl_tex_id, GL_TEXTURE_MIN_FILTER, min_filter); glTextureParameteri(gl_tex_id, GL_TEXTURE_MAG_FILTER, mag_filter); glBindTexture(GL_TEXTURE_2D_ARRAY, 0); HydraTextureBuffer texture_buffer = {}; HydraID texture_id = _GetTextureID(); texture_buffer.texture_id = texture_id; texture_buffer.format = 0; texture_buffer.internal_format = internal_format; texture_buffer.width = width; texture_buffer.height = height; texture_buffer.gl_tex_id = gl_tex_id; texture_buffer.mag_filter = mag_filter; texture_buffer.min_filter = min_filter; m_textures[texture_id] = texture_buffer; m_texture_lookup.insert(std::pair(texture_name, texture_id)); return texture_id; } HydraID HydraTextureBufferManager::CreateTexture(std::string texture_name, uint32_t width, uint32_t height, uint32_t internal_format, uint32_t min_filter, uint32_t mag_filter, uint32_t format, uint32_t data_type, uint32_t mip_levels, void *data) { uint32_t gl_tex_id = 0; glCreateTextures(GL_TEXTURE_2D, 1, &gl_tex_id); glBindTexture(GL_TEXTURE_2D, gl_tex_id); glTextureStorage2D(gl_tex_id,1+ mip_levels, internal_format, width, height); if (data != nullptr) { glTextureSubImage2D( gl_tex_id, // level, xoffset, yoffset, width, height 0, 0, 0, width, height, format, data_type, data); if (mip_levels > 0) { glGenerateTextureMipmap(gl_tex_id); } } glTextureParameteri(gl_tex_id, GL_TEXTURE_MIN_FILTER, min_filter); glTextureParameteri(gl_tex_id, GL_TEXTURE_MAG_FILTER, mag_filter); glBindTexture(GL_TEXTURE_2D, 0); HydraTextureBuffer texture_buffer = {}; HydraID texture_id = _GetTextureID(); texture_buffer.texture_id = texture_id; texture_buffer.format = format; texture_buffer.internal_format = internal_format; texture_buffer.width = width; texture_buffer.height = height; texture_buffer.gl_tex_id = gl_tex_id; texture_buffer.mag_filter = mag_filter; texture_buffer.min_filter = min_filter; m_textures[texture_id] = texture_buffer; m_texture_lookup.insert(std::pair(texture_name, texture_id)); return texture_id; } void HydraTextureBufferManager::BindTexture(HydraID texture_id, uint32_t target) { if (texture_id >= MAX_TEXTURES) { return; } HydraTextureBuffer texture = m_textures[texture_id]; glBindTexture(target, texture.gl_tex_id); glTextureParameteri(texture.gl_tex_id, GL_TEXTURE_WRAP_S, GL_REPEAT); glTextureParameteri(texture.gl_tex_id, GL_TEXTURE_WRAP_T, GL_REPEAT); glTextureParameteri(texture.gl_tex_id, GL_TEXTURE_MIN_FILTER, texture.min_filter); glTextureParameteri(texture.gl_tex_id, GL_TEXTURE_MAG_FILTER, texture.mag_filter); texture.texture_binding = glGetTextureHandleARB(texture.gl_tex_id); glMakeTextureHandleResidentARB(texture.texture_binding); m_bindless_texture_ids[texture_id] = texture.texture_binding; } void HydraTextureBufferManager::UnbindTexture(HydraID texture_id) { glMakeTextureHandleNonResidentARB(texture_id); } void HydraTextureBufferManager::DeleteTexture(HydraID texture_id) { if (m_bindless_texture_ids[texture_id] != 0) { UnbindTexture(m_bindless_texture_ids[texture_id]); } }