Skip to content

Commit

Permalink
[rhi_texture] fixed an issue where the bistro world would load pre-co…
Browse files Browse the repository at this point in the history
…mpressed textures with mips and the engine would try to generate it's own compressed mips resulting in a crash
  • Loading branch information
PanosK92 committed Nov 13, 2024
1 parent c66fa71 commit df7da1d
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 81 deletions.
128 changes: 63 additions & 65 deletions runtime/RHI/RHI_Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,52 +116,56 @@ namespace Spartan
{
void downsample_bilinear(const vector<byte>& input, vector<byte>& output, uint32_t width, uint32_t height)
{
constexpr uint32_t channels = 4; // RGBA32
// Calculate new dimensions (halving both width and height)
constexpr uint32_t channels = 4; // RGBA32 - engine standard

// calculate new dimensions (halving both width and height)
uint32_t new_width = width >> 1;
uint32_t new_height = height >> 1;

// Ensure minimum size
// ensure minimum size
if (new_width < 1) new_width = 1;
if (new_height < 1) new_height = 1;

// Perform bilinear downsampling
// perform bilinear downsampling
for (uint32_t y = 0; y < new_height; y++)
{
for (uint32_t x = 0; x < new_width; x++)
{
// Calculate base indices for this 2x2 block
uint32_t src_idx = (y * 2 * width + x * 2) * channels;
uint32_t dst_idx = (y * new_width + x) * channels;

// Process all 4 channels (RGBA)
// calculate base indices for this 2x2 block
uint32_t src_idx = (y * 2 * width + x * 2) * channels;
uint32_t src_idx_right = src_idx + channels; // right pixel
uint32_t src_idx_bottom = src_idx + (width * channels); // bottom pixel
uint32_t src_idx_bottom_right = src_idx + (width * channels) + channels; // bottom-right pixel
uint32_t dst_idx = (y * new_width + x) * channels;

// process all 4 channels (RGBA)
for (uint32_t c = 0; c < channels; c++)
{
uint32_t sum = to_integer<uint32_t>(input[src_idx + c]);
uint32_t count = 1;
// Right pixel

// right pixel
if (x * 2 + 1 < width)
{
sum += to_integer<uint32_t>(input[src_idx + channels + c]);
sum += to_integer<uint32_t>(input[src_idx_right + c]);
count++;
}
// Bottom pixel

// bottom pixel
if (y * 2 + 1 < height)
{
sum += to_integer<uint32_t>(input[src_idx + (width * channels) + c]);
sum += to_integer<uint32_t>(input[src_idx_bottom + c]);
count++;
}
// Bottom-right pixel

// bottom-right pixel
if ((x * 2 + 1 < width) && (y * 2 + 1 < height))
{
sum += to_integer<uint32_t>(input[src_idx + (width * channels) + channels + c]);
sum += to_integer<uint32_t>(input[src_idx_bottom_right + c]);
count++;
}


// assign the averaged result to the output
output[dst_idx + c] = byte(sum / count);
}
}
Expand Down Expand Up @@ -398,32 +402,6 @@ namespace Spartan
return true;
}

RHI_Texture_Mip& RHI_Texture::CreateMip(const uint32_t array_index)
{
// ensure there's room for the new array index
while (array_index >= m_slices.size())
{
m_slices.emplace_back();
}

// add the mip
RHI_Texture_Mip& mip = m_slices[array_index].mips.emplace_back();
m_depth = static_cast<uint32_t>(m_slices.size());
m_mip_count = static_cast<uint32_t>(m_slices[0].mips.size());

// allocate memory if requested
{
uint32_t mip_index = static_cast<uint32_t>(m_slices[array_index].mips.size()) - 1;
uint32_t width = max(1u, m_width >> mip_index);
uint32_t height = max(1u, m_height >> mip_index);
uint32_t depth = (GetType() == RHI_Texture_Type::Type3D) ? (m_depth >> mip_index) : 1;
size_t size_bytes = CalculateMipSize(width, height, depth, m_format, m_bits_per_channel, m_channel_count);
mip.bytes.resize(size_bytes);
}

return mip;
}

RHI_Texture_Mip& RHI_Texture::GetMip(const uint32_t array_index, const uint32_t mip_index)
{
static RHI_Texture_Mip empty;
Expand All @@ -447,6 +425,24 @@ namespace Spartan
return m_slices[array_index];
}

void RHI_Texture::AllocateMip()
{
if (m_slices.empty())
{
m_slices.emplace_back();
}

RHI_Texture_Mip& mip = m_slices[0].mips.emplace_back();
m_depth = static_cast<uint32_t>(m_slices.size());
m_mip_count = static_cast<uint32_t>(m_slices[0].mips.size());
int32_t mip_index = static_cast<uint32_t>(m_slices[0].mips.size()) - 1;
uint32_t width = max(1u, m_width >> mip_index);
uint32_t height = max(1u, m_height >> mip_index);
uint32_t depth = (GetType() == RHI_Texture_Type::Type3D) ? (m_depth >> mip_index) : 1;
size_t size_bytes = CalculateMipSize(width, height, depth, m_format, m_bits_per_channel, m_channel_count);
mip.bytes.resize(size_bytes);
}

void RHI_Texture::ComputeMemoryUsage()
{
m_object_size = 0;
Expand Down Expand Up @@ -527,27 +523,29 @@ namespace Spartan
SP_ASSERT(m_slices.size() > 0);
SP_ASSERT(m_slices[0].mips.size() > 0);

// generate mips
uint32_t mip_count = mips::compute_count(m_width, m_height);
for (uint32_t mip_index = 1; mip_index < mip_count; mip_index++)
if (!IsCompressedFormat(m_format)) // the bistro world loads compressed textures with mips
{
const uint32_t width_above = max(1u, m_width >> (mip_index - 1));
const uint32_t height_above = max(1u, m_height >> (mip_index - 1));

mips::downsample_bilinear(
m_slices[0].mips[mip_index - 1].bytes, // above
CreateMip(0).bytes, // below
width_above,
height_above
);
}
// generate mip chain
uint32_t mip_count = mips::compute_count(m_width, m_height);
for (uint32_t mip_index = 1; mip_index < mip_count; mip_index++)
{
AllocateMip();

mips::downsample_bilinear(
m_slices[0].mips[mip_index - 1].bytes, // above
m_slices[0].mips[mip_index].bytes, // below
max(1u, m_width >> (mip_index - 1)), // above width
max(1u, m_height >> (mip_index - 1)) // above height
);
}

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

// upload to gpu
Expand Down
6 changes: 3 additions & 3 deletions runtime/RHI/RHI_Texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ namespace Spartan
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);
void AllocateMip();

// flags
bool IsSrv() const { return m_flags & RHI_Texture_Srv; }
Expand Down Expand Up @@ -168,8 +168,8 @@ namespace Spartan

uint32_t m_width = 0;
uint32_t m_height = 0;
uint32_t m_depth = 1;
uint32_t m_mip_count = 1;
uint32_t m_depth = 0;
uint32_t m_mip_count = 0;
uint32_t m_bits_per_channel = 0;
uint32_t m_channel_count = 0;
RHI_Format m_format = RHI_Format::Max;
Expand Down
20 changes: 10 additions & 10 deletions runtime/Rendering/Material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,24 +359,24 @@ namespace Spartan
// GetTexture(MaterialTextureType::Color)->GetMip(0, 0).bytes,
// GetTexture(MaterialTextureType::AlphaMask)->GetMip(0, 0).bytes
//);
//

//SetTexture(MaterialTextureType::AlphaMask, nullptr);
}

//ThreadPool::AddTask([this]() // if one mip waits for the previous one, we can multithread this here
//{
for (RHI_Texture* texture : m_textures)
for (RHI_Texture* texture : m_textures)
{
if (texture)
{
if (texture)
// check IsGpuReady() to avoid redundant PrepareForGpu() calls, as textures may be shared across materials and material slots
if (!texture->IsGpuReady())
{
// check IsGpuReady() to avoid redundant PrepareForGpu() calls, as textures may be shared across materials and material slots
if (!texture->IsGpuReady())
{
//ThreadPool::AddTask([texture]() // good perf gain if PrepareForGpu() becomes thread safe
//{
texture->PrepareForGpu();
}
//});
}
}
//});
}
}

uint32_t Material::GetUsedSlotCount() const
Expand Down
9 changes: 6 additions & 3 deletions runtime/Resource/Import/ImageImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,10 @@ namespace Spartan
// set data
for (uint32_t mip_index = 0; mip_index < dds_file.GetMipCount(); mip_index++)
{
RHI_Texture_Mip& mip = texture->CreateMip(0);
const auto& data = dds_file.GetImageData(mip_index, 0);
texture->AllocateMip();
RHI_Texture_Mip& mip = texture->GetMip(0, mip_index);

const auto& data = dds_file.GetImageData(mip_index, 0);
memcpy(&mip.bytes[0], data->m_mem, mip.bytes.size());
}

Expand Down Expand Up @@ -446,7 +448,8 @@ namespace Spartan
texture->SetFlag(RHI_Texture_Transparent, has_transparent_pixels(bitmap));

// copy data over
RHI_Texture_Mip& mip = texture->CreateMip(slice_index);
texture->AllocateMip();
RHI_Texture_Mip& mip = texture->GetMip(0, 0);
BYTE* bytes = FreeImage_GetBits(bitmap);
size_t bytes_size = FreeImage_GetPitch(bitmap) * FreeImage_GetHeight(bitmap);
mip.bytes.resize(bytes_size);
Expand Down

0 comments on commit df7da1d

Please sign in to comment.