Compare commits

..

1 Commits

Author SHA1 Message Date
Powei Feng
277669e5fe egl: allow for ordering display init paths
On certain platforms, initialization by query device is
preferred. On others, initialization by default device is
preferred. To accommodate for either, we use a bool to switch the
ordering if needed. PlatformEGLHeadless is assumed use the query
device path first, and PlatformEGL will still check the
default device/display first.
2026-02-18 11:43:31 -08:00
19 changed files with 73 additions and 171 deletions

View File

@@ -6,5 +6,3 @@
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- engine: fix crash when using variance shadow maps

View File

@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.69.4'
implementation 'com.google.android.filament:filament-android:1.69.2'
}
```
@@ -50,7 +50,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.69.4'
pod 'Filament', '~> 1.69.2'
```
## Documentation

View File

@@ -7,9 +7,6 @@ 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.69.4
## v1.69.3

View File

@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.69.4
VERSION_NAME=1.69.2
POM_DESCRIPTION=Real-time physically based rendering engine for Android.

View File

@@ -83,6 +83,22 @@ protected:
*/
Driver* createDriver(void* sharedContext, const DriverConfig& driverConfig) override;
/**
* The implementation of *createDriver*.
* @param sharedContext an optional shared context. This is not meaningful with all graphic
* APIs and platforms.
* For EGL platforms, this is an EGLContext.
*
* @param driverConfig specifies driver initialization parameters
*
* @param initFirstbyquery determines the order of initialization. If true, then we'd query by
* eglQueryDevicesEXT first instead of using the default display. Useful
* for headless egl initialization.
* @return nullptr on failure, or a pointer to the newly created driver.
*/
Driver* createDriverBase(void* sharedContext, const DriverConfig& driverConfig,
bool initFirstByQuery);
/**
* This returns zero. This method can be overridden to return something more useful.
* @return zero

View File

@@ -123,63 +123,6 @@ void reshapeImageImpl(uint8_t* UTILS_RESTRICT dest, const uint8_t* UTILS_RESTRIC
}
}
struct UnpackerR11G11B10 {
static void unpack(const uint8_t* src, float* out) {
uint32_t p;
std::memcpy(&p, src, 4);
using R11 = math::fp<0, 5, 6>;
using G11 = math::fp<0, 5, 6>;
using B10 = math::fp<0, 5, 5>;
out[0] = R11::tof(R11(uint16_t((p >> 21) & 0x7FF)));
out[1] = G11::tof(G11(uint16_t((p >> 10) & 0x7FF)));
out[2] = B10::tof(B10(uint16_t(p & 0x3FF)));
}
};
template<typename dstComponentType, typename Unpacker, bool Swizzle>
static void reshapeImagePacked(uint8_t* UTILS_RESTRICT dest, const uint8_t* UTILS_RESTRICT src,
size_t srcBytesPerRow, size_t srcChannelCount, size_t dstRowOffset, size_t dstColumnOffset,
size_t dstBytesPerRow, size_t dstChannelCount, size_t width, size_t height, bool /*swizzle*/) {
dest += (dstRowOffset * dstBytesPerRow);
const dstComponentType dstMaxValue = getMaxValue<dstComponentType>();
for (size_t row = 0; row < height; ++row) {
const uint8_t* inPtr = src;
dstComponentType* out = (dstComponentType*) dest + (dstColumnOffset * dstChannelCount);
for (size_t column = 0; column < width; ++column) {
float rgba[4] = {0.0f, 0.0f, 0.0f, 1.0f};
Unpacker::unpack(inPtr, rgba);
if constexpr (Swizzle) {
std::swap(rgba[0], rgba[2]);
}
for (size_t c = 0; c < dstChannelCount; ++c) {
if constexpr (std::is_same_v<dstComponentType, float>) {
out[c] = rgba[c];
} else if constexpr (std::is_same_v<dstComponentType, math::half>) {
out[c] = math::half(rgba[c]);
} else {
out[c] = static_cast<dstComponentType>(std::clamp(
static_cast<double>(rgba[c]) * static_cast<double>(dstMaxValue),
0.0,
static_cast<double>(std::numeric_limits<dstComponentType>::max())
));
}
}
inPtr += 4;
out += dstChannelCount;
}
src += srcBytesPerRow;
dest += dstBytesPerRow;
}
}
} // anonymous namespace
class DataReshaper {
@@ -251,8 +194,6 @@ public:
constexpr auto UINT = PixelDataType::UINT;
constexpr auto INT = PixelDataType::INT;
constexpr auto HALF = PixelDataType::HALF;
constexpr auto UINT_10F_11F_11F_REV = PixelDataType::UINT_10F_11F_11F_REV;
switch (dst->type) {
case UBYTE:
switch (srcType) {
@@ -268,10 +209,6 @@ public:
case INT: reshaper = reshapeImageImpl<uint8_t, int32_t>; break;
case UINT: reshaper = reshapeImageImpl<uint8_t, uint32_t>; break;
case HALF: reshaper = reshapeImageImpl<uint8_t, math::half>; break;
case UINT_10F_11F_11F_REV:
if (swizzle) reshaper = reshapeImagePacked<uint8_t, UnpackerR11G11B10, true>;
else reshaper = reshapeImagePacked<uint8_t, UnpackerR11G11B10, false>;
break;
default:
LOG(ERROR) << "DataReshaper: UBYTE dst, unsupported srcType: "
<< (int) srcType;
@@ -284,10 +221,6 @@ public:
case FLOAT: reshaper = reshapeImageImpl<float, float>; break;
case INT: reshaper = reshapeImageImpl<float, int32_t>; break;
case UINT: reshaper = reshapeImageImpl<float, uint32_t>; break;
case UINT_10F_11F_11F_REV:
if (swizzle) reshaper = reshapeImagePacked<float, UnpackerR11G11B10, true>;
else reshaper = reshapeImagePacked<float, UnpackerR11G11B10, false>;
break;
default:
LOG(ERROR) << "DataReshaper: FLOAT dst, unsupported srcType: "
<< (int) srcType;
@@ -300,10 +233,6 @@ public:
case FLOAT: reshaper = reshapeImageImpl<int32_t, float>; break;
case INT: reshaper = reshapeImageImpl<int32_t, int32_t>; break;
case UINT: reshaper = reshapeImageImpl<int32_t, uint32_t>; break;
case UINT_10F_11F_11F_REV:
if (swizzle) reshaper = reshapeImagePacked<int32_t, UnpackerR11G11B10, true>;
else reshaper = reshapeImagePacked<int32_t, UnpackerR11G11B10, false>;
break;
default:
LOG(ERROR)
<< "DataReshaper: INT dst, unsupported srcType: " << (int) srcType;
@@ -316,10 +245,6 @@ public:
case FLOAT: reshaper = reshapeImageImpl<uint32_t, float>; break;
case INT: reshaper = reshapeImageImpl<uint32_t, int32_t>; break;
case UINT: reshaper = reshapeImageImpl<uint32_t, uint32_t>; break;
case UINT_10F_11F_11F_REV:
if (swizzle) reshaper = reshapeImagePacked<uint32_t, UnpackerR11G11B10, true>;
else reshaper = reshapeImagePacked<uint32_t, UnpackerR11G11B10, false>;
break;
default:
LOG(ERROR)
<< "DataReshaper: UINT dst, unsupported srcType: " << (int) srcType;
@@ -331,10 +256,6 @@ public:
case HALF:
reshaper = copyImage;
break;
case UINT_10F_11F_11F_REV:
if (swizzle) reshaper = reshapeImagePacked<math::half, UnpackerR11G11B10, true>;
else reshaper = reshapeImagePacked<math::half, UnpackerR11G11B10, false>;
break;
default:
LOG(ERROR)
<< "DataReshaper: HALF dst, unsupported srcType: " << (int) srcType;

View File

@@ -3623,8 +3623,6 @@ void OpenGLDriver::detachStream(GLTexture* t) noexcept {
case StreamType::NATIVE:
mPlatform.detach(t->hwStream->stream);
// ^ this deletes the texture id
// We still need to call unbind to update the bookkeeping.
gl.unbindTexture(t->gl.target, t->gl.id);
break;
case StreamType::ACQUIRED:
gl.unbindTexture(t->gl.target, t->gl.id);

View File

@@ -120,17 +120,28 @@ bool PlatformEGL::isOpenGL() const noexcept {
PlatformEGL::ExternalImageEGL::~ExternalImageEGL() = default;
Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& driverConfig) {
return createDriverBase(sharedContext, driverConfig, false /* initFirstByQuery */);
}
Driver* PlatformEGL::createDriverBase(void* sharedContext, const DriverConfig& driverConfig,
bool initFirstByQuery) {
static constexpr int kMaxNumEGLDevices = 32;
EGLint major, minor;
EGLBoolean initialized = false;
PFNEGLQUERYDEVICESEXTPROC const eglQueryDevicesEXT =
PFNEGLQUERYDEVICESEXTPROC(eglGetProcAddress("eglQueryDevicesEXT"));
PFNEGLGETPLATFORMDISPLAYEXTPROC const getPlatformDisplay =
PFNEGLGETPLATFORMDISPLAYEXTPROC(eglGetProcAddress("eglGetPlatformDisplay"));
using InitFunc = std::function<void()>;
InitFunc queryInit = [&]() {
PFNEGLQUERYDEVICESEXTPROC const eglQueryDevicesEXT =
PFNEGLQUERYDEVICESEXTPROC(eglGetProcAddress("eglQueryDevicesEXT"));
PFNEGLGETPLATFORMDISPLAYEXTPROC const getPlatformDisplay =
PFNEGLGETPLATFORMDISPLAYEXTPROC(eglGetProcAddress("eglGetPlatformDisplay"));
if (!eglQueryDevicesEXT || !getPlatformDisplay) {
return;
}
if (eglQueryDevicesEXT != nullptr && getPlatformDisplay != nullptr) {
EGLint numDevices = 0;
EGLDeviceEXT eglDevices[kMaxNumEGLDevices];
if (eglQueryDevicesEXT(kMaxNumEGLDevices, eglDevices, &numDevices)) {
@@ -139,12 +150,27 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& drive
initialized = eglInitialize(mEGLDisplay, &major, &minor);
}
}
};
InitFunc defaultInit = [&]() {
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
initialized = eglInitialize(mEGLDisplay, &major, &minor);
};
// The order by which we check for display/device does matter because certain platforms have
// multiple displays/devices. We either return the first queried (and successfully init'd
// display) or just use the default display. Deciding which init path should go first is
// determined by the bool *initFirstByQuery*..
std::array<InitFunc, 2> initFuncs{ defaultInit, queryInit };
if (initFirstByQuery) {
std::swap(initFuncs[0], initFuncs[1]);
}
if (!initialized) {
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
assert_invariant(mEGLDisplay != EGL_NO_DISPLAY);
initialized = eglInitialize(mEGLDisplay, &major, &minor);
for (auto& initFunc: initFuncs) {
if (initialized) {
break;
}
initFunc();
}
if (UTILS_UNLIKELY(!initialized)) {

View File

@@ -66,7 +66,7 @@ backend::Driver* PlatformEGLHeadless::createDriver(void* sharedContext,
return nullptr;
}
return PlatformEGL::createDriver(sharedContext, driverConfig);
return PlatformEGL::createDriverBase(sharedContext, driverConfig, true /* initFirstByQuery */);
}
} // namespace filament

View File

@@ -2481,7 +2481,6 @@ void VulkanDriver::bindPipelineImpl(PipelineState const& pipelineState,
// Push state changes to the VulkanPipelineCache instance. This is fast and does not make VK calls.
mPipelineCache.bindProgram(program);
mPipelineCache.bindRasterState(vulkanRasterState);
mPipelineCache.bindStencilState(pipelineState.stencilState);
mPipelineCache.bindPrimitiveTopology(topology);
mPipelineCache.bindVertexArray(attribDesc, bufferDesc, vbi->getAttributeCount());

View File

@@ -166,7 +166,6 @@ void VulkanPipelineCache::asyncPrewarmCache(
.depthBiasConstantFactor = 0.f,
.depthBiasSlopeFactor = 0.f,
},
.stencilState = {},
.layout = layout,
};
PipelineDynamicOptions dynamicOptions {
@@ -298,45 +297,24 @@ VkPipeline VulkanPipelineCache::createPipeline(
bool const enableDepthTest =
raster.depthCompareOp != SamplerCompareFunc::A ||
raster.depthWriteEnable;
// Stencil must be enabled if we're testing OR writing to the stencil buffer.
auto const& stencil = key.stencilState;
bool const enableStencilTest =
stencil.front.stencilFunc != StencilState::StencilFunction::A ||
stencil.back.stencilFunc != StencilState::StencilFunction::A ||
stencil.front.stencilOpDepthFail != StencilOperation::KEEP ||
stencil.back.stencilOpDepthFail != StencilOperation::KEEP ||
stencil.front.stencilOpStencilFail != StencilOperation::KEEP ||
stencil.back.stencilOpStencilFail != StencilOperation::KEEP ||
stencil.front.stencilOpDepthStencilPass != StencilOperation::KEEP ||
stencil.back.stencilOpDepthStencilPass != StencilOperation::KEEP ||
stencil.stencilWrite;
VkPipelineDepthStencilStateCreateInfo vkDs = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.depthTestEnable = enableDepthTest ? VK_TRUE : VK_FALSE,
.depthWriteEnable = raster.depthWriteEnable,
.depthCompareOp = fvkutils::getCompareOp(raster.depthCompareOp),
.depthBoundsTestEnable = VK_FALSE,
.stencilTestEnable = enableStencilTest ? VK_TRUE : VK_FALSE,
.stencilTestEnable = VK_FALSE,
.minDepthBounds = 0.0f,
.maxDepthBounds = 0.0f,
};
vkDs.front = {
.failOp = fvkutils::getStencilOp(stencil.front.stencilOpStencilFail),
.passOp = fvkutils::getStencilOp(stencil.front.stencilOpDepthStencilPass),
.depthFailOp = fvkutils::getStencilOp(stencil.front.stencilOpDepthFail),
.compareOp = fvkutils::getCompareOp(stencil.front.stencilFunc),
.compareMask = stencil.front.readMask,
.writeMask = (uint32_t) (stencil.stencilWrite ? stencil.front.writeMask : 0u),
.reference = (uint32_t) stencil.front.ref,
};
vkDs.back = {
.failOp = fvkutils::getStencilOp(stencil.back.stencilOpStencilFail),
.passOp = fvkutils::getStencilOp(stencil.back.stencilOpDepthStencilPass),
.depthFailOp = fvkutils::getStencilOp(stencil.back.stencilOpDepthFail),
.compareOp = fvkutils::getCompareOp(stencil.back.stencilFunc),
.compareMask = stencil.back.readMask,
.writeMask = (uint32_t) (stencil.stencilWrite ? stencil.back.writeMask : 0u),
.reference = (uint32_t) stencil.back.ref,
vkDs.front = vkDs.back = {
.failOp = VK_STENCIL_OP_KEEP,
.passOp = VK_STENCIL_OP_KEEP,
.depthFailOp = VK_STENCIL_OP_KEEP,
.compareOp = VK_COMPARE_OP_ALWAYS,
.compareMask = 0u,
.writeMask = 0u,
.reference = 0u,
};
VkGraphicsPipelineCreateInfo pipelineCreateInfo = {
@@ -455,10 +433,6 @@ void VulkanPipelineCache::bindRasterState(RasterState const& rasterState) noexce
mPipelineRequirements.rasterState = rasterState;
}
void VulkanPipelineCache::bindStencilState(StencilState const& stencilState) noexcept {
mPipelineRequirements.stencilState = stencilState;
}
void VulkanPipelineCache::bindRenderPass(VkRenderPass renderPass, int subpassIndex) noexcept {
mPipelineRequirements.renderPass = renderPass;
mPipelineRequirements.subpassIndex = subpassIndex;

View File

@@ -122,7 +122,6 @@ public:
void bindLayout(VkPipelineLayout layout) noexcept;
void bindProgram(fvkmemory::resource_ptr<VulkanProgram> program) noexcept;
void bindRasterState(RasterState const& rasterState) noexcept;
void bindStencilState(StencilState const& stencilState) noexcept;
void bindRenderPass(VkRenderPass renderPass, int subpassIndex) noexcept;
void bindPrimitiveTopology(VkPrimitiveTopology topology) noexcept;
void bindVertexArray(VkVertexInputAttributeDescription const* attribDesc,
@@ -187,8 +186,8 @@ private:
VertexInputAttributeDescription vertexAttributes[VERTEX_ATTRIBUTE_COUNT]; // 128 : 28
VertexInputBindingDescription vertexBuffers[VERTEX_ATTRIBUTE_COUNT]; // 128 : 156
RasterState rasterState; // 16 : 284
StencilState stencilState; // 12 : 300
VkPipelineLayout layout; // 8 : 312
uint32_t padding; // 4 : 300
VkPipelineLayout layout; // 8 : 304
};
// Provides information about any dynamic state that should be used in creation of the
@@ -204,7 +203,7 @@ private:
uint8_t stereoscopicViewCount = 2;
};
static_assert(sizeof(PipelineKey) == 320, "PipelineKey must not have implicit padding.");
static_assert(sizeof(PipelineKey) == 312, "PipelineKey must not have implicit padding.");
using PipelineHashFn = utils::hash::MurmurHashFn<PipelineKey>;

View File

@@ -633,19 +633,6 @@ VkCompareOp getCompareOp(SamplerCompareFunc func) {
}
}
VkStencilOp getStencilOp(StencilOperation op) {
switch (op) {
case StencilOperation::KEEP: return VK_STENCIL_OP_KEEP;
case StencilOperation::ZERO: return VK_STENCIL_OP_ZERO;
case StencilOperation::REPLACE: return VK_STENCIL_OP_REPLACE;
case StencilOperation::INCR: return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
case StencilOperation::INCR_WRAP: return VK_STENCIL_OP_INCREMENT_AND_WRAP;
case StencilOperation::DECR: return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
case StencilOperation::DECR_WRAP: return VK_STENCIL_OP_DECREMENT_AND_WRAP;
case StencilOperation::INVERT: return VK_STENCIL_OP_INVERT;
}
}
VkBlendFactor getBlendFactor(BlendFunction mode) {
switch (mode) {
case BlendFunction::ZERO: return VK_BLEND_FACTOR_ZERO;

View File

@@ -53,7 +53,6 @@ uint32_t getBytesPerPixel(TextureFormat format);
uint8_t getTexelBlockSize(VkFormat format);
VkCompareOp getCompareOp(SamplerCompareFunc func);
VkStencilOp getStencilOp(StencilOperation op);
VkBlendFactor getBlendFactor(BlendFunction mode);
VkCullModeFlags getCullMode(CullingMode mode);
VkFrontFace getFrontFace(bool inverseFrontFaces);

View File

@@ -798,12 +798,6 @@ void FEngine::submitFrame() {
void FEngine::flush() {
// flush the command buffer
flushCommandBuffer(mCommandBufferQueue);
// In single-threaded mode, we have to call execute() to drain the command
// buffer to really free up space
if constexpr (!UTILS_HAS_THREADING) {
execute();
}
}
void FEngine::flushAndWait() {

View File

@@ -378,14 +378,8 @@ private:
Variant variant = {}) const noexcept;
bool isSharedVariant(Variant const variant) const {
// HACK: The default material "should" have VSM | DEP, but then we'd have to compile it as a
// lit material, which would increase binary size. Perhaps we could specially compile it
// with this variant, but with the shader program cache in active development, the days of
// the default material are numbered anyway.
constexpr Variant::type_t vsmAndDep = Variant::VSM | Variant::DEP;
return mDefinition.materialDomain == MaterialDomain::SURFACE && !mIsDefaultMaterial &&
!mDefinition.hasCustomDepthShader && Variant::isValidDepthVariant(variant) &&
(variant.key & vsmAndDep) != vsmAndDep;
return (mDefinition.materialDomain == MaterialDomain::SURFACE) && !mIsDefaultMaterial &&
!mDefinition.hasCustomDepthShader && Variant::isValidDepthVariant(variant);
}
mutable utils::FixedCapacityVector<backend::Handle<backend::HwProgram>> mCachedPrograms;

View File

@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.69.4"
spec.version = "1.69.2"
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.69.4/filament-v1.69.4-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.69.2/filament-v1.69.2-ios.tgz" }
spec.libraries = 'c++'

View File

@@ -94,7 +94,7 @@ public:
} backend;
struct {
bool check_crc32_after_loading = false;
bool enable_material_instance_uniform_batching = false;
bool enable_material_instance_uniform_batching = true;
bool enable_fog_as_postprocess = false;
} material;
} features;

View File

@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.69.4",
"version": "1.69.2",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",