blob: 6651bdd07f77a32cd52d9807e2b4ef67ab2f5b79 [file] [log] [blame]
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// RendererVk.h:
// Defines the class interface for RendererVk.
//
#ifndef LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_
#define LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_
#include <vulkan/vulkan.h>
#include <memory>
#include "common/angleutils.h"
#include "libANGLE/BlobCache.h"
#include "libANGLE/Caps.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/QueryVk.h"
#include "libANGLE/renderer/vulkan/UtilsVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
#include "libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h"
namespace egl
{
class Display;
class BlobCache;
} // namespace egl
namespace rx
{
class DisplayVk;
class FramebufferVk;
namespace vk
{
struct Format;
}
class RendererVk : angle::NonCopyable
{
public:
RendererVk();
~RendererVk();
angle::Result initialize(DisplayVk *displayVk,
egl::Display *display,
const char *wsiExtension,
const char *wsiLayer);
void onDestroy(vk::Context *context);
void notifyDeviceLost();
bool isDeviceLost() const;
std::string getVendorString() const;
std::string getRendererDescription() const;
gl::Version getMaxSupportedESVersion() const;
VkInstance getInstance() const { return mInstance; }
VkPhysicalDevice getPhysicalDevice() const { return mPhysicalDevice; }
const VkPhysicalDeviceProperties &getPhysicalDeviceProperties() const
{
return mPhysicalDeviceProperties;
}
const VkPhysicalDeviceFeatures &getPhysicalDeviceFeatures() const
{
return mPhysicalDeviceFeatures;
}
VkQueue getQueue() const { return mQueue; }
VkDevice getDevice() const { return mDevice; }
angle::Result selectPresentQueueForSurface(DisplayVk *displayVk,
VkSurfaceKHR surface,
uint32_t *presentQueueOut);
angle::Result finish(vk::Context *context);
angle::Result flush(vk::Context *context);
const vk::CommandPool &getCommandPool() const;
const gl::Caps &getNativeCaps() const;
const gl::TextureCapsMap &getNativeTextureCaps() const;
const gl::Extensions &getNativeExtensions() const;
const gl::Limitations &getNativeLimitations() const;
uint32_t getMaxActiveTextures();
Serial getCurrentQueueSerial() const { return mCurrentQueueSerial; }
Serial getLastSubmittedQueueSerial() const { return mLastSubmittedQueueSerial; }
Serial getLastCompletedQueueSerial() const { return mLastCompletedQueueSerial; }
bool isSerialInUse(Serial serial) const;
template <typename T>
void releaseObject(Serial resourceSerial, T *object)
{
if (!isSerialInUse(resourceSerial))
{
object->destroy(mDevice);
}
else
{
object->dumpResources(resourceSerial, &mGarbage);
}
}
// Check to see which batches have finished completion (forward progress for
// mLastCompletedQueueSerial, for example for when the application busy waits on a query
// result).
angle::Result checkCompletedCommands(vk::Context *context);
// Wait for completion of batches until (at least) batch with given serial is finished.
angle::Result finishToSerial(vk::Context *context, Serial serial);
// A variant of finishToSerial that can time out. Timeout status returned in outTimedOut.
angle::Result finishToSerialOrTimeout(vk::Context *context,
Serial serial,
uint64_t timeout,
bool *outTimedOut);
uint32_t getQueueFamilyIndex() const { return mCurrentQueueFamilyIndex; }
const vk::MemoryProperties &getMemoryProperties() const { return mMemoryProperties; }
// TODO(jmadill): We could pass angle::FormatID here.
const vk::Format &getFormat(GLenum internalFormat) const
{
return mFormatTable[internalFormat];
}
const vk::Format &getFormat(angle::FormatID formatID) const { return mFormatTable[formatID]; }
angle::Result getCompatibleRenderPass(vk::Context *context,
const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut);
angle::Result getRenderPassWithOps(vk::Context *context,
const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &ops,
vk::RenderPass **renderPassOut);
// Queries the descriptor set layout cache. Creates the layout if not present.
angle::Result getDescriptorSetLayout(
vk::Context *context,
const vk::DescriptorSetLayoutDesc &desc,
vk::BindingPointer<vk::DescriptorSetLayout> *descriptorSetLayoutOut);
// Queries the pipeline layout cache. Creates the layout if not present.
angle::Result getPipelineLayout(vk::Context *context,
const vk::PipelineLayoutDesc &desc,
const vk::DescriptorSetLayoutPointerArray &descriptorSetLayouts,
vk::BindingPointer<vk::PipelineLayout> *pipelineLayoutOut);
angle::Result syncPipelineCacheVk(DisplayVk *displayVk);
vk::DynamicSemaphorePool *getDynamicSemaphorePool() { return &mSubmitSemaphorePool; }
// Request a semaphore, that is expected to be signaled externally. The next submission will
// wait on it.
angle::Result allocateSubmitWaitSemaphore(vk::Context *context,
const vk::Semaphore **outSemaphore);
// Get the last signaled semaphore to wait on externally. The semaphore will not be waited on
// by next submission.
const vk::Semaphore *getSubmitLastSignaledSemaphore(vk::Context *context);
// This should only be called from ResourceVk.
// TODO(jmadill): Keep in ContextVk to enable threaded rendering.
vk::CommandGraph *getCommandGraph();
// Issues a new serial for linked shader modules. Used in the pipeline cache.
Serial issueShaderSerial();
vk::ShaderLibrary &getShaderLibrary() { return mShaderLibrary; }
UtilsVk &getUtils() { return mUtils; }
const angle::FeaturesVk &getFeatures() const
{
ASSERT(mFeaturesInitialized);
return mFeatures;
}
angle::Result getTimestamp(vk::Context *context, uint64_t *timestampOut);
// Create Begin/End/Instant GPU trace events, which take their timestamps from GPU queries.
// The events are queued until the query results are available. Possible values for `phase`
// are TRACE_EVENT_PHASE_*
ANGLE_INLINE angle::Result traceGpuEvent(vk::Context *context,
vk::CommandBuffer *commandBuffer,
char phase,
const char *name)
{
if (mGpuEventsEnabled)
return traceGpuEventImpl(context, commandBuffer, phase, name);
return angle::Result::Continue;
}
bool isMockICDEnabled() const { return mEnableMockICD; }
RenderPassCache &getRenderPassCache() { return mRenderPassCache; }
const vk::PipelineCache &getPipelineCache() const { return mPipelineCache; }
// Query the format properties for select bits (linearTilingFeatures, optimalTilingFeatures and
// bufferFeatures). Looks through mandatory features first, and falls back to querying the
// device (first time only).
bool hasLinearTextureFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
bool hasTextureFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
bool hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
static constexpr size_t kMaxExtensionNames = 200;
using ExtensionNameList = angle::FixedVector<const char *, kMaxExtensionNames>;
private:
// Number of semaphores for external entities to renderer to issue a wait, such as surface's
// image acquire.
static constexpr size_t kMaxExternalSemaphores = 64;
// Total possible number of semaphores a submission can wait on. +1 is for the semaphore
// signaled in the last submission.
static constexpr size_t kMaxWaitSemaphores = kMaxExternalSemaphores + 1;
angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex);
void ensureCapsInitialized() const;
void getSubmitWaitSemaphores(
vk::Context *context,
angle::FixedVector<VkSemaphore, kMaxWaitSemaphores> *waitSemaphores,
angle::FixedVector<VkPipelineStageFlags, kMaxWaitSemaphores> *waitStageMasks);
angle::Result submitFrame(vk::Context *context,
const VkSubmitInfo &submitInfo,
vk::CommandBuffer &&commandBuffer);
void freeAllInFlightResources();
angle::Result flushCommandGraph(vk::Context *context, vk::CommandBuffer *commandBatch);
void initFeatures(const ExtensionNameList &extensions);
void initPipelineCacheVkKey();
angle::Result initPipelineCache(DisplayVk *display);
angle::Result synchronizeCpuGpuTime(vk::Context *context);
angle::Result traceGpuEventImpl(vk::Context *context,
vk::CommandBuffer *commandBuffer,
char phase,
const char *name);
angle::Result checkCompletedGpuEvents(vk::Context *context);
void flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpuTimestampS);
template <VkFormatFeatureFlags VkFormatProperties::*features>
bool hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
void nextSerial();
egl::Display *mDisplay;
mutable bool mCapsInitialized;
mutable gl::Caps mNativeCaps;
mutable gl::TextureCapsMap mNativeTextureCaps;
mutable gl::Extensions mNativeExtensions;
mutable gl::Limitations mNativeLimitations;
mutable bool mFeaturesInitialized;
mutable angle::FeaturesVk mFeatures;
VkInstance mInstance;
bool mEnableValidationLayers;
bool mEnableMockICD;
VkDebugUtilsMessengerEXT mDebugUtilsMessenger;
VkDebugReportCallbackEXT mDebugReportCallback;
VkPhysicalDevice mPhysicalDevice;
VkPhysicalDeviceProperties mPhysicalDeviceProperties;
VkPhysicalDeviceFeatures mPhysicalDeviceFeatures;
std::vector<VkQueueFamilyProperties> mQueueFamilyProperties;
VkQueue mQueue;
uint32_t mCurrentQueueFamilyIndex;
uint32_t mMaxVertexAttribDivisor;
VkDevice mDevice;
vk::CommandPool mCommandPool;
SerialFactory mQueueSerialFactory;
SerialFactory mShaderSerialFactory;
Serial mLastCompletedQueueSerial;
Serial mLastSubmittedQueueSerial;
Serial mCurrentQueueSerial;
bool mDeviceLost;
struct CommandBatch final : angle::NonCopyable
{
CommandBatch();
~CommandBatch();
CommandBatch(CommandBatch &&other);
CommandBatch &operator=(CommandBatch &&other);
void destroy(VkDevice device);
vk::CommandPool commandPool;
vk::Fence fence;
Serial serial;
};
std::vector<CommandBatch> mInFlightCommands;
std::vector<vk::GarbageObject> mGarbage;
vk::MemoryProperties mMemoryProperties;
vk::FormatTable mFormatTable;
RenderPassCache mRenderPassCache;
vk::PipelineCache mPipelineCache;
egl::BlobCache::Key mPipelineCacheVkBlobKey;
uint32_t mPipelineCacheVkUpdateTimeout;
// A cache of VkFormatProperties as queried from the device over time.
std::array<VkFormatProperties, vk::kNumVkFormats> mFormatProperties;
// mSubmitWaitSemaphores is a list of specifically requested semaphores to be waited on before a
// command buffer submission, for example, semaphores signaled by vkAcquireNextImageKHR.
// After first use, the list is automatically cleared. This is a vector to support concurrent
// rendering to multiple surfaces.
//
// Note that with multiple contexts present, this may result in a context waiting on image
// acquisition even if it doesn't render to that surface. If CommandGraphs are separated by
// context or share group for example, this could be moved to the one that actually uses the
// image.
angle::FixedVector<vk::SemaphoreHelper, kMaxExternalSemaphores> mSubmitWaitSemaphores;
// mSubmitLastSignaledSemaphore shows which semaphore was last signaled by submission. This can
// be set to nullptr if retrieved to be waited on outside RendererVk, such
// as by the surface before presentation. Each submission waits on the
// previously signaled semaphore (as well as any in mSubmitWaitSemaphores)
// and allocates a new semaphore to signal.
vk::SemaphoreHelper mSubmitLastSignaledSemaphore;
// A pool of semaphores used to support the aforementioned mid-frame submissions.
vk::DynamicSemaphorePool mSubmitSemaphorePool;
// See CommandGraph.h for a desription of the Command Graph.
vk::CommandGraph mCommandGraph;
// ANGLE uses a PipelineLayout cache to store compatible pipeline layouts.
PipelineLayoutCache mPipelineLayoutCache;
// DescriptorSetLayouts are also managed in a cache.
DescriptorSetLayoutCache mDescriptorSetLayoutCache;
// Internal shader library.
vk::ShaderLibrary mShaderLibrary;
UtilsVk mUtils;
// The GpuEventQuery struct holds together a timestamp query and enough data to create a
// trace event based on that. Use traceGpuEvent to insert such queries. They will be readback
// when the results are available, without inserting a GPU bubble.
//
// - eventName will be the reported name of the event
// - phase is either 'B' (duration begin), 'E' (duration end) or 'i' (instant // event).
// See Google's "Trace Event Format":
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU
// - serial is the serial of the batch the query was submitted on. Until the batch is
// submitted, the query is not checked to avoid incuring a flush.
struct GpuEventQuery final
{
const char *name;
char phase;
uint32_t queryIndex;
size_t queryPoolIndex;
Serial serial;
};
// Once a query result is available, the timestamp is read and a GpuEvent object is kept until
// the next clock sync, at which point the clock drift is compensated in the results before
// handing them off to the application.
struct GpuEvent final
{
uint64_t gpuTimestampCycles;
const char *name;
char phase;
};
bool mGpuEventsEnabled;
vk::DynamicQueryPool mGpuEventQueryPool;
// A list of queries that have yet to be turned into an event (their result is not yet
// available).
std::vector<GpuEventQuery> mInFlightGpuEventQueries;
// A list of gpu events since the last clock sync.
std::vector<GpuEvent> mGpuEvents;
// Hold information from the last gpu clock sync for future gpu-to-cpu timestamp conversions.
struct GpuClockSyncInfo
{
double gpuTimestampS;
double cpuTimestampS;
};
GpuClockSyncInfo mGpuClockSync;
// The very first timestamp queried for a GPU event is used as origin, so event timestamps would
// have a value close to zero, to avoid losing 12 bits when converting these 64 bit values to
// double.
uint64_t mGpuEventTimestampOrigin;
};
uint32_t GetUniformBufferDescriptorCount();
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_