Skip to content

Commit

Permalink
resource: implement texture hot-reloading
Browse files Browse the repository at this point in the history
Fixes: #186
  • Loading branch information
dbartolini committed Nov 5, 2024
1 parent 2737da6 commit 7e5e916
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 35 deletions.
5 changes: 4 additions & 1 deletion src/device/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -873,10 +873,13 @@ void Device::refresh(const char *json)
StringId64 resource_type(type);
StringId64 resource_name(resource.c_str(), len);

_resource_manager->reload(resource_type, resource_name);
const void *old_resource = _resource_manager->get(resource_type, resource_name);
const void *new_resource = _resource_manager->reload(resource_type, resource_name);

if (resource_type == RESOURCE_TYPE_SCRIPT) {
refresh_lua = true;
} else if (resource_type == RESOURCE_TYPE_TEXTURE) {
_material_manager->reload_textures((TextureResource *)old_resource, (TextureResource *)new_resource);
}
}

Expand Down
29 changes: 29 additions & 0 deletions src/world/material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* SPDX-License-Identifier: MIT
*/

#include "core/containers/array.inl"
#include "core/strings/string_id.inl"
#include "resource/material_resource.h"
#include "resource/resource_manager.h"
Expand All @@ -13,6 +14,14 @@

namespace crown
{
Material::Material(Allocator &a)
#if CROWN_CAN_RELOAD
: _texture_resources(a)
#endif
{
CE_UNUSED(a);
}

void Material::bind(ShaderManager &sm, u8 view, s32 depth) const
{
using namespace material_resource;
Expand Down Expand Up @@ -88,6 +97,26 @@ void Material::set_texture(StringId32 sampler_name, ResourceId texture_resource)
u32 idx = material_resource::texture_data_index(_resource, td, sampler_name);
TextureHandle *th = (TextureHandle *)material_resource::texture_handle(td, idx, _data);
th->texture_handle = tr->handle.idx;
#if CROWN_CAN_RELOAD
u32 index = material_resource::texture_data_index(_resource, td, sampler_name);
_texture_resources[index] = (TextureResource *)tr;
#endif
}

void Material::reload_textures(const TextureResource *old_resource, const TextureResource *new_resource)
{
#if CROWN_CAN_RELOAD
const TextureData *td = material_resource::texture_data_array(_resource);
for (u32 i = 0; i < array::size(_texture_resources); ++i) {
if (_texture_resources[i] == old_resource) {
_texture_resources[i] = (TextureResource *)new_resource;
TextureHandle *th = material_resource::texture_handle(td, i, _data);
th->texture_handle = new_resource->handle.idx;
}
}
#else
CE_UNUSED_2(old_resource, new_resource);
#endif
}

} // namespace crown
10 changes: 10 additions & 0 deletions src/world/material.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#pragma once

#include "config.h"
#include "core/math/types.h"
#include "resource/resource_id.h"
#include "resource/types.h"
Expand All @@ -20,6 +21,12 @@ struct Material
ResourceManager *_resource_manager;
const MaterialResource *_resource;
char *_data;
#if CROWN_CAN_RELOAD
Array<TextureResource *> _texture_resources;
#endif

///
explicit Material(Allocator &a);

///
void bind(ShaderManager &sm, u8 view, s32 depth = 0) const;
Expand All @@ -41,6 +48,9 @@ struct Material

/// Sets the @a texture_resource of the sampler @a sampler_name.
void set_texture(StringId32 sampler_name, ResourceId texture_resource);

///
void reload_textures(const TextureResource *old_resource, const TextureResource *new_resource);
};

} // namespace crown
75 changes: 44 additions & 31 deletions src/world/material_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* SPDX-License-Identifier: MIT
*/

#include "core/containers/array.inl"
#include "core/containers/hash_map.inl"
#include "core/filesystem/file.h"
#include "core/strings/string_id.inl"
Expand Down Expand Up @@ -48,78 +49,75 @@ void MaterialManager::online(StringId64 id, ResourceManager &rm)
using namespace material_resource;

MaterialResource *mr = (MaterialResource *)rm.get(RESOURCE_TYPE_MATERIAL, id);

char *base = (char *)mr + mr->dynamic_data_offset;
Material *material = create_material(mr);

const TextureData *td = texture_data_array(mr);
for (u32 i = 0; i < mr->num_textures; ++i) {
TextureHandle *th = texture_handle(td, i, base);
TextureHandle *th = texture_handle(td, i, material->_data);
TextureResource *tr = (TextureResource *)rm.get(RESOURCE_TYPE_TEXTURE, td->id);
th->sampler_handle = bgfx::createUniform(texture_name(mr, td, i), bgfx::UniformType::Sampler).idx;
th->texture_handle = tr->handle.idx;
#if CROWN_CAN_RELOAD
material->_texture_resources[i] = tr;
#endif
}

const UniformData *ud = uniform_data_array(mr);
for (u32 i = 0; i < mr->num_uniforms; ++i) {
UniformHandle *uh = uniform_handle(ud, i, base);
UniformHandle *uh = uniform_handle(ud, i, material->_data);
uh->uniform_handle = bgfx::createUniform(uniform_name(mr, ud, i), s_bgfx_uniform_type[ud->type]).idx;
}

create_material(mr);
}

void MaterialManager::offline(StringId64 id, ResourceManager &rm)
{
using namespace material_resource;

MaterialResource *mr = (MaterialResource *)rm.get(RESOURCE_TYPE_MATERIAL, id);

destroy_material(mr);

char *base = (char *)mr + mr->dynamic_data_offset;
const MaterialResource *mr = (MaterialResource *)rm.get(RESOURCE_TYPE_MATERIAL, id);
Material *material = hash_map::get(_materials, mr, (Material *)NULL);

const TextureData *td = texture_data_array(mr);
for (u32 i = 0; i < mr->num_textures; ++i) {
TextureHandle *th = texture_handle(td, i, base);
TextureHandle *th = texture_handle(td, i, material->_data);
bgfx::UniformHandle sh;
sh.idx = th->sampler_handle;
bgfx::destroy(sh);
}

const UniformData *ud = uniform_data_array(mr);
for (u32 i = 0; i < mr->num_uniforms; ++i) {
UniformHandle *uh = uniform_handle(ud, i, base);
UniformHandle *uh = uniform_handle(ud, i, material->_data);
bgfx::UniformHandle bgfx_uh;
bgfx_uh.idx = uh->uniform_handle;
bgfx::destroy(bgfx_uh);
}

CE_DELETE(*_allocator, material);
hash_map::remove(_materials, mr);
}

Material *MaterialManager::create_material(const MaterialResource *resource)
{
Material *mat = hash_map::get(_materials, resource, (Material *)NULL);
if (mat != NULL)
return mat;
Material *material = hash_map::get(_materials, resource, (Material *)NULL);
if (material != NULL)
return material;

const u32 size = sizeof(Material) + resource->dynamic_data_size;
mat = (Material *)_allocator->allocate(size);
mat->_resource_manager = _resource_manager;
mat->_resource = resource;
mat->_data = (char *)&mat[1];

const char *data = (char *)resource + resource->dynamic_data_offset;
memcpy(mat->_data, data, resource->dynamic_data_size);
material = (Material *)_allocator->allocate(size);
new (material) Material(*_allocator);
material->_resource_manager = _resource_manager;
material->_resource = resource;
material->_data = (char *)&material[1];

hash_map::set(_materials, resource, mat);
return mat;
}
const char *dynamic_data = (char *)resource + resource->dynamic_data_offset;
memcpy(material->_data, dynamic_data, resource->dynamic_data_size);

void MaterialManager::destroy_material(const MaterialResource *resource)
{
Material *mat = hash_map::get(_materials, resource, (Material *)NULL);
_allocator->deallocate(mat);
#if CROWN_CAN_RELOAD
array::resize(material->_texture_resources, resource->num_textures);
#endif

hash_map::remove(_materials, resource);
hash_map::set(_materials, resource, material);
return material;
}

Material *MaterialManager::get(const MaterialResource *resource)
Expand All @@ -128,4 +126,19 @@ Material *MaterialManager::get(const MaterialResource *resource)
return hash_map::get(_materials, resource, (Material *)NULL);
}

void MaterialManager::reload_textures(const TextureResource *old_resource, const TextureResource *new_resource)
{
#if CROWN_CAN_RELOAD
auto cur = hash_map::begin(_materials);
auto end = hash_map::end(_materials);
for (; cur != end; ++cur) {
HASH_MAP_SKIP_HOLE(_materials, cur);

cur->second->reload_textures(old_resource, new_resource);
}
#else
CE_UNUSED_2(old_resource, new_resource);
#endif
}

} // namespace crown
6 changes: 3 additions & 3 deletions src/world/material_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ struct MaterialManager
/// Instantiates the material @a resource.
Material *create_material(const MaterialResource *resource);

/// Destroys the instance of the material @a resource.
void destroy_material(const MaterialResource *resource);

/// Returns the instance of the material @a resource.
Material *get(const MaterialResource *resource);

///
void reload_textures(const TextureResource *old_resource, const TextureResource *new_resource);
};

} // namespace crown

0 comments on commit 7e5e916

Please sign in to comment.