-
Notifications
You must be signed in to change notification settings - Fork 6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Impeller] Fix hot reload for shaders on Impeller (#49739)
I broke this in #49543 While investigating flutter/flutter#141235 I realized that the specific things that were wrong there were probably artifacts of some intermediate issue in the previous patch - they no longer appear. However, I had broken hot reload. This patch fixes it and updates the `EntityTest.RuntimeEffect` to artificially run the rendering callback a few times simulating a hot reload. The test fails without my changes here.
- Loading branch information
Showing
7 changed files
with
200 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
// 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 <cstdint> | ||
|
||
#include "gtest/gtest.h" | ||
|
||
#include "impeller/core/allocator.h" | ||
#include "impeller/core/device_buffer_descriptor.h" | ||
#include "impeller/entity/contents/content_context.h" | ||
#include "impeller/geometry/color.h" | ||
#include "impeller/renderer/capabilities.h" | ||
#include "impeller/renderer/pipeline.h" | ||
#include "impeller/renderer/pipeline_descriptor.h" | ||
|
||
namespace impeller { | ||
namespace testing { | ||
|
||
class FakeAllocator : public Allocator { | ||
public: | ||
FakeAllocator() : Allocator() {} | ||
|
||
uint16_t MinimumBytesPerRow(PixelFormat format) const override { return 0; } | ||
ISize GetMaxTextureSizeSupported() const override { return ISize(); } | ||
|
||
std::shared_ptr<DeviceBuffer> OnCreateBuffer( | ||
const DeviceBufferDescriptor& desc) override { | ||
return nullptr; | ||
} | ||
std::shared_ptr<Texture> OnCreateTexture( | ||
const TextureDescriptor& desc) override { | ||
return nullptr; | ||
} | ||
}; | ||
|
||
class FakeContext : public Context { | ||
public: | ||
FakeContext() : Context(), allocator_(std::make_shared<FakeAllocator>()) {} | ||
|
||
BackendType GetBackendType() const override { return BackendType::kVulkan; } | ||
std::string DescribeGpuModel() const override { return ""; } | ||
bool IsValid() const override { return false; } | ||
const std::shared_ptr<const Capabilities>& GetCapabilities() const override { | ||
return capabilities_; | ||
} | ||
std::shared_ptr<Allocator> GetResourceAllocator() const override { | ||
return allocator_; | ||
} | ||
std::shared_ptr<ShaderLibrary> GetShaderLibrary() const { return nullptr; } | ||
std::shared_ptr<SamplerLibrary> GetSamplerLibrary() const { return nullptr; } | ||
std::shared_ptr<PipelineLibrary> GetPipelineLibrary() const { | ||
return nullptr; | ||
} | ||
std::shared_ptr<CommandBuffer> CreateCommandBuffer() const { return nullptr; } | ||
void Shutdown() {} | ||
|
||
private: | ||
std::shared_ptr<Allocator> allocator_; | ||
std::shared_ptr<const Capabilities> capabilities_; | ||
}; | ||
|
||
class FakePipeline : public Pipeline<PipelineDescriptor> { | ||
public: | ||
FakePipeline() : Pipeline({}, PipelineDescriptor{}) {} | ||
|
||
bool IsValid() const override { return false; } | ||
}; | ||
|
||
static std::shared_ptr<FakePipeline> CreateFakePipelineCallback() { | ||
return std::make_shared<FakePipeline>(); | ||
} | ||
|
||
TEST(ContentContext, CachesPipelines) { | ||
auto context = std::make_shared<FakeContext>(); | ||
ContentContext content_context(context, nullptr); | ||
ContentContextOptions optionsA{.blend_mode = BlendMode::kSourceOver}; | ||
ContentContextOptions optionsB{.blend_mode = BlendMode::kSource}; | ||
|
||
auto pipelineA = content_context.GetCachedRuntimeEffectPipeline( | ||
"A", optionsA, CreateFakePipelineCallback); | ||
|
||
auto pipelineA2 = content_context.GetCachedRuntimeEffectPipeline( | ||
"A", optionsA, CreateFakePipelineCallback); | ||
|
||
auto pipelineA3 = content_context.GetCachedRuntimeEffectPipeline( | ||
"A", optionsB, CreateFakePipelineCallback); | ||
|
||
auto pipelineB = content_context.GetCachedRuntimeEffectPipeline( | ||
"B", optionsB, CreateFakePipelineCallback); | ||
|
||
ASSERT_EQ(pipelineA.get(), pipelineA2.get()); | ||
ASSERT_NE(pipelineA.get(), pipelineA3.get()); | ||
ASSERT_NE(pipelineB.get(), pipelineA.get()); | ||
} | ||
|
||
TEST(ContentContext, InvalidatesAllPipelinesWithSameUniqueNameOnClear) { | ||
auto context = std::make_shared<FakeContext>(); | ||
ContentContext content_context(context, nullptr); | ||
ContentContextOptions optionsA{.blend_mode = BlendMode::kSourceOver}; | ||
ContentContextOptions optionsB{.blend_mode = BlendMode::kSource}; | ||
|
||
auto pipelineA = content_context.GetCachedRuntimeEffectPipeline( | ||
"A", optionsA, CreateFakePipelineCallback); | ||
|
||
auto pipelineA2 = content_context.GetCachedRuntimeEffectPipeline( | ||
"A", optionsB, CreateFakePipelineCallback); | ||
|
||
auto pipelineB = content_context.GetCachedRuntimeEffectPipeline( | ||
"B", optionsB, CreateFakePipelineCallback); | ||
|
||
ASSERT_TRUE(pipelineA); | ||
ASSERT_TRUE(pipelineA2); | ||
ASSERT_TRUE(pipelineB); | ||
|
||
ASSERT_EQ(pipelineA, content_context.GetCachedRuntimeEffectPipeline( | ||
"A", optionsA, CreateFakePipelineCallback)); | ||
ASSERT_EQ(pipelineA2, content_context.GetCachedRuntimeEffectPipeline( | ||
"A", optionsB, CreateFakePipelineCallback)); | ||
ASSERT_EQ(pipelineB, content_context.GetCachedRuntimeEffectPipeline( | ||
"B", optionsB, CreateFakePipelineCallback)); | ||
|
||
content_context.ClearCachedRuntimeEffectPipeline("A"); | ||
|
||
ASSERT_NE(pipelineA, content_context.GetCachedRuntimeEffectPipeline( | ||
"A", optionsA, CreateFakePipelineCallback)); | ||
ASSERT_NE(pipelineA2, content_context.GetCachedRuntimeEffectPipeline( | ||
"A", optionsB, CreateFakePipelineCallback)); | ||
ASSERT_EQ(pipelineB, content_context.GetCachedRuntimeEffectPipeline( | ||
"B", optionsB, CreateFakePipelineCallback)); | ||
|
||
content_context.ClearCachedRuntimeEffectPipeline("B"); | ||
|
||
ASSERT_NE(pipelineB, content_context.GetCachedRuntimeEffectPipeline( | ||
"B", optionsB, CreateFakePipelineCallback)); | ||
} | ||
|
||
} // namespace testing | ||
} // namespace impeller |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters