#pragma once #include "prism_engineering/asset_pipeline.hpp" #include #include #include namespace prism_engineering { struct AllocationCounts { std::size_t calls{}, requested_bytes{}, live_bytes{}, peak_live_bytes{}; }; // Single-threaded instrumentation. Equality is identity, not upstream equality: // allocating through one counter and deallocating through another loses accounting. class CountingResource final : public std::pmr::memory_resource { public: explicit CountingResource(std::pmr::memory_resource& upstream) noexcept : upstream_{upstream} {} CountingResource(const CountingResource&)=delete; CountingResource& operator=(const CountingResource&)=delete; [[nodiscard]] AllocationCounts counts() const noexcept { return counts_; } private: void* do_allocate(std::size_t bytes, std::size_t alignment) override; void do_deallocate(void* pointer, std::size_t bytes, std::size_t alignment) override; bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this==&other; } std::pmr::memory_resource& upstream_; AllocationCounts counts_; }; enum class ResourceChoice { ordinary, monotonic, pool }; struct RenderMeasurement { PreparedImage image; // Ordinary owning allocation, outside scratch accounting. AllocationCounts requests; AllocationCounts upstream_before_release; AllocationCounts upstream_after_release; std::int64_t elapsed_nanoseconds{}; }; // Same 64x64, four-samples-per-pixel integer scene under each resource policy. // All temporary tile objects die before returning; result pixels own their bytes. [[nodiscard]] PreparedImage render_tiles(std::pmr::memory_resource& scratch); [[nodiscard]] PreparedImage render_plain(); [[nodiscard]] RenderMeasurement measure_render(ResourceChoice choice); [[nodiscard]] std::uint64_t image_checksum(const PreparedImage& image) noexcept; } // namespace prism_engineering