diff --git a/readme.md b/readme.md index 567b0dcd3..14efe8524 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ -

Spartan Engine is one of the most advanced one-man game engines out there, pushing the limits of real-time solutions and innovation. What started as a portfolio project has evolved into a cutting-edge platform for developers to explore, learn, and contribute. This isn't an engine for the average user, it's designed for advanced research and experimentation, ideal for industry veterans looking to push boundaries, not to build a game (yet). With a thriving Discord community of over 430 members, including industry veterans, and contribution perks that you won't believe when you see, it's one of the most unique projects you'll ever come across.

+

Spartan Engine is one of the most advanced one-man game engines out there, pushing the limits of real-time solutions. What started as a portfolio project has evolved into a cutting-edge platform for developers to explore, learn, and contribute. This isn't an engine for the average user, it's designed for advanced research and experimentation, ideal for industry veterans looking to experiment, not to build a game (yet). With a thriving Discord community of over 440 members, including industry veterans, and contribution perks that you won't believe when you see, it's one of the most unique projects you'll ever come across.

- For occasional updates regarding the project's development, you can follow me on X. diff --git a/runtime/RHI/RHI_Texture.cpp b/runtime/RHI/RHI_Texture.cpp index 40d5778de..f3a5f7ca5 100644 --- a/runtime/RHI/RHI_Texture.cpp +++ b/runtime/RHI/RHI_Texture.cpp @@ -218,11 +218,7 @@ namespace Spartan m_channel_count = rhi_to_format_channel_count(format); m_bits_per_channel = rhi_format_to_bits_per_channel(m_format); - if (!(flags & RHI_Texture_DontPrepareForGpu)) - { - RHI_Texture::RHI_CreateResource(); - m_resource_state = ResourceState::PreparedForGpu; - } + PrepareForGpu(); if (!compressonator::registered) { @@ -292,7 +288,7 @@ namespace Spartan } } - ClearBytes(); + ClearData(); } // write properties @@ -320,7 +316,7 @@ namespace Spartan m_flags |= RHI_Texture_Srv; m_object_name = FileSystem::GetFileNameFromFilePath(file_path); - ClearBytes(); + ClearData(); // load from drive if (FileSystem::IsEngineTextureFile(file_path)) @@ -507,7 +503,7 @@ namespace Spartan } } - void RHI_Texture::ClearBytes() + void RHI_Texture::ClearData() { m_slices.clear(); m_slices.shrink_to_fit(); @@ -518,11 +514,15 @@ namespace Spartan SP_ASSERT_MSG(m_resource_state == ResourceState::Max, "Only unprepared textures can be prepared"); m_resource_state = ResourceState::PreparingForGpu; - SP_ASSERT(m_slices.size() > 0); - SP_ASSERT(m_slices[0].mips.size() > 0); + bool generate_mips_and_compress = !IsCompressedFormat() && // the bistro world loads pre-compressed textures + IsMaterialTexture() && // render targets or textures which are written to in compute passes, don't need mip and compression + !(m_flags & RHI_Texture_DontPrepareForGpu); // some textures delay preperation because the material packs their data in a custom way before preparing them - if (!IsCompressedFormat()) // the bistro world loads compressed textures with mips + if (generate_mips_and_compress) { + SP_ASSERT(m_slices.size() > 0); + SP_ASSERT(m_slices[0].mips.size() > 0); + // 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++) @@ -530,10 +530,10 @@ namespace Spartan 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 + m_slices[0].mips[mip_index - 1].bytes, // larger + m_slices[0].mips[mip_index].bytes, // smaller + max(1u, m_width >> (mip_index - 1)), // larger width + max(1u, m_height >> (mip_index - 1)) // larger height ); } @@ -576,16 +576,26 @@ namespace Spartan } // upload to gpu - SP_ASSERT_MSG(RHI_CreateResource(), "Failed to create GPU resource");; + if (!(m_flags & RHI_Texture_DontPrepareForGpu)) + { + SP_ASSERT(RHI_CreateResource()); + } // clear data if (!(m_flags & RHI_Texture_KeepData)) { - ClearBytes(); + ClearData(); } ComputeMemoryUsage(); - m_resource_state = ResourceState::PreparedForGpu; + if (m_rhi_resource) + { + m_resource_state = ResourceState::PreparedForGpu; + } + else + { + m_resource_state = ResourceState::Max; + } } void RHI_Texture::SaveAsImage(const string& file_path) diff --git a/runtime/RHI/RHI_Texture.h b/runtime/RHI/RHI_Texture.h index 4fd42094d..52fb15615 100644 --- a/runtime/RHI/RHI_Texture.h +++ b/runtime/RHI/RHI_Texture.h @@ -115,7 +115,7 @@ namespace Spartan void SetExternalMemoryHandle(void* handle) { m_rhi_external_memory = handle; } // misc - void ClearBytes(); + void ClearData(); void PrepareForGpu(); void SaveAsImage(const std::string& file_path); 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); @@ -146,6 +146,15 @@ namespace Spartan bool IsDepthStencilFormat() const { return IsDepthFormat() || IsStencilFormat(); } bool IsColorFormat() const { return !IsDepthStencilFormat(); } + // usage + bool IsMaterialTexture() const + { + return m_format == RHI_Format::R8G8B8A8_Unorm && + m_channel_count == 4 && + m_bits_per_channel == 8 && + !(IsRtv() || IsDsv()); + } + // layout void SetLayout(const RHI_Image_Layout layout, RHI_CommandList* cmd_list, uint32_t mip_index = rhi_all_mips, uint32_t mip_range = 0); RHI_Image_Layout GetLayout(const uint32_t mip) const { return m_layout[mip]; } @@ -182,8 +191,8 @@ namespace Spartan // api resources void* m_rhi_srv = nullptr; // an srv with all mips std::array m_rhi_srv_mips = { nullptr }; // an srv for each mip - std::array m_rhi_rtv = { nullptr }; - std::array m_rhi_dsv = { nullptr }; + std::array m_rhi_rtv = { nullptr }; + std::array m_rhi_dsv = { nullptr }; void* m_rhi_resource = nullptr; void* m_rhi_external_memory = nullptr; void* m_mapped_data = nullptr; diff --git a/runtime/RHI/Vulkan/Vulkan_Texture.cpp b/runtime/RHI/Vulkan/Vulkan_Texture.cpp index e0cf386bc..13cbec6f1 100644 --- a/runtime/RHI/Vulkan/Vulkan_Texture.cpp +++ b/runtime/RHI/Vulkan/Vulkan_Texture.cpp @@ -311,10 +311,6 @@ namespace Spartan if (HasData()) { stage(this); - if ((m_flags & RHI_Texture_KeepData) == 0) - { - ClearBytes(); - } } // transition to target layout diff --git a/runtime/Rendering/Material.cpp b/runtime/Rendering/Material.cpp index 6e535820b..6a8930576 100644 --- a/runtime/Rendering/Material.cpp +++ b/runtime/Rendering/Material.cpp @@ -323,7 +323,7 @@ namespace Spartan void Material::PrepareForGpu() { - SP_ASSERT_MSG(m_resource_state == ResourceState::Max, "Only unprepared materiasl can be prepared"); + SP_ASSERT_MSG(m_resource_state == ResourceState::Max, "Only unprepared materials can be prepared"); m_resource_state = ResourceState::PreparingForGpu; RHI_Texture* texture_color = GetTexture(MaterialTextureType::Color); @@ -439,6 +439,7 @@ namespace Spartan { if (texture && texture->GetResourceState() == ResourceState::Max) { + texture->SetFlag(RHI_Texture_DontPrepareForGpu, false); texture->PrepareForGpu(); } } diff --git a/runtime/Rendering/Renderer_Resources.cpp b/runtime/Rendering/Renderer_Resources.cpp index 7ba76a1e7..54ad438e8 100644 --- a/runtime/Rendering/Renderer_Resources.cpp +++ b/runtime/Rendering/Renderer_Resources.cpp @@ -196,8 +196,6 @@ namespace Spartan mip_count++; } - // notes: - // - gbuffer_normal: any format with or below 8 bits per channel, will produce banding #define render_target(x) render_targets[static_cast(x)] // typical flags @@ -557,7 +555,7 @@ namespace Spartan const string dir_texture = ResourceCache::GetResourceDirectory(ResourceDirectory::Textures) + "\\"; #define standard_texture(x) standard_textures[static_cast(x)] - // noise + // blue noise textures with 2 channels, each channel containing a different pattern { standard_texture(Renderer_StandardTexture::Noise_blue_0) = make_shared(dir_texture + "noise_blue_0.png"); standard_texture(Renderer_StandardTexture::Noise_blue_1) = make_shared(dir_texture + "noise_blue_1.png"); @@ -569,11 +567,6 @@ namespace Spartan standard_texture(Renderer_StandardTexture::Noise_blue_7) = make_shared(dir_texture + "noise_blue_7.png"); } - // color - { - standard_texture(Renderer_StandardTexture::Checkerboard) = make_shared(dir_texture + "no_texture.png"); - } - // gizmos { standard_texture(Renderer_StandardTexture::Gizmo_light_directional) = make_shared(dir_texture + "sun.png"); @@ -584,6 +577,7 @@ namespace Spartan // misc { + standard_texture(Renderer_StandardTexture::Checkerboard) = make_shared(dir_texture + "no_texture.png"); standard_texture(Renderer_StandardTexture::Foam) = make_shared(dir_texture + "foam.jpg"); } } diff --git a/runtime/Resource/Import/ModelImporter.cpp b/runtime/Resource/Import/ModelImporter.cpp index 58f7f8be5..ad976d5e4 100644 --- a/runtime/Resource/Import/ModelImporter.cpp +++ b/runtime/Resource/Import/ModelImporter.cpp @@ -445,8 +445,8 @@ namespace Spartan // import flags uint32_t import_flags = 0; { - import_flags |= aiProcess_ValidateDataStructure; // validates the imported scene data structure. - import_flags |= aiProcess_Triangulate; // triangulates all faces of all meshes. + import_flags |= aiProcess_ValidateDataStructure; // validates the imported scene data structure + import_flags |= aiProcess_Triangulate; // triangulates all faces of all meshes import_flags |= aiProcess_SortByPType; // splits meshes with more than one primitive type in homogeneous sub-meshes // switch to engine conventions