Compare commits
1 Commits
v1.52.0
...
pf/fix-bac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd697f667b |
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.52.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.51.8'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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.52.0'
|
||||
pod 'Filament', '~> 1.51.8'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
|
||||
@@ -7,7 +7,7 @@ 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.52.0
|
||||
## v1.51.9
|
||||
|
||||
|
||||
## v1.51.8
|
||||
|
||||
@@ -244,25 +244,13 @@ Java_com_google_android_filament_RenderableManager_nBuilderMorphing(JNIEnv*, jcl
|
||||
builder->morphing(targetCount);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nBuilderMorphingStandard(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jlong nativeMorphTargetBuffer) {
|
||||
RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder;
|
||||
MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer;
|
||||
builder->morphing(morphTargetBuffer);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_RenderableManager_nBuilderSetMorphTargetBufferAt(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, int level, int primitiveIndex, jlong nativeMorphTargetBuffer,
|
||||
int offset, int count) {
|
||||
RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder;
|
||||
if (nativeMorphTargetBuffer) {
|
||||
MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer;
|
||||
builder->morphing(level, primitiveIndex, morphTargetBuffer, offset, count);
|
||||
} else {
|
||||
builder->morphing(level, primitiveIndex, offset, count);
|
||||
}
|
||||
MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer;
|
||||
builder->morphing(level, primitiveIndex, morphTargetBuffer, offset, count);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@@ -338,14 +326,9 @@ Java_com_google_android_filament_RenderableManager_nSetMorphTargetBufferAt(JNIEn
|
||||
jclass, jlong nativeRenderableManager, jint i, int level, jint primitiveIndex,
|
||||
jlong nativeMorphTargetBuffer, jint offset, jint count) {
|
||||
RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
|
||||
if (nativeMorphTargetBuffer) {
|
||||
MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer;
|
||||
rm->setMorphTargetBufferAt((RenderableManager::Instance) i, (uint8_t) level,
|
||||
(size_t) primitiveIndex, morphTargetBuffer, (size_t) offset, (size_t) count);
|
||||
} else {
|
||||
rm->setMorphTargetBufferAt((RenderableManager::Instance) i, (uint8_t) level,
|
||||
(size_t) primitiveIndex, (size_t) offset, (size_t) count);
|
||||
}
|
||||
MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer;
|
||||
rm->setMorphTargetBufferAt((RenderableManager::Instance) i, (uint8_t) level,
|
||||
(size_t) primitiveIndex, morphTargetBuffer, (size_t) offset, (size_t) count);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
|
||||
@@ -524,7 +524,14 @@ public class RenderableManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls if the renderable has legacy vertex morphing targets, zero by default.
|
||||
* Controls if the renderable has vertex morphing targets, zero by default. This is
|
||||
* required to enable GPU morphing.
|
||||
*
|
||||
* <p>Filament supports two morphing modes: standard (default) and legacy.</p>
|
||||
*
|
||||
* <p>For standard morphing, A {@link MorphTargetBuffer} must be created and provided via
|
||||
* {@link RenderableManager#setMorphTargetBufferAt}. Standard morphing supports up to
|
||||
* <code>CONFIG_MAX_MORPH_TARGET_COUNT</code> morph targets.</p>
|
||||
*
|
||||
* For legacy morphing, the attached {@link VertexBuffer} must provide data in the
|
||||
* appropriate {@link VertexBuffer.VertexAttribute} slots (<code>MORPH_POSITION_0</code> etc).
|
||||
@@ -542,22 +549,6 @@ public class RenderableManager {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls if the renderable has vertex morphing targets, zero by default.
|
||||
*
|
||||
* <p>For standard morphing, A {@link MorphTargetBuffer} must be provided.
|
||||
* Standard morphing supports up to
|
||||
* <code>CONFIG_MAX_MORPH_TARGET_COUNT</code> morph targets.</p>
|
||||
*
|
||||
* <p>See also {@link RenderableManager#setMorphWeights}, which can be called on a per-frame basis
|
||||
* to advance the animation.</p>
|
||||
*/
|
||||
@NonNull
|
||||
public Builder morphing(@NonNull MorphTargetBuffer morphTargetBuffer) {
|
||||
nBuilderMorphingStandard(mNativeBuilder, morphTargetBuffer.getNativeObject());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the morph target buffer for a primitive.
|
||||
*
|
||||
@@ -574,17 +565,6 @@ public class RenderableManager {
|
||||
* @param count number of vertices in the morph target buffer to read, must equal the geometry's count (for triangles, this should be a multiple of 3)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder morphing(@IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int primitiveIndex,
|
||||
@IntRange(from = 0) int offset,
|
||||
@IntRange(from = 0) int count) {
|
||||
nBuilderSetMorphTargetBufferAt(mNativeBuilder, level, primitiveIndex, 0, offset, count);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
@NonNull
|
||||
public Builder morphing(@IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int primitiveIndex,
|
||||
@NonNull MorphTargetBuffer morphTargetBuffer,
|
||||
@@ -595,8 +575,10 @@ public class RenderableManager {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
/**
|
||||
* Utility method to specify morph target buffer for a primitive.
|
||||
* For details, see the {@link RenderableManager.Builder#morphing}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder morphing(@IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int primitiveIndex,
|
||||
@@ -705,16 +687,6 @@ public class RenderableManager {
|
||||
*
|
||||
* @see Builder#morphing
|
||||
*/
|
||||
public void setMorphTargetBufferAt(@EntityInstance int i,
|
||||
@IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int primitiveIndex,
|
||||
@IntRange(from = 0) int offset,
|
||||
@IntRange(from = 0) int count) {
|
||||
nSetMorphTargetBufferAt(mNativeObject, i, level, primitiveIndex, 0, offset, count);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
public void setMorphTargetBufferAt(@EntityInstance int i,
|
||||
@IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int primitiveIndex,
|
||||
@@ -725,8 +697,10 @@ public class RenderableManager {
|
||||
morphTargetBuffer.getNativeObject(), offset, count);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
@Deprecated
|
||||
/**
|
||||
* Utility method to change morph target buffer for the given primitive.
|
||||
* For details, see the {@link RenderableManager#setMorphTargetBufferAt}.
|
||||
*/
|
||||
public void setMorphTargetBufferAt(@EntityInstance int i,
|
||||
@IntRange(from = 0) int level,
|
||||
@IntRange(from = 0) int primitiveIndex,
|
||||
@@ -1032,7 +1006,6 @@ public class RenderableManager {
|
||||
private static native int nBuilderSkinningBones(long nativeBuilder, int boneCount, Buffer bones, int remaining);
|
||||
private static native void nBuilderSkinningBuffer(long nativeBuilder, long nativeSkinningBuffer, int boneCount, int offset);
|
||||
private static native void nBuilderMorphing(long nativeBuilder, int targetCount);
|
||||
private static native void nBuilderMorphingStandard(long nativeBuilder, long nativeMorphTargetBuffer);
|
||||
private static native void nBuilderSetMorphTargetBufferAt(long nativeBuilder, int level, int primitiveIndex, long nativeMorphTargetBuffer, int offset, int count);
|
||||
private static native void nBuilderEnableSkinningBuffers(long nativeBuilder, boolean enabled);
|
||||
private static native void nBuilderFog(long nativeBuilder, boolean enabled);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.52.0
|
||||
VERSION_NAME=1.51.8
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -417,9 +417,7 @@ if (APPLE OR LINUX)
|
||||
test/test_MissingRequiredAttributes.cpp
|
||||
test/test_ReadPixels.cpp
|
||||
test/test_BufferUpdates.cpp
|
||||
test/test_Callbacks.cpp
|
||||
test/test_MRT.cpp
|
||||
test/test_PushConstants.cpp
|
||||
test/test_LoadImage.cpp
|
||||
test/test_StencilBuffer.cpp
|
||||
test/test_Scissor.cpp
|
||||
|
||||
@@ -117,7 +117,7 @@ static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT,
|
||||
"The number of buffer objects that can be attached to a VertexBuffer must be "
|
||||
"less than or equal to the maximum number of vertex attributes.");
|
||||
|
||||
static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 9; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t CONFIG_UNIFORM_BINDING_COUNT = 10; // This is guaranteed by OpenGL ES.
|
||||
static constexpr size_t CONFIG_SAMPLER_BINDING_COUNT = 4; // This is guaranteed by OpenGL ES.
|
||||
|
||||
/**
|
||||
|
||||
@@ -144,7 +144,8 @@ DECL_DRIVER_API_N(setFrameScheduledCallback,
|
||||
DECL_DRIVER_API_N(setFrameCompletedCallback,
|
||||
backend::SwapChainHandle, sch,
|
||||
backend::CallbackHandler*, handler,
|
||||
utils::Invocable<void(void)>&&, callback)
|
||||
backend::CallbackHandler::Callback, callback,
|
||||
void*, user)
|
||||
|
||||
DECL_DRIVER_API_N(setPresentationTime,
|
||||
int64_t, monotonic_clock_ns)
|
||||
|
||||
@@ -55,18 +55,6 @@ struct MetalVertexBuffer;
|
||||
|
||||
constexpr static uint8_t MAX_SAMPLE_COUNT = 8; // Metal devices support at most 8 MSAA samples
|
||||
|
||||
class MetalPushConstantBuffer {
|
||||
public:
|
||||
void setPushConstant(PushConstantVariant value, uint8_t index);
|
||||
bool isDirty() const { return mDirty; }
|
||||
void setBytes(id<MTLCommandEncoder> encoder, ShaderStage stage);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
std::vector<PushConstantVariant> mPushConstants;
|
||||
bool mDirty = false;
|
||||
};
|
||||
|
||||
struct MetalContext {
|
||||
explicit MetalContext(size_t metalFreedTextureListSize)
|
||||
: texturesToDestroy(metalFreedTextureListSize) {}
|
||||
@@ -121,8 +109,6 @@ struct MetalContext {
|
||||
|
||||
PolygonOffset currentPolygonOffset = {0.0f, 0.0f};
|
||||
|
||||
std::array<MetalPushConstantBuffer, Program::SHADER_TYPE_COUNT> currentPushConstants;
|
||||
|
||||
MetalSamplerGroup* samplerBindings[Program::SAMPLER_BINDING_COUNT] = {};
|
||||
|
||||
// Keeps track of sampler groups we've finalized for the current render pass.
|
||||
|
||||
@@ -153,68 +153,5 @@ bool isInRenderPass(MetalContext* context) {
|
||||
return context->currentRenderPassEncoder != nil;
|
||||
}
|
||||
|
||||
void MetalPushConstantBuffer::setPushConstant(PushConstantVariant value, uint8_t index) {
|
||||
if (mPushConstants.size() <= index) {
|
||||
mPushConstants.resize(index + 1);
|
||||
mDirty = true;
|
||||
}
|
||||
if (UTILS_LIKELY(mPushConstants[index] != value)) {
|
||||
mDirty = true;
|
||||
mPushConstants[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void MetalPushConstantBuffer::setBytes(id<MTLCommandEncoder> encoder, ShaderStage stage) {
|
||||
constexpr size_t PUSH_CONSTANT_SIZE_BYTES = 4;
|
||||
constexpr size_t PUSH_CONSTANT_BUFFER_INDEX = 26;
|
||||
|
||||
static char buffer[MAX_PUSH_CONSTANT_COUNT * PUSH_CONSTANT_SIZE_BYTES];
|
||||
assert_invariant(mPushConstants.size() <= MAX_PUSH_CONSTANT_COUNT);
|
||||
|
||||
size_t bufferSize = PUSH_CONSTANT_SIZE_BYTES * mPushConstants.size();
|
||||
for (size_t i = 0; i < mPushConstants.size(); i++) {
|
||||
const auto& constant = mPushConstants[i];
|
||||
std::visit(
|
||||
[i](auto arg) {
|
||||
if constexpr (std::is_same_v<decltype(arg), bool>) {
|
||||
// bool push constants are converted to uints in MSL.
|
||||
// We must ensure we write all the bytes for boolean values to work
|
||||
// correctly.
|
||||
uint32_t boolAsUint = arg ? 0x00000001 : 0x00000000;
|
||||
*(reinterpret_cast<uint32_t*>(buffer + PUSH_CONSTANT_SIZE_BYTES * i)) =
|
||||
boolAsUint;
|
||||
} else {
|
||||
*(decltype(arg)*)(buffer + PUSH_CONSTANT_SIZE_BYTES * i) = arg;
|
||||
}
|
||||
},
|
||||
constant);
|
||||
}
|
||||
|
||||
switch (stage) {
|
||||
case ShaderStage::VERTEX:
|
||||
[(id<MTLRenderCommandEncoder>)encoder setVertexBytes:buffer
|
||||
length:bufferSize
|
||||
atIndex:PUSH_CONSTANT_BUFFER_INDEX];
|
||||
break;
|
||||
case ShaderStage::FRAGMENT:
|
||||
[(id<MTLRenderCommandEncoder>)encoder setFragmentBytes:buffer
|
||||
length:bufferSize
|
||||
atIndex:PUSH_CONSTANT_BUFFER_INDEX];
|
||||
break;
|
||||
case ShaderStage::COMPUTE:
|
||||
[(id<MTLComputeCommandEncoder>)encoder setBytes:buffer
|
||||
length:bufferSize
|
||||
atIndex:PUSH_CONSTANT_BUFFER_INDEX];
|
||||
break;
|
||||
}
|
||||
|
||||
mDirty = false;
|
||||
}
|
||||
|
||||
void MetalPushConstantBuffer::clear() {
|
||||
mPushConstants.clear();
|
||||
mDirty = false;
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
|
||||
@@ -243,10 +243,10 @@ void MetalDriver::setFrameScheduledCallback(
|
||||
swapChain->setFrameScheduledCallback(handler, std::move(callback));
|
||||
}
|
||||
|
||||
void MetalDriver::setFrameCompletedCallback(
|
||||
Handle<HwSwapChain> sch, CallbackHandler* handler, utils::Invocable<void(void)>&& callback) {
|
||||
void MetalDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
|
||||
CallbackHandler* handler, CallbackHandler::Callback callback, void* user) {
|
||||
auto* swapChain = handle_cast<MetalSwapChain>(sch);
|
||||
swapChain->setFrameCompletedCallback(handler, std::move(callback));
|
||||
swapChain->setFrameCompletedCallback(handler, callback, user);
|
||||
}
|
||||
|
||||
void MetalDriver::execute(std::function<void(void)> const& fn) noexcept {
|
||||
@@ -1109,10 +1109,6 @@ void MetalDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
mContext->currentPolygonOffset = {0.0f, 0.0f};
|
||||
|
||||
mContext->finalizedSamplerGroups.clear();
|
||||
|
||||
for (auto& pc : mContext->currentPushConstants) {
|
||||
pc.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void MetalDriver::nextSubpass(int dummy) {}
|
||||
@@ -1261,14 +1257,7 @@ void MetalDriver::bindSamplers(uint32_t index, Handle<HwSamplerGroup> sbh) {
|
||||
}
|
||||
|
||||
void MetalDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
|
||||
backend::PushConstantVariant value) {
|
||||
ASSERT_PRECONDITION(
|
||||
isInRenderPass(mContext), "setPushConstant must be called inside a render pass.");
|
||||
assert_invariant(static_cast<size_t>(stage) < mContext->currentPushConstants.size());
|
||||
MetalPushConstantBuffer& pushConstants =
|
||||
mContext->currentPushConstants[static_cast<size_t>(stage)];
|
||||
pushConstants.setPushConstant(value, index);
|
||||
}
|
||||
backend::PushConstantVariant value) {}
|
||||
|
||||
void MetalDriver::insertEventMarker(const char* string, uint32_t len) {
|
||||
|
||||
@@ -1876,14 +1865,6 @@ void MetalDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t inst
|
||||
UNIFORM_BUFFER_BINDING_START, MetalBuffer::Stage::VERTEX | MetalBuffer::Stage::FRAGMENT,
|
||||
uniformsToBind, offsets, Program::UNIFORM_BINDING_COUNT);
|
||||
|
||||
// Update push constants.
|
||||
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
|
||||
auto& pushConstants = mContext->currentPushConstants[i];
|
||||
if (UTILS_UNLIKELY(pushConstants.isDirty())) {
|
||||
pushConstants.setBytes(mContext->currentRenderPassEncoder, static_cast<ShaderStage>(i));
|
||||
}
|
||||
}
|
||||
|
||||
auto primitive = handle_cast<MetalRenderPrimitive>(mContext->currentRenderPrimitive);
|
||||
|
||||
MetalIndexBuffer* indexBuffer = primitive->indexBuffer;
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
|
||||
void setFrameScheduledCallback(CallbackHandler* handler, FrameScheduledCallback&& callback);
|
||||
void setFrameCompletedCallback(
|
||||
CallbackHandler* handler, utils::Invocable<void(void)>&& callback);
|
||||
CallbackHandler* handler, CallbackHandler::Callback callback, void* user);
|
||||
|
||||
// For CAMetalLayer-backed SwapChains, presents the drawable or schedules a
|
||||
// FrameScheduledCallback.
|
||||
@@ -119,12 +119,13 @@ private:
|
||||
// PresentCallable object.
|
||||
struct {
|
||||
CallbackHandler* handler = nullptr;
|
||||
std::shared_ptr<FrameScheduledCallback> callback = nullptr;
|
||||
FrameScheduledCallback callback = {};
|
||||
} frameScheduled;
|
||||
|
||||
struct {
|
||||
CallbackHandler* handler = nullptr;
|
||||
std::shared_ptr<utils::Invocable<void(void)>> callback = nullptr;
|
||||
CallbackHandler::Callback callback = {};
|
||||
void* user = nullptr;
|
||||
} frameCompleted;
|
||||
};
|
||||
|
||||
|
||||
@@ -224,13 +224,14 @@ void MetalSwapChain::ensureDepthStencilTexture() {
|
||||
void MetalSwapChain::setFrameScheduledCallback(
|
||||
CallbackHandler* handler, FrameScheduledCallback&& callback) {
|
||||
frameScheduled.handler = handler;
|
||||
frameScheduled.callback = std::make_shared<FrameScheduledCallback>(std::move(callback));
|
||||
frameScheduled.callback = std::move(callback);
|
||||
}
|
||||
|
||||
void MetalSwapChain::setFrameCompletedCallback(
|
||||
CallbackHandler* handler, utils::Invocable<void(void)>&& callback) {
|
||||
void MetalSwapChain::setFrameCompletedCallback(CallbackHandler* handler,
|
||||
CallbackHandler::Callback callback, void* user) {
|
||||
frameCompleted.handler = handler;
|
||||
frameCompleted.callback = std::make_shared<utils::Invocable<void(void)>>(std::move(callback));
|
||||
frameCompleted.callback = callback;
|
||||
frameCompleted.user = user;
|
||||
}
|
||||
|
||||
void MetalSwapChain::present() {
|
||||
@@ -303,17 +304,17 @@ void MetalSwapChain::scheduleFrameScheduledCallback() {
|
||||
assert_invariant(drawable);
|
||||
|
||||
struct Callback {
|
||||
Callback(std::shared_ptr<FrameScheduledCallback> callback, id<CAMetalDrawable> drawable,
|
||||
Callback(FrameScheduledCallback&& callback, id<CAMetalDrawable> drawable,
|
||||
MetalDriver* driver)
|
||||
: f(callback), data(PresentDrawableData::create(drawable, driver)) {}
|
||||
std::shared_ptr<FrameScheduledCallback> f;
|
||||
: f(std::move(callback)), data(PresentDrawableData::create(drawable, driver)) {}
|
||||
FrameScheduledCallback f;
|
||||
// PresentDrawableData* is destroyed by maybePresentAndDestroyAsync() later.
|
||||
std::unique_ptr<PresentDrawableData> data;
|
||||
static void func(void* user) {
|
||||
auto* const c = reinterpret_cast<Callback*>(user);
|
||||
PresentDrawableData* presentDrawableData = c->data.release();
|
||||
PresentCallable presentCallable(presentDrawable, presentDrawableData);
|
||||
c->f->operator()(presentCallable);
|
||||
c->f(presentCallable);
|
||||
delete c;
|
||||
}
|
||||
};
|
||||
@@ -321,7 +322,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, context.driver);
|
||||
std::make_unique<Callback>(std::move(frameScheduled.callback), drawable, context.driver);
|
||||
|
||||
backend::CallbackHandler* handler = frameScheduled.handler;
|
||||
MetalDriver* driver = context.driver;
|
||||
@@ -336,25 +337,13 @@ void MetalSwapChain::scheduleFrameCompletedCallback() {
|
||||
return;
|
||||
}
|
||||
|
||||
struct Callback {
|
||||
Callback(std::shared_ptr<utils::Invocable<void(void)>> callback) : f(callback) {}
|
||||
std::shared_ptr<utils::Invocable<void(void)>> f;
|
||||
static void func(void* user) {
|
||||
auto* const c = reinterpret_cast<Callback*>(user);
|
||||
c->f->operator()();
|
||||
delete c;
|
||||
}
|
||||
};
|
||||
|
||||
// This callback pointer will be captured by the block. Even if the completed handler is never
|
||||
// called, the unique_ptr will still ensure we don't leak memory.
|
||||
__block auto callback = std::make_unique<Callback>(frameCompleted.callback);
|
||||
|
||||
CallbackHandler* handler = frameCompleted.handler;
|
||||
void* user = frameCompleted.user;
|
||||
CallbackHandler::Callback callback = frameCompleted.callback;
|
||||
|
||||
MetalDriver* driver = context.driver;
|
||||
[getPendingCommandBuffer(&context) addCompletedHandler:^(id<MTLCommandBuffer> cb) {
|
||||
Callback* user = callback.release();
|
||||
driver->scheduleCallback(handler, user, &Callback::func);
|
||||
driver->scheduleCallback(handler, user, callback);
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,7 @@ inline bool operator==(const SamplerParams& lhs, const SamplerParams& rhs) {
|
||||
// ------------------------------------------------------
|
||||
// 0 Zero buffer (placeholder vertex buffer) 1
|
||||
// 1-16 Filament vertex buffers 16 limited by MAX_VERTEX_BUFFER_COUNT
|
||||
// 17-25 Uniform buffers 9 Program::UNIFORM_BINDING_COUNT
|
||||
// 26 Push constants 1
|
||||
// 17-26 Uniform buffers 10 Program::UNIFORM_BINDING_COUNT
|
||||
// 27-30 Sampler groups (argument buffers) 4 Program::SAMPLER_BINDING_COUNT
|
||||
//
|
||||
// Total 31
|
||||
@@ -54,8 +53,7 @@ inline bool operator==(const SamplerParams& lhs, const SamplerParams& rhs) {
|
||||
// Bindings Buffer name Count
|
||||
// ------------------------------------------------------
|
||||
// 0-3 SSBO buffers 4 MAX_SSBO_COUNT
|
||||
// 17-25 Uniform buffers 9 Program::UNIFORM_BINDING_COUNT
|
||||
// 26 Push constants 1
|
||||
// 17-26 Uniform buffers 10 Program::UNIFORM_BINDING_COUNT
|
||||
// 27-30 Sampler groups (argument buffers) 4 Program::SAMPLER_BINDING_COUNT
|
||||
//
|
||||
// Total 18
|
||||
|
||||
@@ -59,7 +59,7 @@ void NoopDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch,
|
||||
}
|
||||
|
||||
void NoopDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
|
||||
CallbackHandler* handler, utils::Invocable<void(void)>&& callback) {
|
||||
CallbackHandler* handler, CallbackHandler::Callback callback, void* user) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3459,7 +3459,7 @@ void OpenGLDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch,
|
||||
}
|
||||
|
||||
void OpenGLDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
|
||||
CallbackHandler* handler, utils::Invocable<void(void)>&& callback) {
|
||||
CallbackHandler* handler, CallbackHandler::Callback callback, void* user) {
|
||||
DEBUG_MARKER()
|
||||
}
|
||||
|
||||
|
||||
@@ -398,7 +398,7 @@ void VulkanDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch,
|
||||
}
|
||||
|
||||
void VulkanDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
|
||||
CallbackHandler* handler, utils::Invocable<void(void)>&& callback) {
|
||||
CallbackHandler* handler, CallbackHandler::Callback callback, void* user) {
|
||||
}
|
||||
|
||||
void VulkanDriver::setPresentationTime(int64_t monotonic_clock_ns) {
|
||||
|
||||
@@ -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;
|
||||
utils::slog.e << "Failed to wait for readPixels fence=" << status << utils::io::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +22,14 @@
|
||||
#include <spirv_glsl.hpp>
|
||||
#include <spirv_msl.hpp>
|
||||
|
||||
#include <spirv-tools/libspirv.hpp>
|
||||
|
||||
#include "../src/GLSLPostProcessor.h"
|
||||
|
||||
#include "builtinResource.h"
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
@@ -36,6 +39,7 @@ namespace test {
|
||||
|
||||
using namespace glslang;
|
||||
using namespace spirv_cross;
|
||||
using namespace spvtools;
|
||||
|
||||
using namespace filament::backend;
|
||||
|
||||
@@ -128,6 +132,8 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(
|
||||
|
||||
bool ok = tShader.parse(&DefaultTBuiltInResource, version, false, msg);
|
||||
|
||||
utils::slog.e <<"-----------" << shaderCString << utils::io::endl;
|
||||
|
||||
if (!ok) {
|
||||
std::cerr << "ERROR: Unable to parse " <<
|
||||
(stage == ShaderStage::VERTEX ? "vertex" : "fragment") << " shader:" << std::endl;
|
||||
@@ -146,6 +152,13 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(
|
||||
|
||||
GlslangToSpv(*program.getIntermediate(language), spirv);
|
||||
|
||||
SpirvTools const tools(SPV_ENV_UNIVERSAL_1_3);
|
||||
std::string disassembly;
|
||||
bool rr = tools.Disassemble(spirv, &disassembly);
|
||||
|
||||
utils::slog.e <<"dissambly=" << rr << "\n" <<
|
||||
disassembly << utils::io::endl;
|
||||
|
||||
std::string result;
|
||||
|
||||
assert_invariant(backend == Backend::OPENGL ||
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::backend;
|
||||
|
||||
namespace test {
|
||||
|
||||
TEST_F(BackendTest, FrameScheduledCallback) {
|
||||
auto& api = getDriverApi();
|
||||
|
||||
// Create a SwapChain.
|
||||
// In order for the frameScheduledCallback to be called, this must be a real SwapChain (not
|
||||
// headless) so we obtain a drawable.
|
||||
auto swapChain = createSwapChain();
|
||||
|
||||
Handle<HwRenderTarget> renderTarget = api.createDefaultRenderTarget();
|
||||
|
||||
int callbackCountA = 0;
|
||||
api.setFrameScheduledCallback(swapChain, nullptr, [&callbackCountA](PresentCallable callable) {
|
||||
callable();
|
||||
callbackCountA++;
|
||||
});
|
||||
|
||||
// Render the first frame.
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.beginRenderPass(renderTarget, {});
|
||||
api.endRenderPass(0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Render the next frame. The same callback should be called.
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.beginRenderPass(renderTarget, {});
|
||||
api.endRenderPass(0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Now switch out the callback.
|
||||
int callbackCountB = 0;
|
||||
api.setFrameScheduledCallback(swapChain, nullptr, [&callbackCountB](PresentCallable callable) {
|
||||
callable();
|
||||
callbackCountB++;
|
||||
});
|
||||
|
||||
// Render one final frame.
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.beginRenderPass(renderTarget, {});
|
||||
api.endRenderPass(0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
api.finish();
|
||||
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
|
||||
EXPECT_EQ(callbackCountA, 2);
|
||||
EXPECT_EQ(callbackCountB, 1);
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, FrameCompletedCallback) {
|
||||
auto& api = getDriverApi();
|
||||
|
||||
// Create a SwapChain.
|
||||
auto swapChain = api.createSwapChainHeadless(256, 256, 0);
|
||||
|
||||
int callbackCountA = 0;
|
||||
api.setFrameCompletedCallback(swapChain, nullptr,
|
||||
[&callbackCountA]() { callbackCountA++; });
|
||||
|
||||
// Render the first frame.
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Render the next frame. The same callback should be called.
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Now switch out the callback.
|
||||
int callbackCountB = 0;
|
||||
api.setFrameCompletedCallback(swapChain, nullptr,
|
||||
[&callbackCountB]() { callbackCountB++; });
|
||||
|
||||
// Render one final frame.
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
api.finish();
|
||||
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
|
||||
EXPECT_EQ(callbackCountA, 2);
|
||||
EXPECT_EQ(callbackCountB, 1);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
@@ -23,11 +23,22 @@
|
||||
#include "private/filament/SamplerInterfaceBlock.h"
|
||||
#include "private/backend/SamplerGroup.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Hash.h>
|
||||
|
||||
#include <math/half.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#ifndef IOS
|
||||
#include <imageio/ImageEncoder.h>
|
||||
#include <image/ColorTransform.h>
|
||||
|
||||
using namespace image;
|
||||
#endif
|
||||
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::backend;
|
||||
|
||||
@@ -56,7 +67,7 @@ layout(location = 0) out vec4 fragColor;
|
||||
|
||||
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
||||
// This parameter is ignored for other backends.
|
||||
layout(location = 0, set = 1) uniform {samplerType} test_tex;
|
||||
layout(binding = 0, set = 1) uniform {samplerType} test_tex;
|
||||
|
||||
void main() {
|
||||
vec2 fbsize = vec2(512);
|
||||
@@ -109,6 +120,49 @@ void main() {
|
||||
)");
|
||||
|
||||
}
|
||||
static void readScreenshot(DriverApi& dapi, Handle<HwRenderTarget> rt, size_t const readWidth,
|
||||
size_t const readHeight, std::function<void(void*)> output) {
|
||||
size_t const size = readWidth * readHeight * 4;
|
||||
void* buffer = calloc(1, size);
|
||||
struct ReadPixelUserData {
|
||||
std::function<void(void*)> onRead;
|
||||
};
|
||||
ReadPixelUserData* userdata = new ReadPixelUserData{output};
|
||||
auto cb = [](void* buffer, size_t size, void* user) {
|
||||
ReadPixelUserData* data = (ReadPixelUserData*) user;
|
||||
data->onRead(buffer);
|
||||
free(buffer);
|
||||
delete data;
|
||||
};
|
||||
PixelBufferDescriptor pb(buffer, size, PixelDataFormat::RGBA, PixelDataType::UBYTE, cb,
|
||||
userdata);
|
||||
dapi.readPixels(rt, 0, 0, readWidth, readHeight, std::move(pb));
|
||||
}
|
||||
|
||||
static void dumpScreenshot(DriverApi& dapi, Handle<HwRenderTarget> rt, size_t const readWidth,
|
||||
size_t const readHeight, test::Backend backend, std::string fname = "") {
|
||||
size_t const size = readWidth * readHeight * 4;
|
||||
if (fname.empty()) {
|
||||
std::string backendStr = "gl";
|
||||
if (backend == test::Backend::METAL) {
|
||||
backendStr = "mtl";
|
||||
} else if (backend == test::Backend::VULKAN) {
|
||||
backendStr = "vk";
|
||||
}
|
||||
fname = "feedback_" + backendStr + "_" + ".png";
|
||||
}
|
||||
utils::slog.e << "writing: " << fname << utils::io::endl;
|
||||
readScreenshot(dapi, rt, readWidth, readHeight, [w = readWidth, h = readHeight, size, fname](void* buffer) {
|
||||
uint32_t const* texels = (uint32_t*) buffer;
|
||||
auto hashResutl = utils::hash::murmur3(texels, size / 4, 0);
|
||||
#ifndef IOS
|
||||
LinearImage image(w, h, 4);
|
||||
image = toLinearWithAlpha<uint8_t>(w, h, w * 4, (uint8_t*) buffer);
|
||||
std::ofstream pngstrm(fname.c_str(), std::ios::binary | std::ios::trunc);
|
||||
ImageEncoder::encode(pngstrm, ImageEncoder::Format::PNG, image, "", fname.c_str());
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
namespace test {
|
||||
|
||||
@@ -246,21 +300,22 @@ TEST_F(BackendTest, UpdateImage2D) {
|
||||
|
||||
std::vector<TestCase> testCases;
|
||||
|
||||
|
||||
// Test basic upload.
|
||||
testCases.emplace_back("RGBA, UBYTE -> RGBA8", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8);
|
||||
|
||||
// Test format conversion.
|
||||
// TODO: Vulkan crashes with `Texture at colorAttachment[0] has usage (0x01) which doesn't specify MTLTextureUsageRenderTarget (0x04)'
|
||||
testCases.emplace_back("RGBA, FLOAT -> RGBA16F", PixelDataFormat::RGBA, PixelDataType::FLOAT, TextureFormat::RGBA16F);
|
||||
|
||||
/*
|
||||
// Test texture formats not all backends support natively.
|
||||
// TODO: Vulkan crashes with "VK_FORMAT_R32G32B32_SFLOAT is not supported"
|
||||
testCases.emplace_back("RGB, FLOAT -> RGB32F", PixelDataFormat::RGB, PixelDataType::FLOAT, TextureFormat::RGB32F);
|
||||
testCases.emplace_back("RGB, FLOAT -> RGB16F", PixelDataFormat::RGB, PixelDataType::FLOAT, TextureFormat::RGB16F);
|
||||
|
||||
// Test packed format uploads.
|
||||
// packed Test format uploads.
|
||||
// TODO: Vulkan crashes with "Texture at colorAttachment[0] has usage (0x01) which doesn't specify MTLTextureUsageRenderTarget (0x04)"
|
||||
testCases.emplace_back("RGBA, UINT_2_10_10_10_REV -> RGB10_A2", PixelDataFormat::RGBA, PixelDataType::UINT_2_10_10_10_REV, TextureFormat::RGB10_A2);
|
||||
testCases.emplace_back("RGBA, UINT_2_10_10_10_REV -> RGB10_A2", PixelDataFormat::RGBA, PixelDataType::UINT_2_10_10_10_REV, TextureFormat::RGB10_A2);gitgg
|
||||
testCases.emplace_back("RGB, UINT_10F_11F_11F_REV -> R11F_G11F_B10F", PixelDataFormat::RGB, PixelDataType::UINT_10F_11F_11F_REV, TextureFormat::R11F_G11F_B10F);
|
||||
testCases.emplace_back("RGB, HALF -> R11F_G11F_B10F", PixelDataFormat::RGB, PixelDataType::HALF, TextureFormat::R11F_G11F_B10F);
|
||||
|
||||
@@ -281,8 +336,9 @@ TEST_F(BackendTest, UpdateImage2D) {
|
||||
// TODO: Vulkan crashes with "Offsets not yet supported"
|
||||
testCases.emplace_back("RGBA, UBYTE -> RGBA8 (subregions)", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8, 0u, true);
|
||||
testCases.emplace_back("RGBA, FLOAT -> RGBA16F (subregions)", PixelDataFormat::RGBA, PixelDataType::FLOAT, TextureFormat::RGBA16F, 0u, true);
|
||||
testCases.emplace_back("RGBA, UBYTE -> RGBA8 (subregions, buffer padding)", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8, 64u, true);
|
||||
testCases.emplace_back("RGBA, UBYTE -> RGBA8 (subregions, buffer padding)", PixelDataFormat::RGBA, PixelDataType::UBYTE, TextureFormat::RGBA8, 64u, true);
|
||||
testCases.emplace_back("RGB, FLOAT -> RGB32F (subregions, buffer padding)", PixelDataFormat::RGB, PixelDataType::FLOAT, TextureFormat::RGB32F, 64u, true);
|
||||
*/
|
||||
|
||||
auto& api = getDriverApi();
|
||||
|
||||
@@ -305,6 +361,7 @@ TEST_F(BackendTest, UpdateImage2D) {
|
||||
|
||||
std::string const fragment = stringReplace("{samplerType}",
|
||||
getSamplerTypeName(t.textureFormat), fragmentTemplate);
|
||||
utils::slog.e <<"sampler=" << fragment << utils::io::endl;
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
Program::Sampler psamplers[] = { utils::CString("test_tex"), 0 };
|
||||
@@ -348,6 +405,8 @@ TEST_F(BackendTest, UpdateImage2D) {
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// dumpScreenshot(api, defaultRenderTarget, 512, 512, test::Backend::VULKAN, t.name);
|
||||
|
||||
api.destroyProgram(program);
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyRenderTarget(defaultRenderTarget);
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "BackendTest.h"
|
||||
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
#include <utils/Hash.h>
|
||||
|
||||
namespace test {
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::backend;
|
||||
|
||||
static constexpr struct {
|
||||
size_t TRIANGLE_HIDE = 0;
|
||||
size_t TRIANGLE_SCALE = 1;
|
||||
size_t TRIANGLE_OFFSET_X = 2;
|
||||
size_t TRIANGLE_OFFSET_Y = 3;
|
||||
|
||||
size_t RED = 0;
|
||||
size_t GREEN = 2;
|
||||
size_t BLUE = 3;
|
||||
} pushConstantIndex;
|
||||
|
||||
static const char* const triangleVs = R"(#version 450 core
|
||||
|
||||
layout(push_constant) uniform Constants {
|
||||
bool hideTriangle;
|
||||
float triangleScale;
|
||||
float triangleOffsetX;
|
||||
float triangleOffsetY;
|
||||
} pushConstants;
|
||||
|
||||
layout(location = 0) in vec4 mesh_position;
|
||||
void main() {
|
||||
if (pushConstants.hideTriangle) {
|
||||
// Test that bools are written correctly. All bits must be 0 if the bool is false.
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
gl_Position = vec4(mesh_position.xy * pushConstants.triangleScale +
|
||||
vec2(pushConstants.triangleOffsetX, pushConstants.triangleOffsetY), 0.0, 1.0);
|
||||
#if defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
// In Vulkan, clip space is Y-down. In OpenGL and Metal, clip space is Y-up.
|
||||
gl_Position.y = -gl_Position.y;
|
||||
#endif
|
||||
})";
|
||||
|
||||
static const char* const triangleFs = R"(#version 450 core
|
||||
|
||||
layout(push_constant) uniform Constants {
|
||||
float red;
|
||||
bool padding; // test correct bool padding
|
||||
float green;
|
||||
float blue;
|
||||
} pushConstants;
|
||||
|
||||
precision mediump int; precision highp float;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = vec4(pushConstants.red, pushConstants.green, pushConstants.blue, 1.0);
|
||||
})";
|
||||
|
||||
TEST_F(BackendTest, PushConstants) {
|
||||
auto& api = getDriverApi();
|
||||
|
||||
api.startCapture(0);
|
||||
|
||||
// The test is executed within this block scope to force destructors to run before
|
||||
// executeCommands().
|
||||
{
|
||||
// Create a SwapChain and make it current.
|
||||
auto swapChain = createSwapChain();
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a program.
|
||||
ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
ProgramHandle program = api.createProgram(std::move(p));
|
||||
|
||||
Handle<HwRenderTarget> renderTarget = api.createDefaultRenderTarget();
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
|
||||
RenderPassParams params = {};
|
||||
params.flags.clear = TargetBufferFlags::COLOR0;
|
||||
params.viewport = { 0, 0, 512, 512 };
|
||||
params.clearColor = math::float4(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
|
||||
PipelineState ps = {};
|
||||
ps.program = program;
|
||||
ps.rasterState.colorWrite = true;
|
||||
ps.rasterState.depthWrite = false;
|
||||
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
|
||||
api.beginRenderPass(renderTarget, params);
|
||||
|
||||
// Set the push constants to scale the triangle in half
|
||||
api.setPushConstant(ShaderStage::VERTEX, pushConstantIndex.TRIANGLE_HIDE, false);
|
||||
api.setPushConstant(ShaderStage::VERTEX, pushConstantIndex.TRIANGLE_SCALE, 0.5f);
|
||||
api.setPushConstant(ShaderStage::VERTEX, pushConstantIndex.TRIANGLE_OFFSET_X, 0.0f);
|
||||
api.setPushConstant(ShaderStage::VERTEX, pushConstantIndex.TRIANGLE_OFFSET_Y, 0.0f);
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.RED, 0.25f);
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.GREEN, 0.5f);
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.BLUE, 1.0f);
|
||||
api.draw(ps, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
|
||||
// Draw another triangle, transposed to the upper-right.
|
||||
api.setPushConstant(ShaderStage::VERTEX, pushConstantIndex.TRIANGLE_OFFSET_X, 0.5f);
|
||||
api.setPushConstant(ShaderStage::VERTEX, pushConstantIndex.TRIANGLE_OFFSET_Y, 0.5f);
|
||||
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.RED, 1.00f);
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.GREEN, 0.5f);
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.BLUE, 0.25f);
|
||||
|
||||
api.draw(ps, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
|
||||
// Draw a final triangle, transposed to the lower-left.
|
||||
api.setPushConstant(ShaderStage::VERTEX, pushConstantIndex.TRIANGLE_OFFSET_X, -0.5f);
|
||||
api.setPushConstant(ShaderStage::VERTEX, pushConstantIndex.TRIANGLE_OFFSET_Y, -0.5f);
|
||||
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.RED, 0.5f);
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.GREEN, 0.25f);
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.BLUE, 1.00f);
|
||||
|
||||
api.draw(ps, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
|
||||
api.endRenderPass();
|
||||
|
||||
readPixelsAndAssertHash("pushConstants", 512, 512, renderTarget, 1957275826, true);
|
||||
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
// Cleanup.
|
||||
api.destroySwapChain(swapChain);
|
||||
api.destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
api.stopCapture(0);
|
||||
|
||||
// Wait for the ReadPixels result to come back.
|
||||
api.finish();
|
||||
|
||||
executeCommands();
|
||||
getDriver().purge();
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
@@ -464,11 +464,16 @@ public:
|
||||
Builder& boneIndicesAndWeights(size_t primitiveIndex,
|
||||
utils::FixedCapacityVector<
|
||||
utils::FixedCapacityVector<math::float2>> indicesAndWeightsVector) noexcept;
|
||||
|
||||
/**
|
||||
* Controls if the renderable has legacy vertex morphing targets, zero by default. This is
|
||||
* Controls if the renderable has vertex morphing targets, zero by default. This is
|
||||
* required to enable GPU morphing.
|
||||
*
|
||||
* Filament supports two morphing modes: standard (default) and legacy.
|
||||
*
|
||||
* For standard morphing, A MorphTargetBuffer must be created and provided via
|
||||
* RenderableManager::setMorphTargetBufferAt(). Standard morphing supports up to
|
||||
* \c CONFIG_MAX_MORPH_TARGET_COUNT morph targets.
|
||||
*
|
||||
* For legacy morphing, the attached VertexBuffer must provide data in the
|
||||
* appropriate VertexAttribute slots (\c MORPH_POSITION_0 etc). Legacy morphing only
|
||||
* supports up to 4 morph targets and will be deprecated in the future. Legacy morphing must
|
||||
@@ -481,52 +486,26 @@ public:
|
||||
Builder& morphing(size_t targetCount) noexcept;
|
||||
|
||||
/**
|
||||
* Controls if the renderable has vertex morphing targets, zero by default. This is
|
||||
* required to enable GPU morphing.
|
||||
* Specifies the morph target buffer for a primitive.
|
||||
*
|
||||
* Filament supports two morphing modes: standard (default) and legacy.
|
||||
* The morph target buffer must have an associated renderable and geometry. Two conditions
|
||||
* must be met:
|
||||
* 1. The number of morph targets in the buffer must equal the renderable's morph target
|
||||
* count.
|
||||
* 2. The vertex count of each morph target must equal the geometry's vertex count.
|
||||
*
|
||||
* For standard morphing, A MorphTargetBuffer must be provided.
|
||||
* Standard morphing supports up to \c CONFIG_MAX_MORPH_TARGET_COUNT morph targets.
|
||||
*
|
||||
* For legacy morphing, the attached VertexBuffer must provide data in the
|
||||
* appropriate VertexAttribute slots (\c MORPH_POSITION_0 etc). Legacy morphing only
|
||||
* supports up to 4 morph targets and will be deprecated in the future. Legacy morphing must
|
||||
* be enabled on the material definition: either via the legacyMorphing material attribute
|
||||
* or by calling filamat::MaterialBuilder::useLegacyMorphing().
|
||||
*
|
||||
* See also RenderableManager::setMorphWeights(), which can be called on a per-frame basis
|
||||
* to advance the animation.
|
||||
*/
|
||||
Builder& morphing(MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept;
|
||||
|
||||
/**
|
||||
* @deprecated Use morphing(uint8_t level, size_t primitiveIndex, size_t offset, size_t count) instead
|
||||
* @param level the level of detail (lod), only 0 can be specified
|
||||
* @param primitiveIndex zero-based index of the primitive, must be less than the count passed to Builder constructor
|
||||
* @param morphTargetBuffer specifies the morph target buffer
|
||||
* @param offset specifies where in the morph target buffer to start reading (expressed as a number of vertices)
|
||||
* @param count number of vertices in the morph target buffer to read, must equal the geometry's count (for triangles, this should be a multiple of 3)
|
||||
*/
|
||||
Builder& morphing(uint8_t level, size_t primitiveIndex,
|
||||
MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer,
|
||||
size_t offset, size_t count) noexcept;
|
||||
|
||||
/**
|
||||
* @deprecated Use morphing(uint8_t level, size_t primitiveIndex, size_t offset, size_t count) instead
|
||||
*/
|
||||
inline Builder& morphing(uint8_t level, size_t primitiveIndex,
|
||||
MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept {
|
||||
return morphing(level, primitiveIndex, morphTargetBuffer, 0,
|
||||
morphTargetBuffer->getVertexCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the the range of the MorphTargetBuffer to use with this primitive.
|
||||
*
|
||||
* @param level the level of detail (lod), only 0 can be specified
|
||||
* @param primitiveIndex zero-based index of the primitive, must be less than the count passed to Builder constructor
|
||||
* @param offset specifies where in the morph target buffer to start reading (expressed as a number of vertices)
|
||||
* @param count number of vertices in the morph target buffer to read, must equal the geometry's count (for triangles, this should be a multiple of 3)
|
||||
*/
|
||||
Builder& morphing(uint8_t level, size_t primitiveIndex,
|
||||
size_t offset, size_t count) noexcept;
|
||||
|
||||
MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept;
|
||||
|
||||
/**
|
||||
* Sets the drawing order for blended primitives. The drawing order is either global or
|
||||
@@ -786,19 +765,14 @@ public:
|
||||
/**
|
||||
* Associates a MorphTargetBuffer to the given primitive.
|
||||
*/
|
||||
void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex,
|
||||
size_t offset, size_t count);
|
||||
|
||||
/** @deprecated */
|
||||
void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex,
|
||||
MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer, size_t offset, size_t count);
|
||||
|
||||
/** @deprecated */
|
||||
/**
|
||||
* Utility method to change a MorphTargetBuffer to the given primitive
|
||||
*/
|
||||
inline void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex,
|
||||
MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) {
|
||||
setMorphTargetBufferAt(instance, level, primitiveIndex, morphTargetBuffer, 0,
|
||||
morphTargetBuffer->getVertexCount());
|
||||
}
|
||||
MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer);
|
||||
|
||||
/**
|
||||
* Get a MorphTargetBuffer to the given primitive or null if it doesn't exist.
|
||||
@@ -932,6 +906,20 @@ protected:
|
||||
~RenderableManager() = default;
|
||||
};
|
||||
|
||||
RenderableManager::Builder& RenderableManager::Builder::morphing(
|
||||
uint8_t level, size_t primitiveIndex,
|
||||
MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept {
|
||||
return morphing(level, primitiveIndex, morphTargetBuffer, 0,
|
||||
morphTargetBuffer->getVertexCount());
|
||||
}
|
||||
|
||||
void RenderableManager::setMorphTargetBufferAt(
|
||||
Instance instance, uint8_t level, size_t primitiveIndex,
|
||||
MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) {
|
||||
setMorphTargetBufferAt(instance, level, primitiveIndex, morphTargetBuffer, 0,
|
||||
morphTargetBuffer->getVertexCount());
|
||||
}
|
||||
|
||||
template<typename VECTOR, typename INDEX, typename, typename>
|
||||
Box RenderableManager::computeAABB(
|
||||
VECTOR const* UTILS_NONNULL vertices,
|
||||
|
||||
@@ -684,7 +684,6 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla
|
||||
cmd.info.indexCount = primitive.getIndexCount();
|
||||
cmd.info.type = primitive.getPrimitiveType();
|
||||
cmd.info.morphTargetBuffer = morphTargets.buffer->getHwHandle();
|
||||
cmd.info.morphingOffset = morphTargets.offset;
|
||||
|
||||
if constexpr (isColorPass) {
|
||||
RenderPass::setupColorCommand(cmd, renderableVariant, mi, inverseFrontFaces);
|
||||
@@ -1030,9 +1029,6 @@ void RenderPass::Executor::execute(FEngine& engine,
|
||||
rebindPipeline = false;
|
||||
currentPipeline = pipeline;
|
||||
driver.bindPipeline(pipeline);
|
||||
|
||||
driver.setPushConstant(ShaderStage::VERTEX,
|
||||
+PushConstantIds::MORPHING_BUFFER_OFFSET, int32_t(info.morphingOffset));
|
||||
}
|
||||
|
||||
if (info.rph != currentPrimitiveHandle) {
|
||||
|
||||
@@ -251,7 +251,6 @@ public:
|
||||
uint32_t indexCount; // 4 bytes
|
||||
uint32_t index = 0; // 4 bytes
|
||||
backend::SamplerGroupHandle morphTargetBuffer; // 4 bytes
|
||||
uint32_t morphingOffset = 0; // 4 bytes
|
||||
|
||||
backend::RasterState rasterState; // 4 bytes
|
||||
|
||||
@@ -262,7 +261,7 @@ public:
|
||||
bool hasMorphing : 1; // 1 bit
|
||||
bool hasHybridInstancing : 1; // 1 bit
|
||||
|
||||
uint32_t rfu[2]; // 16 bytes
|
||||
uint32_t rfu[3]; // 16 bytes
|
||||
};
|
||||
static_assert(sizeof(PrimitiveInfo) == 56);
|
||||
|
||||
|
||||
@@ -164,11 +164,6 @@ void RenderableManager::setMorphTargetBufferAt(Instance instance, uint8_t level,
|
||||
downcast(morphTargetBuffer), offset, count);
|
||||
}
|
||||
|
||||
void RenderableManager::setMorphTargetBufferAt(
|
||||
Instance instance, uint8_t level, size_t primitiveIndex, size_t offset, size_t count) {
|
||||
downcast(this)->setMorphTargetBufferAt(instance, level, primitiveIndex, offset, count);
|
||||
}
|
||||
|
||||
MorphTargetBuffer* RenderableManager::getMorphTargetBufferAt(Instance instance, uint8_t level,
|
||||
size_t primitiveIndex) const noexcept {
|
||||
return downcast(this)->getMorphTargetBufferAt(instance, level, primitiveIndex);
|
||||
|
||||
@@ -86,7 +86,6 @@ struct RenderableManager::BuilderDetails {
|
||||
RenderableManager::Builder::GeometryType mGeometryType : 2;
|
||||
size_t mSkinningBoneCount = 0;
|
||||
size_t mMorphTargetCount = 0;
|
||||
FMorphTargetBuffer* mMorphTargetBuffer = nullptr;
|
||||
Bone const* mUserBones = nullptr;
|
||||
mat4f const* mUserBoneMatrices = nullptr;
|
||||
FSkinningBuffer* mSkinningBuffer = nullptr;
|
||||
@@ -274,18 +273,6 @@ RenderableManager::Builder& RenderableManager::Builder::morphing(size_t targetCo
|
||||
return *this;
|
||||
}
|
||||
|
||||
RenderableManager::Builder& RenderableManager::Builder::morphing(
|
||||
MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept {
|
||||
mImpl->mMorphTargetBuffer = downcast(morphTargetBuffer);
|
||||
mImpl->mMorphTargetCount = morphTargetBuffer->getCount();
|
||||
return *this;
|
||||
}
|
||||
|
||||
RenderableManager::Builder& RenderableManager::Builder::morphing(
|
||||
uint8_t level, size_t primitiveIndex, size_t offset, size_t count) noexcept {
|
||||
return morphing(level, primitiveIndex, mImpl->mMorphTargetBuffer, offset, count);
|
||||
}
|
||||
|
||||
RenderableManager::Builder& RenderableManager::Builder::morphing(uint8_t, size_t primitiveIndex,
|
||||
MorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count) noexcept {
|
||||
std::vector<Entry>& entries = mImpl->mEntries;
|
||||
@@ -659,14 +646,10 @@ void FRenderableManager::create(
|
||||
|
||||
// Create and initialize all needed MorphTargets.
|
||||
// It's required to avoid branches in hot loops.
|
||||
FMorphTargetBuffer* morphTargetBuffer = builder->mMorphTargetBuffer;
|
||||
if (morphTargetBuffer == nullptr) {
|
||||
morphTargetBuffer = mEngine.getDummyMorphTargetBuffer();
|
||||
}
|
||||
MorphTargets* const morphTargets = new MorphTargets[entryCount];
|
||||
std::generate_n(morphTargets, entryCount,
|
||||
[morphTargetBuffer]() -> MorphTargets {
|
||||
return { morphTargetBuffer, 0, 0 };
|
||||
[dummy = mEngine.getDummyMorphTargetBuffer()]() -> MorphTargets {
|
||||
return { dummy, 0, 0 };
|
||||
});
|
||||
|
||||
mManager[ci].morphTargets = { morphTargets, size_type(entryCount) };
|
||||
@@ -966,13 +949,15 @@ void FRenderableManager::setMorphWeights(Instance instance, float const* weights
|
||||
|
||||
void FRenderableManager::setMorphTargetBufferAt(Instance instance, uint8_t level,
|
||||
size_t primitiveIndex, FMorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count) {
|
||||
assert_invariant(offset == 0 && "Offset not yet supported.");
|
||||
assert_invariant(count == morphTargetBuffer->getVertexCount() && "Count not yet supported.");
|
||||
if (instance) {
|
||||
assert_invariant(morphTargetBuffer);
|
||||
|
||||
MorphWeights const& morphWeights = mManager[instance].morphWeights;
|
||||
ASSERT_PRECONDITION(morphWeights.count == count,
|
||||
ASSERT_PRECONDITION(morphWeights.count == morphTargetBuffer->getCount(),
|
||||
"Only %d morph targets can be set (count=%d)",
|
||||
morphWeights.count, count);
|
||||
morphWeights.count, morphTargetBuffer->getCount());
|
||||
|
||||
Slice<MorphTargets>& morphTargets = getMorphTargets(instance, level);
|
||||
if (primitiveIndex < morphTargets.size()) {
|
||||
@@ -982,17 +967,6 @@ void FRenderableManager::setMorphTargetBufferAt(Instance instance, uint8_t level
|
||||
}
|
||||
}
|
||||
|
||||
void FRenderableManager::setMorphTargetBufferAt(Instance instance, uint8_t level,
|
||||
size_t primitiveIndex, size_t offset, size_t count) {
|
||||
if (instance) {
|
||||
Slice<MorphTargets>& morphTargets = getMorphTargets(instance, level);
|
||||
if (primitiveIndex < morphTargets.size()) {
|
||||
setMorphTargetBufferAt(instance, level,
|
||||
primitiveIndex, morphTargets[primitiveIndex].buffer, offset, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MorphTargetBuffer* FRenderableManager::getMorphTargetBufferAt(Instance instance, uint8_t level,
|
||||
size_t primitiveIndex) const noexcept {
|
||||
if (instance) {
|
||||
|
||||
@@ -157,8 +157,6 @@ public:
|
||||
void setMorphWeights(Instance instance, float const* weights, size_t count, size_t offset);
|
||||
void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex,
|
||||
FMorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count);
|
||||
void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex,
|
||||
size_t offset, size_t count);
|
||||
MorphTargetBuffer* getMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex) const noexcept;
|
||||
size_t getMorphTargetCount(Instance instance) const noexcept;
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ void FMorphTargetBuffer::setPositionsAt(FEngine& engine, size_t targetIndex,
|
||||
"MorphTargetBuffer (size=%lu) overflow (count=%u, offset=%u)",
|
||||
(unsigned)mVertexCount, (unsigned)count, (unsigned)offset);
|
||||
|
||||
auto size = getSize<VertexAttribute::POSITION>(count);
|
||||
auto size = getSize<VertexAttribute::POSITION>(mVertexCount);
|
||||
|
||||
ASSERT_PRECONDITION(targetIndex < mCount,
|
||||
"%d target index must be < %d", targetIndex, mCount);
|
||||
@@ -177,7 +177,7 @@ void FMorphTargetBuffer::setPositionsAt(FEngine& engine, size_t targetIndex,
|
||||
"MorphTargetBuffer (size=%lu) overflow (count=%u, offset=%u)",
|
||||
(unsigned)mVertexCount, (unsigned)count, (unsigned)offset);
|
||||
|
||||
auto size = getSize<VertexAttribute::POSITION>(count);
|
||||
auto size = getSize<VertexAttribute::POSITION>(mVertexCount);
|
||||
|
||||
ASSERT_PRECONDITION(targetIndex < mCount,
|
||||
"%d target index must be < %d", targetIndex, mCount);
|
||||
@@ -200,7 +200,7 @@ void FMorphTargetBuffer::setTangentsAt(FEngine& engine, size_t targetIndex,
|
||||
"MorphTargetBuffer (size=%lu) overflow (count=%u, offset=%u)",
|
||||
(unsigned)mVertexCount, (unsigned)count, (unsigned)offset);
|
||||
|
||||
const auto size = getSize<VertexAttribute::TANGENTS>(count);
|
||||
const auto size = getSize<VertexAttribute::TANGENTS>(mVertexCount);
|
||||
|
||||
ASSERT_PRECONDITION(targetIndex < mCount,
|
||||
"%d target index must be < %d", targetIndex, mCount);
|
||||
@@ -226,8 +226,8 @@ void FMorphTargetBuffer::updateDataAt(backend::DriverApi& driver,
|
||||
size_t const xoffset = offset % MAX_MORPH_TARGET_BUFFER_WIDTH;
|
||||
size_t const textureWidth = getWidth(mVertexCount);
|
||||
size_t const alignment = ((textureWidth - xoffset) % textureWidth);
|
||||
size_t const lineCount = (count > alignment) ? (count - alignment) / textureWidth : 0;
|
||||
size_t const lastLineCount = (count > alignment) ? (count - alignment) % textureWidth : 0;
|
||||
size_t const lineCount = (count - alignment) / textureWidth;
|
||||
size_t const lastLineCount = (count - alignment) % textureWidth;
|
||||
|
||||
// 'out' buffer is going to be used up to 3 times, so for simplicity we use a shared_buffer
|
||||
// to manage its lifetime. One side effect of this is that the callbacks below will allocate
|
||||
|
||||
@@ -79,11 +79,24 @@ bool FSwapChain::isFrameScheduledCallbackSet() const noexcept {
|
||||
return mFrameScheduledCallbackIsSet;
|
||||
}
|
||||
|
||||
void FSwapChain::setFrameCompletedCallback(
|
||||
backend::CallbackHandler* handler, FrameCompletedCallback&& callback) noexcept {
|
||||
using namespace std::placeholders;
|
||||
auto boundCallback = std::bind(std::move(callback), this);
|
||||
mEngine.getDriverApi().setFrameCompletedCallback(mHwSwapChain, handler, std::move(boundCallback));
|
||||
void FSwapChain::setFrameCompletedCallback(backend::CallbackHandler* handler,
|
||||
utils::Invocable<void(SwapChain*)>&& callback) noexcept {
|
||||
struct Callback {
|
||||
utils::Invocable<void(SwapChain*)> f;
|
||||
SwapChain* s;
|
||||
static void func(void* user) {
|
||||
auto* const c = reinterpret_cast<Callback*>(user);
|
||||
c->f(c->s);
|
||||
delete c;
|
||||
}
|
||||
};
|
||||
if (callback) {
|
||||
auto* const user = new(std::nothrow) Callback{ std::move(callback), this };
|
||||
mEngine.getDriverApi().setFrameCompletedCallback(
|
||||
mHwSwapChain, handler, &Callback::func, static_cast<void*>(user));
|
||||
} else {
|
||||
mEngine.getDriverApi().setFrameCompletedCallback(mHwSwapChain, nullptr, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool FSwapChain::isSRGBSwapChainSupported(FEngine& engine) noexcept {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.52.0"
|
||||
spec.version = "1.51.8"
|
||||
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.52.0/filament-v1.52.0-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.51.8/filament-v1.51.8-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 52;
|
||||
static constexpr size_t MATERIAL_VERSION = 51;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -72,7 +72,7 @@ enum class ReservedSpecializationConstants : uint8_t {
|
||||
CONFIG_STEREO_EYE_COUNT = 8, // don't change (hardcoded in ShaderCompilerService.cpp)
|
||||
};
|
||||
|
||||
enum class PushConstantIds : uint8_t {
|
||||
enum class PushConstantIds {
|
||||
MORPHING_BUFFER_OFFSET = 0,
|
||||
};
|
||||
|
||||
@@ -143,8 +143,6 @@ struct utils::EnableIntegerOperators<filament::SamplerBindingPoints> : public st
|
||||
template<>
|
||||
struct utils::EnableIntegerOperators<filament::ReservedSpecializationConstants> : public std::true_type {};
|
||||
template<>
|
||||
struct utils::EnableIntegerOperators<filament::PushConstantIds> : public std::true_type {};
|
||||
template<>
|
||||
struct utils::EnableIntegerOperators<filament::PostProcessVariant> : public std::true_type {};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -255,17 +255,6 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob *spirv, std::string *outMsl,
|
||||
mslCompiler.add_msl_resource_binding(argBufferBinding);
|
||||
}
|
||||
|
||||
// Bind push constants to [buffer(26)]
|
||||
MSLResourceBinding pushConstantBinding;
|
||||
// the baseType doesn't matter, but can't be UNKNOWN
|
||||
pushConstantBinding.basetype = SPIRType::BaseType::Struct;
|
||||
pushConstantBinding.stage = executionModel;
|
||||
pushConstantBinding.desc_set = kPushConstDescSet;
|
||||
pushConstantBinding.binding = kPushConstBinding;
|
||||
pushConstantBinding.count = 1;
|
||||
pushConstantBinding.msl_buffer = 26;
|
||||
mslCompiler.add_msl_resource_binding(pushConstantBinding);
|
||||
|
||||
auto updateResourceBindingDefault = [executionModel, &mslCompiler](const auto& resource) {
|
||||
auto set = mslCompiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||
auto binding = mslCompiler.get_decoration(resource.id, spv::DecorationBinding);
|
||||
|
||||
@@ -54,6 +54,7 @@ struct App {
|
||||
Skybox* skybox;
|
||||
Entity renderable;
|
||||
MorphTargetBuffer *mt1;
|
||||
MorphTargetBuffer *mt2;
|
||||
};
|
||||
|
||||
struct Vertex {
|
||||
@@ -173,7 +174,12 @@ int main(int argc, char** argv) {
|
||||
.build(*engine);
|
||||
|
||||
app.mt1 = MorphTargetBuffer::Builder()
|
||||
.vertexCount(9 * 2)
|
||||
.vertexCount(9)
|
||||
.count(3)
|
||||
.build(*engine);
|
||||
|
||||
app.mt2 = MorphTargetBuffer::Builder()
|
||||
.vertexCount(9)
|
||||
.count(3)
|
||||
.build(*engine);
|
||||
|
||||
@@ -184,12 +190,12 @@ int main(int argc, char** argv) {
|
||||
app.mt1->setTangentsAt(*engine,1, targets_tan+3, 3, 0);
|
||||
app.mt1->setTangentsAt(*engine,2, targets_tan+6, 3, 0);
|
||||
|
||||
app.mt1->setPositionsAt(*engine,0, targets_pos2, 3, 9);
|
||||
app.mt1->setPositionsAt(*engine,1, targets_pos2+3, 3, 9);
|
||||
app.mt1->setPositionsAt(*engine,2, targets_pos2+6, 3, 9);
|
||||
app.mt1->setTangentsAt(*engine,0, targets_tan, 3, 9);
|
||||
app.mt1->setTangentsAt(*engine,1, targets_tan+3, 3, 9);
|
||||
app.mt1->setTangentsAt(*engine,2, targets_tan+6, 3, 9);
|
||||
app.mt2->setPositionsAt(*engine,0, targets_pos2, 3, 0);
|
||||
app.mt2->setPositionsAt(*engine,1, targets_pos2+3, 3, 0);
|
||||
app.mt2->setPositionsAt(*engine,2, targets_pos2+6, 3, 0);
|
||||
app.mt2->setTangentsAt(*engine,0, targets_tan, 3, 0);
|
||||
app.mt2->setTangentsAt(*engine,1, targets_tan+3, 3, 0);
|
||||
app.mt2->setTangentsAt(*engine,2, targets_tan+6, 3, 0);
|
||||
|
||||
app.renderable = EntityManager::get().create();
|
||||
|
||||
@@ -203,8 +209,8 @@ int main(int argc, char** argv) {
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.morphing(3)
|
||||
.morphing(0,0,app.mt1, 0, app.mt1->getCount())
|
||||
.morphing(0,1,app.mt1, 9, app.mt1->getCount())
|
||||
.morphing(0,0,app.mt1)
|
||||
.morphing(0,1,app.mt2)
|
||||
.build(*engine, app.renderable);
|
||||
|
||||
scene->addEntity(app.renderable);
|
||||
@@ -220,6 +226,7 @@ int main(int argc, char** argv) {
|
||||
engine->destroy(app.vb);
|
||||
engine->destroy(app.ib);
|
||||
engine->destroy(app.mt1);
|
||||
engine->destroy(app.mt2);
|
||||
engine->destroyCameraComponent(app.camera);
|
||||
utils::EntityManager::get().destroy(app.camera);
|
||||
};
|
||||
|
||||
@@ -146,8 +146,7 @@ void skinNormalTangent(inout vec3 n, inout vec3 t, const uvec4 ids, const vec4 w
|
||||
#define MAX_MORPH_TARGET_BUFFER_WIDTH 2048
|
||||
|
||||
void morphPosition(inout vec4 p) {
|
||||
int index = getVertexIndex() + pushConstants.morphingBufferOffset;
|
||||
ivec3 texcoord = ivec3(index % MAX_MORPH_TARGET_BUFFER_WIDTH, index / MAX_MORPH_TARGET_BUFFER_WIDTH, 0);
|
||||
ivec3 texcoord = ivec3(getVertexIndex() % MAX_MORPH_TARGET_BUFFER_WIDTH, getVertexIndex() / MAX_MORPH_TARGET_BUFFER_WIDTH, 0);
|
||||
int c = object_uniforms_morphTargetCount;
|
||||
for (int i = 0; i < c; ++i) {
|
||||
float w = morphingUniforms.weights[i][0];
|
||||
@@ -160,8 +159,7 @@ void morphPosition(inout vec4 p) {
|
||||
|
||||
void morphNormal(inout vec3 n) {
|
||||
vec3 baseNormal = n;
|
||||
int index = getVertexIndex() + pushConstants.morphingBufferOffset;
|
||||
ivec3 texcoord = ivec3(index % MAX_MORPH_TARGET_BUFFER_WIDTH, index / MAX_MORPH_TARGET_BUFFER_WIDTH, 0);
|
||||
ivec3 texcoord = ivec3(getVertexIndex() % MAX_MORPH_TARGET_BUFFER_WIDTH, getVertexIndex() / MAX_MORPH_TARGET_BUFFER_WIDTH, 0);
|
||||
int c = object_uniforms_morphTargetCount;
|
||||
for (int i = 0; i < c; ++i) {
|
||||
float w = morphingUniforms.weights[i][0];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.52.0",
|
||||
"version": "1.51.8",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user