mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add pass bindings cache. Frame insights are empty.
This commit is contained in:
parent
66f9afe038
commit
d9f645ba50
@ -4,6 +4,9 @@
|
||||
|
||||
#include "impeller/compositor/render_pass.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "flutter/fml/closure.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "impeller/base/base.h"
|
||||
@ -176,7 +179,147 @@ bool RenderPass::FinishEncoding(Allocator& transients_allocator) const {
|
||||
return EncodeCommands(transients_allocator, pass);
|
||||
}
|
||||
|
||||
static bool Bind(id<MTLRenderCommandEncoder> pass,
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief Ensures that bindings on the pass are not redundantly set or
|
||||
/// updated. Avoids making the driver do additional checks and makes
|
||||
/// the frame insights during profiling and instrumentation not
|
||||
/// complain about the same.
|
||||
///
|
||||
/// There should be no change to rendering if this caching was
|
||||
/// absent.
|
||||
///
|
||||
struct PassBindingsCache {
|
||||
PassBindingsCache(id<MTLRenderCommandEncoder> pass) : pass_(pass) {}
|
||||
|
||||
PassBindingsCache(const PassBindingsCache&) = delete;
|
||||
|
||||
PassBindingsCache(PassBindingsCache&&) = delete;
|
||||
|
||||
void SetRenderPipelineState(id<MTLRenderPipelineState> pipeline) {
|
||||
if (pipeline == pipeline_) {
|
||||
return;
|
||||
}
|
||||
pipeline_ = pipeline;
|
||||
[pass_ setRenderPipelineState:pipeline_];
|
||||
}
|
||||
|
||||
void SetDepthStencilState(id<MTLDepthStencilState> depth_stencil) {
|
||||
if (depth_stencil_ == depth_stencil) {
|
||||
return;
|
||||
}
|
||||
depth_stencil_ = depth_stencil;
|
||||
[pass_ setDepthStencilState:depth_stencil_];
|
||||
}
|
||||
|
||||
bool SetBuffer(ShaderStage stage,
|
||||
uint64_t index,
|
||||
uint64_t offset,
|
||||
id<MTLBuffer> buffer) {
|
||||
auto& buffers_map = buffers_[stage];
|
||||
auto found = buffers_map.find(index);
|
||||
if (found != buffers_map.end() && found->second.buffer == buffer) {
|
||||
// The right buffer is bound. Check if its offset needs to be updated.
|
||||
if (found->second.offset == offset) {
|
||||
// Buffer and its offset is identical. Nothing to do.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only the offset needs to be updated.
|
||||
found->second.offset = offset;
|
||||
|
||||
switch (stage) {
|
||||
case ShaderStage::kVertex:
|
||||
[pass_ setVertexBufferOffset:offset atIndex:index];
|
||||
return true;
|
||||
case ShaderStage::kFragment:
|
||||
[pass_ setFragmentBufferOffset:offset atIndex:index];
|
||||
return true;
|
||||
default:
|
||||
FML_DCHECK(false)
|
||||
<< "Cannot update buffer offset of an unknown stage.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
buffers_map[index] = {buffer, offset};
|
||||
switch (stage) {
|
||||
case ShaderStage::kVertex:
|
||||
[pass_ setVertexBuffer:buffer offset:offset atIndex:index];
|
||||
return true;
|
||||
case ShaderStage::kFragment:
|
||||
[pass_ setFragmentBuffer:buffer offset:offset atIndex:index];
|
||||
return true;
|
||||
default:
|
||||
FML_DCHECK(false) << "Cannot bind buffer to unknown shader stage.";
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SetTexture(ShaderStage stage, uint64_t index, id<MTLTexture> texture) {
|
||||
auto& texture_map = textures_[stage];
|
||||
auto found = texture_map.find(index);
|
||||
if (found != texture_map.end() && found->second == texture) {
|
||||
// Already bound.
|
||||
return true;
|
||||
}
|
||||
texture_map[index] = texture;
|
||||
switch (stage) {
|
||||
case ShaderStage::kVertex:
|
||||
[pass_ setVertexTexture:texture atIndex:index];
|
||||
return true;
|
||||
case ShaderStage::kFragment:
|
||||
[pass_ setFragmentTexture:texture atIndex:index];
|
||||
return true;
|
||||
default:
|
||||
FML_DCHECK(false) << "Cannot bind buffer to unknown shader stage.";
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SetSampler(ShaderStage stage,
|
||||
uint64_t index,
|
||||
id<MTLSamplerState> sampler) {
|
||||
auto& sampler_map = samplers_[stage];
|
||||
auto found = sampler_map.find(index);
|
||||
if (found != sampler_map.end() && found->second == sampler) {
|
||||
// Already bound.
|
||||
return true;
|
||||
}
|
||||
sampler_map[index] = sampler;
|
||||
switch (stage) {
|
||||
case ShaderStage::kVertex:
|
||||
[pass_ setVertexSamplerState:sampler atIndex:index];
|
||||
return true;
|
||||
case ShaderStage::kFragment:
|
||||
[pass_ setFragmentSamplerState:sampler atIndex:index];
|
||||
return true;
|
||||
default:
|
||||
FML_DCHECK(false) << "Cannot bind buffer to unknown shader stage.";
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
struct BufferOffsetPair {
|
||||
id<MTLBuffer> buffer = nullptr;
|
||||
size_t offset = 0u;
|
||||
};
|
||||
using BufferMap = std::map<uint64_t, BufferOffsetPair>;
|
||||
using TextureMap = std::map<uint64_t, id<MTLTexture>>;
|
||||
using SamplerMap = std::map<uint64_t, id<MTLSamplerState>>;
|
||||
|
||||
const id<MTLRenderCommandEncoder> pass_;
|
||||
id<MTLRenderPipelineState> pipeline_ = nullptr;
|
||||
id<MTLDepthStencilState> depth_stencil_ = nullptr;
|
||||
std::map<ShaderStage, BufferMap> buffers_;
|
||||
std::map<ShaderStage, TextureMap> textures_;
|
||||
std::map<ShaderStage, SamplerMap> samplers_;
|
||||
};
|
||||
|
||||
static bool Bind(PassBindingsCache& pass,
|
||||
Allocator& allocator,
|
||||
ShaderStage stage,
|
||||
size_t bind_index,
|
||||
@ -196,25 +339,10 @@ static bool Bind(id<MTLRenderCommandEncoder> pass,
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (stage) {
|
||||
case ShaderStage::kVertex:
|
||||
[pass setVertexBuffer:buffer offset:view.range.offset atIndex:bind_index];
|
||||
return true;
|
||||
case ShaderStage::kFragment:
|
||||
[pass setFragmentBuffer:buffer
|
||||
offset:view.range.offset
|
||||
atIndex:bind_index];
|
||||
return true;
|
||||
default:
|
||||
FML_DLOG(ERROR) << "Cannot bind buffer to unknown shader stage.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
return pass.SetBuffer(stage, bind_index, view.range.offset, buffer);
|
||||
}
|
||||
|
||||
static bool Bind(id<MTLRenderCommandEncoder> pass,
|
||||
Allocator& allocator,
|
||||
static bool Bind(PassBindingsCache& pass,
|
||||
ShaderStage stage,
|
||||
size_t bind_index,
|
||||
const Texture& texture) {
|
||||
@ -222,23 +350,10 @@ static bool Bind(id<MTLRenderCommandEncoder> pass,
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (stage) {
|
||||
case ShaderStage::kVertex:
|
||||
[pass setVertexTexture:texture.GetMTLTexture() atIndex:bind_index];
|
||||
return true;
|
||||
case ShaderStage::kFragment:
|
||||
[pass setFragmentTexture:texture.GetMTLTexture() atIndex:bind_index];
|
||||
return true;
|
||||
default:
|
||||
FML_DLOG(ERROR) << "Cannot bind buffer to unknown shader stage.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
return pass.SetTexture(stage, bind_index, texture.GetMTLTexture());
|
||||
}
|
||||
|
||||
static bool Bind(id<MTLRenderCommandEncoder> pass,
|
||||
Allocator& allocator,
|
||||
static bool Bind(PassBindingsCache& pass,
|
||||
ShaderStage stage,
|
||||
size_t bind_index,
|
||||
const Sampler& sampler) {
|
||||
@ -246,48 +361,33 @@ static bool Bind(id<MTLRenderCommandEncoder> pass,
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (stage) {
|
||||
case ShaderStage::kVertex:
|
||||
[pass setVertexSamplerState:sampler.GetMTLSamplerState()
|
||||
atIndex:bind_index];
|
||||
|
||||
return true;
|
||||
case ShaderStage::kFragment:
|
||||
[pass setFragmentSamplerState:sampler.GetMTLSamplerState()
|
||||
atIndex:bind_index];
|
||||
return true;
|
||||
default:
|
||||
FML_DLOG(ERROR) << "Cannot bind buffer to unknown shader stage.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
return pass.SetSampler(stage, bind_index, sampler.GetMTLSamplerState());
|
||||
}
|
||||
|
||||
bool RenderPass::EncodeCommands(Allocator& allocator,
|
||||
id<MTLRenderCommandEncoder> pass) const {
|
||||
// There a numerous opportunities here to ensure bindings are not repeated.
|
||||
// Stuff like setting the vertex buffer bindings over and over when just the
|
||||
// offsets could be updated (as recommended in best practices).
|
||||
auto bind_stage_resources = [&allocator, pass](const Bindings& bindings,
|
||||
ShaderStage stage) -> bool {
|
||||
PassBindingsCache pass_bindings(pass);
|
||||
auto bind_stage_resources = [&allocator, &pass_bindings](
|
||||
const Bindings& bindings,
|
||||
ShaderStage stage) -> bool {
|
||||
for (const auto buffer : bindings.buffers) {
|
||||
if (!Bind(pass, allocator, stage, buffer.first, buffer.second)) {
|
||||
if (!Bind(pass_bindings, allocator, stage, buffer.first, buffer.second)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto texture : bindings.textures) {
|
||||
if (!Bind(pass, allocator, stage, texture.first, *texture.second)) {
|
||||
if (!Bind(pass_bindings, stage, texture.first, *texture.second)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto sampler : bindings.samplers) {
|
||||
if (!Bind(pass, allocator, stage, sampler.first, *sampler.second)) {
|
||||
if (!Bind(pass_bindings, stage, sampler.first, *sampler.second)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
fml::closure pop_debug_marker = [pass]() { [pass popDebugGroup]; };
|
||||
for (const auto& command : commands_) {
|
||||
if (command.index_count == 0u) {
|
||||
@ -300,8 +400,10 @@ bool RenderPass::EncodeCommands(Allocator& allocator,
|
||||
} else {
|
||||
auto_pop_debug_marker.Release();
|
||||
}
|
||||
[pass setRenderPipelineState:command.pipeline->GetMTLRenderPipelineState()];
|
||||
[pass setDepthStencilState:command.pipeline->GetMTLDepthStencilState()];
|
||||
pass_bindings.SetRenderPipelineState(
|
||||
command.pipeline->GetMTLRenderPipelineState());
|
||||
pass_bindings.SetDepthStencilState(
|
||||
command.pipeline->GetMTLDepthStencilState());
|
||||
[pass setFrontFacingWinding:MTLWindingClockwise];
|
||||
[pass setCullMode:MTLCullModeBack];
|
||||
if (!bind_stage_resources(command.vertex_bindings, ShaderStage::kVertex)) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user