blob: 34dc9e4b21443ae0f2be5bd07ce1af7566251742 [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.
#include <memory>
#include "src/lib/fxl/macros.h"
#include "src/lib/fxl/memory/weak_ptr.h"
#include "src/ui/lib/escher/forward_declarations.h"
#include "src/ui/lib/escher/impl/image_cache.h"
#include "src/ui/lib/escher/shape/mesh_builder_factory.h"
#include "src/ui/lib/escher/status.h"
#include "src/ui/lib/escher/util/hash.h"
#include "src/ui/lib/escher/util/hash_map.h"
#include "src/ui/lib/escher/vk/chained_semaphore_generator.h"
#include "src/ui/lib/escher/vk/command_buffer.h"
#include "src/ui/lib/escher/vk/shader_program_factory.h"
#include "src/ui/lib/escher/vk/vulkan_context.h"
#include "src/ui/lib/escher/vk/vulkan_device_queues.h"
namespace escher {
// Escher is the primary class used by clients of the Escher library.
// Escher is currently not thread-safe; it (and all objects obtained from it)
// must be used from a single thread.
class Escher final : public MeshBuilderFactory, public ShaderProgramFactory {
// Escher does not take ownership of the objects in the Vulkan context. It is
// up to the application to eventually destroy them, and also to ensure that
// they outlive the Escher instance.
explicit Escher(VulkanDeviceQueuesPtr device);
// If |gpu_allocator| is nullptr, a default allocator will be created.
Escher(VulkanDeviceQueuesPtr device, HackFilesystemPtr filesystem,
std::shared_ptr<GpuAllocator> gpu_allocator);
EscherWeakPtr GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
// Implement MeshBuilderFactory interface.
MeshBuilderPtr NewMeshBuilder(BatchGpuUploader* gpu_uploader, const MeshSpec& spec,
size_t max_vertex_count, size_t max_index_count) override;
// Return new Image containing the provided pixels.
ImagePtr NewRgbaImage(BatchGpuUploader* gpu_uploader, uint32_t width, uint32_t height,
const uint8_t* bytes);
// Returns RGBA image.
ImagePtr NewCheckerboardImage(BatchGpuUploader* gpu_uploader, uint32_t width, uint32_t height);
// Returns RGBA image.
ImagePtr NewGradientImage(BatchGpuUploader* gpu_uploader, uint32_t width, uint32_t height);
// Returns single-channel luminance image.
ImagePtr NewNoiseImage(BatchGpuUploader* gpu_uploader, uint32_t width, uint32_t height);
// Return a new Frame, which is passed to Renderers to obtain and submit
// command buffers, to add timestamps for GPU profiling, etc. If
// |enable_gpu_logging| is true, GPU profiling timestamps will be logged via
// FX_LOGS().
FramePtr NewFrame(
const char* trace_literal, uint64_t frame_number, bool enable_gpu_logging = false,
escher::CommandBuffer::Type requested_type = escher::CommandBuffer::Type::kGraphics,
bool use_protected_memory = false);
// Construct a new Texture, which encapsulates a newly-created VkImageView and
// VkSampler. |aspect_mask| is used to create the VkImageView, and |filter|
// and |use_unnormalized_coordinates| are used to create the VkSampler.
TexturePtr NewTexture(ImagePtr image, vk::Filter filter,
vk::ImageAspectFlags aspect_mask = vk::ImageAspectFlagBits::eColor,
bool use_unnormalized_coordinates = false);
// Construct a new Texture, which encapsulates a newly-created VkImage,
// VkImageView and VkSampler. |aspect_mask| is used to create the
// VkImageView, and |filter| and |use_unnormalized_coordinates| are used to
// create the VkSampler.
TexturePtr NewTexture(vk::Format format, uint32_t width, uint32_t height, uint32_t sample_count,
vk::ImageUsageFlags usage_flags, vk::Filter filter,
vk::ImageAspectFlags aspect_flags,
bool use_unnormalized_coordinates = false,
vk::MemoryPropertyFlags memory_flags = vk::MemoryPropertyFlags());
// Construct a new Buffer, which encapsulates a newly-created VkBuffer.
// |usage_flags| defines whether it is to be used as e.g. a uniform and/or a
// vertex buffer, and |memory_property_flags| is used to select the heap that
// the buffer's backing VkDeviceMemory is allocated from.
BufferPtr NewBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage_flags,
vk::MemoryPropertyFlags memory_property_flags);
// Same as the NewTexture() variant that creates the image, except that it
// automatically sets up the vk::ImageAspectFlags, and adds the following to
// |additional_usage_flags|:
// - either eColorAttachment or eDepthAttachment, depending on |format|
// - optionally eTransientAttachment, depending on |is_transient|
// - optionally eInputAttachment, depending on |is_input|
TexturePtr NewAttachmentTexture(
vk::Format format, uint32_t width, uint32_t height, uint32_t sample_count, vk::Filter filter,
vk::ImageUsageFlags additional_usage_flags = vk::ImageUsageFlags(),
bool use_unnormalized_coordinates = false,
vk::MemoryPropertyFlags memory_flags = vk::MemoryPropertyFlags());
uint64_t GetNumGpuBytesAllocated();
// Do periodic housekeeping. This is called by Renderer::EndFrame(), so you
// don't need to call it if your application is constantly rendering.
// However, if your app enters a "quiet period" then you might want to
// arrange to call Cleanup() after the last frame has finished rendering.
// Return true if cleanup was complete, and false if more cleanup remains
// (in that case, the app should wait a moment before calling Cleanup()
// again).
bool Cleanup();
// Allow clients to set the pipeline builder; if this isn't called then Escher will use a
// default builder.
void set_pipeline_builder(std::unique_ptr<PipelineBuilder> pipeline_builder);
VulkanDeviceQueues* device() const { return device_.get(); }
vk::Device vk_device() const { return device_->vk_device(); }
vk::PhysicalDevice vk_physical_device() const { return device_->vk_physical_device(); }
const VulkanContext& vulkan_context() const { return vulkan_context_; }
ResourceRecycler* resource_recycler() { return resource_recycler_.get(); }
GpuAllocator* gpu_allocator() { return gpu_allocator_.get(); }
impl::CommandBufferSequencer* command_buffer_sequencer() {
return command_buffer_sequencer_.get();
shaderc::Compiler* shaderc_compiler() { return shaderc_compiler_.get(); }
ImageFactory* image_cache() { return image_cache_.get(); }
BufferCache* buffer_cache() { return buffer_cache_.get(); }
SamplerCache* sampler_cache() { return sampler_cache_.get(); }
impl::MeshManager* mesh_manager() { return mesh_manager_.get(); }
impl::PipelineLayoutCache* pipeline_layout_cache() { return pipeline_layout_cache_.get(); }
impl::DescriptorSetAllocatorCache* descriptor_set_allocator_cache() {
return descriptor_set_allocator_cache_.get();
impl::RenderPassCache* render_pass_cache() const { return render_pass_cache_.get(); }
impl::FramebufferAllocator* framebuffer_allocator() const { return framebuffer_allocator_.get(); }
ImageViewAllocator* image_view_allocator() const { return image_view_allocator_.get(); }
ChainedSemaphoreGenerator* semaphore_chain() const { return semaphore_chain_.get(); }
// Pool for CommandBuffers submitted on the main queue.
impl::CommandBufferPool* command_buffer_pool() { return command_buffer_pool_.get(); }
// Pool for CommandBuffers submitted on the transfer queue (if one exists).
impl::CommandBufferPool* transfer_command_buffer_pool() {
return transfer_command_buffer_pool_.get();
// Pool for CommandBuffers submitted in a protected context.
impl::CommandBufferPool* protected_command_buffer_pool();
DefaultShaderProgramFactory* shader_program_factory() { return shader_program_factory_.get(); }
PipelineBuilder* pipeline_builder() const { return pipeline_builder_.get(); }
// Check if GPU performance profiling is supported.
bool supports_timer_queries() const { return supports_timer_queries_; }
float timestamp_period() const { return timestamp_period_; }
bool supports_wireframe() const { return device_->caps().enabled_features.fillModeNonSolid; }
bool allow_protected_memory() const { return device_->caps().allow_protected_memory; }
bool allow_ycbcr() const { return device_->caps().allow_ycbcr; }
// |ShaderProgramFactory|
ShaderProgramPtr GetProgramImpl(const std::string shader_paths[EnumCount<ShaderStage>()],
ShaderVariantArgs args) override;
VulkanDeviceQueuesPtr device_;
VulkanContext vulkan_context_;
// These can be constructed without an EscherWeakPtr.
std::shared_ptr<GpuAllocator> gpu_allocator_;
std::unique_ptr<impl::CommandBufferSequencer> command_buffer_sequencer_;
std::unique_ptr<impl::CommandBufferPool> command_buffer_pool_;
std::unique_ptr<impl::CommandBufferPool> transfer_command_buffer_pool_;
std::unique_ptr<impl::CommandBufferPool> protected_command_buffer_pool_;
std::unique_ptr<shaderc::Compiler> shaderc_compiler_;
// Everything below this point requires |weak_factory_| to be initialized
// before they can be constructed.
std::unique_ptr<ResourceRecycler> resource_recycler_;
std::unique_ptr<impl::ImageCache> image_cache_;
std::unique_ptr<BufferCache> buffer_cache_;
std::unique_ptr<SamplerCache> sampler_cache_;
std::unique_ptr<impl::MeshManager> mesh_manager_;
std::unique_ptr<DefaultShaderProgramFactory> shader_program_factory_;
std::unique_ptr<PipelineBuilder> pipeline_builder_;
std::unique_ptr<impl::DescriptorSetAllocatorCache> descriptor_set_allocator_cache_;
std::unique_ptr<impl::PipelineLayoutCache> pipeline_layout_cache_;
std::unique_ptr<impl::RenderPassCache> render_pass_cache_;
std::unique_ptr<impl::FramebufferAllocator> framebuffer_allocator_;
std::unique_ptr<ImageViewAllocator> image_view_allocator_;
std::unique_ptr<impl::FrameManager> frame_manager_;
std::unique_ptr<ChainedSemaphoreGenerator> semaphore_chain_;
bool supports_timer_queries_ = false;
float timestamp_period_ = 0.f;
fxl::WeakPtrFactory<Escher> weak_factory_; // must be last
using EscherUniquePtr = std::unique_ptr<Escher, std::function<void(Escher*)>>;
} // namespace escher