vulkan: refactor debug defines (#7170)
Add more fine grain debug defines and add some systrace markers.
This commit is contained in:
@@ -28,8 +28,6 @@
|
||||
|
||||
#include "generated/vkshaders/vkshaders.h"
|
||||
|
||||
#define FILAMENT_VULKAN_CHECK_BLIT_FORMAT 0
|
||||
|
||||
using namespace bluevk;
|
||||
using namespace utils;
|
||||
|
||||
@@ -69,7 +67,7 @@ inline void blitFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect,
|
||||
.layerCount = 1,
|
||||
};
|
||||
|
||||
if constexpr (FILAMENT_VULKAN_VERBOSE) {
|
||||
if constexpr (FVK_ENABLED(FVK_DEBUG_BLITTER)) {
|
||||
utils::slog.d << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
|
||||
<< "layout=" << src.getLayout()
|
||||
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
|
||||
@@ -132,7 +130,7 @@ void VulkanBlitter::blitColor(BlitArgs args) {
|
||||
const VulkanAttachment dst = args.dstTarget->getColor(0);
|
||||
const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
||||
#if FILAMENT_VULKAN_CHECK_BLIT_FORMAT
|
||||
#if FVK_ENABLED(FVK_DEBUG_BLIT_FORMAT)
|
||||
VkPhysicalDevice const gpu = mPhysicalDevice;
|
||||
VkFormatProperties info;
|
||||
vkGetPhysicalDeviceFormatProperties(gpu, src.getFormat(), &info);
|
||||
@@ -160,7 +158,7 @@ void VulkanBlitter::blitDepth(BlitArgs args) {
|
||||
const VulkanAttachment dst = args.dstTarget->getDepth();
|
||||
const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
|
||||
#if FILAMENT_VULKAN_CHECK_BLIT_FORMAT
|
||||
#if FVK_ENABLED(FVK_DEBUG_BLIT_FORMAT)
|
||||
VkPhysicalDevice const gpu = mPhysicalDevice;
|
||||
VkFormatProperties info;
|
||||
vkGetPhysicalDeviceFormatProperties(gpu, src.getFormat(), &info);
|
||||
@@ -241,7 +239,7 @@ void VulkanBlitter::lazyInit() noexcept {
|
||||
mDepthResolveProgram->samplerGroupInfo[0].samplers.reserve(1);
|
||||
mDepthResolveProgram->samplerGroupInfo[0].samplers.resize(1);
|
||||
|
||||
if constexpr (FILAMENT_VULKAN_VERBOSE) {
|
||||
if constexpr (FVK_ENABLED(FVK_DEBUG_BLITTER)) {
|
||||
utils::slog.d << "Created Shader Module for VulkanBlitter "
|
||||
<< "shaders = (" << vertexShader << ", " << fragmentShader << ")"
|
||||
<< utils::io::endl;
|
||||
|
||||
@@ -33,7 +33,9 @@ using namespace utils;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
using Timestamp = VulkanGroupMarkers::Timestamp;
|
||||
#endif
|
||||
|
||||
VulkanCmdFence::VulkanCmdFence(VkFence ifence)
|
||||
: fence(ifence) {
|
||||
@@ -63,20 +65,21 @@ CommandBufferObserver::~CommandBufferObserver() {}
|
||||
|
||||
static VkCommandPool createPool(VkDevice device, uint32_t queueFamilyIndex) {
|
||||
VkCommandPoolCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags =
|
||||
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
||||
.queueFamilyIndex = queueFamilyIndex,
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
|
||||
| VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
||||
.queueFamilyIndex = queueFamilyIndex,
|
||||
};
|
||||
VkCommandPool pool;
|
||||
vkCreateCommandPool(device, &createInfo, VKALLOC, &pool);
|
||||
return pool;
|
||||
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
void VulkanGroupMarkers::push(std::string const& marker, Timestamp start) noexcept {
|
||||
mMarkers.push_back(marker);
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS)
|
||||
mTimestamps.push_back(start.time_since_epoch().count() > 0.0
|
||||
? start
|
||||
: std::chrono::high_resolution_clock::now());
|
||||
@@ -87,7 +90,7 @@ std::pair<std::string, Timestamp> VulkanGroupMarkers::pop() noexcept {
|
||||
auto const marker = mMarkers.back();
|
||||
mMarkers.pop_back();
|
||||
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS)
|
||||
auto const timestamp = mTimestamps.back();
|
||||
mTimestamps.pop_back();
|
||||
return std::make_pair(marker, timestamp);
|
||||
@@ -100,7 +103,7 @@ std::pair<std::string, Timestamp> VulkanGroupMarkers::pop_bottom() noexcept {
|
||||
auto const marker = mMarkers.front();
|
||||
mMarkers.pop_front();
|
||||
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS)
|
||||
auto const timestamp = mTimestamps.front();
|
||||
mTimestamps.pop_front();
|
||||
return std::make_pair(marker, timestamp);
|
||||
@@ -112,7 +115,7 @@ std::pair<std::string, Timestamp> VulkanGroupMarkers::pop_bottom() noexcept {
|
||||
std::pair<std::string, Timestamp> VulkanGroupMarkers::top() const {
|
||||
assert_invariant(!empty());
|
||||
auto const marker = mMarkers.back();
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS)
|
||||
auto const topTimestamp = mTimestamps.front();
|
||||
return std::make_pair(marker, topTimestamp);
|
||||
#else
|
||||
@@ -124,6 +127,8 @@ bool VulkanGroupMarkers::empty() const noexcept {
|
||||
return mMarkers.empty();
|
||||
}
|
||||
|
||||
#endif // FVK_DEBUG_GROUP_MARKERS
|
||||
|
||||
VulkanCommands::VulkanCommands(VkDevice device, VkQueue queue, uint32_t queueFamilyIndex,
|
||||
VulkanContext* context, VulkanResourceAllocator* allocator)
|
||||
: mDevice(device),
|
||||
@@ -144,6 +149,10 @@ VulkanCommands::VulkanCommands(VkDevice device, VkQueue queue, uint32_t queueFam
|
||||
for (size_t i = 0; i < CAPACITY; ++i) {
|
||||
mStorage[i] = std::make_unique<VulkanCommandBuffer>(allocator, mDevice, mPool);
|
||||
}
|
||||
|
||||
#if !FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
(void) mContext;
|
||||
#endif
|
||||
}
|
||||
|
||||
VulkanCommands::~VulkanCommands() {
|
||||
@@ -167,7 +176,7 @@ VulkanCommandBuffer& VulkanCommands::get() {
|
||||
// It occurs only when Filament invokes commit() or endFrame() a large number of times without
|
||||
// presenting the swap chain or waiting on a fence.
|
||||
while (mAvailableBufferCount == 0) {
|
||||
#if VK_REPORT_STALLS
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "VulkanCommands has stalled. "
|
||||
<< "If this occurs frequently, consider increasing VK_MAX_COMMAND_BUFFERS."
|
||||
<< io::endl;
|
||||
@@ -207,12 +216,14 @@ VulkanCommandBuffer& VulkanCommands::get() {
|
||||
mObserver->onCommandBuffer(*currentbuf);
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
// We push the current markers onto a temporary stack. This must be placed after currentbuf is
|
||||
// set to the new command buffer since pushGroupMarker also calls get().
|
||||
while (mCarriedOverMarkers && !mCarriedOverMarkers->empty()) {
|
||||
auto [marker, time] = mCarriedOverMarkers->pop();
|
||||
pushGroupMarker(marker.c_str(), time);
|
||||
}
|
||||
#endif
|
||||
return *currentbuf;
|
||||
}
|
||||
|
||||
@@ -224,6 +235,7 @@ bool VulkanCommands::flush() {
|
||||
|
||||
// Before actually submitting, we need to pop any leftover group markers.
|
||||
// Note that this needs to occur before vkEndCommandBuffer.
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
while (mGroupMarkers && !mGroupMarkers->empty()) {
|
||||
if (!mCarriedOverMarkers) {
|
||||
mCarriedOverMarkers = std::make_unique<VulkanGroupMarkers>();
|
||||
@@ -233,7 +245,7 @@ bool VulkanCommands::flush() {
|
||||
// We still need to call through to vkCmdEndDebugUtilsLabelEXT.
|
||||
popGroupMarker();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int8_t const index = mCurrentCommandBufferIndex;
|
||||
VulkanCommandBuffer const* currentbuf = mStorage[index].get();
|
||||
@@ -283,7 +295,7 @@ bool VulkanCommands::flush() {
|
||||
submitInfo.pWaitSemaphores = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "Submitting cmdbuffer=" << cmdbuffer
|
||||
<< " wait=(" << signals[0] << ", " << signals[1] << ") "
|
||||
<< " signal=" << renderingFinished
|
||||
@@ -297,7 +309,7 @@ bool VulkanCommands::flush() {
|
||||
cmdfence->condition.notify_all();
|
||||
lock.unlock();
|
||||
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
if (result != VK_SUCCESS) {
|
||||
utils::slog.d << "Failed command buffer submission result: " << result << utils::io::endl;
|
||||
}
|
||||
@@ -313,8 +325,8 @@ bool VulkanCommands::flush() {
|
||||
VkSemaphore VulkanCommands::acquireFinishedSignal() {
|
||||
VkSemaphore semaphore = mSubmissionSignal;
|
||||
mSubmissionSignal = VK_NULL_HANDLE;
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
slog.i << "Acquiring " << semaphore << " (e.g. for vkQueuePresentKHR)" << io::endl;
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "Acquiring " << semaphore << " (e.g. for vkQueuePresentKHR)" << io::endl;
|
||||
#endif
|
||||
return semaphore;
|
||||
}
|
||||
@@ -322,7 +334,7 @@ VkSemaphore VulkanCommands::acquireFinishedSignal() {
|
||||
void VulkanCommands::injectDependency(VkSemaphore next) {
|
||||
assert_invariant(mInjectedSignal == VK_NULL_HANDLE);
|
||||
mInjectedSignal = next;
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "Injecting " << next << " (e.g. due to vkAcquireNextImageKHR)" << io::endl;
|
||||
#endif
|
||||
}
|
||||
@@ -344,6 +356,9 @@ void VulkanCommands::wait() {
|
||||
}
|
||||
|
||||
void VulkanCommands::gc() {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("commands::gc");
|
||||
|
||||
VkFence fences[CAPACITY];
|
||||
size_t count = 0;
|
||||
|
||||
@@ -365,6 +380,7 @@ void VulkanCommands::gc() {
|
||||
if (count > 0) {
|
||||
vkResetFences(mDevice, count, fences);
|
||||
}
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanCommands::updateFences() {
|
||||
@@ -381,8 +397,10 @@ void VulkanCommands::updateFences() {
|
||||
}
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
|
||||
void VulkanCommands::pushGroupMarker(char const* str, VulkanGroupMarkers::Timestamp timestamp) {
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS)
|
||||
// If the timestamp is not 0, then we are carrying over a marker across buffer submits.
|
||||
// If it is 0, then this is a normal marker push and we should just print debug line as usual.
|
||||
if (timestamp.time_since_epoch().count() == 0.0) {
|
||||
@@ -420,7 +438,7 @@ void VulkanCommands::popGroupMarker() {
|
||||
|
||||
if (!mGroupMarkers->empty()) {
|
||||
VkCommandBuffer const cmdbuffer = get().buffer();
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS)
|
||||
auto const [marker, startTime] = mGroupMarkers->pop();
|
||||
auto const endTime = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> diff = endTime - startTime;
|
||||
@@ -429,7 +447,6 @@ void VulkanCommands::popGroupMarker() {
|
||||
#else
|
||||
mGroupMarkers->pop();
|
||||
#endif
|
||||
|
||||
if (mContext->isDebugUtilsSupported()) {
|
||||
vkCmdEndDebugUtilsLabelEXT(cmdbuffer);
|
||||
} else if (mContext->isDebugMarkersSupported()) {
|
||||
@@ -468,8 +485,9 @@ std::string VulkanCommands::getTopGroupMarker() const {
|
||||
}
|
||||
return std::get<0>(mGroupMarkers->top());
|
||||
}
|
||||
#endif // FVK_DEBUG_GROUP_MARKERS
|
||||
|
||||
}// namespace filament::backend
|
||||
} // namespace filament::backend
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning( pop )
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace filament::backend {
|
||||
|
||||
struct VulkanContext;
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
class VulkanGroupMarkers {
|
||||
public:
|
||||
using Timestamp = std::chrono::time_point<std::chrono::high_resolution_clock>;
|
||||
@@ -51,11 +52,13 @@ public:
|
||||
|
||||
private:
|
||||
std::list<std::string> mMarkers;
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS)
|
||||
std::list<Timestamp> mTimestamps;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // FVK_DEBUG_GROUP_MARKERS
|
||||
|
||||
// Wrapper to enable use of shared_ptr for implementing shared ownership of low-level Vulkan fences.
|
||||
struct VulkanCmdFence {
|
||||
VulkanCmdFence(VkFence ifence);
|
||||
@@ -170,6 +173,7 @@ class VulkanCommands {
|
||||
// The observer's event handler can only be called during get().
|
||||
void setObserver(CommandBufferObserver* observer) { mObserver = observer; }
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
void pushGroupMarker(char const* str, VulkanGroupMarkers::Timestamp timestamp = {});
|
||||
|
||||
void popGroupMarker();
|
||||
@@ -177,9 +181,10 @@ class VulkanCommands {
|
||||
void insertEventMarker(char const* string, uint32_t len);
|
||||
|
||||
std::string getTopGroupMarker() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
static constexpr int CAPACITY = VK_MAX_COMMAND_BUFFERS;
|
||||
static constexpr int CAPACITY = FVK_MAX_COMMAND_BUFFERS;
|
||||
VkDevice const mDevice;
|
||||
VkQueue const mQueue;
|
||||
VkCommandPool const mPool;
|
||||
@@ -196,8 +201,10 @@ class VulkanCommands {
|
||||
uint8_t mAvailableBufferCount = CAPACITY;
|
||||
CommandBufferObserver* mObserver = nullptr;
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
std::unique_ptr<VulkanGroupMarkers> mGroupMarkers;
|
||||
std::unique_ptr<VulkanGroupMarkers> mCarriedOverMarkers;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -19,13 +19,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define FILAMENT_VULKAN_VERBOSE 0
|
||||
#define FILAMENT_VULKAN_DUMP_API 0
|
||||
|
||||
#ifndef FILAMENT_VULKAN_HANDLE_ARENA_SIZE_IN_MB
|
||||
#define FILAMENT_VULKAN_HANDLE_ARENA_SIZE_IN_MB 8
|
||||
#endif
|
||||
|
||||
// In debug builds, we enable validation layers and set up a debug callback.
|
||||
//
|
||||
// To enable validation layers in Android, also be sure to set the jniLibs property in the gradle
|
||||
@@ -43,21 +36,80 @@
|
||||
// ndkVersion "23.1.7779620"
|
||||
//
|
||||
// Also consider changing the root `gradle.properties` to point to a debug build, although this is
|
||||
// not required for validation if you change the definition of VK_ENABLE_VALIDATION below.
|
||||
#if defined(NDEBUG)
|
||||
#define VK_ENABLE_VALIDATION 0
|
||||
// not required for validation.
|
||||
|
||||
// FVK is short for Filament Vulkan
|
||||
#define FVK_DEBUG_SYSTRACE 0x00000001
|
||||
#define FVK_DEBUG_GROUP_MARKERS 0x00000002
|
||||
#define FVK_DEBUG_TEXTURE 0x00000004
|
||||
#define FVK_DEBUG_LAYOUT_TRANSITION 0x00000008
|
||||
#define FVK_DEBUG_COMMAND_BUFFER 0x00000010
|
||||
#define FVK_DEBUG_DUMP_API 0x00000020
|
||||
#define FVK_DEBUG_VALIDATION 0x00000040
|
||||
#define FVK_DEBUG_PRINT_GROUP_MARKERS 0x00000080
|
||||
#define FVK_DEBUG_BLIT_FORMAT 0x00000100
|
||||
#define FVK_DEBUG_BLITTER 0x00000200
|
||||
#define FVK_DEBUG_FBO_CACHE 0x00000400
|
||||
#define FVK_DEBUG_SHADER_MODULE 0x00000800
|
||||
#define FVK_DEBUG_READ_PIXELS 0x00001000
|
||||
#define FVK_DEBUG_PIPELINE_CACHE 0x00002000
|
||||
#define FVK_DEBUG_ALLOCATION 0x00004000
|
||||
|
||||
// Usefaul default combinations
|
||||
#define FVK_DEBUG_EVERYTHING 0xFFFFFFFF
|
||||
#define FVK_DEBUG_PERFORMANCE \
|
||||
FVK_DEBUG_SYSTRACE | \
|
||||
FVK_DEBUG_GROUP_MARKERS
|
||||
|
||||
#define FVK_DEBUG_CORRECTNESS \
|
||||
FVK_DEBUG_VALIDATION | \
|
||||
FVK_DEBUG_SHADER_MODULE | \
|
||||
FVK_DEBUG_TEXTURE | \
|
||||
FVK_DEBUG_LAYOUT_TRANSITION
|
||||
|
||||
#define FVK_DEBUG_RENDER_PASSES \
|
||||
FVK_DEBUG_GROUP_MARKERS | \
|
||||
FVK_DEBUG_PRINT_GROUP_MARKERS
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define FVK_DEBUG_FLAGS FVK_DEBUG_PERFORMANCE
|
||||
#else
|
||||
#define VK_ENABLE_VALIDATION 1
|
||||
#define FVK_DEBUG_FLAGS 0
|
||||
#endif
|
||||
|
||||
#define VK_REPORT_STALLS 0
|
||||
#define FVK_ENABLED(flags) ((FVK_DEBUG_FLAGS) & (flags))
|
||||
#define FVK_ENABLED_BOOL(flags) ((bool) FVK_ENABLED(flags))
|
||||
|
||||
// Ensure dependencies are met between debug options
|
||||
#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS)
|
||||
static_assert(FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS));
|
||||
#endif
|
||||
|
||||
// end dependcy checks
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_SYSTRACE)
|
||||
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#define FVK_SYSTRACE_CONTEXT() SYSTRACE_CONTEXT()
|
||||
#define FVK_SYSTRACE_START(marker) SYSTRACE_NAME_BEGIN(marker)
|
||||
#define FVK_SYSTRACE_END() SYSTRACE_NAME_END()
|
||||
#else
|
||||
#define FVK_SYSTRACE_CONTEXT()
|
||||
#define FVK_SYSTRACE_START(marker)
|
||||
#define FVK_SYSTRACE_END()
|
||||
#endif
|
||||
|
||||
#ifndef FVK_HANDLE_ARENA_SIZE_IN_MB
|
||||
#define FVK_HANDLE_ARENA_SIZE_IN_MB 8
|
||||
#endif
|
||||
|
||||
// All vkCreate* functions take an optional allocator. For now we select the default allocator by
|
||||
// passing in a null pointer, and we highlight the argument by using the VKALLOC constant.
|
||||
constexpr struct VkAllocationCallbacks* VKALLOC = nullptr;
|
||||
|
||||
constexpr static const int VK_REQUIRED_VERSION_MAJOR = 1;
|
||||
constexpr static const int VK_REQUIRED_VERSION_MINOR = 1;
|
||||
constexpr static const int FVK_REQUIRED_VERSION_MAJOR = 1;
|
||||
constexpr static const int FVK_REQUIRED_VERSION_MINOR = 1;
|
||||
|
||||
// Maximum number of VkCommandBuffer handles managed simultaneously by VulkanCommands.
|
||||
//
|
||||
@@ -65,18 +117,18 @@ constexpr static const int VK_REQUIRED_VERSION_MINOR = 1;
|
||||
// buffers that have been submitted but have not yet finished rendering. Note that Filament can
|
||||
// issue multiple commit calls in a single frame, and that we use a triple buffered swap chain on
|
||||
// some platforms.
|
||||
constexpr static const int VK_MAX_COMMAND_BUFFERS = 10;
|
||||
constexpr static const int FVK_MAX_COMMAND_BUFFERS = 10;
|
||||
|
||||
// Number of command buffer submissions that should occur before an unused pipeline is removed
|
||||
// from the cache.
|
||||
//
|
||||
// If this number is low, VkPipeline construction will occur frequently, which can
|
||||
// be extremely slow. If this number is high, the memory footprint will be large.
|
||||
constexpr static const int VK_MAX_PIPELINE_AGE = 10;
|
||||
constexpr static const int FVK_MAX_PIPELINE_AGE = 10;
|
||||
|
||||
// VulkanPipelineCache does not track which command buffers contain references to which pipelines,
|
||||
// instead it simply waits for at least VK_MAX_COMMAND_BUFFERS submissions to occur before
|
||||
// instead it simply waits for at least FVK_MAX_COMMAND_BUFFERS submissions to occur before
|
||||
// destroying any unused pipeline object.
|
||||
static_assert(VK_MAX_PIPELINE_AGE >= VK_MAX_COMMAND_BUFFERS);
|
||||
static_assert(FVK_MAX_PIPELINE_AGE >= FVK_MAX_COMMAND_BUFFERS);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,10 +30,9 @@
|
||||
#include <utils/CString.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <set>
|
||||
#include <set> // For VulkanDriver::debugCommandBegin
|
||||
#endif
|
||||
|
||||
using namespace bluevk;
|
||||
@@ -101,7 +100,7 @@ VulkanTexture* createEmptyTexture(VkDevice device, VkPhysicalDevice physicalDevi
|
||||
return emptyTexture;
|
||||
}
|
||||
|
||||
#if VK_ENABLE_VALIDATION
|
||||
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallback(VkDebugReportFlagsEXT flags,
|
||||
VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location,
|
||||
int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) {
|
||||
@@ -136,7 +135,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsCallback(VkDebugUtilsMessageSeverityFla
|
||||
utils::slog.e << utils::io::endl;
|
||||
return VK_FALSE;
|
||||
}
|
||||
#endif// VK_ENABLE_VALIDATION
|
||||
#endif // FVK_EANBLED(FVK_DEBUG_VALIDATION)
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
@@ -159,7 +158,7 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
|
||||
mBlitter(mStagePool, mPipelineCache, mFramebufferCache, mSamplerCache),
|
||||
mReadPixels(mPlatform->getDevice()) {
|
||||
|
||||
#if VK_ENABLE_VALIDATION
|
||||
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
|
||||
UTILS_UNUSED const PFN_vkCreateDebugReportCallbackEXT createDebugReportCallback
|
||||
= vkCreateDebugReportCallbackEXT;
|
||||
VkResult result;
|
||||
@@ -214,7 +213,7 @@ UTILS_NOINLINE
|
||||
Driver* VulkanDriver::create(VulkanPlatform* platform, VulkanContext const& context,
|
||||
Platform::DriverConfig const& driverConfig) noexcept {
|
||||
assert_invariant(platform);
|
||||
size_t defaultSize = FILAMENT_VULKAN_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
||||
size_t defaultSize = FVK_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
||||
Platform::DriverConfig validConfig{
|
||||
.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize)};
|
||||
return new VulkanDriver(platform, context, validConfig);
|
||||
@@ -266,24 +265,15 @@ void VulkanDriver::tick(int) {
|
||||
// rather than the wall clock, because we must wait 3 frames after a DriverAPI-level resource has
|
||||
// been destroyed for safe destruction, due to outstanding command buffers and triple buffering.
|
||||
void VulkanDriver::collectGarbage() {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("gc");
|
||||
// Command buffers need to be submitted and completed before other resources can be gc'd. And
|
||||
// its gc() function carrys out the *wait*.
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_NAME_BEGIN("gc");
|
||||
|
||||
mCommands->gc();
|
||||
|
||||
SYSTRACE_NAME_BEGIN("stagepool-gc");
|
||||
mStagePool.gc();
|
||||
SYSTRACE_NAME_END();
|
||||
|
||||
SYSTRACE_NAME_BEGIN("framebuffercache-gc");
|
||||
mFramebufferCache.gc();
|
||||
SYSTRACE_NAME_END();
|
||||
|
||||
SYSTRACE_NAME_END(); // "gc"
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) {
|
||||
// Do nothing.
|
||||
}
|
||||
@@ -306,14 +296,21 @@ void VulkanDriver::endFrame(uint32_t frameId) {
|
||||
}
|
||||
|
||||
void VulkanDriver::flush(int) {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("flush");
|
||||
mCommands->flush();
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanDriver::finish(int dummy) {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("finish");
|
||||
|
||||
mCommands->flush();
|
||||
mCommands->wait();
|
||||
|
||||
mReadPixels.runUntilComplete();
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanDriver::createSamplerGroupR(Handle<HwSamplerGroup> sbh, uint32_t count) {
|
||||
@@ -990,6 +987,9 @@ void VulkanDriver::compilePrograms(CompilerPriorityQueue priority,
|
||||
}
|
||||
|
||||
void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassParams& params) {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("beginRenderPass");
|
||||
|
||||
VulkanRenderTarget* const rt = mResourceAllocator.handle_cast<VulkanRenderTarget*>(rth);
|
||||
const VkExtent2D extent = rt->getExtent();
|
||||
assert_invariant(extent.width > 0 && extent.height > 0);
|
||||
@@ -1008,7 +1008,8 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
}
|
||||
|
||||
VulkanAttachment depth = rt->getSamples() == 1 ? rt->getDepth() : rt->getMsaaDepth();
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||
if (depth.texture) {
|
||||
depth.texture->print();
|
||||
}
|
||||
@@ -1153,6 +1154,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
VkFramebuffer vkfb = mFramebufferCache.getFramebuffer(fbkey);
|
||||
|
||||
// Assign a label to the framebuffer for debugging purposes.
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
if (UTILS_UNLIKELY(mContext.isDebugUtilsSupported())) {
|
||||
auto const topMarker = mCommands->getTopGroupMarker();
|
||||
if (!topMarker.empty()) {
|
||||
@@ -1166,6 +1168,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
vkSetDebugUtilsObjectNameEXT(mPlatform->getDevice(), &info);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// The current command buffer now owns a reference to the render target and its attachments.
|
||||
// Note that we must acquire parent textures, not sidecars.
|
||||
@@ -1242,9 +1245,13 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
.params = params,
|
||||
.currentSubpass = 0,
|
||||
};
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanDriver::endRenderPass(int) {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("endRenderPass");
|
||||
|
||||
VulkanCommandBuffer& commands = mCommands->get();
|
||||
VkCommandBuffer cmdbuffer = commands.buffer();
|
||||
vkCmdEndRenderPass(cmdbuffer);
|
||||
@@ -1288,6 +1295,7 @@ void VulkanDriver::endRenderPass(int) {
|
||||
}
|
||||
mCurrentRenderPass.renderTarget = nullptr;
|
||||
mCurrentRenderPass.renderPass = VK_NULL_HANDLE;
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanDriver::nextSubpass(int) {
|
||||
@@ -1334,6 +1342,9 @@ void VulkanDriver::setRenderPrimitiveRange(Handle<HwRenderPrimitive> rph,
|
||||
}
|
||||
|
||||
void VulkanDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain> readSch) {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("makeCurrent");
|
||||
|
||||
ASSERT_PRECONDITION_NON_FATAL(drawSch == readSch,
|
||||
"Vulkan driver does not support distinct draw/read swap chains.");
|
||||
VulkanSwapChain* swapChain = mCurrentSwapChain
|
||||
@@ -1349,9 +1360,14 @@ void VulkanDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain>
|
||||
if (UTILS_LIKELY(mDefaultRenderTarget)) {
|
||||
mDefaultRenderTarget->bindToSwapChain(*swapChain);
|
||||
}
|
||||
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanDriver::commit(Handle<HwSwapChain> sch) {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("commit");
|
||||
|
||||
VulkanSwapChain* swapChain = mResourceAllocator.handle_cast<VulkanSwapChain*>(sch);
|
||||
|
||||
if (mCommands->flush()) {
|
||||
@@ -1360,6 +1376,7 @@ void VulkanDriver::commit(Handle<HwSwapChain> sch) {
|
||||
|
||||
// Present the backbuffer after the most recent command buffer submission has finished.
|
||||
swapChain->present();
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanDriver::bindUniformBuffer(uint32_t index, Handle<HwBufferObject> boh) {
|
||||
@@ -1391,24 +1408,26 @@ void VulkanDriver::bindSamplers(uint32_t index, Handle<HwSamplerGroup> sbh) {
|
||||
}
|
||||
|
||||
void VulkanDriver::insertEventMarker(char const* string, uint32_t len) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
mCommands->insertEventMarker(string, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void VulkanDriver::pushGroupMarker(char const* string, uint32_t) {
|
||||
// Turns out all the markers are 0-terminated, so we can just pass it without len.
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
mCommands->pushGroupMarker(string);
|
||||
{
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_NAME_BEGIN(string);
|
||||
}
|
||||
#endif
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START(string);
|
||||
}
|
||||
|
||||
void VulkanDriver::popGroupMarker(int) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
mCommands->popGroupMarker();
|
||||
{
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_NAME_END();
|
||||
}
|
||||
#endif
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanDriver::startCapture(int) {}
|
||||
@@ -1439,6 +1458,9 @@ void VulkanDriver::readBufferSubData(backend::BufferObjectHandle boh,
|
||||
|
||||
void VulkanDriver::blit(TargetBufferFlags buffers, Handle<HwRenderTarget> dst, Viewport dstRect,
|
||||
Handle<HwRenderTarget> src, Viewport srcRect, SamplerMagFilter filter) {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("blit");
|
||||
|
||||
assert_invariant(mCurrentRenderPass.renderPass == VK_NULL_HANDLE);
|
||||
|
||||
// blit operation only support COLOR0 color buffer
|
||||
@@ -1478,10 +1500,14 @@ void VulkanDriver::blit(TargetBufferFlags buffers, Handle<HwRenderTarget> dst, V
|
||||
if (any(buffers & TargetBufferFlags::COLOR0)) {
|
||||
mBlitter.blitColor({ dstTarget, dstOffsets, srcTarget, srcOffsets, vkfilter, int(0) });
|
||||
}
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> rph,
|
||||
const uint32_t instanceCount) {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("draw");
|
||||
|
||||
VulkanCommandBuffer* commands = &mCommands->get();
|
||||
VkCommandBuffer cmdbuffer = commands->buffer();
|
||||
const VulkanRenderPrimitive& prim = *mResourceAllocator.handle_cast<VulkanRenderPrimitive*>(rph);
|
||||
@@ -1497,7 +1523,7 @@ void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> r
|
||||
commands->acquire(prim.vertexBuffer);
|
||||
|
||||
// If this is a debug build, validate the current shader.
|
||||
#if !defined(NDEBUG)
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
if (program->bundle.vertex == VK_NULL_HANDLE || program->bundle.fragment == VK_NULL_HANDLE) {
|
||||
utils::slog.e << "Binding missing shader: " << program->name.c_str() << utils::io::endl;
|
||||
}
|
||||
@@ -1613,7 +1639,7 @@ void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> r
|
||||
// This fallback path is very flaky because the dummy texture might not have
|
||||
// matching characteristics. (e.g. if the missing texture is a 3D texture)
|
||||
if (UTILS_UNLIKELY(texture->getPrimaryImageLayout() == VulkanLayout::UNDEFINED)) {
|
||||
#ifndef NDEBUG
|
||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||
utils::slog.w << "Uninitialized texture bound to '" << sampler.name.c_str() << "'";
|
||||
utils::slog.w << " in material '" << program->name.c_str() << "'";
|
||||
utils::slog.w << " at binding point " << +sampler.binding << utils::io::endl;
|
||||
@@ -1687,6 +1713,7 @@ void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> r
|
||||
const uint32_t firstInstId = 0;
|
||||
|
||||
vkCmdDrawIndexed(cmdbuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstId);
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
// If any VkRenderPass or VkFramebuffer is unused for more than TIME_BEFORE_EVICTION frames, it
|
||||
// is evicted from the cache.
|
||||
static constexpr uint32_t TIME_BEFORE_EVICTION = VK_MAX_COMMAND_BUFFERS;
|
||||
static constexpr uint32_t TIME_BEFORE_EVICTION = FVK_MAX_COMMAND_BUFFERS;
|
||||
|
||||
using namespace bluevk;
|
||||
|
||||
@@ -97,7 +97,7 @@ VkFramebuffer VulkanFboCache::getFramebuffer(FboKey config) noexcept {
|
||||
attachments[attachmentCount++] = config.depth;
|
||||
}
|
||||
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_FBO_CACHE)
|
||||
utils::slog.d << "Creating framebuffer " << config.width << "x" << config.height << " "
|
||||
<< "for render pass " << config.renderPass << ", "
|
||||
<< "samples = " << int(config.samples) << ", "
|
||||
@@ -312,7 +312,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey config) noexcept {
|
||||
ASSERT_POSTCONDITION(!error, "Unable to create render pass.");
|
||||
mRenderPassCache[config] = {renderPass, mCurrentTime};
|
||||
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_FBO_CACHE)
|
||||
utils::slog.d << "Created render pass " << renderPass << " with "
|
||||
<< "samples = " << int(config.samples) << ", "
|
||||
<< "depth = " << (hasDepth ? 1 : 0) << ", "
|
||||
@@ -338,6 +338,9 @@ void VulkanFboCache::reset() noexcept {
|
||||
// Frees up old framebuffers and render passes, then nulls out their key. Doesn't bother removing
|
||||
// the actual map entry since it is fairly small.
|
||||
void VulkanFboCache::gc() noexcept {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("fbocache::gc");
|
||||
|
||||
// If this is one of the first few frames, return early to avoid wrapping unsigned integers.
|
||||
if (++mCurrentTime <= TIME_BEFORE_EVICTION) {
|
||||
return;
|
||||
@@ -359,6 +362,7 @@ void VulkanFboCache::gc() noexcept {
|
||||
iter.value().handle = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -114,10 +114,10 @@ VulkanProgram::VulkanProgram(VkDevice device, const Program& builder) noexcept
|
||||
|
||||
// Make a copy of the binding map
|
||||
samplerGroupInfo = builder.getSamplerGroupInfo();
|
||||
if constexpr (FILAMENT_VULKAN_VERBOSE) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
utils::slog.d << "Created VulkanProgram " << builder << ", shaders = (" << bundle.vertex
|
||||
<< ", " << bundle.fragment << ")" << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
VulkanProgram::VulkanProgram(VkDevice device, VkShaderModule vs, VkShaderModule fs) noexcept
|
||||
|
||||
@@ -218,7 +218,7 @@ bool operator<(const VkImageSubresourceRange& a, const VkImageSubresourceRange&
|
||||
return false;
|
||||
}
|
||||
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION | FVK_DEBUG_TEXTURE)
|
||||
#define CASE(VALUE) \
|
||||
case filament::backend::VulkanLayout::VALUE: { \
|
||||
out << #VALUE; \
|
||||
|
||||
@@ -481,10 +481,10 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
||||
|
||||
PipelineCacheEntry cacheEntry = {};
|
||||
|
||||
if constexpr (FILAMENT_VULKAN_VERBOSE) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
utils::slog.d << "vkCreateGraphicsPipelines with shaders = ("
|
||||
<< shaderStages[0].module << ", " << shaderStages[1].module << ")" << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
VkResult error = vkCreateGraphicsPipelines(mDevice, VK_NULL_HANDLE, 1, &pipelineCreateInfo,
|
||||
VKALLOC, &cacheEntry.handle);
|
||||
assert_invariant(error == VK_SUCCESS);
|
||||
@@ -681,7 +681,7 @@ void VulkanPipelineCache::terminate() noexcept {
|
||||
void VulkanPipelineCache::onCommandBuffer(const VulkanCommandBuffer& commands) {
|
||||
// The timestamp associated with a given cache entry represents "time" as a count of flush
|
||||
// events since the cache was constructed. If any cache entry was most recently used over
|
||||
// VK_MAX_PIPELINE_AGE flush events in the past, then we can be sure that it is no longer
|
||||
// FVK_MAX_PIPELINE_AGE flush events in the past, then we can be sure that it is no longer
|
||||
// being used by the GPU, and is therefore safe to destroy or reclaim.
|
||||
++mCurrentTime;
|
||||
|
||||
@@ -698,7 +698,7 @@ void VulkanPipelineCache::onCommandBuffer(const VulkanCommandBuffer& commands) {
|
||||
using ConstDescIterator = decltype(mDescriptorSets)::const_iterator;
|
||||
for (ConstDescIterator iter = mDescriptorSets.begin(); iter != mDescriptorSets.end();) {
|
||||
const DescriptorCacheEntry& cacheEntry = iter.value();
|
||||
if (cacheEntry.lastUsed + VK_MAX_PIPELINE_AGE < mCurrentTime) {
|
||||
if (cacheEntry.lastUsed + FVK_MAX_PIPELINE_AGE < mCurrentTime) {
|
||||
auto& arenas = mPipelineLayouts[cacheEntry.pipelineLayout].descriptorSetArenas;
|
||||
for (uint32_t i = 0; i < DESCRIPTOR_TYPE_COUNT; ++i) {
|
||||
arenas[i].push_back(cacheEntry.handles[i]);
|
||||
@@ -712,11 +712,11 @@ void VulkanPipelineCache::onCommandBuffer(const VulkanCommandBuffer& commands) {
|
||||
}
|
||||
|
||||
// Evict any pipelines that have not been used in a while.
|
||||
// Any pipeline older than VK_MAX_COMMAND_BUFFERS can be safely destroyed.
|
||||
// Any pipeline older than FVK_MAX_COMMAND_BUFFERS can be safely destroyed.
|
||||
using ConstPipeIterator = decltype(mPipelines)::const_iterator;
|
||||
for (ConstPipeIterator iter = mPipelines.begin(); iter != mPipelines.end();) {
|
||||
const PipelineCacheEntry& cacheEntry = iter.value();
|
||||
if (cacheEntry.lastUsed + VK_MAX_PIPELINE_AGE < mCurrentTime) {
|
||||
if (cacheEntry.lastUsed + FVK_MAX_PIPELINE_AGE < mCurrentTime) {
|
||||
vkDestroyPipeline(mDevice, iter->second.handle, VKALLOC);
|
||||
iter = mPipelines.erase(iter);
|
||||
} else {
|
||||
@@ -728,15 +728,15 @@ void VulkanPipelineCache::onCommandBuffer(const VulkanCommandBuffer& commands) {
|
||||
using ConstLayoutIterator = decltype(mPipelineLayouts)::const_iterator;
|
||||
for (ConstLayoutIterator iter = mPipelineLayouts.begin(); iter != mPipelineLayouts.end();) {
|
||||
const PipelineLayoutCacheEntry& cacheEntry = iter.value();
|
||||
if (cacheEntry.lastUsed + VK_MAX_PIPELINE_AGE < mCurrentTime) {
|
||||
if (cacheEntry.lastUsed + FVK_MAX_PIPELINE_AGE < mCurrentTime) {
|
||||
vkDestroyPipelineLayout(mDevice, iter->second.handle, VKALLOC);
|
||||
for (auto setLayout : iter->second.descriptorSetLayouts) {
|
||||
#ifndef NDEBUG
|
||||
#if FVK_ENABLED(FVK_DEBUG_PIPELINE_CACHE)
|
||||
PipelineLayoutKey key = iter.key();
|
||||
for (auto& pair : mDescriptorSets) {
|
||||
assert_invariant(pair.second.pipelineLayout != key);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
vkDestroyDescriptorSetLayout(mDevice, setLayout, VKALLOC);
|
||||
}
|
||||
auto& arenas = iter->second.descriptorSetArenas;
|
||||
@@ -755,7 +755,7 @@ void VulkanPipelineCache::onCommandBuffer(const VulkanCommandBuffer& commands) {
|
||||
// destroy the extinct pools, which implicitly frees their associated descriptor sets.
|
||||
bool canPurgeExtinctPools = true;
|
||||
for (auto& bundle : mExtinctDescriptorBundles) {
|
||||
if (bundle.lastUsed + VK_MAX_PIPELINE_AGE >= mCurrentTime) {
|
||||
if (bundle.lastUsed + FVK_MAX_PIPELINE_AGE >= mCurrentTime) {
|
||||
canPurgeExtinctPools = false;
|
||||
break;
|
||||
}
|
||||
@@ -799,7 +799,7 @@ VkDescriptorPool VulkanPipelineCache::createDescriptorPool(uint32_t size) const
|
||||
void VulkanPipelineCache::destroyLayoutsAndDescriptors() noexcept {
|
||||
// Our current descriptor set strategy can cause the # of descriptor sets to explode in certain
|
||||
// situations, so it's interesting to report the number that get stuffed into the cache.
|
||||
#ifndef NDEBUG
|
||||
#if FVK_ENABLED(FVK_DEBUG_PIPELINE_CACHE)
|
||||
utils::slog.d << "Destroying " << mDescriptorSets.size() << " bundles of descriptor sets."
|
||||
<< utils::io::endl;
|
||||
#endif
|
||||
@@ -808,7 +808,7 @@ void VulkanPipelineCache::destroyLayoutsAndDescriptors() noexcept {
|
||||
|
||||
// Our current layout bundle strategy can cause the # of layout bundles to explode in certain
|
||||
// situations, so it's interesting to report the number that get stuffed into the cache.
|
||||
#ifndef NDEBUG
|
||||
#if FVK_ENABLED(FVK_DEBUG_PIPELINE_CACHE)
|
||||
utils::slog.d << "Destroying " << mPipelineLayouts.size() << " pipeline layouts."
|
||||
<< utils::io::endl;
|
||||
#endif
|
||||
|
||||
@@ -340,7 +340,7 @@ private:
|
||||
|
||||
// The timestamp associated with a given cache entry represents time as a count of flush
|
||||
// events since the cache was constructed. If any cache entry was most recently used over
|
||||
// VK_MAX_PIPELINE_AGE flushes in the past, then we can be sure that it is no longer
|
||||
// FVK_MAX_PIPELINE_AGE flushes in the past, then we can be sure that it is no longer
|
||||
// being used by the GPU, and is therefore safe to destroy or reclaim.
|
||||
using Timestamp = uint64_t;
|
||||
Timestamp mCurrentTime = 0;
|
||||
|
||||
@@ -167,7 +167,7 @@ void VulkanReadPixels::run(VulkanRenderTarget const* srcTarget, uint32_t const x
|
||||
VkImage stagingImage;
|
||||
vkCreateImage(device, &imageInfo, VKALLOC, &stagingImage);
|
||||
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_READ_PIXELS)
|
||||
utils::slog.d << "readPixels created image=" << stagingImage
|
||||
<< " to copy from image=" << srcTexture->getVkImage()
|
||||
<< " src-layout=" << srcTexture->getLayout(0, 0) << utils::io::endl;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
static constexpr uint32_t TIME_BEFORE_EVICTION = VK_MAX_COMMAND_BUFFERS;
|
||||
static constexpr uint32_t TIME_BEFORE_EVICTION = FVK_MAX_COMMAND_BUFFERS;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
@@ -59,7 +59,7 @@ VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) {
|
||||
UTILS_UNUSED_IN_RELEASE VkResult result = vmaCreateBuffer(mAllocator, &bufferInfo,
|
||||
&allocInfo, &stage->buffer, &stage->memory, nullptr);
|
||||
|
||||
#ifndef NDEBUG
|
||||
#if FVK_ENABLED(FVK_DEBUG_ALLOCATION)
|
||||
if (result != VK_SUCCESS) {
|
||||
utils::slog.e << "Allocation error: " << result << utils::io::endl;
|
||||
}
|
||||
@@ -129,6 +129,9 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi
|
||||
}
|
||||
|
||||
void VulkanStagePool::gc() noexcept {
|
||||
FVK_SYSTRACE_CONTEXT();
|
||||
FVK_SYSTRACE_START("stagepool::gc");
|
||||
|
||||
// If this is one of the first few frames, return early to avoid wrapping unsigned integers.
|
||||
if (++mCurrentFrame <= TIME_BEFORE_EVICTION) {
|
||||
return;
|
||||
@@ -182,6 +185,7 @@ void VulkanStagePool::gc() noexcept {
|
||||
mUsedImages.insert(image);
|
||||
}
|
||||
}
|
||||
FVK_SYSTRACE_END();
|
||||
}
|
||||
|
||||
void VulkanStagePool::terminate() noexcept {
|
||||
|
||||
@@ -106,7 +106,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
||||
|
||||
if (any(usage & TextureUsage::SAMPLEABLE)) {
|
||||
|
||||
#if VK_ENABLE_VALIDATION
|
||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||
// Validate that the format is actually sampleable.
|
||||
VkFormatProperties props;
|
||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, mVkFormat, &props);
|
||||
@@ -160,7 +160,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
||||
imageInfo.samples = (VkSampleCountFlagBits) samples;
|
||||
|
||||
VkResult error = vkCreateImage(mDevice, &imageInfo, VKALLOC, &mTextureImage);
|
||||
if (error || FILAMENT_VULKAN_VERBOSE) {
|
||||
if (error || FVK_ENABLED_BOOL(FVK_DEBUG_TEXTURE)) {
|
||||
utils::slog.d << "vkCreateImage: "
|
||||
<< "image = " << mTextureImage << ", "
|
||||
<< "result = " << error << ", "
|
||||
@@ -417,7 +417,7 @@ void VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, const VkImageSubres
|
||||
VulkanLayout newLayout) {
|
||||
VulkanLayout oldLayout = getLayout(range.baseArrayLayer, range.baseMipLevel);
|
||||
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
|
||||
utils::slog.i << "transition layout of " << mTextureImage << ",layer=" << range.baseArrayLayer
|
||||
<< ",level=" << range.baseMipLevel << " from=" << oldLayout << " to=" << newLayout
|
||||
<< " format=" << mVkFormat
|
||||
@@ -463,7 +463,7 @@ VulkanLayout VulkanTexture::getLayout(uint32_t layer, uint32_t level) const {
|
||||
return mSubresourceLayouts.get(key);
|
||||
}
|
||||
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||
void VulkanTexture::print() const {
|
||||
const uint32_t firstLayer = 0;
|
||||
const uint32_t lastLayer = firstLayer + mPrimaryViewRange.layerCount;
|
||||
|
||||
@@ -84,7 +84,7 @@ struct VulkanTexture : public HwTexture, VulkanResource {
|
||||
// For now this always returns either DEPTH or COLOR.
|
||||
VkImageAspectFlags getImageAspect() const;
|
||||
|
||||
#if FILAMENT_VULKAN_VERBOSE
|
||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||
void print() const;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -45,11 +45,11 @@ constexpr uint32_t const INVALID_VK_INDEX = 0xFFFFFFFF;
|
||||
|
||||
typedef std::unordered_set<std::string_view> ExtensionSet;
|
||||
|
||||
#if VK_ENABLE_VALIDATION
|
||||
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
|
||||
// These strings need to be allocated outside a function stack
|
||||
const std::string_view DESIRED_LAYERS[] = {
|
||||
"VK_LAYER_KHRONOS_validation",
|
||||
#if FILAMENT_VULKAN_DUMP_API
|
||||
#if FVK_ENABLED(FVK_DEBUG_DUMP_API)
|
||||
"VK_LAYER_LUNARG_api_dump",
|
||||
#endif
|
||||
#if defined(ENABLE_RENDERDOC)
|
||||
@@ -75,7 +75,7 @@ FixedCapacityVector<const char*> getEnabledLayers() {
|
||||
}
|
||||
return enabledLayers;
|
||||
}
|
||||
#endif
|
||||
#endif // FVK_EANBLED(FVK_DEBUG_VALIDATION)
|
||||
|
||||
void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
|
||||
// Print some driver or MoltenVK information if it is available.
|
||||
@@ -129,27 +129,27 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
|
||||
<< minor << ")" << utils::io::endl;
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
|
||||
void printDepthFormats(VkPhysicalDevice device) {
|
||||
// For diagnostic purposes, print useful information about available depth formats.
|
||||
// Note that Vulkan is more constrained than OpenGL ES 3.1 in this area.
|
||||
if constexpr (VK_ENABLE_VALIDATION && FILAMENT_VULKAN_VERBOSE) {
|
||||
const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||
const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||
| VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
||||
utils::slog.i << "Sampleable depth formats: ";
|
||||
for (VkFormat format = (VkFormat) 1;;) {
|
||||
VkFormatProperties props;
|
||||
vkGetPhysicalDeviceFormatProperties(device, format, &props);
|
||||
if ((props.optimalTilingFeatures & required) == required) {
|
||||
utils::slog.i << format << " ";
|
||||
}
|
||||
if (format == VK_FORMAT_ASTC_12x12_SRGB_BLOCK) {
|
||||
utils::slog.i << utils::io::endl;
|
||||
break;
|
||||
}
|
||||
format = (VkFormat) (1 + (int) format);
|
||||
utils::slog.i << "Sampleable depth formats: ";
|
||||
for (VkFormat format = (VkFormat) 1;;) {
|
||||
VkFormatProperties props;
|
||||
vkGetPhysicalDeviceFormatProperties(device, format, &props);
|
||||
if ((props.optimalTilingFeatures & required) == required) {
|
||||
utils::slog.i << format << " ";
|
||||
}
|
||||
if (format == VK_FORMAT_ASTC_12x12_SRGB_BLOCK) {
|
||||
utils::slog.i << utils::io::endl;
|
||||
break;
|
||||
}
|
||||
format = (VkFormat) (1 + (int) format);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ExtensionSet getInstanceExtensions() {
|
||||
std::string_view const TARGET_EXTS[] = {
|
||||
@@ -161,7 +161,7 @@ ExtensionSet getInstanceExtensions() {
|
||||
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
|
||||
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
|
||||
|
||||
#if VK_ENABLE_VALIDATION
|
||||
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
|
||||
VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
|
||||
#endif
|
||||
};
|
||||
@@ -207,7 +207,7 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
||||
VkInstanceCreateInfo instanceCreateInfo = {};
|
||||
bool validationFeaturesSupported = false;
|
||||
|
||||
#if VK_ENABLE_VALIDATION
|
||||
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
|
||||
auto const enabledLayers = getEnabledLayers();
|
||||
if (!enabledLayers.empty()) {
|
||||
// If layers are supported, Check if VK_EXT_validation_features is supported.
|
||||
@@ -229,9 +229,10 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
||||
#else
|
||||
utils::slog.d << "Validation layer not available; did you install the Vulkan SDK?\n"
|
||||
<< "Please ensure that VK_LAYER_PATH is set correctly." << utils::io::endl;
|
||||
#endif
|
||||
#endif // __ANDROID__
|
||||
|
||||
}
|
||||
#endif// VK_ENABLE_VALIDATION
|
||||
#endif // FVK_ENABLED(FVK_DEBUG_VALIDATION)
|
||||
|
||||
// The Platform class can require 1 or 2 instance extensions, plus we'll request at most 5
|
||||
// instance extensions here in the common code. So that's a max of 7.
|
||||
@@ -252,7 +253,7 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
||||
VkApplicationInfo appInfo = {};
|
||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
appInfo.apiVersion
|
||||
= VK_MAKE_API_VERSION(0, VK_REQUIRED_VERSION_MAJOR, VK_REQUIRED_VERSION_MINOR, 0);
|
||||
= VK_MAKE_API_VERSION(0, FVK_REQUIRED_VERSION_MAJOR, FVK_REQUIRED_VERSION_MINOR, 0);
|
||||
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
instanceCreateInfo.pApplicationInfo = &appInfo;
|
||||
instanceCreateInfo.enabledExtensionCount = enabledExtensionCount;
|
||||
@@ -274,12 +275,8 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
||||
}
|
||||
|
||||
VkResult result = vkCreateInstance(&instanceCreateInfo, VKALLOC, &instance);
|
||||
#ifndef NDEBUG
|
||||
if (result != VK_SUCCESS) {
|
||||
utils::slog.e << "Unable to create instance: " << result << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
ASSERT_POSTCONDITION(result == VK_SUCCESS, "Unable to create Vulkan instance.");
|
||||
ASSERT_POSTCONDITION(result == VK_SUCCESS, "Unable to create Vulkan instance. Result=%d",
|
||||
result);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -443,10 +440,10 @@ VkPhysicalDevice selectPhysicalDevice(VkInstance instance,
|
||||
int const minor = VK_VERSION_MINOR(targetDeviceProperties.apiVersion);
|
||||
|
||||
// Does the device support the required Vulkan level?
|
||||
if (major < VK_REQUIRED_VERSION_MAJOR) {
|
||||
if (major < FVK_REQUIRED_VERSION_MAJOR) {
|
||||
continue;
|
||||
}
|
||||
if (major == VK_REQUIRED_VERSION_MAJOR && minor < VK_REQUIRED_VERSION_MINOR) {
|
||||
if (major == FVK_REQUIRED_VERSION_MAJOR && minor < FVK_REQUIRED_VERSION_MINOR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -667,7 +664,9 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
||||
// just yet, since that would require a corollary change to the "aspect" flags for the VkImage.
|
||||
context.mDepthFormat = findSupportedFormat(mImpl->mPhysicalDevice);
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
|
||||
printDepthFormats(mImpl->mPhysicalDevice);
|
||||
#endif
|
||||
|
||||
// Keep a copy of context for swapchains.
|
||||
mImpl->mContext = context;
|
||||
|
||||
Reference in New Issue
Block a user