blob: ad4c1a426af7a6cfe67bf5d6b18b69e1dd0da2cc [file] [log] [blame]
// Copyright 2017 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.
#ifndef LIB_ESCHER_RENDERER_FRAME_H_
#define LIB_ESCHER_RENDERER_FRAME_H_
#include <cstdint>
#include <functional>
#include <vulkan/vulkan.hpp>
#include <lib/fit/function.h>
#include "lib/escher/base/reffable.h"
#include "lib/escher/forward_declarations.h"
#include "lib/escher/impl/command_buffer.h"
#include "lib/escher/profiling/timestamp_profiler.h"
#include "lib/escher/renderer/uniform_block_allocator.h"
#include "lib/escher/util/block_allocator.h"
#include "lib/escher/vk/command_buffer.h"
namespace escher {
typedef fit::function<void()> FrameRetiredCallback;
class Frame;
using FramePtr = fxl::RefPtr<Frame>;
// Represents a single render pass on a command queue. There may be multiple
// frames issuing commands per render draw call. Frame is passed into a
// Renderer, which uses it to obtain command buffers, submit partial frames, do
// profiling, etc.
class Frame : public Resource {
public:
static const ResourceTypeInfo kTypeInfo;
const ResourceTypeInfo& type_info() const override { return kTypeInfo; }
~Frame();
// Obtain a CommandBuffer, to record commands for the current frame.
void SubmitPartialFrame(const SemaphorePtr& partial_frame_done);
void EndFrame(const SemaphorePtr& frame_done,
FrameRetiredCallback frame_retired_callback);
// If profiling is enabled, inserts a Vulkan timestamp query into the frame's
// current CommandBuffer; the result will be inserted into the trace log.
// |stages| denotes the set of pipeline stages that must be completed by all
// previously-issued commands; see TimestampProfiler docs for more details.
void AddTimestamp(const char* name,
vk::PipelineStageFlagBits stages =
vk::PipelineStageFlagBits::eBottomOfPipe);
uint64_t frame_number() const { return frame_number_; }
CommandBuffer* cmds() const { return command_buffer_.get(); }
impl::CommandBuffer* command_buffer() const;
vk::CommandBuffer vk_command_buffer() const;
uint64_t command_buffer_sequence_number() const {
return command_buffer_sequence_number_;
}
GpuAllocator* gpu_allocator();
// Allocate temporary CPU memory that is valid until EndFrame() is called.
template <typename T>
T* Allocate() {
return block_allocator_.Allocate<T>();
}
// Allocate temporary CPU memory that is valid until EndFrame() is called.
template <typename T>
T* AllocateMany(size_t count) {
return block_allocator_.AllocateMany<T>(count);
}
// Allocate temporary GPU uniform buffer memory that is value until the frame
// is finished rendering (after EndFrame() is called).
UniformAllocation AllocateUniform(size_t size, size_t alignment) {
return uniform_block_allocator_.Allocate(size, alignment);
}
private:
// These resources will be retained until the current frame is finished
// running on the GPU.
void KeepAlive(ResourcePtr resource);
// Constructor called by Escher::NewFrame().
// NOTE: moving the BlockAllocator into the Frame (instead of e.g. passing a
// unique_ptr) avoids an extra pointer indirection on each allocation.
friend class impl::FrameManager;
Frame(impl::FrameManager* manager, CommandBuffer::Type requested_type,
BlockAllocator allocator,
impl::UniformBufferPoolWeakPtr uniform_buffer_pool,
uint64_t frame_number, const char* trace_literal,
const char* gpu_vthread_literal, uint64_t gpu_vthread_id,
bool enable_gpu_logging);
void BeginFrame();
// Issues a new CommandBuffer for a frame, and marks the frame as InProgress.
void IssueCommandBuffer();
// Called by impl::FrameManager when the Frame is returned to the pool, so
// that it can be reused in newly constructed frames.
BlockAllocator TakeBlockAllocator() { return std::move(block_allocator_); }
// Called by BatchGpuUploader to write to the new_command_buffer_ and gather
// work to post to the GPU.
// TODO(SCN-846) Remove these functions once BatchGpuUploader::Writers are
// backed by secondary buffers, and the frame's primary command buffer is not
// moved into the Writer.
friend class BatchGpuUploader;
CommandBufferPtr TakeCommandBuffer();
void PutCommandBuffer(CommandBufferPtr command_buffer);
enum class State {
kReadyToBegin,
kInProgress,
kFinishing,
};
State state_ = State::kReadyToBegin;
// The frame number associated with this frame. Used to correlate work across
// threads for tracing events.
const uint64_t frame_number_;
// A unique number to identify this escher frame. It can diverge from
// frame_number_, as frame_number_ is used by the client for its own tracking.
const uint64_t escher_frame_number_;
// A string constant that is the name of the trace event this frame will
// generate.
const char* trace_literal_;
// A string constant that is the name of the virtual thread this frame
// generates events for.
const char* gpu_vthread_literal_;
// A unique identifier for the virtual thread this frame generates events for.
const uint64_t gpu_vthread_id_;
bool enable_gpu_logging_;
vk::Queue queue_;
CommandBuffer::Type command_buffer_type_;
// The sequence number of the command_buffer managed by this frame. Cached
// here to track which command_buffer was managed by this frame if the command
// buffer was taken (via TakeCommandBuffer()) for GPU uploads.
uint64_t command_buffer_sequence_number_;
CommandBufferPtr command_buffer_;
BlockAllocator block_allocator_;
UniformBlockAllocator uniform_block_allocator_;
TimestampProfilerPtr profiler_;
uint32_t submission_count_ = 0;
// TODO(ES-103): ideally we can move away from explicitly retaining used
// resources in the Frame. For now, this approach is easy and relatively
// fool-proof.
std::vector<ResourcePtr> keep_alive_;
};
} // namespace escher
#endif // LIB_ESCHER_RENDERER_FRAME_H_