From 2deaeaf73331f52a5122eb740e133b4a9d114830 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Fri, 14 Apr 2023 13:54:40 -0700 Subject: [PATCH] [Impeller] Add debug ToString methods to render targets. Also fixes and issue where SPrintF would only consider strings 64 bytes or smaller. --- impeller/base/base_unittests.cc | 8 ++++ impeller/base/strings.cc | 15 +++++-- impeller/core/formats.cc | 40 +++++++++++++++++ impeller/core/formats.h | 68 +++++++++++++++++++++++++++++ impeller/core/texture_descriptor.cc | 14 +++++- impeller/core/texture_descriptor.h | 13 ++++++ impeller/geometry/BUILD.gn | 5 ++- impeller/geometry/color.cc | 10 +++++ impeller/geometry/color.h | 2 + impeller/renderer/render_target.cc | 32 +++++++++++++- impeller/renderer/render_target.h | 2 + 11 files changed, 202 insertions(+), 7 deletions(-) diff --git a/impeller/base/base_unittests.cc b/impeller/base/base_unittests.cc index 181401fca52ec..5edfdff6ccf1b 100644 --- a/impeller/base/base_unittests.cc +++ b/impeller/base/base_unittests.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flutter/testing/testing.h" +#include "impeller/base/strings.h" #include "impeller/base/thread.h" namespace impeller { @@ -68,5 +69,12 @@ TEST(ThreadTest, CanCreateRWMutexLock) { // f.mtx.UnlockReader(); <--- Static analysis error. } +TEST(StringsTest, CanSPrintF) { + ASSERT_EQ(SPrintF("%sx%d", "Hello", 12), "Hellox12"); + ASSERT_EQ(SPrintF(""), ""); + ASSERT_EQ(SPrintF("Hello"), "Hello"); + ASSERT_EQ(SPrintF("%sx%.2f", "Hello", 12.122222), "Hellox12.12"); +} + } // namespace testing } // namespace impeller diff --git a/impeller/base/strings.cc b/impeller/base/strings.cc index 7b6349157e3ce..9623a11827966 100644 --- a/impeller/base/strings.cc +++ b/impeller/base/strings.cc @@ -10,12 +10,21 @@ namespace impeller { IMPELLER_PRINTF_FORMAT(1, 2) std::string SPrintF(const char* format, ...) { + std::string ret_val; va_list list; + va_list list2; va_start(list, format); - char buffer[64] = {0}; - ::vsnprintf(buffer, sizeof(buffer), format, list); + va_copy(list2, list); + if (auto string_length = ::vsnprintf(nullptr, 0, format, list); + string_length >= 0) { + auto buffer = reinterpret_cast(::malloc(string_length + 1)); + ::vsnprintf(buffer, string_length + 1, format, list2); + ret_val = std::string{buffer, static_cast(string_length)}; + ::free(buffer); + } + va_end(list2); va_end(list); - return buffer; + return ret_val; } bool HasPrefix(const std::string& string, const std::string& prefix) { diff --git a/impeller/core/formats.cc b/impeller/core/formats.cc index 3bcfc98ac2cb0..61cb783b656f6 100644 --- a/impeller/core/formats.cc +++ b/impeller/core/formats.cc @@ -101,4 +101,44 @@ std::string TextureUsageMaskToString(TextureUsageMask mask) { return stream.str(); } +std::string AttachmentToString(const Attachment& attachment) { + std::stringstream stream; + if (attachment.texture) { + stream << "Texture=(" + << TextureDescriptorToString( + attachment.texture->GetTextureDescriptor()) + << "),"; + } + if (attachment.resolve_texture) { + stream << "ResolveTexture=(" + << TextureDescriptorToString( + attachment.resolve_texture->GetTextureDescriptor()) + << "),"; + } + stream << "LoadAction=" << LoadActionToString(attachment.load_action) << ","; + stream << "StoreAction=" << StoreActionToString(attachment.store_action); + return stream.str(); +} + +std::string ColorAttachmentToString(const ColorAttachment& color) { + std::stringstream stream; + stream << AttachmentToString(color) << ","; + stream << "ClearColor=(" << ColorToString(color.clear_color) << ")"; + return stream.str(); +} + +std::string DepthAttachmentToString(const DepthAttachment& depth) { + std::stringstream stream; + stream << AttachmentToString(depth) << ","; + stream << "ClearDepth=" << SPrintF("%.2f", depth.clear_depth); + return stream.str(); +} + +std::string StencilAttachmentToString(const StencilAttachment& stencil) { + std::stringstream stream; + stream << AttachmentToString(stencil) << ","; + stream << "ClearStencil=" << stencil.clear_stencil; + return stream.str(); +} + } // namespace impeller diff --git a/impeller/core/formats.h b/impeller/core/formats.h index eb58dda9d9719..7fc4a6f221eb6 100644 --- a/impeller/core/formats.h +++ b/impeller/core/formats.h @@ -110,6 +110,42 @@ enum class PixelFormat { kD32FloatS8UInt, }; +constexpr const char* PixelFormatToString(PixelFormat format) { + switch (format) { + case PixelFormat::kUnknown: + return "Unknown"; + case PixelFormat::kA8UNormInt: + return "A8UNormInt"; + case PixelFormat::kR8UNormInt: + return "R8UNormInt"; + case PixelFormat::kR8G8UNormInt: + return "R8G8UNormInt"; + case PixelFormat::kR8G8B8A8UNormInt: + return "R8G8B8A8UNormInt"; + case PixelFormat::kR8G8B8A8UNormIntSRGB: + return "R8G8B8A8UNormIntSRGB"; + case PixelFormat::kB8G8R8A8UNormInt: + return "B8G8R8A8UNormInt"; + case PixelFormat::kB8G8R8A8UNormIntSRGB: + return "B8G8R8A8UNormIntSRGB"; + case PixelFormat::kR32G32B32A32Float: + return "R32G32B32A32Float"; + case PixelFormat::kR16G16B16A16Float: + return "R16G16B16A16Float"; + case PixelFormat::kB10G10R10XR: + return "B10G10R10XR"; + case PixelFormat::kB10G10R10XRSRGB: + return "B10G10R10XRSRGB"; + case PixelFormat::kB10G10R10A10XR: + return "B10G10R10A10XR"; + case PixelFormat::kS8UInt: + return "S8UInt"; + case PixelFormat::kD32FloatS8UInt: + return "D32FloatS8UInt"; + } + FML_UNREACHABLE(); +} + enum class BlendFactor { kZero, kOne, @@ -147,6 +183,30 @@ enum class StoreAction { kStoreAndMultisampleResolve, }; +constexpr const char* LoadActionToString(LoadAction action) { + switch (action) { + case LoadAction::kDontCare: + return "DontCare"; + case LoadAction::kLoad: + return "Load"; + case LoadAction::kClear: + return "Clear"; + } +} + +constexpr const char* StoreActionToString(StoreAction action) { + switch (action) { + case StoreAction::kDontCare: + return "DontCare"; + case StoreAction::kStore: + return "Store"; + case StoreAction::kMultisampleResolve: + return "MultisampleResolve"; + case StoreAction::kStoreAndMultisampleResolve: + return "StoreAndMultisampleResolve"; + } +} + constexpr bool CanClearAttachment(LoadAction action) { switch (action) { case LoadAction::kLoad: @@ -530,6 +590,14 @@ struct StencilAttachment : public Attachment { uint32_t clear_stencil = 0; }; +std::string AttachmentToString(const Attachment& attachment); + +std::string ColorAttachmentToString(const ColorAttachment& color); + +std::string DepthAttachmentToString(const DepthAttachment& depth); + +std::string StencilAttachmentToString(const StencilAttachment& stencil); + } // namespace impeller namespace std { diff --git a/impeller/core/texture_descriptor.cc b/impeller/core/texture_descriptor.cc index 05f4e75d449ef..e55c7ada7068e 100644 --- a/impeller/core/texture_descriptor.cc +++ b/impeller/core/texture_descriptor.cc @@ -4,8 +4,20 @@ #include "impeller/core/texture_descriptor.h" +#include + namespace impeller { -// +std::string TextureDescriptorToString(const TextureDescriptor& desc) { + std::stringstream stream; + stream << "StorageMode=" << StorageModeToString(desc.storage_mode) << ","; + stream << "Type=" << TextureTypeToString(desc.type) << ","; + stream << "Format=" << PixelFormatToString(desc.format) << ","; + stream << "Size=" << desc.size << ","; + stream << "MipCount=" << desc.mip_count << ","; + stream << "SampleCount=" << static_cast(desc.sample_count) << ","; + stream << "Compression=" << CompressionTypeToString(desc.compression_type); + return stream.str(); +} } // namespace impeller diff --git a/impeller/core/texture_descriptor.h b/impeller/core/texture_descriptor.h index e55aea2e4e858..7d99d20408da5 100644 --- a/impeller/core/texture_descriptor.h +++ b/impeller/core/texture_descriptor.h @@ -21,6 +21,17 @@ enum class CompressionType { kLossless, kLossy, }; + +constexpr const char* CompressionTypeToString(CompressionType type) { + switch (type) { + case CompressionType::kLossless: + return "Lossless"; + case CompressionType::kLossy: + return "Lossy"; + } + FML_UNREACHABLE(); +} + //------------------------------------------------------------------------------ /// @brief A lightweight object that describes the attributes of a texture /// that can then used an allocator to create that texture. @@ -63,4 +74,6 @@ struct TextureDescriptor { } }; +std::string TextureDescriptorToString(const TextureDescriptor& desc); + } // namespace impeller diff --git a/impeller/geometry/BUILD.gn b/impeller/geometry/BUILD.gn index 53d344d93f501..2afb29631c8e1 100644 --- a/impeller/geometry/BUILD.gn +++ b/impeller/geometry/BUILD.gn @@ -42,7 +42,10 @@ impeller_component("geometry") { "vector.h", ] - deps = [ "//flutter/fml" ] + deps = [ + "../base", + "//flutter/fml", + ] } impeller_component("geometry_asserts") { diff --git a/impeller/geometry/color.cc b/impeller/geometry/color.cc index 61f6a3bf0570b..17dd4f34ae138 100644 --- a/impeller/geometry/color.cc +++ b/impeller/geometry/color.cc @@ -8,6 +8,7 @@ #include #include +#include "impeller/base/strings.h" #include "impeller/geometry/constants.h" #include "impeller/geometry/scalar.h" #include "impeller/geometry/vector.h" @@ -360,4 +361,13 @@ Color Color::BlendColor(const Color& src, } } +std::string ColorToString(const Color& color) { + return SPrintF("R=%.1f,G=%.1f,B=%.1f,A=%.1f", // + color.red, // + color.green, // + color.blue, // + color.alpha // + ); +} + } // namespace impeller diff --git a/impeller/geometry/color.h b/impeller/geometry/color.h index c1e0da44ea4a3..99d491e8f4305 100644 --- a/impeller/geometry/color.h +++ b/impeller/geometry/color.h @@ -797,6 +797,8 @@ struct Color { constexpr bool IsOpaque() const { return alpha == 1.0f; } }; +std::string ColorToString(const Color& color); + /** * Represents a color by its constituent hue, saturation, brightness and alpha */ diff --git a/impeller/renderer/render_target.cc b/impeller/renderer/render_target.cc index 426bc0ad8a12a..fe29d31df6e1b 100644 --- a/impeller/renderer/render_target.cc +++ b/impeller/renderer/render_target.cc @@ -4,6 +4,8 @@ #include "impeller/renderer/render_target.h" +#include + #include "impeller/base/strings.h" #include "impeller/base/validation.h" #include "impeller/core/allocator.h" @@ -59,12 +61,20 @@ bool RenderTarget::IsValid() const { if (texture_type != attachment.texture->GetTextureDescriptor().type) { passes_type_validation = false; + VALIDATION_LOG << "Render target has incompatible texture types: " + << TextureTypeToString(texture_type.value()) << " != " + << TextureTypeToString( + attachment.texture->GetTextureDescriptor().type) + << " on target " << ToString(); return false; } if (sample_count != attachment.texture->GetTextureDescriptor().sample_count) { passes_type_validation = false; + VALIDATION_LOG << "Render target (" << ToString() + << ") has incompatible sample counts."; + return false; } @@ -72,8 +82,6 @@ bool RenderTarget::IsValid() const { }; IterateAllAttachments(iterator); if (!passes_type_validation) { - VALIDATION_LOG << "Render target texture types are not of the same type " - "and sample count."; return false; } } @@ -370,4 +378,24 @@ size_t RenderTarget::GetTotalAttachmentCount() const { return count; } +std::string RenderTarget::ToString() const { + std::stringstream stream; + + for (const auto& [index, color] : colors_) { + stream << SPrintF("Color[%zu]=(%s)", index, + ColorAttachmentToString(color).c_str()); + } + if (depth_) { + stream << ","; + stream << SPrintF("Depth=(%s)", + DepthAttachmentToString(depth_.value()).c_str()); + } + if (stencil_) { + stream << ","; + stream << SPrintF("Stencil=(%s)", + StencilAttachmentToString(stencil_.value()).c_str()); + } + return stream.str(); +} + } // namespace impeller diff --git a/impeller/renderer/render_target.h b/impeller/renderer/render_target.h index 14562c6cc71b6..9e1da3272104a 100644 --- a/impeller/renderer/render_target.h +++ b/impeller/renderer/render_target.h @@ -109,6 +109,8 @@ class RenderTarget final { void IterateAllAttachments( const std::function& iterator) const; + std::string ToString() const; + private: std::map colors_; std::optional depth_;