Compare commits

..
72 changed files with 22314 additions and 20505 deletions
+1 -1
View File
@@ -6,4 +6,4 @@ We are chaning the way Vulkan buffers are handled. We need to switch over to a m
**If you are cherry-picking a commit into an rc/ branch**: add the release note under the
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
## Release notes for next branch cut
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.61.2'
implementation 'com.google.android.filament:filament-android:1.61.1'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.61.2'
pod 'Filament', '~> 1.61.1'
```
## Documentation
+3 -1
View File
@@ -7,9 +7,11 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.61.2
## v1.62.0
- samples: samples now have a CLI to select backend api
- materials: sampler now export their type in the material binary [⚠️ **New Material Version**]
- materials: new mutable specialization constants feature. See the [materials documentation](https://google.github.io/filament/Materials.html) for details. [⚠️ **New Material Version**]
## v1.61.1
@@ -60,6 +60,14 @@ static void setParameter(JNIEnv* env, jlong nativeMaterialInstance, jstring name
env->ReleaseStringUTFChars(name_, name);
}
template<typename T>
static void setConstant(JNIEnv* env, jlong nativeMaterialInstance, jstring name_, T v) {
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
const char *name = env->GetStringUTFChars(name_, 0);
instance->setConstant(name, v);
env->ReleaseStringUTFChars(name_, name);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetParameterBool(JNIEnv *env, jclass,
@@ -264,6 +272,13 @@ Java_com_google_android_filament_MaterialInstance_nSetParameterTexture(
env->ReleaseStringUTFChars(name_, name);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetConstantBool(JNIEnv *env, jclass,
jlong nativeMaterialInstance, jstring name_, jboolean x) {
setConstant(env, nativeMaterialInstance, name_, bool(x));
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetScissor(
@@ -402,6 +402,16 @@ public class MaterialInstance {
nSetParameterFloat4(getNativeObject(), name, color[0], color[1], color[2], color[3]);
}
/**
* Sets the value of a bool constant.
*
* @param name the name of the material constant
* @param x the value of the material constant
*/
public void setConstant(@NonNull String name, boolean x) {
nSetConstantBool(getNativeObject(), name, x);
}
/**
* Set-up a custom scissor rectangle; by default it is disabled.
*
@@ -921,6 +931,9 @@ public class MaterialInstance {
@NonNull String name, int element, @NonNull @Size(min = 1) float[] v,
@IntRange(from = 0) int offset, @IntRange(from = 1) int count);
private static native void nSetConstantBool(long nativeMaterialInstance,
@NonNull String name, boolean x);
private static native void nSetParameterTexture(long nativeMaterialInstance,
@NonNull String name, long nativeTexture, long sampler);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.61.2
VERSION_NAME=1.61.1
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+31 -24
View File
@@ -211,7 +211,7 @@ when using textures.
This property can dramatically change the appearance of a surface. Non-metallic surfaces have
chromatic diffuse reflection and achromatic specular reflection (reflected light does not change
color). Metallic surfaces do not have any diffuse reflection and chromatic specular reflection
(reflected light takes on the color of the surfaced as defined by `baseColor`).
(reflected light takes on the color of the surfaced as defined by `baseColor`).
The effect of `metallic` is shown in figure [metallicProperty] (click on the image to see a
larger version).
@@ -247,7 +247,7 @@ The effect of `roughness` on metallic surfaces is shown in figure [roughnessCond
When refraction through an object is enabled (using a `refractonType` of `thin` or `solid`), the
`roughness` property will also affect the refractions, as shown in figure
[roughnessRefractionProperty] (click on the image to see a larger version).
![Figure [roughnessRefractionProperty]: Refractive sphere with `roughness` varying from 0.0
(left) to 1.0 (right)](images/materials/refraction_roughness.png)
@@ -306,7 +306,7 @@ The sheen color controls the color appearance and strength of an optional sheen
base layer described by the properties above. The sheen layer always sits below the clear coat layer
if such a layer is present.
The sheen layer can be used to represent cloth and fabric materials. Please refer to
The sheen layer can be used to represent cloth and fabric materials. Please refer to
section [Cloth model] for more information about cloth and fabric materials.
The effect of `sheenColor` is shown in figure [materialSheenColor]
@@ -519,14 +519,14 @@ light to bend further away from the initial path.
Table [commonMatIOR] describes acceptable refractive indices for various types of materials.
Material | IOR
Material | IOR
--------------------------:|:-----------------
Air | 1.0
Water | 1.33
Common liquids | 1.33 to 1.5
Common gemstones | 1.58 to 2.33
Plastics, glass | 1.5 to 1.58
Other dielectric materials | 1.33 to 1.58
Water | 1.33
Common liquids | 1.33 to 1.5
Common gemstones | 1.58 to 2.33
Plastics, glass | 1.5 to 1.58
Other dielectric materials | 1.33 to 1.58
[Table [commonMatIOR]: Index of refraction of common materials]
The appearance of a refractive material will greatly depend on the `refractionType` and
@@ -1091,30 +1091,37 @@ Value
`bool` or `number`, depending on the `type` of the constant. The type must be one of the types
described in table [materialConstantsTypes].
Type | Description | Default
:----------------------|:-----------------------------------------|:------------------
int | A signed, 32 bit GLSL int | 0
float | A single-precision GLSL float | 0.0
bool | A GLSL bool | false
Constants may also be specified as mutable by setting the `mutable` property to `true`. Only
`bool` spec constants may be specified as mutable.
| Type | Description | Default | May be mutable? |
|:------|:------------------------------|:--------|-----------------|
| int | A signed, 32 bit GLSL int | | no |
| float | A single-precision GLSL float | 0.0 | no |
| bool | A GLSL bool | false | yes |
[Table [materialConstantsTypes]: Material constants types]
Description
: Lists the constant parameters accepted by your material. These constants can be set, or
"specialized", at runtime when loading a material package. Multiple materials can be loaded from
the same material package with differing constant parameter specializations. Once a material is
loaded from a material package, its constant parameters cannot be changed. Compared to regular
parameters, constant parameters allow the compiler to generate more efficient code. Access
constant parameters from the shader by prefixing the name with `materialConstant_`. For example,
a constant parameter named `myConstant` is accessed in the shader as
`materialConstant_myConstant`. If a constant parameter is not set at runtime, the default is
used.
the same material package with differing constant parameter specializations. If a constant
parameter is specialized as mutable, it may be changed at any time on a per-instance basis via
`MaterialInstance::setConstant(name, value)`. Otherwise, once a material is loaded from a
material package, its constant parameters cannot be changed.
Compared to regular parameters, constant parameters allow the compiler to generate more
efficient code. Access constant parameters from the shader by prefixing the name with
`materialConstant_`. For example, a constant parameter named `myConstant` is accessed in the
shader as `materialConstant_myConstant`. If a constant parameter is not set at runtime, the
default is used.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
constants : [
{
name : overrideAlpha,
type : bool
type : bool,
mutable : true,
},
{
name : customAlpha,
@@ -2553,7 +2560,7 @@ standard skybox material. It produces a list of 2 parameters, named `showSun` an
respectively a boolean and a cubemap texture.
```text
$ matc --reflect parameters filament/src/materials/skybox.mat
$ matc --reflect parameters filament/src/materials/skybox.mat
{
"parameters": [
{
@@ -2569,7 +2576,7 @@ $ matc --reflect parameters filament/src/materials/skybox.mat
}
]
}
```
```
### --variant-filter
@@ -149,13 +149,6 @@ public:
* - PlatformEGLAndroid
*/
bool assertNativeWindowIsValid = false;
/**
* The action to take if a Drawable cannot be acquired. If true, the
* frame is aborted instead of panic. This is only supported for:
* - PlatformMetal
*/
bool metalDisablePanicOnDrawableFailure = false;
};
Platform() noexcept;
+4 -1
View File
@@ -20,6 +20,7 @@
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Invocable.h>
#include <utils/bitset.h>
#include <backend/DriverEnums.h>
@@ -66,6 +67,7 @@ public:
using DescriptorBindingsInfo = utils::FixedCapacityVector<Descriptor>;
using DescriptorSetInfo = std::array<DescriptorBindingsInfo, MAX_DESCRIPTOR_SET_COUNT>;
using SpecializationConstantsInfo = utils::FixedCapacityVector<SpecializationConstant>;
using MutableSpecConstantsInfo = utils::bitset8;
using ShaderBlob = utils::FixedCapacityVector<uint8_t>;
using ShaderSource = std::array<ShaderBlob, SHADER_TYPE_COUNT>;
@@ -102,7 +104,8 @@ public:
Program& descriptorBindings(backend::descriptor_set_t set,
DescriptorBindingsInfo descriptorBindings) noexcept;
Program& specializationConstants(SpecializationConstantsInfo specConstants) noexcept;
Program& specializationConstants(SpecializationConstantsInfo specConstants,
uint32_t firstMutableId, MutableSpecConstantsInfo mutableSpecConstants) noexcept;
struct PushConstant {
utils::CString name;
+11 -1
View File
@@ -80,8 +80,18 @@ Program& Program::attributes(AttributesInfo attributes) noexcept {
return *this;
}
Program& Program::specializationConstants(SpecializationConstantsInfo specConstants) noexcept {
Program& Program::specializationConstants(SpecializationConstantsInfo specConstants,
uint32_t firstMutableId, MutableSpecConstantsInfo mutableSpecConstants) noexcept {
// String the two lists together.
mSpecializationConstants = std::move(specConstants);
uint32_t firstMutableIndex = specConstants.size();
mSpecializationConstants.reserve(specConstants.size() + mutableSpecConstants.size());
for (uint32_t i = 0; i < mutableSpecConstants.size(); i++) {
mSpecializationConstants[i + firstMutableIndex] = SpecializationConstant {
.id = i + firstMutableId,
.value = mutableSpecConstants[i],
};
}
return *this;
}
@@ -53,9 +53,6 @@ PlatformMetal::~PlatformMetal() noexcept {
}
Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::DriverConfig& driverConfig) noexcept {
pImpl->mDrawableFailureBehavior = driverConfig.metalDisablePanicOnDrawableFailure
? DrawableFailureBehavior::ABORT_FRAME
: DrawableFailureBehavior::PANIC;
return MetalDriverFactory::create(this, driverConfig);
}
@@ -122,18 +122,12 @@ struct ShaderCompilerService::OpenGLProgramToken : ProgramToken {
}
std::optional<CallbackManager::Handle> handle{};
// Only valid when the blob functions are provided by users. The validity of this variable
// doesn't guarantee that the program was created from the cache blob.
BlobCacheKey key;
// Used for the `THREAD_POOL` mode.
mutable Mutex lock;
mutable Condition cond;
bool signaled = false;
// Indicate this program was created from the cache blob.
bool retrievedFromBlobCache = false;
};
ShaderCompilerService::OpenGLProgramToken::~OpenGLProgramToken() {
@@ -265,7 +259,6 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
// Try retrieving the cached program blob if available.
token->gl.program = mBlobCache.retrieve(&token->key, mDriver.mPlatform, program);
if (token->gl.program) {
token->retrievedFromBlobCache = true;
return token;
}
@@ -344,15 +337,12 @@ GLuint ShaderCompilerService::getProgram(program_token_t& token) {
assert_invariant(token);// This function should be called when the token is still alive.
// Finalize any pending shader compilation tasks only when the token was created without cache.
if (!token->retrievedFromBlobCache) {
if (token->compiler.mMode == Mode::THREAD_POOL) {
auto const job = token->compiler.mCompilerThreadPool.dequeue(token);
if (!job) {
// It's likely that the job was already completed. But it may be still being
// executed at this moment. Just try waiting for it to avoid a race.
token->wait();
}
if (token->compiler.mMode == Mode::THREAD_POOL) {
auto const job = token->compiler.mCompilerThreadPool.dequeue(token);
if (!job) {
// It's likely that the job was already completed. But it may be still being
// executed at this moment. Just try waiting for it to avoid a race.
token->wait();
}
}
@@ -27,8 +27,7 @@ namespace filament::backend {
VulkanBufferProxy::VulkanBufferProxy(VmaAllocator allocator, VulkanStagePool& stagePool,
VulkanBufferCache& bufferCache, VulkanBufferUsage usage, uint32_t numBytes)
: mAllocator(allocator),
mStagePool(stagePool),
: mStagePool(stagePool),
mBufferCache(bufferCache),
mBuffer(mBufferCache.acquire(usage, numBytes)),
mUpdatedOffset(0),
@@ -39,10 +38,8 @@ void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* c
// Note: this should be stored within the command buffer before going out of
// scope, so that the command buffer can manage its lifecycle.
fvkmemory::resource_ptr<VulkanStage::Segment> stage = mStagePool.acquireStage(numBytes);
assert_invariant(stage->memory());
commands.acquire(stage);
memcpy(stage->mapping(), cpuData, numBytes);
vmaFlushAllocation(mAllocator, stage->memory(), stage->offset(), numBytes);
stage->copy(0, cpuData, numBytes);
// If there was a previous update, then we need to make sure the following write is properly
// synced with the previous read.
@@ -40,7 +40,6 @@ public:
VulkanBufferUsage getUsage() const noexcept;
private:
VmaAllocator mAllocator;
VulkanStagePool& mStagePool;
VulkanBufferCache& mBufferCache;
@@ -95,7 +95,7 @@
#endif
#ifndef NDEBUG
#define FVK_DEBUG_FLAGS (FVK_DEBUG_PERFORMANCE | FVK_DEBUG_FORWARDED_FLAG)
#define FVK_DEBUG_FLAGS (FVK_DEBUG_PERFORMANCE | FVK_DEBUG_FORWARDED_FLAG | FVK_DEBUG_DEBUG_UTILS | FVK_DEBUG_GROUP_MARKERS | FVK_DEBUG_VALIDATION)
#else
#define FVK_DEBUG_FLAGS 0
#endif
@@ -38,15 +38,23 @@ constexpr uint32_t STAGE_SIZE = 1048576;
fvkmemory::resource_ptr<VulkanStage::Segment> VulkanStage::acquireSegment(
fvkmemory::ResourceManager* resManager, uint32_t numBytes) {
auto segment = fvkmemory::resource_ptr<Segment>::construct(
resManager, this, numBytes, mCurrentOffset, [this](uint32_t offset) {
mSegments.erase(offset);
});
mSegments.insert({mCurrentOffset, segment.get()});
auto segment = fvkmemory::resource_ptr<Segment>::construct(resManager, mAllocator, this,
mCurrentOffset, [this](uint32_t offset) { mSegments.erase(offset); });
mSegments.insert({ mCurrentOffset, segment.get() });
// constexpr uint32_t BLOCK_SIZE = 16;
// uint32_t const additional = BLOCK_SIZE - (numBytes % BLOCK_SIZE);
// numBytes += (additional != BLOCK_SIZE ? additional : 0);
mCurrentOffset += numBytes;
return segment;
}
VkResult VulkanStage::Segment::copy(size_t dstOffset, void const* src, size_t writeSize) {
// uint8_t* mapped = ((uint8_t*) mapping()) + dstOffset;
// memcpy(mapped, src, writeSize);
// return vmaFlushAllocation(mAllocator, memory(), offset() + dstOffset, writeSize);
return vmaCopyMemoryToAllocation(mAllocator, src, memory(), offset() + dstOffset, writeSize);
}
VulkanStagePool::VulkanStagePool(VmaAllocator allocator, fvkmemory::ResourceManager* resManager,
VulkanCommands* commands, const VkPhysicalDeviceLimits* deviceLimits)
: mAllocator(allocator),
@@ -125,7 +133,7 @@ VulkanStage* VulkanStagePool::allocateNewStage(uint32_t capacity) {
#endif
}
return new VulkanStage(memory, buffer, capacity, pMapping);
return new VulkanStage(mAllocator, memory, buffer, capacity, pMapping);
}
void VulkanStagePool::destroyStage(VulkanStage const*&& stage) {
+14 -11
View File
@@ -35,8 +35,10 @@ class VulkanCommands;
// into smaller buffers as needed.
class VulkanStage {
public:
VulkanStage(VmaAllocation memory, VkBuffer buffer, uint32_t capacity, void* mapping)
: mMemory(memory),
VulkanStage(VmaAllocator allocator, VmaAllocation memory, VkBuffer buffer, uint32_t capacity,
void* mapping)
: mAllocator(allocator),
mMemory(memory),
mBuffer(buffer),
mCapacity(capacity),
mMapping(mapping) {}
@@ -51,10 +53,10 @@ public:
public:
using OnRecycle = std::function<void(uint32_t offset)>;
Segment(VulkanStage* parentStage, uint32_t capacity, uint32_t offset,
Segment(VmaAllocator allocator, VulkanStage* parentStage, uint32_t offset,
OnRecycle&& onRecycleFn)
: mParentStage(parentStage),
mCapacity(capacity),
: mAllocator(allocator),
mParentStage(parentStage),
mOffset(offset),
mOnRecycleFn(onRecycleFn) {}
@@ -70,12 +72,12 @@ public:
Segment& operator=(const Segment& other) = delete;
Segment& operator=(Segment&& other) = delete;
inline VulkanStage* parentStage() const { return mParentStage; }
inline VkBuffer buffer() const { return parentStage()->buffer(); }
inline VmaAllocation memory() const { return parentStage()->memory(); }
inline uint32_t capacity() const { return mCapacity; }
inline VkBuffer buffer() const { return mParentStage->buffer(); }
inline VmaAllocation memory() const { return mParentStage->memory(); }
inline uint32_t offset() const { return mOffset; }
VkResult copy(size_t dstOffset, void const* src, size_t writeSize);
inline void* mapping() const {
return reinterpret_cast<void*>(
reinterpret_cast<char*>(mParentStage->mapping()) + offset());
@@ -85,9 +87,9 @@ public:
// Ensure parent class can access the terminate method.
friend class VulkanStage;
VmaAllocator const mAllocator;
VulkanStage* const mParentStage;
const uint32_t mCapacity;
const uint32_t mOffset;
uint32_t const mOffset;
OnRecycle mOnRecycleFn;
};
@@ -109,6 +111,7 @@ public:
uint32_t numBytes);
private:
VmaAllocator const mAllocator;
const VmaAllocation mMemory;
const VkBuffer mBuffer;
const uint32_t mCapacity;
+15 -9
View File
@@ -219,8 +219,8 @@ VkImageUsageFlags getUsage(VulkanContext const& context, uint8_t samples,
return usage;
}
void adjustedMemcpy(void* mapped, PixelBufferDescriptor const& p, size_t width, size_t height,
size_t depth) {
void adjustedMemcpy(PixelBufferDescriptor const& p, size_t width, size_t height,
size_t depth, std::function<void(size_t, uint8_t*, size_t)> cpy) {
uint8_t* buf = (uint8_t*) p.buffer;
size_t const pixelSize = PixelBufferDescriptor::computeDataSize(p.format, p.type, 1, 1, 1);
size_t const pbdStride = p.stride ? p.stride : width;
@@ -243,13 +243,13 @@ void adjustedMemcpy(void* mapped, PixelBufferDescriptor const& p, size_t width,
for (size_t y = p.top; y < pbdHeight; y++) {
uint8_t* buf = (uint8_t*) p.buffer +
((p.left * pixelSize) + (y * pbdRowSize) + (z * pbdLayerSize));
uint8_t* curMapped = (uint8_t*) mapped + ((y - p.top) * rowSize + z * layerSize);
memcpy(curMapped, buf, writeSize);
uint32_t const offset = (y - p.top) * rowSize + z * layerSize;
cpy(offset, buf, writeSize);
}
}
} else {
size_t const writeSize = pixelSize * (width * height * depth);
memcpy(mapped, buf, writeSize);
cpy(0, buf, writeSize);
}
}
@@ -525,9 +525,12 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt
fvkmemory::resource_ptr<VulkanStage::Segment> stageSegment =
mState->mStagePool.acquireStage(writeSize);
assert_invariant(stageSegment->memory());
adjustedMemcpy(stageSegment->mapping(), *hostData, width, height, depth);
vmaFlushAllocation(mState->mAllocator, stageSegment->memory(), stageSegment->offset(),
writeSize);
adjustedMemcpy(*hostData, width, height, depth,
[&stageSegment](size_t dstOffset, uint8_t* src, size_t numBytes) {
stageSegment->copy(dstOffset, src, numBytes);
});
// vmaFlushAllocation(mState->mAllocator, stageSegment->memory(), stageSegment->offset(),
// writeSize);
VulkanCommandBuffer& commands = mState->mCommands->get();
VkCommandBuffer const cmdbuf = commands.buffer();
@@ -597,7 +600,10 @@ void VulkanTexture::updateImageWithBlit(const PixelBufferDescriptor& data, uint3
VulkanStageImage const* stage
= mState->mStagePool.acquireImage(data.format, data.type, width, height);
vmaMapMemory(mState->mAllocator, stage->memory, &mapped);
adjustedMemcpy(mapped, data, width, height, depth);
adjustedMemcpy(data, width, height, depth,
[&mapped](size_t, uint8_t* src, size_t numBytes) {
memcpy(mapped, src, numBytes);
});
vmaUnmapMemory(mState->mAllocator, stage->memory);
vmaFlushAllocation(mState->mAllocator, stage->memory, 0, writeSize);
@@ -923,7 +923,7 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
// Keep a copy of context for swapchains.
mImpl->mContext = context;
return VulkanDriver::create(this, mImpl->mContext, driverConfig);
return VulkanDriver::create(this, context, driverConfig);
}
// This needs to be explictly written for
+12 -4
View File
@@ -529,8 +529,8 @@ bool WebGPUDriver::isTextureSwizzleSupported() {
}
bool WebGPUDriver::isTextureFormatMipmappable(const TextureFormat format) {
//todo
return true;
return WebGPUTexture::supportsMultipleMipLevelsViaStorageBinding(
WebGPUTexture::fToWGPUTextureFormat(format));
}
bool WebGPUDriver::isRenderTargetFormatSupported(const TextureFormat format) {
@@ -756,6 +756,14 @@ void WebGPUDriver::generateMipmaps(Handle<HwTexture> textureHandle) {
if (mipLevelCount <= 1) {
return;
}
FILAMENT_CHECK_PRECONDITION(texture->supportsMultipleMipLevels())
<< "Calling generateMipmaps(...) on a texture that doesn't support generating them. "
"sampler type "
<< to_string(texture->target) << " levels " << static_cast<uint32_t>(texture->levels)
<< " wgpu format (enum value) "
<< static_cast<uint32_t>(texture->getTexture().GetFormat()) << " width "
<< texture->width << " height " << texture->height << " depth " << texture->depth
<< " usage flags (as a number) " << static_cast<uint32_t>(texture->usage);
uint32_t width = wgpuTexture.GetWidth();
uint32_t height = wgpuTexture.GetHeight();
@@ -853,7 +861,7 @@ void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> renderTargetHandle,
const uint32_t depthArrayLayer = depthInfo.layer;
customDepthView =
depthTexture->getOrMakeTextureView(depthMipLevel, depthArrayLayer);
customDepthFormat = depthTexture->getWebGPUFormat();
customDepthFormat = depthTexture->getViewFormat();
}
}
@@ -870,7 +878,7 @@ void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> renderTargetHandle,
const uint32_t stencilArrayLayer = stencilInfo.layer;
customStencilView =
stencilTexture->getOrMakeTextureView(stencilMipLevel, stencilArrayLayer);
customStencilFormat = stencilTexture->getWebGPUFormat();
customStencilFormat = stencilTexture->getViewFormat();
}
}
}
@@ -29,6 +29,7 @@
#include <utils/compiler.h>
#include <tsl/robin_map.h>
#include <webgpu/webgpu_cpp.h>
#include <cstdint>
+140 -19
View File
@@ -28,6 +28,10 @@
#include <utils/ostream.h>
#include <webgpu/webgpu_cpp.h>
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
#include <webgpu/webgpu_cpp_print.h>
#include <sstream>
#endif
#include <cstdint>
@@ -59,21 +63,108 @@ namespace {
}
}
/**
* @param format texture format to potentially be used for storage binding
* @return true if the format is compatible with wgpu::TextureUsage::StorageBinding
*/
[[nodiscard]] constexpr bool isFormatStorageCompatible(const wgpu::TextureFormat format) {
switch (format) {
// List of formats that support storage binding
case wgpu::TextureFormat::R32Float:
case wgpu::TextureFormat::R32Sint:
case wgpu::TextureFormat::R32Uint:
case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RG32Sint:
case wgpu::TextureFormat::RG32Uint:
case wgpu::TextureFormat::RGBA16Float:
case wgpu::TextureFormat::RGBA16Sint:
case wgpu::TextureFormat::RGBA16Uint:
case wgpu::TextureFormat::RGBA32Float:
case wgpu::TextureFormat::RGBA32Sint:
case wgpu::TextureFormat::RGBA32Uint:
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8Snorm:
case wgpu::TextureFormat::RGBA8Uint:
case wgpu::TextureFormat::RGBA8Sint:
return true;
default:
// All other formats, including packed floats (RG11B10Ufloat),
// depth/stencil, and sRGB formats do not support storage.
return false;
}
}
/**
* @param viewFormat potential view format to a texture
* @return an underlying texture format that is storage binding compatible for which this view
* texture format can be used. If no such format exists, Undefined is returned.
* If the view texture is already storage binding compatible then the view texture itself
* is returned.
*/
[[nodiscard]] constexpr wgpu::TextureFormat storageBindingCompatibleFormatForViewFormat(
const wgpu::TextureFormat viewFormat) {
switch (viewFormat) {
case wgpu::TextureFormat::RGBA8UnormSrgb: return wgpu::TextureFormat::RGBA8Unorm;
case wgpu::TextureFormat::BGRA8UnormSrgb: return wgpu::TextureFormat::BGRA8Unorm;
case wgpu::TextureFormat::BC1RGBAUnormSrgb: return wgpu::TextureFormat::BC1RGBAUnorm;
case wgpu::TextureFormat::BC2RGBAUnormSrgb: return wgpu::TextureFormat::BC2RGBAUnorm;
case wgpu::TextureFormat::BC3RGBAUnormSrgb: return wgpu::TextureFormat::BC3RGBAUnorm;
case wgpu::TextureFormat::BC7RGBAUnormSrgb: return wgpu::TextureFormat::BC7RGBAUnorm;
case wgpu::TextureFormat::ETC2RGB8UnormSrgb: return wgpu::TextureFormat::ETC2RGB8Unorm;
case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb: return wgpu::TextureFormat::ETC2RGB8A1Unorm;
case wgpu::TextureFormat::ETC2RGBA8UnormSrgb: return wgpu::TextureFormat::ETC2RGBA8Unorm;
case wgpu::TextureFormat::ASTC4x4UnormSrgb: return wgpu::TextureFormat::ASTC4x4Unorm;
case wgpu::TextureFormat::ASTC5x4UnormSrgb: return wgpu::TextureFormat::ASTC5x4Unorm;
case wgpu::TextureFormat::ASTC5x5UnormSrgb: return wgpu::TextureFormat::ASTC5x5Unorm;
case wgpu::TextureFormat::ASTC6x5UnormSrgb: return wgpu::TextureFormat::ASTC6x5Unorm;
case wgpu::TextureFormat::ASTC6x6UnormSrgb: return wgpu::TextureFormat::ASTC6x6Unorm;
case wgpu::TextureFormat::ASTC8x5UnormSrgb: return wgpu::TextureFormat::ASTC8x5Unorm;
case wgpu::TextureFormat::ASTC8x6UnormSrgb: return wgpu::TextureFormat::ASTC8x6Unorm;
case wgpu::TextureFormat::ASTC8x8UnormSrgb: return wgpu::TextureFormat::ASTC8x8Unorm;
case wgpu::TextureFormat::ASTC10x5UnormSrgb: return wgpu::TextureFormat::ASTC10x5Unorm;
case wgpu::TextureFormat::ASTC10x6UnormSrgb: return wgpu::TextureFormat::ASTC10x6Unorm;
case wgpu::TextureFormat::ASTC10x8UnormSrgb: return wgpu::TextureFormat::ASTC10x8Unorm;
case wgpu::TextureFormat::ASTC10x10UnormSrgb: return wgpu::TextureFormat::ASTC10x10Unorm;
case wgpu::TextureFormat::ASTC12x10UnormSrgb: return wgpu::TextureFormat::ASTC12x10Unorm;
case wgpu::TextureFormat::ASTC12x12UnormSrgb: return wgpu::TextureFormat::ASTC12x12Unorm;
default:
if (isFormatStorageCompatible(viewFormat)) {
return viewFormat; // view format is itself already storage binding compatible
} else {
return wgpu::TextureFormat::Undefined; // no valid format in this case
}
}
}
/**
* @param fUsage Filament's requested texture usage
* @param samples How many samples to use for MSAA
* @param needsComputeStorageSupport if we need to use this texture as storage binding in something
* like a compute shader
* @return The appropriate texture usage flags for the underlying texture
*/
[[nodiscard]] wgpu::TextureUsage fToWGPUTextureUsage(TextureUsage const& fUsage,
const uint8_t samples) {
const uint8_t samples, const bool needsComputeStorageSupport) {
wgpu::TextureUsage retUsage = wgpu::TextureUsage::None;
// if needsComputeStorageSupport we need to read and write to the texture in a shader and thus
// require CopySrc, CopyDst, TextureBinding, & StorageBinding
// Basing this mapping off of VulkanTexture.cpp's getUsage func and suggestions from Gemini
// TODO Validate assumptions, revisit if issues.
if (any(TextureUsage::BLIT_SRC & fUsage)) {
if (needsComputeStorageSupport || any(TextureUsage::BLIT_SRC & fUsage)) {
retUsage |= wgpu::TextureUsage::CopySrc;
}
if (any((TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE) & fUsage)) {
if (needsComputeStorageSupport ||
any((TextureUsage::BLIT_DST | TextureUsage::UPLOADABLE) & fUsage)) {
retUsage |= wgpu::TextureUsage::CopyDst;
}
if (any(TextureUsage::SAMPLEABLE & fUsage)) {
if (needsComputeStorageSupport || any(TextureUsage::SAMPLEABLE & fUsage)) {
retUsage |= wgpu::TextureUsage::TextureBinding;
}
if (needsComputeStorageSupport) {
retUsage |= wgpu::TextureUsage::StorageBinding;
}
// WGPU Render attachment covers either color or stencil situation dependant
// NOTE: Depth attachment isn't used this way in Vulkan but logically maps to WGPU docs. If
// issues, investigate here.
@@ -100,7 +191,6 @@ namespace {
retUsage |= wgpu::TextureUsage::TransientAttachment;
}
// NOTE: Unused wgpu flags:
// StorageBinding
// StorageAttachment
// NOTE: Unused Filament flags:
@@ -205,11 +295,19 @@ WebGPUTexture::WebGPUTexture(const SamplerType samplerType, const uint8_t levels
const uint32_t height, const uint32_t depth, const TextureUsage usage,
wgpu::Device const& device) noexcept
: HwTexture{ samplerType, levels, samples, width, height, depth, format, usage },
mWebGPUFormat{ fToWGPUTextureFormat(format) },
mViewFormat{ fToWGPUTextureFormat(format) },
mSupportsMultipleMipLevels{ levels > 1 &&
supportsMultipleMipLevelsViaStorageBinding(mViewFormat) },
mWebGPUFormat{ mSupportsMultipleMipLevels
? storageBindingCompatibleFormatForViewFormat(mViewFormat)
: mViewFormat },
mAspect{ fToWGPUTextureViewAspect(usage, format) },
mWebGPUUsage{ fToWGPUTextureUsage(usage, samples) },
mWebGPUUsage{ fToWGPUTextureUsage(usage, samples, mSupportsMultipleMipLevels) },
mViewUsage{ fToWGPUTextureUsage(usage, samples, false) },
mBlockWidth{ filament::backend::getBlockWidth(format) },
mBlockHeight{ filament::backend::getBlockHeight(format) } {
mBlockHeight{ filament::backend::getBlockHeight(format) },
mDefaultMipLevel{ 0 },
mDefaultBaseArrayLayer{ 0 } {
assert_invariant(
samples == 1 ||
samples == 4 &&
@@ -225,10 +323,8 @@ WebGPUTexture::WebGPUTexture(const SamplerType samplerType, const uint8_t levels
.format = mWebGPUFormat,
.mipLevelCount = levels,
.sampleCount = samples,
// TODO Is this fine? Could do all-the-things, a naive mapping or get something from
// Filament
.viewFormatCount = 0,
.viewFormats = nullptr,
.viewFormatCount = 1,
.viewFormats = &mViewFormat,
};
mArrayLayerCount = toArrayLayerCount(samplerType, textureDescriptor.size.depthOrArrayLayers);
assert_invariant(textureDescriptor.format != wgpu::TextureFormat::Undefined &&
@@ -240,23 +336,41 @@ WebGPUTexture::WebGPUTexture(const SamplerType samplerType, const uint8_t levels
mArrayLayerCount, samplerType);
FILAMENT_CHECK_POSTCONDITION(mDefaultTextureView)
<< "Failed to create default texture view for " << textureDescriptor.label;
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
if (mViewFormat != mWebGPUFormat) {
std::stringstream viewFormatStream;
viewFormatStream << mViewFormat;
std::stringstream textureFormatStream;
textureFormatStream << mWebGPUFormat;
FWGPU_LOGD << "Texture '" << textureDescriptor.label << "' has view format "
<< viewFormatStream.str() << " and texture format " << textureFormatStream.str()
<< utils::io::endl;
}
#endif
}
WebGPUTexture::WebGPUTexture(WebGPUTexture const* src, const uint8_t baseLevel,
const uint8_t levelCount) noexcept
: HwTexture{ src->target, levelCount, src->samples, src->width, src->height, src->depth,
src->format, src->usage },
mTexture{ src->mTexture },
mViewFormat{ src->mViewFormat },
mSupportsMultipleMipLevels{ src->mSupportsMultipleMipLevels },
mWebGPUFormat{ src->mWebGPUFormat },
mAspect{ src->mAspect },
mWebGPUUsage{ src->mWebGPUUsage },
mArrayLayerCount{ src->mArrayLayerCount },
mViewUsage{ src->mViewUsage },
mBlockWidth{ src->mBlockWidth },
mBlockHeight{ src->mBlockHeight },
mDefaultTextureView{ makeTextureView(baseLevel, levelCount, 0, src->mArrayLayerCount,
src->target) },
mArrayLayerCount{ src->mArrayLayerCount },
mTexture{ src->mTexture },
mDefaultMipLevel{ baseLevel },
mDefaultBaseArrayLayer{ src->mArrayLayerCount } {}
mDefaultBaseArrayLayer{ src->mArrayLayerCount },
mDefaultTextureView{ makeTextureView(mDefaultMipLevel, levelCount, 0, mDefaultBaseArrayLayer,
src->target) } {}
bool WebGPUTexture::supportsMultipleMipLevelsViaStorageBinding(const wgpu::TextureFormat format) {
return storageBindingCompatibleFormatForViewFormat(format) != wgpu::TextureFormat::Undefined;
}
wgpu::TextureView WebGPUTexture::getOrMakeTextureView(const uint8_t mipLevel,
const uint32_t arrayLayer) {
@@ -455,16 +569,23 @@ wgpu::TextureFormat WebGPUTexture::fToWGPUTextureFormat(TextureFormat const& fFo
wgpu::TextureView WebGPUTexture::makeTextureView(const uint8_t& baseLevel,
const uint8_t& levelCount, const uint32_t& baseArrayLayer, const uint32_t& arrayLayerCount,
const SamplerType samplerType) const noexcept {
#if FWGPU_ENABLED(FWGPU_DEBUG_VALIDATION)
if (baseLevel > 0 && !mSupportsMultipleMipLevels) {
FWGPU_LOGW << "Trying to make a texture view into a level ("
<< static_cast<uint32_t>(baseLevel)
<< ") for which we cannot generate mip levels." << utils::io::endl;
}
#endif
const wgpu::TextureViewDescriptor textureViewDescriptor{
.label = getUserTextureViewLabel(target),
.format = mWebGPUFormat,
.format = mViewFormat,
.dimension = toWebGPUTextureViewDimension(samplerType),
.baseMipLevel = baseLevel,
.mipLevelCount = levelCount,
.baseArrayLayer = baseArrayLayer,
.arrayLayerCount = arrayLayerCount,
.aspect = mAspect,
.usage = mWebGPUUsage };
.usage = mViewUsage };
wgpu::TextureView textureView = mTexture.CreateView(&textureViewDescriptor);
FILAMENT_CHECK_POSTCONDITION(textureView)
<< "Failed to create texture view " << textureViewDescriptor.label;
+24 -7
View File
@@ -47,29 +47,46 @@ public:
[[nodiscard]] wgpu::TextureView getOrMakeTextureView(uint8_t mipLevel, uint32_t arrayLayer);
[[nodiscard]] wgpu::TextureFormat getWebGPUFormat() const { return mWebGPUFormat; }
[[nodiscard]] wgpu::TextureFormat getViewFormat() const { return mViewFormat; }
[[nodiscard]] uint32_t getArrayLayerCount() const { return mArrayLayerCount; }
[[nodiscard]] bool supportsMultipleMipLevels() const { return mSupportsMultipleMipLevels; }
[[nodiscard]] static wgpu::TextureFormat fToWGPUTextureFormat(
filament::backend::TextureFormat const& fFormat);
/**
* @param format a required texture format (can be a view to a different underlying texture
* format)
* @return true if multiple mip levels can be generated via a compute shader + storage binding
* on the texture, false otherwise.
*/
[[nodiscard]] static bool supportsMultipleMipLevelsViaStorageBinding(
wgpu::TextureFormat format);
private:
// CreateTextureR has info for a texture and sampler. Texture Views are needed for binding,
// along with a sampler Current plan: Inherit the sampler and Texture to always exist (It is a
// ref counted pointer) when making views. View is optional
wgpu::Texture mTexture = nullptr;
// the texture view's format, which may differ from the underlying texture's format itself,
// an example of when this is needed is when certain underlying shaders don't support
// certain formats (e.g. compute shaders), but we need a view to that format elsewhere
// (e.g. another shader or render target)
wgpu::TextureFormat mViewFormat = wgpu::TextureFormat::Undefined;
// this is true IFF levels > 1 AND we can actually generate mipmaps for the texture
bool mSupportsMultipleMipLevels = false;
// format is inherited from HwTexture. This naming is to distinguish it from Filament's format
// this is the underlying texture's format, not necessarily the "view" of it... see mViewFormat
wgpu::TextureFormat mWebGPUFormat = wgpu::TextureFormat::Undefined;
wgpu::TextureAspect mAspect = wgpu::TextureAspect::Undefined;
// usage is inherited from HwTexture. This naming is to distinguish it from Filament's usage
wgpu::TextureUsage mWebGPUUsage = wgpu::TextureUsage::None;
uint32_t mArrayLayerCount = 1;
wgpu::TextureUsage mViewUsage = wgpu::TextureUsage::None;
size_t mBlockWidth = 0;
size_t mBlockHeight = 0;
wgpu::TextureView mDefaultTextureView = nullptr;
uint32_t mArrayLayerCount = 1;
wgpu::Texture mTexture = nullptr;
uint32_t mDefaultMipLevel = 0;
uint32_t mDefaultBaseArrayLayer = 0;
wgpu::TextureView mDefaultTextureView = nullptr;
[[nodiscard]] wgpu::TextureView makeTextureView(const uint8_t& baseLevel,
const uint8_t& levelCount, const uint32_t& baseArrayLayer,
-9
View File
@@ -317,15 +317,6 @@ public:
*/
size_t metalUploadBufferSizeBytes = 512 * 1024;
/**
* The action to take if a Drawable cannot be acquired.
*
* Each frame rendered requires a CAMetalDrawable texture, which is
* presented on-screen at the completion of each frame. These are
* limited and provided round-robin style by the system.
*/
bool metalDisablePanicOnDrawableFailure = false;
/**
* Set to `true` to forcibly disable parallel shader compilation in the backend.
* Currently only honored by the GL and Metal backends.
+53 -3
View File
@@ -86,6 +86,9 @@ public:
std::is_same_v<math::mat3f, T>
>;
template<typename T>
using is_supported_constant_parameter_t = std::enable_if_t<std::is_same_v<bool, T>>;
/**
* Creates a new MaterialInstance using another MaterialInstance as a template for initialization.
* The new MaterialInstance is an instance of the same Material of the template instance and
@@ -237,13 +240,13 @@ public:
/**
* Gets the value of a parameter by name.
*
*
* Note: Only supports non-texture parameters such as numeric and math types.
*
*
* @param name Name of the parameter as defined by Material. Cannot be nullptr.
* @param nameLength Length in `char` of the name parameter.
* @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled.
*
*
* @see Material::hasParameter
*/
template<typename T>
@@ -261,6 +264,53 @@ public:
return getParameter<T>(name, strlen(name));
}
/**
* Set a mutable constant parameter by name.
*
* @param name Name of the parameter as defined by Material. Cannot be nullptr.
* @param nameLength Length in `char` of the name parameter.
* @param value Value of the parameter to set.
* @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled.
*/
template<typename T, typename = is_supported_constant_parameter_t<T>>
void setConstant(const char* UTILS_NONNULL name, size_t nameLength, T const& value);
/** inline helper to provide the name as a null-terminated string literal */
template<typename T, typename = is_supported_constant_parameter_t<T>>
void setConstant(StringLiteral const name, T const& value) {
setConstant<T>(name.data, name.size, value);
}
/** inline helper to provide the name as a null-terminated C string */
template<typename T, typename = is_supported_constant_parameter_t<T>>
void setConstant(const char* UTILS_NONNULL name, T const& value) {
setConstant<T>(name, strlen(name), value);
}
/**
* Gets the value of a mutable constant parameter by name.
*
* @param name Name of the parameter as defined by Material. Cannot be nullptr.
* @param nameLength Length in `char` of the name parameter.
* @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled.
*
* @see Material::hasConstant
*/
template<typename T, typename = is_supported_constant_parameter_t<T>>
T getConstant(const char* UTILS_NONNULL name, size_t nameLength) const;
/** inline helper to provide the name as a null-terminated C string */
template<typename T, typename = is_supported_constant_parameter_t<T>>
T getConstant(StringLiteral const name) const {
return getConstant<T>(name.data, name.size);
}
/** inline helper to provide the name as a null-terminated C string */
template<typename T, typename = is_supported_constant_parameter_t<T>>
T getConstant(const char* UTILS_NONNULL name) const {
return getConstant<T>(name, strlen(name));
}
/**
* Set-up a custom scissor rectangle; by default it is disabled.
*
+40
View File
@@ -232,6 +232,46 @@ template UTILS_PUBLIC mat3f MaterialInstance::getParameter<mat3f> (const ch
// ------------------------------------------------------------------------------------------------
template<>
inline void FMaterialInstance::setConstantImpl<bool>(std::string_view const name, bool const& value) {
std::optional<uint32_t> id = mMaterial->getMutableConstantId(name);
FILAMENT_CHECK_PRECONDITION(id.has_value()) << "No mutable constant with name " << name;
mConstants.set(*id, value);
}
template<typename T, typename>
void MaterialInstance::setConstant(const char* name, size_t nameLength, T const& value) {
downcast(this)->setConstantImpl({ name, nameLength }, value);
}
// Explicit template instantiation of our supported types.
//
// Mutable spec constants will probably only ever allow bools, but it's nice to keep the API
// forwards-compatible.
template UTILS_PUBLIC void MaterialInstance::setConstant<bool>(const char* name, size_t nameLength, bool const& v);
// ------------------------------------------------------------------------------------------------
template<>
inline bool FMaterialInstance::getConstantImpl<bool>(std::string_view const name) const {
std::optional<uint32_t> id = mMaterial->getMutableConstantId(name);
FILAMENT_CHECK_PRECONDITION(id.has_value()) << "No mutable constant with name " << name;
return mConstants[*id];
}
template<typename T, typename>
T MaterialInstance::getConstant(const char* name, size_t nameLength) const {
return downcast(this)->getConstantImpl<T>({ name, nameLength });
}
// Explicit template instantiation of our supported types.
//
// Mutable spec constants will probably only ever allow bools, but it's nice to keep the API
// forwards-compatible.
template UTILS_PUBLIC bool MaterialInstance::getConstant<bool>(const char* name, size_t nameLength) const;
// ------------------------------------------------------------------------------------------------
Material const* MaterialInstance::getMaterial() const noexcept {
return downcast(this)->getMaterial();
}
+37
View File
@@ -229,6 +229,11 @@ bool MaterialParser::getConstants(FixedCapacityVector<MaterialConstant>* contain
return get<ChunkMaterialConstants>(container);
}
bool MaterialParser::getMutableConstants(
FixedCapacityVector<MaterialMutableConstant>* container) const noexcept {
return get<ChunkMaterialMutableConstants>(container);
}
bool MaterialParser::getPushConstants(CString* structVarName,
FixedCapacityVector<MaterialPushConstant>* value) const noexcept {
auto [start, end] = mImpl.mChunkContainer.getChunkRange(MaterialPushConstants);
@@ -751,6 +756,38 @@ bool ChunkMaterialConstants::unflatten(Unflattener& unflattener,
return true;
}
bool ChunkMaterialMutableConstants::unflatten(Unflattener& unflattener,
FixedCapacityVector<MaterialMutableConstant>* materialConstants) {
assert_invariant(materialConstants);
// Read number of constants.
uint64_t numConstants = 0;
if (!unflattener.read(&numConstants)) {
return false;
}
materialConstants->reserve(numConstants);
materialConstants->resize(numConstants);
for (uint64_t i = 0; i < numConstants; i++) {
CString constantName;
bool defaultValue;
if (!unflattener.read(&constantName)) {
return false;
}
if (!unflattener.read(&defaultValue)) {
return false;
}
(*materialConstants)[i].name = std::move(constantName);
(*materialConstants)[i].defaultValue = defaultValue;
}
return true;
}
bool ChunkMaterialPushConstants::unflatten(Unflattener& unflattener,
CString* structVarName,
FixedCapacityVector<MaterialPushConstant>* materialPushConstants) {
+10
View File
@@ -49,6 +49,7 @@ class BufferInterfaceBlock;
class SamplerInterfaceBlock;
struct SubpassInfo;
struct MaterialConstant;
struct MaterialMutableConstant;
struct MaterialPushConstant;
class MaterialParser {
@@ -79,6 +80,8 @@ public:
bool getShaderModels(uint32_t* value) const noexcept;
bool getMaterialProperties(uint64_t* value) const noexcept;
bool getConstants(utils::FixedCapacityVector<MaterialConstant>* value) const noexcept;
bool getMutableConstants(utils::FixedCapacityVector<MaterialMutableConstant>* value)
const noexcept;
bool getPushConstants(utils::CString* structVarName,
utils::FixedCapacityVector<MaterialPushConstant>* value) const noexcept;
@@ -237,6 +240,13 @@ struct ChunkMaterialConstants {
static filamat::ChunkType const tag = filamat::MaterialConstants;
};
struct ChunkMaterialMutableConstants {
static bool unflatten(filaflat::Unflattener& unflattener,
utils::FixedCapacityVector<MaterialMutableConstant>* materialConstants);
using Container = utils::FixedCapacityVector<MaterialMutableConstant>;
static filamat::ChunkType const tag = filamat::MaterialMutableConstants;
};
struct ChunkMaterialPushConstants {
static bool unflatten(filaflat::Unflattener& unflattener, utils::CString* structVarName,
utils::FixedCapacityVector<MaterialPushConstant>* materialPushConstants);
+8 -2
View File
@@ -187,7 +187,10 @@ FMaterial* PostProcessManager::PostProcessMaterial::getMaterial(FEngine& engine,
if (UTILS_UNLIKELY(mSize)) {
loadMaterial(engine);
}
mMaterial->prepareProgram(Variant{ Variant::type_t(variant) });
mMaterial->prepareProgram(Variant{ Variant::type_t(variant) },
// TODO(exv): allow post process materials to use mutable spec constants?
Program::MutableSpecConstantsInfo(0)
);
return mMaterial;
}
@@ -423,7 +426,10 @@ UTILS_NOINLINE
PipelineState PostProcessManager::getPipelineState(
FMaterial const* const ma, PostProcessVariant variant) const noexcept {
return {
.program = ma->getProgram(Variant{ Variant::type_t(variant) }),
.program = ma->getProgram(Variant{ Variant::type_t(variant) },
// TODO(exv): allow post process materials to use mutable spec constants?
Program::MutableSpecConstantsInfo(0)
),
.vertexBufferInfo = mFullScreenQuadVbih,
.pipelineLayout = {
.setLayout = {
+4 -2
View File
@@ -246,7 +246,8 @@ void RenderPass::appendCommands(FEngine const& engine,
for (Command const* first = curr, *last = curr + commandCount ; first != last ; ++first) {
if (UTILS_LIKELY((first->key & CUSTOM_MASK) == uint64_t(CustomCommand::PASS))) {
auto ma = first->info.mi->getMaterial();
ma->prepareProgram(first->info.materialVariant);
ma->prepareProgram(first->info.materialVariant,
first->info.mi->getMutableSpecConstants());
}
}
}
@@ -1098,7 +1099,8 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
}
assert_invariant(ma);
pipeline.program = ma->getProgram(info.materialVariant);
pipeline.program = ma->getProgram(info.materialVariant,
info.mi->getMutableSpecConstants());
if (UTILS_UNLIKELY(memcmp(&pipeline, &currentPipeline, sizeof(PipelineState)) != 0)) {
currentPipeline = pipeline;
-2
View File
@@ -140,7 +140,6 @@ Engine* FEngine::create(Builder const& builder) {
.forceGLES2Context = instance->getConfig().forceGLES2Context,
.stereoscopicType = instance->getConfig().stereoscopicType,
.assertNativeWindowIsValid = instance->features.backend.opengl.assert_native_window_is_valid,
.metalDisablePanicOnDrawableFailure = instance->getConfig().metalDisablePanicOnDrawableFailure,
};
instance->mDriver = platform->createDriver(sharedContext, driverConfig);
@@ -760,7 +759,6 @@ int FEngine::loop() {
.forceGLES2Context = mConfig.forceGLES2Context,
.stereoscopicType = mConfig.stereoscopicType,
.assertNativeWindowIsValid = features.backend.opengl.assert_native_window_is_valid,
.metalDisablePanicOnDrawableFailure = mConfig.metalDisablePanicOnDrawableFailure,
};
mDriver = mPlatform->createDriver(mSharedGLContext, driverConfig);
+100 -32
View File
@@ -342,8 +342,24 @@ FMaterial::FMaterial(FEngine& engine, const Builder& builder,
processBlendingMode(parser);
processSpecializationConstants(engine, builder, parser);
processMutableSpecializationConstants(engine, builder, parser);
processPushConstants(engine, parser);
processDescriptorSets(engine, parser);
switch (mMaterialDomain) {
case filament::MaterialDomain::SURFACE:
mVariantBits = VARIANT_BITS;
break;
case filament::MaterialDomain::POST_PROCESS:
mVariantBits = POST_PROCESS_VARIANT_BITS;
break;
case filament::MaterialDomain::COMPUTE:
mVariantBits = 0;
break;
}
mCachedPrograms = FixedCapacityVector<backend::Handle<backend::HwProgram>>(
1 << (mVariantBits + mMaterialMutableConstants.size()));
precacheDepthVariants(engine);
#if FILAMENT_ENABLE_MATDBG
@@ -449,13 +465,17 @@ void FMaterial::compile(CompilerPriorityQueue const priority,
UserVariantFilterMask const variantFilter =
~variantSpec & UserVariantFilterMask(UserVariantFilterBit::ALL);
int mutableConstantVariations = 1 << mMaterialMutableConstants.size();
if (UTILS_LIKELY(mEngine.getDriverApi().isParallelShaderCompileSupported())) {
auto const& variants = isVariantLit() ?
VariantUtils::getLitVariants() : VariantUtils::getUnlitVariants();
for (auto const variant: variants) {
if (!variantFilter || variant == Variant::filterUserVariant(variant, variantFilter)) {
if (hasVariant(variant)) {
prepareProgram(variant, priority);
for (int spec = 0; spec < mutableConstantVariations; spec++) {
prepareProgram(variant, Program::MutableSpecConstantsInfo(spec), priority);
}
}
}
}
@@ -496,6 +516,11 @@ FMaterialInstance* FMaterial::getDefaultInstance() noexcept {
return mDefaultMaterialInstance;
}
bool FMaterial::isCached(Variant const variant,
const backend::Program::MutableSpecConstantsInfo mutableSpecConstants) const noexcept {
return bool(mCachedPrograms[getCachedProgramIndex(variant, mutableSpecConstants)]);
}
bool FMaterial::hasParameter(const char* name) const noexcept {
return mUniformInterfaceBlock.hasField(name) ||
mSamplerInterfaceBlock.hasSampler(name) ||
@@ -536,14 +561,15 @@ bool FMaterial::hasVariant(Variant const variant) const noexcept {
}
void FMaterial::prepareProgramSlow(Variant const variant,
const backend::Program::MutableSpecConstantsInfo mutableSpecConstants,
backend::CompilerPriorityQueue const priorityQueue) const noexcept {
assert_invariant(mEngine.hasFeatureLevel(mFeatureLevel));
switch (getMaterialDomain()) {
case MaterialDomain::SURFACE:
getSurfaceProgramSlow(variant, priorityQueue);
getSurfaceProgramSlow(variant, mutableSpecConstants, priorityQueue);
break;
case MaterialDomain::POST_PROCESS:
getPostProcessProgramSlow(variant, priorityQueue);
getPostProcessProgramSlow(variant, mutableSpecConstants, priorityQueue);
break;
case MaterialDomain::COMPUTE:
// TODO: implement MaterialDomain::COMPUTE
@@ -552,6 +578,7 @@ void FMaterial::prepareProgramSlow(Variant const variant,
}
void FMaterial::getSurfaceProgramSlow(Variant const variant,
const backend::Program::MutableSpecConstantsInfo mutableSpecConstants,
CompilerPriorityQueue const priorityQueue) const noexcept {
// filterVariant() has already been applied in generateCommands(), shouldn't be needed here
// if we're unlit, we don't have any bits that correspond to lit materials
@@ -562,25 +589,25 @@ void FMaterial::getSurfaceProgramSlow(Variant const variant,
Variant const vertexVariant = Variant::filterVariantVertex(variant);
Variant const fragmentVariant = Variant::filterVariantFragment(variant);
Program pb{ getProgramWithVariants(variant, vertexVariant, fragmentVariant) };
Program pb{ getProgramWithVariants(variant, vertexVariant, fragmentVariant, mutableSpecConstants) };
pb.priorityQueue(priorityQueue);
pb.multiview(
mEngine.getConfig().stereoscopicType == StereoscopicType::MULTIVIEW &&
Variant::isStereoVariant(variant));
createAndCacheProgram(std::move(pb), variant);
createAndCacheProgram(std::move(pb), variant, mutableSpecConstants);
}
void FMaterial::getPostProcessProgramSlow(Variant const variant,
const backend::Program::MutableSpecConstantsInfo mutableSpecConstants,
CompilerPriorityQueue const priorityQueue) const noexcept {
Program pb{ getProgramWithVariants(variant, variant, variant) };
Program pb{ getProgramWithVariants(variant, variant, variant, mutableSpecConstants) };
pb.priorityQueue(priorityQueue);
createAndCacheProgram(std::move(pb), variant);
createAndCacheProgram(std::move(pb), variant, mutableSpecConstants);
}
Program FMaterial::getProgramWithVariants(
Variant variant,
Variant vertexVariant,
Variant fragmentVariant) const {
Program FMaterial::getProgramWithVariants(Variant variant,
Variant vertexVariant, Variant fragmentVariant,
const backend::Program::MutableSpecConstantsInfo mutableSpecConstants) const {
FEngine const& engine = mEngine;
const ShaderModel sm = engine.getShaderModel();
const bool isNoop = engine.getBackend() == Backend::NOOP;
@@ -641,29 +668,34 @@ Program FMaterial::getProgramWithVariants(
mProgramDescriptorBindings[+DescriptorSetBindingPoints::PER_RENDERABLE]);
program.descriptorBindings(+DescriptorSetBindingPoints::PER_MATERIAL,
mProgramDescriptorBindings[+DescriptorSetBindingPoints::PER_MATERIAL]);
program.specializationConstants(mSpecializationConstants);
program.specializationConstants(mSpecializationConstants,
CONFIG_MAX_RESERVED_SPEC_CONSTANTS + mMaterialConstants.size(), mutableSpecConstants);
program.pushConstants(ShaderStage::VERTEX, mPushConstants[uint8_t(ShaderStage::VERTEX)]);
program.pushConstants(ShaderStage::FRAGMENT, mPushConstants[uint8_t(ShaderStage::FRAGMENT)]);
program.cacheId(hash::combine(size_t(mCacheId), variant.key));
program.cacheId(
hash::combine(size_t(mCacheId),
hash::combine(variant.key, mutableSpecConstants.getValue())));
return program;
}
void FMaterial::createAndCacheProgram(Program&& p, Variant const variant) const noexcept {
void FMaterial::createAndCacheProgram(Program&& p, Variant const variant,
Program::MutableSpecConstantsInfo const mutableSpecConstants) const noexcept {
FEngine const& engine = mEngine;
DriverApi& driverApi = mEngine.getDriverApi();
bool const isShared = isSharedVariant(variant);
size_t const cacheIndex = getCachedProgramIndex(variant, mutableSpecConstants);
// Check if the default material has this program cached
if (isShared) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
if (pDefaultMaterial) {
auto const program = pDefaultMaterial->mCachedPrograms[variant.key];
auto const program = pDefaultMaterial->mCachedPrograms[cacheIndex];
if (program) {
mCachedPrograms[variant.key] = program;
mCachedPrograms[cacheIndex] = program;
return;
}
}
@@ -672,17 +704,17 @@ void FMaterial::createAndCacheProgram(Program&& p, Variant const variant) const
auto const program = driverApi.createProgram(std::move(p));
driverApi.setDebugTag(program.getId(), mName);
assert_invariant(program);
mCachedPrograms[variant.key] = program;
mCachedPrograms[cacheIndex] = program;
// If the default material doesn't already have this program cached, and all caching conditions
// are met (Surface Domain and no custom depth shader), cache it now.
// New Materials will inherit these program automatically.
if (isShared) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
if (pDefaultMaterial && !pDefaultMaterial->mCachedPrograms[variant.key]) {
if (pDefaultMaterial && !pDefaultMaterial->mCachedPrograms[cacheIndex]) {
// set the tag to the default material name
driverApi.setDebugTag(program.getId(), mName);
pDefaultMaterial->mCachedPrograms[variant.key] = program;
pDefaultMaterial->mCachedPrograms[cacheIndex] = program;
}
}
}
@@ -730,6 +762,14 @@ size_t FMaterial::getParameters(ParameterInfo* parameters, size_t count) const n
return count;
}
std::optional<uint32_t> FMaterial::getMutableConstantId(std::string_view name) const noexcept {
auto const pos = mMutableSpecializationConstantsNameToIndex.find(name);
if (pos != mMutableSpecializationConstantsNameToIndex.end()) {
return pos->second;
}
return std::nullopt;
}
#if FILAMENT_ENABLE_MATDBG
// Swaps in an edited version of the original package that was used to create the material. The
@@ -788,7 +828,9 @@ void FMaterial::onQueryCallback(void* userdata, VariantList* pActiveVariants) {
#endif // FILAMENT_ENABLE_MATDBG
[[nodiscard]] Handle<HwProgram> FMaterial::getProgramWithMATDBG(Variant const variant) const noexcept {
[[nodiscard]] Handle<HwProgram> FMaterial::getProgramWithMATDBG(Variant const variant,
Program::MutableSpecConstantsInfo const mutableSpecConstants) const noexcept {
size_t cacheIndex = getCachedProgramIndex(variant, mutableSpecConstants);
#if FILAMENT_ENABLE_MATDBG
assert_invariant((size_t)variant.key < VARIANT_COUNT);
std::unique_lock lock(mActiveProgramsLock);
@@ -803,13 +845,13 @@ void FMaterial::onQueryCallback(void* userdata, VariantList* pActiveVariants) {
lock.unlock();
if (isSharedVariant(variant)) {
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
if (pDefaultMaterial && pDefaultMaterial->mCachedPrograms[variant.key]) {
return pDefaultMaterial->getProgram(variant);
if (pDefaultMaterial && pDefaultMaterial->mCachedPrograms[cacheIndex]) {
return pDefaultMaterial->getProgram(variant, mutableSpecConstants);
}
}
#endif
assert_invariant(mCachedPrograms[variant.key]);
return mCachedPrograms[variant.key];
assert_invariant(mCachedPrograms[cacheIndex]);
return mCachedPrograms[cacheIndex];
}
void FMaterial::destroyPrograms(FEngine& engine,
@@ -822,7 +864,7 @@ void FMaterial::destroyPrograms(FEngine& engine,
case MaterialDomain::SURFACE: {
if (mIsDefaultMaterial || mHasCustomDepthShader) {
// default material, or we have custom depth shaders, we destroy all variants
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
for (size_t k = 0, n = cachedPrograms.size(); k < n; ++k) {
if ((k & variantMask) == variantValue) {
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
// of variants, and this generates traffic in the command queue.
@@ -840,7 +882,7 @@ void FMaterial::destroyPrograms(FEngine& engine,
UTILS_UNUSED_IN_RELEASE
auto const UTILS_NULLABLE pDefaultMaterial = engine.getDefaultMaterial();
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
for (size_t k = 0, n = cachedPrograms.size(); k < n; ++k) {
if ((k & variantMask) == variantValue) {
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
// of variant, and this generates traffic in the command queue.
@@ -852,7 +894,7 @@ void FMaterial::destroyPrograms(FEngine& engine,
// During Engine::shutdown, auto-cleanup destroys the
// default material first
assert_invariant(!pDefaultMaterial ||
pDefaultMaterial->mCachedPrograms[k]);
pDefaultMaterial->mCachedPrograms[k & (VARIANT_COUNT - 1)]);
// we don't own this variant, skip, but clear the entry.
cachedPrograms[k].clear();
continue;
@@ -866,7 +908,7 @@ void FMaterial::destroyPrograms(FEngine& engine,
break;
}
case MaterialDomain::POST_PROCESS: {
for (size_t k = 0, n = POST_PROCESS_VARIANT_COUNT; k < n; ++k) {
for (size_t k = 0, n = cachedPrograms.size(); k < n; ++k) {
if ((k & variantMask) == variantValue) {
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
// of variant, and this generates traffic in the command queue.
@@ -878,8 +920,13 @@ void FMaterial::destroyPrograms(FEngine& engine,
break;
}
case MaterialDomain::COMPUTE: {
// Compute programs don't have variants
driverApi.destroyProgram(std::move(cachedPrograms[0]));
for (size_t k = 0, n = cachedPrograms.size(); k < n; ++k) {
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
// of variant, and this generates traffic in the command queue.
if (cachedPrograms[k]) {
driverApi.destroyProgram(std::move(cachedPrograms[k]));
}
}
break;
}
}
@@ -1114,6 +1161,19 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Builder const& b
}
}
void FMaterial::processMutableSpecializationConstants(FEngine& engine, Builder const& builder,
MaterialParser const* const parser) {
// Older materials won't have a mutable constants chunk, but that's okay.
parser->getMutableConstants(&mMaterialMutableConstants);
for (size_t i = 0, c = mMaterialMutableConstants.size(); i < c; i++) {
auto& item = mMaterialMutableConstants[i];
// the key can be a string_view because mMaterialMutableConstants owns the CString
std::string_view const key{ item.name.data(), item.name.size() };
mMutableSpecializationConstantsNameToIndex[key] = i;
mDefaultMutableSpecializationConstants.set(i, item.defaultValue);
}
}
void FMaterial::processPushConstants(FEngine&, MaterialParser const* parser) {
FixedCapacityVector<Program::PushConstant>& vertexConstants =
mPushConstants[uint8_t(ShaderStage::VERTEX)];
@@ -1169,7 +1229,8 @@ void FMaterial::precacheDepthVariants(FEngine& engine) {
}
assert_invariant(Variant::isValidDepthVariant(variant));
if (hasVariant(variant)) {
prepareProgram(variant);
// The default material shouldn't ever have mutable spec constants.
prepareProgram(variant, Program::MutableSpecConstantsInfo(0));
}
}
return;
@@ -1182,9 +1243,16 @@ void FMaterial::precacheDepthVariants(FEngine& engine) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
assert_invariant(pDefaultMaterial);
auto const allDepthVariants = VariantUtils::getDepthVariants();
int mutableConstantVariations = 1 << mMaterialMutableConstants.size();
for (auto const variant: allDepthVariants) {
assert_invariant(Variant::isValidDepthVariant(variant));
mCachedPrograms[variant.key] = pDefaultMaterial->mCachedPrograms[variant.key];
size_t defaultCacheIndex = pDefaultMaterial->getCachedProgramIndex(variant,
Program::MutableSpecConstantsInfo(0));
for (int spec = 0; spec < mutableConstantVariations; spec++) {
size_t cacheIndex = getCachedProgramIndex(variant,
Program::MutableSpecConstantsInfo(spec));
mCachedPrograms[cacheIndex] = pDefaultMaterial->mCachedPrograms[defaultCacheIndex];
}
}
}
}
+46 -14
View File
@@ -122,9 +122,8 @@ public:
FEngine& getEngine() const noexcept { return mEngine; }
bool isCached(Variant const variant) const noexcept {
return bool(mCachedPrograms[variant.key]);
}
bool isCached(Variant const variant,
const backend::Program::MutableSpecConstantsInfo mutableSpecConstants) const noexcept;
void invalidate(Variant::type_t variantMask = 0, Variant::type_t variantValue = 0) noexcept;
@@ -132,26 +131,31 @@ public:
// Must be called outside of backend render pass.
// Must be called before getProgram() below.
void prepareProgram(Variant const variant,
backend::Program::MutableSpecConstantsInfo const mutableSpecConstants,
backend::CompilerPriorityQueue const priorityQueue = CompilerPriorityQueue::HIGH) const noexcept {
// prepareProgram() is called for each RenderPrimitive in the scene, so it must be efficient.
if (UTILS_UNLIKELY(!isCached(variant))) {
prepareProgramSlow(variant, priorityQueue);
if (UTILS_UNLIKELY(!isCached(variant, mutableSpecConstants))) {
prepareProgramSlow(variant, mutableSpecConstants, priorityQueue);
}
}
// getProgram returns the backend program for the material's given variant.
// getProgram returns the backend program for the material's given variant and set of mutable
// spec constants.
// Must be called after prepareProgram().
[[nodiscard]]
backend::Handle<backend::HwProgram> getProgram(Variant const variant) const noexcept {
backend::Handle<backend::HwProgram> getProgram(Variant const variant,
backend::Program::MutableSpecConstantsInfo const mutableSpecConstants) const noexcept {
#if FILAMENT_ENABLE_MATDBG
return getProgramWithMATDBG(variant);
return getProgramWithMATDBG(variant, mutableSpecConstants);
#endif
assert_invariant(mCachedPrograms[variant.key]);
return mCachedPrograms[variant.key];
size_t index = getCachedProgramIndex(variant, mutableSpecConstants);
assert_invariant(mCachedPrograms[index]);
return mCachedPrograms[index];
}
[[nodiscard]]
backend::Handle<backend::HwProgram> getProgramWithMATDBG(Variant variant) const noexcept;
backend::Handle<backend::HwProgram> getProgramWithMATDBG(Variant variant,
backend::Program::MutableSpecConstantsInfo const mutableSpecConstants) const noexcept;
bool isVariantLit() const noexcept { return mIsVariantLit; }
@@ -208,6 +212,12 @@ public:
}
size_t getParameters(ParameterInfo* parameters, size_t count) const noexcept;
uint32_t getMutableConstantCount() const noexcept { return mMaterialMutableConstants.size(); }
std::optional<uint32_t> getMutableConstantId(std::string_view name) const noexcept;
backend::Program::MutableSpecConstantsInfo getDefaultMutableConstants() const noexcept {
return mDefaultMutableSpecializationConstants;
}
uint32_t generateMaterialInstanceId() const noexcept { return mMaterialInstanceId++; }
void destroyPrograms(FEngine& engine,
@@ -261,34 +271,48 @@ public:
private:
bool hasVariant(Variant variant) const noexcept;
void prepareProgramSlow(Variant variant,
backend::Program::MutableSpecConstantsInfo mutableSpecConstants,
CompilerPriorityQueue priorityQueue) const noexcept;
void getSurfaceProgramSlow(Variant variant,
backend::Program::MutableSpecConstantsInfo mutableSpecConstants,
CompilerPriorityQueue priorityQueue) const noexcept;
void getPostProcessProgramSlow(Variant variant,
backend::Program::MutableSpecConstantsInfo mutableSpecConstants,
CompilerPriorityQueue priorityQueue) const noexcept;
backend::Program getProgramWithVariants(Variant variant,
Variant vertexVariant, Variant fragmentVariant) const;
Variant vertexVariant, Variant fragmentVariant,
backend::Program::MutableSpecConstantsInfo mutableSpecConstants) const;
void processBlendingMode(MaterialParser const* parser);
void processSpecializationConstants(FEngine& engine, Builder const& builder,
MaterialParser const* parser);
void processMutableSpecializationConstants(FEngine& engine, Builder const& builder,
MaterialParser const* parser);
void processPushConstants(FEngine& engine, MaterialParser const* parser);
void precacheDepthVariants(FEngine& engine);
void processDescriptorSets(FEngine& engine, MaterialParser const* parser);
void createAndCacheProgram(backend::Program&& p, Variant variant) const noexcept;
void createAndCacheProgram(backend::Program&& p, Variant variant,
backend::Program::MutableSpecConstantsInfo mutableSpecConstants) const noexcept;
inline bool isSharedVariant(Variant const variant) const {
return (mMaterialDomain == MaterialDomain::SURFACE) && !mIsDefaultMaterial &&
!mHasCustomDepthShader && Variant::isValidDepthVariant(variant);
}
inline size_t getCachedProgramIndex(const Variant variant,
const backend::Program::MutableSpecConstantsInfo mutableSpecConstants) const noexcept {
return static_cast<size_t>(variant.key) |
(static_cast<size_t>(mutableSpecConstants.getValue()) << mVariantBits);
}
// try to order by frequency of use
mutable std::array<backend::Handle<backend::HwProgram>, VARIANT_COUNT> mCachedPrograms;
mutable utils::FixedCapacityVector<backend::Handle<backend::HwProgram>> mCachedPrograms;
DescriptorSetLayout mPerViewDescriptorSetLayout;
DescriptorSetLayout mPerViewDescriptorSetLayoutVsm;
DescriptorSetLayout mDescriptorSetLayout;
@@ -324,6 +348,7 @@ private:
bool mHasCustomDepthShader = false;
bool mIsDefaultMaterial = false;
bool mSpecularAntiAliasing = false;
uint8_t mVariantBits;
// reserve some space to construct the default material instance
mutable FMaterialInstance* mDefaultMaterialInstance = nullptr;
@@ -348,6 +373,13 @@ private:
// current specialization constants for the HwProgram
utils::FixedCapacityVector<backend::Program::SpecializationConstant> mSpecializationConstants;
// Mutable constants defined by this Material.
utils::FixedCapacityVector<MaterialMutableConstant> mMaterialMutableConstants;
// A map from the Constant name to the mMutableMaterialConstant index
std::unordered_map<std::string_view, uint32_t> mMutableSpecializationConstantsNameToIndex;
// Default values for the mutable constants.
backend::Program::MutableSpecConstantsInfo mDefaultMutableSpecializationConstants;
// current push constants for the HwProgram
std::array<utils::FixedCapacityVector<backend::Program::PushConstant>,
backend::Program::SHADER_TYPE_COUNT>
@@ -63,6 +63,7 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material,
const char* name) noexcept
: mMaterial(material),
mDescriptorSet("MaterialInstance", material->getDescriptorSetLayout()),
mConstants(material->getDefaultMutableConstants()),
mCulling(CullingMode::BACK),
mShadowCulling(CullingMode::BACK),
mDepthFunc(RasterState::DepthFunc::LE),
@@ -128,6 +129,7 @@ FMaterialInstance::FMaterialInstance(FEngine& engine,
mTextureParameters(other->mTextureParameters),
mDescriptorSet(other->mDescriptorSet.duplicate(
"MaterialInstance", mMaterial->getDescriptorSetLayout())),
mConstants(other->mConstants),
mPolygonOffset(other->mPolygonOffset),
mStencilState(other->mStencilState),
mMaskThreshold(other->mMaskThreshold),
+13 -1
View File
@@ -31,6 +31,7 @@
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <backend/Program.h>
#include <utils/BitmaskEnum.h>
#include <utils/bitset.h>
@@ -66,7 +67,7 @@ public:
void terminate(FEngine& engine);
void commitStreamUniformAssociations(FEngine::DriverApi& driver);
void commit(FEngine& engine) const;
void commit(FEngine::DriverApi& driver) const;
@@ -242,6 +243,10 @@ public:
using MaterialInstance::setParameter;
const backend::Program::MutableSpecConstantsInfo getMutableSpecConstants() const noexcept {
return mConstants;
}
private:
friend class FMaterial;
friend class MaterialInstance;
@@ -264,6 +269,12 @@ private:
template<typename T>
T getParameterImpl(std::string_view name) const;
template<typename T>
void setConstantImpl(std::string_view name, T const& value);
template<typename T>
T getConstantImpl(std::string_view name) const;
// keep these grouped, they're accessed together in the render-loop
FMaterial const* mMaterial = nullptr;
@@ -277,6 +288,7 @@ private:
mutable DescriptorSet mDescriptorSet;
UniformBuffer mUniforms;
bool mHasStreamUniformAssociations = false;
backend::Program::MutableSpecConstantsInfo mConstants;
backend::PolygonOffset mPolygonOffset{};
backend::StencilState mStencilState{};
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.61.2"
spec.version = "1.61.1"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.61.2/filament-v1.61.2-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.61.1/filament-v1.61.1-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
@@ -54,6 +54,7 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
MaterialDescriptorSetLayoutInfo = charTo64bitNum("MAT_DSLI"),
MaterialProperties = charTo64bitNum("MAT_PROP"),
MaterialConstants = charTo64bitNum("MAT_CONS"),
MaterialMutableConstants = charTo64bitNum("MAT_MCNS"),
MaterialPushConstants = charTo64bitNum("MAT_PCON"),
MaterialName = charTo64bitNum("MAT_NAME"),
@@ -28,7 +28,7 @@
namespace filament {
// update this when a new version of filament wouldn't work with older materials
static constexpr size_t MATERIAL_VERSION = 61;
static constexpr size_t MATERIAL_VERSION = 60;
/**
* Supported shading models
@@ -30,7 +30,19 @@ struct MaterialConstant {
ConstantType type;
MaterialConstant() = default;
MaterialConstant(const char* name, ConstantType type) : name(name), type(type) {}
MaterialConstant(utils::CString name, ConstantType type) : name(std::move(name)), type(type) {}
};
struct MaterialMutableConstant {
utils::CString name;
// The Filament engine stores mutable spec constants as a bitfield, meaning that must override
// all of the default values built into in the shader souces. Therefore, unlike the immutable
// constants above, we have to store the default values in the material metadata.
bool defaultValue;
MaterialMutableConstant() = default;
MaterialMutableConstant(utils::CString name, bool defaultValue)
: name(std::move(name)), defaultValue(defaultValue) {}
};
}
@@ -307,14 +307,15 @@ public:
MaterialBuilder& parameter(const char* name, size_t size, UniformType type,
ParameterPrecision precision = ParameterPrecision::DEFAULT);
//! Add a constant parameter to this material.
//! Add a (mutable) constant parameter to this material.
template<typename T>
using is_supported_constant_parameter_t = typename std::enable_if<
std::is_same<int32_t, T>::value ||
std::is_same<float, T>::value ||
std::is_same<bool, T>::value>::type;
template<typename T, typename = is_supported_constant_parameter_t<T>>
MaterialBuilder& constant(const char *name, ConstantType type, T defaultValue = 0);
MaterialBuilder& constant(const char* name, ConstantType type, bool isMutable,
T defaultValue = 0);
/**
* Add a sampler parameter to this material.
@@ -871,6 +872,7 @@ private:
PropertyList mProperties;
ParameterList mParameters;
ConstantList mConstants;
ConstantList mMutableConstants;
PushConstantList mPushConstants;
SubpassList mSubpasses;
VariableList mVariables;
+29 -12
View File
@@ -317,12 +317,19 @@ MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType sample
}
template<typename T, typename>
MaterialBuilder& MaterialBuilder::constant(const char* name, ConstantType const type, T defaultValue) {
auto result = std::find_if(mConstants.begin(), mConstants.end(), [name](const Constant& c) {
return c.name == CString(name);
});
FILAMENT_CHECK_POSTCONDITION(result == mConstants.end())
MaterialBuilder& MaterialBuilder::constant(const char* name, ConstantType const type,
bool isMutable, T defaultValue) {
ConstantList& constants = isMutable ? mMutableConstants : mConstants;
const ConstantList& otherConstants = isMutable ? mConstants : mMutableConstants;
auto result = std::find_if(constants.begin(), constants.end(),
[name](const Constant& c) { return c.name == CString(name); });
FILAMENT_CHECK_POSTCONDITION(result == constants.end())
<< "There is already a constant parameter present with the name " << name << ".";
auto otherResult = std::find_if(otherConstants.begin(), otherConstants.end(),
[name](const Constant& c) { return c.name == CString(name); });
FILAMENT_CHECK_POSTCONDITION(otherResult == otherConstants.end())
<< "There is already a constant parameter present with the name " << name << ".";
Constant constant {
.name = CString(name),
.type = type,
@@ -354,15 +361,20 @@ MaterialBuilder& MaterialBuilder::constant(const char* name, ConstantType const
assert_invariant(false);
}
mConstants.push_back(constant);
if (isMutable) {
FILAMENT_CHECK_POSTCONDITION(type == ConstantType::BOOL)
<< "Mutable spec constants must be bool type.";
}
constants.push_back(constant);
return *this;
}
template MaterialBuilder& MaterialBuilder::constant<int32_t>(
const char* name, ConstantType type, int32_t defaultValue);
const char* name, ConstantType type, bool isMutable, int32_t defaultValue);
template MaterialBuilder& MaterialBuilder::constant<float>(
const char* name, ConstantType type, float defaultValue);
const char* name, ConstantType type, bool isMutable, float defaultValue);
template MaterialBuilder& MaterialBuilder::constant<bool>(
const char* name, ConstantType type, bool defaultValue);
const char* name, ConstantType type, bool isMutable, bool defaultValue);
MaterialBuilder& MaterialBuilder::buffer(BufferInterfaceBlock bib) {
FILAMENT_CHECK_POSTCONDITION(mBuffers.size() < MAX_BUFFERS_COUNT) << "Too many buffers";
@@ -907,7 +919,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
BlobDictionary spirvDictionary;
// End: must be protected by lock
ShaderGenerator sg(mProperties, mVariables, mOutputs, mDefines, mConstants, mPushConstants,
ShaderGenerator sg(mProperties, mVariables, mOutputs, mDefines, mConstants, mMutableConstants, mPushConstants,
mMaterialFragmentCode.getResolved(), mMaterialFragmentCode.getLineOffset(),
mMaterialVertexCode.getResolved(), mMaterialVertexCode.getLineOffset(),
mMaterialDomain);
@@ -1492,7 +1504,7 @@ bool MaterialBuilder::needsStandardDepthProgram() const noexcept {
std::string MaterialBuilder::peek(backend::ShaderStage const stage,
const CodeGenParams& params, const PropertyList& properties) noexcept {
ShaderGenerator const sg(properties, mVariables, mOutputs, mDefines, mConstants, mPushConstants,
ShaderGenerator const sg(properties, mVariables, mOutputs, mDefines, mConstants, mMutableConstants, mPushConstants,
mMaterialFragmentCode.getResolved(), mMaterialFragmentCode.getLineOffset(),
mMaterialVertexCode.getResolved(), mMaterialVertexCode.getLineOffset(),
mMaterialDomain);
@@ -1618,9 +1630,14 @@ void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo&
// User constant parameters
FixedCapacityVector<MaterialConstant> constantsEntry(mConstants.size());
std::transform(mConstants.begin(), mConstants.end(), constantsEntry.begin(),
[](Constant const& c) { return MaterialConstant(c.name.c_str(), c.type); });
[](Constant const& c) { return MaterialConstant(c.name, c.type); });
container.push<MaterialConstantParametersChunk>(std::move(constantsEntry));
FixedCapacityVector<MaterialMutableConstant> mutableConstantsEntry(mMutableConstants.size());
std::transform(mMutableConstants.begin(), mMutableConstants.end(), mutableConstantsEntry.begin(),
[](Constant const& c) { return MaterialMutableConstant(c.name, c.defaultValue.b); });
container.push<MaterialMutableConstantParametersChunk>(std::move(mutableConstantsEntry));
FixedCapacityVector<MaterialPushConstant> pushConstantsEntry(mPushConstants.size());
std::transform(mPushConstants.begin(), mPushConstants.end(), pushConstantsEntry.begin(),
[](PushConstant const& c) {
@@ -117,6 +117,20 @@ void MaterialConstantParametersChunk::flatten(Flattener& f) {
// ------------------------------------------------------------------------------------------------
MaterialMutableConstantParametersChunk::MaterialMutableConstantParametersChunk(
FixedCapacityVector<MaterialMutableConstant> constants)
: Chunk(MaterialMutableConstants), mConstants(std::move(constants)) {}
void MaterialMutableConstantParametersChunk::flatten(Flattener& f) {
f.writeUint64(mConstants.size());
for (const auto& constant : mConstants) {
f.writeString(constant.name.c_str());
f.writeBool(constant.defaultValue);
}
}
// ------------------------------------------------------------------------------------------------
MaterialPushConstantParametersChunk::MaterialPushConstantParametersChunk(
CString const& structVarName, FixedCapacityVector<MaterialPushConstant> constants)
: Chunk(MaterialPushConstants),
@@ -18,6 +18,7 @@
#define TNT_FILAMAT_MAT_INTEFFACE_BLOCK_CHUNK_H
#include "Chunk.h"
#include "private/filament/ConstantInfo.h"
#include <backend/Program.h>
@@ -91,6 +92,20 @@ private:
// ------------------------------------------------------------------------------------------------
class MaterialMutableConstantParametersChunk final : public Chunk {
public:
explicit MaterialMutableConstantParametersChunk(
FixedCapacityVector<filament::MaterialMutableConstant> constants);
~MaterialMutableConstantParametersChunk() override = default;
private:
void flatten(Flattener&) override;
FixedCapacityVector<filament::MaterialMutableConstant> mConstants;
};
// ------------------------------------------------------------------------------------------------
class MaterialPushConstantParametersChunk final : public Chunk {
public:
explicit MaterialPushConstantParametersChunk(CString const& structVarName,
+17 -8
View File
@@ -283,10 +283,17 @@ void ShaderGenerator::appendShader(io::sstream& ss,
}
}
void ShaderGenerator::generateUserSpecConstants(
const CodeGenerator& cg, io::sstream& fs, MaterialBuilder::ConstantList const& constants) {
void ShaderGenerator::generateAllUserSpecConstants(const CodeGenerator& cg, io::sstream& fs,
MaterialBuilder::ConstantList const& constants,
MaterialBuilder::ConstantList const& mutableConstants) {
generateUserSpecConstants(cg, fs, constants, 0);
generateUserSpecConstants(cg, fs, mutableConstants, constants.size());
}
void ShaderGenerator::generateUserSpecConstants(const CodeGenerator& cg, io::sstream& fs,
MaterialBuilder::ConstantList const& constants, size_t offset) {
// Constants 0 to CONFIG_MAX_RESERVED_SPEC_CONSTANTS - 1 are reserved by Filament.
size_t index = CONFIG_MAX_RESERVED_SPEC_CONSTANTS;
size_t index = CONFIG_MAX_RESERVED_SPEC_CONSTANTS + offset;
for (const auto& constant : constants) {
std::string const fullName = std::string("materialConstants_") + constant.name.c_str();
switch (constant.type) {
@@ -314,6 +321,7 @@ ShaderGenerator::ShaderGenerator(
MaterialBuilder::OutputList const& outputs,
MaterialBuilder::PreprocessorDefineList const& defines,
MaterialBuilder::ConstantList const& constants,
MaterialBuilder::ConstantList const& mutableConstants,
MaterialBuilder::PushConstantList const& pushConstants,
CString const& materialCode, size_t const lineOffset,
CString const& materialVertexCode, size_t const vertexLineOffset,
@@ -336,6 +344,7 @@ ShaderGenerator::ShaderGenerator(
mMaterialDomain = materialDomain;
mDefines = defines;
mConstants = constants;
mMutableConstants = mutableConstants;
mPushConstants = pushConstants;
if (mMaterialFragmentCode.empty()) {
@@ -392,7 +401,7 @@ std::string ShaderGenerator::createSurfaceVertexProgram(ShaderModel const shader
cg.generateCommonProlog(vs, ShaderStage::VERTEX, material, variant);
generateUserSpecConstants(cg, vs, mConstants);
generateAllUserSpecConstants(cg, vs, mConstants, mMutableConstants);
// note: even if the user vertex shader is empty, we can't use the "optimized" version if
// we're in masked mode because fragment shader needs the color varyings
@@ -525,7 +534,7 @@ std::string ShaderGenerator::createSurfaceFragmentProgram(ShaderModel const shad
io::sstream fs;
cg.generateCommonProlog(fs, ShaderStage::FRAGMENT, material, variant);
generateUserSpecConstants(cg, fs, mConstants);
generateAllUserSpecConstants(cg, fs, mConstants, mMutableConstants);
generateSurfaceMaterialVariantDefines(
fs, ShaderStage::FRAGMENT, featureLevel, material, variant);
@@ -681,7 +690,7 @@ std::string ShaderGenerator::createSurfaceComputeProgram(ShaderModel const shade
cg.generateCommonProlog(s, ShaderStage::COMPUTE, material, {});
generateUserSpecConstants(cg, s, mConstants);
generateAllUserSpecConstants(cg, s, mConstants, mMutableConstants);
CodeGenerator::generateSurfaceTypes(s, ShaderStage::COMPUTE);
@@ -721,7 +730,7 @@ std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel const sm
io::sstream vs;
cg.generateCommonProlog(vs, ShaderStage::VERTEX, material, {});
generateUserSpecConstants(cg, vs, mConstants);
generateAllUserSpecConstants(cg, vs, mConstants, mMutableConstants);
CodeGenerator::generateDefine(vs, "LOCATION_POSITION", uint32_t(POSITION));
@@ -765,7 +774,7 @@ std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel const
io::sstream fs;
cg.generateCommonProlog(fs, ShaderStage::FRAGMENT, material, {});
generateUserSpecConstants(cg, fs, mConstants);
generateAllUserSpecConstants(cg, fs, mConstants, mMutableConstants);
generatePostProcessMaterialVariantDefines(fs, PostProcessVariant(variant));
+8 -1
View File
@@ -51,6 +51,7 @@ public:
MaterialBuilder::OutputList const& outputs,
MaterialBuilder::PreprocessorDefineList const& defines,
MaterialBuilder::ConstantList const& constants,
MaterialBuilder::ConstantList const& mutableConstants,
MaterialBuilder::PushConstantList const& pushConstants,
utils::CString const& materialCode,
size_t lineOffset,
@@ -104,9 +105,14 @@ private:
static void generatePostProcessMaterialVariantDefines(utils::io::sstream& out,
filament::PostProcessVariant variant) noexcept;
static void generateAllUserSpecConstants(const CodeGenerator& cg, utils::io::sstream& fs,
MaterialBuilder::ConstantList const& constants,
MaterialBuilder::ConstantList const& mutableConstants);
static void generateUserSpecConstants(
const CodeGenerator& cg, utils::io::sstream& fs,
MaterialBuilder::ConstantList const& constants);
MaterialBuilder::ConstantList const& constants,
size_t offset);
std::string createPostProcessVertexProgram(filament::backend::ShaderModel sm,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
@@ -135,6 +141,7 @@ private:
MaterialBuilder::MaterialDomain mMaterialDomain;
MaterialBuilder::PreprocessorDefineList mDefines;
MaterialBuilder::ConstantList mConstants;
MaterialBuilder::ConstantList mMutableConstants;
MaterialBuilder::PushConstantList mPushConstants;
utils::CString mMaterialFragmentCode; // fragment or compute code
utils::CString mMaterialVertexCode;
+7 -7
View File
@@ -888,10 +888,10 @@ TEST_F(MaterialCompiler, ConstantParameter) {
}
)");
filamat::MaterialBuilder builder;
builder.constant("myFloatConstant", ConstantType::FLOAT, 1.0f);
builder.constant("myIntConstant", ConstantType::INT, 123);
builder.constant("myBoolConstant", ConstantType::BOOL, true);
builder.constant<bool>("myOtherBoolConstant", ConstantType::BOOL);
builder.constant("myFloatConstant", ConstantType::FLOAT, /*isMutable=*/false, 1.0f);
builder.constant("myIntConstant", ConstantType::INT, /*isMutable=*/false, 123);
builder.constant("myBoolConstant", ConstantType::BOOL, /*isMutable=*/false, true);
builder.constant<bool>("myOtherBoolConstant", ConstantType::BOOL, /*isMutable=*/false);
builder.shading(filament::Shading::LIT);
builder.material(shaderCode.c_str());
@@ -904,8 +904,8 @@ TEST_F(MaterialCompiler, ConstantParameterSameName) {
#ifdef __EXCEPTIONS
EXPECT_THROW({
filamat::MaterialBuilder builder;
builder.constant("myFloatConstant", ConstantType::FLOAT, 1.0f);
builder.constant("myFloatConstant", ConstantType::FLOAT, 1.0f);
builder.constant("myFloatConstant", ConstantType::FLOAT, /*isMutable=*/false, 1.0f);
builder.constant("myFloatConstant", ConstantType::FLOAT, /*isMutable=*/false, 1.0f);
}, utils::PostconditionPanic);
#endif
}
@@ -914,7 +914,7 @@ TEST_F(MaterialCompiler, ConstantParameterWrongType) {
#ifdef __EXCEPTIONS
EXPECT_THROW({
filamat::MaterialBuilder builder;
builder.constant("myFloatConstant", ConstantType::FLOAT, 10);
builder.constant("myFloatConstant", ConstantType::FLOAT, /*isMutable=*/false, 10);
}, utils::PostconditionPanic);
#endif
}
+2
View File
@@ -19,6 +19,7 @@ set(RESOURCE_BINS)
set(MATERIAL_SRCS
materials/aiDefaultMat.mat
materials/bakedColor.mat
materials/bakedColorWithMutableConstants.mat
materials/bakedTexture.mat
materials/aoPreview.mat
materials/arrayTexture.mat
@@ -278,6 +279,7 @@ if (NOT ANDROID)
add_demo(lightbulb)
add_demo(material_sandbox)
add_demo(multiple_windows)
add_demo(mutable_constants)
# Tint does not support setting gl_PointSize, disable the relevant sample if using WebGPU
# https://github.com/gpuweb/gpuweb/issues/1190
if (NOT FILAMENT_SUPPORTS_WEBGPU)
@@ -0,0 +1,44 @@
material {
name : BakedColorWithMutableConstants,
requires : [
color
],
constants : [
{
name: swizzle,
type: bool,
mutable: true,
default: true,
},
{
name: darken,
type: bool,
mutable: true,
},
{
// In generated shader sources, we first specify immutable
// specialization constants, then mutable specialization constants.
// By including this dummy constant, we offset the ID of the first
// mutable constant by one. This is done here purely for testing
// purposes.
name: dummy,
type: bool,
}
],
shadingModel : unlit,
culling : none,
}
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
if (materialConstants_swizzle) {
material.baseColor = getColor().gbra;
} else {
material.baseColor = getColor();
}
if (materialConstants_darken) {
material.baseColor.rgb *= 0.5;
}
}
}
+214
View File
@@ -0,0 +1,214 @@
/*
* Copyright (C) 2025 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 <filament/Camera.h>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/RenderableManager.h>
#include <filament/Scene.h>
#include <filament/Skybox.h>
#include <filament/TransformManager.h>
#include <filament/VertexBuffer.h>
#include <filament/View.h>
#include <imgui.h>
#include <utils/EntityManager.h>
#include <filamentapp/Config.h>
#include <filamentapp/FilamentApp.h>
#include <getopt/getopt.h>
#include <cmath>
#include <iostream>
#include "generated/resources/resources.h"
using namespace filament;
using utils::Entity;
using utils::EntityManager;
struct App {
Config config;
VertexBuffer* vb;
IndexBuffer* ib;
Material* mat;
Camera* cam;
Entity camera;
Skybox* skybox;
Entity renderable;
};
struct Vertex {
filament::math::float2 position;
uint32_t color;
};
static const Vertex TRIANGLE_VERTICES[3] = {
{{1, 0}, 0xffff0000u},
{{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u},
{{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu},
};
static constexpr uint16_t TRIANGLE_INDICES[3] = { 0, 1, 2 };
static void printUsage(char* name) {
std::string exec_name(utils::Path(name).getName());
std::string usage(
"MUTABLE_CONSTANTS renders a spinning colored triangle\n"
"Usage:\n"
" MUTABLE_CONSTANTS [options]\n"
"Options:\n"
" --help, -h\n"
" Prints this message\n\n"
" --api, -a\n"
" Specify the backend API: opengl, vulkan, metal, or webgpu\n"
" (note: webgpu is a no-op for now, printing backend\n"
" component info if FILAMENT_BACKEND_DEBUG_FLAG, \n"
" set at build time, includes the \n"
" FWGPU_PRINT_SYSTEM bit flag 0x2)\n"
);
const std::string from("MUTABLE_CONSTANTS");
for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) {
usage.replace(pos, from.length(), exec_name);
}
std::cout << usage;
}
static int handleCommandLineArguments(int argc, char* argv[], App* app) {
static constexpr const char* OPTSTR = "ha:";
static const struct option OPTIONS[] = {
{ "help", no_argument, nullptr, 'h' },
{ "api", required_argument, nullptr, 'a' },
{ nullptr, 0, nullptr, 0 }
};
int opt;
int option_index = 0;
while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) {
std::string arg(optarg ? optarg : "");
switch (opt) {
default:
case 'h':
printUsage(argv[0]);
exit(0);
case 'a':
if (arg == "opengl") {
app->config.backend = Engine::Backend::OPENGL;
} else if (arg == "vulkan") {
app->config.backend = Engine::Backend::VULKAN;
} else if (arg == "metal") {
app->config.backend = Engine::Backend::METAL;
} else if (arg == "webgpu") {
app->config.backend = Engine::Backend::WEBGPU;
} else {
std::cerr << "Unrecognized backend. Must be "
"'opengl'|'vulkan'|'metal'|'webgpu'.\n";
exit(1);
}
break;
}
}
return optind;
}
int main(int argc, char** argv) {
App app{};
app.config.title = "mutable_constants";
handleCommandLineArguments(argc, argv, &app);
auto setup = [&app](Engine* engine, View* view, Scene* scene) {
app.skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*engine);
scene->setSkybox(app.skybox);
view->setPostProcessingEnabled(false);
static_assert(sizeof(Vertex) == 12, "Strange vertex size.");
app.vb = VertexBuffer::Builder()
.vertexCount(3)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12)
.attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12)
.normalized(VertexAttribute::COLOR)
.build(*engine);
app.vb->setBufferAt(*engine, 0,
VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr));
app.ib = IndexBuffer::Builder()
.indexCount(3)
.bufferType(IndexBuffer::IndexType::USHORT)
.build(*engine);
app.ib->setBuffer(*engine,
IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 6, nullptr));
app.mat = Material::Builder().package(RESOURCES_BAKEDCOLORWITHMUTABLECONSTANTS_DATA,
RESOURCES_BAKEDCOLORWITHMUTABLECONSTANTS_SIZE)
.build(*engine);
app.renderable = EntityManager::get().create();
RenderableManager::Builder(1)
.boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }})
.material(0, app.mat->getDefaultInstance())
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.vb, app.ib, 0, 3)
.culling(false)
.receiveShadows(false)
.castShadows(false)
.build(*engine, app.renderable);
scene->addEntity(app.renderable);
app.camera = utils::EntityManager::get().create();
app.cam = engine->createCamera(app.camera);
view->setCamera(app.cam);
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
engine->destroy(app.skybox);
engine->destroy(app.renderable);
engine->destroy(app.mat);
engine->destroy(app.vb);
engine->destroy(app.ib);
engine->destroyCameraComponent(app.camera);
utils::EntityManager::get().destroy(app.camera);
};
auto gui = [&app](Engine* engine, View* view) {
MaterialInstance* mi = app.mat->getDefaultInstance();
bool swizzle = mi->getConstant<bool>("swizzle");
bool darken = mi->getConstant<bool>("darken");
ImGui::Checkbox("Swizzle", &swizzle);
ImGui::Checkbox("Darken", &darken);
if (swizzle != mi->getConstant<bool>("swizzle")) {
mi->setConstant("swizzle", swizzle);
}
if (darken != mi->getConstant<bool>("darken")) {
mi->setConstant("darken", darken);
}
};
FilamentApp::get().animate([&app](Engine* engine, View* view, double now) {
constexpr float ZOOM = 1.5f;
const uint32_t w = view->getViewport().width;
const uint32_t h = view->getViewport().height;
const float aspect = (float) w / h;
app.cam->setProjection(Camera::Projection::ORTHO,
-aspect * ZOOM, aspect * ZOOM,
-ZOOM, ZOOM, 0, 1);
auto& tcm = engine->getTransformManager();
tcm.setTransform(tcm.getInstance(app.renderable),
filament::math::mat4f::rotation(now, filament::math::float3{ 0, 0, 1 }));
});
FilamentApp::get().run(app.config, setup, cleanup, gui);
return 0;
}
+59
View File
@@ -1,3 +1,62 @@
# 3.3.0 (2025-05-12)
Additions to the library API:
- Added function `vmaImportVulkanFunctionsFromVolk`, useful for loading pointers to Vulkan functions with [volk library](https://github.com/zeux/volk).
Other changes:
- Added macro `VMA_DEBUG_DONT_EXCEED_HEAP_SIZE_WITH_ALLOCATION_SIZE` with default value 1.
- Changed macro `VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT` default value from 0 to 1.
- Added documentation chapter "Frequenty asked questions".
- Other fixes and improvements, including compatibility with various platforms and compilers.
# 3.2.1 (2025-02-05)
Changes:
- Fixed an assert in `vmaCreateAllocator` function incorrectly failing when Vulkan version 1.4 is used (#457).
- Fix for importing function `vkGetPhysicalDeviceMemoryProperties2` / `vkGetPhysicalDeviceMemoryProperties2KHR` when `VMA_DYNAMIC_VULKAN_FUNCTIONS` macro is enabled (#410).
- Other minor fixes and improvements...
# 3.2.0 (2024-12-30)
Additions to the library API:
- Added support for Vulkan 1.4.
- Added support for VK_KHR_external_memory_win32 extension - `VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT` flag, `vmaGetMemoryWin32Handle` function, and a whole new documentation chapter about it (#442).
Other changes:
- Fixed thread safety issue (#451).
- Many other bug fixes and improvements in the library code, documentation, sample app, Cmake script, mostly to improve compatibility with various compilers and GPUs.
# 3.1.0 (2024-05-27)
This release gathers fixes and improvements made during many months of continuous development on the main branch, mostly based on issues and pull requests on GitHub.
Additions to the library API:
- Added convenience functions `vmaCopyMemoryToAllocation`, `vmaCopyAllocationToMemory`.
- Added functions `vmaCreateAliasingBuffer2`, `vmaCreateAliasingImage2` that offer creating a buffer/image in an existing allocation with additional `allocationLocalOffset`.
- Added function `vmaGetAllocationInfo2`, structure `VmaAllocationInfo2` that return additional information about an allocation, useful for interop with other APIs (#383, #340).
- Added callback `VmaDefragmentationInfo::pfnBreakCallback` that allows breaking long execution of `vmaBeginDefragmentation`.
Also added `PFN_vmaCheckDefragmentationBreakFunction`, `VmaDefragmentationInfo::pBreakCallbackUserData`.
- Added support for VK_KHR_maintenance4 extension - `VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT` flag (#397).
- Added support for VK_KHR_maintenance5 extension - `VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT` flag (#411).
Other changes:
- Changes in debug and configuration macros:
- Split macros into separate `VMA_DEBUG_LOG` and `VMA_DEBUG_LOG_FORMAT` (#297).
- Added macros `VMA_ASSERT_LEAK`, `VMA_LEAK_LOG_FORMAT` separate from normal `VMA_ASSERT`, `VMA_DEBUG_LOG_FORMAT` (#379, #385).
- Added macro `VMA_EXTENDS_VK_STRUCT` (#347).
- Countless bug fixes and improvements in the code and documentation, mostly to improve compatibility with various compilers and GPUs, including:
- Fixed missing `#include` that resulted in compilation error about `snprintf` not declared on some compilers (#312).
- Fixed main memory type selection algorithm for GPUs that have no `HOST_CACHED` memory type, like Raspberry Pi (#362).
- Major changes in Cmake script.
- Fixes in GpuMemDumpVis.py script.
# 3.0.1 (2022-05-26)
- Fixes in defragmentation algorithm.
+51 -35
View File
@@ -1,55 +1,71 @@
cmake_minimum_required(VERSION 3.9)
#
# Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
project(VulkanMemoryAllocator)
cmake_minimum_required(VERSION 3.15...3.26)
find_package(Vulkan REQUIRED)
include_directories(${Vulkan_INCLUDE_DIR})
project(VMA VERSION 3.3.0 LANGUAGES CXX)
# VulkanMemoryAllocator contains an sample application which is not built by default
option(VMA_BUILD_SAMPLE "Build VulkanMemoryAllocator sample application" OFF)
option(VMA_BUILD_SAMPLE_SHADERS "Build VulkanMemoryAllocator sample application's shaders" OFF)
add_library(VulkanMemoryAllocator INTERFACE)
add_library(GPUOpen::VulkanMemoryAllocator ALIAS VulkanMemoryAllocator)
message(STATUS "VMA_BUILD_SAMPLE = ${VMA_BUILD_SAMPLE}")
message(STATUS "VMA_BUILD_SAMPLE_SHADERS = ${VMA_BUILD_SAMPLE_SHADERS}")
target_include_directories(VulkanMemoryAllocator INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
option(VMA_STATIC_VULKAN_FUNCTIONS "Link statically with Vulkan API" ON)
option(VMA_DYNAMIC_VULKAN_FUNCTIONS "Fetch pointers to Vulkan functions internally (no static linking)" OFF)
option(VMA_DEBUG_ALWAYS_DEDICATED_MEMORY "Every allocation will have its own memory block" OFF)
option(VMA_DEBUG_INITIALIZE_ALLOCATIONS "Automatically fill new allocations and destroyed allocations with some bit pattern" OFF)
option(VMA_DEBUG_GLOBAL_MUTEX "Enable single mutex protecting all entry calls to the library" OFF)
option(VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT "Never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount and return error" OFF)
if (CMAKE_VERSION VERSION_LESS "3.21")
# https://cmake.org/cmake/help/latest/variable/PROJECT_IS_TOP_LEVEL.html
string(COMPARE EQUAL ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} PROJECT_IS_TOP_LEVEL)
endif()
message(STATUS "VMA_STATIC_VULKAN_FUNCTIONS = ${VMA_STATIC_VULKAN_FUNCTIONS}")
message(STATUS "VMA_DYNAMIC_VULKAN_FUNCTIONS = ${VMA_DYNAMIC_VULKAN_FUNCTIONS}")
message(STATUS "VMA_DEBUG_ALWAYS_DEDICATED_MEMORY = ${VMA_DEBUG_ALWAYS_DEDICATED_MEMORY}")
message(STATUS "VMA_DEBUG_INITIALIZE_ALLOCATIONS = ${VMA_DEBUG_INITIALIZE_ALLOCATIONS}")
message(STATUS "VMA_DEBUG_GLOBAL_MUTEX = ${VMA_DEBUG_GLOBAL_MUTEX}")
message(STATUS "VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT = ${VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT}")
option(VMA_ENABLE_INSTALL "Install VulkanMemoryAllocator" ${PROJECT_IS_TOP_LEVEL})
if (VMA_ENABLE_INSTALL)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
if(VMA_BUILD_SAMPLE)
set(VMA_BUILD_SAMPLE_SHADERS ON)
endif(VMA_BUILD_SAMPLE)
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS VulkanMemoryAllocator EXPORT VulkanMemoryAllocatorConfig INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(EXPORT VulkanMemoryAllocatorConfig NAMESPACE "GPUOpen::" DESTINATION "share/cmake/VulkanMemoryAllocator")
find_package(Doxygen)
option(BUILD_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" OFF)
write_basic_package_version_file(VulkanMemoryAllocatorConfigVersion.cmake COMPATIBILITY SameMajorVersion ARCH_INDEPENDENT)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/VulkanMemoryAllocatorConfigVersion.cmake" DESTINATION "share/cmake/VulkanMemoryAllocator")
if(BUILD_DOCUMENTATION)
if(DOXYGEN_FOUND)
option(VMA_BUILD_DOCUMENTATION "Create and install the HTML based API documentation")
if(VMA_BUILD_DOCUMENTATION)
find_package(Doxygen REQUIRED)
# set input and output files
set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile)
set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
# request to configure the file
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
# note the option ALL which allows to build the docs together with the application
add_custom_target( doc_doxygen ALL
add_custom_target(doc_doxygen ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen"
VERBATIM )
else()
message("Doxygen need to be installed to generate the doxygen documentation")
VERBATIM
)
install(DIRECTORY docs/ DESTINATION "${CMAKE_INSTALL_DATADIR}/doc/VulkanMemoryAllocator" PATTERN ".nojekyll" EXCLUDE)
endif()
option(VMA_BUILD_SAMPLES "Build samples")
if (VMA_BUILD_SAMPLES)
add_subdirectory(src)
endif()
endif()
add_subdirectory(src)
+360 -139
View File
@@ -1,4 +1,4 @@
# Doxyfile 1.9.2
# Doxyfile 1.10.0
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -12,6 +12,16 @@
# For lists, items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (\" \").
#
# Note:
#
# Use doxygen to compare the used configuration file with the template
# configuration file:
# doxygen -x [configFile]
# Use doxygen to compare the used configuration file with the template
# configuration file without replacing the environment variables or CMake type
# replacement variables:
# doxygen -x_noenv [configFile]
#---------------------------------------------------------------------------
# Project related configuration options
@@ -53,23 +63,41 @@ PROJECT_BRIEF =
PROJECT_LOGO =
# With the PROJECT_ICON tag one can specify an icon that is included in the tabs
# when the HTML document is shown. Doxygen will copy the logo to the output
# directory.
PROJECT_ICON =
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = "@CMAKE_SOURCE_DIR@/docs"
OUTPUT_DIRECTORY = @CMAKE_SOURCE_DIR@/docs
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
# sub-directories (in 2 levels) under the output directory of each output format
# and will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
# putting all generated files in the same directory would otherwise causes
# performance problems for the file system.
# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
# control the number of sub-directories.
# The default value is: NO.
CREATE_SUBDIRS = NO
# Controls the number of sub-directories that will be created when
# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
# level increment doubles the number of directories, resulting in 4096
# directories at level 8 which is the default and also the maximum value. The
# sub-directories are organized in 2 levels, the first level always has a fixed
# number of 16 directories.
# Minimum value: 0, maximum value: 8, default value: 8.
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
CREATE_SUBDIRS_LEVEL = 8
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
@@ -81,14 +109,14 @@ ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
# Ukrainian and Vietnamese.
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
# English messages), Korean, Korean-en (Korean with English messages), Latvian,
# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
# Swedish, Turkish, Ukrainian and Vietnamese.
# The default value is: English.
OUTPUT_LANGUAGE = English
@@ -341,6 +369,17 @@ MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 0
# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
# generate identifiers for the Markdown headings. Note: Every identifier is
# unique.
# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a
# sequence number starting at 0 and GITHUB use the lower case version of title
# with any whitespace replaced by '-' and punctuation characters removed.
# The default value is: DOXYGEN.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
MARKDOWN_ID_STYLE = DOXYGEN
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by putting a % sign in front of the word or
@@ -452,7 +491,7 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
@@ -465,6 +504,14 @@ LOOKUP_CACHE_SIZE = 0
NUM_PROC_THREADS = 1
# If the TIMESTAMP tag is set different from NO then each generated page will
# contain the date or date and time when the page was generated. Setting this to
# NO can help when comparing the output of multiple runs.
# Possible values are: YES, NO, DATETIME and DATE.
# The default value is: NO.
TIMESTAMP = NO
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@@ -546,7 +593,8 @@ HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option
# has no effect if EXTRACT_ALL is enabled.
# will also hide undocumented C++ concepts if enabled. This option has no effect
# if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
@@ -577,14 +625,15 @@ INTERNAL_DOCS = NO
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
# are not case sensitive the option should be be set to NO to properly deal with
# are not case sensitive the option should be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
# The default value is: system dependent.
# Possible values are: SYSTEM, NO and YES.
# The default value is: SYSTEM.
CASE_SENSE_NAMES = NO
@@ -836,11 +885,26 @@ WARN_IF_INCOMPLETE_DOC = YES
WARN_NO_PARAMDOC = NO
# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
# undocumented enumeration values. If set to NO, doxygen will accept
# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: NO.
WARN_IF_UNDOC_ENUM_VAL = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
# write the warning messages in between other messages but write them at the end
# of a run, in case a WARN_LOGFILE is defined the warning messages will be
# besides being in the defined file also be shown at the end of a run, unless
# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
# the behavior will remain as with the setting FAIL_ON_WARNINGS.
# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
# The default value is: NO.
WARN_AS_ERROR = NO
@@ -851,13 +915,27 @@ WARN_AS_ERROR = NO
# and the warning text. Optionally the format may contain $version, which will
# be replaced by the version of the file (if it could be obtained via
# FILE_VERSION_FILTER)
# See also: WARN_LINE_FORMAT
# The default value is: $file:$line: $text.
WARN_FORMAT = "$file:$line: $text"
# In the $text part of the WARN_FORMAT command it is possible that a reference
# to a more specific place is given. To make it easier to jump to this place
# (outside of doxygen) the user can define a custom "cut" / "paste" string.
# Example:
# WARN_LINE_FORMAT = "'vi $file +$line'"
# See also: WARN_FORMAT
# The default value is: at line $line of file $file.
WARN_LINE_FORMAT = "at line $line of file $file"
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
# messages should be written. If left blank the output is written to standard
# error (stderr).
# error (stderr). In case the file specified cannot be opened for writing the
# warning and error messages are written to standard error. When as file - is
# specified the warning and error messages are written to standard output
# (stdout).
WARN_LOGFILE =
@@ -878,10 +956,21 @@ INPUT = "@CMAKE_SOURCE_DIR@/include/vk_mem_alloc.h"
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# See also: INPUT_FILE_ENCODING
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
# This tag can be used to specify the character encoding of the source files
# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
# character encoding on a per file pattern basis. Doxygen will compare the file
# name with each pattern and apply the encoding instead of the default
# INPUT_ENCODING) if there is a match. The character encodings are a list of the
# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
# "INPUT_ENCODING" for further information on supported encodings.
INPUT_FILE_ENCODING =
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories.
@@ -893,12 +982,12 @@ INPUT_ENCODING = UTF-8
# Note the list of default checked file patterns might differ from the list of
# default file extension mappings.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
# *.vhdl, *.ucf, *.qsf and *.ice.
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl,
# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d,
# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to
# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \
*.cc \
@@ -980,10 +1069,7 @@ EXCLUDE_PATTERNS =
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
# ANamespace::AClass, ANamespace::*Test
EXCLUDE_SYMBOLS =
@@ -1028,6 +1114,11 @@ IMAGE_PATH =
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
#
# Note that doxygen will use the data processed and written to standard output
# for further processing, therefore nothing else, like debug statements or used
# commands (so in case of a Windows batch file always use @echo OFF), should be
# written to standard output.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
@@ -1069,6 +1160,15 @@ FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
# The Fortran standard specifies that for fixed formatted Fortran code all
# characters from position 72 are to be considered as comment. A common
# extension is to allow longer lines before the automatic comment starts. The
# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
# be processed before the automatic comment starts.
# Minimum value: 7, maximum value: 10000, default value: 72.
FORTRAN_COMMENT_AFTER = 72
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
@@ -1083,7 +1183,8 @@ USE_MDFILE_AS_MAINPAGE =
SOURCE_BROWSER = NO
# Setting the INLINE_SOURCES tag to YES will include the body of functions,
# classes and enums directly into the documentation.
# multi-line macros, enums or list initialized variables directly into the
# documentation.
# The default value is: NO.
INLINE_SOURCES = NO
@@ -1206,10 +1307,11 @@ CLANG_DATABASE_PATH =
ALPHABETICAL_INDEX = YES
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored
# while generating the index headers.
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
# that should be ignored while generating the index headers. The IGNORE_PREFIX
# tag works for classes, function and member names. The entity will be placed in
# the alphabetical list under the first letter of the entity name that remains
# after removing the prefix.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
@@ -1288,7 +1390,12 @@ HTML_STYLESHEET =
# Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation.
# list).
# Note: Since the styling of scrollbars can currently not be overruled in
# Webkit/Chromium, the styling will be left out of the default doxygen.css if
# one or more extra stylesheets have been specified. So if scrollbar
# customization is desired it has to be added explicitly. For an example see the
# documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
@@ -1303,6 +1410,19 @@ HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
# should be rendered with a dark or light theme.
# Possible values are: LIGHT always generate light mode output, DARK always
# generate dark mode output, AUTO_LIGHT automatically set the mode according to
# the user preference, use light mode if no preference is set (the default),
# AUTO_DARK automatically set the mode according to the user preference, use
# dark mode if no preference is set and TOGGLE allow to user to switch between
# light and dark mode via a button.
# The default value is: AUTO_LIGHT.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE = AUTO_LIGHT
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a color-wheel, see
@@ -1333,15 +1453,6 @@ HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
# to YES can help to show when doxygen was last run and thus if the
# documentation is up to date.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = NO
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
# are dynamically created via JavaScript. If disabled, the navigation index will
@@ -1361,6 +1472,33 @@ HTML_DYNAMIC_MENUS = YES
HTML_DYNAMIC_SECTIONS = NO
# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be
# dynamically folded and expanded in the generated HTML source code.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_CODE_FOLDING = YES
# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in
# the top right corner of code and text fragments that allows the user to copy
# its content to the clipboard. Note this only works if supported by the browser
# and the web page is served via a secure context (see:
# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file:
# protocol.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COPY_CLIPBOARD = YES
# Doxygen stores a couple of settings persistently in the browser (via e.g.
# cookies). By default these settings apply to all HTML pages generated by
# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store
# the settings under a project specific key, such that the user preferences will
# be stored separately.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_PROJECT_COOKIE =
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
# shown in the various tree structured indices initially; the user can expand
# and collapse entries dynamically later on. Doxygen will expand the tree to
@@ -1397,6 +1535,13 @@ GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
# This tag determines the URL of the docset feed. A documentation feed provides
# an umbrella under which multiple documentation sets from a single provider
# (such as a company or product suite) can be grouped.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_FEEDURL =
# This tag specifies a string that should uniquely identify the documentation
# set bundle. This should be a reverse domain-name style string, e.g.
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
@@ -1484,6 +1629,16 @@ BINARY_TOC = NO
TOC_EXPAND = NO
# The SITEMAP_URL tag is used to specify the full URL of the place where the
# generated documentation will be placed on the server by the user during the
# deployment of the documentation. The generated sitemap is called sitemap.xml
# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
# is specified no sitemap is generated. For information about the sitemap
# protocol see https://www.sitemaps.org
# This tag requires that the tag GENERATE_HTML is set to YES.
SITEMAP_URL =
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
@@ -1601,7 +1756,7 @@ GENERATE_TREEVIEW = NO
# area (value NO) or if it should extend to the full height of the window (value
# YES). Setting this to YES gives a layout similar to
# https://docs.readthedocs.io with more room for contents, but less room for the
# project logo, title, and description. If either GENERATOR_TREEVIEW or
# project logo, title, and description. If either GENERATE_TREEVIEW or
# DISABLE_INDEX is set to NO, this option has no effect.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1632,6 +1787,13 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
# addresses.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
OBFUSCATE_EMAILS = YES
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
@@ -1652,17 +1814,6 @@ HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
# Note that when changing this option you need to delete any form_*.png files in
# the HTML output directory before the changes have effect.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_TRANSPARENT = YES
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details.
@@ -1976,9 +2127,16 @@ PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
# command to the generated LaTeX files. This will instruct LaTeX to keep running
# if errors occur, instead of asking the user for help.
# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
# mode nothing is printed on the terminal, errors are scrolled as if <return> is
# hit at every error; missing files that TeX tries to input or request from
# keyboard input (\read on a not open input stream) cause the job to abort,
# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
# but there is no possibility of user interaction just like in batch mode,
# SCROLL In scroll mode, TeX will stop only for missing files to input or if
# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
# each error, asking for user intervention.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1999,14 +2157,6 @@ LATEX_HIDE_INDICES = NO
LATEX_BIB_STYLE = plain
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_TIMESTAMP = NO
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
# path from which the emoji images will be read. If a relative path is entered,
# it will be relative to the LATEX_OUTPUT directory. If left blank the
@@ -2172,13 +2322,39 @@ DOCBOOK_OUTPUT = docbook
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
# the structure of the code including all documentation. Note that this feature
# is still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to Sqlite3 output
#---------------------------------------------------------------------------
# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3
# database with symbols found by doxygen stored in tables.
# The default value is: NO.
GENERATE_SQLITE3 = NO
# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be
# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put
# in front of it.
# The default directory is: sqlite3.
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
SQLITE3_OUTPUT = sqlite3
# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db
# database file will be recreated with each doxygen run. If set to NO, doxygen
# will warn if a database file is already found and not modify it.
# The default value is: YES.
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
SQLITE3_RECREATE_DB = YES
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
@@ -2253,7 +2429,8 @@ SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by the
# preprocessor.
# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
# RECURSIVE has no effect here.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH =
@@ -2282,8 +2459,18 @@ PREDEFINED = VMA_CALL_PRE= \
VMA_NOT_NULL_NON_DISPATCHABLE= \
VMA_NULLABLE_NON_DISPATCHABLE= \
VMA_VULKAN_VERSION=1003000 \
VMA_DEDICATED_ALLOCATION=1 \
VMA_BIND_MEMORY2=1 \
VMA_MEMORY_BUDGET=1 \
VMA_BUFFER_DEVICE_ADDRESS=1 \
VMA_MEMORY_PRIORITY=1 \
VMA_KHR_MAINTENANCE4=1 \
VMA_KHR_MAINTENANCE5=1 \
VMA_EXTERNAL_MEMORY_WIN32=1 \
VMA_EXTERNAL_MEMORY=1 \
VMA_MEMORY_PRIORITY=1
VMA_EXTENDS_VK_STRUCT= \
VMA_STATS_STRING_ENABLED=1 \
VOLK_HEADER_VERSION=304
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
@@ -2329,15 +2516,15 @@ TAGFILES =
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
# the class index. If set to NO, only the inherited external classes will be
# listed.
# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
# will be listed in the class and namespace index. If set to NO, only the
# inherited external classes will be listed.
# The default value is: NO.
ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will be
# in the topic index. If set to NO, only the current project's groups will be
# listed.
# The default value is: YES.
@@ -2351,25 +2538,9 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
# Configuration options related to diagram generator tools
#---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more
# powerful graphs.
# The default value is: YES.
CLASS_DIAGRAMS = YES
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
# If left empty dia is assumed to be found in the default search path.
DIA_PATH =
# If set to YES the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
# The default value is: YES.
@@ -2378,7 +2549,7 @@ HIDE_UNDOC_RELATIONS = YES
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz (see:
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# Bell Labs. The other options in this section have no effect if this option is
# set to NO
# The default value is: NO.
@@ -2395,49 +2566,77 @@ HAVE_DOT = NO
DOT_NUM_THREADS = 0
# When you want a differently looking font in the dot files that doxygen
# generates you can specify the font name using DOT_FONTNAME. You need to make
# sure dot is able to find the font, which can be done by putting it in a
# standard location or by setting the DOTFONTPATH environment variable or by
# setting DOT_FONTPATH to the directory containing the font.
# The default value is: Helvetica.
# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
# subgraphs. When you want a differently looking font in the dot files that
# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
# Edge and Graph Attributes specification</a> You need to make sure dot is able
# to find the font, which can be done by putting it in a standard location or by
# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
# directory containing the font. Default graphviz fontsize is 14.
# The default value is: fontname=Helvetica,fontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTNAME = Helvetica
DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
# dot graphs.
# Minimum value: 4, maximum value: 24, default value: 10.
# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
# arrows shapes.</a>
# The default value is: labelfontname=Helvetica,labelfontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTSIZE = 10
DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
# By default doxygen will tell dot to use the default font as specified with
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
# the path where dot can find it using this tag.
# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
# around nodes set 'shape=plain' or 'shape=plaintext' <a
# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
# The default value is: shape=box,height=0.2,width=0.4.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
# You can set the path where dot can find font specified with fontname in
# DOT_COMMON_ATTR and others dot attributes.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH =
# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
# each documented class showing the direct and indirect inheritance relations.
# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
# generate a graph for each documented class showing the direct and indirect
# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
# relations will be shown as texts / links. Explicit enabling an inheritance
# graph or choosing a different representation for an inheritance graph of a
# specific class, can be accomplished by means of the command \inheritancegraph.
# Disabling an inheritance graph can be accomplished by means of the command
# \hideinheritancegraph.
# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
CLASS_GRAPH = YES
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
# graph for each documented class showing the direct and indirect implementation
# dependencies (inheritance, containment, and class references variables) of the
# class with other documented classes.
# class with other documented classes. Explicit enabling a collaboration graph,
# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the
# command \collaborationgraph. Disabling a collaboration graph can be
# accomplished by means of the command \hidecollaborationgraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
COLLABORATION_GRAPH = YES
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
# groups, showing the direct groups dependencies.
# groups, showing the direct groups dependencies. Explicit enabling a group
# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means
# of the command \groupgraph. Disabling a directory graph can be accomplished by
# means of the command \hidegroupgraph. See also the chapter Grouping in the
# manual.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2479,8 +2678,8 @@ DOT_UML_DETAILS = NO
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# significantly it will be wrapped across multiple lines. Some heuristics are
# applied to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2497,7 +2696,9 @@ TEMPLATE_RELATIONS = NO
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
# YES then doxygen will generate a graph for each documented file showing the
# direct and indirect include dependencies of the file with other documented
# files.
# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,
# can be accomplished by means of the command \includegraph. Disabling an
# include graph can be accomplished by means of the command \hideincludegraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2506,7 +2707,10 @@ INCLUDE_GRAPH = YES
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
# set to YES then doxygen will generate a graph for each documented file showing
# the direct and indirect include dependencies of the file with other documented
# files.
# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set
# to NO, can be accomplished by means of the command \includedbygraph. Disabling
# an included by graph can be accomplished by means of the command
# \hideincludedbygraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2546,16 +2750,26 @@ GRAPHICAL_HIERARCHY = YES
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
# dependencies a directory has on other directories in a graphical way. The
# dependency relations are determined by the #include relations between the
# files in the directories.
# files in the directories. Explicit enabling a directory graph, when
# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command
# \directorygraph. Disabling a directory graph can be accomplished by means of
# the command \hidedirectorygraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DIRECTORY_GRAPH = YES
# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
# of child directories generated in directory dependency graphs by dot.
# Minimum value: 1, maximum value: 25, default value: 1.
# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
DIR_GRAPH_MAX_DEPTH = 1
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. For an explanation of the image formats see the section
# output formats in the documentation of the dot tool (Graphviz (see:
# http://www.graphviz.org/)).
# https://www.graphviz.org/)).
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
@@ -2592,11 +2806,12 @@ DOT_PATH =
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile
# command).
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
# If left empty dia is assumed to be found in the default search path.
MSCFILE_DIRS =
DIA_PATH =
# The DIAFILE_DIRS tag can be used to specify one or more directories that
# contain dia files that are included in the documentation (see the \diafile
@@ -2605,10 +2820,10 @@ MSCFILE_DIRS =
DIAFILE_DIRS =
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
# path where java can find the plantuml.jar file. If left blank, it is assumed
# PlantUML is not used or called during a preprocessing step. Doxygen will
# generate a warning when it encounters a \startuml command in this case and
# will not generate output for the diagram.
# path where java can find the plantuml.jar file or to the filename of jar file
# to be used. If left blank, it is assumed PlantUML is not used or called during
# a preprocessing step. Doxygen will generate a warning when it encounters a
# \startuml command in this case and will not generate output for the diagram.
PLANTUML_JAR_PATH =
@@ -2646,18 +2861,6 @@ DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not seem
# to support this out of the box.
#
# Warning: Depending on the platform used, enabling this option may lead to
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
# read).
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
@@ -2670,6 +2873,8 @@ DOT_MULTI_TARGETS = NO
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
# explaining the meaning of the various boxes and arrows in the dot generated
# graphs.
# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
# graphical representation for inheritance and collaboration diagrams is used.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2683,3 +2888,19 @@ GENERATE_LEGEND = YES
# The default value is: YES.
DOT_CLEANUP = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
# use a built-in version of mscgen tool to produce the charts. Alternatively,
# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
# specifying prog as the value, doxygen will call the tool as prog -T
# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
# output file formats "png", "eps", "svg", and "ismap".
MSCGEN_TOOL =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile
# command).
MSCFILE_DIRS =
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+50 -34
View File
@@ -10,11 +10,6 @@ Easy to integrate Vulkan memory allocation library.
**Product page:** [Vulkan Memory Allocator on GPUOpen](https://gpuopen.com/gaming-product/vulkan-memory-allocator/)
**Build status:**
- Windows: [![Build status](https://ci.appveyor.com/api/projects/status/4vlcrb0emkaio2pn/branch/master?svg=true)](https://ci.appveyor.com/project/adam-sawicki-amd/vulkanmemoryallocator/branch/master)
- Linux: [![Build Status](https://app.travis-ci.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.svg?branch=master)](https://app.travis-ci.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator)
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.svg)](http://isitmaintained.com/project/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator "Average time to resolve an issue")
# Problem
@@ -48,13 +43,17 @@ Additional features:
- Support for sparse binding and sparse residency: Convenience functions that allocate or free multiple memory pages at once.
- Custom memory pools: Create a pool with desired parameters (e.g. fixed or limited maximum size) and allocate memory out of it.
- Linear allocator: Create a pool with linear algorithm and use it for much faster allocations and deallocations in free-at-once, stack, double stack, or ring buffer fashion.
- Support for Vulkan 1.0, 1.1, 1.2, 1.3.
- Support for Vulkan 1.0...1.4.
- Support for extensions (and equivalent functionality included in new Vulkan versions):
- VK_KHR_dedicated_allocation: Just enable it and it will be used automatically by the library.
- VK_KHR_buffer_device_address: Flag `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR` is automatically added to memory allocations where needed.
- VK_KHR_bind_memory2.
- VK_KHR_maintenance4.
- VK_KHR_maintenance5, including `VkBufferUsageFlags2CreateInfoKHR`.
- VK_EXT_memory_budget: Used internally if available to query for current usage and budget. If not available, it falls back to an estimation based on memory heap sizes.
- VK_KHR_buffer_device_address: Flag `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR` is automatically added to memory allocations where needed.
- VK_EXT_memory_priority: Set `priority` of allocations or custom pools and it will be set automatically using this extension.
- VK_AMD_device_coherent_memory
- VK_AMD_device_coherent_memory.
- VK_KHR_external_memory_win32.
- Defragmentation of GPU and CPU memory: Let the library move data around to free some memory blocks and make your allocations better compacted.
- Statistics: Obtain brief or detailed statistics about the amount of memory used, unused, number of allocated blocks, number of allocations etc. - globally, per memory heap, and per memory type.
- Debug annotations: Associate custom `void* pUserData` and debug `char* pName` with each allocation.
@@ -99,42 +98,51 @@ With this one function call:
# How to build
On Windows it is recommended to use [CMake UI](https://cmake.org/runningcmake/). Alternatively you can generate a Visual Studio project map using CMake in command line: `cmake -B./build/ -DCMAKE_BUILD_TYPE=Debug -G "Visual Studio 16 2019" -A x64 ./`
On Windows it is recommended to use [CMake GUI](https://cmake.org/runningcmake/).
Alternatively you can generate/open a Visual Studio from the command line:
```sh
# By default CMake picks the newest version of Visual Studio it can use
cmake -S . -B build -D VMA_BUILD_SAMPLES=ON
cmake --open build
```
On Linux:
```
mkdir build
cd build
cmake ..
make
```sh
cmake -S . -B build
# Since VMA has no source files, you can skip to installation immediately
cmake --install build --prefix build/install
```
The following targets are available
## How to use
| Target | Description | CMake option | Default setting |
| ------------- | ------------- | ------------- | ------------- |
| VmaSample | VMA sample application | `VMA_BUILD_SAMPLE` | `OFF` |
| VmaBuildSampleShaders | Shaders for VmaSample | `VMA_BUILD_SAMPLE_SHADERS` | `OFF` |
After calling either `find_package` or `add_subdirectory` simply link the library.
This automatically handles configuring the include directory. Example:
Please note that while VulkanMemoryAllocator library is supported on other platforms besides Windows, VmaSample is not.
```cmake
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
target_link_libraries(YourGameEngine PRIVATE GPUOpen::VulkanMemoryAllocator)
```
These CMake options are available
For more info on using CMake visit the official [CMake documentation](https://cmake.org/cmake/help/latest/index.html).
| CMake option | Description | Default setting |
| ------------- | ------------- | ------------- |
| `VMA_RECORDING_ENABLED` | Enable VMA memory recording for debugging | `OFF` |
| `VMA_USE_STL_CONTAINERS` | Use C++ STL containers instead of VMA's containers | `OFF` |
| `VMA_STATIC_VULKAN_FUNCTIONS` | Link statically with Vulkan API | `OFF` |
| `VMA_DYNAMIC_VULKAN_FUNCTIONS` | Fetch pointers to Vulkan functions internally (no static linking) | `ON` |
| `VMA_DEBUG_ALWAYS_DEDICATED_MEMORY` | Every allocation will have its own memory block | `OFF` |
| `VMA_DEBUG_INITIALIZE_ALLOCATIONS` | Automatically fill new allocations and destroyed allocations with some bit pattern | `OFF` |
| `VMA_DEBUG_GLOBAL_MUTEX` | Enable single mutex protecting all entry calls to the library | `OFF` |
| `VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT` | Never exceed [VkPhysicalDeviceLimits::maxMemoryAllocationCount](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#limits-maxMemoryAllocationCount) and return error | `OFF` |
## Building using vcpkg
You can download and install VulkanMemoryAllocator using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install vulkan-memory-allocator
The VulkanMemoryAllocator port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
# Binaries
The release comes with precompiled binary executable for "VulkanSample" application which contains test suite. It is compiled using Visual Studio 2019, so it requires appropriate libraries to work, including "MSVCP140.dll", "VCRUNTIME140.dll", "VCRUNTIME140_1.dll". If the launch fails with error message telling about those files missing, please download and install [Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads), "x64" version.
The release comes with precompiled binary executable for "VulkanSample" application which contains test suite. It is compiled using Visual Studio 2022, so it requires appropriate libraries to work, including "MSVCP140.dll", "VCRUNTIME140.dll", "VCRUNTIME140_1.dll". If the launch fails with error message telling about those files missing, please download and install [Microsoft Visual C++ Redistributable](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads), "X64" version.
# Read more
@@ -142,24 +150,31 @@ See **[Documentation](https://gpuopen-librariesandsdks.github.io/VulkanMemoryAll
# Software using this library
- **[Blender](https://www.blender.org)**
- **[Qt Project](https://github.com/qt)**
- **[Baldur's Gate III](https://www.mobygames.com/game/150689/baldurs-gate-iii/credits/windows/?autoplatform=true)**
- **[Cyberpunk 2077](https://www.mobygames.com/game/128136/cyberpunk-2077/credits/windows/?autoplatform=true)**
- **[X-Plane](https://x-plane.com/)**
- **[Detroit: Become Human](https://gpuopen.com/learn/porting-detroit-3/)**
- **[Vulkan Samples](https://github.com/LunarG/VulkanSamples)** - official Khronos Vulkan samples. License: Apache-style.
- **[GFXReconstruct](https://github.com/LunarG/gfxreconstruct)** - a tools for the capture and replay of graphics API calls. License: MIT.
- **[Anvil](https://github.com/GPUOpen-LibrariesAndSDKs/Anvil)** - cross-platform framework for Vulkan. License: MIT.
- **[Filament](https://github.com/google/filament)** - physically based rendering engine for Android, Windows, Linux and macOS, from Google. Apache License 2.0.
- **[Atypical Games - proprietary game engine](https://developer.samsung.com/galaxy-gamedev/gamedev-blog/infinitejet.html)**
- **[Flax Engine](https://flaxengine.com/)**
- **[Godot Engine](https://github.com/godotengine/godot/)** - multi-platform 2D and 3D game engine. License: MIT.
- **[Lightweight Java Game Library (LWJGL)](https://www.lwjgl.org/)** - includes binding of the library for Java. License: BSD.
- **[LightweightVK](https://github.com/corporateshark/lightweightvk)** - lightweight C++ bindless Vulkan 1.3 wrapper. License: MIT.
- **[PowerVR SDK](https://github.com/powervr-graphics/Native_SDK)** - C++ cross-platform 3D graphics SDK, from Imagination. License: MIT.
- **[Skia](https://github.com/google/skia)** - complete 2D graphic library for drawing Text, Geometries, and Images, from Google.
- **[The Forge](https://github.com/ConfettiFX/The-Forge)** - cross-platform rendering framework. Apache License 2.0.
- **[VK9](https://github.com/disks86/VK9)** - Direct3D 9 compatibility layer using Vulkan. Zlib lincese.
- **[VK9](https://github.com/disks86/VK9)** - Direct3D 9 compatibility layer using Vulkan. Zlib license.
- **[vkDOOM3](https://github.com/DustinHLand/vkDOOM3)** - Vulkan port of GPL DOOM 3 BFG Edition. License: GNU GPL.
- **[vkQuake2](https://github.com/kondrak/vkQuake2)** - vanilla Quake 2 with Vulkan support. License: GNU GPL.
- **[Vulkan Best Practice for Mobile Developers](https://github.com/ARM-software/vulkan_best_practice_for_mobile_developers)** from ARM. License: MIT.
- **[RPCS3](https://github.com/RPCS3/rpcs3)** - PlayStation 3 emulator/debugger. License: GNU GPLv2.
- **[PPSSPP](https://github.com/hrydgard/ppsspp)** - Playstation Portable emulator/debugger. License: GNU GPLv2+.
- **[Wicked Engine](https://github.com/turanszkij/WickedEngine)** - 3D engine with modern graphics
[Many other projects on GitHub](https://github.com/search?q=AMD_VULKAN_MEMORY_ALLOCATOR_H&type=Code) and some game development studios that use Vulkan in their games.
@@ -167,7 +182,8 @@ See **[Documentation](https://gpuopen-librariesandsdks.github.io/VulkanMemoryAll
- **[D3D12 Memory Allocator](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator)** - equivalent library for Direct3D 12. License: MIT.
- **[Awesome Vulkan](https://github.com/vinjn/awesome-vulkan)** - a curated list of awesome Vulkan libraries, debuggers and resources.
- **[VulkanMemoryAllocator-Hpp](https://github.com/malte-v/VulkanMemoryAllocator-Hpp)** - C++ binding for this library. License: CC0-1.0.
- **[vcpkg](https://github.com/Microsoft/vcpkg)** dependency manager from Microsoft also offers a port of this library.
- **[VulkanMemoryAllocator-Hpp](https://github.com/YaaZ/VulkanMemoryAllocator-Hpp)** - C++ binding for this library. License: CC0-1.0.
- **[PyVMA](https://github.com/realitix/pyvma)** - Python wrapper for this library. Author: Jean-Sébastien B. (@realitix). License: Apache 2.0.
- **[vk-mem](https://github.com/gwihlidal/vk-mem-rs)** - Rust binding for this library. Author: Graham Wihlidal. License: Apache 2.0 or MIT.
- **[Haskell bindings](https://hackage.haskell.org/package/VulkanMemoryAllocator)**, **[github](https://github.com/expipiplus1/vulkan/tree/master/VulkanMemoryAllocator)** - Haskell bindings for this library. Author: Ellie Hermaszewska (@expipiplus1). License BSD-3-Clause.
+19530 -19562
View File
File diff suppressed because it is too large Load Diff
+80 -88
View File
@@ -1,109 +1,101 @@
set(VMA_LIBRARY_SOURCE_FILES
#
# Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
option(VMA_STATIC_VULKAN_FUNCTIONS "Link statically with Vulkan API" ON)
option(VMA_DYNAMIC_VULKAN_FUNCTIONS "Fetch pointers to Vulkan functions internally (no static linking)" OFF)
set(VMA_VOLK_HEADER_PATH "" CACHE STRING "Path to volk.h file from the volk library (optional)")
option(VMA_DEBUG_ALWAYS_DEDICATED_MEMORY "Every allocation will have its own memory block" OFF)
option(VMA_DEBUG_INITIALIZE_ALLOCATIONS "Automatically fill new allocations and destroyed allocations with some bit pattern" OFF)
option(VMA_DEBUG_GLOBAL_MUTEX "Enable single mutex protecting all entry calls to the library" OFF)
option(VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT "Never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount and return error" OFF)
message(STATUS "VMA_STATIC_VULKAN_FUNCTIONS = ${VMA_STATIC_VULKAN_FUNCTIONS}")
message(STATUS "VMA_DYNAMIC_VULKAN_FUNCTIONS = ${VMA_DYNAMIC_VULKAN_FUNCTIONS}")
message(STATUS "VMA_DEBUG_ALWAYS_DEDICATED_MEMORY = ${VMA_DEBUG_ALWAYS_DEDICATED_MEMORY}")
message(STATUS "VMA_DEBUG_INITIALIZE_ALLOCATIONS = ${VMA_DEBUG_INITIALIZE_ALLOCATIONS}")
message(STATUS "VMA_DEBUG_GLOBAL_MUTEX = ${VMA_DEBUG_GLOBAL_MUTEX}")
message(STATUS "VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT = ${VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT}")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(Vulkan REQUIRED)
add_executable(VmaSample)
target_sources(VmaSample PRIVATE
Common.cpp
Common.h
SparseBindingTest.cpp
SparseBindingTest.h
Tests.cpp
Tests.h
VmaUsage.cpp
VmaUsage.h
"${PROJECT_SOURCE_DIR}/include/vk_mem_alloc.h"
VolkUsage.cpp
VulkanSample.cpp
../include/vk_mem_alloc.h
)
# Visual Studio only debugger symbols
if(WIN32 AND ${CMAKE_GENERATOR} MATCHES "Visual Studio.*")
set(VMA_LIBRARY_SOURCE_FILES ${VMA_LIBRARY_SOURCE_FILES} vk_mem_alloc.natvis)
# Only link to Vulkan library if volk loader is not used, but always add Vulkan headers directory.
if("${VMA_VOLK_HEADER_PATH}" STREQUAL "")
target_link_libraries(VmaSample PUBLIC Vulkan::Vulkan)
else()
target_link_libraries(VmaSample PUBLIC Vulkan::Headers)
endif()
set(CMAKE_DEBUG_POSTFIX d)
set(CMAKE_RELWITHDEBINFO_POSTFIX rd)
set(CMAKE_MINSIZEREL_POSTFIX s)
target_link_libraries(VmaSample PRIVATE GPUOpen::VulkanMemoryAllocator)
add_library(VulkanMemoryAllocator ${VMA_LIBRARY_SOURCE_FILES})
set_target_properties(
VulkanMemoryAllocator PROPERTIES
CXX_EXTENSIONS OFF
# Use C++14
CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
)
target_include_directories(VulkanMemoryAllocator PUBLIC "${PROJECT_SOURCE_DIR}/include")
# Only link to Vulkan if static linking is used
if(${VMA_STATIC_VULKAN_FUNCTIONS})
target_link_libraries(VulkanMemoryAllocator PUBLIC Vulkan::Vulkan)
endif()
target_compile_definitions(
VulkanMemoryAllocator
PUBLIC
target_compile_definitions(VmaSample PUBLIC
VMA_STATIC_VULKAN_FUNCTIONS=$<BOOL:${VMA_STATIC_VULKAN_FUNCTIONS}>
VMA_DYNAMIC_VULKAN_FUNCTIONS=$<BOOL:${VMA_DYNAMIC_VULKAN_FUNCTIONS}>
VMA_DEBUG_ALWAYS_DEDICATED_MEMORY=$<BOOL:${VMA_DEBUG_ALWAYS_DEDICATED_MEMORY}>
VMA_DEBUG_INITIALIZE_ALLOCATIONS=$<BOOL:${VMA_DEBUG_INITIALIZE_ALLOCATIONS}>
VMA_DEBUG_GLOBAL_MUTEX=$<BOOL:${VMA_DEBUG_GLOBAL_MUTEX}>
VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT=$<BOOL:${VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT}>
VMA_RECORDING_ENABLED=$<BOOL:${VMA_RECORDING_ENABLED}>
)
install(TARGETS VulkanMemoryAllocator DESTINATION "lib")
install(FILES "${PROJECT_SOURCE_DIR}/include/vk_mem_alloc.h" DESTINATION "include")
# Provides MSVC users nicer debugging support
target_sources(VmaSample PRIVATE vk_mem_alloc.natvis)
if(VMA_BUILD_SAMPLE)
if(WIN32)
set(VMA_SAMPLE_SOURCE_FILES
Common.cpp
Common.h
SparseBindingTest.cpp
SparseBindingTest.h
Tests.cpp
Tests.h
VulkanSample.cpp
)
add_subdirectory(Shaders)
add_dependencies(VmaSample VmaSampleShaders)
add_executable(VmaSample ${VMA_SAMPLE_SOURCE_FILES})
add_dependencies(VmaSample VulkanMemoryAllocator VmaSampleShaders)
# Visual Studio specific settings
if(${CMAKE_GENERATOR} MATCHES "Visual Studio.*")
# Use Unicode instead of multibyte set
add_compile_definitions(UNICODE _UNICODE)
# Set VmaSample as startup project
set_property(DIRECTORY "${PROJECT_SOURCE_DIR}" PROPERTY VS_STARTUP_PROJECT "VmaSample")
# Add C++ warnings and security checks
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /permissive- /sdl /W3")
# Enable multithreaded compiling
target_compile_options(VmaSample PRIVATE "/MP")
# Set working directory for Visual Studio debugger
set_target_properties(
VmaSample
PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/bin"
)
endif()
set_target_properties(
VmaSample PROPERTIES
CXX_EXTENSIONS OFF
# Use C++14
CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
)
target_link_libraries(
VmaSample
PRIVATE
VulkanMemoryAllocator
Vulkan::Vulkan
)
if(NOT "${VMA_VOLK_HEADER_PATH}" STREQUAL "")
if(EXISTS "${VMA_VOLK_HEADER_PATH}")
message(STATUS "File volk.h found and used from path: ${VMA_VOLK_HEADER_PATH}")
target_compile_definitions(VmaSample PRIVATE VMA_VOLK_HEADER_PATH="${VMA_VOLK_HEADER_PATH}")
else()
message(STATUS "VmaSample application is not supported to Linux")
message(FATAL_ERROR "File volk.h not found in path: ${VMA_VOLK_HEADER_PATH}")
endif()
endif()
if(VMA_BUILD_SAMPLE_SHADERS)
add_subdirectory(Shaders)
endif()
# Use Unicode instead of multibyte set
add_compile_definitions(UNICODE _UNICODE)
# Add C++ warnings and security checks
add_compile_options(/permissive- /sdl /W3)
# Set VmaSample as startup project
set_property(DIRECTORY "${PROJECT_SOURCE_DIR}" PROPERTY VS_STARTUP_PROJECT "VmaSample")
set_target_properties(VmaSample PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/bin")
+5 -5
View File
@@ -1,5 +1,5 @@
//
// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -68,9 +68,9 @@ void PrintMessage(CONSOLE_COLOR color, const char* msg)
{
if(color != CONSOLE_COLOR::NORMAL)
SetConsoleColor(color);
printf("%s\n", msg);
if (color != CONSOLE_COLOR::NORMAL)
SetConsoleColor(CONSOLE_COLOR::NORMAL);
}
@@ -79,9 +79,9 @@ void PrintMessage(CONSOLE_COLOR color, const wchar_t* msg)
{
if(color != CONSOLE_COLOR::NORMAL)
SetConsoleColor(color);
wprintf(L"%s\n", msg);
if (color != CONSOLE_COLOR::NORMAL)
SetConsoleColor(CONSOLE_COLOR::NORMAL);
}
+1 -1
View File
@@ -1,5 +1,5 @@
//
// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
+31 -1
View File
@@ -1,3 +1,25 @@
#
# Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# This file will only be executed if VMA_BUILD_SAMPLE_SHADERS is set to ON
find_program(GLSL_VALIDATOR glslangValidator REQUIRED)
@@ -17,16 +39,24 @@ foreach(SHADER ${SHADERS})
get_filename_component(FILE_NAME ${SHADER} NAME)
# Put the .spv files into the bin folder
set(SPIRV_BIN ${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.spv)
set(SPIRV ${PROJECT_SOURCE_DIR}/bin/${FILE_NAME}.spv)
add_custom_command(
OUTPUT ${SPIRV}
# Use the same file name and append .spv to the compiled shader
COMMAND ${GLSL_VALIDATOR} -V ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER} -o ${SPIRV}
DEPENDS ${SHADER}
)
add_custom_command(
OUTPUT ${SPIRV_BIN}
# Use the same file name and append .spv to the compiled shader
COMMAND ${GLSL_VALIDATOR} -V ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER} -o ${SPIRV_BIN}
DEPENDS ${SHADER}
)
list(APPEND SPIRV_FILES ${SPIRV})
list(APPEND SPIRV_FILES ${SPIRV} ${SPIRV_BIN})
endforeach()
add_custom_target(VmaSampleShaders ALL DEPENDS ${SPIRV_FILES})
+1 -1
View File
@@ -1,5 +1,5 @@
//
// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,5 +1,5 @@
//
// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,5 +1,5 @@
//
// Copyright (c) 2018-2022 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2018-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
+5 -14
View File
@@ -1,5 +1,5 @@
//
// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -153,7 +153,7 @@ void BaseImage::UploadContent()
VmaAllocation srcBufAlloc = nullptr;
VmaAllocationInfo srcAllocInfo = {};
TEST( vmaCreateBuffer(g_hAllocator, &srcBufCreateInfo, &srcBufAllocCreateInfo, &srcBuf, &srcBufAlloc, &srcAllocInfo) == VK_SUCCESS );
// Fill texels with: r = x % 255, g = u % 255, b = 13, a = 25
uint32_t* srcBufPtr = (uint32_t*)srcAllocInfo.pMappedData;
for(uint32_t y = 0, sizeY = m_CreateInfo.extent.height; y < sizeY; ++y)
@@ -211,7 +211,7 @@ void BaseImage::UploadContent()
vkCmdCopyBufferToImage(g_hTemporaryCommandBuffer, srcBuf, m_Image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
}
// Barrier transfer dst to fragment shader read only.
{
VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
@@ -441,7 +441,7 @@ void TraditionalImage::Init(RandomNumberGenerator& rand)
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
// Default BEST_FIT is clearly better.
//allocCreateInfo.flags |= VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT;
ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &m_CreateInfo, &allocCreateInfo,
&m_Image, &m_Allocation, nullptr) );
}
@@ -470,15 +470,6 @@ void SparseBindingImage::Init(RandomNumberGenerator& rand)
VkMemoryRequirements imageMemReq;
vkGetImageMemoryRequirements(g_hDevice, m_Image, &imageMemReq);
// This is just to silence validation layer warning.
// But it doesn't help. Looks like a bug in Vulkan validation layers.
// See: https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/364
uint32_t sparseMemReqCount = 0;
vkGetImageSparseMemoryRequirements(g_hDevice, m_Image, &sparseMemReqCount, nullptr);
TEST(sparseMemReqCount <= 8);
VkSparseImageMemoryRequirements sparseMemReq[8];
vkGetImageSparseMemoryRequirements(g_hDevice, m_Image, &sparseMemReqCount, sparseMemReq);
// According to Vulkan specification, for sparse resources memReq.alignment is also page size.
const VkDeviceSize pageSize = imageMemReq.alignment;
const uint32_t pageCount = (uint32_t)ceil_div<VkDeviceSize>(imageMemReq.size, pageSize);
@@ -513,7 +504,7 @@ void SparseBindingImage::Init(RandomNumberGenerator& rand)
VkBindSparseInfo bindSparseInfo = { VK_STRUCTURE_TYPE_BIND_SPARSE_INFO };
bindSparseInfo.pImageOpaqueBinds = &imageBindInfo;
bindSparseInfo.imageOpaqueBindCount = 1;
ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &g_ImmediateFence) );
ERR_GUARD_VULKAN( vkQueueBindSparse(g_hSparseBindingQueue, 1, &bindSparseInfo, g_ImmediateFence) );
ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &g_ImmediateFence, VK_TRUE, UINT64_MAX) );
+1 -1
View File
@@ -1,5 +1,5 @@
//
// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
+874 -294
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,5 +1,5 @@
//
// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -1,5 +1,5 @@
//
// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
+23 -5
View File
@@ -1,5 +1,5 @@
//
// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -25,9 +25,15 @@
#ifdef _WIN32
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#if !defined(NOMINMAX)
#define NOMINMAX
#endif
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#if !defined(VK_USE_PLATFORM_WIN32_KHR)
#define VK_USE_PLATFORM_WIN32_KHR
#endif // #if !defined(VK_USE_PLATFORM_WIN32_KHR)
@@ -58,6 +64,7 @@ include all public interface declarations. Example:
//#define VMA_MEMORY_BUDGET 0
//#define VMA_STATS_STRING_ENABLED 0
//#define VMA_MAPPING_HYSTERESIS_ENABLED 0
//#define VMA_KHR_MAINTENANCE5 0
//#define VMA_VULKAN_VERSION 1003000 // Vulkan 1.3
//#define VMA_VULKAN_VERSION 1002000 // Vulkan 1.2
@@ -76,6 +83,7 @@ include all public interface declarations. Example:
#pragma warning(disable: 4100) // unreferenced formal parameter
#pragma warning(disable: 4189) // local variable is initialized but not referenced
#pragma warning(disable: 4324) // structure was padded due to alignment specifier
#pragma warning(disable: 4820) // 'X': 'N' bytes padding added after data member 'X'
#endif // #ifdef _MSVC_LANG
@@ -88,7 +96,17 @@ include all public interface declarations. Example:
#pragma clang diagnostic ignored "-Wnullability-completeness"
#endif
#include "../include/vk_mem_alloc.h"
#ifdef VMA_VOLK_HEADER_PATH
#include VMA_VOLK_HEADER_PATH
#else
#include <vulkan/vulkan.h>
#endif
#ifdef _WIN32
#include <vulkan/vulkan_win32.h>
#endif // #ifdef _WIN32
#include "vk_mem_alloc.h"
#ifdef __clang__
#pragma clang diagnostic pop
+28
View File
@@ -0,0 +1,28 @@
//
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#ifdef VMA_VOLK_HEADER_PATH
#define VOLK_IMPLEMENTATION
#include "VmaUsage.h"
#endif // #ifdef VMA_VOLK_HEADER_PATH
+197 -95
View File
@@ -1,5 +1,5 @@
//
// Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -28,15 +28,16 @@
#include "Common.h"
#include <atomic>
#include <Shlwapi.h>
#include <unordered_set>
#pragma comment(lib, "shlwapi.lib")
static const char* const SHADER_PATH1 = "./";
static const char* const SHADER_PATH1 = "./Shaders/";
static const char* const SHADER_PATH2 = "../bin/";
static const wchar_t* const WINDOW_CLASS_NAME = L"VULKAN_MEMORY_ALLOCATOR_SAMPLE";
static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation";
static const char* const APP_TITLE_A = "Vulkan Memory Allocator Sample 3.0.1";
static const wchar_t* const APP_TITLE_W = L"Vulkan Memory Allocator Sample 3.0.1";
static const char* const APP_TITLE_A = "Vulkan Memory Allocator Sample 3.3.0";
static const wchar_t* const APP_TITLE_W = L"Vulkan Memory Allocator Sample 3.3.0";
static const bool VSYNC = true;
static const uint32_t COMMAND_BUFFER_COUNT = 2;
@@ -67,6 +68,8 @@ bool VK_AMD_device_coherent_memory_enabled = false;
bool VK_KHR_buffer_device_address_enabled = false;
bool VK_EXT_memory_priority_enabled = false;
bool VK_EXT_debug_utils_enabled = false;
bool VK_KHR_maintenance5_enabled = false;
bool VK_KHR_external_memory_win32_enabled = false;
bool g_SparseBindingEnabled = false;
// # Pointers to functions from extensions
@@ -85,11 +88,14 @@ static std::vector<VkImageView> g_SwapchainImageViews;
static std::vector<VkFramebuffer> g_Framebuffers;
static VkCommandPool g_hCommandPool;
static VkCommandBuffer g_MainCommandBuffers[COMMAND_BUFFER_COUNT];
static VkFence g_MainCommandBufferExecutedFances[COMMAND_BUFFER_COUNT];
static VkFence g_MainCommandBufferExecutedFences[COMMAND_BUFFER_COUNT];
VkFence g_ImmediateFence;
static uint32_t g_NextCommandBufferIndex;
static VkSemaphore g_hImageAvailableSemaphore;
static VkSemaphore g_hRenderFinishedSemaphore;
// Notice we need as many semaphores as there are swapchain images
static std::vector<VkSemaphore> g_hImageAvailableSemaphores;
static std::vector<VkSemaphore> g_hRenderFinishedSemaphores;
static uint32_t g_SwapchainImageCount = 0;
static uint32_t g_SwapchainImageIndex = 0;
static uint32_t g_GraphicsQueueFamilyIndex = UINT_MAX;
static uint32_t g_PresentQueueFamilyIndex = UINT_MAX;
static uint32_t g_SparseBindingQueueFamilyIndex = UINT_MAX;
@@ -257,16 +263,16 @@ struct CommandLineParameters
}
} g_CommandLineParameters;
void SetDebugUtilsObjectName(VkObjectType type, uint64_t handle, const char* name)
void SetDebugUtilsObjectName(VkObjectType type, uint64_t handle, const std::string &name)
{
if(vkSetDebugUtilsObjectNameEXT_Func == nullptr)
if (vkSetDebugUtilsObjectNameEXT_Func == nullptr)
return;
VkDebugUtilsObjectNameInfoEXT info = { VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT };
info.objectType = type;
info.objectHandle = handle;
info.pObjectName = name;
vkSetDebugUtilsObjectNameEXT_Func(g_hDevice, &info);
info.pObjectName = name.c_str();
ERR_GUARD_VULKAN( vkSetDebugUtilsObjectNameEXT_Func(g_hDevice, &info) );
}
void BeginSingleTimeCommands()
@@ -280,6 +286,8 @@ void EndSingleTimeCommands()
{
ERR_GUARD_VULKAN( vkEndCommandBuffer(g_hTemporaryCommandBuffer) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_COMMAND_BUFFER, reinterpret_cast<std::uint64_t>(g_hTemporaryCommandBuffer), "g_hTemporaryCommandBuffer");
VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &g_hTemporaryCommandBuffer;
@@ -352,7 +360,7 @@ static VkSurfaceFormatKHR ChooseSurfaceFormat()
VkSurfaceFormatKHR result = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
return result;
}
for(const auto& format : g_SurfaceFormats)
{
if((format.format == VK_FORMAT_B8G8R8A8_UNORM) &&
@@ -368,7 +376,7 @@ static VkSurfaceFormatKHR ChooseSurfaceFormat()
VkPresentModeKHR ChooseSwapPresentMode()
{
VkPresentModeKHR preferredMode = VSYNC ? VK_PRESENT_MODE_MAILBOX_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR;
if(std::find(g_PresentModes.begin(), g_PresentModes.end(), preferredMode) !=
g_PresentModes.end())
{
@@ -393,7 +401,9 @@ static VkExtent2D ChooseSwapExtent()
static constexpr uint32_t GetVulkanApiVersion()
{
#if VMA_VULKAN_VERSION == 1003000
#if VMA_VULKAN_VERSION == 1004000
return VK_API_VERSION_1_4;
#elif VMA_VULKAN_VERSION == 1003000
return VK_API_VERSION_1_3;
#elif VMA_VULKAN_VERSION == 1002000
return VK_API_VERSION_1_2;
@@ -416,6 +426,10 @@ void VulkanUsage::Init()
g_Allocs = &g_CpuAllocationCallbacks;
}
#ifdef VOLK_HEADER_VERSION
ERR_GUARD_VULKAN(volkInitialize());
#endif
uint32_t instanceLayerPropCount = 0;
ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
@@ -456,7 +470,7 @@ void VulkanUsage::Init()
if(strcmp(extensionProperties.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
{
if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
{
{
enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
VK_KHR_get_physical_device_properties2_enabled = true;
}
@@ -494,12 +508,19 @@ void VulkanUsage::Init()
#endif
#ifdef VK_VERSION_1_3
case VK_API_VERSION_1_3: wprintf(L"1.3\n"); break;
#endif
#ifdef VK_VERSION_1_4
case VK_API_VERSION_1_4: wprintf(L"1.4\n"); break;
#endif
default: assert(0);
}
ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
#ifdef VOLK_HEADER_VERSION
volkLoadInstance(g_hVulkanInstance);
#endif
if(VK_EXT_debug_utils_enabled)
{
RegisterDebugCallbacks();
@@ -696,6 +717,7 @@ static void CreateMesh()
vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
vbAllocCreateInfo.flags = 0;
ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &g_hVertexBuffer, &g_hVertexBufferAlloc, nullptr) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_BUFFER, reinterpret_cast<std::uint64_t>(g_hVertexBuffer), "g_hVertexBuffer");
// Create index buffer
@@ -703,11 +725,11 @@ static void CreateMesh()
ibInfo.size = indexBufferSize;
ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
ibInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo ibAllocCreateInfo = {};
ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;
VkBuffer stagingIndexBuffer = VK_NULL_HANDLE;
VmaAllocation stagingIndexBufferAlloc = VK_NULL_HANDLE;
VmaAllocationInfo stagingIndexBufferAllocInfo = {};
@@ -720,6 +742,7 @@ static void CreateMesh()
ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
ibAllocCreateInfo.flags = 0;
ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &g_hIndexBuffer, &g_hIndexBufferAlloc, nullptr) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_BUFFER, reinterpret_cast<std::uint64_t>(g_hIndexBuffer), "g_hIndexBuffer");
// Copy buffers
@@ -756,7 +779,7 @@ static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
VmaAllocationCreateInfo stagingBufAllocCreateInfo = {};
stagingBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
stagingBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;
VkBuffer stagingBuf = VK_NULL_HANDLE;
VmaAllocation stagingBufAlloc = VK_NULL_HANDLE;
VmaAllocationInfo stagingBufAllocInfo = {};
@@ -767,7 +790,7 @@ static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
for(uint32_t y = 0; y < sizeY; ++y)
{
uint32_t* pPixelData = (uint32_t*)pRowData;
for(uint32_t x = 0; x < sizeY; ++x)
for(uint32_t x = 0; x < sizeX; ++x)
{
*pPixelData =
((x & 0x18) == 0x08 ? 0x000000FF : 0x00000000) |
@@ -800,8 +823,12 @@ static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
VmaAllocationCreateInfo imageAllocCreateInfo = {};
imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageInfo, &imageAllocCreateInfo, &g_hTextureImage, &g_hTextureImageAlloc, nullptr) );
VmaAllocationInfo textureImageAllocInfo = {};
ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageInfo, &imageAllocCreateInfo, &g_hTextureImage, &g_hTextureImageAlloc, &textureImageAllocInfo) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_IMAGE, reinterpret_cast<std::uint64_t>(g_hTextureImage), "g_hTextureImage");
SetDebugUtilsObjectName(VK_OBJECT_TYPE_DEVICE_MEMORY, reinterpret_cast<std::uint64_t>(textureImageAllocInfo.deviceMemory), "textureImageAllocInfo.deviceMemory");
// Transition image layouts, copy image.
@@ -870,6 +897,7 @@ static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
textureImageViewInfo.subresourceRange.baseArrayLayer = 0;
textureImageViewInfo.subresourceRange.layerCount = 1;
ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &textureImageViewInfo, g_Allocs, &g_hTextureImageView) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_IMAGE_VIEW, reinterpret_cast<std::uint64_t>(g_hTextureImageView), "g_hTextureImageView");
}
struct UniformBufferObject
@@ -886,7 +914,7 @@ static VkFormat FindSupportedFormat(
{
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(g_hPhysicalDevice, format, &props);
if ((tiling == VK_IMAGE_TILING_LINEAR) &&
((props.linearTilingFeatures & features) == features))
{
@@ -919,7 +947,7 @@ static void CreateSwapchain()
// Query surface formats.
ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_hPhysicalDevice, g_hSurface, &g_SurfaceCapabilities) );
uint32_t formatCount = 0;
ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, nullptr) );
g_SurfaceFormats.resize(formatCount);
@@ -936,16 +964,16 @@ static void CreateSwapchain()
VkPresentModeKHR presentMode = ChooseSwapPresentMode();
g_Extent = ChooseSwapExtent();
uint32_t imageCount = g_SurfaceCapabilities.minImageCount + 1;
g_SwapchainImageCount = g_SurfaceCapabilities.minImageCount + 1;
if((g_SurfaceCapabilities.maxImageCount > 0) &&
(imageCount > g_SurfaceCapabilities.maxImageCount))
(g_SwapchainImageCount > g_SurfaceCapabilities.maxImageCount))
{
imageCount = g_SurfaceCapabilities.maxImageCount;
g_SwapchainImageCount = g_SurfaceCapabilities.maxImageCount;
}
VkSwapchainCreateInfoKHR swapChainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
swapChainInfo.surface = g_hSurface;
swapChainInfo.minImageCount = imageCount;
swapChainInfo.minImageCount = g_SwapchainImageCount;
swapChainInfo.imageFormat = g_SurfaceFormat.format;
swapChainInfo.imageColorSpace = g_SurfaceFormat.colorSpace;
swapChainInfo.imageExtent = g_Extent;
@@ -975,6 +1003,8 @@ static void CreateSwapchain()
vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
g_hSwapchain = hNewSwapchain;
SetDebugUtilsObjectName(VK_OBJECT_TYPE_SWAPCHAIN_KHR, reinterpret_cast<std::uint64_t>(g_hSwapchain), "g_hSwapchain");
// Retrieve swapchain images.
uint32_t swapchainImageCount = 0;
@@ -982,6 +1012,11 @@ static void CreateSwapchain()
g_SwapchainImages.resize(swapchainImageCount);
ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, g_SwapchainImages.data()) );
for (size_t i = 0; i < swapchainImageCount; i++) {
std::string swapchainImgName = "g_SwapchainImages[" + std::to_string(i) + "]";
SetDebugUtilsObjectName(VK_OBJECT_TYPE_IMAGE, reinterpret_cast<std::uint64_t>(g_SwapchainImages[i]), swapchainImgName);
}
// Create swapchain image views.
for(size_t i = g_SwapchainImageViews.size(); i--; )
@@ -1005,6 +1040,8 @@ static void CreateSwapchain()
swapchainImageViewInfo.subresourceRange.baseArrayLayer = 0;
swapchainImageViewInfo.subresourceRange.layerCount = 1;
ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &swapchainImageViewInfo, g_Allocs, &g_SwapchainImageViews[i]) );
std::string imgViewName = "g_SwapchainImageViews["+ std::to_string(i) + "]";
SetDebugUtilsObjectName(VK_OBJECT_TYPE_IMAGE_VIEW, reinterpret_cast<std::uint64_t>(g_SwapchainImageViews[i]), imgViewName);
}
// Create depth buffer
@@ -1030,7 +1067,11 @@ static void CreateSwapchain()
VmaAllocationCreateInfo depthImageAllocCreateInfo = {};
depthImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &depthImageInfo, &depthImageAllocCreateInfo, &g_hDepthImage, &g_hDepthImageAlloc, nullptr) );
VmaAllocationInfo depthImageAllocInfo = {};
ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &depthImageInfo, &depthImageAllocCreateInfo, &g_hDepthImage, &g_hDepthImageAlloc, &depthImageAllocInfo) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_IMAGE, reinterpret_cast<std::uint64_t>(g_hDepthImage), "g_hDepthImage");
SetDebugUtilsObjectName(VK_OBJECT_TYPE_DEVICE_MEMORY, reinterpret_cast<std::uint64_t>(depthImageAllocInfo.deviceMemory), "depthImageAllocInfo.deviceMemory");
VkImageViewCreateInfo depthImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
depthImageViewInfo.image = g_hDepthImage;
@@ -1043,6 +1084,7 @@ static void CreateSwapchain()
depthImageViewInfo.subresourceRange.layerCount = 1;
ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &depthImageViewInfo, g_Allocs, &g_hDepthImageView) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_IMAGE_VIEW, reinterpret_cast<std::uint64_t>(g_hDepthImageView), "g_hDepthImageView");
// Create pipeline layout
{
@@ -1065,6 +1107,7 @@ static void CreateSwapchain()
pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges;
ERR_GUARD_VULKAN( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutInfo, g_Allocs, &g_hPipelineLayout) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_PIPELINE_LAYOUT, reinterpret_cast<std::uint64_t>(g_hPipelineLayout), "g_hPipelineLayout");
}
// Create render pass
@@ -1099,11 +1142,11 @@ static void CreateSwapchain()
VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference depthStencilAttachmentRef = {};
depthStencilAttachmentRef.attachment = 1;
depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpassDesc = {};
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc.colorAttachmentCount = 1;
@@ -1117,6 +1160,7 @@ static void CreateSwapchain()
renderPassInfo.pSubpasses = &subpassDesc;
renderPassInfo.dependencyCount = 0;
ERR_GUARD_VULKAN( vkCreateRenderPass(g_hDevice, &renderPassInfo, g_Allocs, &g_hRenderPass) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_RENDER_PASS, reinterpret_cast<std::uint64_t>(g_hRenderPass), "g_hRenderPass");
}
// Create pipeline
@@ -1128,6 +1172,7 @@ static void CreateSwapchain()
shaderModuleInfo.pCode = (const uint32_t*)vertShaderCode.data();
VkShaderModule hVertShaderModule = VK_NULL_HANDLE;
ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &hVertShaderModule) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_SHADER_MODULE, reinterpret_cast<std::uint64_t>(hVertShaderModule), "hVertShaderModule");
std::vector<char> hFragShaderCode;
LoadShader(hFragShaderCode, "Shader.frag.spv");
@@ -1135,6 +1180,7 @@ static void CreateSwapchain()
shaderModuleInfo.pCode = (const uint32_t*)hFragShaderCode.data();
VkShaderModule fragShaderModule = VK_NULL_HANDLE;
ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &fragShaderModule) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_SHADER_MODULE, reinterpret_cast<std::uint64_t>(fragShaderModule), "fragShaderModule");
VkPipelineShaderStageCreateInfo vertPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
vertPipelineShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
@@ -1163,7 +1209,7 @@ static void CreateSwapchain()
attributeDescriptions[0].location = 0;
attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[0].offset = offsetof(Vertex, pos);
attributeDescriptions[1].binding = 0;
attributeDescriptions[1].location = 1;
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
@@ -1274,6 +1320,8 @@ static void CreateSwapchain()
g_Allocs,
&g_hPipeline) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_PIPELINE, reinterpret_cast<std::uint64_t>(g_hPipeline), "g_hPipeline");
vkDestroyShaderModule(g_hDevice, fragShaderModule, g_Allocs);
vkDestroyShaderModule(g_hDevice, hVertShaderModule, g_Allocs);
}
@@ -1297,37 +1345,54 @@ static void CreateSwapchain()
framebufferInfo.height = g_Extent.height;
framebufferInfo.layers = 1;
ERR_GUARD_VULKAN( vkCreateFramebuffer(g_hDevice, &framebufferInfo, g_Allocs, &g_Framebuffers[i]) );
std::string framebufName = "g_Framebuffers["+ std::to_string(i) + "]";
SetDebugUtilsObjectName(VK_OBJECT_TYPE_FRAMEBUFFER, reinterpret_cast<std::uint64_t>(g_Framebuffers[i]), framebufName);
}
// Create semaphores
// Destroy the old semaphores and create new ones
if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
{
vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
g_hImageAvailableSemaphore = VK_NULL_HANDLE;
if (g_hImageAvailableSemaphores.size() < g_SwapchainImageCount) {
g_hImageAvailableSemaphores.resize(g_SwapchainImageCount);
}
if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
{
vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
if (g_hRenderFinishedSemaphores.size() < g_SwapchainImageCount) {
g_hRenderFinishedSemaphores.resize(g_SwapchainImageCount);
}
VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hImageAvailableSemaphore) );
ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hRenderFinishedSemaphore) );
for (std::size_t swapchain_img_index = 0; swapchain_img_index < g_SwapchainImageCount; swapchain_img_index++) {
if (g_hImageAvailableSemaphores.at(swapchain_img_index) != VK_NULL_HANDLE) {
vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphores[swapchain_img_index], g_Allocs);
g_hImageAvailableSemaphores[swapchain_img_index] = VK_NULL_HANDLE;
}
if (g_hRenderFinishedSemaphores.at(swapchain_img_index) != VK_NULL_HANDLE) {
vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphores[swapchain_img_index], g_Allocs);
g_hRenderFinishedSemaphores[swapchain_img_index] = VK_NULL_HANDLE;
}
}
for (std::size_t swapchain_img_index = 0; swapchain_img_index < g_SwapchainImageCount; swapchain_img_index++) {
ERR_GUARD_VULKAN(vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hImageAvailableSemaphores[swapchain_img_index]));
std::string semaphoreName = "g_hImageAvailableSemaphores[" + std::to_string(swapchain_img_index) + "]";
SetDebugUtilsObjectName(VK_OBJECT_TYPE_SEMAPHORE, reinterpret_cast<std::uint64_t>(g_hImageAvailableSemaphores[swapchain_img_index]), semaphoreName);
ERR_GUARD_VULKAN(vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hRenderFinishedSemaphores[swapchain_img_index]));
semaphoreName = "g_hRenderFinishedSemaphores[" + std::to_string(swapchain_img_index) + "]";
SetDebugUtilsObjectName(VK_OBJECT_TYPE_SEMAPHORE, reinterpret_cast<std::uint64_t>(g_hRenderFinishedSemaphores[swapchain_img_index]), semaphoreName);
}
}
static void DestroySwapchain(bool destroyActualSwapchain)
{
if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
{
vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
g_hImageAvailableSemaphore = VK_NULL_HANDLE;
}
if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
{
vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
for (std::size_t swapchain_img_index = 0; swapchain_img_index < g_SwapchainImageCount; swapchain_img_index++) {
if (g_hImageAvailableSemaphores.at(swapchain_img_index) != VK_NULL_HANDLE) {
vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphores[swapchain_img_index], g_Allocs);
g_hImageAvailableSemaphores[swapchain_img_index] = VK_NULL_HANDLE;
}
if (g_hRenderFinishedSemaphores.at(swapchain_img_index) != VK_NULL_HANDLE) {
vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphores[swapchain_img_index], g_Allocs);
g_hRenderFinishedSemaphores[swapchain_img_index] = VK_NULL_HANDLE;
}
}
for(size_t i = g_Framebuffers.size(); i--; )
@@ -1362,7 +1427,7 @@ static void DestroySwapchain(bool destroyActualSwapchain)
vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
g_hPipelineLayout = VK_NULL_HANDLE;
}
for(size_t i = g_SwapchainImageViews.size(); i--; )
vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
g_SwapchainImageViews.clear();
@@ -1396,7 +1461,9 @@ static void PrintEnabledFeatures()
{
wprintf(L"bufferDeviceAddress: %d\n", VK_KHR_buffer_device_address_enabled ? 1 : 0);
}
wprintf(L"VK_EXT_memory_priority: %d\n", VK_EXT_memory_priority ? 1 : 0);
wprintf(L"VK_EXT_memory_priority: %d\n", VK_EXT_memory_priority_enabled ? 1 : 0);
wprintf(L"VK_KHR_maintenance5: %d\n", VK_KHR_maintenance5_enabled? 1 : 0);
wprintf(L"VK_KHR_external_memory_win32: %d\n", VK_KHR_external_memory_win32_enabled ? 1 : 0);
}
void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo)
@@ -1437,25 +1504,33 @@ void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo)
outInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT;
}
#endif
if(VK_KHR_maintenance5_enabled)
{
outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT;
}
if(VK_KHR_external_memory_win32_enabled)
{
outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT;
}
if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
{
outInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
}
#ifdef VOLK_HEADER_VERSION
static VmaVulkanFunctions vulkanFunctions = {};
vmaImportVulkanFunctionsFromVolk(&outInfo, &vulkanFunctions);
outInfo.pVulkanFunctions = &vulkanFunctions;
#endif // #ifdef VOLK_HEADER_VERSION
#if VMA_DYNAMIC_VULKAN_FUNCTIONS
static VmaVulkanFunctions vulkanFunctions = {};
vulkanFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
vulkanFunctions.vkGetDeviceProcAddr = vkGetDeviceProcAddr;
outInfo.pVulkanFunctions = &vulkanFunctions;
#endif
// Uncomment to enable recording to CSV file.
/*
static VmaRecordSettings recordSettings = {};
recordSettings.pFilePath = "VulkanSample.csv";
outInfo.pRecordSettings = &recordSettings;
*/
#endif // #if VMA_DYNAMIC_VULKAN_FUNCTIONS
// Uncomment to enable HeapSizeLimit.
/*
@@ -1558,7 +1633,7 @@ static void PrintMemoryTypes()
sizeStr = SizeToStr(heap.size);
flagsStr = HeapFlagsToStr(heap.flags);
wprintf(L"Heap %u: %llu B (%s) %s\n", heapIndex, heap.size, sizeStr.c_str(), flagsStr.c_str());
for(uint32_t typeIndex = 0; typeIndex < memProps->memoryTypeCount; ++typeIndex)
{
const VkMemoryType& type = memProps->memoryTypes[typeIndex];
@@ -1571,17 +1646,6 @@ static void PrintMemoryTypes()
}
}
#if 0
template<typename It, typename MapFunc>
inline VkDeviceSize MapSum(It beg, It end, MapFunc mapFunc)
{
VkDeviceSize result = 0;
for(It it = beg; it != end; ++it)
result += mapFunc(*it);
return result;
}
#endif
static bool CanCreateVertexBuffer(uint32_t allowedMemoryTypeBits)
{
VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
@@ -1762,7 +1826,7 @@ static void PrintMemoryConclusions()
if(deviceLocalHeapCount < heapCount)
{
const uint32_t nonDeviceLocalTypeBits = ~deviceLocalTypeBits & allTypeBits;
if(CanCreateVertexBuffer(nonDeviceLocalTypeBits))
wprintf(L"- A buffer with VERTEX_BUFFER usage can be created in some non-DEVICE_LOCAL type.\n");
else
@@ -1836,6 +1900,10 @@ static void InitializeApplication()
}
else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME) == 0)
VK_EXT_memory_priority_enabled = true;
else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_MAINTENANCE_5_EXTENSION_NAME) == 0)
VK_KHR_maintenance5_enabled = true;
else if (strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME) == 0)
VK_KHR_external_memory_win32_enabled = VMA_DYNAMIC_VULKAN_FUNCTIONS;
}
if(GetVulkanApiVersion() >= VK_API_VERSION_1_2)
@@ -1845,7 +1913,7 @@ static void InitializeApplication()
#if VMA_VULKAN_VERSION >= 1001000
VkPhysicalDeviceProperties2 physicalDeviceProperties2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
#if VMA_VULKAN_VERSION >= 1002000
// Vulkan spec says structure VkPhysicalDeviceVulkan11Properties is "Provided by VK_VERSION_1_2" - is this a mistake? Assuming not...
VkPhysicalDeviceVulkan11Properties physicalDeviceVulkan11Properties = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES };
@@ -1872,13 +1940,13 @@ static void InitializeApplication()
wprintf(L"\n");
VkPhysicalDeviceFeatures2 physicalDeviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
VkPhysicalDeviceCoherentMemoryFeaturesAMD physicalDeviceCoherentMemoryFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD };
if(VK_AMD_device_coherent_memory_enabled)
{
PnextChainPushFront(&physicalDeviceFeatures, &physicalDeviceCoherentMemoryFeatures);
}
VkPhysicalDeviceBufferDeviceAddressFeaturesKHR physicalDeviceBufferDeviceAddressFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR };
if(VK_KHR_buffer_device_address_enabled)
{
@@ -1955,7 +2023,7 @@ static void InitializeApplication()
queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
queueCreateInfo[0].queueCount = 1;
queueCreateInfo[0].pQueuePriorities = &queuePriority;
if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
{
@@ -1965,7 +2033,7 @@ static void InitializeApplication()
queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
++queueCount;
}
if(g_SparseBindingEnabled &&
g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
@@ -1994,6 +2062,10 @@ static void InitializeApplication()
enabledDeviceExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
if(VK_EXT_memory_priority_enabled)
enabledDeviceExtensions.push_back(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME);
if(VK_KHR_maintenance5_enabled)
enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
if (VK_KHR_external_memory_win32_enabled)
enabledDeviceExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
VkPhysicalDeviceFeatures2 deviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
deviceFeatures.features.samplerAnisotropy = VK_TRUE;
@@ -2026,6 +2098,15 @@ static void InitializeApplication()
ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );
#ifdef VOLK_HEADER_VERSION
volkLoadDevice(g_hDevice);
#endif
SetDebugUtilsObjectName(VK_OBJECT_TYPE_DEVICE, reinterpret_cast<std::uint64_t>(g_hDevice), "g_hDevice");
// Only now that SetDebugUtilsObjectName is loaded, we can assign a name to g_hVulkanInstance as well
SetDebugUtilsObjectName(VK_OBJECT_TYPE_INSTANCE, reinterpret_cast<std::uint64_t>(g_hVulkanInstance), "g_hVulkanInstance");
SetDebugUtilsObjectName(VK_OBJECT_TYPE_PHYSICAL_DEVICE, reinterpret_cast<std::uint64_t>(g_hPhysicalDevice), "g_hPhysicalDevice");
// Fetch pointers to extension functions
if(VK_KHR_buffer_device_address_enabled)
{
@@ -2059,6 +2140,8 @@ static void InitializeApplication()
vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
assert(g_hGraphicsQueue);
assert(g_hPresentQueue);
SetDebugUtilsObjectName(VK_OBJECT_TYPE_QUEUE, reinterpret_cast<std::uint64_t>(g_hGraphicsQueue), "g_hGraphicsQueue");
SetDebugUtilsObjectName(VK_OBJECT_TYPE_QUEUE, reinterpret_cast<std::uint64_t>(g_hPresentQueue), "g_hPresentQueue");
if(g_SparseBindingEnabled)
{
@@ -2072,24 +2155,33 @@ static void InitializeApplication()
commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_COMMAND_POOL, reinterpret_cast<std::uint64_t>(g_hCommandPool), "g_hCommandPool");
VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
commandBufferInfo.commandPool = g_hCommandPool;
commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
for (size_t i = 0; i < COMMAND_BUFFER_COUNT; i++) {
std::string cmdBufName = "g_MainCommandBuffers[" + std::to_string(i) + "]";
SetDebugUtilsObjectName(VK_OBJECT_TYPE_COMMAND_BUFFER, reinterpret_cast<std::uint64_t>(g_MainCommandBuffers[i]), cmdBufName);
}
VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
{
ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFences[i]) );
std::string fenceName = "g_MainCommandBufferExecutedFences[" + std::to_string(i) + "]";
SetDebugUtilsObjectName(VK_OBJECT_TYPE_FENCE, reinterpret_cast<std::uint64_t>(g_MainCommandBufferExecutedFences[i]), fenceName);
}
ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_FENCE, reinterpret_cast<std::uint64_t>(g_ImmediateFence), "g_ImmediateFence");
commandBufferInfo.commandBufferCount = 1;
ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_COMMAND_BUFFER, reinterpret_cast<std::uint64_t>(g_hTemporaryCommandBuffer), "g_hTemporaryCommandBuffer");
// Create texture sampler
@@ -2110,6 +2202,7 @@ static void InitializeApplication()
samplerInfo.minLod = 0.f;
samplerInfo.maxLod = FLT_MAX;
ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_SAMPLER, reinterpret_cast<std::uint64_t>(g_hSampler), "g_hSampler");
CreateTexture(128, 128);
CreateMesh();
@@ -2124,6 +2217,7 @@ static void InitializeApplication()
descriptorSetLayoutInfo.bindingCount = 1;
descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, reinterpret_cast<std::uint64_t>(g_hDescriptorSetLayout), "g_hDescriptorSetLayout");
// Create descriptor pool
@@ -2139,6 +2233,7 @@ static void InitializeApplication()
descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
descriptorPoolInfo.maxSets = 1;
ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_DESCRIPTOR_POOL, reinterpret_cast<std::uint64_t>(g_hDescriptorPool), "g_hDescriptorPool");
// Create descriptor set layout
@@ -2148,6 +2243,7 @@ static void InitializeApplication()
descriptorSetInfo.descriptorSetCount = 1;
descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_DESCRIPTOR_SET, reinterpret_cast<std::uint64_t>(g_hDescriptorSet), "g_hDescriptorSet");
VkDescriptorImageInfo descriptorImageInfo = {};
descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -2206,7 +2302,7 @@ static void FinalizeApplication()
vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
g_hVertexBuffer = VK_NULL_HANDLE;
}
if(g_hSampler != VK_NULL_HANDLE)
{
vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
@@ -2221,10 +2317,10 @@ static void FinalizeApplication()
for(size_t i = COMMAND_BUFFER_COUNT; i--; )
{
if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
if(g_MainCommandBufferExecutedFences[i] != VK_NULL_HANDLE)
{
vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFences[i], g_Allocs);
g_MainCommandBufferExecutedFences[i] = VK_NULL_HANDLE;
}
}
if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
@@ -2285,7 +2381,7 @@ static void DrawFrame()
// Begin main command buffer
size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFences[cmdBufIndex];
ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
@@ -2293,10 +2389,11 @@ static void DrawFrame()
VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
SetDebugUtilsObjectName(VK_OBJECT_TYPE_COMMAND_BUFFER, reinterpret_cast<std::uint64_t>(hCommandBuffer), "hCommandBuffer");
// Acquire swapchain image
uint32_t imageIndex = 0;
VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphores.at(g_SwapchainImageIndex), VK_NULL_HANDLE, &imageIndex);
if(res == VK_ERROR_OUT_OF_DATE_KHR)
{
RecreateSwapChain();
@@ -2326,7 +2423,7 @@ static void DrawFrame()
renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
renderPassBeginInfo.pClearValues = clearValues;
vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(
hCommandBuffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
@@ -2369,14 +2466,14 @@ static void DrawFrame()
vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
vkCmdEndRenderPass(hCommandBuffer);
vkEndCommandBuffer(hCommandBuffer);
// Submit command buffer
VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphores.at(g_SwapchainImageIndex)};
VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphores.at(g_SwapchainImageIndex)};
VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = submitWaitSemaphores;
@@ -2387,7 +2484,7 @@ static void DrawFrame()
submitInfo.pSignalSemaphores = submitSignalSemaphores;
ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphores.at(g_SwapchainImageIndex) };
VkSwapchainKHR swapchains[] = { g_hSwapchain };
VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
@@ -2404,6 +2501,11 @@ static void DrawFrame()
}
else
ERR_GUARD_VULKAN(res);
g_SwapchainImageIndex++;
if (g_SwapchainImageIndex >= g_SwapchainImageCount) {
g_SwapchainImageIndex = 0;
}
}
static void HandlePossibleSizeChange()
@@ -2538,7 +2640,7 @@ int MainWindow()
wndClassDesc.hInstance = g_hAppInstance;
wndClassDesc.lpfnWndProc = WndProc;
wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
assert(hWndClass);
@@ -2631,7 +2733,7 @@ int wmain(int argc, wchar_t** argv)
}
CATCH_PRINT_ERROR(return (int)ExitCode::RuntimeError;)
return result;
}
}
#else // #ifdef _WIN32
+17 -4
View File
@@ -154,7 +154,7 @@ static bool processParameter(MaterialBuilder& builder, const JsonishObject& json
std::cerr << "parameters: name value must be STRING." << std::endl;
return false;
}
const JsonishValue* transformNameValue = jsonObject.getValue("transformName");
if (transformNameValue && transformNameValue->getType() != JsonishValue::STRING) {
std::cerr << "parameters: transformName value must be STRING." << std::endl;
@@ -328,6 +328,19 @@ static bool processConstant(MaterialBuilder& builder, const JsonishObject& jsonO
return false;
}
const JsonishValue* mutableValue = jsonObject.getValue("mutable");
bool isMutable;
if (mutableValue) {
const JsonishBool* mutableBool = mutableValue->toJsonBool();
if (!mutableBool) {
std::cerr << "constants: mutable value must be BOOL." << std::endl;
return false;
}
isMutable = mutableBool->getBool();
} else {
isMutable = false;
}
auto typeString = typeValue->toJsonString()->getString();
auto nameString = nameValue->toJsonString()->getString();
const JsonishValue* defaultValue = jsonObject.getValue("default");
@@ -346,7 +359,7 @@ static bool processConstant(MaterialBuilder& builder, const JsonishObject& jsonO
// FIXME: Jsonish doesn't distinguish between integers and floats.
intDefault = (int32_t)defaultValue->toJsonNumber()->getFloat();
}
builder.constant(nameString.c_str(), type, intDefault);
builder.constant(nameString.c_str(), type, isMutable, intDefault);
break;
}
case ConstantType::FLOAT: {
@@ -359,7 +372,7 @@ static bool processConstant(MaterialBuilder& builder, const JsonishObject& jsonO
}
floatDefault = defaultValue->toJsonNumber()->getFloat();
}
builder.constant(nameString.c_str(), type, floatDefault);
builder.constant(nameString.c_str(), type, isMutable, floatDefault);
break;
}
case ConstantType::BOOL:
@@ -372,7 +385,7 @@ static bool processConstant(MaterialBuilder& builder, const JsonishObject& jsonO
}
boolDefault = defaultValue->toJsonBool()->getBool();
}
builder.constant(nameString.c_str(), type, boolDefault);
builder.constant(nameString.c_str(), type, isMutable, boolDefault);
break;
}
} else {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.61.2",
"version": "1.61.1",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",