blob: 481b24a3f929919d574d88a45e2fee516baa531a [file] [log] [blame]
// Copyright 2016 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_IMPL_COMMAND_BUFFER_H_
#define LIB_ESCHER_IMPL_COMMAND_BUFFER_H_
#include <functional>
#include <vector>
#include <lib/fit/function.h>
#include "lib/escher/forward_declarations.h"
#include "lib/escher/renderer/semaphore.h"
#include "lib/escher/scene/camera.h"
#include "lib/escher/vk/vulkan_context.h"
#include "lib/fxl/macros.h"
namespace escher {
typedef fit::function<void()> CommandBufferFinishedCallback;
namespace impl {
// CommandBuffer is a wrapper around vk::CommandBuffer. Vulkan forbids the
// client application from destroying any resources while they are used by
// any "pending command buffers" (i.e. those that have not finished executing
// on the GPU).
//
// CommandBuffers are obtained from a CommandBufferPool, and is automatically
// returned to it when all GPU-work is finished.
//
// Not thread-safe.
//
// TODO(ES-77): RenderPass and Framebuffer are deprecated, to be replaced by
// impl::RenderPass and impl::Framebuffer. The latter two aren't visible to
// Escher clients; they are an implementation detail of escher::CommandBuffer
// (NOTE: NOT escher::impl::CommandBuffer, which is also deprecated).
class CommandBuffer {
public:
~CommandBuffer();
vk::CommandBuffer vk() const { return command_buffer_; }
// Return true if successful. The callback will be invoked after all commands
// have finished executing on the GPU (there is no guarantee about how long
// afterward: this depends on when the CommandBufferPool that owns this buffer
// calls Retire()).
bool Submit(vk::Queue queue, CommandBufferFinishedCallback callback);
// During Submit(), these semaphores will be added to the vk::SubmitInfo.
// No-op if semaphore is null.
void AddWaitSemaphore(SemaphorePtr semaphore, vk::PipelineStageFlags stage);
// For convenience, calls TakeWaitSemaphore() on the resource, and passes the
// result to AddWaitSemaphore().
template <typename ResourcePtrT>
void TakeWaitSemaphore(const ResourcePtrT& resource,
vk::PipelineStageFlags stage) {
AddWaitSemaphore(resource->TakeWaitSemaphore(), stage);
}
// During Submit(), these semaphores will be added to the vk::SubmitInfo.
// No-op if semaphore is null.
void AddSignalSemaphore(SemaphorePtr semaphore);
// These resources will be retained until the command-buffer is finished
// running on the GPU.
void KeepAlive(Resource* resource);
template <typename ResourceT>
void KeepAlive(const fxl::RefPtr<ResourceT>& ptr) {
KeepAlive(ptr.get());
}
// Bind index/vertex buffers and write draw command.
// Retain mesh in used_resources.
void DrawMesh(const MeshPtr& mesh);
// Copy pixels from one image to another. No image barriers or other
// synchronization is used. Retain both images in used_resources.
void CopyImage(const ImagePtr& src_image, const ImagePtr& dst_image,
vk::ImageLayout src_layout, vk::ImageLayout dst_layout,
vk::ImageCopy* region);
// Copy memory from one buffer to another.
void CopyBuffer(const BufferPtr& src, const BufferPtr& dst,
vk::BufferCopy region);
// Copy the specified region of |src| into |dst| after inserting a
// memory-barrier to use the memory on the same queue (i.e. the barrier's
// queue family indices are VK_QUEUE_FAMILY_IGNORED).
void CopyBufferAfterBarrier(const BufferPtr& src, const BufferPtr& dst,
vk::BufferCopy region,
vk::AccessFlags src_access_mask,
vk::PipelineStageFlags src_stage_mask);
// Transition the image between the two layouts; see section 11.4 of the
// Vulkan spec. Retain image in used_resources.
void TransitionImageLayout(const ImagePtr& image, vk::ImageLayout old_layout,
vk::ImageLayout new_layout);
// Convenient way to begin a render-pass that renders to the whole framebuffer
// (i.e. width/height of viewport and scissors are obtained from framebuffer).
void BeginRenderPass(const escher::RenderPassPtr& render_pass,
const escher::FramebufferPtr& framebuffer,
const std::vector<vk::ClearValue>& clear_values,
const vk::Rect2D viewport);
void BeginRenderPass(vk::RenderPass render_pass,
const escher::FramebufferPtr& framebuffer,
const std::vector<vk::ClearValue>& clear_values,
const vk::Rect2D viewport);
void BeginRenderPass(vk::RenderPass render_pass,
const escher::FramebufferPtr& framebuffer,
const vk::ClearValue* clear_values,
size_t clear_value_count, const vk::Rect2D viewport);
// Simple wrapper around endRenderPass().
void EndRenderPass();
// Block until the command-buffer is no longer pending, or the specified
// number of nanoseconds has elapsed. Return vk::Result::eSuccess in the
// former case, and vk::Result::eTimeout in the latter.
vk::Result Wait(uint64_t timeout_nanoseconds);
// Each CommandBuffer that is obtained from a CommandBufferPool is given a
// monotonically-increasing sequence number. This number is globally unique
// (per Escher instance), even across multiple CommandBufferPools.
uint64_t sequence_number() const { return sequence_number_; }
private:
friend class CommandBufferPool;
// Called by CommandBufferPool, which is responsible for eventually destroying
// the Vulkan command buffer and fence. Submit() and Retire() use the fence
// to determine when the command buffer has finished executing on the GPU.
CommandBuffer(vk::Device device, vk::CommandBuffer command_buffer,
vk::Fence fence, vk::PipelineStageFlags pipeline_stage_mask);
vk::Fence fence() const { return fence_; }
// Called by CommandBufferPool when this buffer is obtained from it.
void Begin(uint64_t sequence_number);
// Called by CommandBufferPool, to attempt to reset the buffer for reuse.
// Return false and do nothing if the buffer's submission fence is not ready.
bool Retire();
const vk::Device device_;
const vk::CommandBuffer command_buffer_;
const vk::Fence fence_;
const vk::PipelineStageFlags pipeline_stage_mask_;
std::vector<SemaphorePtr> wait_semaphores_;
std::vector<vk::PipelineStageFlags> wait_semaphore_stages_;
std::vector<vk::Semaphore> wait_semaphores_for_submit_;
std::vector<SemaphorePtr> signal_semaphores_;
std::vector<vk::Semaphore> signal_semaphores_for_submit_;
bool is_active_ = false;
bool is_submitted_ = false;
uint64_t sequence_number_ = 0;
CommandBufferFinishedCallback callback_;
FXL_DISALLOW_COPY_AND_ASSIGN(CommandBuffer);
};
} // namespace impl
} // namespace escher
#endif // LIB_ESCHER_IMPL_COMMAND_BUFFER_H_