Compare commits
51
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
531bfd6f6e | ||
|
|
db272484f9 | ||
|
|
9dadf400d2 | ||
|
|
16c7a3c968 | ||
|
|
626f338cba | ||
|
|
4e05cd73c6 | ||
|
|
49f9708312 | ||
|
|
2791195a92 | ||
|
|
65f78c06bb | ||
|
|
71175ee410 | ||
|
|
c9b310450c | ||
|
|
54c636d54c | ||
|
|
f503205be2 | ||
|
|
02106110fe | ||
|
|
5a0f78d915 | ||
|
|
f548c588d9 | ||
|
|
487fb273f1 | ||
|
|
111ac62d2f | ||
|
|
2fac13e154 | ||
|
|
bcae04c9ef | ||
|
|
55fc91b35f | ||
|
|
ff2827b226 | ||
|
|
13e1d2a042 | ||
|
|
b09cbaf0db | ||
|
|
b570d489e3 | ||
|
|
7f7daddbfa | ||
|
|
cfe6a423d3 | ||
|
|
ba99844f22 | ||
|
|
ea4c20ec2c | ||
|
|
0a661c1f3c | ||
|
|
021c4f6691 | ||
|
|
be6b6ae7be | ||
|
|
ad3a5b70b6 | ||
|
|
80803f9693 | ||
|
|
3b0e44c9a3 | ||
|
|
c5c2d42467 | ||
|
|
ff145f6ccf | ||
|
|
48bb10a4b5 | ||
|
|
01a2480175 | ||
|
|
9e921936c6 | ||
|
|
8bc4d3a9df | ||
|
|
0fdf1cac1d | ||
|
|
387942cc39 | ||
|
|
c81cedd887 | ||
|
|
abe8a49d17 | ||
|
|
96cba96058 | ||
|
|
4fccd957db | ||
|
|
d49554d5ce | ||
|
|
867161773e | ||
|
|
e2658506f6 | ||
|
|
6218164f79 |
@@ -8,5 +8,3 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
|||||||
## Release notes for next branch cut
|
## Release notes for next branch cut
|
||||||
|
|
||||||
- engine: add `View::getLastDynamicResolutionScale()` (b/457753622)
|
- engine: add `View::getLastDynamicResolutionScale()` (b/457753622)
|
||||||
|
|
||||||
- materials: Make Material Instances' UBO descriptor use dynamic offsets. [⚠️ **Recompile Materials**]
|
|
||||||
|
|||||||
-1
@@ -22,7 +22,6 @@ object Utils {
|
|||||||
/**
|
/**
|
||||||
* Initializes the utils JNI layer. Must be called before using any utils functionality.
|
* Initializes the utils JNI layer. Must be called before using any utils functionality.
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
|
||||||
fun init() {
|
fun init() {
|
||||||
// Load Filament first to ensure that the NioUtils Java class is available in the JNIEnv.
|
// Load Filament first to ensure that the NioUtils Java class is available in the JNIEnv.
|
||||||
Filament.init()
|
Filament.init()
|
||||||
|
|||||||
@@ -17,20 +17,12 @@ filamentTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// don't forget to update MainACtivity.kt when/if changing this.
|
// don't forget to update MainACtivity.kt when/if changing this.
|
||||||
tasks.register('copyDamagedHelmetGltf', Copy) {
|
tasks.register('copyMesh', Copy) {
|
||||||
from file("../../../third_party/models/DamagedHelmet/DamagedHelmet.glb")
|
|
||||||
into file("src/main/assets/models")
|
|
||||||
rename {String fileName -> "helmet.glb"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't forget to update MainACtivity.kt when/if changing this.
|
|
||||||
tasks.register('copyBusterGltf', Copy) {
|
|
||||||
from "../../../third_party/models/BusterDrone"
|
from "../../../third_party/models/BusterDrone"
|
||||||
into "src/main/assets/models"
|
into "src/main/assets/models"
|
||||||
}
|
}
|
||||||
|
|
||||||
preBuild.dependsOn copyDamagedHelmetGltf
|
preBuild.dependsOn copyMesh
|
||||||
preBuild.dependsOn copyBusterGltf
|
|
||||||
|
|
||||||
clean.doFirst {
|
clean.doFirst {
|
||||||
delete "src/main/assets"
|
delete "src/main/assets"
|
||||||
|
|||||||
Binary file not shown.
@@ -214,6 +214,14 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
|||||||
src/vulkan/VulkanMemory.h
|
src/vulkan/VulkanMemory.h
|
||||||
src/vulkan/VulkanPipelineCache.cpp
|
src/vulkan/VulkanPipelineCache.cpp
|
||||||
src/vulkan/VulkanPipelineCache.h
|
src/vulkan/VulkanPipelineCache.h
|
||||||
|
src/vulkan/VulkanPipelineStateSerializer.cpp
|
||||||
|
src/vulkan/VulkanPipelineStateSerializer.h
|
||||||
|
src/vulkan/VulkanSamplerStateSerializer.h
|
||||||
|
src/vulkan/VulkanSamplerStateSerializer.cpp
|
||||||
|
src/vulkan/VulkanRenderPassStateSerializer.h
|
||||||
|
src/vulkan/VulkanRenderPassStateSerializer.cpp
|
||||||
|
src/vulkan/VulkanDescriptorSetLayoutSerializer.h
|
||||||
|
src/vulkan/VulkanDescriptorSetLayoutSerializer.cpp
|
||||||
src/vulkan/VulkanPipelineLayoutCache.cpp
|
src/vulkan/VulkanPipelineLayoutCache.cpp
|
||||||
src/vulkan/VulkanPipelineLayoutCache.h
|
src/vulkan/VulkanPipelineLayoutCache.h
|
||||||
src/vulkan/VulkanQueryManager.cpp
|
src/vulkan/VulkanQueryManager.cpp
|
||||||
|
|||||||
@@ -444,11 +444,6 @@ protected:
|
|||||||
|
|
||||||
virtual VkExternalFenceHandleTypeFlagBits getFenceExportFlags() const noexcept;
|
virtual VkExternalFenceHandleTypeFlagBits getFenceExportFlags() const noexcept;
|
||||||
|
|
||||||
/**
|
|
||||||
* Query if transient attachments are supported by the backend.
|
|
||||||
*/
|
|
||||||
bool isTransientAttachmentSupported() const noexcept;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct VulkanPlatformPrivate;
|
friend struct VulkanPlatformPrivate;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -214,10 +214,4 @@ constexpr static const int FVK_MAX_PIPELINE_AGE = FVK_MAX_COMMAND_BUFFERS;
|
|||||||
// destroying any unused pipeline object.
|
// destroying any unused pipeline object.
|
||||||
static_assert(FVK_MAX_PIPELINE_AGE >= FVK_MAX_COMMAND_BUFFERS);
|
static_assert(FVK_MAX_PIPELINE_AGE >= FVK_MAX_COMMAND_BUFFERS);
|
||||||
|
|
||||||
// Indicates if the backend must be setup to allow doing a RenderDoc capture.
|
|
||||||
//
|
|
||||||
// If this is true, the features not supported by RenderDoc must be disabled, otherwise
|
|
||||||
// when using RenderDoc the application will crash or will fail to do a capture.
|
|
||||||
constexpr static const int FVK_RENDERDOC_CAPTURE_MODE = false;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -154,10 +154,6 @@ public:
|
|||||||
return mStagingBufferBypassEnabled;
|
return mStagingBufferBypassEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool pipelineCreationFeedbackSupported() const noexcept {
|
|
||||||
return mPipelineCreationFeedbackSupported;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
|
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
|
||||||
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
||||||
@@ -185,7 +181,6 @@ private:
|
|||||||
bool mProtectedMemorySupported = false;
|
bool mProtectedMemorySupported = false;
|
||||||
bool mIsUnifiedMemoryArchitecture = false;
|
bool mIsUnifiedMemoryArchitecture = false;
|
||||||
bool mStagingBufferBypassEnabled = false;
|
bool mStagingBufferBypassEnabled = false;
|
||||||
bool mPipelineCreationFeedbackSupported = false;
|
|
||||||
|
|
||||||
fvkutils::VkFormatList mDepthStencilFormats;
|
fvkutils::VkFormatList mDepthStencilFormats;
|
||||||
fvkutils::VkFormatList mBlittableDepthStencilFormats;
|
fvkutils::VkFormatList mBlittableDepthStencilFormats;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VulkanDescriptorSetLayoutCache.h"
|
#include "VulkanDescriptorSetLayoutCache.h"
|
||||||
|
#include "VulkanDescriptorSetLayoutSerializer.h"
|
||||||
|
|
||||||
#include "VulkanHandles.h"
|
#include "VulkanHandles.h"
|
||||||
|
|
||||||
@@ -100,22 +101,32 @@ uint32_t appendSamplerBindings(VkDescriptorSetLayoutBinding* toBind,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t computeImmutableSamplerHash(utils::FixedCapacityVector<VkSampler> const& samplers) {
|
uint64_t computeImmutableSamplerHash(utils::FixedCapacityVector<VkSampler> const& samplers, VulkanSamplerCache* cache) {
|
||||||
size_t const size = samplers.size();
|
size_t const size = samplers.size();
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (size == 1) {
|
|
||||||
return (uint64_t) samplers[0];
|
|
||||||
}
|
}
|
||||||
return utils::hash::murmur3((uint32_t*) samplers.data(), samplers.size() * 2, 0);
|
|
||||||
|
utils::FixedCapacityVector<uint32_t> samplerHash;
|
||||||
|
if (size > 0) {
|
||||||
|
samplerHash.reserve(MAX_SAMPLER_COUNT);
|
||||||
|
for (auto sampler : samplers) {
|
||||||
|
samplerHash.push_back(cache->getKey(sampler));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == 1) {
|
||||||
|
return (uint64_t) samplerHash[0];
|
||||||
|
}
|
||||||
|
return utils::hash::murmur3((uint32_t*) samplerHash.data(), samplerHash.size() * 2, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
VulkanDescriptorSetLayoutCache::VulkanDescriptorSetLayoutCache(VkDevice device,
|
VulkanDescriptorSetLayoutCache::VulkanDescriptorSetLayoutCache(VkDevice device,
|
||||||
fvkmemory::ResourceManager* resourceManager)
|
fvkmemory::ResourceManager* resourceManager, VulkanSamplerCache* cache)
|
||||||
: mDevice(device),
|
: mDevice(device),
|
||||||
mResourceManager(resourceManager) {}
|
mResourceManager(resourceManager), mSamplerCache(cache) {}
|
||||||
|
|
||||||
VulkanDescriptorSetLayoutCache::~VulkanDescriptorSetLayoutCache() = default;
|
VulkanDescriptorSetLayoutCache::~VulkanDescriptorSetLayoutCache() = default;
|
||||||
|
|
||||||
@@ -131,7 +142,7 @@ VkDescriptorSetLayout VulkanDescriptorSetLayoutCache::getVkLayout(
|
|||||||
utils::FixedCapacityVector<VkSampler> immutableSamplers) {
|
utils::FixedCapacityVector<VkSampler> immutableSamplers) {
|
||||||
LayoutKey key = {
|
LayoutKey key = {
|
||||||
.bitmask = bitmasks,
|
.bitmask = bitmasks,
|
||||||
.immutableSamplerHash = computeImmutableSamplerHash(immutableSamplers),
|
.immutableSamplerHash = computeImmutableSamplerHash(immutableSamplers, mSamplerCache),
|
||||||
};
|
};
|
||||||
if (auto itr = mVkLayouts.find(key); itr != mVkLayouts.end()) {
|
if (auto itr = mVkLayouts.find(key); itr != mVkLayouts.end()) {
|
||||||
return itr->second;
|
return itr->second;
|
||||||
@@ -153,9 +164,20 @@ VkDescriptorSetLayout VulkanDescriptorSetLayoutCache::getVkLayout(
|
|||||||
.bindingCount = count,
|
.bindingCount = count,
|
||||||
.pBindings = toBind,
|
.pBindings = toBind,
|
||||||
};
|
};
|
||||||
|
LayoutKeyHashFn hashFunc;
|
||||||
|
uint32_t hashedKey = hashFunc(key);
|
||||||
|
utils::FixedCapacityVector<uint32_t> immutableSamplersHashes;
|
||||||
|
immutableSamplersHashes.reserve(MAX_SAMPLER_COUNT);
|
||||||
|
for (auto sampler: immutableSamplers) {
|
||||||
|
immutableSamplersHashes.push_back(mSamplerCache->getKey(sampler));
|
||||||
|
}
|
||||||
|
VulkanDescriptorSetLayoutSerializer setSer(dlinfo, immutableSamplersHashes, hashedKey);
|
||||||
|
|
||||||
VkDescriptorSetLayout vklayout;
|
VkDescriptorSetLayout vklayout;
|
||||||
vkCreateDescriptorSetLayout(mDevice, &dlinfo, VKALLOC, &vklayout);
|
vkCreateDescriptorSetLayout(mDevice, &dlinfo, VKALLOC, &vklayout);
|
||||||
mVkLayouts[key] = vklayout;
|
mVkLayouts[key] = vklayout;
|
||||||
|
|
||||||
|
mLayoutToKey[vklayout] = hashedKey;
|
||||||
return vklayout;
|
return vklayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "VulkanHandles.h"
|
#include "VulkanHandles.h"
|
||||||
|
|
||||||
|
#include "VulkanSamplerCache.h"
|
||||||
|
|
||||||
#include "vulkan/memory/ResourcePointer.h"
|
#include "vulkan/memory/ResourcePointer.h"
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
@@ -35,7 +37,8 @@ namespace filament::backend {
|
|||||||
|
|
||||||
class VulkanDescriptorSetLayoutCache {
|
class VulkanDescriptorSetLayoutCache {
|
||||||
public:
|
public:
|
||||||
VulkanDescriptorSetLayoutCache(VkDevice device, fvkmemory::ResourceManager* resourceManager);
|
VulkanDescriptorSetLayoutCache(VkDevice device, fvkmemory::ResourceManager* resourceManager,
|
||||||
|
VulkanSamplerCache* cache);
|
||||||
~VulkanDescriptorSetLayoutCache();
|
~VulkanDescriptorSetLayoutCache();
|
||||||
|
|
||||||
void terminate() noexcept;
|
void terminate() noexcept;
|
||||||
@@ -48,10 +51,19 @@ public:
|
|||||||
VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout::Bitmask const& bitmasks,
|
VkDescriptorSetLayout getVkLayout(VulkanDescriptorSetLayout::Bitmask const& bitmasks,
|
||||||
fvkutils::SamplerBitmask externalSamplers,
|
fvkutils::SamplerBitmask externalSamplers,
|
||||||
utils::FixedCapacityVector<VkSampler> immutableSamplers = {});
|
utils::FixedCapacityVector<VkSampler> immutableSamplers = {});
|
||||||
|
uint32_t getKey(VkDescriptorSetLayout layout) {
|
||||||
|
uint32_t key = 0;
|
||||||
|
auto iter = mLayoutToKey.find(layout);
|
||||||
|
if (iter != mLayoutToKey.end()) {
|
||||||
|
key = iter->second;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkDevice mDevice;
|
VkDevice mDevice;
|
||||||
fvkmemory::ResourceManager* mResourceManager;
|
fvkmemory::ResourceManager* mResourceManager;
|
||||||
|
VulkanSamplerCache* mSamplerCache;
|
||||||
|
|
||||||
struct LayoutKey {
|
struct LayoutKey {
|
||||||
// this describes the layout using bitset.
|
// this describes the layout using bitset.
|
||||||
@@ -69,6 +81,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
tsl::robin_map<LayoutKey, VkDescriptorSetLayout, LayoutKeyHashFn, LayoutKeyEqual> mVkLayouts;
|
tsl::robin_map<LayoutKey, VkDescriptorSetLayout, LayoutKeyHashFn, LayoutKeyEqual> mVkLayouts;
|
||||||
|
std::map<VkDescriptorSetLayout, uint32_t> mLayoutToKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
#include "VulkanDescriptorSetLayoutSerializer.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <utils/Hash.h>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
VulkanDescriptorSetLayoutSerializer::VulkanDescriptorSetLayoutSerializer(
|
||||||
|
const VkDescriptorSetLayoutCreateInfo& info,
|
||||||
|
utils::FixedCapacityVector<uint32_t> immutableSamplers, uint32_t hash) {
|
||||||
|
std::stringstream filename;
|
||||||
|
filename << "descriptor_set_layout_" << hash << ".json";
|
||||||
|
|
||||||
|
std::ofstream file(filename.str());
|
||||||
|
if (file.is_open()) {
|
||||||
|
std::stringstream buffer;
|
||||||
|
buffer << "[" << std::endl;
|
||||||
|
for (uint32_t i = 0; i < info.bindingCount; ++i) {
|
||||||
|
buffer << "{" << std::endl;
|
||||||
|
buffer << "\"binding\":" << info.pBindings[i].binding << "," << std::endl;
|
||||||
|
buffer << "\"descriptor_type\":" << info.pBindings[i].descriptorType << "," << std::endl;
|
||||||
|
buffer << "\"stage_flags\":" << info.pBindings[i].stageFlags;
|
||||||
|
if (immutableSamplers.size()) {
|
||||||
|
buffer << "," << std::endl;
|
||||||
|
buffer << "\"immutable_samplers\":[" << std::endl;
|
||||||
|
for (uint32_t i = 0; i < immutableSamplers.size(); ++i) {
|
||||||
|
buffer << immutableSamplers[i];
|
||||||
|
if (i < immutableSamplers.size() - 1) {
|
||||||
|
buffer << ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer << "]";
|
||||||
|
}
|
||||||
|
buffer << std::endl;
|
||||||
|
buffer << "}";
|
||||||
|
if (i < info.bindingCount - 1) {
|
||||||
|
buffer << ",";
|
||||||
|
}
|
||||||
|
buffer << std::endl;
|
||||||
|
}
|
||||||
|
buffer << "]" << std::endl;
|
||||||
|
|
||||||
|
file << buffer.str();
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPipelineLayoutSerializer::VulkanPipelineLayoutSerializer(
|
||||||
|
const VkPipelineLayoutCreateInfo& info, VulkanDescriptorSetLayoutCache* cache,
|
||||||
|
uint32_t hash) {
|
||||||
|
std::stringstream filename;
|
||||||
|
filename << "pipeline_layout_" << hash << ".json";
|
||||||
|
std::ofstream file(filename.str());
|
||||||
|
if (file.is_open()) {
|
||||||
|
std::stringstream buffer;
|
||||||
|
buffer << "{" << std::endl;
|
||||||
|
buffer << "\"flags\":" << info.flags << "," << std::endl;
|
||||||
|
|
||||||
|
buffer << "\"layouts\":[" << std::endl;
|
||||||
|
for (uint32_t i = 0; i < info.setLayoutCount; ++i) {
|
||||||
|
buffer << cache->getKey(info.pSetLayouts[i]);
|
||||||
|
if (i < info.setLayoutCount - 1) {
|
||||||
|
buffer << ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer << "]," << std::endl;
|
||||||
|
|
||||||
|
buffer << "\"push_constants\":[" << std::endl;
|
||||||
|
for (uint32_t i = 0; i < info.pushConstantRangeCount; ++i) {
|
||||||
|
buffer << "{" << std::endl;
|
||||||
|
buffer << "\"stage_flags\":" << info.pPushConstantRanges[i].stageFlags << "," << std::endl;
|
||||||
|
buffer << "\"offset\":" << info.pPushConstantRanges[i].offset << ","
|
||||||
|
<< std::endl;
|
||||||
|
buffer << "\"size\":" << info.pPushConstantRanges[i].size
|
||||||
|
<< std::endl;
|
||||||
|
buffer << "}" << std::endl;
|
||||||
|
if (i < info.pushConstantRangeCount - 1) {
|
||||||
|
buffer << ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer << "]" << std::endl;
|
||||||
|
|
||||||
|
buffer << "}" << std::endl;
|
||||||
|
file << buffer.str();
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
} // namespace filament::backend
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_FILAMENT_BACKEND_VULKANDESCRIPTORSETLAYOUTSERIALIZER_H
|
||||||
|
#define TNT_FILAMENT_BACKEND_VULKANDESCRIPTORSETLAYOUTSERIALIZER_H
|
||||||
|
|
||||||
|
#include "VulkanPipelineLayoutCache.h"
|
||||||
|
#include "VulkanYcbcrConversionCache.h"
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
|
#include <bluevk/BlueVK.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
class VulkanDescriptorSetLayoutSerializer {
|
||||||
|
public:
|
||||||
|
VulkanDescriptorSetLayoutSerializer(VulkanDescriptorSetLayoutSerializer const&) = delete;
|
||||||
|
VulkanDescriptorSetLayoutSerializer& operator=(
|
||||||
|
VulkanDescriptorSetLayoutSerializer const&) = delete;
|
||||||
|
|
||||||
|
VulkanDescriptorSetLayoutSerializer(const VkDescriptorSetLayoutCreateInfo& info,
|
||||||
|
utils::FixedCapacityVector<uint32_t> immutableSamplers,
|
||||||
|
uint32_t hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
class VulkanPipelineLayoutSerializer {
|
||||||
|
public:
|
||||||
|
VulkanPipelineLayoutSerializer(VulkanPipelineLayoutSerializer const&) = delete;
|
||||||
|
VulkanPipelineLayoutSerializer& operator=(VulkanPipelineLayoutSerializer const&) = delete;
|
||||||
|
|
||||||
|
VulkanPipelineLayoutSerializer(const VkPipelineLayoutCreateInfo& layout,
|
||||||
|
VulkanDescriptorSetLayoutCache* cache, uint32_t hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace filament::backend
|
||||||
|
|
||||||
|
#endif // TNT_FILAMENT_BACKEND_VULKANDESCRIPTORSETLAYOUTSERIALIZER_H
|
||||||
@@ -230,16 +230,16 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
|
|||||||
mCommands(mPlatform->getDevice(), mPlatform->getGraphicsQueue(),
|
mCommands(mPlatform->getDevice(), mPlatform->getGraphicsQueue(),
|
||||||
mPlatform->getGraphicsQueueFamilyIndex(), mPlatform->getProtectedGraphicsQueue(),
|
mPlatform->getGraphicsQueueFamilyIndex(), mPlatform->getProtectedGraphicsQueue(),
|
||||||
mPlatform->getProtectedGraphicsQueueFamilyIndex(), mContext, &mSemaphoreManager),
|
mPlatform->getProtectedGraphicsQueueFamilyIndex(), mContext, &mSemaphoreManager),
|
||||||
mPipelineLayoutCache(mPlatform->getDevice()),
|
mPipelineCache(mPlatform->getDevice()),
|
||||||
mPipelineCache(mPlatform->getDevice(), mContext),
|
|
||||||
mStagePool(mAllocator, &mResourceManager, &mCommands, &mContext.getPhysicalDeviceLimits()),
|
mStagePool(mAllocator, &mResourceManager, &mCommands, &mContext.getPhysicalDeviceLimits()),
|
||||||
mBufferCache(mContext, mResourceManager, mAllocator),
|
mBufferCache(mContext, mResourceManager, mAllocator),
|
||||||
mFramebufferCache(mPlatform->getDevice()),
|
mFramebufferCache(mPlatform->getDevice()),
|
||||||
mYcbcrConversionCache(mPlatform->getDevice()),
|
mYcbcrConversionCache(mPlatform->getDevice()),
|
||||||
mSamplerCache(mPlatform->getDevice()),
|
mSamplerCache(mPlatform->getDevice(), &mYcbcrConversionCache),
|
||||||
mBlitter(mPlatform->getPhysicalDevice(), &mCommands),
|
mBlitter(mPlatform->getPhysicalDevice(), &mCommands),
|
||||||
mReadPixels(mPlatform->getDevice()),
|
mReadPixels(mPlatform->getDevice()),
|
||||||
mDescriptorSetLayoutCache(mPlatform->getDevice(), &mResourceManager),
|
mDescriptorSetLayoutCache(mPlatform->getDevice(), &mResourceManager, &mSamplerCache),
|
||||||
|
mPipelineLayoutCache(mPlatform->getDevice(), &mDescriptorSetLayoutCache),
|
||||||
mDescriptorSetCache(mPlatform->getDevice(), &mResourceManager),
|
mDescriptorSetCache(mPlatform->getDevice(), &mResourceManager),
|
||||||
mQueryManager(mPlatform->getDevice()),
|
mQueryManager(mPlatform->getDevice()),
|
||||||
mExternalImageManager(platform, &mSamplerCache, &mYcbcrConversionCache, &mDescriptorSetCache,
|
mExternalImageManager(platform, &mSamplerCache, &mYcbcrConversionCache, &mDescriptorSetCache,
|
||||||
@@ -1666,7 +1666,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
|||||||
rpkey.subpassMask = uint8_t(params.subpassMask);
|
rpkey.subpassMask = uint8_t(params.subpassMask);
|
||||||
|
|
||||||
VkRenderPass renderPass = mFramebufferCache.getRenderPass(rpkey);
|
VkRenderPass renderPass = mFramebufferCache.getRenderPass(rpkey);
|
||||||
mPipelineCache.bindRenderPass(renderPass, 0);
|
mPipelineCache.bindRenderPass(renderPass, mFramebufferCache.getRenderPassKey(renderPass), 0);
|
||||||
|
|
||||||
// Create the VkFramebuffer or fetch it from cache.
|
// Create the VkFramebuffer or fetch it from cache.
|
||||||
VulkanFboCache::FboKey fbkey = rt->getFboKey();
|
VulkanFboCache::FboKey fbkey = rt->getFboKey();
|
||||||
@@ -1785,6 +1785,7 @@ void VulkanDriver::nextSubpass(int) {
|
|||||||
VK_SUBPASS_CONTENTS_INLINE);
|
VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
mPipelineCache.bindRenderPass(mCurrentRenderPass.renderPass,
|
mPipelineCache.bindRenderPass(mCurrentRenderPass.renderPass,
|
||||||
|
mFramebufferCache.getRenderPassKey(mCurrentRenderPass.renderPass),
|
||||||
++mCurrentRenderPass.currentSubpass);
|
++mCurrentRenderPass.currentSubpass);
|
||||||
|
|
||||||
if (mCurrentRenderPass.params.subpassMask & 0x1) {
|
if (mCurrentRenderPass.params.subpassMask & 0x1) {
|
||||||
@@ -2160,7 +2161,8 @@ void VulkanDriver::bindPipelineImpl(PipelineState const& pipelineState,
|
|||||||
mPipelineState.pipelineLayout = pipelineLayout;
|
mPipelineState.pipelineLayout = pipelineLayout;
|
||||||
mPipelineState.descriptorSetMask = descriptorSetMask;
|
mPipelineState.descriptorSetMask = descriptorSetMask;
|
||||||
|
|
||||||
mPipelineCache.bindLayout(pipelineLayout);
|
auto key = mPipelineLayoutCache.getKey(pipelineLayout);
|
||||||
|
mPipelineCache.bindLayout(pipelineLayout, key);
|
||||||
mPipelineCache.bindPipeline(mCurrentRenderPass.commandBuffer);
|
mPipelineCache.bindPipeline(mCurrentRenderPass.commandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,6 @@ private:
|
|||||||
|
|
||||||
VulkanSemaphoreManager mSemaphoreManager;
|
VulkanSemaphoreManager mSemaphoreManager;
|
||||||
VulkanCommands mCommands;
|
VulkanCommands mCommands;
|
||||||
VulkanPipelineLayoutCache mPipelineLayoutCache;
|
|
||||||
VulkanPipelineCache mPipelineCache;
|
VulkanPipelineCache mPipelineCache;
|
||||||
VulkanStagePool mStagePool;
|
VulkanStagePool mStagePool;
|
||||||
VulkanBufferCache mBufferCache;
|
VulkanBufferCache mBufferCache;
|
||||||
@@ -158,6 +157,7 @@ private:
|
|||||||
VulkanBlitter mBlitter;
|
VulkanBlitter mBlitter;
|
||||||
VulkanReadPixels mReadPixels;
|
VulkanReadPixels mReadPixels;
|
||||||
VulkanDescriptorSetLayoutCache mDescriptorSetLayoutCache;
|
VulkanDescriptorSetLayoutCache mDescriptorSetLayoutCache;
|
||||||
|
VulkanPipelineLayoutCache mPipelineLayoutCache;
|
||||||
VulkanDescriptorSetCache mDescriptorSetCache;
|
VulkanDescriptorSetCache mDescriptorSetCache;
|
||||||
VulkanQueryManager mQueryManager;
|
VulkanQueryManager mQueryManager;
|
||||||
VulkanExternalImageManager mExternalImageManager;
|
VulkanExternalImageManager mExternalImageManager;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VulkanFboCache.h"
|
#include "VulkanFboCache.h"
|
||||||
|
#include "VulkanRenderPassStateSerializer.h"
|
||||||
|
|
||||||
#include "VulkanConstants.h"
|
#include "VulkanConstants.h"
|
||||||
#include "vulkan/utils/Image.h"
|
#include "vulkan/utils/Image.h"
|
||||||
@@ -69,6 +70,15 @@ VulkanFboCache::~VulkanFboCache() {
|
|||||||
<< "Please explicitly call terminate() while the VkDevice is still alive.";
|
<< "Please explicitly call terminate() while the VkDevice is still alive.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t VulkanFboCache::getRenderPassKey(VkRenderPass pass) noexcept {
|
||||||
|
uint32_t key = 0;
|
||||||
|
auto iter = mRenderPassToKey.find(pass);
|
||||||
|
if (iter != mRenderPassToKey.end()) {
|
||||||
|
key = iter->second;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
VkFramebuffer VulkanFboCache::getFramebuffer(FboKey const& config) noexcept {
|
VkFramebuffer VulkanFboCache::getFramebuffer(FboKey const& config) noexcept {
|
||||||
FboMap::iterator iter = mFramebufferCache.find(config);
|
FboMap::iterator iter = mFramebufferCache.find(config);
|
||||||
if (UTILS_LIKELY(iter != mFramebufferCache.end() && iter->second.handle != VK_NULL_HANDLE)) {
|
if (UTILS_LIKELY(iter != mFramebufferCache.end() && iter->second.handle != VK_NULL_HANDLE)) {
|
||||||
@@ -117,6 +127,7 @@ VkFramebuffer VulkanFboCache::getFramebuffer(FboKey const& config) noexcept {
|
|||||||
VkResult error = vkCreateFramebuffer(mDevice, &info, VKALLOC, &framebuffer);
|
VkResult error = vkCreateFramebuffer(mDevice, &info, VKALLOC, &framebuffer);
|
||||||
FILAMENT_CHECK_POSTCONDITION(error == VK_SUCCESS) << "Unable to create framebuffer."
|
FILAMENT_CHECK_POSTCONDITION(error == VK_SUCCESS) << "Unable to create framebuffer."
|
||||||
<< " error=" << static_cast<int32_t>(error);
|
<< " error=" << static_cast<int32_t>(error);
|
||||||
|
|
||||||
mFramebufferCache[config] = {framebuffer, mCurrentTime};
|
mFramebufferCache[config] = {framebuffer, mCurrentTime};
|
||||||
return framebuffer;
|
return framebuffer;
|
||||||
}
|
}
|
||||||
@@ -326,6 +337,12 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept
|
|||||||
VkResult error = vkCreateRenderPass(mDevice, &renderPassInfo, VKALLOC, &renderPass);
|
VkResult error = vkCreateRenderPass(mDevice, &renderPassInfo, VKALLOC, &renderPass);
|
||||||
FILAMENT_CHECK_POSTCONDITION(error == VK_SUCCESS) << "Unable to create render pass."
|
FILAMENT_CHECK_POSTCONDITION(error == VK_SUCCESS) << "Unable to create render pass."
|
||||||
<< " error=" << error;
|
<< " error=" << error;
|
||||||
|
|
||||||
|
RenderPassHash hashFunc;
|
||||||
|
uint32_t key = hashFunc(config);
|
||||||
|
VulkanRenderPassStateSerializer passSer(renderPassInfo, key);
|
||||||
|
mRenderPassToKey[renderPass] = key;
|
||||||
|
|
||||||
mRenderPassCache[config] = {renderPass, mCurrentTime};
|
mRenderPassCache[config] = {renderPass, mCurrentTime};
|
||||||
|
|
||||||
#if FVK_ENABLED(FVK_DEBUG_FBO_CACHE)
|
#if FVK_ENABLED(FVK_DEBUG_FBO_CACHE)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <backend/TargetBufferInfo.h>
|
#include <backend/TargetBufferInfo.h>
|
||||||
|
|
||||||
#include <tsl/robin_map.h>
|
#include <tsl/robin_map.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -97,6 +98,8 @@ public:
|
|||||||
explicit VulkanFboCache(VkDevice device);
|
explicit VulkanFboCache(VkDevice device);
|
||||||
~VulkanFboCache();
|
~VulkanFboCache();
|
||||||
|
|
||||||
|
uint32_t getRenderPassKey(VkRenderPass pass) noexcept;
|
||||||
|
|
||||||
// Retrieves or creates a VkFramebuffer handle.
|
// Retrieves or creates a VkFramebuffer handle.
|
||||||
VkFramebuffer getFramebuffer(FboKey const& config) noexcept;
|
VkFramebuffer getFramebuffer(FboKey const& config) noexcept;
|
||||||
|
|
||||||
@@ -118,6 +121,7 @@ private:
|
|||||||
FboMap mFramebufferCache;
|
FboMap mFramebufferCache;
|
||||||
|
|
||||||
tsl::robin_map<RenderPassKey, RenderPassVal, RenderPassHash, RenderPassEq> mRenderPassCache;
|
tsl::robin_map<RenderPassKey, RenderPassVal, RenderPassHash, RenderPassEq> mRenderPassCache;
|
||||||
|
std::map<VkRenderPass, uint32_t> mRenderPassToKey;
|
||||||
tsl::robin_map<VkRenderPass, uint32_t> mRenderPassRefCount;
|
tsl::robin_map<VkRenderPass, uint32_t> mRenderPassRefCount;
|
||||||
uint32_t mCurrentTime = 0;
|
uint32_t mCurrentTime = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include <utils/compiler.h> // UTILS_FALLTHROUGH
|
#include <utils/compiler.h> // UTILS_FALLTHROUGH
|
||||||
#include <utils/Panic.h> // ASSERT_POSTCONDITION
|
#include <utils/Panic.h> // ASSERT_POSTCONDITION
|
||||||
#include <utils/CString.h>
|
#include <utils/CString.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
using namespace bluevk;
|
using namespace bluevk;
|
||||||
|
|
||||||
@@ -179,6 +180,23 @@ VulkanAttachment createSwapchainAttachment(const fvkmemory::resource_ptr<VulkanT
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint64_t serializeShaderModule(utils::CString progName, VkShaderModuleCreateInfo info,
|
||||||
|
VkShaderStageFlagBits stage) {
|
||||||
|
std::stringstream filename;
|
||||||
|
filename << progName.c_str() << "_" << stage << "_";
|
||||||
|
constexpr uint32_t wordReadCount = 8;
|
||||||
|
uint64_t key = utils::hash::murmur3(info.pCode, wordReadCount, 0);
|
||||||
|
key |= uint64_t(utils::hash::murmur3(info.pCode + (wordReadCount / 2), wordReadCount, 0)) << 32;
|
||||||
|
filename << key << ".bin";
|
||||||
|
|
||||||
|
std::ofstream file(filename.str());
|
||||||
|
if (file.is_open()) {
|
||||||
|
file.write(reinterpret_cast<const char*>(info.pCode), info.codeSize);
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(DescriptorSetLayout&& layout,
|
VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(DescriptorSetLayout&& layout,
|
||||||
@@ -280,6 +298,12 @@ VulkanProgram::VulkanProgram(VkDevice device, Program const& builder) noexcept
|
|||||||
.codeSize = dataSize,
|
.codeSize = dataSize,
|
||||||
.pCode = data,
|
.pCode = data,
|
||||||
};
|
};
|
||||||
|
if (i == 0) {
|
||||||
|
mVertexShaderHash = serializeShaderModule(name, moduleInfo, VK_SHADER_STAGE_VERTEX_BIT);
|
||||||
|
} else if (i == 1) {
|
||||||
|
mFragmentShaderHash =
|
||||||
|
serializeShaderModule(name, moduleInfo, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
}
|
||||||
VkResult result = vkCreateShaderModule(mDevice, &moduleInfo, VKALLOC, &module);
|
VkResult result = vkCreateShaderModule(mDevice, &moduleInfo, VKALLOC, &module);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "Unable to create shader module."
|
<< "Unable to create shader module."
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso
|
|||||||
|
|
||||||
using DescriptorSetLayoutArray = std::array<VkDescriptorSetLayout,
|
using DescriptorSetLayoutArray = std::array<VkDescriptorSetLayout,
|
||||||
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
|
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
|
||||||
|
using DescriptorSetLayoutHashArray = std::array<uint64_t,
|
||||||
|
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
|
||||||
|
|
||||||
// The bitmask representation of a set layout.
|
// The bitmask representation of a set layout.
|
||||||
struct Bitmask {
|
struct Bitmask {
|
||||||
@@ -280,6 +282,10 @@ struct VulkanProgram : public HwProgram, fvkmemory::Resource {
|
|||||||
mInfo->pushConstantDescription.write(cmdbuf, layout, stage, index, value);
|
mInfo->pushConstantDescription.write(cmdbuf, layout, stage, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint64_t getVertexShaderHash() { return mVertexShaderHash;
|
||||||
|
}
|
||||||
|
inline uint64_t getFragmentShaderHash() { return mFragmentShaderHash; }
|
||||||
|
|
||||||
// TODO: handle compute shaders.
|
// TODO: handle compute shaders.
|
||||||
// The expected order of shaders - from frontend to backend - is vertex, fragment, compute.
|
// The expected order of shaders - from frontend to backend - is vertex, fragment, compute.
|
||||||
static constexpr uint8_t const MAX_SHADER_MODULES = 2;
|
static constexpr uint8_t const MAX_SHADER_MODULES = 2;
|
||||||
@@ -295,6 +301,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
PipelineInfo* mInfo;
|
PipelineInfo* mInfo;
|
||||||
|
uint64_t mVertexShaderHash;
|
||||||
|
uint64_t mFragmentShaderHash;
|
||||||
VkDevice mDevice = VK_NULL_HANDLE;
|
VkDevice mDevice = VK_NULL_HANDLE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VulkanPipelineCache.h"
|
#include "VulkanPipelineCache.h"
|
||||||
|
#include "VulkanPipelineStateSerializer.h"
|
||||||
|
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
@@ -34,49 +35,17 @@ using namespace bluevk;
|
|||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
namespace {
|
VulkanPipelineCache::VulkanPipelineCache(VkDevice device)
|
||||||
|
: mDevice(device) {
|
||||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
|
||||||
void printPipelineFeedbackInfo(VkPipelineCreationFeedbackCreateInfo const& feedbackInfo) {
|
|
||||||
VkPipelineCreationFeedback const& pipelineInfo = *feedbackInfo.pPipelineCreationFeedback;
|
|
||||||
if (!(pipelineInfo.flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool const isCacheHit =
|
|
||||||
(pipelineInfo.flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT);
|
|
||||||
FVK_LOGD << "Pipeline build stats - Cache hit: " << isCacheHit
|
|
||||||
<< ", Time: " << pipelineInfo.duration / 1000000.0 << "ms";
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < feedbackInfo.pipelineStageCreationFeedbackCount; ++i) {
|
|
||||||
VkPipelineCreationFeedback const& stageInfo = feedbackInfo.pPipelineStageCreationFeedbacks[i];
|
|
||||||
if (!(stageInfo.flags & VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool const isVertexShader = (i == 0);
|
|
||||||
bool const isCacheHit = (stageInfo.flags &
|
|
||||||
VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT);
|
|
||||||
FVK_LOGD << (isVertexShader ? "Vertex" : "Fragment")
|
|
||||||
<< " shader build stats - Cache hit: " << isCacheHit
|
|
||||||
<< ", Time: " << stageInfo.duration / 1000000.0 << "ms";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
VulkanPipelineCache::VulkanPipelineCache(VkDevice device, VulkanContext const& context)
|
|
||||||
: mDevice(device),
|
|
||||||
mContext(context) {
|
|
||||||
VkPipelineCacheCreateInfo createInfo = {
|
VkPipelineCacheCreateInfo createInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
|
||||||
};
|
};
|
||||||
bluevk::vkCreatePipelineCache(mDevice, &createInfo, VKALLOC, &mPipelineCache);
|
bluevk::vkCreatePipelineCache(mDevice, &createInfo, VKALLOC, &mPipelineCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanPipelineCache::bindLayout(VkPipelineLayout layout) noexcept {
|
void VulkanPipelineCache::bindLayout(VkPipelineLayout layout, uint32_t key) noexcept {
|
||||||
mPipelineRequirements.layout = layout;
|
mPipelineRequirements.layout = layout;
|
||||||
|
mPipelineLayoutKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::getOrCreatePipeline() noexcept {
|
VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::getOrCreatePipeline() noexcept {
|
||||||
@@ -110,6 +79,7 @@ void VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) {
|
|||||||
VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() noexcept {
|
VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() noexcept {
|
||||||
assert_invariant(mPipelineRequirements.shaders[0] && "Vertex shader is not bound.");
|
assert_invariant(mPipelineRequirements.shaders[0] && "Vertex shader is not bound.");
|
||||||
assert_invariant(mPipelineRequirements.layout && "No pipeline layout specified");
|
assert_invariant(mPipelineRequirements.layout && "No pipeline layout specified");
|
||||||
|
VulkanPipelineStateSerializer serializer(mProgramName);
|
||||||
|
|
||||||
VkPipelineShaderStageCreateInfo shaderStages[SHADER_MODULE_COUNT];
|
VkPipelineShaderStageCreateInfo shaderStages[SHADER_MODULE_COUNT];
|
||||||
shaderStages[0] = {
|
shaderStages[0] = {
|
||||||
@@ -122,6 +92,12 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
|||||||
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
shaderStages[1].module = mPipelineRequirements.shaders[1];
|
shaderStages[1].module = mPipelineRequirements.shaders[1];
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer::ShaderStageInfo vtx = { shaderStages[0].stage, mVertexShaderHash,
|
||||||
|
shaderStages[0].pName };
|
||||||
|
VulkanPipelineStateSerializer::ShaderStageInfo frg = { shaderStages[1].stage, mFragmentShaderHash,
|
||||||
|
shaderStages[1].pName };
|
||||||
|
serializer << vtx << frg;
|
||||||
|
|
||||||
bool const hasFragmentShader = shaderStages[1].module != VK_NULL_HANDLE;
|
bool const hasFragmentShader = shaderStages[1].module != VK_NULL_HANDLE;
|
||||||
|
|
||||||
VkPipelineColorBlendAttachmentState colorBlendAttachments[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT];
|
VkPipelineColorBlendAttachmentState colorBlendAttachments[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT];
|
||||||
@@ -140,9 +116,11 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
|||||||
for (uint32_t i = 0; i < VERTEX_ATTRIBUTE_COUNT; i++) {
|
for (uint32_t i = 0; i < VERTEX_ATTRIBUTE_COUNT; i++) {
|
||||||
if (mPipelineRequirements.vertexAttributes[i].format > 0) {
|
if (mPipelineRequirements.vertexAttributes[i].format > 0) {
|
||||||
vertexAttributes[numVertexAttribs++] = mPipelineRequirements.vertexAttributes[i];
|
vertexAttributes[numVertexAttribs++] = mPipelineRequirements.vertexAttributes[i];
|
||||||
|
serializer << mPipelineRequirements.vertexAttributes[i];
|
||||||
}
|
}
|
||||||
if (mPipelineRequirements.vertexBuffers[i].stride > 0) {
|
if (mPipelineRequirements.vertexBuffers[i].stride > 0) {
|
||||||
vertexBuffers[numVertexBuffers++] = mPipelineRequirements.vertexBuffers[i];
|
vertexBuffers[numVertexBuffers++] = mPipelineRequirements.vertexBuffers[i];
|
||||||
|
serializer << mPipelineRequirements.vertexBuffers[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VkPipelineVertexInputStateCreateInfo vertexInputState = {
|
VkPipelineVertexInputStateCreateInfo vertexInputState = {
|
||||||
@@ -156,11 +134,15 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
|||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||||
.topology = (VkPrimitiveTopology) mPipelineRequirements.topology,
|
.topology = (VkPrimitiveTopology) mPipelineRequirements.topology,
|
||||||
};
|
};
|
||||||
|
serializer << inputAssemblyState;
|
||||||
|
|
||||||
VkPipelineViewportStateCreateInfo viewportState = {
|
VkPipelineViewportStateCreateInfo viewportState = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||||
.viewportCount = 1,
|
.viewportCount = 1,
|
||||||
.scissorCount = 1,
|
.scissorCount = 1,
|
||||||
};
|
};
|
||||||
|
serializer << viewportState;
|
||||||
|
|
||||||
VkDynamicState dynamicStateEnables[] = {
|
VkDynamicState dynamicStateEnables[] = {
|
||||||
VK_DYNAMIC_STATE_VIEWPORT,
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
VK_DYNAMIC_STATE_SCISSOR,
|
VK_DYNAMIC_STATE_SCISSOR,
|
||||||
@@ -170,6 +152,8 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
|||||||
.dynamicStateCount = 2,
|
.dynamicStateCount = 2,
|
||||||
.pDynamicStates = dynamicStateEnables,
|
.pDynamicStates = dynamicStateEnables,
|
||||||
};
|
};
|
||||||
|
serializer << dynamicState;
|
||||||
|
|
||||||
auto const& raster = mPipelineRequirements.rasterState;
|
auto const& raster = mPipelineRequirements.rasterState;
|
||||||
VkPipelineRasterizationStateCreateInfo vkRaster = {
|
VkPipelineRasterizationStateCreateInfo vkRaster = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||||
@@ -183,6 +167,8 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
|||||||
.depthBiasSlopeFactor = raster.depthBiasSlopeFactor,
|
.depthBiasSlopeFactor = raster.depthBiasSlopeFactor,
|
||||||
.lineWidth = 1.0f,
|
.lineWidth = 1.0f,
|
||||||
};
|
};
|
||||||
|
serializer << vkRaster;
|
||||||
|
|
||||||
VkPipelineMultisampleStateCreateInfo vkMs = {
|
VkPipelineMultisampleStateCreateInfo vkMs = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
.rasterizationSamples = (VkSampleCountFlagBits) raster.rasterizationSamples,
|
.rasterizationSamples = (VkSampleCountFlagBits) raster.rasterizationSamples,
|
||||||
@@ -191,6 +177,8 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
|||||||
.alphaToCoverageEnable = raster.alphaToCoverageEnable,
|
.alphaToCoverageEnable = raster.alphaToCoverageEnable,
|
||||||
.alphaToOneEnable = VK_FALSE,
|
.alphaToOneEnable = VK_FALSE,
|
||||||
};
|
};
|
||||||
|
serializer << vkMs;
|
||||||
|
|
||||||
VkPipelineDepthStencilStateCreateInfo vkDs = {
|
VkPipelineDepthStencilStateCreateInfo vkDs = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||||
.depthTestEnable = VK_TRUE,
|
.depthTestEnable = VK_TRUE,
|
||||||
@@ -210,6 +198,12 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
|||||||
.writeMask = 0u,
|
.writeMask = 0u,
|
||||||
.reference = 0u,
|
.reference = 0u,
|
||||||
};
|
};
|
||||||
|
serializer << vkDs;
|
||||||
|
|
||||||
|
//layout
|
||||||
|
serializer.setPipelineLayoutKey(mPipelineLayoutKey);
|
||||||
|
// renderPass
|
||||||
|
serializer.setRenderPassKey(mRenderPassKey);
|
||||||
|
|
||||||
VkGraphicsPipelineCreateInfo pipelineCreateInfo = {
|
VkGraphicsPipelineCreateInfo pipelineCreateInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
@@ -248,52 +242,36 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
|||||||
colorBlendAttachments[i] = colorBlendAttachments[0];
|
colorBlendAttachments[i] = colorBlendAttachments[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
serializer << colorBlendState;
|
||||||
|
|
||||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||||
FVK_LOGD << "vkCreateGraphicsPipelines with shaders = (" << shaderStages[0].module << ", "
|
FVK_LOGD << "vkCreateGraphicsPipelines with shaders = ("
|
||||||
<< shaderStages[1].module << ")";
|
<< shaderStages[0].module << ", " << shaderStages[1].module << ")";
|
||||||
|
#endif
|
||||||
VkPipelineCreationFeedback stageFeedbacks[SHADER_MODULE_COUNT] = {};
|
|
||||||
VkPipelineCreationFeedback pipelineFeedback = {};
|
|
||||||
VkPipelineCreationFeedbackCreateInfo feedbackInfo = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.pPipelineCreationFeedback = &pipelineFeedback,
|
|
||||||
.pipelineStageCreationFeedbackCount = hasFragmentShader ? SHADER_MODULE_COUNT : 1,
|
|
||||||
.pPipelineStageCreationFeedbacks = stageFeedbacks,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (mContext.pipelineCreationFeedbackSupported()) {
|
|
||||||
feedbackInfo.pNext = pipelineCreateInfo.pNext;
|
|
||||||
pipelineCreateInfo.pNext = &feedbackInfo;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
PipelineCacheEntry cacheEntry = {
|
PipelineCacheEntry cacheEntry = {
|
||||||
.lastUsed = mCurrentTime,
|
.lastUsed = mCurrentTime,
|
||||||
};
|
};
|
||||||
VkResult error = vkCreateGraphicsPipelines(mDevice, mPipelineCache, 1, &pipelineCreateInfo,
|
VkResult error = vkCreateGraphicsPipelines(mDevice, mPipelineCache, 1, &pipelineCreateInfo,
|
||||||
VKALLOC, &cacheEntry.handle);
|
VKALLOC, &cacheEntry.handle);
|
||||||
|
|
||||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
|
||||||
FVK_LOGD << "vkCreateGraphicsPipelines with shaders = (" << shaderStages[0].module << ", "
|
|
||||||
<< shaderStages[1].module << ")";
|
|
||||||
|
|
||||||
if (mContext.pipelineCreationFeedbackSupported()) {
|
|
||||||
printPipelineFeedbackInfo(feedbackInfo);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
assert_invariant(error == VK_SUCCESS);
|
assert_invariant(error == VK_SUCCESS);
|
||||||
if (error != VK_SUCCESS) {
|
if (error != VK_SUCCESS) {
|
||||||
FVK_LOGE << "vkCreateGraphicsPipelines error " << error;
|
FVK_LOGE << "vkCreateGraphicsPipelines error " << error;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PipelineHashFn hashFunc;
|
||||||
|
|
||||||
|
serializer.setID(hashFunc(mPipelineRequirements));
|
||||||
return &mPipelines.emplace(mPipelineRequirements, cacheEntry).first.value();
|
return &mPipelines.emplace(mPipelineRequirements, cacheEntry).first.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanPipelineCache::bindProgram(fvkmemory::resource_ptr<VulkanProgram> program) noexcept {
|
void VulkanPipelineCache::bindProgram(fvkmemory::resource_ptr<VulkanProgram> program) noexcept {
|
||||||
mPipelineRequirements.shaders[0] = program->getVertexShader();
|
mPipelineRequirements.shaders[0] = program->getVertexShader();
|
||||||
mPipelineRequirements.shaders[1] = program->getFragmentShader();
|
mPipelineRequirements.shaders[1] = program->getFragmentShader();
|
||||||
|
mProgramName = program->name;
|
||||||
|
mVertexShaderHash = program->getVertexShaderHash();
|
||||||
|
mFragmentShaderHash= program->getFragmentShaderHash();
|
||||||
|
|
||||||
|
|
||||||
// If this is a debug build, validate the current shader.
|
// If this is a debug build, validate the current shader.
|
||||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||||
@@ -308,9 +286,10 @@ void VulkanPipelineCache::bindRasterState(RasterState const& rasterState) noexce
|
|||||||
mPipelineRequirements.rasterState = rasterState;
|
mPipelineRequirements.rasterState = rasterState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanPipelineCache::bindRenderPass(VkRenderPass renderPass, int subpassIndex) noexcept {
|
void VulkanPipelineCache::bindRenderPass(VkRenderPass renderPass, uint32_t passKey, int subpassIndex) noexcept {
|
||||||
mPipelineRequirements.renderPass = renderPass;
|
mPipelineRequirements.renderPass = renderPass;
|
||||||
mPipelineRequirements.subpassIndex = subpassIndex;
|
mPipelineRequirements.subpassIndex = subpassIndex;
|
||||||
|
mRenderPassKey = passKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanPipelineCache::bindPrimitiveTopology(VkPrimitiveTopology topology) noexcept {
|
void VulkanPipelineCache::bindPrimitiveTopology(VkPrimitiveTopology topology) noexcept {
|
||||||
|
|||||||
@@ -86,9 +86,9 @@ public:
|
|||||||
|
|
||||||
static_assert(sizeof(RasterState) == 16, "RasterState must not have implicit padding.");
|
static_assert(sizeof(RasterState) == 16, "RasterState must not have implicit padding.");
|
||||||
|
|
||||||
VulkanPipelineCache(VkDevice device, VulkanContext const& context);
|
VulkanPipelineCache(VkDevice device);
|
||||||
|
|
||||||
void bindLayout(VkPipelineLayout layout) noexcept;
|
void bindLayout(VkPipelineLayout layout, uint32_t key) noexcept;
|
||||||
|
|
||||||
// Creates a new pipeline if necessary and binds it using vkCmdBindPipeline.
|
// Creates a new pipeline if necessary and binds it using vkCmdBindPipeline.
|
||||||
void bindPipeline(VulkanCommandBuffer* commands);
|
void bindPipeline(VulkanCommandBuffer* commands);
|
||||||
@@ -96,7 +96,7 @@ public:
|
|||||||
// Each of the following methods are fast and do not make Vulkan calls.
|
// Each of the following methods are fast and do not make Vulkan calls.
|
||||||
void bindProgram(fvkmemory::resource_ptr<VulkanProgram> program) noexcept;
|
void bindProgram(fvkmemory::resource_ptr<VulkanProgram> program) noexcept;
|
||||||
void bindRasterState(RasterState const& rasterState) noexcept;
|
void bindRasterState(RasterState const& rasterState) noexcept;
|
||||||
void bindRenderPass(VkRenderPass renderPass, int subpassIndex) noexcept;
|
void bindRenderPass(VkRenderPass renderPass, uint32_t passKey, int subpassIndex) noexcept;
|
||||||
void bindPrimitiveTopology(VkPrimitiveTopology topology) noexcept;
|
void bindPrimitiveTopology(VkPrimitiveTopology topology) noexcept;
|
||||||
void bindVertexArray(VkVertexInputAttributeDescription const* attribDesc,
|
void bindVertexArray(VkVertexInputAttributeDescription const* attribDesc,
|
||||||
VkVertexInputBindingDescription const* bufferDesc, uint8_t count);
|
VkVertexInputBindingDescription const* bufferDesc, uint8_t count);
|
||||||
@@ -207,11 +207,14 @@ private:
|
|||||||
|
|
||||||
// Current requirements for the pipeline layout, pipeline, and descriptor sets.
|
// Current requirements for the pipeline layout, pipeline, and descriptor sets.
|
||||||
PipelineKey mPipelineRequirements = {};
|
PipelineKey mPipelineRequirements = {};
|
||||||
|
utils::CString mProgramName;
|
||||||
|
uint64_t mVertexShaderHash;
|
||||||
|
uint64_t mFragmentShaderHash;
|
||||||
|
uint32_t mPipelineLayoutKey;
|
||||||
|
uint32_t mRenderPassKey;
|
||||||
|
|
||||||
// Current bindings for the pipeline and descriptor sets.
|
// Current bindings for the pipeline and descriptor sets.
|
||||||
PipelineKey mBoundPipeline = {};
|
PipelineKey mBoundPipeline = {};
|
||||||
|
|
||||||
[[maybe_unused]] VulkanContext const& mContext;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VulkanPipelineLayoutCache.h"
|
#include "VulkanPipelineLayoutCache.h"
|
||||||
|
#include "VulkanDescriptorSetLayoutSerializer.h"
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -23,7 +24,11 @@ VkPipelineLayout VulkanPipelineLayoutCache::getLayout(
|
|||||||
fvkmemory::resource_ptr<VulkanProgram> program) {
|
fvkmemory::resource_ptr<VulkanProgram> program) {
|
||||||
PipelineLayoutKey key = {};
|
PipelineLayoutKey key = {};
|
||||||
uint8_t descSetLayoutCount = 0;
|
uint8_t descSetLayoutCount = 0;
|
||||||
key.descSetLayouts = descriptorSetLayouts;
|
DescriptorSetLayoutHashArray hashArray;
|
||||||
|
for (uint32_t i = 0; i < descriptorSetLayouts.size(); ++i) {
|
||||||
|
hashArray[i] = mDescriptorSetCache->getKey(descriptorSetLayouts[i]);
|
||||||
|
}
|
||||||
|
key.descSetLayouts = hashArray;
|
||||||
for (auto layoutHandle: descriptorSetLayouts) {
|
for (auto layoutHandle: descriptorSetLayouts) {
|
||||||
if (layoutHandle == VK_NULL_HANDLE) {
|
if (layoutHandle == VK_NULL_HANDLE) {
|
||||||
break;
|
break;
|
||||||
@@ -62,11 +67,14 @@ VkPipelineLayout VulkanPipelineLayoutCache::getLayout(
|
|||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.setLayoutCount = (uint32_t) descSetLayoutCount,
|
.setLayoutCount = (uint32_t) descSetLayoutCount,
|
||||||
.pSetLayouts = key.descSetLayouts.data(),
|
.pSetLayouts = descriptorSetLayouts.data(),
|
||||||
.pushConstantRangeCount = pushConstantRangeCount,
|
.pushConstantRangeCount = pushConstantRangeCount,
|
||||||
.pPushConstantRanges = pushConstantRanges,
|
.pPushConstantRanges = pushConstantRanges,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PipelineLayoutKeyHashFn hashFunc;
|
||||||
|
uint32_t hashedKey = hashFunc(key);
|
||||||
|
VulkanPipelineLayoutSerializer pipelineSer(info, mDescriptorSetCache, hashedKey);
|
||||||
VkPipelineLayout layout;
|
VkPipelineLayout layout;
|
||||||
vkCreatePipelineLayout(mDevice, &info, VKALLOC, &layout);
|
vkCreatePipelineLayout(mDevice, &info, VKALLOC, &layout);
|
||||||
|
|
||||||
@@ -74,6 +82,8 @@ VkPipelineLayout VulkanPipelineLayoutCache::getLayout(
|
|||||||
.handle = layout,
|
.handle = layout,
|
||||||
.lastUsed = mTimestamp++,
|
.lastUsed = mTimestamp++,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mPipelineToKey[layout] = hashedKey;
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#define TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
#define TNT_FILAMENT_BACKEND_VULKANPIPELINELAYOUTCACHE_H
|
||||||
|
|
||||||
#include "VulkanHandles.h"
|
#include "VulkanHandles.h"
|
||||||
|
#include "VulkanDescriptorSetLayoutCache.h"
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
|
|
||||||
@@ -30,10 +31,11 @@ namespace filament::backend {
|
|||||||
class VulkanPipelineLayoutCache {
|
class VulkanPipelineLayoutCache {
|
||||||
public:
|
public:
|
||||||
using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
|
using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray;
|
||||||
|
using DescriptorSetLayoutHashArray = VulkanDescriptorSetLayout::DescriptorSetLayoutHashArray;
|
||||||
|
|
||||||
VulkanPipelineLayoutCache(VkDevice device)
|
VulkanPipelineLayoutCache(VkDevice device, VulkanDescriptorSetLayoutCache* cache)
|
||||||
: mDevice(device),
|
: mDevice(device),
|
||||||
mTimestamp(0) {}
|
mTimestamp(0), mDescriptorSetCache(cache) {}
|
||||||
|
|
||||||
void terminate() noexcept;
|
void terminate() noexcept;
|
||||||
|
|
||||||
@@ -45,7 +47,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct PipelineLayoutKey {
|
struct PipelineLayoutKey {
|
||||||
DescriptorSetLayoutArray descSetLayouts = {}; // 8 * 4
|
DescriptorSetLayoutHashArray descSetLayouts = {}; // 8 * 4
|
||||||
PushConstantKey pushConstant[Program::SHADER_TYPE_COUNT] = {}; // 2 * 3
|
PushConstantKey pushConstant[Program::SHADER_TYPE_COUNT] = {}; // 2 * 3
|
||||||
uint16_t padding = 0;
|
uint16_t padding = 0;
|
||||||
};
|
};
|
||||||
@@ -58,6 +60,14 @@ public:
|
|||||||
// are described in the program.
|
// are described in the program.
|
||||||
VkPipelineLayout getLayout(DescriptorSetLayoutArray const& descriptorSetLayouts,
|
VkPipelineLayout getLayout(DescriptorSetLayoutArray const& descriptorSetLayouts,
|
||||||
fvkmemory::resource_ptr<VulkanProgram> program);
|
fvkmemory::resource_ptr<VulkanProgram> program);
|
||||||
|
uint32_t getKey(VkPipelineLayout layout) {
|
||||||
|
uint32_t key = 0;
|
||||||
|
auto iter = mPipelineToKey.find(layout);
|
||||||
|
if (iter != mPipelineToKey.end()) {
|
||||||
|
key = iter->second;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using Timestamp = uint64_t;
|
using Timestamp = uint64_t;
|
||||||
@@ -79,6 +89,8 @@ private:
|
|||||||
VkDevice mDevice;
|
VkDevice mDevice;
|
||||||
Timestamp mTimestamp;
|
Timestamp mTimestamp;
|
||||||
PipelineLayoutMap mPipelineLayouts;
|
PipelineLayoutMap mPipelineLayouts;
|
||||||
|
std::map<VkPipelineLayout, uint32_t> mPipelineToKey;
|
||||||
|
VulkanDescriptorSetLayoutCache* mDescriptorSetCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // filament::backend
|
} // filament::backend
|
||||||
|
|||||||
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "VulkanPipelineStateSerializer.h"
|
||||||
|
#include <utils/Log.h>
|
||||||
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
|
#include "VulkanConstants.h"
|
||||||
|
#include "VulkanHandles.h"
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
// Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer
|
||||||
|
// to a stack-allocated variable.
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wreturn-stack-address"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace bluevk;
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer::VulkanPipelineStateSerializer(const utils::CString& name) {
|
||||||
|
mBuffer << "{" << std::endl;
|
||||||
|
mBuffer << "\"program_name\":" << "\"" << name.c_str() << "\"" << "," << std::endl;
|
||||||
|
}
|
||||||
|
VulkanPipelineStateSerializer::~VulkanPipelineStateSerializer() {
|
||||||
|
//Shader Modules
|
||||||
|
mBuffer << "\"shader_modules\":[" << std::endl;
|
||||||
|
for (uint32_t i = 0; i < mShaderStages.size(); ++i) {
|
||||||
|
mBuffer << "{" << std::endl;
|
||||||
|
mBuffer << "\"stage\":" << mShaderStages[i].stage << "," << std::endl;
|
||||||
|
mBuffer << "\"key\":" << mShaderStages[i].module << "," << std::endl;
|
||||||
|
mBuffer << "\"name\":" << "\"" << mShaderStages[i].mName << "\"" << std::endl;
|
||||||
|
mBuffer << "}";
|
||||||
|
if (i < mShaderStages.size() - 1) {
|
||||||
|
mBuffer << ",";
|
||||||
|
}
|
||||||
|
mBuffer << std::endl;
|
||||||
|
}
|
||||||
|
mBuffer << "]," << std::endl;
|
||||||
|
|
||||||
|
//Vertex Attribute
|
||||||
|
mBuffer << "\"vertex_attributes\":[" << std::endl;
|
||||||
|
for (uint32_t i = 0; i < mVtxAttribs.size(); ++i) {
|
||||||
|
mBuffer << "{" << std::endl;
|
||||||
|
mBuffer << "\"location\":" << mVtxAttribs[i].location << "," << std::endl;
|
||||||
|
mBuffer << "\"binding\":" << mVtxAttribs[i].binding << "," << std::endl;
|
||||||
|
mBuffer << "\"format\":" << mVtxAttribs[i].format << "," << std::endl;
|
||||||
|
mBuffer << "\"offset\":" << mVtxAttribs[i].offset << std::endl;
|
||||||
|
mBuffer << "}";
|
||||||
|
if (i < mVtxAttribs.size() - 1) {
|
||||||
|
mBuffer << ",";
|
||||||
|
}
|
||||||
|
mBuffer << std::endl;
|
||||||
|
}
|
||||||
|
mBuffer << "]," << std::endl;
|
||||||
|
|
||||||
|
// Vertex Bindings
|
||||||
|
mBuffer << "\"vertex_bindings\":[" << std::endl;
|
||||||
|
for (uint32_t i = 0; i < mVtxBindings.size(); ++i) {
|
||||||
|
mBuffer << "{" << std::endl;
|
||||||
|
mBuffer << "\"binding\":" << mVtxBindings[i].binding << "," << std::endl;
|
||||||
|
mBuffer << "\"stride\":" << mVtxBindings[i].stride << "," << std::endl;
|
||||||
|
mBuffer << "\"input_rate\":" << mVtxBindings[i].inputRate << std::endl;
|
||||||
|
mBuffer << "}";
|
||||||
|
if (i < mVtxBindings.size() - 1) {
|
||||||
|
mBuffer << ",";
|
||||||
|
}
|
||||||
|
mBuffer << std::endl;
|
||||||
|
}
|
||||||
|
mBuffer << "]" << std::endl;
|
||||||
|
|
||||||
|
mBuffer << "}" << std::endl;
|
||||||
|
|
||||||
|
std::ofstream file(mFileName);
|
||||||
|
if (file.is_open()) {
|
||||||
|
file << mBuffer.str();
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanPipelineStateSerializer::setPipelineLayoutKey(uint32_t pipelineLayoutKey) {
|
||||||
|
mBuffer << "\"layout\":" << pipelineLayoutKey << "," << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanPipelineStateSerializer::setRenderPassKey(uint32_t renderPassKey) {
|
||||||
|
mBuffer << "\"render_pass\":" << renderPassKey << "," << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanPipelineStateSerializer::setID(uint32_t key) {
|
||||||
|
std::stringstream temp;
|
||||||
|
temp << "pipeline_" << key << ".json";
|
||||||
|
temp >> mFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer& VulkanPipelineStateSerializer::operator<<(
|
||||||
|
const VkPipelineInputAssemblyStateCreateInfo& inputAsm) {
|
||||||
|
mBuffer << "\"topology\":" << inputAsm.topology << "," << std::endl;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer& VulkanPipelineStateSerializer::operator<<(
|
||||||
|
const VkPipelineViewportStateCreateInfo& viewport) {
|
||||||
|
mBuffer << "\"viewport_count\":" << viewport.viewportCount << "," << std::endl;
|
||||||
|
mBuffer << "\"scissor_count\":" << viewport.scissorCount << "," << std::endl;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer& VulkanPipelineStateSerializer::operator<<(
|
||||||
|
const VkPipelineRasterizationStateCreateInfo& rasterState) {
|
||||||
|
mBuffer << "\"raster_states\":{" << std::endl;
|
||||||
|
mBuffer << "\"depth_clamp_enable\":" << rasterState.depthClampEnable << "," << std::endl;
|
||||||
|
mBuffer << "\"polygon_mode\":" << rasterState.polygonMode << "," << std::endl;
|
||||||
|
mBuffer << "\"cull_mode\":" << rasterState.cullMode << "," << std::endl;
|
||||||
|
mBuffer << "\"front_face\":" << rasterState.frontFace << "," << std::endl;
|
||||||
|
mBuffer << "\"depth_bias_enable\":" << rasterState.depthBiasEnable << "," << std::endl;
|
||||||
|
mBuffer << "\"depth_bias_constant_factor\":" << rasterState.depthBiasConstantFactor << ","
|
||||||
|
<< std::endl;
|
||||||
|
mBuffer << "\"depth_bias_clamp\":" << rasterState.depthBiasClamp << "," << std::endl;
|
||||||
|
mBuffer << "\"depth_bias_slope_factor\":" << rasterState.depthBiasSlopeFactor << "," << std::endl;
|
||||||
|
mBuffer << "\"line_width\":" << rasterState.lineWidth << std::endl;
|
||||||
|
mBuffer << "}," << std::endl;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer& VulkanPipelineStateSerializer::operator<<(
|
||||||
|
const VkPipelineDepthStencilStateCreateInfo& depthStencil) {
|
||||||
|
mBuffer << "\"depth_stencil_states\":{" << std::endl;
|
||||||
|
mBuffer << "\"depth_test_enable\":" << depthStencil.depthTestEnable << "," << std::endl;
|
||||||
|
mBuffer << "\"depth_write_enable\":" << depthStencil.depthWriteEnable << "," << std::endl;
|
||||||
|
mBuffer << "\"depth_compare_op\":" << depthStencil.depthCompareOp << "," << std::endl;
|
||||||
|
mBuffer << "\"depth_bounds_test_enable\":" << depthStencil.depthBoundsTestEnable << ","
|
||||||
|
<< std::endl;
|
||||||
|
mBuffer << "\"min_depth_bounds\":" << depthStencil.minDepthBounds << "," << std::endl;
|
||||||
|
mBuffer << "\"max_depth_bounds\":" << depthStencil.maxDepthBounds << "," << std::endl;
|
||||||
|
mBuffer << "\"front\":{" << std::endl;
|
||||||
|
mBuffer << "\"fail_op\":" << depthStencil.front.failOp << "," << std::endl;
|
||||||
|
mBuffer << "\"pass_op\":" << depthStencil.front.passOp << "," << std::endl;
|
||||||
|
mBuffer << "\"depth_fail_op\":" << depthStencil.front.depthFailOp << "," << std::endl;
|
||||||
|
mBuffer << "\"compare_op\":" << depthStencil.front.compareOp << "," << std::endl;
|
||||||
|
mBuffer << "\"compare_mask\":" << depthStencil.front.compareMask << "," << std::endl;
|
||||||
|
mBuffer << "\"write_mask\":" << depthStencil.front.writeMask << "," << std::endl;
|
||||||
|
mBuffer << "\"reference\":" << depthStencil.front.reference << std::endl;
|
||||||
|
mBuffer << "}," << std::endl;
|
||||||
|
mBuffer << "\"back\":{" << std::endl;
|
||||||
|
mBuffer << "\"fail_op\":" << depthStencil.back.failOp << "," << std::endl;
|
||||||
|
mBuffer << "\"pass_op\":" << depthStencil.back.passOp << "," << std::endl;
|
||||||
|
mBuffer << "\"depth_fail_op\":" << depthStencil.back.depthFailOp << "," << std::endl;
|
||||||
|
mBuffer << "\"compare_op\":" << depthStencil.back.compareOp << "," << std::endl;
|
||||||
|
mBuffer << "\"compare_mask\":" << depthStencil.back.compareMask << "," << std::endl;
|
||||||
|
mBuffer << "\"write_mask\":" << depthStencil.back.writeMask << "," << std::endl;
|
||||||
|
mBuffer << "\"reference\":" << depthStencil.back.reference << std::endl;
|
||||||
|
mBuffer << "}" << std::endl;
|
||||||
|
mBuffer << "}," << std::endl;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer& VulkanPipelineStateSerializer::operator<<(
|
||||||
|
const VkPipelineMultisampleStateCreateInfo& multiSample) {
|
||||||
|
mBuffer << "\"multisample_states\":{" << std::endl;
|
||||||
|
mBuffer << "\"rasterization_samples\":" << multiSample.rasterizationSamples << "," << std::endl;
|
||||||
|
mBuffer << "\"sample_shading_enable\":" << multiSample.sampleShadingEnable << "," << std::endl;
|
||||||
|
mBuffer << "\"min_sample_shading\":" << multiSample.minSampleShading << "," << std::endl;
|
||||||
|
mBuffer << "\"alpha_to_coverage_enable\":" << multiSample.alphaToCoverageEnable << ","
|
||||||
|
<< std::endl;
|
||||||
|
mBuffer << "\"alpha_to_one_enable\":" << multiSample.alphaToOneEnable << std::endl;
|
||||||
|
mBuffer << "}," << std::endl;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer& VulkanPipelineStateSerializer::operator<<(
|
||||||
|
const VkPipelineDynamicStateCreateInfo& dyStates) {
|
||||||
|
mBuffer << "\"dynamic_states\":[" << std::endl;
|
||||||
|
for (uint32_t i = 0; i < dyStates.dynamicStateCount; ++i) {
|
||||||
|
mBuffer << dyStates.pDynamicStates[i];
|
||||||
|
if (i < dyStates.dynamicStateCount - 1) {
|
||||||
|
mBuffer << ",";
|
||||||
|
}
|
||||||
|
mBuffer << std::endl;
|
||||||
|
}
|
||||||
|
mBuffer << "]," << std::endl;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer& VulkanPipelineStateSerializer::operator<<(
|
||||||
|
const VkPipelineColorBlendStateCreateInfo& blendStateInfo) {
|
||||||
|
mBuffer << "\"color_blend_state_attachments\":[" << std::endl;
|
||||||
|
for (uint32_t i = 0; i < blendStateInfo.attachmentCount; ++i) {
|
||||||
|
mBuffer << "{" << std::endl;
|
||||||
|
mBuffer << "\"blend_enable\":" << blendStateInfo.pAttachments[i].blendEnable << ","
|
||||||
|
<< std::endl;
|
||||||
|
mBuffer << "\"src_color_blend_factor\":" << blendStateInfo.pAttachments[i].srcColorBlendFactor
|
||||||
|
<< ","
|
||||||
|
<< std::endl;
|
||||||
|
mBuffer << "\"dst_color_blend_factor\":" << blendStateInfo.pAttachments[i].dstColorBlendFactor
|
||||||
|
<< ","
|
||||||
|
<< std::endl;
|
||||||
|
mBuffer << "\"color_blend_op\":" << blendStateInfo.pAttachments[i].colorBlendOp << ","
|
||||||
|
<< std::endl;
|
||||||
|
mBuffer << "\"src_alpha_blend_factor\":" << blendStateInfo.pAttachments[i].srcAlphaBlendFactor
|
||||||
|
<< ","
|
||||||
|
<< std::endl;
|
||||||
|
mBuffer << "\"dst_alpha_blend_factor\":" << blendStateInfo.pAttachments[i].dstAlphaBlendFactor
|
||||||
|
<< ","
|
||||||
|
<< std::endl;
|
||||||
|
mBuffer << "\"alpha_blend_op\":" << blendStateInfo.pAttachments[i].alphaBlendOp << ","
|
||||||
|
<< std::endl;
|
||||||
|
mBuffer << "\"color_write_mask\":" << blendStateInfo.pAttachments[i].colorWriteMask
|
||||||
|
<< std::endl;
|
||||||
|
mBuffer << "}";
|
||||||
|
if (i < blendStateInfo.attachmentCount - 1) {
|
||||||
|
mBuffer << ",";
|
||||||
|
}
|
||||||
|
mBuffer << std::endl;
|
||||||
|
}
|
||||||
|
mBuffer << "]," << std::endl;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer& VulkanPipelineStateSerializer::operator<<(
|
||||||
|
const ShaderStageInfo& shaderStages) {
|
||||||
|
mShaderStages.push_back(shaderStages);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer& VulkanPipelineStateSerializer::operator<<(
|
||||||
|
const VkVertexInputAttributeDescription& attrib) {
|
||||||
|
mVtxAttribs.push_back(attrib);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
VulkanPipelineStateSerializer& VulkanPipelineStateSerializer::operator<<(
|
||||||
|
const VkVertexInputBindingDescription& binding) {
|
||||||
|
mVtxBindings.push_back(binding);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_FILAMENT_BACKEND_VULKANPIPELINESTATESERIALIZER_H
|
||||||
|
#define TNT_FILAMENT_BACKEND_VULKANPIPELINESTATESERIALIZER_H
|
||||||
|
|
||||||
|
#include "VulkanCommands.h"
|
||||||
|
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
#include <backend/TargetBufferInfo.h>
|
||||||
|
|
||||||
|
#include <bluevk/BlueVK.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
// VulkanPipelineStateSerializer stores to a file the pipeline states.
|
||||||
|
class VulkanPipelineStateSerializer {
|
||||||
|
public:
|
||||||
|
VulkanPipelineStateSerializer(VulkanPipelineStateSerializer const&) = delete;
|
||||||
|
VulkanPipelineStateSerializer& operator=(VulkanPipelineStateSerializer const&) = delete;
|
||||||
|
|
||||||
|
VulkanPipelineStateSerializer(const utils::CString& name);
|
||||||
|
~VulkanPipelineStateSerializer();
|
||||||
|
|
||||||
|
void setID(uint32_t key);
|
||||||
|
void setPipelineLayoutKey(uint32_t pipelineLayoutKey);
|
||||||
|
void setRenderPassKey(uint32_t renderPassKey);
|
||||||
|
VulkanPipelineStateSerializer& operator<<(
|
||||||
|
const VkPipelineInputAssemblyStateCreateInfo& inputAsm);
|
||||||
|
VulkanPipelineStateSerializer& operator<<(const VkPipelineViewportStateCreateInfo& viewport);
|
||||||
|
VulkanPipelineStateSerializer& operator<<(const VkPipelineDynamicStateCreateInfo& dyStates);
|
||||||
|
VulkanPipelineStateSerializer& operator<<(
|
||||||
|
const VkPipelineRasterizationStateCreateInfo& rasterState);
|
||||||
|
VulkanPipelineStateSerializer& operator<<(
|
||||||
|
const VkPipelineDepthStencilStateCreateInfo& depthStencil);
|
||||||
|
VulkanPipelineStateSerializer& operator<<(const VkPipelineMultisampleStateCreateInfo& multiSample);
|
||||||
|
VulkanPipelineStateSerializer& operator<<(
|
||||||
|
const VkPipelineColorBlendStateCreateInfo& blendStateInfo);
|
||||||
|
|
||||||
|
struct ShaderStageInfo {
|
||||||
|
VkShaderStageFlagBits stage;
|
||||||
|
uint64_t module;
|
||||||
|
std::string mName;
|
||||||
|
};
|
||||||
|
VulkanPipelineStateSerializer& operator<<(const ShaderStageInfo& shaderStages);
|
||||||
|
VulkanPipelineStateSerializer& operator<<(
|
||||||
|
const VkVertexInputAttributeDescription& attrib);
|
||||||
|
VulkanPipelineStateSerializer& operator<<(const VkVertexInputBindingDescription& binding);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mFileName;
|
||||||
|
std::stringstream mBuffer;
|
||||||
|
|
||||||
|
//temp data
|
||||||
|
utils::CString mProgramName;
|
||||||
|
std::vector<ShaderStageInfo> mShaderStages;
|
||||||
|
std::vector<VkVertexInputAttributeDescription> mVtxAttribs;
|
||||||
|
std::vector<VkVertexInputBindingDescription> mVtxBindings;
|
||||||
|
};
|
||||||
|
} // namespace filament::backend
|
||||||
|
|
||||||
|
#endif //TNT_FILAMENT_BACKEND_VULKANPIPELINESTATESERIALIZER_H
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "VulkanRenderPassStateSerializer.h"
|
||||||
|
#include <utils/Log.h>
|
||||||
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
|
#include "VulkanConstants.h"
|
||||||
|
#include "VulkanHandles.h"
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
// Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer
|
||||||
|
// to a stack-allocated variable.
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wreturn-stack-address"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace bluevk;
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
VulkanRenderPassStateSerializer::VulkanRenderPassStateSerializer(
|
||||||
|
const VkRenderPassCreateInfo& info, uint32_t key) {
|
||||||
|
std::stringstream filename;
|
||||||
|
filename << "render_pass_" << key << ".json";
|
||||||
|
|
||||||
|
std::ofstream file(filename.str());
|
||||||
|
if (file.is_open()) {
|
||||||
|
std::stringstream buffer;
|
||||||
|
buffer << "{" << std::endl;
|
||||||
|
buffer << "\"attachments\":[" << std::endl;
|
||||||
|
for (uint32_t i = 0; i < info.attachmentCount; ++i) {
|
||||||
|
buffer << "{" << std::endl;
|
||||||
|
buffer << "\"flags\":" << info.pAttachments[i].flags << "," << std::endl;
|
||||||
|
buffer << "\"format\":" << info.pAttachments[i].format << "," << std::endl;
|
||||||
|
buffer << "\"samples\":" << info.pAttachments[i].samples << "," << std::endl;
|
||||||
|
buffer << "\"load_op\":" << info.pAttachments[i].loadOp << "," << std::endl;
|
||||||
|
buffer << "\"store_op\":" << info.pAttachments[i].storeOp << "," << std::endl;
|
||||||
|
buffer << "\"stencil_load_op\":" << info.pAttachments[i].stencilLoadOp << "," << std::endl;
|
||||||
|
buffer << "\"stencil_store_op\":" << info.pAttachments[i].stencilStoreOp << "," << std::endl;
|
||||||
|
buffer << "\"initial_layout\":" << info.pAttachments[i].initialLayout << "," << std::endl;
|
||||||
|
buffer << "\"final_layout\":" << info.pAttachments[i].finalLayout << std::endl;
|
||||||
|
buffer << "}";
|
||||||
|
if (i < info.attachmentCount - 1) {
|
||||||
|
buffer << ",";
|
||||||
|
}
|
||||||
|
buffer << std::endl;
|
||||||
|
}
|
||||||
|
buffer << "]," << std::endl;
|
||||||
|
|
||||||
|
buffer << "\"subpasses\":[" << std::endl;
|
||||||
|
for (uint32_t i = 0; i < info.subpassCount; ++i) {
|
||||||
|
buffer << "{" << std::endl;
|
||||||
|
buffer << "\"flags\":" << info.pSubpasses[i].flags << "," << std::endl;
|
||||||
|
buffer << "\"pipeline_bind_point\":" << info.pSubpasses[i].pipelineBindPoint;
|
||||||
|
|
||||||
|
//------------depth stencil-------------------
|
||||||
|
if (info.pSubpasses[i].pDepthStencilAttachment) {
|
||||||
|
buffer << "," << std::endl;
|
||||||
|
buffer << "\"depth_stencil_attachment\":{" << std::endl;
|
||||||
|
buffer << "\"attachement\":"
|
||||||
|
<< info.pSubpasses[i].pDepthStencilAttachment->attachment << ","
|
||||||
|
<< std::endl;
|
||||||
|
buffer << "\"layout\":" << info.pSubpasses[i].pDepthStencilAttachment->layout
|
||||||
|
<< std::endl;
|
||||||
|
buffer << "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------Resolve-------------------
|
||||||
|
if (info.pSubpasses[i].pResolveAttachments) {
|
||||||
|
buffer << "," << std::endl;
|
||||||
|
buffer << "\"resolve_attachments\":[" << std::endl;
|
||||||
|
for (uint32_t j = 0; j < info.pSubpasses[i].colorAttachmentCount; ++j) {
|
||||||
|
buffer << "{" << std::endl;
|
||||||
|
buffer << "\"attachement\":"
|
||||||
|
<< info.pSubpasses[i].pResolveAttachments[j].attachment << ","
|
||||||
|
<< std::endl;
|
||||||
|
buffer << "\"layout\":" << info.pSubpasses[i].pResolveAttachments[j].layout
|
||||||
|
<< std::endl;
|
||||||
|
buffer << "}" << std::endl;
|
||||||
|
if (j < info.pSubpasses[i].colorAttachmentCount - 1) {
|
||||||
|
buffer << ",";
|
||||||
|
}
|
||||||
|
buffer << std::endl;
|
||||||
|
}
|
||||||
|
buffer << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------Color-------------------
|
||||||
|
if (info.pSubpasses[i].pColorAttachments) {
|
||||||
|
buffer << "," << std::endl;
|
||||||
|
buffer << "\"color_attachments\":[" << std::endl;
|
||||||
|
for (uint32_t j = 0; j < info.pSubpasses[i].colorAttachmentCount; ++j) {
|
||||||
|
buffer << "{" << std::endl;
|
||||||
|
buffer << "\"attachement\":"
|
||||||
|
<< info.pSubpasses[i].pColorAttachments[j].attachment << ","
|
||||||
|
<< std::endl;
|
||||||
|
buffer << "\"layout\":" << info.pSubpasses[i].pColorAttachments[j].layout
|
||||||
|
<< std::endl;
|
||||||
|
buffer << "}" << std::endl;
|
||||||
|
if (j < info.pSubpasses[i].colorAttachmentCount - 1) {
|
||||||
|
buffer << ",";
|
||||||
|
}
|
||||||
|
buffer << std::endl;
|
||||||
|
}
|
||||||
|
buffer << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------Input-------------------
|
||||||
|
if (info.pSubpasses[i].pInputAttachments) {
|
||||||
|
buffer << "," << std::endl;
|
||||||
|
buffer << "\"input_attachments\":[" << std::endl;
|
||||||
|
for (uint32_t j = 0; j < info.pSubpasses[i].inputAttachmentCount; ++j) {
|
||||||
|
buffer << "{" << std::endl;
|
||||||
|
buffer << "\"attachement\":"
|
||||||
|
<< info.pSubpasses[i].pInputAttachments[j].attachment << ","
|
||||||
|
<< std::endl;
|
||||||
|
buffer << "\"layout\":" << info.pSubpasses[i].pInputAttachments[j].layout
|
||||||
|
<< std::endl;
|
||||||
|
buffer << "}" << std::endl;
|
||||||
|
if (j < info.pSubpasses[i].inputAttachmentCount - 1) {
|
||||||
|
buffer << ",";
|
||||||
|
}
|
||||||
|
buffer << std::endl;
|
||||||
|
}
|
||||||
|
buffer << "]" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer << "}";
|
||||||
|
if (i < info.subpassCount - 1) {
|
||||||
|
buffer << ",";
|
||||||
|
}
|
||||||
|
buffer << std::endl;
|
||||||
|
}
|
||||||
|
buffer << "]" << std::endl;
|
||||||
|
|
||||||
|
buffer << "}";
|
||||||
|
file << buffer.str();
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_FILAMENT_BACKEND_VULKANRENDERPASSSTATESERIALIZER_H
|
||||||
|
#define TNT_FILAMENT_BACKEND_VULKANRENDERPASSSTATESERIALIZER_H
|
||||||
|
|
||||||
|
#include "VulkanCommands.h"
|
||||||
|
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
#include <backend/TargetBufferInfo.h>
|
||||||
|
|
||||||
|
#include <bluevk/BlueVK.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
class VulkanRenderPassStateSerializer {
|
||||||
|
public:
|
||||||
|
VulkanRenderPassStateSerializer(VulkanRenderPassStateSerializer const&) = delete;
|
||||||
|
VulkanRenderPassStateSerializer& operator=(VulkanRenderPassStateSerializer const&) = delete;
|
||||||
|
|
||||||
|
VulkanRenderPassStateSerializer(const VkRenderPassCreateInfo& info, uint32_t key);
|
||||||
|
};
|
||||||
|
} // namespace filament::backend
|
||||||
|
|
||||||
|
#endif //TNT_FILAMENT_BACKEND_VULKANRENDERPASSSTATESERIALIZER_H
|
||||||
@@ -21,12 +21,14 @@
|
|||||||
|
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
|
#include "VulkanSamplerStateSerializer.h"
|
||||||
|
|
||||||
using namespace bluevk;
|
using namespace bluevk;
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
VulkanSamplerCache::VulkanSamplerCache(VkDevice device)
|
VulkanSamplerCache::VulkanSamplerCache(VkDevice device, VulkanYcbcrConversionCache* conversionCache)
|
||||||
: mDevice(device) {}
|
: mDevice(device), mConversionCache(conversionCache) {}
|
||||||
|
|
||||||
VkSampler VulkanSamplerCache::getSampler(Params params) {
|
VkSampler VulkanSamplerCache::getSampler(Params params) {
|
||||||
auto iter = mCache.find(params);
|
auto iter = mCache.find(params);
|
||||||
@@ -57,11 +59,16 @@ VkSampler VulkanSamplerCache::getSampler(Params params) {
|
|||||||
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
||||||
.unnormalizedCoordinates = VK_FALSE,
|
.unnormalizedCoordinates = VK_FALSE,
|
||||||
};
|
};
|
||||||
|
VulkanSamplerStateSerializer samplerSer(params,
|
||||||
|
params.conversion != VK_NULL_HANDLE ? mConversionCache->getKey(params.conversion) : 0);
|
||||||
|
|
||||||
VkSampler sampler;
|
VkSampler sampler;
|
||||||
VkResult result = vkCreateSampler(mDevice, &samplerInfo, VKALLOC, &sampler);
|
VkResult result = vkCreateSampler(mDevice, &samplerInfo, VKALLOC, &sampler);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to create sampler."
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to create sampler."
|
||||||
<< " error=" << static_cast<int32_t>(result);
|
<< " error=" << static_cast<int32_t>(result);
|
||||||
mCache.insert({ params, sampler });
|
mCache.insert({ params, sampler });
|
||||||
|
SamplerHashFn hashFn;
|
||||||
|
mSamplerToKey[sampler] = hashFn(params);
|
||||||
return sampler;
|
return sampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_VULKANSAMPLERCACHE_H
|
#ifndef TNT_FILAMENT_BACKEND_VULKANSAMPLERCACHE_H
|
||||||
#define TNT_FILAMENT_BACKEND_VULKANSAMPLERCACHE_H
|
#define TNT_FILAMENT_BACKEND_VULKANSAMPLERCACHE_H
|
||||||
|
|
||||||
|
#include "VulkanYcbcrConversionCache.h"
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
#include <utils/Hash.h>
|
#include <utils/Hash.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
#include <tsl/robin_map.h>
|
#include <tsl/robin_map.h>
|
||||||
@@ -37,11 +39,20 @@ public:
|
|||||||
|
|
||||||
static_assert(sizeof(Params) == 16);
|
static_assert(sizeof(Params) == 16);
|
||||||
|
|
||||||
explicit VulkanSamplerCache(VkDevice device);
|
explicit VulkanSamplerCache(VkDevice device, VulkanYcbcrConversionCache* conversionCache);
|
||||||
VkSampler getSampler(Params params);
|
VkSampler getSampler(Params params);
|
||||||
|
uint32_t getKey(VkSampler sampler) {
|
||||||
|
uint32_t key = 0;
|
||||||
|
auto iter = mSamplerToKey.find(sampler);
|
||||||
|
if (iter != mSamplerToKey.end()) {
|
||||||
|
key = iter->second;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
void terminate() noexcept;
|
void terminate() noexcept;
|
||||||
private:
|
private:
|
||||||
VkDevice mDevice;
|
VkDevice mDevice;
|
||||||
|
VulkanYcbcrConversionCache* mConversionCache;
|
||||||
|
|
||||||
struct SamplerEqualTo {
|
struct SamplerEqualTo {
|
||||||
bool operator()(Params lhs, Params rhs) const noexcept {
|
bool operator()(Params lhs, Params rhs) const noexcept {
|
||||||
@@ -51,6 +62,7 @@ private:
|
|||||||
};
|
};
|
||||||
using SamplerHashFn = utils::hash::MurmurHashFn<Params>;
|
using SamplerHashFn = utils::hash::MurmurHashFn<Params>;
|
||||||
tsl::robin_map<Params, VkSampler, SamplerHashFn, SamplerEqualTo> mCache;
|
tsl::robin_map<Params, VkSampler, SamplerHashFn, SamplerEqualTo> mCache;
|
||||||
|
std::map<VkSampler, uint32_t> mSamplerToKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#include "VulkanSamplerStateSerializer.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <utils/Hash.h>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
VulkanYcbcrConversionSerializer::VulkanYcbcrConversionSerializer(
|
||||||
|
const VulkanYcbcrConversionCache::Params& params) {
|
||||||
|
using ConversionHashFn = utils::hash::MurmurHashFn<VulkanYcbcrConversionCache::Params>;
|
||||||
|
ConversionHashFn hashFn;
|
||||||
|
uint32_t key = hashFn(params);
|
||||||
|
std::stringstream filename;
|
||||||
|
filename << "ycbcr_conv_" << key << ".json";
|
||||||
|
|
||||||
|
std::ofstream file(filename.str());
|
||||||
|
if (file.is_open()) {
|
||||||
|
std::stringstream buffer;
|
||||||
|
auto const& chroma = params.conversion;
|
||||||
|
buffer << "{" << std::endl;
|
||||||
|
buffer << "\"format\":" << params.format << "," << std::endl;
|
||||||
|
buffer << "\"external_format\":" << params.externalFormat << "," << std::endl;
|
||||||
|
buffer << "\"ycbcr_model\":" << uint8_t(chroma.ycbcrModel) << "," << std::endl;
|
||||||
|
buffer << "\"ycbcr_range\":" << uint8_t(chroma.ycbcrRange) << "," << std::endl;
|
||||||
|
buffer << "\"swizzle_array\":[" << uint8_t(chroma.r) << "," << uint8_t(chroma.g) << ","
|
||||||
|
<< uint8_t(chroma.b) << "," << uint8_t(chroma.a) << "]," << std::endl;
|
||||||
|
buffer << "\"x_chroma_offset\":" << uint8_t(chroma.xChromaOffset) << "," << std::endl;
|
||||||
|
buffer << "\"y_chroma_offset\":" << uint8_t(chroma.yChromaOffset) << "," << std::endl;
|
||||||
|
buffer << "\"chroma_filter\":" << uint8_t(chroma.chromaFilter) << std::endl;
|
||||||
|
buffer << "}" << std::endl;
|
||||||
|
|
||||||
|
file << buffer.str();
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanSamplerStateSerializer::VulkanSamplerStateSerializer(const VulkanSamplerCache::Params& params, uint32_t ycbcr_conv_key) {
|
||||||
|
using ConversionHashFn = utils::hash::MurmurHashFn<VulkanSamplerCache::Params>;
|
||||||
|
ConversionHashFn hashFn;
|
||||||
|
uint32_t key = hashFn(params);
|
||||||
|
std::stringstream filename;
|
||||||
|
filename << "sampler_" << key << ".json";
|
||||||
|
|
||||||
|
std::ofstream file(filename.str());
|
||||||
|
if (file.is_open()) {
|
||||||
|
std::stringstream buffer;
|
||||||
|
auto const& samplerParams = params.sampler;
|
||||||
|
buffer << "{" << std::endl;
|
||||||
|
buffer << "\"filter_mag\":" << uint32_t(samplerParams.filterMag) << "," << std::endl;
|
||||||
|
buffer << "\"filter_min\":" << uint32_t(samplerParams.filterMin) << "," << std::endl;
|
||||||
|
buffer << "\"wrap_s\":" << uint32_t(samplerParams.wrapS) << "," << std::endl;
|
||||||
|
buffer << "\"wrap_t\":" << uint32_t(samplerParams.wrapT) << "," << std::endl;
|
||||||
|
buffer << "\"wrap_r\":" << uint32_t(samplerParams.wrapR) << "," << std::endl;
|
||||||
|
buffer << "\"anisotropy_log2\":" << uint32_t(samplerParams.anisotropyLog2) << "," << std::endl;
|
||||||
|
buffer << "\"compare_mode\":" << uint32_t(samplerParams.compareMode) << "," << std::endl;
|
||||||
|
buffer << "\"compare_func\":" << uint32_t(samplerParams.compareFunc) << "," << std::endl;
|
||||||
|
buffer << "\"ycbcr_conv_key\":" << ycbcr_conv_key << std::endl;
|
||||||
|
buffer << "}" << std::endl;
|
||||||
|
|
||||||
|
file << buffer.str();
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace filament::backend
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_FILAMENT_BACKEND_VULKANSAMPLERSTATESERIALIZER_H
|
||||||
|
#define TNT_FILAMENT_BACKEND_VULKANSAMPLERSTATESERIALIZER_H
|
||||||
|
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
#include "VulkanYcbcrConversionCache.h"
|
||||||
|
#include "VulkanSamplerCache.h"
|
||||||
|
|
||||||
|
#include <bluevk/BlueVK.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
class VulkanYcbcrConversionSerializer {
|
||||||
|
public:
|
||||||
|
VulkanYcbcrConversionSerializer(VulkanYcbcrConversionSerializer const&) = delete;
|
||||||
|
VulkanYcbcrConversionSerializer& operator=(VulkanYcbcrConversionSerializer const&) = delete;
|
||||||
|
|
||||||
|
VulkanYcbcrConversionSerializer(const VulkanYcbcrConversionCache::Params& params);
|
||||||
|
};
|
||||||
|
// VulkanPipelineStateSerializer stores to a file the pipeline states.
|
||||||
|
class VulkanSamplerStateSerializer {
|
||||||
|
public:
|
||||||
|
VulkanSamplerStateSerializer(VulkanSamplerStateSerializer const&) = delete;
|
||||||
|
VulkanSamplerStateSerializer& operator=(VulkanSamplerStateSerializer const&) = delete;
|
||||||
|
|
||||||
|
VulkanSamplerStateSerializer(const VulkanSamplerCache::Params& params, uint32_t ycbcr_conv_key);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //TNT_FILAMENT_BACKEND_VULKANSAMPLERSTATESERIALIZER_H
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VulkanYcbcrConversionCache.h"
|
#include "VulkanYcbcrConversionCache.h"
|
||||||
|
#include "VulkanSamplerStateSerializer.h"
|
||||||
|
|
||||||
#include "vulkan/VulkanConstants.h"
|
#include "vulkan/VulkanConstants.h"
|
||||||
#include "vulkan/utils/Conversion.h"
|
#include "vulkan/utils/Conversion.h"
|
||||||
@@ -53,6 +54,7 @@ VkSamplerYcbcrConversion VulkanYcbcrConversionCache::getConversion(
|
|||||||
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
|
.yChromaOffset = fvkutils::getChromaLocation(chroma.yChromaOffset),
|
||||||
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
|
.chromaFilter = fvkutils::getFilter(chroma.chromaFilter),
|
||||||
};
|
};
|
||||||
|
VulkanYcbcrConversionSerializer ycbcr_ser(params);
|
||||||
|
|
||||||
// We could put this in the platform class, but that seems like a bit of an overkill
|
// We could put this in the platform class, but that seems like a bit of an overkill
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
@@ -73,6 +75,8 @@ VkSamplerYcbcrConversion VulkanYcbcrConversionCache::getConversion(
|
|||||||
<< " error=" << static_cast<int32_t>(result);
|
<< " error=" << static_cast<int32_t>(result);
|
||||||
|
|
||||||
mCache.insert({ params, conversion });
|
mCache.insert({ params, conversion });
|
||||||
|
ConversionHashFn hashFn;
|
||||||
|
mConversionToKey[conversion] = hashFn(params);
|
||||||
return conversion;
|
return conversion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <bluevk/BlueVK.h>
|
#include <bluevk/BlueVK.h>
|
||||||
#include <tsl/robin_map.h>
|
#include <tsl/robin_map.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -40,6 +41,14 @@ public:
|
|||||||
|
|
||||||
explicit VulkanYcbcrConversionCache(VkDevice device);
|
explicit VulkanYcbcrConversionCache(VkDevice device);
|
||||||
VkSamplerYcbcrConversion getConversion(Params params);
|
VkSamplerYcbcrConversion getConversion(Params params);
|
||||||
|
uint32_t getKey(VkSamplerYcbcrConversion conv) {
|
||||||
|
uint32_t key = 0;
|
||||||
|
auto iter = mConversionToKey.find(conv);
|
||||||
|
if (iter != mConversionToKey.end()) {
|
||||||
|
key = iter->second;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
void terminate() noexcept;
|
void terminate() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -54,6 +63,7 @@ private:
|
|||||||
};
|
};
|
||||||
using ConversionHashFn = utils::hash::MurmurHashFn<Params>;
|
using ConversionHashFn = utils::hash::MurmurHashFn<Params>;
|
||||||
tsl::robin_map<Params, VkSamplerYcbcrConversion, ConversionHashFn, ConversionEqualTo> mCache;
|
tsl::robin_map<Params, VkSamplerYcbcrConversion, ConversionHashFn, ConversionEqualTo> mCache;
|
||||||
|
std::map<VkSamplerYcbcrConversion, uint32_t> mConversionToKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -228,10 +228,6 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
|||||||
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
|
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
|
||||||
#endif
|
#endif
|
||||||
VK_KHR_MULTIVIEW_EXTENSION_NAME,
|
VK_KHR_MULTIVIEW_EXTENSION_NAME,
|
||||||
|
|
||||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
|
||||||
VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME,
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
ExtensionSet exts;
|
ExtensionSet exts;
|
||||||
// Identify supported physical device extensions
|
// Identify supported physical device extensions
|
||||||
@@ -869,8 +865,6 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
|||||||
if (!mImpl->mSharedContext) {
|
if (!mImpl->mSharedContext) {
|
||||||
context.mDebugUtilsSupported = setContains(instExts, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
context.mDebugUtilsSupported = setContains(instExts, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
context.mDebugMarkersSupported = setContains(deviceExts, VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
context.mDebugMarkersSupported = setContains(deviceExts, VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
||||||
context.mPipelineCreationFeedbackSupported =
|
|
||||||
setContains(deviceExts, VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME);
|
|
||||||
} else {
|
} else {
|
||||||
VulkanSharedContext const* scontext = (VulkanSharedContext const*) sharedContext;
|
VulkanSharedContext const* scontext = (VulkanSharedContext const*) sharedContext;
|
||||||
context.mDebugUtilsSupported = scontext->debugUtilsSupported;
|
context.mDebugUtilsSupported = scontext->debugUtilsSupported;
|
||||||
@@ -879,16 +873,13 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
|||||||
|
|
||||||
// Check the availability of lazily allocated memory
|
// Check the availability of lazily allocated memory
|
||||||
context.mLazilyAllocatedMemorySupported = false;
|
context.mLazilyAllocatedMemorySupported = false;
|
||||||
// RenderDoc doesn't support lazy allocated memory
|
for (uint32_t i = 0, typeCount = context.mMemoryProperties.memoryTypeCount; i < typeCount;
|
||||||
if constexpr (!FVK_RENDERDOC_CAPTURE_MODE) {
|
++i) {
|
||||||
for (uint32_t i = 0, typeCount = context.mMemoryProperties.memoryTypeCount; i < typeCount;
|
VkMemoryType const type = context.mMemoryProperties.memoryTypes[i];
|
||||||
++i) {
|
if (type.propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
|
||||||
VkMemoryType const type = context.mMemoryProperties.memoryTypes[i];
|
context.mLazilyAllocatedMemorySupported = true;
|
||||||
if (type.propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
|
assert_invariant(type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
context.mLazilyAllocatedMemorySupported = true;
|
break;
|
||||||
assert_invariant(type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1031,8 +1022,4 @@ VkExternalFenceHandleTypeFlagBits VulkanPlatform::getFenceExportFlags() const no
|
|||||||
return static_cast<VkExternalFenceHandleTypeFlagBits>(0);
|
return static_cast<VkExternalFenceHandleTypeFlagBits>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanPlatform::isTransientAttachmentSupported() const noexcept {
|
|
||||||
return mImpl->mContext.isLazilyAllocatedMemorySupported();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -158,47 +158,7 @@ std::pair<TextureFormat, TextureUsage> getFilamentFormatAndUsage(const AHardware
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t selectMemoryTypeForExternalImage(VkPhysicalDevice physicalDevice, VkDevice device,
|
}// namespace
|
||||||
VkImage image, uint32_t types, VkFlags requiredMemoryFlags) {
|
|
||||||
VkPhysicalDeviceMemoryProperties memoryProperties;
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
|
|
||||||
uint32_t const memoryTypeIndex =
|
|
||||||
VulkanContext::selectMemoryType(memoryProperties, types, requiredMemoryFlags);
|
|
||||||
|
|
||||||
if constexpr (FVK_RENDERDOC_CAPTURE_MODE) {
|
|
||||||
// RenderDoc will replay external resources as non-external.
|
|
||||||
// Adjust properties that will trip it up when replaying, even though these are not valid.
|
|
||||||
// Update memory type index if necessary so that we can replay the capture.
|
|
||||||
|
|
||||||
VkMemoryRequirements imageMemoryRequirements;
|
|
||||||
vkGetImageMemoryRequirements(device, image, &imageMemoryRequirements);
|
|
||||||
|
|
||||||
uint32_t const imageMemoryTypeBits = imageMemoryRequirements.memoryTypeBits;
|
|
||||||
bool const isMemoryTypeSupported = ((1 << memoryTypeIndex) & imageMemoryTypeBits) != 0;
|
|
||||||
if (isMemoryTypeSupported) {
|
|
||||||
return memoryTypeIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Current memory type will not be replayable by RenderDoc.
|
|
||||||
// Attempt to change the memory type index
|
|
||||||
VkMemoryPropertyFlags const kRenderDocFallBackReqs = 0;
|
|
||||||
uint32_t commonMemoryTypeBits = types & imageMemoryTypeBits;
|
|
||||||
uint32_t commonTypeIndex = VulkanContext::selectMemoryType(memoryProperties,
|
|
||||||
commonMemoryTypeBits, kRenderDocFallBackReqs);
|
|
||||||
if (commonMemoryTypeBits && commonTypeIndex != VK_MAX_MEMORY_TYPES) {
|
|
||||||
return commonTypeIndex;
|
|
||||||
}
|
|
||||||
uint32_t imageTypeIndex = VulkanContext::selectMemoryType(memoryProperties,
|
|
||||||
imageMemoryTypeBits, kRenderDocFallBackReqs);
|
|
||||||
if (imageTypeIndex != VK_MAX_MEMORY_TYPES) {
|
|
||||||
return imageTypeIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return memoryTypeIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
VulkanPlatformAndroid::ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() {
|
VulkanPlatformAndroid::ExternalImageVulkanAndroid::~ExternalImageVulkanAndroid() {
|
||||||
if (__builtin_available(android 26, *)) {
|
if (__builtin_available(android 26, *)) {
|
||||||
@@ -394,6 +354,8 @@ VulkanPlatform::ImageData VulkanPlatformAndroid::createVkImageFromExternal(
|
|||||||
.image = image,
|
.image = image,
|
||||||
.buffer = VK_NULL_HANDLE,
|
.buffer = VK_NULL_HANDLE,
|
||||||
};
|
};
|
||||||
|
VkPhysicalDeviceMemoryProperties memoryProperties;
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
|
||||||
VkMemoryPropertyFlags requiredMemoryFlags =
|
VkMemoryPropertyFlags requiredMemoryFlags =
|
||||||
!isExternal && any(metadata.filamentUsage & TextureUsage::UPLOADABLE)
|
!isExternal && any(metadata.filamentUsage & TextureUsage::UPLOADABLE)
|
||||||
? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||||
@@ -403,8 +365,8 @@ VulkanPlatform::ImageData VulkanPlatformAndroid::createVkImageFromExternal(
|
|||||||
requiredMemoryFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
|
requiredMemoryFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t const memoryTypeIndex = selectMemoryTypeForExternalImage(physicalDevice, device,
|
uint32_t const memoryTypeIndex = VulkanContext::selectMemoryType(memoryProperties,
|
||||||
image, metadata.memoryTypeBits, requiredMemoryFlags);
|
metadata.memoryTypeBits, requiredMemoryFlags);
|
||||||
|
|
||||||
VkMemoryAllocateInfo const allocInfo = {
|
VkMemoryAllocateInfo const allocInfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ WebGPUBufferBase::WebGPUBufferBase(wgpu::Device const& device, const wgpu::Buffe
|
|||||||
// WebGPU requires that the size of the data copied from the staging buffer to the GPU buffer is a
|
// WebGPU requires that the size of the data copied from the staging buffer to the GPU buffer is a
|
||||||
// multiple of 4. This function handles cases where the buffer descriptor's size is not a multiple
|
// multiple of 4. This function handles cases where the buffer descriptor's size is not a multiple
|
||||||
// of 4 by padding with zeros.
|
// of 4 by padding with zeros.
|
||||||
void WebGPUBufferBase::updateGPUBuffer(BufferDescriptor&& bufferDescriptor,
|
void WebGPUBufferBase::updateGPUBuffer(BufferDescriptor const& bufferDescriptor,
|
||||||
const uint32_t byteOffset, wgpu::Device const& device,
|
const uint32_t byteOffset, wgpu::Device const& device,
|
||||||
WebGPUQueueManager* const webGPUQueueManager) {
|
WebGPUQueueManager* const webGPUQueueManager) {
|
||||||
FILAMENT_CHECK_PRECONDITION(bufferDescriptor.buffer)
|
FILAMENT_CHECK_PRECONDITION(bufferDescriptor.buffer)
|
||||||
@@ -89,49 +89,24 @@ void WebGPUBufferBase::updateGPUBuffer(BufferDescriptor&& bufferDescriptor,
|
|||||||
wgpu::BufferDescriptor descriptor{
|
wgpu::BufferDescriptor descriptor{
|
||||||
.label = "Filament WebGPU Staging Buffer",
|
.label = "Filament WebGPU Staging Buffer",
|
||||||
.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc,
|
.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc,
|
||||||
.size = stagingBufferSize};
|
.size = stagingBufferSize,
|
||||||
|
.mappedAtCreation = true };
|
||||||
wgpu::Buffer stagingBuffer = device.CreateBuffer(&descriptor);
|
wgpu::Buffer stagingBuffer = device.CreateBuffer(&descriptor);
|
||||||
|
|
||||||
struct UserData final {
|
void* mappedRange = stagingBuffer.GetMappedRange();
|
||||||
uint32_t byteOffset;
|
memcpy(mappedRange, bufferDescriptor.buffer, bufferDescriptor.size);
|
||||||
size_t stagingBufferSize;
|
|
||||||
size_t remainder;
|
// Make sure the padded memory is set to 0 to have deterministic behaviors
|
||||||
BufferDescriptor srcBufferDescriptor;
|
if (remainder != 0) {
|
||||||
wgpu::Buffer stagingBuffer;
|
uint8_t* paddingStart = static_cast<uint8_t*>(mappedRange) + bufferDescriptor.size;
|
||||||
WebGPUQueueManager* const webGPUQueueManager;
|
memset(paddingStart, 0, FILAMENT_WEBGPU_BUFFER_SIZE_MODULUS - remainder);
|
||||||
wgpu::Buffer dstBuffer;
|
}
|
||||||
};
|
|
||||||
auto userData = std::make_unique<UserData>(UserData{
|
stagingBuffer.Unmap();
|
||||||
.byteOffset = byteOffset,
|
|
||||||
.stagingBufferSize = stagingBufferSize,
|
// Copy the staging buffer contents to the destination buffer.
|
||||||
.remainder = remainder,
|
webGPUQueueManager->getCommandEncoder().CopyBufferToBuffer(stagingBuffer, 0, mBuffer,
|
||||||
.srcBufferDescriptor = std::move(bufferDescriptor),
|
byteOffset, stagingBufferSize);
|
||||||
.stagingBuffer = stagingBuffer,
|
|
||||||
.webGPUQueueManager = webGPUQueueManager,
|
|
||||||
.dstBuffer = mBuffer});
|
|
||||||
stagingBuffer.MapAsync(
|
|
||||||
wgpu::MapMode::Write, 0, stagingBufferSize, wgpu::CallbackMode::AllowProcessEvents,
|
|
||||||
[](wgpu::MapAsyncStatus status, const char* message, UserData* userdata) {
|
|
||||||
std::unique_ptr<UserData> data(static_cast<UserData*>(userdata));
|
|
||||||
if (UTILS_LIKELY(status == wgpu::MapAsyncStatus::Success)) {
|
|
||||||
void* mappedRange = data->stagingBuffer.GetMappedRange();
|
|
||||||
memcpy(mappedRange, data->srcBufferDescriptor.buffer,
|
|
||||||
data->srcBufferDescriptor.size);
|
|
||||||
if (data->remainder != 0) {
|
|
||||||
uint8_t* paddingStart =
|
|
||||||
static_cast<uint8_t*>(mappedRange) + data->srcBufferDescriptor.size;
|
|
||||||
memset(paddingStart, 0,
|
|
||||||
FILAMENT_WEBGPU_BUFFER_SIZE_MODULUS - data->remainder);
|
|
||||||
}
|
|
||||||
data->stagingBuffer.Unmap();
|
|
||||||
data->webGPUQueueManager->getCommandEncoder().CopyBufferToBuffer(
|
|
||||||
data->stagingBuffer, 0, data->dstBuffer, data->byteOffset,
|
|
||||||
data->stagingBufferSize);
|
|
||||||
} else {
|
|
||||||
FWGPU_LOGE << "Failed to map staging buffer for readPixels: " << message;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
userData.release());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public:
|
|||||||
* happen after draw commands encoded in the encoder. Submitting any commands up to this point
|
* happen after draw commands encoded in the encoder. Submitting any commands up to this point
|
||||||
* ensures the calls happen in the expected sequence.
|
* ensures the calls happen in the expected sequence.
|
||||||
*/
|
*/
|
||||||
void updateGPUBuffer(BufferDescriptor&&, uint32_t byteOffset, wgpu::Device const& device,
|
void updateGPUBuffer(BufferDescriptor const&, uint32_t byteOffset, wgpu::Device const& device,
|
||||||
WebGPUQueueManager* const webGPUQueueManager);
|
WebGPUQueueManager* const webGPUQueueManager);
|
||||||
|
|
||||||
[[nodiscard]] wgpu::Buffer const& getBuffer() const { return mBuffer; }
|
[[nodiscard]] wgpu::Buffer const& getBuffer() const { return mBuffer; }
|
||||||
|
|||||||
@@ -856,7 +856,7 @@ void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> indexBufferHandle,
|
|||||||
// draw calls are made.
|
// draw calls are made.
|
||||||
flush();
|
flush();
|
||||||
handleCast<WebGPUIndexBuffer>(indexBufferHandle)
|
handleCast<WebGPUIndexBuffer>(indexBufferHandle)
|
||||||
->updateGPUBuffer(std::move(bufferDescriptor), byteOffset, mDevice, &mQueueManager);
|
->updateGPUBuffer(bufferDescriptor, byteOffset, mDevice, &mQueueManager);
|
||||||
scheduleDestroy(std::move(bufferDescriptor));
|
scheduleDestroy(std::move(bufferDescriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -867,14 +867,14 @@ void WebGPUDriver::updateBufferObject(Handle<HwBufferObject> bufferObjectHandle,
|
|||||||
// draw calls are made.
|
// draw calls are made.
|
||||||
flush();
|
flush();
|
||||||
handleCast<WebGPUBufferObject>(bufferObjectHandle)
|
handleCast<WebGPUBufferObject>(bufferObjectHandle)
|
||||||
->updateGPUBuffer(std::move(bufferDescriptor), byteOffset, mDevice, &mQueueManager);
|
->updateGPUBuffer(bufferDescriptor, byteOffset, mDevice, &mQueueManager);
|
||||||
scheduleDestroy(std::move(bufferDescriptor));
|
scheduleDestroy(std::move(bufferDescriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> bufferObjectHandle,
|
void WebGPUDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> bufferObjectHandle,
|
||||||
BufferDescriptor&& bufferDescriptor, const uint32_t byteOffset) {
|
BufferDescriptor&& bufferDescriptor, const uint32_t byteOffset) {
|
||||||
handleCast<WebGPUBufferObject>(bufferObjectHandle)
|
handleCast<WebGPUBufferObject>(bufferObjectHandle)
|
||||||
->updateGPUBuffer(std::move(bufferDescriptor), byteOffset, mDevice, &mQueueManager);
|
->updateGPUBuffer(bufferDescriptor, byteOffset, mDevice, &mQueueManager);
|
||||||
scheduleDestroy(std::move(bufferDescriptor));
|
scheduleDestroy(std::move(bufferDescriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -59,7 +58,6 @@ WebGPUQueueManager::WebGPUQueueManager(wgpu::Device const& device)
|
|||||||
WebGPUQueueManager::~WebGPUQueueManager() = default;
|
WebGPUQueueManager::~WebGPUQueueManager() = default;
|
||||||
|
|
||||||
wgpu::CommandEncoder WebGPUQueueManager::getCommandEncoder() {
|
wgpu::CommandEncoder WebGPUQueueManager::getCommandEncoder() {
|
||||||
// std::unique_lock<std::mutex> lock(mLock);
|
|
||||||
if (!mCommandEncoder) {
|
if (!mCommandEncoder) {
|
||||||
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = {
|
wgpu::CommandEncoderDescriptor commandEncoderDescriptor = {
|
||||||
.label = "Filament Command Encoder",
|
.label = "Filament Command Encoder",
|
||||||
@@ -92,9 +90,7 @@ std::shared_ptr<WebGPUSubmissionState> WebGPUQueueManager::getLatestSubmissionSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUQueueManager::submit() {
|
void WebGPUQueueManager::submit() {
|
||||||
// std::unique_lock<std::mutex> lock(mLock);
|
|
||||||
if (!mCommandEncoder) {
|
if (!mCommandEncoder) {
|
||||||
std::cout << "Run Yu: no mCommandEncoder found!\n";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ private:
|
|||||||
wgpu::Queue mQueue;
|
wgpu::Queue mQueue;
|
||||||
wgpu::CommandEncoder mCommandEncoder;
|
wgpu::CommandEncoder mCommandEncoder;
|
||||||
std::shared_ptr<WebGPUSubmissionState> mLatestSubmissionState;
|
std::shared_ptr<WebGPUSubmissionState> mLatestSubmissionState;
|
||||||
std::mutex mLock;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace filament::backend
|
} // namespace filament::backend
|
||||||
|
|||||||
@@ -258,10 +258,6 @@ void PostProcessManager::bindPerRenderableDescriptorSet(DriverApi& driver) const
|
|||||||
{ { 0, 0 }, driver });
|
{ { 0, 0 }, driver });
|
||||||
}
|
}
|
||||||
|
|
||||||
UboManager* PostProcessManager::getUboManager() const noexcept {
|
|
||||||
return mEngine.getUboManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
void PostProcessManager::registerPostProcessMaterial(std::string_view const name,
|
void PostProcessManager::registerPostProcessMaterial(std::string_view const name,
|
||||||
StaticMaterialInfo const& info) {
|
StaticMaterialInfo const& info) {
|
||||||
@@ -517,7 +513,7 @@ UTILS_NOINLINE
|
|||||||
void PostProcessManager::commitAndRenderFullScreenQuad(DriverApi& driver,
|
void PostProcessManager::commitAndRenderFullScreenQuad(DriverApi& driver,
|
||||||
FrameGraphResources::RenderPassInfo const& out, FMaterialInstance const* mi,
|
FrameGraphResources::RenderPassInfo const& out, FMaterialInstance const* mi,
|
||||||
PostProcessVariant const variant) const noexcept {
|
PostProcessVariant const variant) const noexcept {
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
FMaterial const* const ma = mi->getMaterial();
|
FMaterial const* const ma = mi->getMaterial();
|
||||||
PipelineState const pipeline = getPipelineState(ma, variant);
|
PipelineState const pipeline = getPipelineState(ma, variant);
|
||||||
@@ -649,7 +645,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
|||||||
auto th = driver.createTextureView(in, level, 1);
|
auto th = driver.createTextureView(in, level, 1);
|
||||||
mi->setParameter("depth", th, SamplerParams{
|
mi->setParameter("depth", th, SamplerParams{
|
||||||
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
renderFullScreenQuad(out, pipeline, driver);
|
renderFullScreenQuad(out, pipeline, driver);
|
||||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||||
@@ -1083,7 +1079,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
|||||||
mi->setParameter("ssctRayCount",
|
mi->setParameter("ssctRayCount",
|
||||||
float2{ options.ssct.rayCount, 1.0f / float(options.ssct.rayCount) });
|
float2{ options.ssct.rayCount, 1.0f / float(options.ssct.rayCount) });
|
||||||
|
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
|
|
||||||
auto pipeline = getPipelineState(ma);
|
auto pipeline = getPipelineState(ma);
|
||||||
@@ -1204,7 +1200,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::bilateralBlurPass(FrameGraph
|
|||||||
mi->setParameter("sampleCount", kGaussianCount);
|
mi->setParameter("sampleCount", kGaussianCount);
|
||||||
mi->setParameter("farPlaneOverEdgeDistance", -zf / config.bilateralThreshold);
|
mi->setParameter("farPlaneOverEdgeDistance", -zf / config.bilateralThreshold);
|
||||||
|
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
|
|
||||||
auto pipeline = getPipelineState(ma);
|
auto pipeline = getPipelineState(ma);
|
||||||
@@ -1899,7 +1895,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
|||||||
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||||
mi->setParameter("weightScale", 0.5f / float(1u << level)); // FIXME: halfres?
|
mi->setParameter("weightScale", 0.5f / float(1u << level)); // FIXME: halfres?
|
||||||
mi->setParameter("texelSize", float2{ 1.0f / w, 1.0f / h });
|
mi->setParameter("texelSize", float2{ 1.0f / w, 1.0f / h });
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
|
|
||||||
renderFullScreenQuad(out, pipeline, driver);
|
renderFullScreenQuad(out, pipeline, driver);
|
||||||
@@ -2429,7 +2425,7 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
|
|||||||
mi->setParameter("source", hwOutView, SamplerParams{
|
mi->setParameter("source", hwOutView, SamplerParams{
|
||||||
.filterMag = SamplerMagFilter::LINEAR,
|
.filterMag = SamplerMagFilter::LINEAR,
|
||||||
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST});
|
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST});
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
renderFullScreenQuad(hwDstRT, pipeline, driver);
|
renderFullScreenQuad(hwDstRT, pipeline, driver);
|
||||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||||
@@ -2537,7 +2533,7 @@ void PostProcessManager::colorGradingPrepareSubpass(DriverApi& driver,
|
|||||||
FMaterialInstance* const mi =
|
FMaterialInstance* const mi =
|
||||||
configureColorGradingMaterial(material, colorGrading, colorGradingConfig,
|
configureColorGradingMaterial(material, colorGrading, colorGradingConfig,
|
||||||
vignetteOptions, width, height);
|
vignetteOptions, width, height);
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessManager::colorGradingSubpass(DriverApi& driver,
|
void PostProcessManager::colorGradingSubpass(DriverApi& driver,
|
||||||
@@ -2570,7 +2566,7 @@ void PostProcessManager::customResolvePrepareSubpass(DriverApi& driver, CustomRe
|
|||||||
auto [mi, fixedIndex] = mMaterialInstanceManager.getFixedMaterialInstance(ma);
|
auto [mi, fixedIndex] = mMaterialInstanceManager.getFixedMaterialInstance(ma);
|
||||||
mFixedMaterialInstanceIndex.customResolve = fixedIndex;
|
mFixedMaterialInstanceIndex.customResolve = fixedIndex;
|
||||||
mi->setParameter("direction", op == CustomResolveOp::COMPRESS ? 1.0f : -1.0f),
|
mi->setParameter("direction", op == CustomResolveOp::COMPRESS ? 1.0f : -1.0f),
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
material.getMaterial(mEngine);
|
material.getMaterial(mEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2623,7 +2619,7 @@ void PostProcessManager::clearAncillaryBuffersPrepare(DriverApi& driver) noexcep
|
|||||||
auto ma = material.getMaterial(mEngine, PostProcessVariant::OPAQUE);
|
auto ma = material.getMaterial(mEngine, PostProcessVariant::OPAQUE);
|
||||||
auto [mi, fixedIndex] = mMaterialInstanceManager.getFixedMaterialInstance(ma);
|
auto [mi, fixedIndex] = mMaterialInstanceManager.getFixedMaterialInstance(ma);
|
||||||
mFixedMaterialInstanceIndex.clearDepth = fixedIndex;
|
mFixedMaterialInstanceIndex.clearDepth = fixedIndex;
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
material.getMaterial(mEngine);
|
material.getMaterial(mEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3115,7 +3111,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
|
|||||||
mat4f{ historyProjection * inverse(current.projection) } *
|
mat4f{ historyProjection * inverse(current.projection) } *
|
||||||
normalizedToClip);
|
normalizedToClip);
|
||||||
|
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
|
|
||||||
if (colorGradingConfig.asSubpass) {
|
if (colorGradingConfig.asSubpass) {
|
||||||
@@ -3200,7 +3196,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
|
|||||||
mi->setParameter("resolution", float4{
|
mi->setParameter("resolution", float4{
|
||||||
outputDesc.width, outputDesc.height,
|
outputDesc.width, outputDesc.height,
|
||||||
1.0f / outputDesc.width, 1.0f / outputDesc.height });
|
1.0f / outputDesc.width, 1.0f / outputDesc.height });
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
|
|
||||||
auto pipeline = getPipelineState(material.getMaterial(mEngine), variant);
|
auto pipeline = getPipelineState(material.getMaterial(mEngine), variant);
|
||||||
@@ -3291,7 +3287,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph&
|
|||||||
float(vp.width) / inputDesc.width,
|
float(vp.width) / inputDesc.width,
|
||||||
float(vp.height) / inputDesc.height
|
float(vp.height) / inputDesc.height
|
||||||
});
|
});
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
|
|
||||||
auto out = resources.getRenderPassInfo();
|
auto out = resources.getRenderPassInfo();
|
||||||
@@ -3378,7 +3374,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleSGSR1(FrameGraph& fg,
|
|||||||
float(inputDesc.height)
|
float(inputDesc.height)
|
||||||
});
|
});
|
||||||
|
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
|
|
||||||
auto const out = resources.getRenderPassInfo();
|
auto const out = resources.getRenderPassInfo();
|
||||||
@@ -3473,7 +3469,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
|
|||||||
mi->setParameter("resolution",
|
mi->setParameter("resolution",
|
||||||
float4{ outputDesc.width, outputDesc.height,
|
float4{ outputDesc.width, outputDesc.height,
|
||||||
1.0f / outputDesc.width, 1.0f / outputDesc.height });
|
1.0f / outputDesc.width, 1.0f / outputDesc.height });
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3500,7 +3496,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
|
|||||||
float(vp.width) / inputDesc.width,
|
float(vp.width) / inputDesc.width,
|
||||||
float(vp.height) / inputDesc.height
|
float(vp.height) / inputDesc.height
|
||||||
});
|
});
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3586,7 +3582,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blit(FrameGraph& fg, bool co
|
|||||||
if (layer) {
|
if (layer) {
|
||||||
mi->setParameter("layerIndex", layer);
|
mi->setParameter("layerIndex", layer);
|
||||||
}
|
}
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
|
|
||||||
auto pipeline = getPipelineState(ma);
|
auto pipeline = getPipelineState(ma);
|
||||||
@@ -3844,7 +3840,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
|
|||||||
});
|
});
|
||||||
mi->setParameter("layer", uint32_t(layer));
|
mi->setParameter("layer", uint32_t(layer));
|
||||||
mi->setParameter("uvscale", 1.0f / float(dim));
|
mi->setParameter("uvscale", 1.0f / float(dim));
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
|
|
||||||
renderFullScreenQuadWithScissor(out, pipeline, scissor, driver);
|
renderFullScreenQuadWithScissor(out, pipeline, scissor, driver);
|
||||||
@@ -3946,7 +3942,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
|
|||||||
float(vp.width) / inputDesc.width,
|
float(vp.width) / inputDesc.width,
|
||||||
float(vp.height) / inputDesc.height
|
float(vp.height) / inputDesc.height
|
||||||
});
|
});
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
mi->use(driver);
|
mi->use(driver);
|
||||||
|
|
||||||
auto pipeline = getPipelineState(ma);
|
auto pipeline = getPipelineState(ma);
|
||||||
@@ -3963,7 +3959,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
|
|||||||
// Render all layers of the texture to the screen side-by-side.
|
// Render all layers of the texture to the screen side-by-side.
|
||||||
for (uint32_t i = 0; i < inputTextureDesc.depth; ++i) {
|
for (uint32_t i = 0; i < inputTextureDesc.depth; ++i) {
|
||||||
mi->setParameter("layerIndex", i);
|
mi->setParameter("layerIndex", i);
|
||||||
mi->commit(driver, getUboManager());
|
mi->commit(driver);
|
||||||
renderFullScreenQuad(out, pipeline, driver);
|
renderFullScreenQuad(out, pipeline, driver);
|
||||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||||
// From the second draw, don't clear the targetbuffer.
|
// From the second draw, don't clear the targetbuffer.
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ class FMaterialInstance;
|
|||||||
class FrameGraph;
|
class FrameGraph;
|
||||||
class RenderPass;
|
class RenderPass;
|
||||||
class RenderPassBuilder;
|
class RenderPassBuilder;
|
||||||
class UboManager;
|
|
||||||
struct CameraInfo;
|
struct CameraInfo;
|
||||||
|
|
||||||
class PostProcessManager {
|
class PostProcessManager {
|
||||||
@@ -423,8 +422,6 @@ private:
|
|||||||
return getMaterialInstance(ma);
|
return getMaterialInstance(ma);
|
||||||
}
|
}
|
||||||
|
|
||||||
UboManager* getUboManager() const noexcept;
|
|
||||||
|
|
||||||
backend::RenderPrimitiveHandle mFullScreenQuadRph;
|
backend::RenderPrimitiveHandle mFullScreenQuadRph;
|
||||||
backend::VertexBufferInfoHandle mFullScreenQuadVbih;
|
backend::VertexBufferInfoHandle mFullScreenQuadVbih;
|
||||||
backend::DescriptorSetLayoutHandle mPerRenderableDslh;
|
backend::DescriptorSetLayoutHandle mPerRenderableDslh;
|
||||||
|
|||||||
+15
-25
@@ -1012,8 +1012,6 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
|
|||||||
uint32_t const index = (first->key & CUSTOM_INDEX_MASK) >> CUSTOM_INDEX_SHIFT;
|
uint32_t const index = (first->key & CUSTOM_INDEX_MASK) >> CUSTOM_INDEX_SHIFT;
|
||||||
assert_invariant(index < mCustomCommands.size());
|
assert_invariant(index < mCustomCommands.size());
|
||||||
pCustomCommands[index]();
|
pCustomCommands[index]();
|
||||||
currentPipeline = {};
|
|
||||||
currentPrimitiveHandle ={};
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1071,34 +1069,26 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
|
|||||||
pipeline.pipelineLayout.setLayout[+DescriptorSetBindingPoints::PER_MATERIAL] =
|
pipeline.pipelineLayout.setLayout[+DescriptorSetBindingPoints::PER_MATERIAL] =
|
||||||
ma->getDescriptorSetLayout(info.materialVariant).getHandle();
|
ma->getDescriptorSetLayout(info.materialVariant).getHandle();
|
||||||
|
|
||||||
// If we have a ColorPassDescriptorSet we use it to bind the per-view
|
|
||||||
// descriptor-set (ideally only if it changed).
|
if (UTILS_UNLIKELY(ma->getMaterialDomain() == MaterialDomain::POST_PROCESS)) {
|
||||||
// If we don't, it means the descriptor-set is already bound and the layout we
|
// It is possible to get a post-process material here (even though it's
|
||||||
// got from the material above should match. This is the case for situations
|
// not technically a public API yet, it is used by the IBLPrefilterLibrary.
|
||||||
// where we have a known per-view descriptor-set layout,
|
// Ideally we would have a more formal compute API). In this case, we need
|
||||||
// e.g.: postfx, shadow-maps, ssr and structure passes.
|
// to set the post-process descriptor-set.
|
||||||
if (mColorPassDescriptorSet) {
|
engine.getPostProcessManager().bindPostProcessDescriptorSet(driver);
|
||||||
if (UTILS_UNLIKELY(ma->getMaterialDomain() == MaterialDomain::POST_PROCESS)) {
|
} else {
|
||||||
// It is possible to get a post-process material here (even though it's
|
// If we have a ColorPassDescriptorSet we use it to bind the per-view
|
||||||
// not technically a public API yet, it is used by the IBLPrefilterLibrary.
|
// descriptor-set (ideally only if it changed). If we don't, it means
|
||||||
// Ideally we would have a more formal compute API). In this case, we need
|
// the descriptor-set is already bound and the layout we got from the
|
||||||
// to set the post-process descriptor-set.
|
// material above should match. This is the case for situations where we
|
||||||
engine.getPostProcessManager().bindPostProcessDescriptorSet(driver);
|
// have a known per-view descriptor-set layout, e.g.: shadow-maps, ssr and
|
||||||
} else {
|
// structure passes.
|
||||||
|
if (mColorPassDescriptorSet) {
|
||||||
// We have a ColorPassDescriptorSet, we need to go through it for binding
|
// We have a ColorPassDescriptorSet, we need to go through it for binding
|
||||||
// the per-view descriptor-set because its layout can change based on the
|
// the per-view descriptor-set because its layout can change based on the
|
||||||
// material.
|
// material.
|
||||||
mColorPassDescriptorSet->bind(driver, ma->getPerViewLayoutIndex());
|
mColorPassDescriptorSet->bind(driver, ma->getPerViewLayoutIndex());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// if we're here it means the per-view descriptor set is constant and
|
|
||||||
// already set. This will be the case for postfx, ssr, structure and
|
|
||||||
// shadow passes. All these passes use a static descriptor set layout
|
|
||||||
// (albeit potentially different for each pass). In particular the
|
|
||||||
// per-view UBO must be compatible for all material domains.
|
|
||||||
// This is the case by construction for postfx, ssr. However, shadows
|
|
||||||
// and structure have their own UBO, but it's content is (must be)
|
|
||||||
// compatible with POST_PROCESS and COMPUTE materials.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each MaterialInstance has its own descriptor set. This binds it.
|
// Each MaterialInstance has its own descriptor set. This binds it.
|
||||||
|
|||||||
@@ -142,11 +142,7 @@ void BufferAllocator::retire(AllocationId id) {
|
|||||||
InternalSlotNode* targetNode = getNodeById(id);
|
InternalSlotNode* targetNode = getNodeById(id);
|
||||||
assert_invariant(targetNode != nullptr);
|
assert_invariant(targetNode != nullptr);
|
||||||
|
|
||||||
Slot& slot = targetNode->slot;
|
targetNode->slot.isAllocated = false;
|
||||||
slot.isAllocated = false;
|
|
||||||
if (slot.gpuUseCount == 0) {
|
|
||||||
mHasPendingFrees = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferAllocator::acquireGpu(AllocationId id) {
|
void BufferAllocator::acquireGpu(AllocationId id) {
|
||||||
@@ -161,18 +157,10 @@ void BufferAllocator::releaseGpu(AllocationId id) {
|
|||||||
assert_invariant(targetNode != nullptr);
|
assert_invariant(targetNode != nullptr);
|
||||||
assert_invariant(targetNode->slot.gpuUseCount > 0);
|
assert_invariant(targetNode->slot.gpuUseCount > 0);
|
||||||
|
|
||||||
Slot& slot = targetNode->slot;
|
targetNode->slot.gpuUseCount--;
|
||||||
slot.gpuUseCount--;
|
|
||||||
if (slot.gpuUseCount == 0 && !slot.isAllocated) {
|
|
||||||
mHasPendingFrees = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferAllocator::releaseFreeSlots() {
|
void BufferAllocator::releaseFreeSlots() {
|
||||||
if (!mHasPendingFrees) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto curr = mSlotPool.begin();
|
auto curr = mSlotPool.begin();
|
||||||
while (curr != mSlotPool.end()) {
|
while (curr != mSlotPool.end()) {
|
||||||
if (!curr->slot.isFree()) {
|
if (!curr->slot.isFree()) {
|
||||||
@@ -211,7 +199,6 @@ void BufferAllocator::releaseFreeSlots() {
|
|||||||
|
|
||||||
curr = next;
|
curr = next;
|
||||||
}
|
}
|
||||||
mHasPendingFrees = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferAllocator::allocation_size_t BufferAllocator::getTotalSize() const noexcept {
|
BufferAllocator::allocation_size_t BufferAllocator::getTotalSize() const noexcept {
|
||||||
|
|||||||
@@ -113,9 +113,8 @@ private:
|
|||||||
|
|
||||||
[[nodiscard]] InternalSlotNode* getNodeById(AllocationId id) const noexcept;
|
[[nodiscard]] InternalSlotNode* getNodeById(AllocationId id) const noexcept;
|
||||||
|
|
||||||
bool mHasPendingFrees = false;
|
|
||||||
allocation_size_t mTotalSize;
|
allocation_size_t mTotalSize;
|
||||||
const allocation_size_t mSlotSize; // Size of a single slot in bytes
|
const allocation_size_t mSlotSize; // Size of a single slot in bytes.
|
||||||
std::list<InternalSlotNode> mSlotPool; // All slots, including both allocated and freed
|
std::list<InternalSlotNode> mSlotPool; // All slots, including both allocated and freed
|
||||||
std::multimap</*slot size*/allocation_size_t, InternalSlotNode*> mFreeList;
|
std::multimap</*slot size*/allocation_size_t, InternalSlotNode*> mFreeList;
|
||||||
std::unordered_map</*slot offset*/allocation_size_t, InternalSlotNode*> mOffsetMap;
|
std::unordered_map</*slot offset*/allocation_size_t, InternalSlotNode*> mOffsetMap;
|
||||||
|
|||||||
@@ -468,26 +468,11 @@ void FEngine::init() {
|
|||||||
}
|
}
|
||||||
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*this));
|
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We must commit the default material instance here. It may not be used in a scene, but its
|
// We must commit the default material instance here. It may not be used in a scene, but its
|
||||||
// descriptor set may still be used for shared variants.
|
// descriptor set may still be used for shared variants.
|
||||||
//
|
mDefaultMaterial->getDefaultInstance()->commit(driverApi);
|
||||||
// Note that this material instance is instantiated before the creation of UboManager, so at
|
|
||||||
// this point `isUboBatchingEnabled` is `false`, and it will fall back to individual UBO
|
|
||||||
// automatically.
|
|
||||||
mDefaultMaterial->getDefaultInstance()->commit(driverApi, mUboManager);
|
|
||||||
|
|
||||||
if (UTILS_UNLIKELY(getSupportedFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1)) {
|
if (UTILS_UNLIKELY(getSupportedFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1)) {
|
||||||
// UBO batching is not supported in feature level 0
|
|
||||||
if (features.material.enable_material_instance_uniform_batching) {
|
|
||||||
// Ubo size of each material instance is at least 16 bytes.
|
|
||||||
constexpr BufferAllocator::allocation_size_t minSlotSize = 16;
|
|
||||||
auto const uboOffsetAlignment = static_cast<BufferAllocator::allocation_size_t>(
|
|
||||||
driverApi.getUniformBufferOffsetAlignment());
|
|
||||||
BufferAllocator::allocation_size_t slotSize = std::max(minSlotSize, uboOffsetAlignment);
|
|
||||||
mUboManager = new UboManager(getDriverApi(), slotSize, mConfig.sharedUboInitialSizeInBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
|
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
|
||||||
|
|
||||||
constexpr float3 dummyPositions[1] = {};
|
constexpr float3 dummyPositions[1] = {};
|
||||||
@@ -668,12 +653,6 @@ void FEngine::shutdown() {
|
|||||||
|
|
||||||
driver.destroyRenderTarget(std::move(mDefaultRenderTarget));
|
driver.destroyRenderTarget(std::move(mDefaultRenderTarget));
|
||||||
|
|
||||||
if (isUboBatchingEnabled()) {
|
|
||||||
mUboManager->terminate(driver);
|
|
||||||
delete mUboManager;
|
|
||||||
mUboManager = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shutdown the backend...
|
* Shutdown the backend...
|
||||||
*/
|
*/
|
||||||
@@ -714,31 +693,18 @@ void FEngine::prepare() {
|
|||||||
// UBOs that are visible only. It's not such a big issue because the actual upload() is
|
// UBOs that are visible only. It's not such a big issue because the actual upload() is
|
||||||
// skipped if the UBO hasn't changed. Still we could have a lot of these.
|
// skipped if the UBO hasn't changed. Still we could have a lot of these.
|
||||||
DriverApi& driver = getDriverApi();
|
DriverApi& driver = getDriverApi();
|
||||||
const bool useUboBatching = isUboBatchingEnabled();
|
|
||||||
|
|
||||||
if (useUboBatching) {
|
|
||||||
assert_invariant(mUboManager != nullptr);
|
|
||||||
|
|
||||||
mUboManager->beginFrame(driver, mMaterialInstances);
|
|
||||||
}
|
|
||||||
|
|
||||||
UboManager* uboManager = mUboManager;
|
|
||||||
for (auto& materialInstanceList: mMaterialInstances) {
|
for (auto& materialInstanceList: mMaterialInstances) {
|
||||||
materialInstanceList.second.forEach([&driver, uboManager](FMaterialInstance* item) {
|
materialInstanceList.second.forEach([&driver](FMaterialInstance* item) {
|
||||||
// post-process materials instances must be commited explicitly because their
|
// post-process materials instances must be commited explicitly because their
|
||||||
// parameters are typically not set at this point in time.
|
// parameters are typically not set at this point in time.
|
||||||
if (item->getMaterial()->getMaterialDomain() == MaterialDomain::SURFACE) {
|
if (item->getMaterial()->getMaterialDomain() == MaterialDomain::SURFACE) {
|
||||||
item->commitStreamUniformAssociations(driver);
|
item->commitStreamUniformAssociations(driver);
|
||||||
item->commit(driver, uboManager);
|
item->commit(driver);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useUboBatching) {
|
|
||||||
assert_invariant(mUboManager != nullptr);
|
|
||||||
getUboManager()->finishBeginFrame(getDriverApi());
|
|
||||||
}
|
|
||||||
|
|
||||||
mMaterials.forEach([](FMaterial* material) {
|
mMaterials.forEach([](FMaterial* material) {
|
||||||
#if FILAMENT_ENABLE_MATDBG // NOLINT(*-include-cleaner)
|
#if FILAMENT_ENABLE_MATDBG // NOLINT(*-include-cleaner)
|
||||||
material->checkProgramEdits();
|
material->checkProgramEdits();
|
||||||
@@ -755,13 +721,6 @@ void FEngine::gc() {
|
|||||||
mCameraManager.gc(*this, em);
|
mCameraManager.gc(*this, em);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FEngine::submitFrame() {
|
|
||||||
if (isUboBatchingEnabled()) {
|
|
||||||
DriverApi& driver = getDriverApi();
|
|
||||||
getUboManager()->endFrame(driver, getMaterialInstanceResourceList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FEngine::flush() {
|
void FEngine::flush() {
|
||||||
// flush the command buffer
|
// flush the command buffer
|
||||||
flushCommandBuffer(mCommandBufferQueue);
|
flushCommandBuffer(mCommandBufferQueue);
|
||||||
@@ -992,10 +951,9 @@ FMaterialInstance* FEngine::createMaterialInstance(const FMaterial* material,
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMaterialInstance* FEngine::createMaterialInstance(const FMaterial* material, const char* name,
|
FMaterialInstance* FEngine::createMaterialInstance(const FMaterial* material,
|
||||||
UboBatchingMode batchingMode) noexcept {
|
const char* name) noexcept {
|
||||||
FMaterialInstance* p =
|
FMaterialInstance* p = mHeapAllocator.make<FMaterialInstance>(*this, material, name);
|
||||||
mHeapAllocator.make<FMaterialInstance>(*this, material, name, batchingMode);
|
|
||||||
if (UTILS_LIKELY(p)) {
|
if (UTILS_LIKELY(p)) {
|
||||||
auto pos = mMaterialInstances.emplace(material, "MaterialInstance");
|
auto pos = mMaterialInstances.emplace(material, "MaterialInstance");
|
||||||
pos.first->second.insert(p);
|
pos.first->second.insert(p);
|
||||||
@@ -1285,11 +1243,6 @@ UTILS_NOINLINE
|
|||||||
bool FEngine::destroy(const FMaterialInstance* p) {
|
bool FEngine::destroy(const FMaterialInstance* p) {
|
||||||
if (p == nullptr) return true;
|
if (p == nullptr) return true;
|
||||||
|
|
||||||
if (p->isUsingUboBatching()) {
|
|
||||||
assert_invariant(isUboBatchingEnabled());
|
|
||||||
mUboManager->retireSlot(p->getAllocationId());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the material instance we're destroying is not in use in the RenderableManager
|
// Check that the material instance we're destroying is not in use in the RenderableManager
|
||||||
// To do this, we currently need to inspect all render primitives in the RenderableManager
|
// To do this, we currently need to inspect all render primitives in the RenderableManager
|
||||||
EntityManager const& em = mEntityManager;
|
EntityManager const& em = mEntityManager;
|
||||||
|
|||||||
@@ -21,17 +21,16 @@
|
|||||||
|
|
||||||
#include "Allocators.h"
|
#include "Allocators.h"
|
||||||
#include "DFG.h"
|
#include "DFG.h"
|
||||||
|
#include "PostProcessManager.h"
|
||||||
|
#include "ResourceList.h"
|
||||||
#include "HwDescriptorSetLayoutFactory.h"
|
#include "HwDescriptorSetLayoutFactory.h"
|
||||||
#include "HwVertexBufferInfoFactory.h"
|
#include "HwVertexBufferInfoFactory.h"
|
||||||
#include "MaterialCache.h"
|
#include "MaterialCache.h"
|
||||||
#include "PostProcessManager.h"
|
|
||||||
#include "ResourceList.h"
|
|
||||||
#include "UboManager.h"
|
|
||||||
|
|
||||||
#include "components/CameraManager.h"
|
#include "components/CameraManager.h"
|
||||||
#include "components/LightManager.h"
|
#include "components/LightManager.h"
|
||||||
#include "components/RenderableManager.h"
|
|
||||||
#include "components/TransformManager.h"
|
#include "components/TransformManager.h"
|
||||||
|
#include "components/RenderableManager.h"
|
||||||
|
|
||||||
#include "ds/DescriptorSetLayout.h"
|
#include "ds/DescriptorSetLayout.h"
|
||||||
|
|
||||||
@@ -264,14 +263,6 @@ public:
|
|||||||
return mBackend;
|
return mBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isUboBatchingEnabled() const noexcept {
|
|
||||||
return mUboManager != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
UboManager* getUboManager() noexcept {
|
|
||||||
return mUboManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform* getPlatform() const noexcept {
|
Platform* getPlatform() const noexcept {
|
||||||
return mPlatform;
|
return mPlatform;
|
||||||
}
|
}
|
||||||
@@ -345,21 +336,11 @@ public:
|
|||||||
|
|
||||||
FRenderer* createRenderer() noexcept;
|
FRenderer* createRenderer() noexcept;
|
||||||
|
|
||||||
// Defines whether a material instance should use UBO batching or not.
|
|
||||||
enum class UboBatchingMode {
|
|
||||||
// For default, it follows the engine settings.
|
|
||||||
// If UBO batching is enabled on the engine and the material domain is not SURFACE, it
|
|
||||||
// turns on the UBO batching. Otherwise, it turns off the UBO batching.
|
|
||||||
DEFAULT,
|
|
||||||
NO_UBO_BATCHING,
|
|
||||||
UBO_BATCHING
|
|
||||||
};
|
|
||||||
|
|
||||||
FMaterialInstance* createMaterialInstance(const FMaterial* material,
|
FMaterialInstance* createMaterialInstance(const FMaterial* material,
|
||||||
const FMaterialInstance* other, const char* name) noexcept;
|
const FMaterialInstance* other, const char* name) noexcept;
|
||||||
|
|
||||||
FMaterialInstance* createMaterialInstance(const FMaterial* material, const char* name,
|
FMaterialInstance* createMaterialInstance(const FMaterial* material,
|
||||||
UboBatchingMode batchingMode) noexcept;
|
const char* name) noexcept;
|
||||||
|
|
||||||
FScene* createScene() noexcept;
|
FScene* createScene() noexcept;
|
||||||
FView* createView() noexcept;
|
FView* createView() noexcept;
|
||||||
@@ -465,7 +446,6 @@ public:
|
|||||||
|
|
||||||
void prepare();
|
void prepare();
|
||||||
void gc();
|
void gc();
|
||||||
void submitFrame();
|
|
||||||
|
|
||||||
using ShaderContent = utils::FixedCapacityVector<uint8_t>;
|
using ShaderContent = utils::FixedCapacityVector<uint8_t>;
|
||||||
|
|
||||||
@@ -670,7 +650,6 @@ private:
|
|||||||
|
|
||||||
uint32_t mFlushCounter = 0;
|
uint32_t mFlushCounter = 0;
|
||||||
|
|
||||||
UboManager* mUboManager = nullptr;
|
|
||||||
RootArenaScope::Arena mPerRenderPassArena;
|
RootArenaScope::Arena mPerRenderPassArena;
|
||||||
HeapAllocatorArena mHeapAllocator;
|
HeapAllocatorArena mHeapAllocator;
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ namespace filament {
|
|||||||
using namespace backend;
|
using namespace backend;
|
||||||
using namespace filaflat;
|
using namespace filaflat;
|
||||||
using namespace utils;
|
using namespace utils;
|
||||||
using UboBatchingMode = FEngine::UboBatchingMode;
|
|
||||||
|
|
||||||
struct Material::BuilderDetails {
|
struct Material::BuilderDetails {
|
||||||
const void* mPayload = nullptr;
|
const void* mPayload = nullptr;
|
||||||
@@ -218,17 +217,16 @@ void FMaterial::terminate(FEngine& engine) {
|
|||||||
|
|
||||||
filament::DescriptorSetLayout const& FMaterial::getPerViewDescriptorSetLayout(
|
filament::DescriptorSetLayout const& FMaterial::getPerViewDescriptorSetLayout(
|
||||||
Variant const variant, bool const useVsmDescriptorSetLayout) const noexcept {
|
Variant const variant, bool const useVsmDescriptorSetLayout) const noexcept {
|
||||||
if (mDefinition.materialDomain == MaterialDomain::SURFACE) {
|
if (Variant::isValidDepthVariant(variant)) {
|
||||||
// `variant` is only sensical for MaterialDomain::SURFACE
|
assert_invariant(mDefinition.materialDomain == MaterialDomain::SURFACE);
|
||||||
if (Variant::isValidDepthVariant(variant)) {
|
return mEngine.getPerViewDescriptorSetLayoutDepthVariant();
|
||||||
return mEngine.getPerViewDescriptorSetLayoutDepthVariant();
|
}
|
||||||
}
|
if (Variant::isSSRVariant(variant)) {
|
||||||
if (Variant::isSSRVariant(variant)) {
|
assert_invariant(mDefinition.materialDomain == MaterialDomain::SURFACE);
|
||||||
return mEngine.getPerViewDescriptorSetLayoutSsrVariant();
|
return mEngine.getPerViewDescriptorSetLayoutSsrVariant();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// mDefinition.perViewDescriptorSetLayout{Vsm} is already resolved for MaterialDomain
|
|
||||||
if (useVsmDescriptorSetLayout) {
|
if (useVsmDescriptorSetLayout) {
|
||||||
|
assert_invariant(mDefinition.materialDomain == MaterialDomain::SURFACE);
|
||||||
return mDefinition.perViewDescriptorSetLayoutVsm;
|
return mDefinition.perViewDescriptorSetLayoutVsm;
|
||||||
}
|
}
|
||||||
return mDefinition.perViewDescriptorSetLayout;
|
return mDefinition.perViewDescriptorSetLayout;
|
||||||
@@ -282,14 +280,14 @@ FMaterialInstance* FMaterial::createInstance(const char* name) const noexcept {
|
|||||||
return FMaterialInstance::duplicate(mDefaultMaterialInstance, name);
|
return FMaterialInstance::duplicate(mDefaultMaterialInstance, name);
|
||||||
} else {
|
} else {
|
||||||
// but if we don't, just create an instance with all the default parameters
|
// but if we don't, just create an instance with all the default parameters
|
||||||
return mEngine.createMaterialInstance(this, name, UboBatchingMode::DEFAULT);
|
return mEngine.createMaterialInstance(this, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FMaterialInstance* FMaterial::getDefaultInstance() noexcept {
|
FMaterialInstance* FMaterial::getDefaultInstance() noexcept {
|
||||||
if (UTILS_UNLIKELY(!mDefaultMaterialInstance)) {
|
if (UTILS_UNLIKELY(!mDefaultMaterialInstance)) {
|
||||||
mDefaultMaterialInstance =
|
mDefaultMaterialInstance = mEngine.createMaterialInstance(this,
|
||||||
mEngine.createMaterialInstance(this, mDefinition.name.c_str(), UboBatchingMode::DEFAULT);
|
mDefinition.name.c_str());
|
||||||
mDefaultMaterialInstance->setDefaultInstance(true);
|
mDefaultMaterialInstance->setDefaultInstance(true);
|
||||||
}
|
}
|
||||||
return mDefaultMaterialInstance;
|
return mDefaultMaterialInstance;
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public:
|
|||||||
backend::CallbackHandler* handler,
|
backend::CallbackHandler* handler,
|
||||||
utils::Invocable<void(Material*)>&& callback) noexcept;
|
utils::Invocable<void(Material*)>&& callback) noexcept;
|
||||||
|
|
||||||
// Creates an instance of this material, specifying the batching mode.
|
// Create an instance of this material
|
||||||
FMaterialInstance* createInstance(const char* name) const noexcept;
|
FMaterialInstance* createInstance(const char* name) const noexcept;
|
||||||
|
|
||||||
bool hasParameter(const char* name) const noexcept;
|
bool hasParameter(const char* name) const noexcept;
|
||||||
|
|||||||
@@ -58,19 +58,15 @@ using namespace utils;
|
|||||||
namespace filament {
|
namespace filament {
|
||||||
|
|
||||||
using namespace backend;
|
using namespace backend;
|
||||||
using UboBatchingMode = FEngine::UboBatchingMode;
|
|
||||||
|
|
||||||
bool shouldEnableBatching(FEngine& engine, UboBatchingMode batchingMode, MaterialDomain domain) {
|
FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material,
|
||||||
if (batchingMode != UboBatchingMode::DEFAULT) {
|
const char* name) noexcept
|
||||||
return batchingMode == UboBatchingMode::UBO_BATCHING;
|
: FMaterialInstance(engine, material, name,
|
||||||
}
|
engine.features.material.enable_material_instance_uniform_batching) {
|
||||||
|
|
||||||
return engine.isUboBatchingEnabled() && domain == MaterialDomain::SURFACE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material, const char* name,
|
FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material,
|
||||||
UboBatchingMode batchingMode) noexcept
|
const char* name, bool useUboBatching) noexcept : mMaterial(material),
|
||||||
: mMaterial(material),
|
|
||||||
mDescriptorSet("MaterialInstance", material->getDescriptorSetLayout()),
|
mDescriptorSet("MaterialInstance", material->getDescriptorSetLayout()),
|
||||||
mCulling(CullingMode::BACK),
|
mCulling(CullingMode::BACK),
|
||||||
mShadowCulling(CullingMode::BACK),
|
mShadowCulling(CullingMode::BACK),
|
||||||
@@ -80,12 +76,10 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material,
|
|||||||
mHasScissor(false),
|
mHasScissor(false),
|
||||||
mIsDoubleSided(false),
|
mIsDoubleSided(false),
|
||||||
mIsDefaultInstance(false),
|
mIsDefaultInstance(false),
|
||||||
mUseUboBatching(
|
mUseUboBatching(useUboBatching),
|
||||||
shouldEnableBatching(engine, batchingMode, material->getMaterialDomain())),
|
|
||||||
mTransparencyMode(TransparencyMode::DEFAULT),
|
mTransparencyMode(TransparencyMode::DEFAULT),
|
||||||
mName(name ? CString(name) : material->getName()) {
|
mName(name ? CString(name) : material->getName()) {
|
||||||
FILAMENT_CHECK_PRECONDITION(!mUseUboBatching || engine.isUboBatchingEnabled())
|
|
||||||
<< "UBO batching is not enabled.";
|
|
||||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||||
|
|
||||||
// even if the material doesn't have any parameters, we allocate a small UBO because it's
|
// even if the material doesn't have any parameters, we allocate a small UBO because it's
|
||||||
@@ -159,7 +153,7 @@ FMaterialInstance::FMaterialInstance(FEngine& engine,
|
|||||||
mUseUboBatching(other->mUseUboBatching),
|
mUseUboBatching(other->mUseUboBatching),
|
||||||
mScissorRect(other->mScissorRect),
|
mScissorRect(other->mScissorRect),
|
||||||
mName(name ? CString(name) : other->mName) {
|
mName(name ? CString(name) : other->mName) {
|
||||||
assert_invariant(!mUseUboBatching || engine.isUboBatchingEnabled());
|
|
||||||
FEngine::DriverApi& driver = engine.getDriverApi();
|
FEngine::DriverApi& driver = engine.getDriverApi();
|
||||||
FMaterial const* const material = other->getMaterial();
|
FMaterial const* const material = other->getMaterial();
|
||||||
|
|
||||||
@@ -199,8 +193,8 @@ FMaterialInstance::FMaterialInstance(FEngine& engine,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FMaterialInstance* FMaterialInstance::duplicate(FMaterialInstance const* other,
|
FMaterialInstance* FMaterialInstance::duplicate(
|
||||||
const char* name) noexcept {
|
FMaterialInstance const* other, const char* name) noexcept {
|
||||||
FMaterial const* const material = other->getMaterial();
|
FMaterial const* const material = other->getMaterial();
|
||||||
FEngine& engine = material->getEngine();
|
FEngine& engine = material->getEngine();
|
||||||
return engine.createMaterialInstance(material, other, name);
|
return engine.createMaterialInstance(material, other, name);
|
||||||
@@ -244,21 +238,15 @@ void FMaterialInstance::commitStreamUniformAssociations(FEngine::DriverApi& driv
|
|||||||
|
|
||||||
void FMaterialInstance::commit(FEngine& engine) const {
|
void FMaterialInstance::commit(FEngine& engine) const {
|
||||||
if (UTILS_LIKELY(mMaterial->getMaterialDomain() != MaterialDomain::SURFACE)) {
|
if (UTILS_LIKELY(mMaterial->getMaterialDomain() != MaterialDomain::SURFACE)) {
|
||||||
commit(engine.getDriverApi(), engine.getUboManager());
|
commit(engine.getDriverApi());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FMaterialInstance::commit(FEngine::DriverApi& driver, UboManager* uboManager) const {
|
void FMaterialInstance::commit(FEngine::DriverApi& driver) const {
|
||||||
if (mUniforms.isDirty() || mHasStreamUniformAssociations) {
|
if (mUniforms.isDirty() || mHasStreamUniformAssociations) {
|
||||||
mUniforms.clean();
|
mUniforms.clean();
|
||||||
if (mUseUboBatching) {
|
if (mUseUboBatching) {
|
||||||
assert_invariant(uboManager != nullptr);
|
// TODO: update the content by `copyToMemoryMappedBuffer`
|
||||||
if (!BufferAllocator::isValid(getAllocationId())) {
|
|
||||||
// The allocation hasn't happened yet, return.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uboManager->updateSlot(driver, getAllocationId(), mUniforms.toBufferDescriptor(driver));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto* ubHandle = std::get_if<Handle<HwBufferObject>>(&mUboData);
|
auto* ubHandle = std::get_if<Handle<HwBufferObject>>(&mUboData);
|
||||||
@@ -283,10 +271,6 @@ void FMaterialInstance::commit(FEngine::DriverApi& driver, UboManager* uboManage
|
|||||||
// TODO: eventually we should remove this in RELEASE builds
|
// TODO: eventually we should remove this in RELEASE builds
|
||||||
fixMissingSamplers();
|
fixMissingSamplers();
|
||||||
|
|
||||||
if (mUseUboBatching && !BufferAllocator::isValid(getAllocationId())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commit descriptors if needed (e.g. when textures are updated,or the first time)
|
// Commit descriptors if needed (e.g. when textures are updated,or the first time)
|
||||||
mDescriptorSet.commit(mMaterial->getDescriptorSetLayout(), driver);
|
mDescriptorSet.commit(mMaterial->getDescriptorSetLayout(), driver);
|
||||||
}
|
}
|
||||||
@@ -429,13 +413,6 @@ const char* FMaterialInstance::getName() const noexcept {
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
void FMaterialInstance::use(FEngine::DriverApi& driver, Variant variant) const {
|
void FMaterialInstance::use(FEngine::DriverApi& driver, Variant variant) const {
|
||||||
if (!mDescriptorSet.getHandle()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mUseUboBatching && !BufferAllocator::isValid(getAllocationId())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UTILS_UNLIKELY(mMissingSamplerDescriptors.any())) {
|
if (UTILS_UNLIKELY(mMissingSamplerDescriptors.any())) {
|
||||||
std::call_once(mMissingSamplersFlag, [this] {
|
std::call_once(mMissingSamplersFlag, [this] {
|
||||||
@@ -462,8 +439,7 @@ void FMaterialInstance::use(FEngine::DriverApi& driver, Variant variant) const {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mDescriptorSet.bind(driver, DescriptorSetBindingPoints::PER_MATERIAL,
|
mDescriptorSet.bind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||||
{ { mUboOffset }, driver });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FMaterialInstance::assignUboAllocation(
|
void FMaterialInstance::assignUboAllocation(
|
||||||
@@ -473,10 +449,8 @@ void FMaterialInstance::assignUboAllocation(
|
|||||||
assert_invariant(mUseUboBatching);
|
assert_invariant(mUseUboBatching);
|
||||||
|
|
||||||
mUboData = id;
|
mUboData = id;
|
||||||
mUboOffset = offset;
|
|
||||||
if (BufferAllocator::isValid(id)) {
|
if (BufferAllocator::isValid(id)) {
|
||||||
// Use dynamic offset during binding, so the offset here is always zero.
|
mDescriptorSet.setBuffer(mMaterial->getDescriptorSetLayout(), 0, ubHandle, offset,
|
||||||
mDescriptorSet.setBuffer(mMaterial->getDescriptorSetLayout(), 0, ubHandle, 0,
|
|
||||||
mUniforms.getSize());
|
mUniforms.getSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,8 +56,11 @@ class FTexture;
|
|||||||
|
|
||||||
class FMaterialInstance : public MaterialInstance {
|
class FMaterialInstance : public MaterialInstance {
|
||||||
public:
|
public:
|
||||||
FMaterialInstance(FEngine& engine, FMaterial const* material, const char* name,
|
FMaterialInstance(FEngine& engine, FMaterial const* material,
|
||||||
FEngine::UboBatchingMode batchingMode) noexcept;
|
const char* name) noexcept;
|
||||||
|
// Use this constructor when you need to override the ubo batching flag for an individual MI.
|
||||||
|
FMaterialInstance(FEngine& engine, FMaterial const* material,
|
||||||
|
const char* name, bool useUboBatching) noexcept;
|
||||||
FMaterialInstance(FEngine& engine, FMaterialInstance const* other, const char* name);
|
FMaterialInstance(FEngine& engine, FMaterialInstance const* other, const char* name);
|
||||||
FMaterialInstance(const FMaterialInstance& rhs) = delete;
|
FMaterialInstance(const FMaterialInstance& rhs) = delete;
|
||||||
FMaterialInstance& operator=(const FMaterialInstance& rhs) = delete;
|
FMaterialInstance& operator=(const FMaterialInstance& rhs) = delete;
|
||||||
@@ -72,7 +75,7 @@ public:
|
|||||||
|
|
||||||
void commit(FEngine& engine) const;
|
void commit(FEngine& engine) const;
|
||||||
|
|
||||||
void commit(FEngine::DriverApi& driver, UboManager* uboManager) const;
|
void commit(FEngine::DriverApi& driver) const;
|
||||||
|
|
||||||
void use(FEngine::DriverApi& driver, Variant variant = {}) const;
|
void use(FEngine::DriverApi& driver, Variant variant = {}) const;
|
||||||
|
|
||||||
@@ -284,7 +287,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::variant<BufferAllocator::AllocationId, backend::Handle<backend::HwBufferObject>> mUboData;
|
std::variant<BufferAllocator::AllocationId, backend::Handle<backend::HwBufferObject>> mUboData;
|
||||||
BufferAllocator::allocation_size_t mUboOffset = 0;
|
|
||||||
tsl::robin_map<backend::descriptor_binding_t, TextureParameter> mTextureParameters;
|
tsl::robin_map<backend::descriptor_binding_t, TextureParameter> mTextureParameters;
|
||||||
mutable DescriptorSet mDescriptorSet;
|
mutable DescriptorSet mDescriptorSet;
|
||||||
UniformBuffer mUniforms;
|
UniformBuffer mUniforms;
|
||||||
@@ -306,7 +308,7 @@ private:
|
|||||||
bool mHasScissor : 1;
|
bool mHasScissor : 1;
|
||||||
bool mIsDoubleSided : 1;
|
bool mIsDoubleSided : 1;
|
||||||
bool mIsDefaultInstance : 1;
|
bool mIsDefaultInstance : 1;
|
||||||
const bool mUseUboBatching : 1;
|
bool mUseUboBatching : 1;
|
||||||
TransparencyMode mTransparencyMode : 2;
|
TransparencyMode mTransparencyMode : 2;
|
||||||
|
|
||||||
uint64_t mMaterialSortingKey = 0;
|
uint64_t mMaterialSortingKey = 0;
|
||||||
|
|||||||
@@ -452,8 +452,6 @@ void FRenderer::endFrame() {
|
|||||||
mFrameInfoManager.endFrame(driver);
|
mFrameInfoManager.endFrame(driver);
|
||||||
mFrameSkipper.submitFrame(driver);
|
mFrameSkipper.submitFrame(driver);
|
||||||
|
|
||||||
engine.submitFrame();
|
|
||||||
|
|
||||||
driver.endFrame(mFrameId);
|
driver.endFrame(mFrameId);
|
||||||
|
|
||||||
// gives the backend a chance to execute periodic tasks
|
// gives the backend a chance to execute periodic tasks
|
||||||
@@ -589,8 +587,6 @@ void FRenderer::renderStandaloneView(FView const* view) {
|
|||||||
// happen with Renderer::beginFrame/endFrame.
|
// happen with Renderer::beginFrame/endFrame.
|
||||||
renderInternal(view, true);
|
renderInternal(view, true);
|
||||||
|
|
||||||
engine.submitFrame();
|
|
||||||
|
|
||||||
driver.endFrame(mFrameId);
|
driver.endFrame(mFrameId);
|
||||||
|
|
||||||
// engine.flush() has already been called by renderInternal(), but we need an extra one
|
// engine.flush() has already been called by renderInternal(), but we need an extra one
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const Builder& builder)
|
|||||||
if (!mBufferObjectsEnabled) {
|
if (!mBufferObjectsEnabled) {
|
||||||
// If buffer objects are not enabled at the API level, then we create them internally.
|
// If buffer objects are not enabled at the API level, then we create them internally.
|
||||||
#pragma nounroll
|
#pragma nounroll
|
||||||
for (size_t index = 0; index < MAX_VERTEX_ATTRIBUTE_COUNT; ++index) {
|
for (size_t index = 0; index < MAX_VERTEX_BUFFER_COUNT; ++index) {
|
||||||
size_t const i = mAttributes[index].buffer;
|
size_t const i = mAttributes[index].buffer;
|
||||||
if (i != Attribute::BUFFER_UNUSED) {
|
if (i != Attribute::BUFFER_UNUSED) {
|
||||||
assert_invariant(bufferSizes[i] > 0);
|
assert_invariant(bufferSizes[i] > 0);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ void PostProcessDescriptorSet::init(FEngine& engine) noexcept {
|
|||||||
// create the descriptor-set layout
|
// create the descriptor-set layout
|
||||||
mDescriptorSetLayout = filament::DescriptorSetLayout{
|
mDescriptorSetLayout = filament::DescriptorSetLayout{
|
||||||
engine.getDescriptorSetLayoutFactory(),
|
engine.getDescriptorSetLayoutFactory(),
|
||||||
engine.getDriverApi(), descriptor_sets::getDepthVariantLayout() };
|
engine.getDriverApi(), descriptor_sets::getPostProcessLayout() };
|
||||||
|
|
||||||
// create the descriptor-set from the layout
|
// create the descriptor-set from the layout
|
||||||
mDescriptorSet = DescriptorSet{ "PostProcessDescriptorSet", mDescriptorSetLayout };
|
mDescriptorSet = DescriptorSet{ "PostProcessDescriptorSet", mDescriptorSetLayout };
|
||||||
|
|||||||
@@ -28,9 +28,9 @@
|
|||||||
|
|
||||||
namespace filament::descriptor_sets {
|
namespace filament::descriptor_sets {
|
||||||
|
|
||||||
|
backend::DescriptorSetLayout const& getPostProcessLayout() noexcept;
|
||||||
backend::DescriptorSetLayout const& getDepthVariantLayout() noexcept;
|
backend::DescriptorSetLayout const& getDepthVariantLayout() noexcept;
|
||||||
backend::DescriptorSetLayout const& getSsrVariantLayout() noexcept;
|
backend::DescriptorSetLayout const& getSsrVariantLayout() noexcept;
|
||||||
|
|
||||||
backend::DescriptorSetLayout const& getPerRenderableLayout() noexcept;
|
backend::DescriptorSetLayout const& getPerRenderableLayout() noexcept;
|
||||||
|
|
||||||
backend::DescriptorSetLayout getPerViewDescriptorSetLayout(
|
backend::DescriptorSetLayout getPerViewDescriptorSetLayout(
|
||||||
|
|||||||
@@ -40,7 +40,12 @@ namespace filament::descriptor_sets {
|
|||||||
|
|
||||||
using namespace backend;
|
using namespace backend;
|
||||||
|
|
||||||
// used to generate shadow-maps, structure and postfx passes
|
// used for post-processing passes
|
||||||
|
static constexpr std::initializer_list<DescriptorSetLayoutBinding> postProcessDescriptorSetLayoutList = {
|
||||||
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to generate shadow-maps
|
||||||
static constexpr std::initializer_list<DescriptorSetLayoutBinding> depthVariantDescriptorSetLayoutList = {
|
static constexpr std::initializer_list<DescriptorSetLayoutBinding> depthVariantDescriptorSetLayoutList = {
|
||||||
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
{ DescriptorType::UNIFORM_BUFFER, ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, +PerViewBindingPoints::FRAME_UNIFORMS },
|
||||||
};
|
};
|
||||||
@@ -137,6 +142,10 @@ static const std::unordered_map<
|
|||||||
{{ SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT }, DescriptorType::SAMPLER_EXTERNAL }
|
{{ SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT }, DescriptorType::SAMPLER_EXTERNAL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// used for post-processing passes
|
||||||
|
static DescriptorSetLayout const postProcessDescriptorSetLayout{ utils::StaticString("postProcess"),
|
||||||
|
postProcessDescriptorSetLayoutList };
|
||||||
|
|
||||||
// used to generate shadow-maps
|
// used to generate shadow-maps
|
||||||
static DescriptorSetLayout const depthVariantDescriptorSetLayout{
|
static DescriptorSetLayout const depthVariantDescriptorSetLayout{
|
||||||
utils::StaticString("depthVariant"), depthVariantDescriptorSetLayoutList
|
utils::StaticString("depthVariant"), depthVariantDescriptorSetLayoutList
|
||||||
@@ -154,6 +163,10 @@ static DescriptorSetLayout perRenderableDescriptorSetLayout = {
|
|||||||
utils::StaticString("perRenderable"), perRenderableDescriptorSetLayoutList
|
utils::StaticString("perRenderable"), perRenderableDescriptorSetLayoutList
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DescriptorSetLayout const& getPostProcessLayout() noexcept {
|
||||||
|
return postProcessDescriptorSetLayout;
|
||||||
|
}
|
||||||
|
|
||||||
DescriptorSetLayout const& getDepthVariantLayout() noexcept {
|
DescriptorSetLayout const& getDepthVariantLayout() noexcept {
|
||||||
return depthVariantDescriptorSetLayout;
|
return depthVariantDescriptorSetLayout;
|
||||||
}
|
}
|
||||||
@@ -267,10 +280,10 @@ DescriptorSetLayout getPerViewDescriptorSetLayout(
|
|||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
case MaterialDomain::POST_PROCESS:
|
case MaterialDomain::POST_PROCESS:
|
||||||
return depthVariantDescriptorSetLayout;
|
return postProcessDescriptorSetLayout;
|
||||||
case MaterialDomain::COMPUTE:
|
case MaterialDomain::COMPUTE:
|
||||||
// TODO: what's the layout for compute?
|
// TODO: what's the layout for compute?
|
||||||
return depthVariantDescriptorSetLayout;
|
return postProcessDescriptorSetLayout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,9 +129,9 @@ DescriptorSetLayout getPerMaterialDescriptorSet(SamplerInterfaceBlock const& sib
|
|||||||
DescriptorSetLayout layout;
|
DescriptorSetLayout layout;
|
||||||
layout.bindings.reserve(1 + samplers.size());
|
layout.bindings.reserve(1 + samplers.size());
|
||||||
|
|
||||||
layout.bindings.push_back(DescriptorSetLayoutBinding{ DescriptorType::UNIFORM_BUFFER,
|
layout.bindings.push_back(DescriptorSetLayoutBinding { DescriptorType::UNIFORM_BUFFER,
|
||||||
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
|
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
|
||||||
+PerMaterialBindingPoints::MATERIAL_PARAMS, DescriptorFlags::DYNAMIC_OFFSET, 0 });
|
+PerMaterialBindingPoints::MATERIAL_PARAMS, DescriptorFlags::NONE, 0 });
|
||||||
|
|
||||||
for (auto const& sampler: samplers) {
|
for (auto const& sampler: samplers) {
|
||||||
DescriptorSetLayoutBinding layoutBinding{
|
DescriptorSetLayoutBinding layoutBinding{
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ void MaterialDescriptorSetLayoutChunk::flatten(Flattener& f) {
|
|||||||
f.writeUint8(uint8_t(DescriptorType::UNIFORM_BUFFER));
|
f.writeUint8(uint8_t(DescriptorType::UNIFORM_BUFFER));
|
||||||
f.writeUint8(uint8_t(ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT));
|
f.writeUint8(uint8_t(ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT));
|
||||||
f.writeUint8(0);
|
f.writeUint8(0);
|
||||||
f.writeUint8(uint8_t(DescriptorFlags::DYNAMIC_OFFSET));
|
f.writeUint8(uint8_t(DescriptorFlags::NONE));
|
||||||
f.writeUint16(0);
|
f.writeUint16(0);
|
||||||
|
|
||||||
// all the material's sampler descriptors
|
// all the material's sampler descriptors
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ static bool printParametersInfo(ostream& text, const ChunkContainer& container)
|
|||||||
}
|
}
|
||||||
|
|
||||||
text << " "
|
text << " "
|
||||||
<< setw(alignment) << fieldName.c_str_safe()
|
<< setw(alignment) << fieldName.c_str()
|
||||||
<< setw(shortAlignment) << toString(UniformType(fieldType))
|
<< setw(shortAlignment) << toString(UniformType(fieldType))
|
||||||
<< arraySizeToString(fieldSize)
|
<< arraySizeToString(fieldSize)
|
||||||
<< setw(shortAlignment) << toString(Precision(fieldPrecision))
|
<< setw(shortAlignment) << toString(Precision(fieldPrecision))
|
||||||
@@ -325,7 +325,7 @@ static bool printParametersInfo(ostream& text, const ChunkContainer& container)
|
|||||||
}
|
}
|
||||||
|
|
||||||
text << " "
|
text << " "
|
||||||
<< setw(alignment) << fieldName.c_str_safe()
|
<< setw(alignment) << fieldName.c_str()
|
||||||
<< setw(shortAlignment) << +fieldBinding
|
<< setw(shortAlignment) << +fieldBinding
|
||||||
<< setw(shortAlignment) << toString(SamplerType(fieldType))
|
<< setw(shortAlignment) << toString(SamplerType(fieldType))
|
||||||
<< setw(shortAlignment) << toString(Precision(fieldPrecision))
|
<< setw(shortAlignment) << toString(Precision(fieldPrecision))
|
||||||
@@ -364,7 +364,7 @@ static bool printConstantInfo(ostream& text, const ChunkContainer& container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
text << " "
|
text << " "
|
||||||
<< setw(alignment) << fieldName.c_str_safe()
|
<< setw(alignment) << fieldName.c_str()
|
||||||
<< setw(shortAlignment) << toString(ConstantType(fieldType))
|
<< setw(shortAlignment) << toString(ConstantType(fieldType))
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user