Skip to content

Commit

Permalink
[rhi] texture compression and gpu uploading will now happen after all…
Browse files Browse the repository at this point in the history
… textures have been set to a material, so before all that, texture packing can now take place
  • Loading branch information
PanosK92 committed Nov 12, 2024
1 parent c35d3b2 commit 0340719
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 121 deletions.
2 changes: 1 addition & 1 deletion editor/ImGui/Implementation/ImGui_RHI.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ namespace ImGui::RHI
is_frame_texture = Renderer::GetRenderTarget(Renderer_RenderTarget::frame_output)->GetObjectId() == texture->GetObjectId();

// during engine startup, some textures might be loading in different threads
if (texture->IsReadyForUse())
if (texture->IsGpuReady())
{
cmd_list->SetTexture(Renderer_BindingsSrv::tex, texture);

Expand Down
2 changes: 1 addition & 1 deletion editor/Widgets/FileDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ void FileDialog::ShowMiddle()
// Image
if (RHI_Texture* texture = item.GetTexture())
{
if (texture->IsReadyForUse()) // This is possible for when the editor is reading from drive
if (texture->IsGpuReady()) // This is possible for when the editor is reading from drive
{
// Compute thumbnail size
ImVec2 image_size = ImVec2(static_cast<float>(texture->GetWidth()), static_cast<float>(texture->GetHeight()));
Expand Down
2 changes: 1 addition & 1 deletion editor/Widgets/IconLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Icon::Icon(IconType type, const string& file_path)

RHI_Texture* Icon::GetTexture() const
{
if (m_texture && m_texture->IsReadyForUse())
if (m_texture && m_texture->IsGpuReady())
{
return m_texture.get();
}
Expand Down
159 changes: 83 additions & 76 deletions runtime/RHI/RHI_Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ namespace Spartan
m_bits_per_channel = rhi_format_to_bits_per_channel(m_format);

RHI_Texture::RHI_CreateResource();
m_is_ready_for_use = true;
m_is_gpu_ready = true;

if (!compressonator::registered)
{
Expand All @@ -160,8 +160,6 @@ namespace Spartan

RHI_Texture::~RHI_Texture()
{
m_slices.clear();
m_slices.shrink_to_fit();
RHI_DestroyResource();
}

Expand Down Expand Up @@ -215,9 +213,7 @@ namespace Spartan
}
}

// the bytes have been saved, so we can now free some memory
m_slices.clear();
m_slices.shrink_to_fit();
ClearBytes();
}

// write properties
Expand All @@ -236,94 +232,95 @@ namespace Spartan

bool RHI_Texture::LoadFromFile(const string& file_path)
{
m_type = RHI_Texture_Type::Type2D;
m_depth = 1;
m_flags |= RHI_Texture_Srv;
m_object_name = FileSystem::GetFileNameFromFilePath(file_path);

if (!FileSystem::IsFile(file_path))
{
SP_LOG_ERROR("Invalid file path \"%s\".", file_path.c_str());
return false;
}

m_slices.clear();
m_slices.shrink_to_fit();
m_type = RHI_Texture_Type::Type2D;
m_depth = 1;
m_flags |= RHI_Texture_Srv;
m_object_name = FileSystem::GetFileNameFromFilePath(file_path);

ClearBytes();

// load from drive
if (FileSystem::IsEngineTextureFile(file_path))
{
if (FileSystem::IsEngineTextureFile(file_path))
auto file = make_unique<FileStream>(file_path, FileStream_Read);
if (!file->IsOpen())
{
auto file = make_unique<FileStream>(file_path, FileStream_Read);
if (!file->IsOpen())
{
SP_LOG_ERROR("Failed to load \"%s\".", file_path.c_str());
return false;
}
SP_LOG_ERROR("Failed to load \"%s\".", file_path.c_str());
return false;
}

// read mip info
file->Read(&m_object_size);
file->Read(&m_depth);
file->Read(&m_mip_count);
// read mip info
file->Read(&m_object_size);
file->Read(&m_depth);
file->Read(&m_mip_count);

// read mip data
m_slices.resize(m_depth);
for (RHI_Texture_Slice& slice : m_slices)
// read mip data
m_slices.resize(m_depth);
for (RHI_Texture_Slice& slice : m_slices)
{
slice.mips.resize(m_mip_count);
for (RHI_Texture_Mip& mip : slice.mips)
{
slice.mips.resize(m_mip_count);
for (RHI_Texture_Mip& mip : slice.mips)
{
file->Read(&mip.bytes);
}
file->Read(&mip.bytes);
}

// read properties
file->Read(&m_width);
file->Read(&m_height);
file->Read(&m_channel_count);
file->Read(&m_bits_per_channel);
file->Read(reinterpret_cast<uint32_t*>(&m_type));
file->Read(reinterpret_cast<uint32_t*>(&m_format));
file->Read(&m_flags);
SetObjectId(file->ReadAs<uint64_t>());
SetResourceFilePath(file->ReadAs<string>());
}
else if (FileSystem::IsSupportedImageFile(file_path))

// read properties
file->Read(&m_width);
file->Read(&m_height);
file->Read(&m_channel_count);
file->Read(&m_bits_per_channel);
file->Read(reinterpret_cast<uint32_t*>(&m_type));
file->Read(reinterpret_cast<uint32_t*>(&m_format));
file->Read(&m_flags);
SetObjectId(file->ReadAs<uint64_t>());
SetResourceFilePath(file->ReadAs<string>());
}
else if (FileSystem::IsSupportedImageFile(file_path))
{
vector<string> file_paths = { file_path };

// if this is an array, try to find all the textures
if (m_type == RHI_Texture_Type::Type2DArray)
{
vector<string> file_paths = { file_path };
string file_path_extension = FileSystem::GetExtensionFromFilePath(file_path);
string file_path_no_extension = FileSystem::GetFilePathWithoutExtension(file_path);
string file_path_no_digit = file_path_no_extension.substr(0, file_path_no_extension.size() - 1);

// if this is an array, try to find all the textures
if (m_type == RHI_Texture_Type::Type2DArray)
uint32_t index = 1;
string file_path_guess = file_path_no_digit + to_string(index) + file_path_extension;
while (FileSystem::Exists(file_path_guess))
{
string file_path_extension = FileSystem::GetExtensionFromFilePath(file_path);
string file_path_no_extension = FileSystem::GetFilePathWithoutExtension(file_path);
string file_path_no_digit = file_path_no_extension.substr(0, file_path_no_extension.size() - 1);

uint32_t index = 1;
string file_path_guess = file_path_no_digit + to_string(index) + file_path_extension;
while (FileSystem::Exists(file_path_guess))
{
file_paths.emplace_back(file_path_guess);
file_path_guess = file_path_no_digit + to_string(++index) + file_path_extension;
}
file_paths.emplace_back(file_path_guess);
file_path_guess = file_path_no_digit + to_string(++index) + file_path_extension;
}
}

// load texture
for (uint32_t slice_index = 0; slice_index < static_cast<uint32_t>(file_paths.size()); slice_index++)
// load texture
for (uint32_t slice_index = 0; slice_index < static_cast<uint32_t>(file_paths.size()); slice_index++)
{
if (!ImageImporterExporter::Load(file_paths[slice_index], slice_index, this))
{
if (!ImageImporterExporter::Load(file_paths[slice_index], slice_index, this))
{
SP_LOG_ERROR("Failed to load \"%s\".", file_path.c_str());
return false;
}
SP_LOG_ERROR("Failed to load \"%s\".", file_path.c_str());
return false;
}

// set resource file path so it can be used by the resource cache.
SetResourceFilePath(file_path);
}

// set resource file path so it can be used by the resource cache.
SetResourceFilePath(file_path);
}

if (!(m_flags & RHI_Texture_DontPrepareForGpu))
{
PrepareForGpu();
}

PrepareForGpu();
ComputeMemoryUsage();

return true;
Expand Down Expand Up @@ -432,7 +429,7 @@ namespace Spartan
if (cmd_list != nullptr)
{
// wait in case this texture loading in another thread
while (!IsReadyForUse())
while (!IsGpuReady())
{
SP_LOG_INFO("Waiting for texture \"%s\" to finish loading...", m_object_name.c_str());
this_thread::sleep_for(chrono::milliseconds(16));
Expand All @@ -449,23 +446,33 @@ namespace Spartan
}
}

void RHI_Texture::ClearBytes()
{
m_slices.clear();
m_slices.shrink_to_fit();
}

void RHI_Texture::PrepareForGpu()
{
// compress texture (if not alraedy compressed)
if ((m_flags & RHI_Texture_Compress) && !IsCompressedFormat(m_format))
SP_ASSERT(m_slices.size() > 0);
SP_ASSERT(m_slices[0].mips.size() > 0);

// compress
bool compress = m_flags & RHI_Texture_Compress;
bool not_compressed = !IsCompressedFormat(m_format);
if (compress && not_compressed)
{
compressonator::compress(this);
}

// create gpu resource
// upload to gpu
SP_ASSERT_MSG(RHI_CreateResource(), "Failed to create GPU resource");
m_is_ready_for_use = true;
m_is_gpu_ready = true;

// clear data
if (!(m_flags & RHI_Texture_KeepData))
{
m_slices.clear();
m_slices.shrink_to_fit();
ClearBytes();
}

ComputeMemoryUsage();
Expand Down
68 changes: 34 additions & 34 deletions runtime/RHI/RHI_Texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,59 +91,59 @@ namespace Spartan
bool LoadFromFile(const std::string& file_path) override;
//=======================================================

uint32_t GetWidth() const { return m_width; }
void SetWidth(const uint32_t width) { m_width = width; }

uint32_t GetHeight() const { return m_height; }
void SetHeight(const uint32_t height) { m_height = height; }

uint32_t GetBitsPerChannel() const { return m_bits_per_channel; }
void SetBitsPerChannel(const uint32_t bits) { m_bits_per_channel = bits; }
uint32_t GetBytesPerChannel() const { return m_bits_per_channel / 8; }
uint32_t GetBytesPerPixel() const { return (m_bits_per_channel / 8) * m_channel_count; }
uint32_t GetChannelCount() const { return m_channel_count; }
void SetChannelCount(const uint32_t channel_count) { m_channel_count = channel_count; }
RHI_Format GetFormat() const { return m_format; }
void SetFormat(const RHI_Format format) { m_format = format; }
uint32_t GetWidth() const { return m_width; }
void SetWidth(const uint32_t width) { m_width = width; }

uint32_t GetHeight() const { return m_height; }
void SetHeight(const uint32_t height) { m_height = height; }

uint32_t GetBitsPerChannel() const { return m_bits_per_channel; }
void SetBitsPerChannel(const uint32_t bits) { m_bits_per_channel = bits; }
uint32_t GetBytesPerChannel() const { return m_bits_per_channel / 8; }
uint32_t GetBytesPerPixel() const { return (m_bits_per_channel / 8) * m_channel_count; }

uint32_t GetChannelCount() const { return m_channel_count; }
void SetChannelCount(const uint32_t channel_count) { m_channel_count = channel_count; }

RHI_Format GetFormat() const { return m_format; }
void SetFormat(const RHI_Format format) { m_format = format; }

// external memory
void* GetExternalMemoryHandle() const { return m_rhi_external_memory; }
void SetExternalMemoryHandle(void* handle) { m_rhi_external_memory = handle; }

// misc
void ClearBytes();
void PrepareForGpu();
void SaveAsImage(const std::string& file_path);
static bool IsCompressedFormat(const RHI_Format format);
static size_t CalculateMipSize(uint32_t width, uint32_t height, uint32_t depth, RHI_Format format, uint32_t bits_per_channel, uint32_t channel_count);

// data
uint32_t GetMipCount() const { return m_mip_count; }
uint32_t GetDepth() const { return m_depth; }
bool HasData() const { return !m_slices.empty() && !m_slices[0].mips.empty() && !m_slices[0].mips[0].bytes.empty(); };
std::vector<RHI_Texture_Slice>& GetData() { return m_slices; }
uint32_t GetMipCount() const { return m_mip_count; }
uint32_t GetDepth() const { return m_depth; }
bool HasData() const { return !m_slices.empty() && !m_slices[0].mips.empty() && !m_slices[0].mips[0].bytes.empty(); };
RHI_Texture_Mip& CreateMip(const uint32_t array_index);
RHI_Texture_Mip& GetMip(const uint32_t array_index, const uint32_t mip_index);
RHI_Texture_Slice& GetSlice(const uint32_t array_index);

// flags
bool IsSrv() const { return m_flags & RHI_Texture_Srv; }
bool IsUav() const { return m_flags & RHI_Texture_Uav; }
bool IsVrs() const { return m_flags & RHI_Texture_Vrs; }
bool IsRt() const { return m_flags & RHI_Texture_Rtv; }
bool IsDsv() const { return IsRt() && IsDepthStencilFormat(); }
bool IsRtv() const { return IsRt() && IsColorFormat(); }
bool HasPerMipViews() const { return m_flags & RHI_Texture_PerMipViews; }
bool IsGrayscale() const { return m_flags & RHI_Texture_Greyscale; }
bool IsSrv() const { return m_flags & RHI_Texture_Srv; }
bool IsUav() const { return m_flags & RHI_Texture_Uav; }
bool IsVrs() const { return m_flags & RHI_Texture_Vrs; }
bool IsRt() const { return m_flags & RHI_Texture_Rtv; }
bool IsDsv() const { return IsRt() && IsDepthStencilFormat(); }
bool IsRtv() const { return IsRt() && IsColorFormat(); }
bool HasPerMipViews() const { return m_flags & RHI_Texture_PerMipViews; }
bool IsGrayscale() const { return m_flags & RHI_Texture_Greyscale; }
bool IsSemiTransparent() const { return m_flags & RHI_Texture_Transparent; }
bool HasExternalMemory() const { return m_flags & RHI_Texture_ExternalMemory; }

// format type
bool IsDepthFormat() const { return m_format == RHI_Format::D16_Unorm || m_format == RHI_Format::D32_Float || m_format == RHI_Format::D32_Float_S8X24_Uint; }
bool IsStencilFormat() const { return m_format == RHI_Format::D32_Float_S8X24_Uint; }
bool IsDepthFormat() const { return m_format == RHI_Format::D16_Unorm || m_format == RHI_Format::D32_Float || m_format == RHI_Format::D32_Float_S8X24_Uint; }
bool IsStencilFormat() const { return m_format == RHI_Format::D32_Float_S8X24_Uint; }
bool IsDepthStencilFormat() const { return IsDepthFormat() || IsStencilFormat(); }
bool IsColorFormat() const { return !IsDepthStencilFormat(); }
bool IsColorFormat() const { return !IsDepthStencilFormat(); }

// layout
void SetLayout(const RHI_Image_Layout layout, RHI_CommandList* cmd_list, uint32_t mip_index = rhi_all_mips, uint32_t mip_range = 0);
Expand All @@ -154,10 +154,10 @@ namespace Spartan
const auto& GetViewport() const { return m_viewport; }

// rhi
RHI_Texture_Type GetType() const { return m_type; }
RHI_Texture_Type GetType() const { return m_type; }
void*& GetRhiResource() { return m_rhi_resource; }
void* GetRhiSrv() const { return m_rhi_srv; }
void* GetRhiSrvMip(const uint32_t i) const { return m_rhi_srv_mips[i]; }
void* GetRhiSrv() const { return m_rhi_srv; }
void* GetRhiSrvMip(const uint32_t i) const { return m_rhi_srv_mips[i]; }
void* GetRhiDsv(const uint32_t i = 0) const { return m_rhi_dsv[i]; }
void* GetRhiRtv(const uint32_t i = 0) const { return m_rhi_rtv[i]; }
void RHI_DestroyResource();
Expand Down
2 changes: 1 addition & 1 deletion runtime/RHI/Vulkan/Vulkan_CommandList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1434,7 +1434,7 @@ namespace Spartan
}

// if the texture is null or it's still loading, ignore it
if (!texture || !texture->IsReadyForUse())
if (!texture || !texture->IsGpuReady())
return;

// get some texture info
Expand Down
2 changes: 1 addition & 1 deletion runtime/RHI/Vulkan/Vulkan_Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ namespace Spartan
stage(this);
if ((m_flags & RHI_Texture_KeepData) == 0)
{
m_slices.clear();
ClearBytes();
}
}

Expand Down
Loading

0 comments on commit 0340719

Please sign in to comment.