| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <memory> |
| |
| #include "flutter/testing/testing.h" |
| #include "impeller/base/validation.h" |
| #include "impeller/core/allocator.h" |
| #include "impeller/core/texture_descriptor.h" |
| #include "impeller/entity/entity_playground.h" |
| #include "impeller/entity/render_target_cache.h" |
| #include "impeller/playground/playground_test.h" |
| #include "impeller/renderer/testing/mocks.h" |
| |
| namespace impeller { |
| namespace testing { |
| |
| using RenderTargetCacheTest = EntityPlayground; |
| INSTANTIATE_PLAYGROUND_SUITE(RenderTargetCacheTest); |
| |
| class TestAllocator : public Allocator { |
| public: |
| TestAllocator() = default; |
| |
| ~TestAllocator() = default; |
| |
| ISize GetMaxTextureSizeSupported() const override { |
| return ISize(1024, 1024); |
| }; |
| |
| std::shared_ptr<DeviceBuffer> OnCreateBuffer( |
| const DeviceBufferDescriptor& desc) override { |
| if (should_fail) { |
| return nullptr; |
| } |
| return std::make_shared<MockDeviceBuffer>(desc); |
| }; |
| |
| virtual std::shared_ptr<Texture> OnCreateTexture( |
| const TextureDescriptor& desc) override { |
| if (should_fail) { |
| return nullptr; |
| } |
| return std::make_shared<MockTexture>(desc); |
| }; |
| |
| bool should_fail = false; |
| }; |
| |
| TEST_P(RenderTargetCacheTest, CachesUsedTexturesAcrossFrames) { |
| auto render_target_cache = |
| RenderTargetCache(GetContext()->GetResourceAllocator()); |
| |
| render_target_cache.Start(); |
| // Create two render targets of the same exact size/shape. Both should be |
| // marked as used this frame, so the cached data set will contain two. |
| render_target_cache.CreateOffscreen(*GetContext(), {100, 100}, 1); |
| render_target_cache.CreateOffscreen(*GetContext(), {100, 100}, 1); |
| |
| EXPECT_EQ(render_target_cache.CachedTextureCount(), 2u); |
| |
| render_target_cache.End(); |
| render_target_cache.Start(); |
| |
| // Next frame, only create one texture. The set will still contain two, |
| // but one will be removed at the end of the frame. |
| render_target_cache.CreateOffscreen(*GetContext(), {100, 100}, 1); |
| EXPECT_EQ(render_target_cache.CachedTextureCount(), 2u); |
| |
| render_target_cache.End(); |
| EXPECT_EQ(render_target_cache.CachedTextureCount(), 1u); |
| } |
| |
| TEST_P(RenderTargetCacheTest, DoesNotPersistFailedAllocations) { |
| ScopedValidationDisable disable; |
| auto allocator = std::make_shared<TestAllocator>(); |
| auto render_target_cache = RenderTargetCache(allocator); |
| |
| render_target_cache.Start(); |
| allocator->should_fail = true; |
| |
| auto render_target = |
| render_target_cache.CreateOffscreen(*GetContext(), {100, 100}, 1); |
| |
| EXPECT_FALSE(render_target.IsValid()); |
| EXPECT_EQ(render_target_cache.CachedTextureCount(), 0u); |
| } |
| |
| TEST_P(RenderTargetCacheTest, CachedTextureGetsNewAttachmentConfig) { |
| auto render_target_cache = |
| RenderTargetCache(GetContext()->GetResourceAllocator()); |
| |
| render_target_cache.Start(); |
| RenderTarget::AttachmentConfig color_attachment_config = |
| RenderTarget::kDefaultColorAttachmentConfig; |
| RenderTarget target1 = render_target_cache.CreateOffscreen( |
| *GetContext(), {100, 100}, 1, "Offscreen1", color_attachment_config); |
| render_target_cache.End(); |
| |
| render_target_cache.Start(); |
| color_attachment_config.clear_color = Color::Red(); |
| RenderTarget target2 = render_target_cache.CreateOffscreen( |
| *GetContext(), {100, 100}, 1, "Offscreen2", color_attachment_config); |
| render_target_cache.End(); |
| |
| auto color1 = target1.GetColorAttachments().find(0)->second; |
| auto color2 = target2.GetColorAttachments().find(0)->second; |
| // The second color attachment should reuse the first attachment's texture |
| // but with attributes from the second AttachmentConfig. |
| EXPECT_EQ(color2.texture, color1.texture); |
| EXPECT_EQ(color2.clear_color, Color::Red()); |
| } |
| |
| TEST_P(RenderTargetCacheTest, CreateWithEmptySize) { |
| auto render_target_cache = |
| RenderTargetCache(GetContext()->GetResourceAllocator()); |
| |
| render_target_cache.Start(); |
| RenderTarget empty_target = |
| render_target_cache.CreateOffscreen(*GetContext(), {100, 0}, 1); |
| RenderTarget empty_target_msaa = |
| render_target_cache.CreateOffscreenMSAA(*GetContext(), {0, 0}, 1); |
| render_target_cache.End(); |
| |
| { |
| ScopedValidationDisable disable_validation; |
| EXPECT_FALSE(empty_target.IsValid()); |
| EXPECT_FALSE(empty_target_msaa.IsValid()); |
| } |
| } |
| |
| } // namespace testing |
| } // namespace impeller |