blob: bc3ecef64dcb9756c061f1e2dd900b6e1cb6b8db [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 "src/ui/lib/escher/vk/impl/framebuffer_allocator.h"
#include "src/ui/lib/escher/third_party/granite/vk/render_pass.h"
#include "src/ui/lib/escher/util/hasher.h"
#include "src/ui/lib/escher/util/trace_macros.h"
#include "src/ui/lib/escher/vk/impl/framebuffer.h"
#include "src/ui/lib/escher/vk/impl/render_pass_cache.h"
#include "src/ui/lib/escher/vk/render_pass_info.h"
namespace escher {
namespace impl {
FramebufferAllocator::FramebufferAllocator(ResourceRecycler* recycler,
impl::RenderPassCache* render_pass_cache)
: recycler_(recycler), render_pass_cache_(render_pass_cache) {}
const impl::FramebufferPtr& FramebufferAllocator::ObtainFramebuffer(
const RenderPassInfo& info, bool allow_render_pass_creation) {
TRACE_DURATION("gfx", "escher::impl::FramebufferAllocator::ObtainFramebuffer");
// We need the render-pass to generate the hash used to look up a framebuffer. If the
// render-pass doesn't exist, we assume that no framebuffer does either. This is currently
// always true (since |RenderPassCache| never deletes cache entries), and is a safe assumption
// going forward (we should always evict items from this cache at least as frequently as from the
// render-pass cache).
auto& render_pass = render_pass_cache_->ObtainRenderPass(info, allow_render_pass_creation);
FX_DCHECK(render_pass || !allow_render_pass_creation);
if (!render_pass) {
// We're returning "const Ptr&" not "Ptr", so we must return a reference to a value that won't
// immediately go out of scope.
FX_LOGS(WARNING) << "FramebufferAllocator::ObtainFramebuffer(): no render-pass was found";
const static impl::FramebufferPtr null_ptr;
return null_ptr;
}
FX_DCHECK(render_pass);
Hasher h;
h.u64(render_pass->uid());
for (uint32_t i = 0; i < info.num_color_attachments; i++) {
FX_DCHECK(info.color_attachments[i]);
h.u64(info.color_attachments[i]->uid());
}
if (info.depth_stencil_attachment) {
h.u64(info.depth_stencil_attachment->uid());
}
// TODO(fxbug.dev/7167): track cache hit/miss rates.
Hash hash = h.value();
auto pair = framebuffer_cache_.Obtain(hash);
if (!pair.second) {
// The cache didn't already have a Framebuffer so it returns an empty
// FramebufferPtr that we will point at a newly-created Framebuffer.
//
// TODO(fxbug.dev/7169): it smells weird to use an ObjectPool to hold possibly-null
// RefPtrs and then fill them in here. Maybe ObjectPool can be rejiggered
// to make this more elegant?
TRACE_DURATION("gfx", "escher::FramebufferAllocator::ObtainFramebuffer (creation)");
FX_DCHECK(!pair.first->framebuffer);
pair.first->framebuffer = fxl::MakeRefCounted<impl::Framebuffer>(recycler_, render_pass, info);
}
FX_DCHECK(pair.first->framebuffer);
return pair.first->framebuffer;
}
} // namespace impl
} // namespace escher