diff --git a/Editor/ObjectWindow.cpp b/Editor/ObjectWindow.cpp index 312992c82..814bf7183 100644 --- a/Editor/ObjectWindow.cpp +++ b/Editor/ObjectWindow.cpp @@ -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) { @@ -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)); @@ -666,6 +684,8 @@ void ObjectWindow::SetEntity(Entity entity) break; } + lightmapBlockCompressionCheckBox.SetCheck(!object->IsLightmapDisableBlockCompression()); + } else { @@ -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); diff --git a/Editor/ObjectWindow.h b/Editor/ObjectWindow.h index bb8f9b520..cffc673e2 100644 --- a/Editor/ObjectWindow.h +++ b/Editor/ObjectWindow.h @@ -24,6 +24,7 @@ public: wi::gui::ColorPicker colorPicker; wi::gui::Slider lightmapResolutionSlider; + wi::gui::CheckBox lightmapBlockCompressionCheckBox; wi::gui::ComboBox lightmapSourceUVSetComboBox; wi::gui::Button generateLightmapButton; wi::gui::Button stopLightmapGenButton; diff --git a/WickedEngine/shaders/blockcompressCS_BC6H.hlsl b/WickedEngine/shaders/blockcompressCS_BC6H.hlsl index 29505b94c..a26154c00 100644 --- a/WickedEngine/shaders/blockcompressCS_BC6H.hlsl +++ b/WickedEngine/shaders/blockcompressCS_BC6H.hlsl @@ -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 diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 03412228a..bd2e90194 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -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; @@ -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); } diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 7b8c1324c..05cf6c500 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -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"); } diff --git a/WickedEngine/wiScene_Components.cpp b/WickedEngine/wiScene_Components.cpp index 8d5727893..be7e82737 100644 --- a/WickedEngine/wiScene_Components.cpp +++ b/WickedEngine/wiScene_Components.cpp @@ -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 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 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(packed_data); + lightmap.desc.format = Format::R11G11B10_FLOAT; + lightmap.desc.bind_flags = BindFlag::SHADER_RESOURCE; } - - 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 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) + 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 diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index 5618dace0..596c88b12 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -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; @@ -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; } @@ -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); }; diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index 1272aa91d..863ef143e 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -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) { diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 0512d404b..3eb6bd058 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -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);