Files
WickedEngine/WickedEngine/wiResourceManager.cpp
T
Turánszki János 74cb74d3c9 version 0.60 (#367)
- namespace refactor (example: wiGraphics:: -> wi::graphics)
  - provided namespace compatibility macro for old user code: WICKEDENGINE_BACKWARDS_COMPATIBILITY_0_59
- resource manager will return `Resource` instead of `shared_ptr<Resource>` objects
- MAD shader optimizations
- implemented alpha to coverage with alpha tested materials when MSAA is enabled
- alpha testing fix with transparent shadow maps
- TLAS and scene buffers will be recreated less frequently when things get added/removed from the scene
2021-12-03 21:22:27 +01:00

750 lines
26 KiB
C++

#include "wiResourceManager.h"
#include "wiRenderer.h"
#include "wiHelper.h"
#include "wiTextureHelper.h"
#include "wiUnorderedMap.h"
#include "Utility/stb_image.h"
#include "Utility/tinyddsloader.h"
#include "Utility/basis_universal/transcoder/basisu_transcoder.h"
extern basist::etc1_global_selector_codebook g_basis_global_codebook;
#include <algorithm>
#include <mutex>
using namespace wi::graphics;
namespace wi
{
struct ResourceInternal
{
resourcemanager::Flags flags = resourcemanager::Flags::NONE;
wi::graphics::Texture texture;
wi::audio::Sound sound;
wi::vector<uint8_t> filedata;
};
const wi::vector<uint8_t>& Resource::GetFileData() const
{
const ResourceInternal* resourceinternal = (ResourceInternal*)internal_state.get();
return resourceinternal->filedata;
}
const wi::graphics::Texture& Resource::GetTexture() const
{
const ResourceInternal* resourceinternal = (ResourceInternal*)internal_state.get();
return resourceinternal->texture;
}
const wi::audio::Sound& Resource::GetSound() const
{
const ResourceInternal* resourceinternal = (ResourceInternal*)internal_state.get();
return resourceinternal->sound;
}
void Resource::SetFileData(const wi::vector<uint8_t>& data)
{
if (internal_state == nullptr)
{
internal_state = std::make_shared<ResourceInternal>();
}
ResourceInternal* resourceinternal = (ResourceInternal*)internal_state.get();
resourceinternal->filedata = data;
}
void Resource::SetFileData(wi::vector<uint8_t>&& data)
{
if (internal_state == nullptr)
{
internal_state = std::make_shared<ResourceInternal>();
}
ResourceInternal* resourceinternal = (ResourceInternal*)internal_state.get();
resourceinternal->filedata = data;
}
void Resource::SetTexture(const wi::graphics::Texture& texture)
{
if (internal_state == nullptr)
{
internal_state = std::make_shared<ResourceInternal>();
}
ResourceInternal* resourceinternal = (ResourceInternal*)internal_state.get();
resourceinternal->texture = texture;
}
void Resource::SetSound(const wi::audio::Sound& sound)
{
if (internal_state == nullptr)
{
internal_state = std::make_shared<ResourceInternal>();
}
ResourceInternal* resourceinternal = (ResourceInternal*)internal_state.get();
resourceinternal->sound = sound;
}
namespace resourcemanager
{
static std::mutex locker;
static wi::unordered_map<std::string, std::weak_ptr<ResourceInternal>> resources;
static Mode mode = Mode::DISCARD_FILEDATA_AFTER_LOAD;
void SetMode(Mode param)
{
mode = param;
}
Mode GetMode()
{
return mode;
}
enum class DataType
{
IMAGE,
SOUND,
};
static const wi::unordered_map<std::string, DataType> types = {
std::make_pair("BASIS", DataType::IMAGE),
std::make_pair("KTX2", DataType::IMAGE),
std::make_pair("JPG", DataType::IMAGE),
std::make_pair("JPEG", DataType::IMAGE),
std::make_pair("PNG", DataType::IMAGE),
std::make_pair("BMP", DataType::IMAGE),
std::make_pair("DDS", DataType::IMAGE),
std::make_pair("TGA", DataType::IMAGE),
std::make_pair("WAV", DataType::SOUND),
std::make_pair("OGG", DataType::SOUND),
};
wi::vector<std::string> GetSupportedImageExtensions()
{
wi::vector<std::string> ret;
for (auto& x : types)
{
if (x.second == DataType::IMAGE)
{
ret.push_back(x.first);
}
}
return ret;
}
wi::vector<std::string> GetSupportedSoundExtensions()
{
wi::vector<std::string> ret;
for (auto& x : types)
{
if (x.second == DataType::SOUND)
{
ret.push_back(x.first);
}
}
return ret;
}
Resource Load(const std::string& name, Flags flags, const uint8_t* filedata, size_t filesize)
{
if (mode == Mode::DISCARD_FILEDATA_AFTER_LOAD)
{
flags &= ~Flags::IMPORT_RETAIN_FILEDATA;
}
locker.lock();
std::weak_ptr<ResourceInternal>& weak_resource = resources[name];
std::shared_ptr<ResourceInternal> resource = weak_resource.lock();
static bool basis_init = false; // within lock!
if (!basis_init)
{
basis_init = true;
basist::basisu_transcoder_init();
}
if (resource == nullptr)
{
resource = std::make_shared<ResourceInternal>();
resources[name] = resource;
locker.unlock();
}
else
{
locker.unlock();
Resource retVal;
retVal.internal_state = resource;
return retVal;
}
if (filedata == nullptr || filesize == 0)
{
if (!wi::helper::FileRead(name, resource->filedata))
{
resource.reset();
return Resource();
}
filedata = resource->filedata.data();
filesize = resource->filedata.size();
}
std::string ext = wi::helper::toUpper(wi::helper::GetExtensionFromFileName(name));
DataType type;
// dynamic type selection:
{
auto it = types.find(ext);
if (it != types.end())
{
type = it->second;
}
else
{
return Resource();
}
}
bool success = false;
switch (type)
{
case DataType::IMAGE:
{
GraphicsDevice* device = wi::graphics::GetDevice();
if (!ext.compare("KTX2"))
{
basist::ktx2_transcoder transcoder(&g_basis_global_codebook);
if (transcoder.init(filedata, (uint32_t)filesize))
{
TextureDesc desc;
desc.bind_flags = BindFlag::SHADER_RESOURCE;
desc.width = transcoder.get_width();
desc.height = transcoder.get_height();
desc.array_size = std::max(desc.array_size, transcoder.get_layers() * transcoder.get_faces());
desc.mip_levels = transcoder.get_levels();
if (transcoder.get_faces() == 6)
{
desc.misc_flags = ResourceMiscFlag::TEXTURECUBE;
}
basist::transcoder_texture_format fmt;
if (transcoder.get_has_alpha())
{
fmt = basist::transcoder_texture_format::cTFBC3_RGBA;
desc.format = Format::BC3_UNORM;
}
else
{
fmt = basist::transcoder_texture_format::cTFBC1_RGB;
desc.format = Format::BC1_UNORM;
}
uint32_t bytes_per_block = basis_get_bytes_per_block_or_pixel(fmt);
if (transcoder.start_transcoding())
{
// all subresources will use one allocation for transcoder destination, so compute combined size:
size_t transcoded_data_size = 0;
for (uint32_t layer = 0; layer < std::max(1u, transcoder.get_layers()); ++layer)
{
for (uint32_t face = 0; face < transcoder.get_faces(); ++face)
{
for (uint32_t mip = 0; mip < transcoder.get_levels(); ++mip)
{
basist::ktx2_image_level_info level_info;
if (transcoder.get_image_level_info(level_info, mip, layer, face))
{
transcoded_data_size += level_info.m_total_blocks * bytes_per_block;
}
}
}
}
wi::vector<uint8_t*> transcoded_data(transcoded_data_size);
wi::vector<SubresourceData> InitData;
size_t transcoded_data_offset = 0;
for (uint32_t layer = 0; layer < std::max(1u, transcoder.get_layers()); ++layer)
{
for (uint32_t face = 0; face < transcoder.get_faces(); ++face)
{
for (uint32_t mip = 0; mip < transcoder.get_levels(); ++mip)
{
basist::ktx2_image_level_info level_info;
if (transcoder.get_image_level_info(level_info, mip, layer, face))
{
void* data_ptr = transcoded_data.data() + transcoded_data_offset;
transcoded_data_offset += level_info.m_total_blocks * bytes_per_block;
if (transcoder.transcode_image_level(
mip, layer, face,
data_ptr,
level_info.m_total_blocks,
fmt
))
{
SubresourceData subresourceData;
subresourceData.data_ptr = data_ptr;
subresourceData.row_pitch = level_info.m_num_blocks_x * bytes_per_block;
subresourceData.slice_pitch = subresourceData.row_pitch * level_info.m_num_blocks_y;
InitData.push_back(subresourceData);
}
}
}
}
}
if (!InitData.empty())
{
success = device->CreateTexture(&desc, InitData.data(), &resource->texture);
device->SetName(&resource->texture, name.c_str());
}
}
transcoder.clear();
}
}
else if (!ext.compare("BASIS"))
{
basist::basisu_transcoder transcoder(&g_basis_global_codebook);
if (transcoder.validate_header(filedata, (uint32_t)filesize))
{
basist::basisu_file_info fileInfo;
if (transcoder.get_file_info(filedata, (uint32_t)filesize, fileInfo))
{
uint32_t image_index = 0;
basist::basisu_image_info info;
if (transcoder.get_image_info(filedata, (uint32_t)filesize, info, image_index))
{
TextureDesc desc;
desc.bind_flags = BindFlag::SHADER_RESOURCE;
desc.width = info.m_width;
desc.height = info.m_height;
desc.mip_levels = info.m_total_levels;
basist::transcoder_texture_format fmt;
if (info.m_alpha_flag)
{
fmt = basist::transcoder_texture_format::cTFBC3_RGBA;
desc.format = Format::BC3_UNORM;
}
else
{
fmt = basist::transcoder_texture_format::cTFBC1_RGB;
desc.format = Format::BC1_UNORM;
}
uint32_t bytes_per_block = basis_get_bytes_per_block_or_pixel(fmt);
if (transcoder.start_transcoding(filedata, (uint32_t)filesize))
{
// all subresources will use one allocation for transcoder destination, so compute combined size:
size_t transcoded_data_size = 0;
for (uint32_t mip = 0; mip < desc.mip_levels; ++mip)
{
basist::basisu_image_level_info level_info;
if (transcoder.get_image_level_info(filedata, (uint32_t)filesize, level_info, image_index, mip))
{
transcoded_data_size += level_info.m_total_blocks * bytes_per_block;
}
}
wi::vector<uint8_t*> transcoded_data(transcoded_data_size);
wi::vector<SubresourceData> InitData;
size_t transcoded_data_offset = 0;
for (uint32_t mip = 0; mip < desc.mip_levels; ++mip)
{
basist::basisu_image_level_info level_info;
if (transcoder.get_image_level_info(filedata, (uint32_t)filesize, level_info, 0, mip))
{
void* data_ptr = transcoded_data.data() + transcoded_data_offset;
transcoded_data_offset += level_info.m_total_blocks * bytes_per_block;
if (transcoder.transcode_image_level(
filedata, (uint32_t)filesize, image_index,
mip,
data_ptr,
info.m_total_blocks,
fmt
))
{
SubresourceData subresourceData;
subresourceData.data_ptr = data_ptr;
subresourceData.row_pitch = level_info.m_num_blocks_x * bytes_per_block;
subresourceData.slice_pitch = subresourceData.row_pitch * level_info.m_num_blocks_y;
InitData.push_back(subresourceData);
}
}
}
if (!InitData.empty())
{
success = device->CreateTexture(&desc, InitData.data(), &resource->texture);
device->SetName(&resource->texture, name.c_str());
}
}
}
}
}
}
else if (!ext.compare("DDS"))
{
// Load dds
tinyddsloader::DDSFile dds;
auto result = dds.Load(filedata, filesize);
if (result == tinyddsloader::Result::Success)
{
TextureDesc desc;
desc.array_size = 1;
desc.bind_flags = BindFlag::SHADER_RESOURCE;
desc.width = dds.GetWidth();
desc.height = dds.GetHeight();
desc.depth = dds.GetDepth();
desc.mip_levels = dds.GetMipCount();
desc.array_size = dds.GetArraySize();
desc.format = Format::R8G8B8A8_UNORM;
desc.layout = ResourceState::SHADER_RESOURCE;
if (dds.IsCubemap())
{
desc.misc_flags |= ResourceMiscFlag::TEXTURECUBE;
}
auto ddsFormat = dds.GetFormat();
switch (ddsFormat)
{
case tinyddsloader::DDSFile::DXGIFormat::R32G32B32A32_Float: desc.format = Format::R32G32B32A32_FLOAT; break;
case tinyddsloader::DDSFile::DXGIFormat::R32G32B32A32_UInt: desc.format = Format::R32G32B32A32_UINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R32G32B32A32_SInt: desc.format = Format::R32G32B32A32_SINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R32G32B32_Float: desc.format = Format::R32G32B32_FLOAT; break;
case tinyddsloader::DDSFile::DXGIFormat::R32G32B32_UInt: desc.format = Format::R32G32B32_UINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R32G32B32_SInt: desc.format = Format::R32G32B32_SINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R16G16B16A16_Float: desc.format = Format::R16G16B16A16_FLOAT; break;
case tinyddsloader::DDSFile::DXGIFormat::R16G16B16A16_UNorm: desc.format = Format::R16G16B16A16_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R16G16B16A16_UInt: desc.format = Format::R16G16B16A16_UINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R16G16B16A16_SNorm: desc.format = Format::R16G16B16A16_SNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R16G16B16A16_SInt: desc.format = Format::R16G16B16A16_SINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R32G32_Float: desc.format = Format::R32G32_FLOAT; break;
case tinyddsloader::DDSFile::DXGIFormat::R32G32_UInt: desc.format = Format::R32G32_UINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R32G32_SInt: desc.format = Format::R32G32_SINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R10G10B10A2_UNorm: desc.format = Format::R10G10B10A2_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R10G10B10A2_UInt: desc.format = Format::R10G10B10A2_UINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R11G11B10_Float: desc.format = Format::R11G11B10_FLOAT; break;
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm: desc.format = Format::B8G8R8A8_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB: desc.format = Format::B8G8R8A8_UNORM_SRGB; break;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm: desc.format = Format::R8G8B8A8_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB: desc.format = Format::R8G8B8A8_UNORM_SRGB; break;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UInt: desc.format = Format::R8G8B8A8_UINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SNorm: desc.format = Format::R8G8B8A8_SNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SInt: desc.format = Format::R8G8B8A8_SINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R16G16_Float: desc.format = Format::R16G16_FLOAT; break;
case tinyddsloader::DDSFile::DXGIFormat::R16G16_UNorm: desc.format = Format::R16G16_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R16G16_UInt: desc.format = Format::R16G16_UINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R16G16_SNorm: desc.format = Format::R16G16_SNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R16G16_SInt: desc.format = Format::R16G16_SINT; break;
case tinyddsloader::DDSFile::DXGIFormat::D32_Float: desc.format = Format::D32_FLOAT; break;
case tinyddsloader::DDSFile::DXGIFormat::R32_Float: desc.format = Format::R32_FLOAT; break;
case tinyddsloader::DDSFile::DXGIFormat::R32_UInt: desc.format = Format::R32_UINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R32_SInt: desc.format = Format::R32_SINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R8G8_UNorm: desc.format = Format::R8G8_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R8G8_UInt: desc.format = Format::R8G8_UINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R8G8_SNorm: desc.format = Format::R8G8_SNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R8G8_SInt: desc.format = Format::R8G8_SINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R16_Float: desc.format = Format::R16_FLOAT; break;
case tinyddsloader::DDSFile::DXGIFormat::D16_UNorm: desc.format = Format::D16_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R16_UNorm: desc.format = Format::R16_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R16_UInt: desc.format = Format::R16_UINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R16_SNorm: desc.format = Format::R16_SNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R16_SInt: desc.format = Format::R16_SINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R8_UNorm: desc.format = Format::R8_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R8_UInt: desc.format = Format::R8_UINT; break;
case tinyddsloader::DDSFile::DXGIFormat::R8_SNorm: desc.format = Format::R8_SNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::R8_SInt: desc.format = Format::R8_SINT; break;
case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm: desc.format = Format::BC1_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB: desc.format = Format::BC1_UNORM_SRGB; break;
case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm: desc.format = Format::BC2_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB: desc.format = Format::BC2_UNORM_SRGB; break;
case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm: desc.format = Format::BC3_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB: desc.format = Format::BC3_UNORM_SRGB; break;
case tinyddsloader::DDSFile::DXGIFormat::BC4_UNorm: desc.format = Format::BC4_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::BC4_SNorm: desc.format = Format::BC4_SNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm: desc.format = Format::BC5_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::BC5_SNorm: desc.format = Format::BC5_SNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::BC7_UNorm: desc.format = Format::BC7_UNORM; break;
case tinyddsloader::DDSFile::DXGIFormat::BC7_UNorm_SRGB: desc.format = Format::BC7_UNORM_SRGB; break;
default:
assert(0); // incoming format is not supported
break;
}
wi::vector<SubresourceData> InitData;
for (uint32_t arrayIndex = 0; arrayIndex < desc.array_size; ++arrayIndex)
{
for (uint32_t mip = 0; mip < desc.mip_levels; ++mip)
{
auto imageData = dds.GetImageData(mip, arrayIndex);
SubresourceData subresourceData;
subresourceData.data_ptr = imageData->m_mem;
subresourceData.row_pitch = imageData->m_memPitch;
subresourceData.slice_pitch = imageData->m_memSlicePitch;
InitData.push_back(subresourceData);
}
}
auto dim = dds.GetTextureDimension();
switch (dim)
{
case tinyddsloader::DDSFile::TextureDimension::Texture1D:
{
desc.type = TextureDesc::Type::TEXTURE_1D;
}
break;
case tinyddsloader::DDSFile::TextureDimension::Texture2D:
{
desc.type = TextureDesc::Type::TEXTURE_2D;
}
break;
case tinyddsloader::DDSFile::TextureDimension::Texture3D:
{
desc.type = TextureDesc::Type::TEXTURE_3D;
}
break;
default:
assert(0);
break;
}
if (IsFormatBlockCompressed(desc.format))
{
desc.width = std::max(GetFormatBlockSize(desc.format), desc.width);
desc.height = std::max(GetFormatBlockSize(desc.format), desc.height);
}
success = device->CreateTexture(&desc, InitData.data(), &resource->texture);
device->SetName(&resource->texture, name.c_str());
}
else assert(0); // failed to load DDS
}
else
{
// png, tga, jpg, etc. loader:
const int channelCount = 4;
int width, height, bpp;
unsigned char* rgb = stbi_load_from_memory(filedata, (int)filesize, &width, &height, &bpp, channelCount);
if (rgb != nullptr)
{
TextureDesc desc;
desc.height = uint32_t(height);
desc.width = uint32_t(width);
desc.layout = ResourceState::SHADER_RESOURCE;
if (has_flag(flags, Flags::IMPORT_COLORGRADINGLUT))
{
if (desc.type != TextureDesc::Type::TEXTURE_2D ||
desc.width != 256 ||
desc.height != 16)
{
wi::helper::messageBox("The Dimensions must be 256 x 16 for color grading LUT!", "Error");
}
else
{
uint32_t data[16 * 16 * 16];
int pixel = 0;
for (int z = 0; z < 16; ++z)
{
for (int y = 0; y < 16; ++y)
{
for (int x = 0; x < 16; ++x)
{
int coord = x + y * 256 + z * 16;
data[pixel++] = ((uint32_t*)rgb)[coord];
}
}
}
desc.type = TextureDesc::Type::TEXTURE_3D;
desc.width = 16;
desc.height = 16;
desc.depth = 16;
desc.format = Format::R8G8B8A8_UNORM;
desc.bind_flags = BindFlag::SHADER_RESOURCE;
SubresourceData InitData;
InitData.data_ptr = data;
InitData.row_pitch = 16 * sizeof(uint32_t);
InitData.slice_pitch = 16 * InitData.row_pitch;
success = device->CreateTexture(&desc, &InitData, &resource->texture);
device->SetName(&resource->texture, name.c_str());
}
}
else
{
desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS;
desc.format = Format::R8G8B8A8_UNORM;
desc.mip_levels = (uint32_t)log2(std::max(width, height)) + 1;
desc.usage = Usage::DEFAULT;
desc.layout = ResourceState::SHADER_RESOURCE;
uint32_t mipwidth = width;
wi::vector<SubresourceData> InitData(desc.mip_levels);
for (uint32_t mip = 0; mip < desc.mip_levels; ++mip)
{
InitData[mip].data_ptr = rgb; // attention! we don't fill the mips here correctly, just always point to the mip0 data by default. Mip levels will be created using compute shader when needed!
InitData[mip].row_pitch = static_cast<uint32_t>(mipwidth * channelCount);
mipwidth = std::max(1u, mipwidth / 2);
}
success = device->CreateTexture(&desc, InitData.data(), &resource->texture);
device->SetName(&resource->texture, name.c_str());
for (uint32_t i = 0; i < resource->texture.desc.mip_levels; ++i)
{
int subresource_index;
subresource_index = device->CreateSubresource(&resource->texture, SubresourceType::SRV, 0, 1, i, 1);
assert(subresource_index == i);
subresource_index = device->CreateSubresource(&resource->texture, SubresourceType::UAV, 0, 1, i, 1);
assert(subresource_index == i);
}
}
}
stbi_image_free(rgb);
}
}
break;
case DataType::SOUND:
{
success = wi::audio::CreateSound(filedata, filesize, &resource->sound);
}
break;
};
if (success)
{
resource->flags = flags;
if (resource->filedata.empty() && has_flag(flags, Flags::IMPORT_RETAIN_FILEDATA))
{
// resource was loaded with external filedata, and we want to retain filedata
resource->filedata.resize(filesize);
std::memcpy(resource->filedata.data(), filedata, filesize);
}
else if (!resource->filedata.empty() && has_flag(flags, Flags::IMPORT_RETAIN_FILEDATA) == 0)
{
// resource was loaded using file name, and we want to discard filedata
resource->filedata.clear();
}
if (type == DataType::IMAGE && resource->texture.desc.mip_levels > 1
&& has_flag(resource->texture.desc.bind_flags, BindFlag::UNORDERED_ACCESS))
{
wi::renderer::AddDeferredMIPGen(resource->texture, true);
}
Resource retVal;
retVal.internal_state = resource;
return retVal;
}
return Resource();
}
bool Contains(const std::string& name)
{
bool result = false;
locker.lock();
auto it = resources.find(name);
if (it != resources.end())
{
auto resource = it->second.lock();
result = resource != nullptr;
}
locker.unlock();
return result;
}
void Clear()
{
locker.lock();
resources.clear();
locker.unlock();
}
void Serialize(wi::Archive& archive, ResourceSerializer& seri)
{
if (archive.IsReadMode())
{
size_t serializable_count = 0;
archive >> serializable_count;
struct TempResource
{
std::string name;
Flags flags = Flags::NONE;
wi::vector<uint8_t> filedata;
};
wi::vector<TempResource> temp_resources;
temp_resources.resize(serializable_count);
wi::jobsystem::context ctx;
std::mutex seri_locker;
for (size_t i = 0; i < serializable_count; ++i)
{
auto& resource = temp_resources[i];
archive >> resource.name;
uint32_t flags_temp;
archive >> flags_temp;
resource.flags = (Flags)flags_temp;
archive >> resource.filedata;
resource.name = archive.GetSourceDirectory() + resource.name;
// "Loading" the resource can happen asynchronously to serialization of file data, to improve performance
wi::jobsystem::Execute(ctx, [i, &temp_resources, &seri_locker, &seri](wi::jobsystem::JobArgs args) {
auto& tmp_resource = temp_resources[i];
auto res = Load(tmp_resource.name, tmp_resource.flags, tmp_resource.filedata.data(), tmp_resource.filedata.size());
seri_locker.lock();
seri.resources.push_back(res);
seri_locker.unlock();
});
}
wi::jobsystem::Wait(ctx);
}
else
{
locker.lock();
size_t serializable_count = 0;
if (mode == Mode::ALLOW_RETAIN_FILEDATA_BUT_DISABLE_EMBEDDING)
{
// Simply not serialize any embedded resources
serializable_count = 0;
archive << serializable_count;
}
else
{
// Count embedded resources:
for (auto& it : resources)
{
std::shared_ptr<ResourceInternal> resource = it.second.lock();
if (resource != nullptr && !resource->filedata.empty())
{
serializable_count++;
}
}
// Write all embedded resources:
archive << serializable_count;
for (auto& it : resources)
{
std::shared_ptr<ResourceInternal> resource = it.second.lock();
if (resource != nullptr && !resource->filedata.empty())
{
std::string name = it.first;
wi::helper::MakePathRelative(archive.GetSourceDirectory(), name);
archive << name;
archive << (uint32_t)resource->flags;
archive << resource->filedata;
}
}
}
locker.unlock();
}
}
}
}