Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5aded33477 | ||
|
|
659b8b6e03 | ||
|
|
c73f4e64d5 | ||
|
|
fe743523bf | ||
|
|
2c1044e812 | ||
|
|
db9183a105 | ||
|
|
e4a0bb8fa0 | ||
|
|
d15c53e530 | ||
|
|
cc8a3ed96b | ||
|
|
213eb6af9e | ||
|
|
e04c6d406f | ||
|
|
cab799f531 | ||
|
|
e95edef9d7 | ||
|
|
9cfef925bb | ||
|
|
3900fc6c37 | ||
|
|
b8ec1658f3 | ||
|
|
371bd1f01f |
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.53.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.53.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.53.0'
|
||||
pod 'Filament', '~> 1.53.1'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
@@ -176,6 +176,7 @@ steps:
|
||||
- [x] KHR_materials_unlit
|
||||
- [x] KHR_materials_variants
|
||||
- [x] KHR_materials_volume
|
||||
- [x] KHR_materials_specular
|
||||
- [x] KHR_mesh_quantization
|
||||
- [x] KHR_texture_basisu
|
||||
- [x] KHR_texture_transform
|
||||
|
||||
@@ -7,6 +7,12 @@ 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.53.2
|
||||
|
||||
|
||||
## v1.53.1
|
||||
|
||||
|
||||
## v1.53.0
|
||||
|
||||
- engine: fix skinning normals with large transforms (b/342459864) [⚠️ **New Material Version**]
|
||||
|
||||
@@ -571,3 +571,9 @@ Java_com_google_android_filament_Engine_nBuilderBuild(JNIEnv*, jclass, jlong nat
|
||||
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||
return (jlong) builder->build();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Engine_getSteadyClockTimeNano(JNIEnv *env, jclass clazz) {
|
||||
return (jlong)Engine::getSteadyClockTimeNano();
|
||||
}
|
||||
|
||||
@@ -25,12 +25,17 @@ using namespace filament;
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Material_nBuilderBuild(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jobject buffer_, jint size) {
|
||||
jlong nativeEngine, jobject buffer_, jint size, jint shBandCount) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
AutoBuffer buffer(env, buffer_, size);
|
||||
Material* material = Material::Builder()
|
||||
auto builder = Material::Builder();
|
||||
if (shBandCount) {
|
||||
builder.sphericalHarmonicsBandCount(shBandCount);
|
||||
}
|
||||
Material* material = builder
|
||||
.package(buffer.getData(), buffer.getSize())
|
||||
.build(*engine);
|
||||
|
||||
return (jlong) material;
|
||||
}
|
||||
|
||||
|
||||
@@ -187,3 +187,10 @@ Java_com_google_android_filament_Renderer_nSetPresentationTime(JNIEnv *, jclass
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
renderer->setPresentationTime(monotonicClockNanos);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Renderer_nSetVsyncTime(JNIEnv *, jclass,
|
||||
jlong nativeRenderer, jlong steadyClockTimeNano) {
|
||||
Renderer *renderer = (Renderer *) nativeRenderer;
|
||||
renderer->setVsyncTime(steadyClockTimeNano);
|
||||
}
|
||||
|
||||
@@ -1292,7 +1292,6 @@ public class Engine {
|
||||
/**
|
||||
* Switch the command queue to unprotected mode. Protected mode can be activated via
|
||||
* Renderer::beginFrame() using a protected SwapChain.
|
||||
|
||||
* @see Renderer
|
||||
* @see SwapChain
|
||||
*/
|
||||
@@ -1300,6 +1299,13 @@ public class Engine {
|
||||
nUnprotected(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current time. This is a convenience function that simply returns the
|
||||
* time in nanosecond since epoch of std::chrono::steady_clock.
|
||||
* @return current time in nanosecond since epoch of std::chrono::steady_clock.
|
||||
* @see Renderer#beginFrame
|
||||
*/
|
||||
public static native long getSteadyClockTimeNano();
|
||||
|
||||
@UsedByReflection("TextureHelper.java")
|
||||
public long getNativeObject() {
|
||||
|
||||
@@ -346,6 +346,7 @@ public class Material {
|
||||
public static class Builder {
|
||||
private Buffer mBuffer;
|
||||
private int mSize;
|
||||
private int mShBandCount = 0;
|
||||
|
||||
/**
|
||||
* Specifies the material data. The material data is a binary blob produced by
|
||||
@@ -361,6 +362,22 @@ public class Material {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the quality of the indirect lights computations. This is only taken into account
|
||||
* if this material is lit and in the surface domain. This setting will affect the
|
||||
* IndirectLight computation if one is specified on the Scene and Spherical Harmonics
|
||||
* are used for the irradiance.
|
||||
*
|
||||
* @param shBandCount Number of spherical harmonic bands. Must be 1, 2 or 3 (default).
|
||||
* @return Reference to this Builder for chaining calls.
|
||||
* @see IndirectLight
|
||||
*/
|
||||
@NonNull
|
||||
public Builder sphericalHarmonicsBandCount(@IntRange(from = 0) int shBandCount) {
|
||||
mShBandCount = shBandCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns the Material object.
|
||||
*
|
||||
@@ -372,7 +389,8 @@ public class Material {
|
||||
*/
|
||||
@NonNull
|
||||
public Material build(@NonNull Engine engine) {
|
||||
long nativeMaterial = nBuilderBuild(engine.getNativeObject(), mBuffer, mSize);
|
||||
long nativeMaterial = nBuilderBuild(engine.getNativeObject(),
|
||||
mBuffer, mSize, mShBandCount);
|
||||
if (nativeMaterial == 0) throw new IllegalStateException("Couldn't create Material");
|
||||
return new Material(nativeMaterial);
|
||||
}
|
||||
@@ -1023,7 +1041,7 @@ public class Material {
|
||||
mNativeObject = 0;
|
||||
}
|
||||
|
||||
private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size);
|
||||
private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size, int shBandCount);
|
||||
private static native long nCreateInstance(long nativeMaterial);
|
||||
private static native long nCreateInstanceWithName(long nativeMaterial, @NonNull String name);
|
||||
private static native long nGetDefaultInstance(long nativeMaterial);
|
||||
|
||||
@@ -284,6 +284,19 @@ public class Renderer {
|
||||
nSetPresentationTime(getNativeObject(), monotonicClockNanos);
|
||||
}
|
||||
|
||||
/**
|
||||
* The use of this method is optional. It sets the VSYNC time expressed as the duration in
|
||||
* nanosecond since epoch of std::chrono::steady_clock.
|
||||
* If called, passing 0 to frameTimeNanos in Renderer.BeginFrame will use this
|
||||
* time instead.
|
||||
* @param steadyClockTimeNano duration in nanosecond since epoch of std::chrono::steady_clock
|
||||
* @see Engine#getSteadyClockTimeNano
|
||||
* @see Renderer#beginFrame
|
||||
*/
|
||||
public void setVsyncTime(long steadyClockTimeNano) {
|
||||
nSetVsyncTime(getNativeObject(), steadyClockTimeNano);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a frame for this <code>Renderer</code>.
|
||||
* <p><code>beginFrame</code> manages frame pacing, and returns whether or not a frame should be
|
||||
@@ -702,6 +715,7 @@ public class Renderer {
|
||||
}
|
||||
|
||||
private static native void nSetPresentationTime(long nativeObject, long monotonicClockNanos);
|
||||
private static native void nSetVsyncTime(long nativeObject, long steadyClockTimeNano);
|
||||
private static native boolean nBeginFrame(long nativeRenderer, long nativeSwapChain, long frameTimeNanos);
|
||||
private static native void nEndFrame(long nativeRenderer);
|
||||
private static native void nRender(long nativeRenderer, long nativeView);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.53.0
|
||||
VERSION_NAME=1.53.1
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -75,6 +75,8 @@ public:
|
||||
*/
|
||||
size_t textureUseAfterFreePoolSize = 0;
|
||||
|
||||
size_t metalUploadBufferSizeBytes = 512 * 1024;
|
||||
|
||||
/**
|
||||
* Set to `true` to forcibly disable parallel shader compilation in the backend.
|
||||
* Currently only honored by the GL and Metal backends.
|
||||
|
||||
@@ -90,6 +90,20 @@ public:
|
||||
VkExtent2D extent = {0, 0};
|
||||
};
|
||||
|
||||
struct ImageSyncData {
|
||||
static constexpr uint32_t INVALID_IMAGE_INDEX = UINT32_MAX;
|
||||
|
||||
// The index of the next image as returned by vkAcquireNextImage or equivalent.
|
||||
uint32_t imageIndex = INVALID_IMAGE_INDEX;
|
||||
|
||||
// Semaphore to be signaled once the image is available.
|
||||
VkSemaphore imageReadySemaphore = VK_NULL_HANDLE;
|
||||
|
||||
// A function called right before vkQueueSubmit. After this call, the image must be
|
||||
// available. This pointer can be null if imageReadySemaphore is not VK_NULL_HANDLE.
|
||||
std::function<void(SwapChainPtr handle)> explicitImageReadyWait = nullptr;
|
||||
};
|
||||
|
||||
VulkanPlatform();
|
||||
|
||||
~VulkanPlatform() override;
|
||||
@@ -127,6 +141,12 @@ public:
|
||||
* before recreating the swapchain. Default is true.
|
||||
*/
|
||||
bool flushAndWaitOnWindowResize = true;
|
||||
|
||||
/**
|
||||
* Whether the swapchain image should be transitioned to a layout suitable for
|
||||
* presentation. Default is true.
|
||||
*/
|
||||
bool transitionSwapChainImageLayoutForPresent = true;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -155,13 +175,10 @@ public:
|
||||
* corresponding VkImage will be used as the output color attachment. The client should signal
|
||||
* the `clientSignal` semaphore when the image is ready to be used by the backend.
|
||||
* @param handle The handle returned by createSwapChain()
|
||||
* @param clientSignal The semaphore that the client will signal to indicate that the backend
|
||||
* may render into the image.
|
||||
* @param index Pointer to memory that will be filled with the index that corresponding
|
||||
* to an image in the `SwapChainBundle.colors` array.
|
||||
* @param outImageSyncData The synchronization data used for image readiness
|
||||
* @return Result of acquire
|
||||
*/
|
||||
virtual VkResult acquire(SwapChainPtr handle, VkSemaphore clientSignal, uint32_t* index);
|
||||
virtual VkResult acquire(SwapChainPtr handle, ImageSyncData* outImageSyncData);
|
||||
|
||||
/**
|
||||
* Present the image corresponding to `index` to the display. The client should wait on
|
||||
|
||||
@@ -181,6 +181,18 @@ public:
|
||||
return static_cast<Dp>(p);
|
||||
}
|
||||
|
||||
template<typename B>
|
||||
bool is_valid(Handle<B>& handle) {
|
||||
if (handle && isPoolHandle(handle.getId())) {
|
||||
auto [p, tag] = handleToPointer(handle.getId());
|
||||
uint8_t const age = (tag & HANDLE_AGE_MASK) >> HANDLE_AGE_SHIFT;
|
||||
auto const pNode = static_cast<typename Allocator::Node*>(p);
|
||||
uint8_t const expectedAge = pNode[-1].age;
|
||||
return expectedAge == age;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Dp, typename B>
|
||||
inline typename std::enable_if_t<
|
||||
std::is_pointer_v<Dp> &&
|
||||
|
||||
@@ -204,6 +204,15 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
enum class UploadStrategy {
|
||||
POOL,
|
||||
BUMP_ALLOCATOR,
|
||||
};
|
||||
|
||||
void uploadWithPoolBuffer(void* src, size_t size, size_t byteOffset) const;
|
||||
void uploadWithBumpAllocator(void* src, size_t size, size_t byteOffset) const;
|
||||
|
||||
UploadStrategy mUploadStrategy;
|
||||
TrackedMetalBuffer mBuffer;
|
||||
size_t mBufferSize = 0;
|
||||
void* mCpuBuffer = nullptr;
|
||||
|
||||
@@ -27,7 +27,16 @@ MetalPlatform* TrackedMetalBuffer::platform = nullptr;
|
||||
MetalPlatform* ScopedAllocationTimer::platform = nullptr;
|
||||
|
||||
MetalBuffer::MetalBuffer(MetalContext& context, BufferObjectBinding bindingType, BufferUsage usage,
|
||||
size_t size, bool forceGpuBuffer) : mBufferSize(size), mContext(context) {
|
||||
size_t size, bool forceGpuBuffer)
|
||||
: mBufferSize(size), mContext(context) {
|
||||
const MetalBumpAllocator& allocator = *mContext.bumpAllocator;
|
||||
// VERTEX is also used for index buffers
|
||||
if (allocator.getCapacity() > 0 && bindingType == BufferObjectBinding::VERTEX) {
|
||||
mUploadStrategy = UploadStrategy::BUMP_ALLOCATOR;
|
||||
} else {
|
||||
mUploadStrategy = UploadStrategy::POOL;
|
||||
}
|
||||
|
||||
// If the buffer is less than 4K in size and is updated frequently, we don't use an explicit
|
||||
// buffer. Instead, we use immediate command encoder methods like setVertexBytes:length:atIndex:.
|
||||
// This won't work for SSBOs, since they are read/write.
|
||||
@@ -61,34 +70,23 @@ void MetalBuffer::copyIntoBuffer(void* src, size_t size, size_t byteOffset) {
|
||||
FILAMENT_CHECK_PRECONDITION(size + byteOffset <= mBufferSize)
|
||||
<< "Attempting to copy " << size << " bytes into a buffer of size " << mBufferSize
|
||||
<< " at offset " << byteOffset;
|
||||
// The copy blit requires that byteOffset be a multiple of 4.
|
||||
FILAMENT_CHECK_PRECONDITION(!(byteOffset & 0x3)) << "byteOffset must be a multiple of 4";
|
||||
|
||||
// Either copy into the Metal buffer or into our cpu buffer.
|
||||
// If we have a cpu buffer, we can directly copy into it.
|
||||
if (mCpuBuffer) {
|
||||
memcpy(static_cast<uint8_t*>(mCpuBuffer) + byteOffset, src, size);
|
||||
return;
|
||||
}
|
||||
|
||||
// Acquire a staging buffer to hold the contents of this update.
|
||||
MetalBufferPool* bufferPool = mContext.bufferPool;
|
||||
const MetalBufferPoolEntry* const staging = bufferPool->acquireBuffer(size);
|
||||
memcpy(staging->buffer.get().contents, src, size);
|
||||
|
||||
// The blit below requires that byteOffset be a multiple of 4.
|
||||
FILAMENT_CHECK_PRECONDITION(!(byteOffset & 0x3u)) << "byteOffset must be a multiple of 4";
|
||||
|
||||
// Encode a blit from the staging buffer into the private GPU buffer.
|
||||
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(&mContext);
|
||||
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
|
||||
blitEncoder.label = @"Buffer upload blit";
|
||||
[blitEncoder copyFromBuffer:staging->buffer.get()
|
||||
sourceOffset:0
|
||||
toBuffer:mBuffer.get()
|
||||
destinationOffset:byteOffset
|
||||
size:size];
|
||||
[blitEncoder endEncoding];
|
||||
[cmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
|
||||
bufferPool->releaseBuffer(staging);
|
||||
}];
|
||||
switch (mUploadStrategy) {
|
||||
case UploadStrategy::BUMP_ALLOCATOR:
|
||||
uploadWithBumpAllocator(src, size, byteOffset);
|
||||
break;
|
||||
case UploadStrategy::POOL:
|
||||
uploadWithPoolBuffer(src, size, byteOffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MetalBuffer::copyIntoBufferUnsynchronized(void* src, size_t size, size_t byteOffset) {
|
||||
@@ -199,5 +197,42 @@ void MetalBuffer::bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLCommandEncod
|
||||
}
|
||||
}
|
||||
|
||||
void MetalBuffer::uploadWithPoolBuffer(void* src, size_t size, size_t byteOffset) const {
|
||||
MetalBufferPool* bufferPool = mContext.bufferPool;
|
||||
const MetalBufferPoolEntry* const staging = bufferPool->acquireBuffer(size);
|
||||
memcpy(staging->buffer.get().contents, src, size);
|
||||
|
||||
// Encode a blit from the staging buffer into the private GPU buffer.
|
||||
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(&mContext);
|
||||
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
|
||||
blitEncoder.label = @"Buffer upload blit - pool buffer";
|
||||
[blitEncoder copyFromBuffer:staging->buffer.get()
|
||||
sourceOffset:0
|
||||
toBuffer:mBuffer.get()
|
||||
destinationOffset:byteOffset
|
||||
size:size];
|
||||
[blitEncoder endEncoding];
|
||||
[cmdBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
|
||||
bufferPool->releaseBuffer(staging);
|
||||
}];
|
||||
}
|
||||
|
||||
void MetalBuffer::uploadWithBumpAllocator(void* src, size_t size, size_t byteOffset) const {
|
||||
MetalBumpAllocator& allocator = *mContext.bumpAllocator;
|
||||
auto [buffer, offset] = allocator.allocateStagingArea(size);
|
||||
memcpy(static_cast<char*>(buffer.contents) + offset, src, size);
|
||||
|
||||
// Encode a blit from the staging buffer into the private GPU buffer.
|
||||
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(&mContext);
|
||||
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
|
||||
blitEncoder.label = @"Buffer upload blit - bump allocator";
|
||||
[blitEncoder copyFromBuffer:buffer
|
||||
sourceOffset:offset
|
||||
toBuffer:mBuffer.get()
|
||||
destinationOffset:byteOffset
|
||||
size:size];
|
||||
[blitEncoder endEncoding];
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
@@ -38,6 +38,28 @@ struct MetalBufferPoolEntry {
|
||||
mutable uint32_t referenceCount;
|
||||
};
|
||||
|
||||
class MetalBumpAllocator {
|
||||
public:
|
||||
MetalBumpAllocator(id<MTLDevice> device, size_t capacity);
|
||||
|
||||
/**
|
||||
* Allocates a staging area of the given size. Returns a pair of the buffer and the offset
|
||||
* within the buffer. The buffer is guaranteed to be at least the given size, but may be larger.
|
||||
* Clients must not write to the buffer beyond the returned offset + size.
|
||||
* Clients are responsible for holding a reference to the returned buffer.
|
||||
* Allocations are guaranteed to be aligned to 4 bytes.
|
||||
*/
|
||||
std::pair<id<MTLBuffer>, size_t> allocateStagingArea(size_t size);
|
||||
|
||||
size_t getCapacity() const noexcept { return mCapacity; }
|
||||
|
||||
private:
|
||||
id<MTLDevice> mDevice;
|
||||
TrackedMetalBuffer mCurrentUploadBuffer = nil;
|
||||
size_t mHead = 0;
|
||||
size_t mCapacity;
|
||||
};
|
||||
|
||||
// Manages a pool of Metal buffers, periodically releasing ones that have been unused for awhile.
|
||||
class MetalBufferPool {
|
||||
public:
|
||||
|
||||
@@ -116,5 +116,38 @@ void MetalBufferPool::reset() noexcept {
|
||||
mFreeStages.clear();
|
||||
}
|
||||
|
||||
MetalBumpAllocator::MetalBumpAllocator(id<MTLDevice> device, size_t capacity)
|
||||
: mDevice(device), mCapacity(capacity) {
|
||||
if (mCapacity > 0) {
|
||||
mCurrentUploadBuffer = { [device newBufferWithLength:capacity options:MTLStorageModeShared],
|
||||
TrackedMetalBuffer::Type::STAGING };
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<id<MTLBuffer>, size_t> MetalBumpAllocator::allocateStagingArea(size_t size) {
|
||||
if (size == 0) {
|
||||
return { nil, 0 };
|
||||
}
|
||||
if (size > mCapacity) {
|
||||
return { [mDevice newBufferWithLength:size options:MTLStorageModeShared], 0 };
|
||||
}
|
||||
assert_invariant(mCurrentUploadBuffer);
|
||||
|
||||
// Align the head to a 4-byte boundary.
|
||||
mHead = (mHead + 3) & ~3;
|
||||
|
||||
if (UTILS_LIKELY(mHead + size <= mCapacity)) {
|
||||
const size_t oldHead = mHead;
|
||||
mHead += size;
|
||||
return { mCurrentUploadBuffer.get(), oldHead };
|
||||
}
|
||||
|
||||
// We're finished with the current allocation.
|
||||
mCurrentUploadBuffer = { [mDevice newBufferWithLength:mCapacity options:MTLStorageModeShared],
|
||||
TrackedMetalBuffer::Type::STAGING };
|
||||
|
||||
return { mCurrentUploadBuffer.get(), 0 };
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace backend {
|
||||
class MetalDriver;
|
||||
class MetalBlitter;
|
||||
class MetalBufferPool;
|
||||
class MetalBumpAllocator;
|
||||
class MetalRenderTarget;
|
||||
class MetalSamplerGroup;
|
||||
class MetalSwapChain;
|
||||
@@ -141,6 +142,7 @@ struct MetalContext {
|
||||
utils::FixedCircularBuffer<Handle<HwTexture>> texturesToDestroy;
|
||||
|
||||
MetalBufferPool* bufferPool;
|
||||
MetalBumpAllocator* bumpAllocator;
|
||||
|
||||
MetalSwapChain* currentDrawSwapChain = nil;
|
||||
MetalSwapChain* currentReadSwapChain = nil;
|
||||
|
||||
@@ -171,6 +171,8 @@ MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig&
|
||||
mContext->samplerStateCache.setDevice(mContext->device);
|
||||
mContext->argumentEncoderCache.setDevice(mContext->device);
|
||||
mContext->bufferPool = new MetalBufferPool(*mContext);
|
||||
mContext->bumpAllocator =
|
||||
new MetalBumpAllocator(mContext->device, driverConfig.metalUploadBufferSizeBytes);
|
||||
mContext->blitter = new MetalBlitter(*mContext);
|
||||
|
||||
if (@available(iOS 12, *)) {
|
||||
@@ -209,6 +211,7 @@ MetalDriver::~MetalDriver() noexcept {
|
||||
mContext->emptyTexture = nil;
|
||||
CFRelease(mContext->textureCache);
|
||||
delete mContext->bufferPool;
|
||||
delete mContext->bumpAllocator;
|
||||
delete mContext->blitter;
|
||||
delete mContext->timerQueryImpl;
|
||||
delete mContext->shaderCompiler;
|
||||
|
||||
@@ -109,7 +109,7 @@ private:
|
||||
NSUInteger headlessWidth = 0;
|
||||
NSUInteger headlessHeight = 0;
|
||||
CAMetalLayer* layer = nullptr;
|
||||
std::mutex layerDrawableMutex;
|
||||
std::shared_ptr<std::mutex> layerDrawableMutex;
|
||||
MetalExternalImage externalImage;
|
||||
SwapChainType type;
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow
|
||||
: context(context),
|
||||
depthStencilFormat(decideDepthStencilFormat(flags)),
|
||||
layer(nativeWindow),
|
||||
layerDrawableMutex(std::make_shared<std::mutex>()),
|
||||
externalImage(context),
|
||||
type(SwapChainType::CAMETALLAYER) {
|
||||
|
||||
@@ -179,7 +180,7 @@ id<MTLTexture> MetalSwapChain::acquireDrawable() {
|
||||
// calling -nextDrawable, or when releasing the last known reference
|
||||
// to any CAMetalDrawable returned from a previous -nextDrawable.
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(layerDrawableMutex);
|
||||
std::lock_guard<std::mutex> lock(*layerDrawableMutex);
|
||||
drawable = [layer nextDrawable];
|
||||
}
|
||||
|
||||
@@ -188,8 +189,10 @@ id<MTLTexture> MetalSwapChain::acquireDrawable() {
|
||||
}
|
||||
|
||||
void MetalSwapChain::releaseDrawable() {
|
||||
std::lock_guard<std::mutex> lock(layerDrawableMutex);
|
||||
drawable = nil;
|
||||
if (drawable) {
|
||||
std::lock_guard<std::mutex> lock(*layerDrawableMutex);
|
||||
drawable = nil;
|
||||
}
|
||||
}
|
||||
|
||||
id<MTLTexture> MetalSwapChain::acquireDepthTexture() {
|
||||
@@ -265,7 +268,7 @@ public:
|
||||
PresentDrawableData& operator=(const PresentDrawableData&) = delete;
|
||||
|
||||
static PresentDrawableData* create(id<CAMetalDrawable> drawable,
|
||||
std::mutex* drawableMutex, MetalDriver* driver) {
|
||||
std::shared_ptr<std::mutex> drawableMutex, MetalDriver* driver) {
|
||||
assert_invariant(drawableMutex);
|
||||
assert_invariant(driver);
|
||||
return new PresentDrawableData(drawable, drawableMutex, driver);
|
||||
@@ -287,22 +290,22 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
PresentDrawableData(id<CAMetalDrawable> drawable, std::mutex* drawableMutex,
|
||||
PresentDrawableData(id<CAMetalDrawable> drawable, std::shared_ptr<std::mutex> drawableMutex,
|
||||
MetalDriver* driver)
|
||||
: mDrawable(drawable), mDrawableMutex(drawableMutex), mDriver(driver) {}
|
||||
|
||||
static void cleanupAndDestroy(PresentDrawableData *that) {
|
||||
{
|
||||
if (that->mDrawable) {
|
||||
std::lock_guard<std::mutex> lock(*(that->mDrawableMutex));
|
||||
that->mDrawable = nil;
|
||||
}
|
||||
that->mDrawableMutex = nullptr;
|
||||
that->mDrawableMutex.reset();
|
||||
that->mDriver = nullptr;
|
||||
delete that;
|
||||
}
|
||||
|
||||
id<CAMetalDrawable> mDrawable;
|
||||
std::mutex* mDrawableMutex = nullptr;
|
||||
std::shared_ptr<std::mutex> mDrawableMutex;
|
||||
MetalDriver* mDriver = nullptr;
|
||||
};
|
||||
|
||||
@@ -320,7 +323,7 @@ void MetalSwapChain::scheduleFrameScheduledCallback() {
|
||||
|
||||
struct Callback {
|
||||
Callback(std::shared_ptr<FrameScheduledCallback> callback, id<CAMetalDrawable> drawable,
|
||||
std::mutex* drawableMutex, MetalDriver* driver)
|
||||
std::shared_ptr<std::mutex> drawableMutex, MetalDriver* driver)
|
||||
: f(callback), data(PresentDrawableData::create(drawable, drawableMutex, driver)) {}
|
||||
std::shared_ptr<FrameScheduledCallback> f;
|
||||
// PresentDrawableData* is destroyed by maybePresentAndDestroyAsync() later.
|
||||
@@ -337,7 +340,7 @@ void MetalSwapChain::scheduleFrameScheduledCallback() {
|
||||
// This callback pointer will be captured by the block. Even if the scheduled handler is never
|
||||
// called, the unique_ptr will still ensure we don't leak memory.
|
||||
__block auto callback = std::make_unique<Callback>(
|
||||
frameScheduled.callback, drawable, &layerDrawableMutex, context.driver);
|
||||
frameScheduled.callback, drawable, layerDrawableMutex, context.driver);
|
||||
|
||||
backend::CallbackHandler* handler = frameScheduled.handler;
|
||||
MetalDriver* driver = context.driver;
|
||||
|
||||
@@ -304,6 +304,13 @@ void OpenGLDriver::bindSampler(GLuint unit, GLuint sampler) noexcept {
|
||||
void OpenGLDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
|
||||
backend::PushConstantVariant value) {
|
||||
assert_invariant(stage == ShaderStage::VERTEX || stage == ShaderStage::FRAGMENT);
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
if (UTILS_UNLIKELY(!mValidProgram)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
utils::Slice<std::pair<GLint, ConstantType>> constants;
|
||||
if (stage == ShaderStage::VERTEX) {
|
||||
constants = mCurrentPushConstants->vertexConstants;
|
||||
@@ -340,15 +347,11 @@ void OpenGLDriver::bindTexture(GLuint unit, GLTexture const* t) noexcept {
|
||||
}
|
||||
|
||||
bool OpenGLDriver::useProgram(OpenGLProgram* p) noexcept {
|
||||
if (UTILS_UNLIKELY(!p->isValid())) {
|
||||
// If the program is not valid, we can't call use().
|
||||
return false;
|
||||
}
|
||||
|
||||
// set-up textures and samplers in the proper TMUs (as specified in setSamplers)
|
||||
p->use(this, mContext);
|
||||
bool const success = p->use(this, mContext);
|
||||
assert_invariant(success == p->isValid());
|
||||
|
||||
if (UTILS_UNLIKELY(mContext.isES2())) {
|
||||
if (UTILS_UNLIKELY(mContext.isES2() && success)) {
|
||||
for (uint32_t i = 0; i < Program::UNIFORM_BINDING_COUNT; i++) {
|
||||
auto [id, buffer, age] = mContext.getEs2UniformBinding(i);
|
||||
if (buffer) {
|
||||
@@ -359,7 +362,8 @@ bool OpenGLDriver::useProgram(OpenGLProgram* p) noexcept {
|
||||
// when mPlatform.isSRGBSwapChainSupported() is false (no need to check though).
|
||||
p->setRec709ColorSpace(mRec709OutputColorspace);
|
||||
}
|
||||
return true;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -2332,9 +2336,9 @@ void OpenGLDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
|
||||
auto const* const pSamplers = (SamplerDescriptor const*)data.buffer;
|
||||
for (size_t i = 0, c = sb->textureUnitEntries.size(); i < c; i++) {
|
||||
GLuint samplerId = 0u;
|
||||
const GLTexture* t = nullptr;
|
||||
if (UTILS_LIKELY(pSamplers[i].t)) {
|
||||
t = handle_cast<const GLTexture*>(pSamplers[i].t);
|
||||
Handle<HwTexture> th = pSamplers[i].t;
|
||||
if (UTILS_LIKELY(th)) {
|
||||
GLTexture const* const t = handle_cast<const GLTexture*>(th);
|
||||
assert_invariant(t);
|
||||
|
||||
SamplerParams params = pSamplers[i].s;
|
||||
@@ -2390,7 +2394,7 @@ void OpenGLDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
|
||||
// which is not an error.
|
||||
}
|
||||
|
||||
sb->textureUnitEntries[i] = { t, samplerId };
|
||||
sb->textureUnitEntries[i] = { th, samplerId };
|
||||
}
|
||||
scheduleDestroy(std::move(data));
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ public:
|
||||
struct GLSamplerGroup : public HwSamplerGroup {
|
||||
using HwSamplerGroup::HwSamplerGroup;
|
||||
struct Entry {
|
||||
GLTexture const* texture = nullptr;
|
||||
Handle<HwTexture> th;
|
||||
GLuint sampler = 0u;
|
||||
};
|
||||
utils::FixedCapacityVector<Entry> textureUnitEntries;
|
||||
@@ -256,6 +256,11 @@ private:
|
||||
return mHandleAllocator.handle_cast<Dp, B>(handle);
|
||||
}
|
||||
|
||||
template<typename B>
|
||||
bool is_valid(Handle<B>& handle) {
|
||||
return mHandleAllocator.is_valid(handle);
|
||||
}
|
||||
|
||||
template<typename Dp, typename B>
|
||||
inline typename std::enable_if_t<
|
||||
std::is_pointer_v<Dp> &&
|
||||
|
||||
@@ -20,21 +20,24 @@
|
||||
#include "OpenGLDriver.h"
|
||||
#include "ShaderCompilerService.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Program.h>
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <private/backend/BackendUtils.h>
|
||||
|
||||
#include <utils/debug.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <new>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
@@ -241,8 +244,9 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* const gld) const noexcept {
|
||||
assert_invariant(sb);
|
||||
if (!sb) continue; // should never happen, this would be a user error.
|
||||
for (uint8_t j = 0, m = sb->textureUnitEntries.size(); j < m; ++j, ++tmu) { // "<=" on purpose here
|
||||
const GLTexture* const t = sb->textureUnitEntries[j].texture;
|
||||
if (t) { // program may not use all samplers of sampler group
|
||||
Handle<HwTexture> th = sb->textureUnitEntries[j].th;
|
||||
if (th) { // program may not use all samplers of sampler group
|
||||
GLTexture const* const t = gld->handle_cast<GLTexture const*>(th);
|
||||
gld->bindTexture(tmu, t);
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
if (UTILS_LIKELY(!es2)) {
|
||||
|
||||
@@ -53,11 +53,21 @@ public:
|
||||
|
||||
bool isValid() const noexcept { return mToken || gl.program != 0; }
|
||||
|
||||
void use(OpenGLDriver* const gld, OpenGLContext& context) noexcept {
|
||||
if (UTILS_UNLIKELY(!gl.program)) {
|
||||
bool use(OpenGLDriver* const gld, OpenGLContext& context) noexcept {
|
||||
// both non-null is impossible by construction
|
||||
assert_invariant(!mToken || !gl.program);
|
||||
|
||||
if (UTILS_UNLIKELY(mToken && !gl.program)) {
|
||||
// first time a program is used
|
||||
initialize(*gld);
|
||||
}
|
||||
|
||||
if (UTILS_UNLIKELY(!gl.program)) {
|
||||
// compilation failed (token should be null)
|
||||
assert_invariant(!mToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
context.useProgram(gl.program);
|
||||
if (UTILS_UNLIKELY(mUsedBindingsCount)) {
|
||||
// We rely on GL state tracking to avoid unnecessary glBindTexture / glBindSampler
|
||||
@@ -74,6 +84,7 @@ public:
|
||||
|
||||
updateSamplers(gld);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// For ES2 only
|
||||
|
||||
@@ -359,7 +359,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
||||
GLuint ShaderCompilerService::getProgram(ShaderCompilerService::program_token_t& token) {
|
||||
GLuint const program = initialize(token);
|
||||
assert_invariant(token == nullptr);
|
||||
#ifndef FILAMENT_ENABLE_MATDBG
|
||||
#if !FILAMENT_ENABLE_MATDBG
|
||||
assert_invariant(program);
|
||||
#endif
|
||||
return program;
|
||||
@@ -572,16 +572,23 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
|
||||
|
||||
// split shader source, so we can insert the specialization constants and the packing
|
||||
// functions
|
||||
auto const [prolog, body] = splitShaderSource({ shader_src, shader_len });
|
||||
auto [version, prolog, body] = splitShaderSource({ shader_src, shader_len });
|
||||
|
||||
const std::array<const char*, 4> sources = {
|
||||
// enable ESSL 3.10 if available
|
||||
if (context.isAtLeastGLES<3, 1>()) {
|
||||
version = "#version 310 es\n";
|
||||
}
|
||||
|
||||
const std::array<const char*, 5> sources = {
|
||||
version.data(),
|
||||
prolog.data(),
|
||||
specializationConstantString.c_str(),
|
||||
packingFunctions.data(),
|
||||
body.data()
|
||||
};
|
||||
|
||||
const std::array<GLint, 4> lengths = {
|
||||
const std::array<GLint, 5> lengths = {
|
||||
(GLint)version.length(),
|
||||
(GLint)prolog.length(),
|
||||
(GLint)specializationConstantString.length(),
|
||||
(GLint)packingFunctions.length(),
|
||||
@@ -661,6 +668,7 @@ void ShaderCompilerService::process_OVR_multiview2(OpenGLContext& context,
|
||||
|
||||
// Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 (appeared in 4.2) and
|
||||
// macOS doesn't support GL_ARB_shading_language_packing
|
||||
// Also GLES3.0 didn't have the full set of packing/unpacking functions
|
||||
std::string_view ShaderCompilerService::process_ARB_shading_language_packing(OpenGLContext& context) noexcept {
|
||||
using namespace std::literals;
|
||||
#ifdef BACKEND_OPENGL_VERSION_GL
|
||||
@@ -700,21 +708,92 @@ highp uint packHalf2x16(vec2 v) {
|
||||
highp uint y = fp32tou16(v.y);
|
||||
return (y << 16u) | x;
|
||||
}
|
||||
highp uint packUnorm4x8(mediump vec4 v) {
|
||||
v = round(clamp(v, 0.0, 1.0) * 255.0);
|
||||
highp uint a = uint(v.x);
|
||||
highp uint b = uint(v.y) << 8;
|
||||
highp uint c = uint(v.z) << 16;
|
||||
highp uint d = uint(v.w) << 24;
|
||||
return (a|b|c|d);
|
||||
}
|
||||
highp uint packSnorm4x8(mediump vec4 v) {
|
||||
v = round(clamp(v, -1.0, 1.0) * 127.0);
|
||||
highp uint a = uint((int(v.x) & 0xff));
|
||||
highp uint b = uint((int(v.y) & 0xff)) << 8;
|
||||
highp uint c = uint((int(v.z) & 0xff)) << 16;
|
||||
highp uint d = uint((int(v.w) & 0xff)) << 24;
|
||||
return (a|b|c|d);
|
||||
}
|
||||
mediump vec4 unpackUnorm4x8(highp uint v) {
|
||||
return vec4(float((v & 0x000000ffu) ),
|
||||
float((v & 0x0000ff00u) >> 8),
|
||||
float((v & 0x00ff0000u) >> 16),
|
||||
float((v & 0xff000000u) >> 24)) / 255.0;
|
||||
}
|
||||
mediump vec4 unpackSnorm4x8(highp uint v) {
|
||||
int a = int(((v ) & 0xffu) << 24u) >> 24 ;
|
||||
int b = int(((v >> 8u) & 0xffu) << 24u) >> 24 ;
|
||||
int c = int(((v >> 16u) & 0xffu) << 24u) >> 24 ;
|
||||
int d = int(((v >> 24u) & 0xffu) << 24u) >> 24 ;
|
||||
return clamp(vec4(float(a), float(b), float(c), float(d)) / 127.0, -1.0, 1.0);
|
||||
}
|
||||
)"sv;
|
||||
}
|
||||
#endif // BACKEND_OPENGL_VERSION_GL
|
||||
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
if (!context.isES2() && !context.isAtLeastGLES<3, 1>()) {
|
||||
return R"(
|
||||
|
||||
highp uint packUnorm4x8(mediump vec4 v) {
|
||||
v = round(clamp(v, 0.0, 1.0) * 255.0);
|
||||
highp uint a = uint(v.x);
|
||||
highp uint b = uint(v.y) << 8;
|
||||
highp uint c = uint(v.z) << 16;
|
||||
highp uint d = uint(v.w) << 24;
|
||||
return (a|b|c|d);
|
||||
}
|
||||
highp uint packSnorm4x8(mediump vec4 v) {
|
||||
v = round(clamp(v, -1.0, 1.0) * 127.0);
|
||||
highp uint a = uint((int(v.x) & 0xff));
|
||||
highp uint b = uint((int(v.y) & 0xff)) << 8;
|
||||
highp uint c = uint((int(v.z) & 0xff)) << 16;
|
||||
highp uint d = uint((int(v.w) & 0xff)) << 24;
|
||||
return (a|b|c|d);
|
||||
}
|
||||
mediump vec4 unpackUnorm4x8(highp uint v) {
|
||||
return vec4(float((v & 0x000000ffu) ),
|
||||
float((v & 0x0000ff00u) >> 8),
|
||||
float((v & 0x00ff0000u) >> 16),
|
||||
float((v & 0xff000000u) >> 24)) / 255.0;
|
||||
}
|
||||
mediump vec4 unpackSnorm4x8(highp uint v) {
|
||||
int a = int(((v ) & 0xffu) << 24u) >> 24 ;
|
||||
int b = int(((v >> 8u) & 0xffu) << 24u) >> 24 ;
|
||||
int c = int(((v >> 16u) & 0xffu) << 24u) >> 24 ;
|
||||
int d = int(((v >> 24u) & 0xffu) << 24u) >> 24 ;
|
||||
return clamp(vec4(float(a), float(b), float(c), float(d)) / 127.0, -1.0, 1.0);
|
||||
}
|
||||
)"sv;
|
||||
}
|
||||
#endif // BACKEND_OPENGL_VERSION_GLES
|
||||
return ""sv;
|
||||
}
|
||||
|
||||
// split shader source code in two, the first section goes from the start to the line after the
|
||||
// last #extension, and the 2nd part goes from there to the end.
|
||||
std::array<std::string_view, 2> ShaderCompilerService::splitShaderSource(std::string_view source) noexcept {
|
||||
// split shader source code in three:
|
||||
// - the version line
|
||||
// - extensions
|
||||
// - everything else
|
||||
std::array<std::string_view, 3> ShaderCompilerService::splitShaderSource(std::string_view source) noexcept {
|
||||
auto start = source.find("#version");
|
||||
assert_invariant(start != std::string_view::npos);
|
||||
|
||||
auto version_eol = source.find('\n', start) + 1;
|
||||
assert_invariant(version_eol != std::string_view::npos);
|
||||
|
||||
auto pos = source.rfind("\n#extension");
|
||||
if (pos == std::string_view::npos) {
|
||||
pos = start;
|
||||
pos = version_eol;
|
||||
} else {
|
||||
++pos;
|
||||
}
|
||||
@@ -722,9 +801,10 @@ std::array<std::string_view, 2> ShaderCompilerService::splitShaderSource(std::st
|
||||
auto eol = source.find('\n', pos) + 1;
|
||||
assert_invariant(eol != std::string_view::npos);
|
||||
|
||||
std::string_view const version = source.substr(start, eol - start);
|
||||
std::string_view const body = source.substr(version.length(), source.length() - version.length());
|
||||
return { version, body };
|
||||
std::string_view const version = source.substr(start, version_eol - start);
|
||||
std::string_view const prolog = source.substr(version_eol, eol - version_eol);
|
||||
std::string_view const body = source.substr(eol, source.length() - eol);
|
||||
return { version, prolog, body };
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -146,7 +146,7 @@ private:
|
||||
|
||||
static std::string_view process_ARB_shading_language_packing(OpenGLContext& context) noexcept;
|
||||
|
||||
static std::array<std::string_view, 2> splitShaderSource(std::string_view source) noexcept;
|
||||
static std::array<std::string_view, 3> splitShaderSource(std::string_view source) noexcept;
|
||||
|
||||
static GLuint linkProgram(OpenGLContext& context,
|
||||
std::array<GLuint, Program::SHADER_TYPE_COUNT> shaders,
|
||||
|
||||
@@ -37,7 +37,7 @@ inline void blitFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect,
|
||||
VulkanAttachment src, VulkanAttachment dst,
|
||||
const VkOffset3D srcRect[2], const VkOffset3D dstRect[2]) {
|
||||
if constexpr (FVK_ENABLED(FVK_DEBUG_BLITTER)) {
|
||||
utils::slog.d << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
|
||||
FVK_LOGD << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
|
||||
<< " layout=" << src.getLayout()
|
||||
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
|
||||
<< " layout=" << dst.getLayout() << utils::io::endl;
|
||||
@@ -76,7 +76,7 @@ inline void blitFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect,
|
||||
inline void resolveFast(const VkCommandBuffer cmdbuffer, VkImageAspectFlags aspect,
|
||||
VulkanAttachment src, VulkanAttachment dst) {
|
||||
if constexpr (FVK_ENABLED(FVK_DEBUG_BLITTER)) {
|
||||
utils::slog.d << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
|
||||
FVK_LOGD << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
|
||||
<< " layout=" << src.getLayout()
|
||||
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
|
||||
<< " layout=" << dst.getLayout() << utils::io::endl;
|
||||
|
||||
@@ -178,7 +178,7 @@ VulkanCommandBuffer& VulkanCommands::get() {
|
||||
// presenting the swap chain or waiting on a fence.
|
||||
while (mAvailableBufferCount == 0) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "VulkanCommands has stalled. "
|
||||
FVK_LOGI << "VulkanCommands has stalled. "
|
||||
<< "If this occurs frequently, consider increasing VK_MAX_COMMAND_BUFFERS."
|
||||
<< io::endl;
|
||||
#endif
|
||||
@@ -289,7 +289,7 @@ bool VulkanCommands::flush() {
|
||||
};
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "Submitting cmdbuffer=" << cmdbuffer
|
||||
FVK_LOGI << "Submitting cmdbuffer=" << cmdbuffer
|
||||
<< " wait=(" << signals[0] << ", " << signals[1] << ") "
|
||||
<< " signal=" << renderingFinished
|
||||
<< " fence=" << currentbuf->fence->fence
|
||||
@@ -305,7 +305,7 @@ bool VulkanCommands::flush() {
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
if (result != VK_SUCCESS) {
|
||||
utils::slog.d << "Failed command buffer submission result: " << result << utils::io::endl;
|
||||
FVK_LOGD << "Failed command buffer submission result: " << result << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
assert_invariant(result == VK_SUCCESS);
|
||||
@@ -320,7 +320,7 @@ VkSemaphore VulkanCommands::acquireFinishedSignal() {
|
||||
VkSemaphore semaphore = mSubmissionSignal;
|
||||
mSubmissionSignal = VK_NULL_HANDLE;
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "Acquiring " << semaphore << " (e.g. for vkQueuePresentKHR)" << io::endl;
|
||||
FVK_LOGI << "Acquiring " << semaphore << " (e.g. for vkQueuePresentKHR)" << io::endl;
|
||||
#endif
|
||||
return semaphore;
|
||||
}
|
||||
@@ -329,7 +329,7 @@ void VulkanCommands::injectDependency(VkSemaphore next) {
|
||||
assert_invariant(mInjectedSignal == VK_NULL_HANDLE);
|
||||
mInjectedSignal = next;
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "Injecting " << next << " (e.g. due to vkAcquireNextImageKHR)" << io::endl;
|
||||
FVK_LOGI << "Injecting " << next << " (e.g. due to vkAcquireNextImageKHR)" << io::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -398,7 +398,7 @@ void VulkanCommands::pushGroupMarker(char const* str, VulkanGroupMarkers::Timest
|
||||
// If the timestamp is not 0, then we are carrying over a marker across buffer submits.
|
||||
// If it is 0, then this is a normal marker push and we should just print debug line as usual.
|
||||
if (timestamp.time_since_epoch().count() == 0.0) {
|
||||
utils::slog.d << "----> " << str << utils::io::endl;
|
||||
FVK_LOGD << "----> " << str << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -436,7 +436,7 @@ void VulkanCommands::popGroupMarker() {
|
||||
auto const [marker, startTime] = mGroupMarkers->pop();
|
||||
auto const endTime = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> diff = endTime - startTime;
|
||||
utils::slog.d << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms"
|
||||
FVK_LOGD << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms"
|
||||
<< utils::io::endl;
|
||||
#else
|
||||
mGroupMarkers->pop();
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_VULKANCONSTANTS_H
|
||||
#define TNT_FILAMENT_BACKEND_VULKANCONSTANTS_H
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// In debug builds, we enable validation layers and set up a debug callback.
|
||||
@@ -70,6 +72,11 @@
|
||||
// the currently active resources.
|
||||
#define FVK_DEBUG_RESOURCE_LEAK 0x00010000
|
||||
|
||||
// Set this to enable logging "only" to one output stream. This is useful in the case where we want
|
||||
// to debug with print statements and want ordered logging (e.g slog.i and slog.e will not appear in
|
||||
// order of calls).
|
||||
#define FVK_DEBUG_FORCE_LOG_TO_I 0x00020000
|
||||
|
||||
// Useful default combinations
|
||||
#define FVK_DEBUG_EVERYTHING 0xFFFFFFFF
|
||||
#define FVK_DEBUG_PERFORMANCE \
|
||||
@@ -133,6 +140,18 @@ static_assert(FVK_ENABLED(FVK_DEBUG_VALIDATION));
|
||||
#define FVK_HANDLE_ARENA_SIZE_IN_MB 8
|
||||
#endif
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_FORCE_LOG_TO_I)
|
||||
#define FVK_LOGI (utils::slog.i)
|
||||
#define FVK_LOGD FVK_LOGI
|
||||
#define FVK_LOGE FVK_LOGI
|
||||
#define FVK_LOGW FVK_LOGI
|
||||
#else
|
||||
#define FVK_LOGE (utils::slog.e)
|
||||
#define FVK_LOGW (utils::slog.w)
|
||||
#define FVK_LOGD (utils::slog.d)
|
||||
#define FVK_LOGI (utils::slog.i)
|
||||
#endif
|
||||
|
||||
// All vkCreate* functions take an optional allocator. For now we select the default allocator by
|
||||
// passing in a null pointer, and we highlight the argument by using the VKALLOC constant.
|
||||
constexpr struct VkAllocationCallbacks* VKALLOC = nullptr;
|
||||
|
||||
@@ -100,7 +100,7 @@ std::tuple<uint32_t, uint32_t> VulkanTimestamps::getNextQuery() {
|
||||
return std::make_tuple(timerIndex * 2, timerIndex * 2 + 1);
|
||||
}
|
||||
}
|
||||
utils::slog.e << "More than " << maxTimers << " timers are not supported." << utils::io::endl;
|
||||
FVK_LOGE << "More than " << maxTimers << " timers are not supported." << utils::io::endl;
|
||||
return std::make_tuple(0, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,10 @@ public:
|
||||
return mDebugUtilsSupported;
|
||||
}
|
||||
|
||||
inline bool isMultiviewEnabled() const noexcept {
|
||||
return mMultiviewEnabled;
|
||||
}
|
||||
|
||||
inline bool isClipDistanceSupported() const noexcept {
|
||||
return mPhysicalDeviceFeatures.shaderClipDistance == VK_TRUE;
|
||||
}
|
||||
@@ -141,6 +145,7 @@ private:
|
||||
VkPhysicalDeviceFeatures mPhysicalDeviceFeatures = {};
|
||||
bool mDebugMarkersSupported = false;
|
||||
bool mDebugUtilsSupported = false;
|
||||
bool mMultiviewEnabled = false;
|
||||
|
||||
VkFormatList mDepthStencilFormats;
|
||||
VkFormatList mBlittableDepthStencilFormats;
|
||||
|
||||
@@ -115,15 +115,15 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallback(VkDebugReportFlagsEXT flags,
|
||||
VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location,
|
||||
int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) {
|
||||
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
|
||||
utils::slog.e << "VULKAN ERROR: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
|
||||
FVK_LOGE << "VULKAN ERROR: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
|
||||
} else {
|
||||
// TODO: emit best practices warnings about aggressive pipeline barriers.
|
||||
if (strstr(pMessage, "ALL_GRAPHICS_BIT") || strstr(pMessage, "ALL_COMMANDS_BIT")) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
utils::slog.w << "VULKAN WARNING: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
|
||||
FVK_LOGW << "VULKAN WARNING: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
|
||||
}
|
||||
utils::slog.e << utils::io::endl;
|
||||
FVK_LOGE << utils::io::endl;
|
||||
return VK_FALSE;
|
||||
}
|
||||
#endif // FVK_EANBLED(FVK_DEBUG_VALIDATION)
|
||||
@@ -133,18 +133,18 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsCallback(VkDebugUtilsMessageSeverityFla
|
||||
VkDebugUtilsMessageTypeFlagsEXT types, const VkDebugUtilsMessengerCallbackDataEXT* cbdata,
|
||||
void* pUserData) {
|
||||
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
|
||||
utils::slog.e << "VULKAN ERROR: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
|
||||
<< utils::io::endl;
|
||||
FVK_LOGE << "VULKAN ERROR: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
|
||||
<< utils::io::endl;
|
||||
} else {
|
||||
// TODO: emit best practices warnings about aggressive pipeline barriers.
|
||||
if (strstr(cbdata->pMessage, "ALL_GRAPHICS_BIT")
|
||||
|| strstr(cbdata->pMessage, "ALL_COMMANDS_BIT")) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
utils::slog.w << "VULKAN WARNING: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
|
||||
<< utils::io::endl;
|
||||
FVK_LOGW << "VULKAN WARNING: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
|
||||
<< utils::io::endl;
|
||||
}
|
||||
utils::slog.e << utils::io::endl;
|
||||
FVK_LOGE << utils::io::endl;
|
||||
return VK_FALSE;
|
||||
}
|
||||
#endif // FVK_EANBLED(FVK_DEBUG_DEBUG_UTILS)
|
||||
@@ -292,7 +292,7 @@ Driver* VulkanDriver::create(VulkanPlatform* platform, VulkanContext const& cont
|
||||
// VulkanRenderTarget : 312 few
|
||||
// -- less than or equal to 312 bytes
|
||||
|
||||
utils::slog.d
|
||||
FVK_LOGD
|
||||
<< "\nVulkanSwapChain: " << sizeof(VulkanSwapChain)
|
||||
<< "\nVulkanBufferObject: " << sizeof(VulkanBufferObject)
|
||||
<< "\nVulkanVertexBuffer: " << sizeof(VulkanVertexBuffer)
|
||||
@@ -660,8 +660,8 @@ void VulkanDriver::createFenceR(Handle<HwFence> fh, int) {
|
||||
|
||||
void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
||||
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
|
||||
utils::slog.w << "sRGB swapchain requested, but Platform does not support it"
|
||||
<< utils::io::endl;
|
||||
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it"
|
||||
<< utils::io::endl;
|
||||
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
|
||||
}
|
||||
auto swapChain = mResourceAllocator.construct<VulkanSwapChain>(sch, mPlatform, mContext,
|
||||
@@ -672,7 +672,7 @@ void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
||||
void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
|
||||
uint32_t height, uint64_t flags) {
|
||||
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
|
||||
utils::slog.w << "sRGB swapchain requested, but Platform does not support it"
|
||||
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it"
|
||||
<< utils::io::endl;
|
||||
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
|
||||
}
|
||||
@@ -914,7 +914,7 @@ bool VulkanDriver::isStereoSupported() {
|
||||
case backend::StereoscopicType::INSTANCED:
|
||||
return mContext.isClipDistanceSupported();
|
||||
case backend::StereoscopicType::MULTIVIEW:
|
||||
// TODO: implement multiview feature in Vulkan.
|
||||
return mContext.isMultiviewEnabled();
|
||||
case backend::StereoscopicType::NONE:
|
||||
return false;
|
||||
}
|
||||
@@ -1862,9 +1862,9 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) {
|
||||
// matching characteristics. (e.g. if the missing texture is a 3D texture)
|
||||
if (UTILS_UNLIKELY(texture->getPrimaryImageLayout() == VulkanLayout::UNDEFINED)) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE) && FVK_ENABLED_DEBUG_SAMPLER_NAME
|
||||
utils::slog.w << "Uninitialized texture bound to '" << bindingToName[binding] << "'";
|
||||
utils::slog.w << " in material '" << program->name.c_str() << "'";
|
||||
utils::slog.w << " at binding point " << +binding << utils::io::endl;
|
||||
FVK_LOGW << "Uninitialized texture bound to '" << bindingToName[binding] << "'";
|
||||
FVK_LOGW << " in material '" << program->name.c_str() << "'";
|
||||
FVK_LOGW << " at binding point " << +binding << utils::io::endl;
|
||||
#endif
|
||||
texture = mEmptyTexture;
|
||||
}
|
||||
@@ -2014,7 +2014,7 @@ void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, cons
|
||||
assert_invariant(inRenderPass);
|
||||
inRenderPass = false;
|
||||
} else if (inRenderPass && OUTSIDE_COMMANDS.find(command) != OUTSIDE_COMMANDS.end()) {
|
||||
utils::slog.e << command.data() << " issued inside a render pass." << utils::io::endl;
|
||||
FVK_LOGE << command.data() << " issued inside a render pass." << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ VkFramebuffer VulkanFboCache::getFramebuffer(FboKey config) noexcept {
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_FBO_CACHE)
|
||||
utils::slog.d << "Creating framebuffer " << config.width << "x" << config.height << " "
|
||||
FVK_LOGD << "Creating framebuffer " << config.width << "x" << config.height << " "
|
||||
<< "for render pass " << config.renderPass << ", "
|
||||
<< "samples = " << int(config.samples) << ", "
|
||||
<< "depth = " << (config.depth ? 1 : 0) << ", "
|
||||
@@ -310,7 +310,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey config) noexcept {
|
||||
mRenderPassCache[config] = {renderPass, mCurrentTime};
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_FBO_CACHE)
|
||||
utils::slog.d << "Created render pass " << renderPass << " with "
|
||||
FVK_LOGD << "Created render pass " << renderPass << " with "
|
||||
<< "samples = " << int(config.samples) << ", "
|
||||
<< "depth = " << (hasDepth ? 1 : 0) << ", "
|
||||
<< "colorAttachmentCount[0] = " << subpasses[0].colorAttachmentCount
|
||||
|
||||
@@ -292,8 +292,8 @@ VulkanProgram::VulkanProgram(VkDevice device, Program const& builder) noexcept
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
utils::slog.d << "Created VulkanProgram " << builder << ", shaders = (" << modules[0]
|
||||
<< ", " << modules[1] << ")" << utils::io::endl;
|
||||
FVK_LOGD << "Created VulkanProgram " << builder << ", shaders = (" << modules[0]
|
||||
<< ", " << modules[1] << ")" << utils::io::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -230,14 +230,15 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
|
||||
PipelineCacheEntry cacheEntry = {};
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
utils::slog.d << "vkCreateGraphicsPipelines with shaders = ("
|
||||
<< shaderStages[0].module << ", " << shaderStages[1].module << ")" << utils::io::endl;
|
||||
FVK_LOGD << "vkCreateGraphicsPipelines with shaders = ("
|
||||
<< shaderStages[0].module << ", " << shaderStages[1].module << ")"
|
||||
<< utils::io::endl;
|
||||
#endif
|
||||
VkResult error = vkCreateGraphicsPipelines(mDevice, VK_NULL_HANDLE, 1, &pipelineCreateInfo,
|
||||
VKALLOC, &cacheEntry.handle);
|
||||
assert_invariant(error == VK_SUCCESS);
|
||||
if (error != VK_SUCCESS) {
|
||||
utils::slog.e << "vkCreateGraphicsPipelines error " << error << utils::io::endl;
|
||||
FVK_LOGE << "vkCreateGraphicsPipelines error " << error << utils::io::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -252,7 +253,7 @@ void VulkanPipelineCache::bindProgram(VulkanProgram* program) noexcept {
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
if (mPipelineRequirements.shaders[0] == VK_NULL_HANDLE ||
|
||||
mPipelineRequirements.shaders[1] == VK_NULL_HANDLE) {
|
||||
utils::slog.e << "Binding missing shader: " << program->name.c_str() << utils::io::endl;
|
||||
FVK_LOGE << "Binding missing shader: " << program->name.c_str() << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -167,9 +167,9 @@ void VulkanReadPixels::run(VulkanRenderTarget* srcTarget, uint32_t const x, uint
|
||||
vkCreateImage(device, &imageInfo, VKALLOC, &stagingImage);
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_READ_PIXELS)
|
||||
utils::slog.d << "readPixels created image=" << stagingImage
|
||||
<< " to copy from image=" << srcTexture->getVkImage()
|
||||
<< " src-layout=" << srcTexture->getLayout(0, 0) << utils::io::endl;
|
||||
FVK_LOGD << "readPixels created image=" << stagingImage
|
||||
<< " to copy from image=" << srcTexture->getVkImage()
|
||||
<< " src-layout=" << srcTexture->getLayout(0, 0) << utils::io::endl;
|
||||
#endif
|
||||
|
||||
VkMemoryRequirements memReqs;
|
||||
@@ -185,7 +185,7 @@ void VulkanReadPixels::run(VulkanRenderTarget* srcTarget, uint32_t const x, uint
|
||||
if (memoryTypeIndex >= VK_MAX_MEMORY_TYPES) {
|
||||
memoryTypeIndex = selectMemoryFunc(memReqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
utils::slog.w
|
||||
FVK_LOGW
|
||||
<< "readPixels is slow because VK_MEMORY_PROPERTY_HOST_CACHED_BIT is not available"
|
||||
<< utils::io::endl;
|
||||
}
|
||||
@@ -303,7 +303,7 @@ void VulkanReadPixels::run(VulkanRenderTarget* srcTarget, uint32_t const x, uint
|
||||
VkResult status = vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
|
||||
// Fence hasn't been reached. Try waiting again.
|
||||
if (status != VK_SUCCESS) {
|
||||
utils::slog.e << "Failed to wait for readPixels fence" << utils::io::endl;
|
||||
FVK_LOGE << "Failed to wait for readPixels fence" << utils::io::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ void VulkanReadPixels::run(VulkanRenderTarget* srcTarget, uint32_t const x, uint
|
||||
getComponentCount(srcFormat), srcPixels,
|
||||
static_cast<int>(subResourceLayout.rowPitch), static_cast<int>(width),
|
||||
static_cast<int>(height), swizzle)) {
|
||||
utils::slog.e << "Unsupported PixelDataFormat or PixelDataType" << utils::io::endl;
|
||||
FVK_LOGE << "Unsupported PixelDataFormat or PixelDataType" << utils::io::endl;
|
||||
}
|
||||
|
||||
vkUnmapMemory(device, stagingMemory);
|
||||
|
||||
@@ -111,11 +111,11 @@ private:
|
||||
#if DEBUG_RESOURCE_LEAKS
|
||||
public:
|
||||
void print() {
|
||||
utils::slog.d << "Resource Allocator state (debug only)" << utils::io::endl;
|
||||
FVK_LOGD << "Resource Allocator state (debug only)" << utils::io::endl;
|
||||
for (size_t i = 0; i < RESOURCE_TYPE_COUNT; i++) {
|
||||
utils::slog.d << "[" << i << "]=" << mDebugOnlyResourceCount[i] << utils::io::endl;
|
||||
FVK_LOGD << "[" << i << "]=" << mDebugOnlyResourceCount[i] << utils::io::endl;
|
||||
}
|
||||
utils::slog.d << "+++++++++++++++++++++++++++++++++++++" << utils::io::endl;
|
||||
FVK_LOGD << "+++++++++++++++++++++++++++++++++++++" << utils::io::endl;
|
||||
}
|
||||
private:
|
||||
utils::FixedCapacityVector<size_t> mDebugOnlyResourceCount;
|
||||
|
||||
@@ -61,7 +61,7 @@ VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) {
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_ALLOCATION)
|
||||
if (result != VK_SUCCESS) {
|
||||
utils::slog.e << "Allocation error: " << result << utils::io::endl;
|
||||
FVK_LOGE << "Allocation error: " << result << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -35,29 +35,13 @@ VulkanSwapChain::VulkanSwapChain(VulkanPlatform* platform, VulkanContext const&
|
||||
mStagePool(stagePool),
|
||||
mHeadless(extent.width != 0 && extent.height != 0 && !nativeWindow),
|
||||
mFlushAndWaitOnResize(platform->getCustomization().flushAndWaitOnWindowResize),
|
||||
mCurrentImageReadyIndex(0),
|
||||
mTransitionSwapChainImageLayoutForPresent(
|
||||
platform->getCustomization().transitionSwapChainImageLayoutForPresent),
|
||||
mAcquired(false),
|
||||
mIsFirstRenderPass(true) {
|
||||
swapChain = mPlatform->createSwapChain(nativeWindow, flags, extent);
|
||||
FILAMENT_CHECK_POSTCONDITION(swapChain) << "Unable to create swapchain";
|
||||
|
||||
VkSemaphoreCreateInfo const createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
};
|
||||
|
||||
// No need to wait on this semaphore before drawing when in Headless mode.
|
||||
if (mHeadless) {
|
||||
// Set all sempahores to VK_NULL_HANDLE
|
||||
memset(mImageReady, 0, sizeof(mImageReady[0]) * IMAGE_READY_SEMAPHORE_COUNT);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < IMAGE_READY_SEMAPHORE_COUNT; ++i) {
|
||||
VkResult result =
|
||||
vkCreateSemaphore(mPlatform->getDevice(), &createInfo, nullptr, mImageReady + i);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "Failed to create semaphore";
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -68,11 +52,6 @@ VulkanSwapChain::~VulkanSwapChain() {
|
||||
mCommands->wait();
|
||||
|
||||
mPlatform->destroy(swapChain);
|
||||
for (uint32_t i = 0; i < IMAGE_READY_SEMAPHORE_COUNT; ++i) {
|
||||
if (mImageReady[i] != VK_NULL_HANDLE) {
|
||||
vkDestroySemaphore(mPlatform->getDevice(), mImageReady[i], VKALLOC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanSwapChain::update() {
|
||||
@@ -95,7 +74,7 @@ void VulkanSwapChain::update() {
|
||||
}
|
||||
|
||||
void VulkanSwapChain::present() {
|
||||
if (!mHeadless) {
|
||||
if (!mHeadless && mTransitionSwapChainImageLayoutForPresent) {
|
||||
VkCommandBuffer const cmdbuf = mCommands->get().buffer();
|
||||
VkImageSubresourceRange const subresources{
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
@@ -106,10 +85,15 @@ void VulkanSwapChain::present() {
|
||||
};
|
||||
mColors[mCurrentSwapIndex]->transitionLayout(cmdbuf, subresources, VulkanLayout::PRESENT);
|
||||
}
|
||||
mCommands->flush();
|
||||
|
||||
// We only present if it is not headless. No-op for headless (but note that we still need the
|
||||
// flush() in the above line).
|
||||
mCommands->flush();
|
||||
|
||||
// call the image ready wait function
|
||||
if (mExplicitImageReadyWait != nullptr) {
|
||||
mExplicitImageReadyWait(swapChain);
|
||||
}
|
||||
|
||||
// We only present if it is not headless. No-op for headless.
|
||||
if (!mHeadless) {
|
||||
VkSemaphore const finishedDrawing = mCommands->acquireFinishedSignal();
|
||||
VkResult const result = mPlatform->present(swapChain, mCurrentSwapIndex, finishedDrawing);
|
||||
@@ -139,13 +123,14 @@ void VulkanSwapChain::acquire(bool& resized) {
|
||||
update();
|
||||
}
|
||||
|
||||
mCurrentImageReadyIndex = (mCurrentImageReadyIndex + 1) % IMAGE_READY_SEMAPHORE_COUNT;
|
||||
const VkSemaphore imageReady = mImageReady[mCurrentImageReadyIndex];
|
||||
VkResult const result = mPlatform->acquire(swapChain, imageReady, &mCurrentSwapIndex);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR)
|
||||
<< "Cannot acquire in swapchain.";
|
||||
if (imageReady != VK_NULL_HANDLE) {
|
||||
mCommands->injectDependency(imageReady);
|
||||
VulkanPlatform::ImageSyncData imageSyncData;
|
||||
VkResult const result = mPlatform->acquire(swapChain, &imageSyncData);
|
||||
mCurrentSwapIndex = imageSyncData.imageIndex;
|
||||
mExplicitImageReadyWait = imageSyncData.explicitImageReadyWait;
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR)
|
||||
<< "Cannot acquire in swapchain.";
|
||||
if (imageSyncData.imageReadySemaphore != VK_NULL_HANDLE) {
|
||||
mCommands->injectDependency(imageSyncData.imageReadySemaphore);
|
||||
}
|
||||
mAcquired = true;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,10 @@ struct VulkanSwapChain : public HwSwapChain, VulkanResource {
|
||||
void acquire(bool& reized);
|
||||
|
||||
inline VulkanTexture* getCurrentColor() const noexcept {
|
||||
return mColors[mCurrentSwapIndex].get();
|
||||
uint32_t const imageIndex = mCurrentSwapIndex;
|
||||
FILAMENT_CHECK_PRECONDITION(
|
||||
imageIndex != VulkanPlatform::ImageSyncData::INVALID_IMAGE_INDEX);
|
||||
return mColors[imageIndex].get();
|
||||
}
|
||||
|
||||
inline VulkanTexture* getDepth() const noexcept {
|
||||
@@ -80,15 +83,15 @@ private:
|
||||
VulkanStagePool& mStagePool;
|
||||
bool const mHeadless;
|
||||
bool const mFlushAndWaitOnResize;
|
||||
bool const mTransitionSwapChainImageLayoutForPresent;
|
||||
|
||||
// We create VulkanTextures based on VkImages. VulkanTexture has facilities for doing layout
|
||||
// transitions, which are useful here.
|
||||
utils::FixedCapacityVector<std::unique_ptr<VulkanTexture>> mColors;
|
||||
std::unique_ptr<VulkanTexture> mDepth;
|
||||
VkExtent2D mExtent;
|
||||
VkSemaphore mImageReady[IMAGE_READY_SEMAPHORE_COUNT];
|
||||
uint32_t mCurrentImageReadyIndex;
|
||||
uint32_t mCurrentSwapIndex;
|
||||
std::function<void(Platform::SwapChain* handle)> mExplicitImageReadyWait = nullptr;
|
||||
bool mAcquired;
|
||||
bool mIsFirstRenderPass;
|
||||
};
|
||||
|
||||
@@ -113,7 +113,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
||||
VkFormatProperties props;
|
||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, mVkFormat, &props);
|
||||
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
|
||||
utils::slog.w << "Texture usage is SAMPLEABLE but format " << mVkFormat << " is not "
|
||||
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << mVkFormat << " is not "
|
||||
"sampleable with optimal tiling." << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
@@ -163,7 +163,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
||||
|
||||
VkResult error = vkCreateImage(mDevice, &imageInfo, VKALLOC, &mTextureImage);
|
||||
if (error || FVK_ENABLED(FVK_DEBUG_TEXTURE)) {
|
||||
utils::slog.d << "vkCreateImage: "
|
||||
FVK_LOGD << "vkCreateImage: "
|
||||
<< "image = " << mTextureImage << ", "
|
||||
<< "result = " << error << ", "
|
||||
<< "handle = " << utils::io::hex << mTextureImage << utils::io::dec << ", "
|
||||
@@ -450,7 +450,7 @@ void VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, const VkImageSubres
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
|
||||
utils::slog.d << "transition texture=" << mTextureImage
|
||||
FVK_LOGD << "transition texture=" << mTextureImage
|
||||
<< " (" << range.baseArrayLayer
|
||||
<< "," << range.baseMipLevel << ")"
|
||||
<< " count=(" << range.layerCount
|
||||
@@ -539,7 +539,7 @@ void VulkanTexture::print() const {
|
||||
layer < (mPrimaryViewRange.baseArrayLayer + mPrimaryViewRange.layerCount) &&
|
||||
level >= mPrimaryViewRange.baseMipLevel &&
|
||||
level < (mPrimaryViewRange.baseMipLevel + mPrimaryViewRange.levelCount);
|
||||
utils::slog.d << "[" << mTextureImage << "]: (" << layer << "," << level
|
||||
FVK_LOGD << "[" << mTextureImage << "]: (" << layer << "," << level
|
||||
<< ")=" << getLayout(layer, level)
|
||||
<< " primary=" << primary
|
||||
<< utils::io::endl;
|
||||
@@ -548,7 +548,7 @@ void VulkanTexture::print() const {
|
||||
|
||||
for (auto view: mCachedImageViews) {
|
||||
auto& range = view.first.range;
|
||||
utils::slog.d << "[" << mTextureImage << ", imageView=" << view.second << "]=>"
|
||||
FVK_LOGD << "[" << mTextureImage << ", imageView=" << view.second << "]=>"
|
||||
<< " (" << range.baseArrayLayer << "," << range.baseMipLevel << ")"
|
||||
<< " count=(" << range.layerCount << "," << range.levelCount << ")"
|
||||
<< " aspect=" << range.aspectMask << " viewType=" << view.first.type
|
||||
|
||||
@@ -95,7 +95,7 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
|
||||
.pNext = &driverProperties,
|
||||
};
|
||||
vkGetPhysicalDeviceProperties2(device, &physicalDeviceProperties2);
|
||||
utils::slog.i << "Vulkan device driver: " << driverProperties.driverName << " "
|
||||
FVK_LOGI << "Vulkan device driver: " << driverProperties.driverName << " "
|
||||
<< driverProperties.driverInfo << utils::io::endl;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
|
||||
const FixedCapacityVector<VkPhysicalDevice> physicalDevices
|
||||
= filament::backend::enumerate(vkEnumeratePhysicalDevices, instance);
|
||||
|
||||
utils::slog.i << "Selected physical device '" << deviceProperties.deviceName << "' from "
|
||||
FVK_LOGI << "Selected physical device '" << deviceProperties.deviceName << "' from "
|
||||
<< physicalDevices.size() << " physical devices. "
|
||||
<< "(vendor " << utils::io::hex << vendorID << ", "
|
||||
<< "device " << deviceID << ", "
|
||||
@@ -142,15 +142,15 @@ void printDepthFormats(VkPhysicalDevice device) {
|
||||
// Note that Vulkan is more constrained than OpenGL ES 3.1 in this area.
|
||||
const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||
| VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
||||
utils::slog.i << "Sampleable depth formats: ";
|
||||
FVK_LOGI << "Sampleable depth formats: ";
|
||||
for (VkFormat format : ALL_VK_FORMATS) {
|
||||
VkFormatProperties props;
|
||||
vkGetPhysicalDeviceFormatProperties(device, format, &props);
|
||||
if ((props.optimalTilingFeatures & required) == required) {
|
||||
utils::slog.i << format << " ";
|
||||
FVK_LOGI << format << " ";
|
||||
}
|
||||
}
|
||||
utils::slog.i << utils::io::endl;
|
||||
FVK_LOGI << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -198,6 +198,7 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
||||
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
|
||||
VK_KHR_MAINTENANCE2_EXTENSION_NAME,
|
||||
VK_KHR_MAINTENANCE3_EXTENSION_NAME,
|
||||
VK_KHR_MULTIVIEW_EXTENSION_NAME,
|
||||
};
|
||||
ExtensionSet exts;
|
||||
// Identify supported physical device extensions
|
||||
@@ -241,11 +242,11 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
||||
instanceCreateInfo.ppEnabledLayerNames = enabledLayers.data();
|
||||
} else {
|
||||
#if defined(__ANDROID__)
|
||||
utils::slog.d << "Validation layers are not available; did you set jniLibs in your "
|
||||
<< "gradle file?" << utils::io::endl;
|
||||
FVK_LOGD << "Validation layers are not available; did you set jniLibs in your "
|
||||
<< "gradle file?" << utils::io::endl;
|
||||
#else
|
||||
utils::slog.d << "Validation layer not available; did you install the Vulkan SDK?\n"
|
||||
<< "Please ensure that VK_LAYER_PATH is set correctly." << utils::io::endl;
|
||||
FVK_LOGD << "Validation layer not available; did you install the Vulkan SDK?\n"
|
||||
<< "Please ensure that VK_LAYER_PATH is set correctly." << utils::io::endl;
|
||||
#endif // __ANDROID__
|
||||
|
||||
}
|
||||
@@ -334,6 +335,7 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
||||
deviceCreateInfo.enabledExtensionCount = (uint32_t) requestExtensions.size();
|
||||
deviceCreateInfo.ppEnabledExtensionNames = requestExtensions.data();
|
||||
|
||||
void* pNext = nullptr;
|
||||
VkPhysicalDevicePortabilitySubsetFeaturesKHR portability = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
|
||||
.pNext = nullptr,
|
||||
@@ -341,9 +343,24 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
||||
.mutableComparisonSamplers = VK_TRUE,
|
||||
};
|
||||
if (setContains(deviceExtensions, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
|
||||
deviceCreateInfo.pNext = &portability;
|
||||
portability.pNext = pNext;
|
||||
pNext = &portability;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceMultiviewFeaturesKHR multiview = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
|
||||
.pNext = nullptr,
|
||||
.multiview = VK_TRUE,
|
||||
.multiviewGeometryShader = VK_FALSE,
|
||||
.multiviewTessellationShader = VK_FALSE
|
||||
};
|
||||
if (setContains(deviceExtensions, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
|
||||
multiview.pNext = pNext;
|
||||
pNext = &multiview;
|
||||
}
|
||||
|
||||
deviceCreateInfo.pNext = pNext;
|
||||
|
||||
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, VKALLOC, &device);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkCreateDevice error=" << result << ".";
|
||||
|
||||
@@ -418,8 +435,8 @@ inline int deviceTypeOrder(VkPhysicalDeviceType deviceType) {
|
||||
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
|
||||
return 1;
|
||||
default:
|
||||
utils::slog.w << "deviceTypeOrder: Unexpected deviceType: " << deviceType
|
||||
<< utils::io::endl;
|
||||
FVK_LOGW << "deviceTypeOrder: Unexpected deviceType: " << deviceType
|
||||
<< utils::io::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -701,6 +718,10 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
||||
= pruneExtensions(mImpl->mPhysicalDevice, instExts, deviceExts);
|
||||
instExts = prunedInstExts;
|
||||
deviceExts = prunedDeviceExts;
|
||||
|
||||
if (driverConfig.stereoscopicType != StereoscopicType::MULTIVIEW) {
|
||||
deviceExts.erase(VK_KHR_MULTIVIEW_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
mImpl->mDevice
|
||||
@@ -716,6 +737,7 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
||||
// Store the extension support in the context
|
||||
context.mDebugUtilsSupported = setContains(instExts, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
context.mDebugMarkersSupported = setContains(deviceExts, VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
||||
context.mMultiviewEnabled = setContains(deviceExts, VK_KHR_MULTIVIEW_EXTENSION_NAME);
|
||||
|
||||
#ifdef NDEBUG
|
||||
// If we are in release build, we should not have turned on debug extensions
|
||||
@@ -750,8 +772,8 @@ VulkanPlatform::SwapChainBundle VulkanPlatform::getSwapChainBundle(SwapChainPtr
|
||||
SWAPCHAIN_RET_FUNC(getSwapChainBundle, handle, )
|
||||
}
|
||||
|
||||
VkResult VulkanPlatform::acquire(SwapChainPtr handle, VkSemaphore clientSignal, uint32_t* index) {
|
||||
SWAPCHAIN_RET_FUNC(acquire, handle, clientSignal, index)
|
||||
VkResult VulkanPlatform::acquire(SwapChainPtr handle, ImageSyncData* outImageSyncData) {
|
||||
SWAPCHAIN_RET_FUNC(acquire, handle, outImageSyncData)
|
||||
}
|
||||
|
||||
VkResult VulkanPlatform::present(SwapChainPtr handle, uint32_t index,
|
||||
|
||||
@@ -133,6 +133,7 @@ VulkanPlatformSurfaceSwapChain::VulkanPlatformSurfaceSwapChain(VulkanContext con
|
||||
VulkanPlatformSurfaceSwapChain::~VulkanPlatformSurfaceSwapChain() {
|
||||
vkDestroySwapchainKHR(mDevice, mSwapchain, VKALLOC);
|
||||
vkDestroySurfaceKHR(mInstance, mSurface, VKALLOC);
|
||||
destroy();
|
||||
}
|
||||
|
||||
VkResult VulkanPlatformSurfaceSwapChain::create() {
|
||||
@@ -153,7 +154,7 @@ VkResult VulkanPlatformSurfaceSwapChain::create() {
|
||||
// the number of images, though there may be limits related to the total amount of memory used
|
||||
// by presentable images."
|
||||
if (maxImageCount != 0 && desiredImageCount > maxImageCount) {
|
||||
utils::slog.e << "Swap chain does not support " << desiredImageCount << " images."
|
||||
FVK_LOGE << "Swap chain does not support " << desiredImageCount << " images."
|
||||
<< utils::io::endl;
|
||||
desiredImageCount = caps.minImageCount;
|
||||
}
|
||||
@@ -246,7 +247,7 @@ VkResult VulkanPlatformSurfaceSwapChain::create() {
|
||||
selectDepthFormat(mContext.getAttachmentDepthStencilFormats(), mHasStencil);
|
||||
mSwapChainBundle.depth = createImage(mSwapChainBundle.extent, mSwapChainBundle.depthFormat);
|
||||
|
||||
slog.i << "vkCreateSwapchain"
|
||||
FVK_LOGI << "vkCreateSwapchain"
|
||||
<< ": " << mSwapChainBundle.extent.width << "x" << mSwapChainBundle.extent.height << ", "
|
||||
<< surfaceFormat.format << ", " << surfaceFormat.colorSpace << ", "
|
||||
<< "swapchain-size=" << mSwapChainBundle.colors.size() << ", "
|
||||
@@ -254,19 +255,29 @@ VkResult VulkanPlatformSurfaceSwapChain::create() {
|
||||
<< "depth=" << mSwapChainBundle.depthFormat
|
||||
<< io::endl;
|
||||
|
||||
VkSemaphoreCreateInfo const semaphoreCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < IMAGE_READY_SEMAPHORE_COUNT; ++i) {
|
||||
VkResult result = vkCreateSemaphore(mDevice, &semaphoreCreateInfo, nullptr,
|
||||
mImageReady + i);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Failed to create semaphore";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VkResult VulkanPlatformSurfaceSwapChain::acquire(VkSemaphore clientSignal, uint32_t* index) {
|
||||
// This immediately retrieves the index of the next available presentable image, and
|
||||
// asynchronously requests the GPU to trigger the "imageAvailable" semaphore.
|
||||
VkResult result = vkAcquireNextImageKHR(mDevice, mSwapchain, UINT64_MAX, clientSignal,
|
||||
VK_NULL_HANDLE, index);
|
||||
VkResult VulkanPlatformSurfaceSwapChain::acquire(VulkanPlatform::ImageSyncData* outImageSyncData) {
|
||||
mCurrentImageReadyIndex = (mCurrentImageReadyIndex + 1) % IMAGE_READY_SEMAPHORE_COUNT;
|
||||
outImageSyncData->imageReadySemaphore = mImageReady[mCurrentImageReadyIndex];
|
||||
VkResult result = vkAcquireNextImageKHR(mDevice, mSwapchain, UINT64_MAX,
|
||||
outImageSyncData->imageReadySemaphore, VK_NULL_HANDLE, &outImageSyncData->imageIndex);
|
||||
|
||||
// Users should be notified of a suboptimal surface, but it should not cause a cascade of
|
||||
// log messages or a loop of re-creations.
|
||||
if (result == VK_SUBOPTIMAL_KHR && !mSuboptimal) {
|
||||
slog.w << "Vulkan Driver: Suboptimal swap chain." << io::endl;
|
||||
FVK_LOGW << "Vulkan Driver: Suboptimal swap chain." << io::endl;
|
||||
mSuboptimal = true;
|
||||
}
|
||||
return result;
|
||||
@@ -288,7 +299,7 @@ VkResult VulkanPlatformSurfaceSwapChain::present(uint32_t index, VkSemaphore fin
|
||||
// On Android Q and above, a suboptimal surface is always reported after screen rotation:
|
||||
// https://android-developers.googleblog.com/2020/02/handling-device-orientation-efficiently.html
|
||||
if (result == VK_SUBOPTIMAL_KHR && !mSuboptimal) {
|
||||
utils::slog.w << "Vulkan Driver: Suboptimal swap chain." << utils::io::endl;
|
||||
FVK_LOGW << "Vulkan Driver: Suboptimal swap chain." << utils::io::endl;
|
||||
mSuboptimal = true;
|
||||
}
|
||||
return result;
|
||||
@@ -312,6 +323,17 @@ VkResult VulkanPlatformSurfaceSwapChain::recreate() {
|
||||
return create();
|
||||
}
|
||||
|
||||
void VulkanPlatformSurfaceSwapChain::destroy() {
|
||||
VulkanPlatformSwapChainImpl::destroy();
|
||||
|
||||
for (uint32_t i = 0; i < IMAGE_READY_SEMAPHORE_COUNT; ++i) {
|
||||
if (mImageReady[i] != VK_NULL_HANDLE) {
|
||||
vkDestroySemaphore(mDevice, mImageReady[i], VKALLOC);
|
||||
mImageReady[i] = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VulkanPlatformHeadlessSwapChain::VulkanPlatformHeadlessSwapChain(VulkanContext const& context,
|
||||
VkDevice device, VkQueue queue, VkExtent2D extent, uint64_t flags)
|
||||
: VulkanPlatformSwapChainImpl(context, device, queue),
|
||||
@@ -343,8 +365,8 @@ VkResult VulkanPlatformHeadlessSwapChain::present(uint32_t index, VkSemaphore fi
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult VulkanPlatformHeadlessSwapChain::acquire(VkSemaphore clientSignal, uint32_t* index) {
|
||||
*index = mCurrentIndex;
|
||||
VkResult VulkanPlatformHeadlessSwapChain::acquire(VulkanPlatform::ImageSyncData* outImageSyncData) {
|
||||
outImageSyncData->imageIndex = mCurrentIndex;
|
||||
mCurrentIndex = (mCurrentIndex + 1) % HEADLESS_SWAPCHAIN_SIZE;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ struct VulkanPlatformSwapChainImpl : public Platform::SwapChain {
|
||||
~VulkanPlatformSwapChainImpl();
|
||||
|
||||
// Non-virtual override-able method
|
||||
VkResult acquire(VkSemaphore clientSignal, uint32_t* index) {
|
||||
VkResult acquire(VulkanPlatform::ImageSyncData* outImageSyncData) {
|
||||
PANIC_PRECONDITION("Should not be called");
|
||||
return VK_ERROR_UNKNOWN;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ struct VulkanPlatformSurfaceSwapChain : public VulkanPlatformSwapChainImpl {
|
||||
~VulkanPlatformSurfaceSwapChain();
|
||||
|
||||
// Non-virtual override
|
||||
VkResult acquire(VkSemaphore clientSignal, uint32_t* index);
|
||||
VkResult acquire(VulkanPlatform::ImageSyncData* outImageSyncData);
|
||||
|
||||
// Non-virtual override
|
||||
VkResult present(uint32_t index, VkSemaphore finished);
|
||||
@@ -97,7 +97,13 @@ struct VulkanPlatformSurfaceSwapChain : public VulkanPlatformSwapChainImpl {
|
||||
// Non-virtual override-able method
|
||||
bool hasResized();
|
||||
|
||||
protected:
|
||||
// Non-virtual override-able method
|
||||
void destroy();
|
||||
|
||||
private:
|
||||
static constexpr int IMAGE_READY_SEMAPHORE_COUNT = FVK_MAX_COMMAND_BUFFERS;
|
||||
|
||||
VkResult create();
|
||||
|
||||
VkInstance mInstance;
|
||||
@@ -106,6 +112,8 @@ private:
|
||||
VkSurfaceKHR mSurface;
|
||||
VkSwapchainKHR mSwapchain = VK_NULL_HANDLE;
|
||||
VkExtent2D const mFallbackExtent;
|
||||
VkSemaphore mImageReady[IMAGE_READY_SEMAPHORE_COUNT];
|
||||
uint32_t mCurrentImageReadyIndex;
|
||||
|
||||
bool mUsesRGB = false;
|
||||
bool mHasStencil = false;
|
||||
@@ -121,7 +129,7 @@ struct VulkanPlatformHeadlessSwapChain : public VulkanPlatformSwapChainImpl {
|
||||
~VulkanPlatformHeadlessSwapChain();
|
||||
|
||||
// Non-virtual override
|
||||
VkResult acquire(VkSemaphore clientSignal, uint32_t* index);
|
||||
VkResult acquire(VulkanPlatform::ImageSyncData* outImageSyncData);
|
||||
|
||||
// Non-virtual override
|
||||
VkResult present(uint32_t index, VkSemaphore finished);
|
||||
|
||||
@@ -298,6 +298,24 @@ public:
|
||||
*/
|
||||
size_t textureUseAfterFreePoolSize = 0;
|
||||
|
||||
/**
|
||||
* When uploading vertex or index data, the Filament Metal backend copies data
|
||||
* into a shared staging area before transferring it to the GPU. This setting controls
|
||||
* the total size of the buffer used to perform these allocations.
|
||||
*
|
||||
* Higher values can improve performance when performing many uploads across a small
|
||||
* number of frames.
|
||||
*
|
||||
* This buffer remains alive throughout the lifetime of the Engine, so this size adds to the
|
||||
* memory footprint of the app and should be set as conservative as possible.
|
||||
*
|
||||
* A value of 0 disables the shared staging buffer entirely; uploads will acquire an
|
||||
* individual buffer from a pool of shared buffers.
|
||||
*
|
||||
* Only respected by the Metal backend.
|
||||
*/
|
||||
size_t metalUploadBufferSizeBytes = 512 * 1024;
|
||||
|
||||
/**
|
||||
* Set to `true` to forcibly disable parallel shader compilation in the backend.
|
||||
* Currently only honored by the GL and Metal backends.
|
||||
@@ -1021,6 +1039,21 @@ public:
|
||||
void resetBackendState() noexcept;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get the current time. This is a convenience function that simply returns the
|
||||
* time in nanosecond since epoch of std::chrono::steady_clock.
|
||||
* A possible implementation is:
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* return std::chrono::steady_clock::now().time_since_epoch().count();
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* @return current time in nanosecond since epoch of std::chrono::steady_clock.
|
||||
* @see Renderer::beginFrame()
|
||||
*/
|
||||
static uint64_t getSteadyClockTimeNano() noexcept;
|
||||
|
||||
|
||||
DebugRegistry& getDebugRegistry() noexcept;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -158,6 +158,8 @@ public:
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*
|
||||
* @see Material::Builder::sphericalHarmonicsBandCount()
|
||||
*
|
||||
* @note
|
||||
* Because the coefficients are pre-scaled, `sh[0]` is the environment's
|
||||
* average irradiance.
|
||||
|
||||
@@ -140,6 +140,18 @@ public:
|
||||
return constant(name, strlen(name), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the quality of the indirect lights computations. This is only taken into account
|
||||
* if this material is lit and in the surface domain. This setting will affect the
|
||||
* IndirectLight computation if one is specified on the Scene and Spherical Harmonics
|
||||
* are used for the irradiance.
|
||||
*
|
||||
* @param shBandCount Number of spherical harmonic bands. Must be 1, 2 or 3 (default).
|
||||
* @return Reference to this Builder for chaining calls.
|
||||
* @see IndirectLight
|
||||
*/
|
||||
Builder& sphericalHarmonicsBandCount(size_t shBandCount) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the Material object and returns a pointer to it.
|
||||
*
|
||||
|
||||
@@ -140,6 +140,7 @@ public:
|
||||
* @param values Array of values to set to the named parameter array.
|
||||
* @param count Size of the array to set.
|
||||
* @throws utils::PreConditionPanic if name doesn't exist or no-op if exceptions are disabled.
|
||||
* @see Material::hasParameter
|
||||
*/
|
||||
template<typename T, typename = is_supported_parameter_t<T>>
|
||||
void setParameter(const char* UTILS_NONNULL name, size_t nameLength,
|
||||
@@ -234,6 +235,32 @@ public:
|
||||
setParameter(name, strlen(name), type, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
T getParameter(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_parameter_t<T>>
|
||||
inline T getParameter(StringLiteral name) const {
|
||||
return getParameter<T>(name.data, name.size);
|
||||
}
|
||||
|
||||
/** inline helper to provide the name as a null-terminated C string */
|
||||
template<typename T, typename = is_supported_parameter_t<T>>
|
||||
inline T getParameter(const char* UTILS_NONNULL name) const {
|
||||
return getParameter<T>(name, strlen(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set-up a custom scissor rectangle; by default it is disabled.
|
||||
*
|
||||
|
||||
@@ -227,6 +227,17 @@ public:
|
||||
static constexpr CopyFrameFlag CLEAR = 0x4;
|
||||
|
||||
|
||||
/**
|
||||
* The use of this method is optional. It sets the VSYNC time expressed as the duration in
|
||||
* nanosecond since epoch of std::chrono::steady_clock.
|
||||
* If called, passing 0 to vsyncSteadyClockTimeNano in Renderer::BeginFrame will use this
|
||||
* time instead.
|
||||
* @param steadyClockTimeNano duration in nanosecond since epoch of std::chrono::steady_clock
|
||||
* @see Engine::getSteadyClockTimeNano()
|
||||
* @see Renderer::BeginFrame()
|
||||
*/
|
||||
void setVsyncTime(uint64_t steadyClockTimeNano) noexcept;
|
||||
|
||||
/**
|
||||
* Set-up a frame for this Renderer.
|
||||
*
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -361,7 +363,7 @@ const Engine::Config& Engine::getConfig() const noexcept {
|
||||
return downcast(this)->getConfig();
|
||||
}
|
||||
|
||||
bool Engine::isStereoSupported(StereoscopicType stereoscopicType) const noexcept {
|
||||
bool Engine::isStereoSupported(StereoscopicType) const noexcept {
|
||||
return downcast(this)->isStereoSupported();
|
||||
}
|
||||
|
||||
@@ -369,6 +371,10 @@ size_t Engine::getMaxStereoscopicEyes() noexcept {
|
||||
return FEngine::getMaxStereoscopicEyes();
|
||||
}
|
||||
|
||||
uint64_t Engine::getSteadyClockTimeNano() noexcept {
|
||||
return std::chrono::steady_clock::now().time_since_epoch().count();
|
||||
}
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
void Engine::resetBackendState() noexcept {
|
||||
downcast(this)->resetBackendState();
|
||||
|
||||
@@ -183,6 +183,35 @@ template UTILS_PUBLIC void MaterialInstance::setParameter<mat4f> (const char*
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
T FMaterialInstance::getParameterImpl(std::string_view name) const {
|
||||
ssize_t offset = mMaterial->getUniformInterfaceBlock().getFieldOffset(name, 0);
|
||||
assert_invariant(offset>=0);
|
||||
return downcast(this)->getUniformBuffer().getUniform<T>(offset);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T MaterialInstance::getParameter(const char* name, size_t nameLength) const {
|
||||
return downcast(this)->getParameterImpl<T>({ name, nameLength });
|
||||
}
|
||||
|
||||
// explicit template instantiation of our supported types
|
||||
template UTILS_PUBLIC float MaterialInstance::getParameter<float> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC int32_t MaterialInstance::getParameter<int32_t> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC uint32_t MaterialInstance::getParameter<uint32_t>(const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC int2 MaterialInstance::getParameter<int2> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC int3 MaterialInstance::getParameter<int3> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC int4 MaterialInstance::getParameter<int4> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC uint2 MaterialInstance::getParameter<uint2> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC uint3 MaterialInstance::getParameter<uint3> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC uint4 MaterialInstance::getParameter<uint4> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC float2 MaterialInstance::getParameter<float2> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC float3 MaterialInstance::getParameter<float3> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC float4 MaterialInstance::getParameter<float4> (const char* name, size_t nameLength) const;
|
||||
template UTILS_PUBLIC mat3f MaterialInstance::getParameter<mat3f> (const char* name, size_t nameLength) const;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
Material const* MaterialInstance::getMaterial() const noexcept {
|
||||
return downcast(this)->getMaterial();
|
||||
}
|
||||
|
||||
@@ -89,4 +89,8 @@ void Renderer::renderStandaloneView(View const* view) {
|
||||
downcast(this)->renderStandaloneView(downcast(view));
|
||||
}
|
||||
|
||||
void Renderer::setVsyncTime(uint64_t steadyClockTimeNano) noexcept {
|
||||
downcast(this)->setVsyncTime(steadyClockTimeNano);
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -102,6 +102,7 @@ Engine* FEngine::create(Engine::Builder const& builder) {
|
||||
DriverConfig const driverConfig{
|
||||
.handleArenaSize = instance->getRequestedDriverHandleArenaSize(),
|
||||
.textureUseAfterFreePoolSize = instance->getConfig().textureUseAfterFreePoolSize,
|
||||
.metalUploadBufferSizeBytes = instance->getConfig().metalUploadBufferSizeBytes,
|
||||
.disableParallelShaderCompile = instance->getConfig().disableParallelShaderCompile,
|
||||
.disableHandleUseAfterFreeCheck = instance->getConfig().disableHandleUseAfterFreeCheck,
|
||||
.forceGLES2Context = instance->getConfig().forceGLES2Context,
|
||||
@@ -678,6 +679,7 @@ int FEngine::loop() {
|
||||
DriverConfig const driverConfig {
|
||||
.handleArenaSize = getRequestedDriverHandleArenaSize(),
|
||||
.textureUseAfterFreePoolSize = mConfig.textureUseAfterFreePoolSize,
|
||||
.metalUploadBufferSizeBytes = mConfig.metalUploadBufferSizeBytes,
|
||||
.disableParallelShaderCompile = mConfig.disableParallelShaderCompile,
|
||||
.disableHandleUseAfterFreeCheck = mConfig.disableHandleUseAfterFreeCheck,
|
||||
.forceGLES2Context = mConfig.forceGLES2Context,
|
||||
|
||||
@@ -119,6 +119,7 @@ struct Material::BuilderDetails {
|
||||
const void* mPayload = nullptr;
|
||||
size_t mSize = 0;
|
||||
bool mDefaultMaterial = false;
|
||||
int32_t mShBandsCount = 3;
|
||||
std::unordered_map<
|
||||
utils::CString,
|
||||
std::variant<int32_t, float, bool>,
|
||||
@@ -143,6 +144,11 @@ Material::Builder& Material::Builder::package(const void* payload, size_t size)
|
||||
return *this;
|
||||
}
|
||||
|
||||
Material::Builder& Material::Builder::sphericalHarmonicsBandCount(size_t shBandCount) noexcept {
|
||||
mImpl->mShBandsCount = math::clamp(shBandCount, size_t(1), size_t(3));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename>
|
||||
Material::Builder& Material::Builder::constant(const char* name, size_t nameLength, T value) {
|
||||
FILAMENT_CHECK_PRECONDITION(name != nullptr) << "name cannot be null";
|
||||
@@ -897,6 +903,8 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Material::Builde
|
||||
mSpecializationConstants.push_back({
|
||||
+ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT,
|
||||
(int)engine.getConfig().stereoscopicEyeCount });
|
||||
mSpecializationConstants.push_back({
|
||||
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT, builder->mShBandsCount });
|
||||
if (UTILS_UNLIKELY(parser->getShaderLanguage() == ShaderLanguage::ESSL1)) {
|
||||
// The actual value of this spec-constant is set in the OpenGLDriver backend.
|
||||
mSpecializationConstants.push_back({
|
||||
|
||||
@@ -231,6 +231,9 @@ private:
|
||||
void setParameterImpl(std::string_view name,
|
||||
FTexture const* texture, TextureSampler const& sampler);
|
||||
|
||||
template<typename T>
|
||||
T getParameterImpl(std::string_view name) const;
|
||||
|
||||
// initialize the default instance
|
||||
FMaterialInstance(FEngine& engine, FMaterial const* material) noexcept;
|
||||
|
||||
|
||||
@@ -232,6 +232,10 @@ void FRenderer::setPresentationTime(int64_t monotonic_clock_ns) {
|
||||
driver.setPresentationTime(monotonic_clock_ns);
|
||||
}
|
||||
|
||||
void FRenderer::setVsyncTime(uint64_t steadyClockTimeNano) noexcept {
|
||||
mVsyncSteadyClockTimeNano = steadyClockTimeNano;
|
||||
}
|
||||
|
||||
bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano) {
|
||||
assert_invariant(swapChain);
|
||||
|
||||
@@ -252,6 +256,11 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!vsyncSteadyClockTimeNano) {
|
||||
vsyncSteadyClockTimeNano = mVsyncSteadyClockTimeNano;
|
||||
mVsyncSteadyClockTimeNano = 0;
|
||||
}
|
||||
|
||||
// get the timestamp as soon as possible
|
||||
using namespace std::chrono;
|
||||
const steady_clock::time_point now{ steady_clock::now() };
|
||||
|
||||
@@ -29,9 +29,6 @@
|
||||
|
||||
#include "backend/DriverApiForward.h"
|
||||
|
||||
#include <fg/FrameGraphId.h>
|
||||
#include <fg/FrameGraphTexture.h>
|
||||
|
||||
#include <filament/Renderer.h>
|
||||
#include <filament/Viewport.h>
|
||||
|
||||
@@ -41,8 +38,18 @@
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Allocator.h>
|
||||
|
||||
#include <math/vec4.h>
|
||||
|
||||
#include <tsl/robin_set.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
namespace backend {
|
||||
@@ -78,6 +85,8 @@ public:
|
||||
|
||||
void setPresentationTime(int64_t monotonic_clock_ns);
|
||||
|
||||
void setVsyncTime(uint64_t steadyClockTimeNano) noexcept;
|
||||
|
||||
// start a frame
|
||||
bool beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeNano);
|
||||
|
||||
@@ -187,6 +196,7 @@ private:
|
||||
backend::TargetBufferFlags mClearFlags{};
|
||||
tsl::robin_set<FRenderTarget*> mPreviousRenderTargets;
|
||||
std::function<void()> mBeginFrameInternal;
|
||||
uint64_t mVsyncSteadyClockTimeNano = 0;
|
||||
};
|
||||
|
||||
FILAMENT_DOWNCAST(Renderer)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.53.0"
|
||||
spec.version = "1.53.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.53.0/filament-v1.53.0-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.53.1/filament-v1.53.1-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -203,7 +203,7 @@ enum class ReflectionMode : uint8_t {
|
||||
// can't really use std::underlying_type<AttributeIndex>::type because the driver takes a uint32_t
|
||||
using AttributeBitset = utils::bitset32;
|
||||
|
||||
static constexpr size_t MATERIAL_PROPERTIES_COUNT = 27;
|
||||
static constexpr size_t MATERIAL_PROPERTIES_COUNT = 29;
|
||||
enum class Property : uint8_t {
|
||||
BASE_COLOR, //!< float4, all shading models
|
||||
ROUGHNESS, //!< float, lit shading models only
|
||||
@@ -232,6 +232,8 @@ enum class Property : uint8_t {
|
||||
IOR, //!< float, material's index of refraction
|
||||
MICRO_THICKNESS, //!< float, thickness of the thin layer
|
||||
BENT_NORMAL, //!< float3, all shading models only, except unlit
|
||||
SPECULAR_FACTOR, //!< float, lit shading models only, except subsurface and cloth
|
||||
SPECULAR_COLOR_FACTOR, //!< float3, lit shading models only, except subsurface and cloth
|
||||
|
||||
// when adding new Properties, make sure to update MATERIAL_PROPERTIES_COUNT
|
||||
};
|
||||
|
||||
@@ -70,6 +70,7 @@ enum class ReservedSpecializationConstants : uint8_t {
|
||||
CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP = 6,
|
||||
CONFIG_DEBUG_FROXEL_VISUALIZATION = 7,
|
||||
CONFIG_STEREO_EYE_COUNT = 8, // don't change (hardcoded in ShaderCompilerService.cpp)
|
||||
CONFIG_SH_BANDS_COUNT = 9
|
||||
};
|
||||
|
||||
enum class PushConstantIds : uint8_t {
|
||||
|
||||
+28
-26
@@ -21,33 +21,35 @@
|
||||
namespace filamat {
|
||||
|
||||
std::unordered_map<std::string, Property> Enums::mStringToProperty = {
|
||||
{ "baseColor", Property::BASE_COLOR },
|
||||
{ "roughness", Property::ROUGHNESS },
|
||||
{ "metallic", Property::METALLIC },
|
||||
{ "reflectance", Property::REFLECTANCE },
|
||||
{ "ambientOcclusion", Property::AMBIENT_OCCLUSION },
|
||||
{ "clearCoat", Property::CLEAR_COAT },
|
||||
{ "clearCoatRoughness", Property::CLEAR_COAT_ROUGHNESS },
|
||||
{ "clearCoatNormal", Property::CLEAR_COAT_NORMAL },
|
||||
{ "anisotropy", Property::ANISOTROPY },
|
||||
{ "anisotropyDirection", Property::ANISOTROPY_DIRECTION },
|
||||
{ "thickness", Property::THICKNESS },
|
||||
{ "subsurfacePower", Property::SUBSURFACE_POWER },
|
||||
{ "subsurfaceColor", Property::SUBSURFACE_COLOR },
|
||||
{ "sheenColor", Property::SHEEN_COLOR },
|
||||
{ "sheenRoughness", Property::SHEEN_ROUGHNESS },
|
||||
{ "glossiness", Property::GLOSSINESS },
|
||||
{ "specularColor", Property::SPECULAR_COLOR },
|
||||
{ "emissive", Property::EMISSIVE },
|
||||
{ "normal", Property::NORMAL },
|
||||
{ "postLightingColor", Property::POST_LIGHTING_COLOR },
|
||||
{ "baseColor", Property::BASE_COLOR },
|
||||
{ "roughness", Property::ROUGHNESS },
|
||||
{ "metallic", Property::METALLIC },
|
||||
{ "reflectance", Property::REFLECTANCE },
|
||||
{ "ambientOcclusion", Property::AMBIENT_OCCLUSION },
|
||||
{ "clearCoat", Property::CLEAR_COAT },
|
||||
{ "clearCoatRoughness", Property::CLEAR_COAT_ROUGHNESS },
|
||||
{ "clearCoatNormal", Property::CLEAR_COAT_NORMAL },
|
||||
{ "anisotropy", Property::ANISOTROPY },
|
||||
{ "anisotropyDirection", Property::ANISOTROPY_DIRECTION },
|
||||
{ "thickness", Property::THICKNESS },
|
||||
{ "subsurfacePower", Property::SUBSURFACE_POWER },
|
||||
{ "subsurfaceColor", Property::SUBSURFACE_COLOR },
|
||||
{ "sheenColor", Property::SHEEN_COLOR },
|
||||
{ "sheenRoughness", Property::SHEEN_ROUGHNESS },
|
||||
{ "glossiness", Property::GLOSSINESS },
|
||||
{ "specularColor", Property::SPECULAR_COLOR },
|
||||
{ "emissive", Property::EMISSIVE },
|
||||
{ "normal", Property::NORMAL },
|
||||
{ "postLightingColor", Property::POST_LIGHTING_COLOR },
|
||||
{ "postLightingMixFactor", Property::POST_LIGHTING_MIX_FACTOR },
|
||||
{ "clipSpaceTransform", Property::CLIP_SPACE_TRANSFORM },
|
||||
{ "absorption", Property::ABSORPTION },
|
||||
{ "transmission", Property::TRANSMISSION },
|
||||
{ "ior", Property::IOR },
|
||||
{ "microThickness", Property::MICRO_THICKNESS },
|
||||
{ "bentNormal", Property::BENT_NORMAL },
|
||||
{ "clipSpaceTransform", Property::CLIP_SPACE_TRANSFORM },
|
||||
{ "absorption", Property::ABSORPTION },
|
||||
{ "transmission", Property::TRANSMISSION },
|
||||
{ "ior", Property::IOR },
|
||||
{ "microThickness", Property::MICRO_THICKNESS },
|
||||
{ "bentNormal", Property::BENT_NORMAL },
|
||||
{ "specularFactor", Property::SPECULAR_FACTOR },
|
||||
{ "specularColorFactor", Property::SPECULAR_COLOR_FACTOR }
|
||||
};
|
||||
|
||||
template <>
|
||||
|
||||
@@ -332,6 +332,9 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
|
||||
generateSpecializationConstant(out, "CONFIG_STEREO_EYE_COUNT",
|
||||
+ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT, material.stereoscopicEyeCount);
|
||||
|
||||
generateSpecializationConstant(out, "CONFIG_SH_BANDS_COUNT",
|
||||
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT, 3);
|
||||
|
||||
// CONFIG_MAX_STEREOSCOPIC_EYES is used to size arrays and on Adreno GPUs + vulkan, this has to
|
||||
// be explicitly, statically defined (as in #define). Otherwise (using const int for
|
||||
// example), we'd run into a GPU crash.
|
||||
@@ -1189,6 +1192,8 @@ char const* CodeGenerator::getConstantName(MaterialBuilder::Property property) n
|
||||
case Property::IOR: return "IOR";
|
||||
case Property::MICRO_THICKNESS: return "MICRO_THICKNESS";
|
||||
case Property::BENT_NORMAL: return "BENT_NORMAL";
|
||||
case Property::SPECULAR_FACTOR: return "SPECULAR_FACTOR";
|
||||
case Property::SPECULAR_COLOR_FACTOR: return "SPECULAR_COLOR_FACTOR";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,6 +147,9 @@ build_ubershader(volume_opaque volume lit opaque)
|
||||
build_ubershader(volume_fade volume lit fade)
|
||||
build_ubershader(volume_masked volume lit masked)
|
||||
build_ubershader(sheen sheen _ _)
|
||||
build_ubershader(specular_opaque specular lit opaque)
|
||||
build_ubershader(specular_fade specular lit fade)
|
||||
build_ubershader(specular_masked specular lit masked)
|
||||
|
||||
add_custom_target(uberz_file DEPENDS ${UBERZ_OUTPUT_PATH})
|
||||
set_target_properties(uberz_file PROPERTIES FOLDER Libs)
|
||||
|
||||
@@ -93,10 +93,17 @@ struct alignas(4) MaterialKey {
|
||||
bool hasSheen : 1;
|
||||
bool hasIOR : 1;
|
||||
bool hasVolume : 1;
|
||||
uint8_t padding : 5;
|
||||
bool hasSpecular : 1;
|
||||
bool hasSpecularTexture : 1;
|
||||
bool hasSpecularColorTexture : 1;
|
||||
bool padding : 2;
|
||||
// -- 32 bit boundary --
|
||||
uint8_t specularTextureUV;
|
||||
uint8_t specularColorTextureUV;
|
||||
uint16_t padding2;
|
||||
};
|
||||
|
||||
static_assert(sizeof(MaterialKey) == 16, "MaterialKey has unexpected size.");
|
||||
static_assert(sizeof(MaterialKey) == 20, "MaterialKey has unexpected size.");
|
||||
|
||||
UTILS_WARNING_POP
|
||||
|
||||
|
||||
@@ -30,3 +30,8 @@ TransmissionTexture = unsupported
|
||||
# Volume Features
|
||||
Volume = unsupported
|
||||
VolumeThicknessTexture = unsupported
|
||||
|
||||
# Specular Features
|
||||
Specular = unsupported
|
||||
SpecularTexture = unsupported
|
||||
SpecularColorTexture = unsupported
|
||||
|
||||
@@ -55,7 +55,16 @@ material {
|
||||
{ type : mat3, name : sheenRoughnessUvMatrix, precision: high },
|
||||
|
||||
// Reflectance
|
||||
{ type : float, name : reflectance }
|
||||
{ type : float, name : reflectance },
|
||||
|
||||
// KHR_materials_specular
|
||||
{ type : float, name : specularStrength },
|
||||
{ type : float3, name : specularColorFactor },
|
||||
{ type : int, name : specularIndex },
|
||||
{ type : sampler2d, name : specularMap },
|
||||
{ type : mat3, name : specularUvMatrix, precision: high },
|
||||
{ type : int, name : specularColorIndex },
|
||||
{ type : mat3, name : specularColorUvMatrix, precision: high }
|
||||
|
||||
${CUSTOM_PARAMS}
|
||||
],
|
||||
@@ -136,6 +145,15 @@ fragment {
|
||||
material.emissive.rgb *= texture(materialParams_emissiveMap, uv).rgb;
|
||||
}
|
||||
|
||||
material.specularFactor = materialParams.specularStrength;
|
||||
material.specularColorFactor = materialParams.specularColorFactor;
|
||||
|
||||
if (materialParams.specularIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.specularIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.specularUvMatrix).xy;
|
||||
material.specularFactor *= texture(materialParams_specularMap, uv).a;
|
||||
}
|
||||
|
||||
${CUSTOM_FRAGMENT}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,3 +17,8 @@ TextureTransforms=optional
|
||||
Sheen=optional
|
||||
SheenColorTexture=optional
|
||||
SheenRoughnessTexture=optional
|
||||
|
||||
# KHR_material_specular Features
|
||||
Specular=optional
|
||||
SpecularTexture=optional
|
||||
SpecularColorTexture=unsupported
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
material {
|
||||
name : specular_ubershader,
|
||||
requires : [ uv0, uv1, color ],
|
||||
shadingModel : lit,
|
||||
blending : ${BLENDING},
|
||||
doubleSided : ${DOUBLESIDED},
|
||||
transparency : ${TRANSPARENCY},
|
||||
flipUV : false,
|
||||
specularAmbientOcclusion : simple,
|
||||
specularAntiAliasing : true,
|
||||
clearCoatIorChange : false,
|
||||
reflections: screenspace,
|
||||
parameters : [
|
||||
|
||||
// Base Color
|
||||
{ type : int, name : baseColorIndex },
|
||||
{ type : float4, name : baseColorFactor },
|
||||
{ type : sampler2d, name : baseColorMap },
|
||||
{ type : mat3, name : baseColorUvMatrix, precision: high },
|
||||
|
||||
// Metallic-Roughness Map
|
||||
{ type : int, name : metallicRoughnessIndex },
|
||||
{ type : float, name : metallicFactor },
|
||||
{ type : float, name : roughnessFactor },
|
||||
{ type : sampler2d, name : metallicRoughnessMap },
|
||||
{ type : mat3, name : metallicRoughnessUvMatrix, precision: high },
|
||||
|
||||
// Normal Map
|
||||
{ type : int, name : normalIndex },
|
||||
{ type : float, name : normalScale },
|
||||
{ type : sampler2d, name : normalMap },
|
||||
{ type : mat3, name : normalUvMatrix, precision: high },
|
||||
|
||||
// Ambient Occlusion
|
||||
{ type : int, name : aoIndex },
|
||||
{ type : float, name : aoStrength },
|
||||
{ type : sampler2d, name : occlusionMap },
|
||||
{ type : mat3, name : occlusionUvMatrix, precision: high },
|
||||
|
||||
// Emissive Map
|
||||
{ type : int, name : emissiveIndex },
|
||||
{ type : float3, name : emissiveFactor },
|
||||
{ type : float, name : emissiveStrength },
|
||||
{ type : sampler2d, name : emissiveMap },
|
||||
{ type : mat3, name : emissiveUvMatrix, precision: high },
|
||||
|
||||
// Clear coat, we drop texture support for clear coat due to 8 texture limits.
|
||||
{ type : float, name : clearCoatFactor },
|
||||
{ type : float, name : clearCoatRoughnessFactor },
|
||||
{ type : int, name : clearCoatIndex },
|
||||
{ type : sampler2d, name : clearCoatMap },
|
||||
{ type : mat3, name : clearCoatUvMatrix, precision: high },
|
||||
{ type : int, name : clearCoatRoughnessIndex },
|
||||
{ type : mat3, name : clearCoatRoughnessUvMatrix, precision: high },
|
||||
{ type : int, name : clearCoatNormalIndex },
|
||||
{ type : mat3, name : clearCoatNormalUvMatrix, precision: high },
|
||||
{ type : float, name : clearCoatNormalScale },
|
||||
|
||||
// KHR_materials_specular
|
||||
{ type : float, name : specularStrength },
|
||||
{ type : float3, name : specularColorFactor },
|
||||
{ type : int, name : specularIndex },
|
||||
{ type : sampler2d, name : specularMap },
|
||||
{ type : mat3, name : specularUvMatrix, precision: high },
|
||||
{ type : int, name : specularColorIndex },
|
||||
{ type : sampler2d, name : specularColorMap },
|
||||
{ type : mat3, name : specularColorUvMatrix, precision: high },
|
||||
|
||||
// IOR
|
||||
{ type : float, name : ior }
|
||||
|
||||
${CUSTOM_PARAMS}
|
||||
],
|
||||
}
|
||||
|
||||
vertex {
|
||||
void materialVertex(inout MaterialVertexInputs material) {
|
||||
${CUSTOM_VERTEX}
|
||||
}
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
highp float2 uvs[2];
|
||||
uvs[0] = getUV0();
|
||||
uvs[1] = getUV1();
|
||||
|
||||
if (materialParams.normalIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.normalIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.normalUvMatrix).xy;
|
||||
material.normal = texture(materialParams_normalMap, uv).xyz * 2.0 - 1.0;
|
||||
material.normal.xy *= materialParams.normalScale;
|
||||
}
|
||||
|
||||
prepareMaterial(material);
|
||||
material.baseColor = materialParams.baseColorFactor;
|
||||
|
||||
if (materialParams.baseColorIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.baseColorIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.baseColorUvMatrix).xy;
|
||||
material.baseColor *= texture(materialParams_baseColorMap, uv);
|
||||
}
|
||||
|
||||
#if defined(BLEND_MODE_TRANSPARENT)
|
||||
material.baseColor.rgb *= material.baseColor.a;
|
||||
#endif
|
||||
|
||||
material.baseColor *= getColor();
|
||||
|
||||
material.roughness = materialParams.roughnessFactor;
|
||||
material.metallic = materialParams.metallicFactor;
|
||||
material.ior = materialParams.ior;
|
||||
|
||||
material.emissive = vec4(materialParams.emissiveStrength *
|
||||
materialParams.emissiveFactor.rgb, 0.0);
|
||||
|
||||
// KHR_materials_clearcoat forbids clear coat from
|
||||
// being applied in the specular/glossiness model
|
||||
material.clearCoat = materialParams.clearCoatFactor;
|
||||
material.clearCoatRoughness = materialParams.clearCoatRoughnessFactor;
|
||||
|
||||
if (materialParams.clearCoatIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.clearCoatIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.clearCoatUvMatrix).xy;
|
||||
material.clearCoat *= texture(materialParams_clearCoatMap, uv).r;
|
||||
}
|
||||
|
||||
material.specularFactor = materialParams.specularStrength;
|
||||
material.specularColorFactor = materialParams.specularColorFactor;
|
||||
|
||||
if (materialParams.specularIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.specularIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.specularUvMatrix).xy;
|
||||
material.specularFactor *= texture(materialParams_specularMap, uv).a;
|
||||
}
|
||||
|
||||
if (materialParams.specularColorIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.specularColorIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.specularColorUvMatrix).xy;
|
||||
vec4 sc = texture(materialParams_specularColorMap, uv);
|
||||
material.specularColorFactor.r *= sc.r;
|
||||
material.specularColorFactor.g *= sc.g;
|
||||
material.specularColorFactor.b *= sc.b;
|
||||
}
|
||||
|
||||
if (materialParams.metallicRoughnessIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.metallicRoughnessIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.metallicRoughnessUvMatrix).xy;
|
||||
vec4 mr = texture(materialParams_metallicRoughnessMap, uv);
|
||||
material.roughness *= mr.g;
|
||||
material.metallic *= mr.b;
|
||||
}
|
||||
|
||||
if (materialParams.aoIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.aoIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.occlusionUvMatrix).xy;
|
||||
float occlusion = texture(materialParams_occlusionMap, uv).r;
|
||||
material.ambientOcclusion = 1.0 + materialParams.aoStrength * (occlusion - 1.0);
|
||||
}
|
||||
if (materialParams.emissiveIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.emissiveIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.emissiveUvMatrix).xy;
|
||||
material.emissive.rgb *= texture(materialParams_emissiveMap, uv).rgb;
|
||||
}
|
||||
|
||||
${CUSTOM_FRAGMENT}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
ShadingModel=lit
|
||||
|
||||
# Required Aspects
|
||||
BlendingMode = ${BLENDING}
|
||||
|
||||
VertexColors = optional
|
||||
BaseColorTexture = optional
|
||||
NormalTexture = optional
|
||||
OcclusionTexture = optional
|
||||
EmissiveTexture = optional
|
||||
MetallicRoughnessTexture = optional
|
||||
TextureTransforms = optional
|
||||
|
||||
# KHR_materials_specular Features
|
||||
Specular = optional
|
||||
SpecularTexture = optional
|
||||
SpecularColorTexture = optional
|
||||
|
||||
# ClearCoat Features
|
||||
ClearCoat = optional
|
||||
ClearCoatTexture = optional
|
||||
|
||||
# Sheen Features
|
||||
Sheen = unsupported
|
||||
SheenColorTexture = unsupported
|
||||
SheenRoughnessTexture = unsupported
|
||||
|
||||
# Transmission and IOR Features
|
||||
Transmission = unsupported
|
||||
Ior = optional
|
||||
TransmissionTexture = unsupported
|
||||
|
||||
# Volume Features
|
||||
Volume = unsupported
|
||||
VolumeThicknessTexture = unsupported
|
||||
@@ -52,7 +52,18 @@ material {
|
||||
{ type : mat3, name : transmissionUvMatrix, precision: high },
|
||||
|
||||
// IOR
|
||||
{ type : float, name : ior }
|
||||
{ type : float, name : ior },
|
||||
|
||||
// KHR_materials_specular
|
||||
{ type : float, name : specularStrength },
|
||||
{ type : float3, name : specularColorFactor },
|
||||
{ type : int, name : specularIndex },
|
||||
{ type : sampler2d, name : specularMap },
|
||||
{ type : mat3, name : specularUvMatrix, precision: high },
|
||||
{ type : int, name : specularColorIndex },
|
||||
{ type : sampler2d, name : specularColorMap },
|
||||
{ type : mat3, name : specularColorUvMatrix, precision: high }
|
||||
|
||||
|
||||
${CUSTOM_PARAMS}
|
||||
],
|
||||
@@ -126,6 +137,24 @@ fragment {
|
||||
material.emissive.rgb *= texture(materialParams_emissiveMap, uv).rgb;
|
||||
}
|
||||
|
||||
material.specularFactor = materialParams.specularStrength;
|
||||
material.specularColorFactor = materialParams.specularColorFactor;
|
||||
|
||||
if (materialParams.specularIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.specularIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.specularUvMatrix).xy;
|
||||
material.specularFactor *= texture(materialParams_specularMap, uv).a;
|
||||
}
|
||||
|
||||
if (materialParams.specularColorIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.specularColorIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.specularColorUvMatrix).xy;
|
||||
vec4 sc = texture(materialParams_specularColorMap, uv);
|
||||
material.specularColorFactor.r *= sc.r;
|
||||
material.specularColorFactor.g *= sc.g;
|
||||
material.specularColorFactor.b *= sc.b;
|
||||
}
|
||||
|
||||
${CUSTOM_FRAGMENT}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,11 @@ EmissiveTexture=optional
|
||||
MetallicRoughnessTexture=optional
|
||||
TextureTransforms=optional
|
||||
|
||||
# KHR_materials_specular Features
|
||||
Specular=optional
|
||||
SpecularTexture=optional
|
||||
SpecularColorTexture=optional
|
||||
|
||||
Transmission=optional
|
||||
Ior=optional
|
||||
TransmissionTexture=optional
|
||||
|
||||
@@ -58,6 +58,15 @@ material {
|
||||
{ type : sampler2d, name : volumeThicknessMap },
|
||||
{ type : mat3, name : volumeThicknessUvMatrix, precision: high },
|
||||
|
||||
// KHR_materials_specular
|
||||
{ type : float, name : specularStrength },
|
||||
{ type : float3, name : specularColorFactor },
|
||||
{ type : int, name : specularIndex },
|
||||
{ type : sampler2d, name : specularMap },
|
||||
{ type : mat3, name : specularUvMatrix, precision: high },
|
||||
{ type : int, name : specularColorIndex },
|
||||
{ type : mat3, name : specularColorUvMatrix, precision: high },
|
||||
|
||||
// IOR
|
||||
{ type : float, name : ior }
|
||||
|
||||
@@ -142,6 +151,15 @@ fragment {
|
||||
material.emissive.rgb *= texture(materialParams_emissiveMap, uv).rgb;
|
||||
}
|
||||
|
||||
material.specularFactor = materialParams.specularStrength;
|
||||
material.specularColorFactor = materialParams.specularColorFactor;
|
||||
|
||||
if (materialParams.specularIndex > -1) {
|
||||
highp float2 uv = uvs[materialParams.specularIndex];
|
||||
uv = (vec3(uv, 1.0) * materialParams.specularUvMatrix).xy;
|
||||
material.specularFactor *= texture(materialParams_specularMap, uv).a;
|
||||
}
|
||||
|
||||
${CUSTOM_FRAGMENT}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,3 +26,8 @@ TransmissionTexture=optional
|
||||
# Volume Features
|
||||
Volume=optional
|
||||
VolumeThicknessTexture=optional
|
||||
|
||||
# KHR_materials_specular Features
|
||||
Specular=optional
|
||||
SpecularTexture=optional
|
||||
SpecularColorTexture=unsupported
|
||||
|
||||
@@ -1222,6 +1222,7 @@ MaterialKey FAssetLoader::getMaterialKey(const cgltf_data* srcAsset,
|
||||
auto trConfig = inputMat->transmission;
|
||||
auto shConfig = inputMat->sheen;
|
||||
auto vlConfig = inputMat->volume;
|
||||
auto spConfig = inputMat->specular;
|
||||
*baseColorTexture = mrConfig.base_color_texture;
|
||||
*metallicRoughnessTexture = mrConfig.metallic_roughness_texture;
|
||||
|
||||
@@ -1238,7 +1239,9 @@ MaterialKey FAssetLoader::getMaterialKey(const cgltf_data* srcAsset,
|
||||
ccConfig.clearcoat_normal_texture.has_transform ||
|
||||
shConfig.sheen_color_texture.has_transform ||
|
||||
shConfig.sheen_roughness_texture.has_transform ||
|
||||
trConfig.transmission_texture.has_transform;
|
||||
trConfig.transmission_texture.has_transform ||
|
||||
spConfig.specular_color_texture.has_transform ||
|
||||
spConfig.specular_texture.has_transform;
|
||||
|
||||
MaterialKey matkey {
|
||||
.doubleSided = !!inputMat->double_sided,
|
||||
@@ -1273,6 +1276,11 @@ MaterialKey FAssetLoader::getMaterialKey(const cgltf_data* srcAsset,
|
||||
.hasSheen = !!inputMat->has_sheen,
|
||||
.hasIOR = !!inputMat->has_ior,
|
||||
.hasVolume = !!inputMat->has_volume,
|
||||
.hasSpecular = !!inputMat->has_specular,
|
||||
.hasSpecularTexture = spConfig.specular_texture.texture != nullptr,
|
||||
.hasSpecularColorTexture = spConfig.specular_color_texture.texture != nullptr,
|
||||
.specularTextureUV = (uint8_t) spConfig.specular_texture.texcoord,
|
||||
.specularColorTextureUV = (uint8_t) spConfig.specular_color_texture.texcoord,
|
||||
};
|
||||
|
||||
if (inputMat->has_pbr_specular_glossiness) {
|
||||
@@ -1361,6 +1369,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_material* inp
|
||||
auto trConfig = inputMat->transmission;
|
||||
auto shConfig = inputMat->sheen;
|
||||
auto vlConfig = inputMat->volume;
|
||||
auto spConfig = inputMat->specular;
|
||||
|
||||
// Check the material blending mode, not the cgltf blending mode, because the provider
|
||||
// might have selected an alternative blend mode (e.g. to support transmission).
|
||||
@@ -1560,6 +1569,30 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_material* inp
|
||||
inputMat->emissive_strength.emissive_strength : 1.0f);
|
||||
}
|
||||
|
||||
if (matkey.hasSpecular) {
|
||||
const float* s = spConfig.specular_color_factor;
|
||||
mi->setParameter("specularColorFactor", float3{s[0], s[1], s[2]});
|
||||
mi->setParameter("specularStrength", spConfig.specular_factor);
|
||||
|
||||
if (matkey.hasSpecularColorTexture) {
|
||||
fAsset->addTextureBinding(mi, "specularColorMap", spConfig.specular_color_texture.texture, sRGB);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform uvt = spConfig.specular_color_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
mi->setParameter("specularColorUvMatrix", uvmat);
|
||||
}
|
||||
}
|
||||
if (matkey.hasSpecularTexture) {
|
||||
bool sameTexture = spConfig.specular_color_texture.texture == spConfig.specular_texture.texture;
|
||||
fAsset->addTextureBinding(mi, "specularMap", spConfig.specular_texture.texture, sameTexture ? sRGB : LINEAR);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform uvt = spConfig.specular_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
mi->setParameter("specularUvMatrix", uvmat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*cacheEntry = { mi, *uvmap };
|
||||
return mi;
|
||||
}
|
||||
|
||||
@@ -308,6 +308,35 @@ std::string shaderFromKey(const MaterialKey& config) {
|
||||
material.ior = materialParams.ior;
|
||||
)SHADER";
|
||||
}
|
||||
|
||||
if (config.hasSpecular) {
|
||||
shader += R"SHADER(
|
||||
material.specularFactor = materialParams.specularStrength;
|
||||
material.specularColorFactor = materialParams.specularColorFactor;
|
||||
)SHADER";
|
||||
|
||||
if (config.hasSpecularTexture) {
|
||||
shader += "highp float2 specularUV = ${specular};\n";
|
||||
if (config.hasTextureTransforms) {
|
||||
shader += "specularUV = (vec3(specularUV, 1.0) * "
|
||||
"materialParams.specularUvMatrix).xy;\n";
|
||||
}
|
||||
shader += R"SHADER(
|
||||
material.specularFactor *= texture(materialParams_specularMap, specularUV).a;
|
||||
)SHADER";
|
||||
}
|
||||
|
||||
if (config.hasSpecularColorTexture) {
|
||||
shader += "highp float2 specularColorUV = ${specularColor};\n";
|
||||
if (config.hasTextureTransforms) {
|
||||
shader += "specularColorUV = (vec3(specularColorUV, 1.0) * "
|
||||
"materialParams.specularColorUvMatrix).xy;\n";
|
||||
}
|
||||
shader += R"SHADER(
|
||||
material.specularColorFactor *= texture(materialParams_specularColorMap, specularColorUV).rgb;
|
||||
)SHADER";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shader += "}\n";
|
||||
@@ -463,6 +492,26 @@ Material* createMaterial(Engine* engine, const MaterialKey& config, const UvMap&
|
||||
}
|
||||
}
|
||||
|
||||
// SPECULAR
|
||||
if (config.hasSpecular) {
|
||||
builder.parameter("specularStrength", MaterialBuilder::UniformType::FLOAT);
|
||||
builder.parameter("specularColorFactor", MaterialBuilder::UniformType::FLOAT3);
|
||||
if (config.hasSpecularTexture) {
|
||||
builder.parameter("specularMap", MaterialBuilder::SamplerType::SAMPLER_2D);
|
||||
if (config.hasTextureTransforms) {
|
||||
builder.parameter("specularUvMatrix", MaterialBuilder::UniformType::MAT3,
|
||||
MaterialBuilder::ParameterPrecision::HIGH);
|
||||
}
|
||||
}
|
||||
if (config.hasSpecularColorTexture) {
|
||||
builder.parameter("specularColorMap", MaterialBuilder::SamplerType::SAMPLER_2D);
|
||||
if (config.hasTextureTransforms) {
|
||||
builder.parameter("specularColorUvMatrix", MaterialBuilder::UniformType::MAT3,
|
||||
MaterialBuilder::ParameterPrecision::HIGH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BLENDING
|
||||
switch (config.alphaMode) {
|
||||
case AlphaMode::OPAQUE:
|
||||
|
||||
@@ -143,6 +143,21 @@ void constrainMaterial(MaterialKey* key, UvMap* uvmap) {
|
||||
retval[key->volumeThicknessUV] = (UvSet) index++;
|
||||
}
|
||||
}
|
||||
if (key->hasSpecularTexture && retval[key->specularTextureUV] == UNUSED) {
|
||||
if (index > MAX_INDEX) {
|
||||
key->hasSpecularTexture = false;
|
||||
} else {
|
||||
retval[key->specularTextureUV] = (UvSet) index++;
|
||||
}
|
||||
}
|
||||
if (key->hasSpecularColorTexture && retval[key->specularColorTextureUV] == UNUSED) {
|
||||
if (index > MAX_INDEX) {
|
||||
key->hasSpecularColorTexture = false;
|
||||
} else {
|
||||
retval[key->specularColorTextureUV] = (UvSet) index++;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: KHR_materials_clearcoat does not provide separate UVs, we'll assume UV0
|
||||
*uvmap = retval;
|
||||
}
|
||||
@@ -167,6 +182,8 @@ void processShaderString(std::string* shader, const UvMap& uvmap, const Material
|
||||
const auto& sheenColorUV = uvstrings[uvmap[config.sheenColorUV]];
|
||||
const auto& sheenRoughnessUV = uvstrings[uvmap[config.sheenRoughnessUV]];
|
||||
const auto& volumeThicknessUV = uvstrings[uvmap[config.volumeThicknessUV]];
|
||||
const auto& specularUV = uvstrings[uvmap[config.specularTextureUV]];
|
||||
const auto& specularColorUV = uvstrings[uvmap[config.specularColorTextureUV]];
|
||||
|
||||
replaceAll("${normal}", normalUV);
|
||||
replaceAll("${color}", baseColorUV);
|
||||
@@ -180,6 +197,8 @@ void processShaderString(std::string* shader, const UvMap& uvmap, const Material
|
||||
replaceAll("${sheenColor}", sheenColorUV);
|
||||
replaceAll("${sheenRoughness}", sheenRoughnessUV);
|
||||
replaceAll("${volumeThickness}", volumeThicknessUV);
|
||||
replaceAll("${specular}", specularUV);
|
||||
replaceAll("${specularColor}", specularColorUV);
|
||||
}
|
||||
|
||||
} // namespace filament::gltfio
|
||||
|
||||
@@ -63,6 +63,42 @@ static void prepareConfig(MaterialKey* config, const char* label) {
|
||||
config->hasSheen = false;
|
||||
config->hasIOR = false;
|
||||
}
|
||||
|
||||
if (config->useSpecularGlossiness && config->hasSpecular) {
|
||||
slog.w << "SpecularGlossiness and specular are not supported together in ubershader mode,"
|
||||
" removing specularGlossiness (" << label << ")." << io::endl;
|
||||
|
||||
config->useSpecularGlossiness = false;
|
||||
}
|
||||
|
||||
if (config->unlit && config->hasSpecular) {
|
||||
slog.w << "Unlit and specular are not supported together in ubershader mode,"
|
||||
" removing unlit (" << label << ")." << io::endl;
|
||||
|
||||
config->unlit = false;
|
||||
}
|
||||
|
||||
// Also due to sampler overload, clearcoat with specular, we can only support with specular map.
|
||||
if ((config->hasClearCoatNormalTexture || config->hasClearCoatRoughnessTexture) && config->hasSpecular) {
|
||||
slog.w << "Specular can only work with clearcoat that does not use clear coat normal or clear coat roughness map,"
|
||||
" removing clear coat normal and roughness (" << label << ")." << io::endl;
|
||||
config->hasClearCoatNormalTexture = false;
|
||||
config->hasClearCoatRoughnessTexture = false;
|
||||
}
|
||||
|
||||
// Also due to sampler overload, sheen with specular, we can only support without specular color texture.
|
||||
if (config->hasSpecularColorTexture && config->hasSheen) {
|
||||
slog.w << "Sheen can only work with specular that does not use specular color map,"
|
||||
" removing specular color (" << label << ")." << io::endl;
|
||||
config->hasSpecularColorTexture = false;
|
||||
}
|
||||
|
||||
// Also due to sampler overload, volume with specular, we can only support without specular color texture.
|
||||
if (config->hasSpecularColorTexture && config->hasVolume) {
|
||||
slog.w << "Volume can only work with specular that does not use specular color map,"
|
||||
"removing specular color (" << label << ")." << io::endl;
|
||||
config->hasSpecularColorTexture = false;
|
||||
}
|
||||
}
|
||||
|
||||
class UbershaderProvider : public MaterialProvider {
|
||||
@@ -155,6 +191,9 @@ Material* UbershaderProvider::getMaterial(const MaterialKey& config) const {
|
||||
requirements.features["SheenColorTexture"] = config.hasSheenColorTexture;
|
||||
requirements.features["SheenRoughnessTexture"] = config.hasSheenRoughnessTexture;
|
||||
requirements.features["VolumeThicknessTexture"] = config.hasVolumeThicknessTexture;
|
||||
requirements.features["Specular"] = config.hasSpecular;
|
||||
requirements.features["SpecularTexture"] = config.hasSpecularTexture;
|
||||
requirements.features["SpecularColorTexture"] = config.hasSpecularColorTexture;
|
||||
|
||||
if (Material* mat = mMaterials.getMaterial(requirements); mat != nullptr) {
|
||||
return mat;
|
||||
@@ -250,6 +289,14 @@ MaterialInstance* UbershaderProvider::createMaterialInstance(MaterialKey* config
|
||||
mi->setParameter("transmissionIndex",
|
||||
getUvIndex(config->transmissionUV, config->hasTransmissionTexture));
|
||||
}
|
||||
if (config->hasSpecular) {
|
||||
mi->setParameter("specularUvMatrix", identity);
|
||||
mi->setParameter("specularIndex",
|
||||
getUvIndex(config->specularTextureUV, config->hasSpecularTexture));
|
||||
mi->setParameter("specularColorUvMatrix", identity);
|
||||
mi->setParameter("specularColorIndex",
|
||||
getUvIndex(config->specularColorTextureUV, config->hasSpecularColorTexture));
|
||||
}
|
||||
}
|
||||
|
||||
TextureSampler sampler;
|
||||
@@ -300,6 +347,14 @@ MaterialInstance* UbershaderProvider::createMaterialInstance(MaterialKey* config
|
||||
mi->setParameter("reflectance", 0.5f);
|
||||
}
|
||||
|
||||
if (needsTexture("SpecularTexture")) {
|
||||
mi->setParameter("specularMap", mDummyTexture, sampler);
|
||||
}
|
||||
|
||||
if (needsTexture("SpecularColorTexture")) {
|
||||
mi->setParameter("specularColorMap", mDummyTexture, sampler);
|
||||
}
|
||||
|
||||
return mi;
|
||||
}
|
||||
|
||||
|
||||
@@ -547,10 +547,11 @@ static bool checkAsset(const utils::Path& filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the glTF file and create Filament entities.
|
||||
// Try parsing the glTF file to check the validity of the file format.
|
||||
cgltf_options options{};
|
||||
cgltf_data* sourceAsset;
|
||||
cgltf_data* sourceAsset = nullptr;
|
||||
cgltf_result result = cgltf_parse(&options, buffer.data(), contentSize, &sourceAsset);
|
||||
cgltf_free(sourceAsset);
|
||||
if (result != cgltf_result_success) {
|
||||
slog.e << "Unable to parse glTF file." << io::endl;
|
||||
return false;
|
||||
|
||||
@@ -181,6 +181,16 @@ vec3 fresnel(const vec3 f0, float LoH) {
|
||||
#endif
|
||||
}
|
||||
|
||||
vec3 fresnel(const vec3 f0, const float f90, float LoH) {
|
||||
#if BRDF_SPECULAR_F == SPECULAR_F_SCHLICK
|
||||
#if FILAMENT_QUALITY == FILAMENT_QUALITY_LOW
|
||||
return F_Schlick(f0, LoH); // f90 = 1.0
|
||||
#else
|
||||
return F_Schlick(f0, f90, LoH);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
float distributionAnisotropic(float at, float ab, float ToH, float BoH, float NoH) {
|
||||
#if BRDF_ANISOTROPIC_D == SPECULAR_D_GGX_ANISOTROPIC
|
||||
return D_GGX_Anisotropic(at, ab, ToH, BoH, NoH);
|
||||
|
||||
@@ -18,6 +18,11 @@ struct PixelParams {
|
||||
float perceptualRoughness;
|
||||
float perceptualRoughnessUnclamped;
|
||||
vec3 f0;
|
||||
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR) || defined(MATERIAL_HAS_SPECULAR_FACTOR)
|
||||
float f90;
|
||||
float specular;
|
||||
vec3 specularColor;
|
||||
#endif
|
||||
float roughness;
|
||||
vec3 dfg;
|
||||
vec3 energyCompensation;
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
// Image based lighting configuration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Number of spherical harmonics bands (1, 2 or 3)
|
||||
#define SPHERICAL_HARMONICS_BANDS 3
|
||||
|
||||
// IBL integration algorithm
|
||||
#define IBL_INTEGRATION_PREFILTERED_CUBEMAP 0
|
||||
#define IBL_INTEGRATION_IMPORTANCE_SAMPLING 1
|
||||
@@ -44,21 +41,25 @@ vec3 prefilteredDFG(float perceptualRoughness, float NoV) {
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
vec3 Irradiance_SphericalHarmonics(const vec3 n) {
|
||||
return max(
|
||||
frameUniforms.iblSH[0]
|
||||
#if SPHERICAL_HARMONICS_BANDS >= 2
|
||||
+ frameUniforms.iblSH[1] * (n.y)
|
||||
+ frameUniforms.iblSH[2] * (n.z)
|
||||
+ frameUniforms.iblSH[3] * (n.x)
|
||||
#endif
|
||||
#if SPHERICAL_HARMONICS_BANDS >= 3
|
||||
+ frameUniforms.iblSH[4] * (n.y * n.x)
|
||||
+ frameUniforms.iblSH[5] * (n.y * n.z)
|
||||
+ frameUniforms.iblSH[6] * (3.0 * n.z * n.z - 1.0)
|
||||
+ frameUniforms.iblSH[7] * (n.z * n.x)
|
||||
+ frameUniforms.iblSH[8] * (n.x * n.x - n.y * n.y)
|
||||
#endif
|
||||
, 0.0);
|
||||
vec3 sphericalHarmonics = frameUniforms.iblSH[0];
|
||||
|
||||
if (CONFIG_SH_BANDS_COUNT >= 2) {
|
||||
sphericalHarmonics +=
|
||||
frameUniforms.iblSH[1] * (n.y)
|
||||
+ frameUniforms.iblSH[2] * (n.z)
|
||||
+ frameUniforms.iblSH[3] * (n.x);
|
||||
}
|
||||
|
||||
if (CONFIG_SH_BANDS_COUNT >= 3) {
|
||||
sphericalHarmonics +=
|
||||
frameUniforms.iblSH[4] * (n.y * n.x)
|
||||
+ frameUniforms.iblSH[5] * (n.y * n.z)
|
||||
+ frameUniforms.iblSH[6] * (3.0 * n.z * n.z - 1.0)
|
||||
+ frameUniforms.iblSH[7] * (n.z * n.x)
|
||||
+ frameUniforms.iblSH[8] * (n.x * n.x - n.y * n.y);
|
||||
}
|
||||
|
||||
return max(sphericalHarmonics, 0.0);
|
||||
}
|
||||
|
||||
vec3 Irradiance_RoughnessOne(const vec3 n) {
|
||||
@@ -135,9 +136,13 @@ vec3 getSpecularDominantDirection(const vec3 n, const vec3 r, float roughness) {
|
||||
vec3 specularDFG(const PixelParams pixel) {
|
||||
#if defined(SHADING_MODEL_CLOTH)
|
||||
return pixel.f0 * pixel.dfg.z;
|
||||
#else
|
||||
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR) || defined(MATERIAL_HAS_SPECULAR_FACTOR)
|
||||
return mix(pixel.dfg.xxx, pixel.dfg.yyy, pixel.f0) * pixel.specular;
|
||||
#else
|
||||
return mix(pixel.dfg.xxx, pixel.dfg.yyy, pixel.f0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
vec3 getReflectedVector(const PixelParams pixel, const vec3 n) {
|
||||
@@ -662,7 +667,6 @@ void evaluateIBL(const MaterialInputs material, const PixelParams pixel, inout v
|
||||
|
||||
// Combine all terms
|
||||
// Note: iblLuminance is already premultiplied by the exposure
|
||||
|
||||
color.rgb += Fr + Fd;
|
||||
#if defined(MATERIAL_HAS_REFRACTION)
|
||||
color.rgb += Ft;
|
||||
|
||||
@@ -89,6 +89,15 @@ struct MaterialInputs {
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MATERIAL_HAS_SPECULAR_FACTOR)
|
||||
float specularFactor;
|
||||
#endif
|
||||
|
||||
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR)
|
||||
vec3 specularColorFactor;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
void initMaterial(out MaterialInputs material) {
|
||||
@@ -177,6 +186,15 @@ void initMaterial(out MaterialInputs material) {
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MATERIAL_HAS_SPECULAR_FACTOR)
|
||||
material.specularFactor = 1.0;
|
||||
#endif
|
||||
|
||||
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR)
|
||||
material.specularColorFactor = vec3(1.0);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if defined(MATERIAL_HAS_CUSTOM_SURFACE_SHADING)
|
||||
|
||||
@@ -75,7 +75,21 @@ void getCommonPixelParams(const MaterialInputs material, inout PixelParams pixel
|
||||
// Assumes an interface from air to an IOR of 1.5 for dielectrics
|
||||
float reflectance = computeDielectricF0(material.reflectance);
|
||||
#endif
|
||||
#if !defined(MATERIAL_HAS_SPECULAR_FACTOR) && !defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR)
|
||||
pixel.f0 = computeF0(baseColor, material.metallic, reflectance);
|
||||
#else
|
||||
vec3 dielectricSpecularF0 = vec3(0.0);
|
||||
float dielectricSpecularF90 = 0.0;
|
||||
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR)
|
||||
dielectricSpecularF0 = min(reflectance * material.specularColorFactor, vec3(1.0));
|
||||
#endif
|
||||
#if defined(MATERIAL_HAS_SPECULAR_FACTOR)
|
||||
dielectricSpecularF0 *= material.specularFactor;
|
||||
dielectricSpecularF90 = material.specularFactor;
|
||||
#endif
|
||||
pixel.f0 = baseColor.rgb * material.metallic + dielectricSpecularF0 * (1.0 - material.metallic);
|
||||
pixel.f90 = material.metallic + dielectricSpecularF90 * (1.0 - material.metallic);
|
||||
#endif
|
||||
#else
|
||||
pixel.diffuseColor = baseColor.rgb;
|
||||
pixel.f0 = material.sheenColor;
|
||||
@@ -123,6 +137,16 @@ void getCommonPixelParams(const MaterialInputs material, inout PixelParams pixel
|
||||
#endif
|
||||
}
|
||||
|
||||
void getSpecularPixelParams(const MaterialInputs material, inout PixelParams pixel) {
|
||||
#if defined(MATERIAL_HAS_SPECULAR_FACTOR)
|
||||
pixel.specular = material.specularFactor;
|
||||
#endif
|
||||
|
||||
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR)
|
||||
pixel.specularColor = material.specularColorFactor;
|
||||
#endif
|
||||
}
|
||||
|
||||
void getSheenPixelParams(const MaterialInputs material, inout PixelParams pixel) {
|
||||
#if defined(MATERIAL_HAS_SHEEN_COLOR) && !defined(SHADING_MODEL_CLOTH) && !defined(SHADING_MODEL_SUBSURFACE)
|
||||
pixel.sheenColor = material.sheenColor;
|
||||
@@ -232,6 +256,7 @@ void getEnergyCompensationPixelParams(inout PixelParams pixel) {
|
||||
* testing fails.
|
||||
*/
|
||||
void getPixelParams(const MaterialInputs material, out PixelParams pixel) {
|
||||
getSpecularPixelParams(material, pixel);
|
||||
getCommonPixelParams(material, pixel);
|
||||
getSheenPixelParams(material, pixel);
|
||||
getClearCoatPixelParams(material, pixel);
|
||||
|
||||
@@ -63,8 +63,11 @@ vec3 isotropicLobe(const PixelParams pixel, const Light light, const vec3 h,
|
||||
|
||||
float D = distribution(pixel.roughness, NoH, h);
|
||||
float V = visibility(pixel.roughness, NoV, NoL);
|
||||
#if defined(MATERIAL_HAS_SPECULAR_COLOR_FACTOR) || defined(MATERIAL_HAS_SPECULAR_FACTOR)
|
||||
vec3 F = fresnel(pixel.f0, pixel.f90, LoH);
|
||||
#else
|
||||
vec3 F = fresnel(pixel.f0, LoH);
|
||||
|
||||
#endif
|
||||
return (D * V) * F;
|
||||
}
|
||||
|
||||
@@ -144,7 +147,6 @@ vec3 surfaceShading(const PixelParams pixel, const Light light, float occlusion)
|
||||
color += clearCoat;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return (color * light.colorIntensity.rgb) *
|
||||
(light.colorIntensity.w * light.attenuation * NoL * occlusion);
|
||||
}
|
||||
|
||||
+6
@@ -81,6 +81,11 @@ filegroup(
|
||||
srcs = ["include/spirv/unified1/extinst.nonsemantic.clspvreflection.grammar.json"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "spirv_ext_inst_nonsemantic_vkspreflection_grammar_unified1",
|
||||
srcs = ["include/spirv/unified1/extinst.nonsemantic.vkspreflection.grammar.json"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "spirv_ext_inst_nonsemantic_debugprintf_grammar_unified1",
|
||||
srcs = ["include/spirv/unified1/extinst.nonsemantic.debugprintf.grammar.json"],
|
||||
@@ -128,6 +133,7 @@ cc_library(
|
||||
"include/spirv/unified1/GLSL.std.450.h",
|
||||
"include/spirv/unified1/NonSemanticClspvReflection.h",
|
||||
"include/spirv/unified1/NonSemanticDebugPrintf.h",
|
||||
"include/spirv/unified1/NonSemanticVkspReflection.h",
|
||||
"include/spirv/unified1/OpenCL.std.h",
|
||||
],
|
||||
includes = ["include"],
|
||||
|
||||
Vendored
+2
-1
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020 Google LLC
|
||||
# Copyright (c) 2020-2024 Google LLC
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and/or associated documentation files (the "Materials"),
|
||||
@@ -35,6 +35,7 @@ source_set("spv_headers") {
|
||||
"include/spirv/unified1/GLSL.std.450.h",
|
||||
"include/spirv/unified1/NonSemanticClspvReflection.h",
|
||||
"include/spirv/unified1/NonSemanticDebugPrintf.h",
|
||||
"include/spirv/unified1/NonSemanticVkspReflection.h",
|
||||
"include/spirv/unified1/OpenCL.std.h",
|
||||
"include/spirv/unified1/spirv.h",
|
||||
"include/spirv/unified1/spirv.hpp",
|
||||
|
||||
+33
-101
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
# Copyright (c) 2015-2024 The Khronos Group Inc.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and/or associated documentation files (the
|
||||
@@ -23,113 +23,45 @@
|
||||
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
#
|
||||
# The SPIR-V headers from the SPIR-V Registry
|
||||
# https://www.khronos.org/registry/spir-v/
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
project(SPIRV-Headers VERSION 1.5.5)
|
||||
project(SPIRV-Headers LANGUAGES CXX VERSION 1.5.5)
|
||||
|
||||
# There are two ways to use this project.
|
||||
#
|
||||
# Using this source tree directly from a CMake-based project:
|
||||
# 1. Add an add_subdirectory directive to include this sub directory.
|
||||
# 2. Use ${SPIRV-Headers_SOURCE_DIR}/include} in a target_include_directories
|
||||
# command.
|
||||
#
|
||||
# Installing the headers first, then using them with an implicit include
|
||||
# directory. To install the headers:
|
||||
# 1. mkdir build ; cd build
|
||||
# 2. cmake ..
|
||||
# 3. cmake --build . --target install
|
||||
|
||||
option(SPIRV_HEADERS_SKIP_EXAMPLES "Skip building examples" ON)
|
||||
|
||||
option(SPIRV_HEADERS_SKIP_INSTALL "Skip install" ON)
|
||||
|
||||
if(NOT ${SPIRV_HEADERS_SKIP_EXAMPLES})
|
||||
set(SPIRV_HEADERS_ENABLE_EXAMPLES ON)
|
||||
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()
|
||||
|
||||
if(NOT ${SPIRV_HEADERS_SKIP_INSTALL})
|
||||
set(SPIRV_HEADERS_ENABLE_INSTALL ON)
|
||||
# legacy
|
||||
add_custom_target(install-headers
|
||||
COMMAND cmake -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/spirv
|
||||
$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/include/spirv)
|
||||
add_library(SPIRV-Headers INTERFACE)
|
||||
add_library(SPIRV-Headers::SPIRV-Headers ALIAS SPIRV-Headers)
|
||||
target_include_directories(SPIRV-Headers INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
|
||||
|
||||
option(SPIRV_HEADERS_ENABLE_TESTS "Test SPIRV-Headers" OFF)
|
||||
option(SPIRV_HEADERS_ENABLE_INSTALL "Install SPIRV-Headers" OFF)
|
||||
|
||||
if(SPIRV_HEADERS_ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if (SPIRV_HEADERS_ENABLE_EXAMPLES)
|
||||
message(STATUS "Building SPIRV-Header examples")
|
||||
add_subdirectory(example)
|
||||
endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
add_library(${PROJECT_NAME} INTERFACE)
|
||||
target_include_directories(${PROJECT_NAME} INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
)
|
||||
|
||||
# Installation
|
||||
|
||||
if (SPIRV_HEADERS_ENABLE_INSTALL)
|
||||
message(STATUS "Installing SPIRV-Header")
|
||||
|
||||
set(config_install_dir "${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}")
|
||||
|
||||
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
||||
|
||||
set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
|
||||
set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
|
||||
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
|
||||
set(namespace "${PROJECT_NAME}::")
|
||||
|
||||
if(SPIRV_HEADERS_ENABLE_INSTALL)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
if (NOT CMAKE_VERSION VERSION_LESS 3.14)
|
||||
set(arch_independent_str ARCH_INDEPENDENT)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/spirv DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
set(cmake_install_dir "${CMAKE_INSTALL_DATADIR}/cmake/SPIRV-Headers")
|
||||
set(version_config "${CMAKE_CURRENT_BINARY_DIR}/generated/SPIRV-HeadersConfigVersion.cmake")
|
||||
|
||||
write_basic_package_version_file("${version_config}" COMPATIBILITY SameMajorVersion ARCH_INDEPENDENT)
|
||||
install(FILES "${version_config}" DESTINATION "${cmake_install_dir}")
|
||||
|
||||
install(TARGETS SPIRV-Headers EXPORT "SPIRV-HeadersConfig" INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(EXPORT "SPIRV-HeadersConfig" NAMESPACE "SPIRV-Headers::" DESTINATION "${cmake_install_dir}")
|
||||
|
||||
if (IS_ABSOLUTE ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
set(SPIRV_HEADERS_PKGCONFIG_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
else()
|
||||
set(SPIRV_HEADERS_PKGCONFIG_INCLUDE_DIR ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR})
|
||||
endif()
|
||||
write_basic_package_version_file(
|
||||
"${version_config}"
|
||||
COMPATIBILITY SameMajorVersion
|
||||
${arch_independent_str}
|
||||
)
|
||||
|
||||
configure_package_config_file(
|
||||
"cmake/Config.cmake.in"
|
||||
"${project_config}"
|
||||
INSTALL_DESTINATION "${config_install_dir}"
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
EXPORT "${TARGETS_EXPORT_NAME}"
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY include/spirv
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
)
|
||||
|
||||
install(
|
||||
FILES "${project_config}" "${version_config}"
|
||||
DESTINATION "${config_install_dir}"
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT "${TARGETS_EXPORT_NAME}"
|
||||
NAMESPACE "${namespace}"
|
||||
DESTINATION "${config_install_dir}"
|
||||
)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers.pc.in ${CMAKE_BINARY_DIR}/SPIRV-Headers.pc @ONLY)
|
||||
install(
|
||||
FILES "${CMAKE_BINARY_DIR}/SPIRV-Headers.pc"
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/pkgconfig
|
||||
)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Headers.pc.in ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Headers.pc @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Headers.pc" DESTINATION ${CMAKE_INSTALL_DATADIR}/pkgconfig)
|
||||
endif()
|
||||
|
||||
Vendored
+79
-1
@@ -1,4 +1,5 @@
|
||||
Copyright (c) 2015-2018 The Khronos Group Inc.
|
||||
Files: All files except for those called out below.
|
||||
Copyright (c) 2015-2024 The Khronos Group Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and/or associated documentation files (the
|
||||
@@ -23,3 +24,80 @@ 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
|
||||
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
---
|
||||
|
||||
Files: include/spirv/spir-v.xml
|
||||
Copyright (c) 2015-2024 The Khronos Group Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and/or associated documentation files (the
|
||||
"Materials"), to deal in the Materials without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
permit persons to whom the Materials are 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 Materials.
|
||||
|
||||
THE MATERIALS ARE 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
|
||||
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
---
|
||||
|
||||
Files: tools/buildHeaders/jsoncpp/*
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
tests and demonstration applications, are licensed under the following
|
||||
conditions...
|
||||
|
||||
The author (Baptiste Lepilleur) explicitly disclaims copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
this software is released into the Public Domain.
|
||||
|
||||
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
|
||||
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
|
||||
released under the terms of the MIT License (see below).
|
||||
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
Public Domain/MIT License conditions described here, as they choose.
|
||||
|
||||
The MIT License is about as close to Public Domain as a license can get, and is
|
||||
described in clear, concise terms at:
|
||||
|
||||
http://en.wikipedia.org/wiki/MIT_License
|
||||
|
||||
The full text of the MIT License follows:
|
||||
|
||||
========================================================================
|
||||
Copyright (c) 2007-2010 Baptiste Lepilleur
|
||||
|
||||
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.
|
||||
========================================================================
|
||||
|
||||
---
|
||||
|
||||
Vendored
+1
-1
@@ -198,7 +198,7 @@ python3 bin/makeExtinstHeaders.py
|
||||
## License
|
||||
<a name="license"></a>
|
||||
```
|
||||
Copyright (c) 2015-2018 The Khronos Group Inc.
|
||||
Copyright (c) 2015-2024 The Khronos Group Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and/or associated documentation files (the
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Security updates are applied only to the latest release.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
|
||||
|
||||
Please disclose it at [security advisory](https://github.com/KhronosGroup/SPIRV-Headers/security/advisories/new).
|
||||
|
||||
This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.
|
||||
@@ -1,4 +0,0 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
|
||||
check_required_components("@PROJECT_NAME@")
|
||||
Vendored
+1
-2
@@ -1,5 +1,4 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||
includedir=@SPIRV_HEADERS_PKGCONFIG_INCLUDE_DIR@
|
||||
|
||||
Name: SPIRV-Headers
|
||||
Description: Header files from the SPIR-V registry
|
||||
@@ -1,4 +0,0 @@
|
||||
add_library(SPIRV-Headers-example
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/example.cpp)
|
||||
target_include_directories(SPIRV-Headers-example
|
||||
PRIVATE ${SPIRV-Headers_SOURCE_DIR}/include)
|
||||
+25
-10
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<registry>
|
||||
<!--
|
||||
Copyright (c) 2015 The Khronos Group Inc.
|
||||
Copyright (c) 2015-2024 The Khronos Group Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and/or associated documentation files (the
|
||||
@@ -82,12 +82,19 @@
|
||||
<id value="29" vendor="Mikkosoft Productions" tool="MSP Shader Compiler" comment="Contact Mikko Rasa, tdb@tdb.fi"/>
|
||||
<id value="30" vendor="SpvGenTwo community" tool="SpvGenTwo SPIR-V IR Tools" comment="https://github.com/rAzoR8/SpvGenTwo"/>
|
||||
<id value="31" vendor="Google" tool="Skia SkSL" comment="Contact Ethan Nicholas, ethannicholas@google.com"/>
|
||||
<id value="32" vendor="TornadoVM" tool="SPIRV Beehive Toolkit" comment="https://github.com/beehive-lab/spirv-beehive-toolkit"/>
|
||||
<id value="32" vendor="TornadoVM" tool="Beehive SPIRV Toolkit" comment="https://github.com/beehive-lab/beehive-spirv-toolkit"/>
|
||||
<id value="33" vendor="DragonJoker" tool="ShaderWriter" comment="Contact Sylvain Doremus, https://github.com/DragonJoker/ShaderWriter"/>
|
||||
<id value="34" vendor="Rayan Hatout" tool="SPIRVSmith" comment="Contact Rayan Hatout rayan.hatout@gmail.com, Repo https://github.com/rayanht/SPIRVSmith"/>
|
||||
<id value="35" vendor="Saarland University" tool="Shady" comment="Contact Hugo Devillers devillers@uni-saarland.de, Repo https://github.com/Hugobros3/shady"/>
|
||||
<id value="36" vendor="Taichi Graphics" tool="Taichi" comment="Contact Rendong Liang rendongliang@taichi.graphics, Repo https://github.com/taichi-dev/taichi"/>
|
||||
<unused start="37" end="0xFFFF" comment="Tool ID range reservable for future use by vendors"/>
|
||||
<id value="37" vendor="heroseh" tool="Hero C Compiler" comment="https://github.com/heroseh/hcc"/>
|
||||
<id value="38" vendor="Meta" tool="SparkSL" comment="Contact Dunfan Lu, dunfanlu@meta.com, https://sparkar.facebook.com/ar-studio/learn/sparksl/sparksl-overview"/>
|
||||
<id value="39" vendor="SirLynix" tool="Nazara ShaderLang Compiler" comment="Contact Jérôme Leclercq, https://github.com/NazaraEngine/ShaderLang"/>
|
||||
<id value="40" vendor="NVIDIA" tool="Slang Compiler" comment="Contact Theresa Foley, tfoley@nvidia.com, https://github.com/shader-slang/slang/"/>
|
||||
<id value="41" vendor="Zig Software Foundation" tool="Zig Compiler" comment="Contact Robin Voetter, https://github.com/Snektron"/>
|
||||
<id value="42" vendor="Rendong Liang" tool="spq" comment="Contact Rendong Liang, admin@penguinliong.moe, https://github.com/PENGUINLIONG/spq-rs"/>
|
||||
<id value="43" vendor="LLVM" tool="LLVM SPIR-V Backend" comment="Contact Michal Paszkowski, michal.paszkowski@intel.com, https://github.com/llvm/llvm-project/tree/main/llvm/lib/Target/SPIRV"/>
|
||||
<unused start="44" end="0xFFFF" comment="Tool ID range reservable for future use by vendors"/>
|
||||
</ids>
|
||||
|
||||
<!-- SECTION: SPIR-V Opcodes and Enumerants -->
|
||||
@@ -140,13 +147,17 @@
|
||||
<ids type="opcode" start="6144" end="6271" vendor="Intel" comment="Contact michael.kinsner@intel.com"/>
|
||||
<ids type="opcode" start="6272" end="6399" vendor="Huawei" comment="Contact wanghuilong2@xunweitech.com"/>
|
||||
<ids type="opcode" start="6400" end="6463" vendor="Intel" comment="Contact ben.ashbaugh@intel.com"/>
|
||||
<ids type="opcode" start="6464" end="6527" vendor="N/A" comment="Blank range to keep alignment with non-opcodes"/>
|
||||
<ids type="opcode" start="6528" end="6591" vendor="Codeplay" comment="Contact duncan.brawley@codeplay.com"/>
|
||||
<ids type="opcode" start="6592" end="6655" vendor="Saarland University" comment="Contact devillers@cg.uni-saarland.de"/>
|
||||
<ids type="opcode" start="6656" end="6719" vendor="Meta" comment="Contact dunfanlu@meta.com"/>
|
||||
<!-- Opcode enumerants to reserve for future use. To get a block, allocate
|
||||
multiples of 64 starting at the lowest available point in this
|
||||
block and add a corresponding <ids> tag immediately above. Make
|
||||
sure to fill in the vendor attribute, and preferably add a contact
|
||||
person/address in a comment attribute. -->
|
||||
<!-- Example new block: <ids type="opcode" start="XXXX" end="XXXX+64n-1" vendor="Add vendor" comment="Contact TBD"/> -->
|
||||
<ids type="opcode" start="6464" end="65535" comment="Opcode range reservable for future use by vendors"/>
|
||||
<ids type="opcode" start="6656" end="65535" comment="Opcode range reservable for future use by vendors"/>
|
||||
<!-- End reservations of opcodes -->
|
||||
|
||||
|
||||
@@ -170,13 +181,16 @@
|
||||
<ids type="enumerant" start="6272" end="6399" vendor="Huawei" comment="Contact wanghuilong2@xunweitech.com"/>
|
||||
<ids type="enumerant" start="6400" end="6463" vendor="Intel" comment="Contact ben.ashbaugh@intel.com"/>
|
||||
<ids type="enumerant" start="6464" end="6527" vendor="Mikkosoft Productions" comment="Contact Mikko Rasa, tdb@tdb.fi"/>
|
||||
<ids type="enumerant" start="6528" end="6591" vendor="Codeplay" comment="Contact duncan.brawley@codeplay.com"/>
|
||||
<ids type="enumerant" start="6592" end="6655" vendor="Saarland University" comment="Contact devillers@cg.uni-saarland.de"/>
|
||||
<ids type="enumerant" start="6656" end="6719" vendor="Meta" comment="Contact dunfanlu@meta.com"/>
|
||||
<!-- Enumerants to reserve for future use. To get a block, allocate
|
||||
multiples of 64 starting at the lowest available point in this
|
||||
block and add a corresponding <ids> tag immediately above. Make
|
||||
sure to fill in the vendor attribute, and preferably add a contact
|
||||
person/address in a comment attribute. -->
|
||||
<!-- Example new block: <ids type="enumerant" start="XXXX" end="XXXX+64n-1" vendor="Add vendor" comment="Contact TBD"/> -->
|
||||
<ids type="enumerant" start="6528" end="4294967295" comment="Enumerant range reservable for future use by vendors"/>
|
||||
<ids type="enumerant" start="6656" end="4294967295" comment="Enumerant range reservable for future use by vendors"/>
|
||||
<!-- End reservations of enumerants -->
|
||||
|
||||
|
||||
@@ -196,8 +210,8 @@
|
||||
|
||||
<!-- Reserved loop control bits -->
|
||||
<ids type="LoopControl" start="0" end="15" vendor="Khronos" comment="Reserved LoopControl bits, not available to vendors - see the SPIR-V Specification"/>
|
||||
<ids type="LoopControl" start="16" end="25" vendor="Intel" comment="Contact michael.kinsner@intel.com"/>
|
||||
<ids type="LoopControl" start="26" end="30" comment="Unreserved bits reservable for use by vendors"/>
|
||||
<ids type="LoopControl" start="16" end="27" vendor="Intel" comment="Contact michael.kinsner@intel.com"/>
|
||||
<ids type="LoopControl" start="28" end="30" comment="Unreserved bits reservable for use by vendors"/>
|
||||
<ids type="LoopControl" start="31" end="31" vendor="Khronos" comment="Reserved LoopControl bit, not available to vendors"/>
|
||||
|
||||
|
||||
@@ -237,7 +251,8 @@
|
||||
<!-- Reserved FP fast math mode bits -->
|
||||
<ids type="FPFastMathMode" start="0" end="15" vendor="Khronos" comment="Reserved FPFastMathMode bits, not available to vendors - see the SPIR-V Specification"/>
|
||||
<ids type="FPFastMathMode" start="16" end="17" vendor="Intel" comment="Contact michael.kinsner@intel.com"/>
|
||||
<ids type="FPFastMathMode" start="18" end="31" comment="Unreserved bits reservable for use by vendors"/>
|
||||
<ids type="FPFastMathMode" start="18" end="18" vendor="khronos" comment="Reserved FPFastMathMode bit, not available to vendors - see SPV_KHR_float_controls2"/>
|
||||
<ids type="FPFastMathMode" start="19" end="31" comment="Unreserved bits reservable for use by vendors"/>
|
||||
|
||||
|
||||
<!-- SECTION: SPIR-V Memory Operand Bit Reservations -->
|
||||
@@ -256,8 +271,8 @@
|
||||
|
||||
<!-- Reserved memory operand bits -->
|
||||
<ids type="MemoryOperand" start="0" end="15" vendor="Khronos" comment="Reserved MemoryOperand bits, not available to vendors - see the SPIR-V Specification"/>
|
||||
<ids type="MemoryOperand" start="16" end="17" vendor="Intel" comment="Contact michael.kinsner@intel.com"/>
|
||||
<ids type="MemoryOperand" start="18" end="30" comment="Unreserved bits reservable for use by vendors"/>
|
||||
<ids type="MemoryOperand" start="16" end="18" vendor="Intel" comment="Contact michael.kinsner@intel.com"/>
|
||||
<ids type="MemoryOperand" start="19" end="30" comment="Unreserved bits reservable for use by vendors"/>
|
||||
<ids type="MemoryOperand" start="31" end="31" vendor="Khronos" comment="Reserved MemoryOperand bit, not available to vendors"/>
|
||||
|
||||
<!-- SECTION: SPIR-V Image Operand Bit Reservations -->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2020 The Khronos Group Inc.
|
||||
// Copyright (c) 2020-2024 The Khronos Group Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2020 The Khronos Group Inc.
|
||||
// Copyright (c) 2020-2024 The Khronos Group Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2020 The Khronos Group Inc.
|
||||
// Copyright (c) 2020-2024 The Khronos Group Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2020 The Khronos Group Inc.
|
||||
// Copyright (c) 2020-2024 The Khronos Group Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2017 The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2024 The Khronos Group Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and/or associated documentation files (the "Materials"),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** Copyright (c) 2014-2016 The Khronos Group Inc.
|
||||
** Copyright (c) 2014-2024 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and/or associated documentation files (the "Materials"),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user