Skip to content

Commit 29733ff

Browse files
committed
[asset_system] Added the ability to bind arbitrary data to an asset name.
* Allows to set the initial state of the data. * Fixed crashes when 'data', 'preload' and 'operator[]' coroutine calls accessed a local 'Asset' object. * We now force a local param copy using the 'this' pointer syntax. * Added new 'data_copy' utiity function.
1 parent 9ee9ede commit 29733ff

File tree

13 files changed

+190
-34
lines changed

13 files changed

+190
-34
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#pragma once
2+
#include <ice/mem_allocator.hxx>
3+
4+
namespace ice
5+
{
6+
7+
inline auto data_copy(ice::Allocator& alloc, ice::Data data) noexcept -> ice::Memory
8+
{
9+
ice::Memory const result = alloc.allocate({ data.size, data.alignment });
10+
if (result.location != nullptr)
11+
{
12+
ice::memcpy(result, data);
13+
}
14+
return result;
15+
}
16+
17+
} // namespace ice

source/code/systems/asset_system/private/asset.cxx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,25 +122,25 @@ namespace ice
122122
return _handle->data_for_state(state).location != nullptr;
123123
}
124124

125-
auto Asset::preload(ice::AssetState state) noexcept -> ice::Task<>
125+
auto Asset::resource() const noexcept -> ice::Resource const*
126126
{
127-
co_await data(state);
127+
return ice::asset_data_resource(_handle->_data);
128128
}
129129

130-
auto Asset::data(ice::AssetState state) noexcept -> ice::Task<ice::Data>
130+
auto Asset::preload(this ice::Asset self, ice::AssetState state) noexcept -> ice::Task<>
131131
{
132-
co_return co_await _handle->_shelve->storage.request(*this, state);
132+
co_await self.data(state);
133133
}
134134

135-
auto Asset::resource() const noexcept -> ice::Resource const*
135+
auto Asset::data(this ice::Asset self, ice::AssetState state) noexcept -> ice::Task<ice::Data>
136136
{
137-
return ice::asset_data_resource(_handle->_data);
137+
co_return co_await self._handle->_shelve->storage.request(self, state);
138138
}
139139

140-
auto Asset::operator[](ice::AssetState state) noexcept -> ice::Task<ice::Data>
140+
auto Asset::operator[](this ice::Asset self, ice::AssetState state) noexcept -> ice::Task<ice::Data>
141141
{
142-
ICE_ASSERT(_handle != nullptr, "Invalid Asset object!");
143-
co_return co_await data(state);
142+
ICE_ASSERT(self._handle != nullptr, "Invalid Asset object!");
143+
co_return co_await self.data(state);
144144
}
145145

146146
auto Asset::start_transaction(

source/code/systems/asset_system/private/asset_data.hxx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <ice/asset.hxx>
66
#include <ice/config.hxx>
77
#include <ice/mem_unique_ptr.hxx>
8+
#include <ice/mem_allocator_utils.hxx>
89
#include <ice/resource.hxx>
910
#include <ice/resource_tracker.hxx>
1011

@@ -103,6 +104,11 @@ namespace ice
103104
ice::ResourceAssetData* resdata = static_cast<ice::ResourceAssetData*>(data.get());
104105
co_return co_await ice::resource_meta(resdata->_resource_handle, out_data);
105106
}
107+
else if (ice::has_any(data->_flags, AssetDataFlags::Allocated))
108+
{
109+
out_data = { data->_readwrite, data->_size, data->_alignment };
110+
co_return S_Success;
111+
}
106112
else // The data stored in this object is pure metadata
107113
{
108114
out_data = { data->_readonly, data->_size, data->_alignment };
@@ -158,13 +164,14 @@ namespace ice
158164
ice::Allocator& alloc,
159165
ice::AssetState state,
160166
ice::Allocator& data_alloc,
161-
ice::Memory asset_memory
167+
ice::Memory asset_memory,
168+
ice::AssetDataFlags additional_flags = AssetDataFlags::None
162169
) noexcept -> ice::UniquePtr<ice::AllocatedAssetData>
163170
{
164171
ice::AllocatedAssetData* data = alloc.create<ice::AllocatedAssetData>();
165172
data->_next = nullptr;
166173
data->_alloc = ice::addressof(alloc);
167-
data->_flags = AssetDataFlags::Allocated;
174+
data->_flags = AssetDataFlags::Allocated | additional_flags;
168175
data->_state = state;
169176
data->_alignment = asset_memory.alignment;
170177
data->_size = asset_memory.size;
@@ -208,4 +215,21 @@ namespace ice
208215
return ice::make_unique(ice::destroy_asset_data_entry<ice::AssetData>, data);
209216
}
210217

218+
inline auto create_asset_data_entry(
219+
ice::Allocator& alloc,
220+
ice::AssetState state,
221+
ice::Allocator& data_alloc,
222+
ice::Data asset_data,
223+
ice::Data metadata_data
224+
) noexcept -> ice::UniquePtr<ice::AssetData>
225+
{
226+
ice::UniquePtr<ice::AssetData> result = ice::create_asset_data_entry(
227+
alloc, state, data_alloc, ice::data_copy(data_alloc, asset_data)
228+
);
229+
result->_next = ice::create_asset_data_entry(
230+
alloc, state, data_alloc, ice::data_copy(data_alloc, metadata_data), AssetDataFlags::Metadata
231+
);
232+
return result;
233+
}
234+
211235
} // namespace ice

source/code/systems/asset_system/private/asset_entry.hxx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ namespace ice
3333
inline AssetHandle(
3434
ice::StringID_Hash id,
3535
ice::AssetShelve* shelve,
36-
ice::UniquePtr<ice::ResourceAssetData> resource
36+
ice::UniquePtr<ice::AssetData> resource
3737
) noexcept;
3838
inline AssetHandle(ice::AssetHandle&& other) noexcept;
3939

@@ -68,7 +68,7 @@ namespace ice
6868
inline AssetHandle::AssetHandle(
6969
ice::StringID_Hash id,
7070
ice::AssetShelve* shelve,
71-
ice::UniquePtr<ice::ResourceAssetData> resource
71+
ice::UniquePtr<ice::AssetData> resource
7272
) noexcept
7373
: _identifier{ id }
7474
, _shelve{ shelve }
@@ -102,7 +102,7 @@ namespace ice
102102
inline AssetEntryFinal(
103103
ice::HeapString<> name,
104104
ice::AssetShelve* shelve,
105-
ice::UniquePtr<ice::ResourceAssetData> resource
105+
ice::UniquePtr<ice::AssetData> resource
106106
) noexcept;
107107
inline AssetEntryFinal(AssetEntryFinal const& other) noexcept;
108108

@@ -129,11 +129,12 @@ namespace ice
129129
inline AssetEntryFinal<IsDebug>::AssetEntryFinal(
130130
ice::HeapString<> name,
131131
ice::AssetShelve* shelve,
132-
ice::UniquePtr<ice::ResourceAssetData> resource
132+
ice::UniquePtr<ice::AssetData> resource
133133
) noexcept
134134
: AssetHandle{ ice::stringid(name), shelve, ice::move(resource) }
135135
, debug_name{ ice::move(name) }
136136
{
137+
_identifier = ice::stringid(debug_name);
137138
}
138139

139140
template<bool IsDebug>

source/code/systems/asset_system/private/asset_request_awaitable.cxx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@ namespace ice
1212
{
1313

1414
AssetRequestAwaitable::AssetRequestAwaitable(
15-
ice::StringID_Arg asset_name,
1615
ice::AssetStateTransaction& transaction
1716
) noexcept
1817
: _next{ nullptr }
1918
, _prev{ nullptr }
2019
, _chained{ nullptr }
21-
, _asset_name{ asset_name }
2220
, _asset_shelve{ transaction.shelve }
2321
, _transaction{ transaction }
2422
, _result_data{ }

source/code/systems/asset_system/private/asset_request_awaitable.hxx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ namespace ice
1616
{
1717
public:
1818
AssetRequestAwaitable(
19-
ice::StringID_Arg asset_name,
2019
ice::AssetStateTransaction& transation
2120
) noexcept;
2221

@@ -46,7 +45,6 @@ namespace ice
4645
AssetRequestAwaitable* _chained;
4746

4847
private:
49-
ice::StringID const _asset_name;
5048
ice::AssetShelve& _asset_shelve;
5149
ice::AssetStateTransaction& _transaction;
5250
ice::Memory _result_data;

source/code/systems/asset_system/private/asset_shelve.cxx

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
#include "asset_shelve.hxx"
55
#include "asset_entry.hxx"
66
#include "asset_request_awaitable.hxx"
7-
#include <ice/task_utils.hxx>
8-
#include <ice/string/heap_string.hxx>
7+
8+
#include <ice/assert.hxx>
99
#include <ice/container/hashmap.hxx>
10+
#include <ice/mem_allocator_utils.hxx>
1011
#include <ice/profiler.hxx>
11-
#include <ice/assert.hxx>
12+
#include <ice/string/heap_string.hxx>
13+
#include <ice/task_utils.hxx>
1214

1315
namespace ice
1416
{
@@ -93,6 +95,45 @@ namespace ice
9395
return *entry;
9496
}
9597

98+
auto AssetShelve::store(
99+
ice::StringID_Arg name,
100+
ice::AssetDataBinding const& data_binding
101+
) noexcept -> ice::AssetEntry*
102+
{
103+
ice::UniquePtr<ice::AssetData> resource_data = ice::create_asset_data_entry(
104+
_allocator,
105+
data_binding.state,
106+
_allocator,
107+
data_binding.content,
108+
data_binding.metadata
109+
);
110+
111+
ice::u64 const name_hash = ice::hash(name);
112+
if constexpr (ice::AssetEntry::HoldsDebugData)
113+
{
114+
ice::HeapString<> asset_name{ _allocator, ice::stringid_hint(name) };
115+
116+
ice::hashmap::set(
117+
_asset_resources,
118+
name_hash,
119+
_allocator.create<ice::AssetEntry>(ice::move(asset_name), this, ice::move(resource_data))
120+
);
121+
}
122+
else
123+
{
124+
ice::hashmap::set(
125+
_asset_resources,
126+
name_hash,
127+
_allocator.create<ice::AssetEntry>(name, this, ice::move(resource_data))
128+
);
129+
}
130+
131+
ice::AssetEntry** entry = ice::hashmap::try_get(_asset_resources, name_hash);
132+
ICE_ASSERT_CORE(entry != nullptr);
133+
ICE_ASSERT_CORE(*entry != nullptr);
134+
return *entry;
135+
}
136+
96137
void AssetShelve::append_request(
97138
ice::AssetRequestAwaitable* request,
98139
ice::AssetState state

source/code/systems/asset_system/private/asset_shelve.hxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#pragma once
55
#include <ice/mem_allocator.hxx>
66
#include <ice/asset_category_archive.hxx>
7+
#include <ice/asset_storage.hxx>
78
#include <ice/devui_widget.hxx>
89
#include <atomic>
910

@@ -39,6 +40,11 @@ namespace ice
3940
ice::ResourceHandle const& resource_handle
4041
) noexcept -> ice::AssetEntry*;
4142

43+
auto store(
44+
ice::StringID_Arg name,
45+
ice::AssetDataBinding const& data_binding
46+
) noexcept -> ice::AssetEntry*;
47+
4248
void append_request(
4349
ice::AssetRequestAwaitable* request,
4450
ice::AssetState state

source/code/systems/asset_system/private/asset_storage.cxx

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "asset_request_awaitable.hxx"
99
#include "asset_transaction.hxx"
1010

11+
#include <ice/mem_allocator_utils.hxx>
1112
#include <ice/config.hxx>
1213

1314
namespace ice
@@ -321,11 +322,7 @@ namespace ice
321322
if (resource_handle.valid())
322323
{
323324
// Create a new asset entry if the handle exists
324-
entry = shelve->store(
325-
ice::stringid(name),
326-
resource_handle
327-
);
328-
325+
entry = shelve->store(ice::stringid(name), resource_handle);
329326
ICE_ASSERT_CORE(entry != nullptr);
330327

331328
//ice::u32 const prev_count = entry->_refcount.fetch_add(1, std::memory_order_relaxed);
@@ -337,6 +334,62 @@ namespace ice
337334
return result;
338335
}
339336

337+
auto DefaultAssetStorage::bind_data(
338+
ice::AssetCategory_Arg category,
339+
ice::String name,
340+
ice::AssetDataBinding const& data_binding
341+
) noexcept -> ice::Asset
342+
{
343+
Asset result{ };
344+
// CHECK: Always called from the same thread.
345+
// OR TODO: Think of how to make it MT + lock-free
346+
347+
// TODO: Can we have empty assets?
348+
if (data_binding.content.location == nullptr)
349+
{
350+
return result;
351+
}
352+
353+
ice::AssetShelve* shelve = nullptr;
354+
ice::AssetEntry* entry = nullptr;
355+
if (find_shelve_and_entry(category, name, shelve, entry))
356+
{
357+
result = Asset{ entry };
358+
359+
// We need to ensure the previous count was higher else the asset might be released already
360+
ice::u32 const curr_count = entry->_refcount.load(std::memory_order_relaxed);
361+
if (curr_count == 1)
362+
{
363+
// Only keep metadata data
364+
while (entry->_data != nullptr)
365+
{
366+
// TODO: Add an sleep statement?
367+
//IPT_MESSAGE_C("Asset waiting for 'Release' operation to finish.", 0xEE8866);
368+
}
369+
370+
entry->_data = ice::create_asset_data_entry(
371+
_allocator,
372+
data_binding.state,
373+
_allocator,
374+
data_binding.content,
375+
data_binding.metadata
376+
);
377+
}
378+
}
379+
else if (shelve != nullptr)
380+
{
381+
// Create a new asset entry if the handle exists
382+
entry = shelve->store(ice::stringid(name), data_binding);
383+
ICE_ASSERT_CORE(entry != nullptr);
384+
385+
//ice::u32 const prev_count = entry->_refcount.fetch_add(1, std::memory_order_relaxed);
386+
//ICE_ASSERT(prev_count == 0, "Unexpected value!");
387+
388+
result = Asset{ entry };
389+
}
390+
return result;
391+
}
392+
340393
auto DefaultAssetStorage::preload(
341394
ice::AssetCategory_Arg category,
342395
ice::String name,
@@ -402,7 +455,7 @@ namespace ice
402455
// We request a baked resource first
403456
co_await request_asset_loaded(transaction);
404457

405-
ice::Memory runtime_data = co_await AssetRequestAwaitable{ StringID_Invalid, transaction };
458+
ice::Memory runtime_data = co_await AssetRequestAwaitable{ transaction };
406459

407460
// ICE_ASSERT_CORE(runtime_data.location == transaction.result_data->readwrite);
408461

source/code/systems/asset_system/private/asset_storage.hxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ namespace ice
4646
ice::String name
4747
) noexcept -> ice::Asset override;
4848

49+
auto bind_data(
50+
ice::AssetCategory_Arg category,
51+
ice::String name,
52+
ice::AssetDataBinding const& data_binding
53+
) noexcept -> ice::Asset override;
54+
4955
auto preload(
5056
ice::AssetCategory_Arg category,
5157
ice::String name,

0 commit comments

Comments
 (0)