Skip to content

Commit

Permalink
lightmap BC6H compression
Browse files Browse the repository at this point in the history
  • Loading branch information
turanszkij committed Jun 3, 2023
1 parent 66bdda7 commit 169e394
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 86 deletions.
25 changes: 24 additions & 1 deletion Editor/ObjectWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ void ObjectWindow::Create(EditorComponent* _editor)
editor = _editor;

wi::gui::Window::Create(ICON_OBJECT " Object", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE);
SetSize(XMFLOAT2(670, 640));
SetSize(XMFLOAT2(670, 700));

closeButton.SetTooltip("Delete ObjectComponent");
OnClose([=](wi::gui::EventArgs args) {
Expand Down Expand Up @@ -437,6 +437,24 @@ void ObjectWindow::Create(EditorComponent* _editor)
});
AddWidget(&lightmapResolutionSlider);

lightmapBlockCompressionCheckBox.Create("Block Compression (BC6H): ");
lightmapBlockCompressionCheckBox.SetTooltip("Enabling block compression for lightmaps will reduce memory usage, but it can lead to reduced quality.\nIf enabled, lightmaps will use BC6H block compression.\nIf disabled, lightmaps will use R11G11B10_FLOAT packing.\nChanging this will take effect after a new lightmap was generated.");
lightmapBlockCompressionCheckBox.SetSize(XMFLOAT2(hei, hei));
lightmapBlockCompressionCheckBox.SetPos(XMFLOAT2(x, y += step));
lightmapBlockCompressionCheckBox.SetCheck(true);
lightmapBlockCompressionCheckBox.OnClick([&](wi::gui::EventArgs args) {
wi::scene::Scene& scene = editor->GetCurrentScene();
for (auto& x : editor->translator.selected)
{
ObjectComponent* object = scene.objects.GetComponent(x.entity);
if (object != nullptr)
{
object->SetLightmapDisableBlockCompression(!args.bValue);
}
}
});
AddWidget(&lightmapBlockCompressionCheckBox);

lightmapSourceUVSetComboBox.Create("UV Set: ");
lightmapSourceUVSetComboBox.SetPos(XMFLOAT2(x, y += step));
lightmapSourceUVSetComboBox.SetSize(XMFLOAT2(wid, hei));
Expand Down Expand Up @@ -666,6 +684,8 @@ void ObjectWindow::SetEntity(Entity entity)
break;
}

lightmapBlockCompressionCheckBox.SetCheck(!object->IsLightmapDisableBlockCompression());

}
else
{
Expand Down Expand Up @@ -729,10 +749,13 @@ void ObjectWindow::ResizeLayout()
add(sortPrioritySlider);
add(colorComboBox);
add_fullwidth(colorPicker);

y += jump;
add(lightmapResolutionSlider);

margin_left = 80;

add_right(lightmapBlockCompressionCheckBox);
add(lightmapSourceUVSetComboBox);
add(generateLightmapButton);
add(stopLightmapGenButton);
Expand Down
1 change: 1 addition & 0 deletions Editor/ObjectWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class ObjectWindow : public wi::gui::Window
wi::gui::ColorPicker colorPicker;

wi::gui::Slider lightmapResolutionSlider;
wi::gui::CheckBox lightmapBlockCompressionCheckBox;
wi::gui::ComboBox lightmapSourceUVSetComboBox;
wi::gui::Button generateLightmapButton;
wi::gui::Button stopLightmapGenButton;
Expand Down
6 changes: 4 additions & 2 deletions WickedEngine/shaders/blockcompressCS_BC6H.hlsl
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Modified version of: https://github.com/knarkowicz/GPURealTimeBC6H/blob/master/bin/compress.hlsl
#include "globals.hlsli"

#pragma warning(disable : 3078) // "loop control variable conflicts with a previous declaration in the outer scope"

// Whether to use P2 modes (4 endpoints) for compression. Slow, but improves quality.
#ifdef COMPRESS_CUBEMAP
#define ENCODE_P2 0
#else
#define ENCODE_P2 1
#endif // COMPRESS_CUBEMAP

// Improve quality at small performance loss
#define INSET_COLOR_BBOX 1
Expand Down
4 changes: 2 additions & 2 deletions WickedEngine/wiRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8569,7 +8569,7 @@ void BlockCompress(const wi::graphics::Texture& texture_src, const wi::graphics:
desc.height = std::max(1u, texture_bc.desc.height / block_size);
desc.bind_flags = BindFlag::UNORDERED_ACCESS;
desc.layout = ResourceState::UNORDERED_ACCESS;
desc.mip_levels = GetMipCount(desc.width, desc.height); // full mipchain
desc.mip_levels = texture_bc.desc.mip_levels;

static Texture bc_raw_uint2;
static Texture bc_raw_uint4;
Expand Down Expand Up @@ -8641,7 +8641,7 @@ void BlockCompress(const wi::graphics::Texture& texture_src, const wi::graphics:
{
const uint32_t width = std::max(1u, desc.width >> mip);
const uint32_t height = std::max(1u, desc.height >> mip);
device->BindResource(&texture_src, 0, cmd, mip);
device->BindResource(&texture_src, 0, cmd, texture_src.desc.mip_levels == 1 ? -1 : mip);
device->BindUAV(bc_raw, 0, cmd, mip);
device->Dispatch((width + 7u) / 8u, (height + 7u) / 8u, desc.array_size, cmd);
}
Expand Down
18 changes: 17 additions & 1 deletion WickedEngine/wiScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3809,7 +3809,23 @@ namespace wi::scene
if (!object.lightmapTextureData.empty() && !object.lightmap.IsValid())
{
// Create a GPU-side per object lightmap if there is none yet, but the data exists already:
object.lightmap.desc.format = Format::R11G11B10_FLOAT;
const size_t lightmap_size = object.lightmapTextureData.size();
if (lightmap_size == object.lightmapWidth * object.lightmapHeight * sizeof(XMFLOAT4))
{
object.lightmap.desc.format = Format::R32G32B32A32_FLOAT;
}
else if (lightmap_size == object.lightmapWidth * object.lightmapHeight * sizeof(PackedVector::XMFLOAT3PK))
{
object.lightmap.desc.format = Format::R11G11B10_FLOAT;
}
else if (lightmap_size == (object.lightmapWidth / GetFormatBlockSize(Format::BC6H_UF16)) * (object.lightmapHeight / GetFormatBlockSize(Format::BC6H_UF16)) * GetFormatStride(Format::BC6H_UF16))
{
object.lightmap.desc.format = Format::BC6H_UF16;
}
else
{
assert(0); // unknown data format
}
wi::texturehelper::CreateTexture(object.lightmap, object.lightmapTextureData.data(), object.lightmapWidth, object.lightmapHeight, object.lightmap.desc.format);
device->SetName(&object.lightmap, "lightmap");
}
Expand Down
93 changes: 28 additions & 65 deletions WickedEngine/wiScene_Components.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1376,77 +1376,40 @@ namespace wi::scene
}
void ObjectComponent::CompressLightmap()
{

// BC6 Block compression code that uses DirectXTex library, but it's not cross platform, so disabled:
#if 0
wi::Timer timer;
wi::backlog::post("compressing lightmap...");

lightmap.desc.Format = lightmap_block_format;
lightmap.desc.BindFlags = BindFlag::SHADER_RESOURCE;

static constexpr wi::graphics::FORMAT lightmap_block_format = wi::graphics::FORMAT_BC6H_UF16;
static constexpr uint32_t lightmap_blocksize = wi::graphics::GetFormatBlockSize(lightmap_block_format);
static_assert(lightmap_blocksize == 4u);
const uint32_t bc6_width = lightmapWidth / lightmap_blocksize;
const uint32_t bc6_height = lightmapHeight / lightmap_blocksize;
wi::vector<uint8_t> bc6_data;
bc6_data.resize(sizeof(XMFLOAT4) * bc6_width * bc6_height);
const XMFLOAT4* raw_data = (const XMFLOAT4*)lightmapTextureData.data();

for (uint32_t x = 0; x < bc6_width; ++x)
if (IsLightmapDisableBlockCompression())
{
for (uint32_t y = 0; y < bc6_height; ++y)
// Simple packing to R11G11B10_FLOAT format on CPU:
using namespace PackedVector;
wi::vector<uint8_t> packed_data;
packed_data.resize(sizeof(XMFLOAT3PK) * lightmapWidth * lightmapHeight);
XMFLOAT3PK* packed_ptr = (XMFLOAT3PK*)packed_data.data();
XMFLOAT4* raw_ptr = (XMFLOAT4*)lightmapTextureData.data();

uint32_t texelcount = lightmapWidth * lightmapHeight;
for (uint32_t i = 0; i < texelcount; ++i)
{
uint32_t bc6_idx = x + y * bc6_width;
uint8_t* ptr = (uint8_t*)((XMFLOAT4*)bc6_data.data() + bc6_idx);

XMVECTOR raw_vec[lightmap_blocksize * lightmap_blocksize];
for (uint32_t i = 0; i < lightmap_blocksize; ++i)
{
for (uint32_t j = 0; j < lightmap_blocksize; ++j)
{
uint32_t raw_idx = (x * lightmap_blocksize + i) + (y * lightmap_blocksize + j) * lightmapWidth;
uint32_t block_idx = i + j * lightmap_blocksize;
raw_vec[block_idx] = XMLoadFloat4(raw_data + raw_idx);
}
}
static_assert(arraysize(raw_vec) == 16); // it will work only for a certain block size!
D3DXEncodeBC6HU(ptr, raw_vec, 0);
XMStoreFloat3PK(packed_ptr + i, XMLoadFloat4(raw_ptr + i));
}
}

lightmapTextureData = std::move(bc6_data); // replace old (raw) data with compressed data

wi::backlog::post(
"compressing lightmap [" +
std::to_string(lightmapWidth) +
"x" +
std::to_string(lightmapHeight) +
"] finished in " +
std::to_string(timer.elapsed_seconds()) +
" seconds"
);
#else

// Simple compression to R11G11B10_FLOAT format:
using namespace PackedVector;
wi::vector<uint8_t> packed_data;
packed_data.resize(sizeof(XMFLOAT3PK) * lightmapWidth * lightmapHeight);
XMFLOAT3PK* packed_ptr = (XMFLOAT3PK*)packed_data.data();
XMFLOAT4* raw_ptr = (XMFLOAT4*)lightmapTextureData.data();

uint32_t texelcount = lightmapWidth * lightmapHeight;
for (uint32_t i = 0; i < texelcount; ++i)
lightmapTextureData = std::move(packed_data);
lightmap.desc.format = Format::R11G11B10_FLOAT;
lightmap.desc.bind_flags = BindFlag::SHADER_RESOURCE;
}
else
{
XMStoreFloat3PK(packed_ptr + i, XMLoadFloat4(raw_ptr + i));
// BC6 compress on GPU:
wi::texturehelper::CreateTexture(lightmap, lightmapTextureData.data(), lightmapWidth, lightmapHeight, lightmap.desc.format);
TextureDesc desc = lightmap.desc;
desc.format = Format::BC6H_UF16;
desc.bind_flags = BindFlag::SHADER_RESOURCE;
Texture bc6tex;
GraphicsDevice* device = GetDevice();
device->CreateTexture(&desc, nullptr, &bc6tex);
CommandList cmd = device->BeginCommandList();
wi::renderer::BlockCompress(lightmap, bc6tex, cmd);
wi::helper::saveTextureToMemory(bc6tex, lightmapTextureData); // internally waits for GPU completion
lightmap.desc = desc;
}

lightmapTextureData = std::move(packed_data);
lightmap.desc.format = Format::R11G11B10_FLOAT;
lightmap.desc.bind_flags = BindFlag::SHADER_RESOURCE;

#endif
}

AnimationComponent::AnimationChannel::PathDataType AnimationComponent::AnimationChannel::GetPathDataType() const
Expand Down
7 changes: 5 additions & 2 deletions WickedEngine/wiScene_Components.h
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ namespace wi::scene
_DEPRECATED_IMPOSTOR_PLACEMENT = 1 << 3,
REQUEST_PLANAR_REFLECTION = 1 << 4,
LIGHTMAP_RENDER_REQUEST = 1 << 5,
LIGHTMAP_DISABLE_BLOCK_COMPRESSION = 1 << 6,
};
uint32_t _flags = RENDERABLE | CAST_SHADOW;

Expand Down Expand Up @@ -686,12 +687,14 @@ namespace wi::scene
inline void SetDynamic(bool value) { if (value) { _flags |= DYNAMIC; } else { _flags &= ~DYNAMIC; } }
inline void SetRequestPlanarReflection(bool value) { if (value) { _flags |= REQUEST_PLANAR_REFLECTION; } else { _flags &= ~REQUEST_PLANAR_REFLECTION; } }
inline void SetLightmapRenderRequest(bool value) { if (value) { _flags |= LIGHTMAP_RENDER_REQUEST; } else { _flags &= ~LIGHTMAP_RENDER_REQUEST; } }
inline void SetLightmapDisableBlockCompression(bool value) { if (value) { _flags |= LIGHTMAP_DISABLE_BLOCK_COMPRESSION; } else { _flags &= ~LIGHTMAP_DISABLE_BLOCK_COMPRESSION; } }

inline bool IsRenderable() const { return _flags & RENDERABLE; }
inline bool IsCastingShadow() const { return _flags & CAST_SHADOW; }
inline bool IsDynamic() const { return _flags & DYNAMIC; }
inline bool IsRequestPlanarReflection() const { return _flags & REQUEST_PLANAR_REFLECTION; }
inline bool IsLightmapRenderRequested() const { return _flags & LIGHTMAP_RENDER_REQUEST; }
inline bool IsLightmapDisableBlockCompression() const { return _flags & LIGHTMAP_DISABLE_BLOCK_COMPRESSION; }

inline float GetTransparency() const { return 1 - color.w; }
inline uint32_t GetFilterMask() const { return filterMask | filterMaskDynamic; }
Expand All @@ -705,8 +708,8 @@ namespace wi::scene
}

void ClearLightmap();
void SaveLightmap();
void CompressLightmap();
void SaveLightmap(); // not thread safe if LIGHTMAP_BLOCK_COMPRESSION is enabled!
void CompressLightmap(); // not thread safe if LIGHTMAP_BLOCK_COMPRESSION is enabled!

void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri);
};
Expand Down
12 changes: 0 additions & 12 deletions WickedEngine/wiScene_Serializers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,18 +568,6 @@ namespace wi::scene
archive >> lightmapWidth;
archive >> lightmapHeight;
archive >> lightmapTextureData;

if (!lightmapTextureData.empty())
{
const uint32_t expected_datasize = lightmapWidth * lightmapHeight * sizeof(PackedVector::XMFLOAT3PK);
if (expected_datasize != lightmapTextureData.size())
{
// This means it's from an old version, when lightmap data was stored in raw format, so compress it...
wi::jobsystem::Execute(seri.ctx, [this](wi::jobsystem::JobArgs args) {
CompressLightmap();
});
}
}
}
if (archive.GetVersion() >= 31)
{
Expand Down
2 changes: 1 addition & 1 deletion WickedEngine/wiVersion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 71;
// minor bug fixes, alterations, refactors, updates
const int revision = 218;
const int revision = 219;

const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);

Expand Down

0 comments on commit 169e394

Please sign in to comment.