Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be3239810a | ||
|
|
e8b268bce4 | ||
|
|
88ef82a611 | ||
|
|
b4256c1c15 | ||
|
|
b49b61e131 | ||
|
|
92dc063a8a | ||
|
|
e8fe85ee89 | ||
|
|
0b63969aab | ||
|
|
af71d773ae | ||
|
|
57faae4645 | ||
|
|
e6cf5fa815 |
@@ -7,6 +7,9 @@ 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.71.1
|
||||
|
||||
|
||||
## v1.71.0
|
||||
|
||||
- matc: better material compression using a Multi-Base Variable-Length Interleaved Token Stream [⚠️ **New Material Version**]
|
||||
|
||||
+12
-13
@@ -204,10 +204,9 @@
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"license": "MIT",
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -235,9 +234,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz",
|
||||
"integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
@@ -410,9 +409,9 @@
|
||||
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -429,9 +428,9 @@
|
||||
"integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q=="
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz",
|
||||
"integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
||||
+2
-2
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.70.1'
|
||||
implementation 'com.google.android.filament:filament-android:1.70.2'
|
||||
}
|
||||
</code></pre>
|
||||
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
|
||||
@@ -195,7 +195,7 @@ dependencies {
|
||||
</div>
|
||||
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
|
||||
<p>iOS projects can use CocoaPods to install the latest release:</p>
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.70.1'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.70.2'
|
||||
</code></pre>
|
||||
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
|
||||
<ul>
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1740,6 +1740,10 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
|
||||
assert_invariant(target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
|
||||
GL_RENDERBUFFER, t->gl.id);
|
||||
|
||||
// Clear the resolve bit for this particular attachment. Note that other attachment(s)
|
||||
// might be sampleable, so this does not necessarily prevent the resolve from occurring.
|
||||
resolveFlags = TargetBufferFlags::NONE;
|
||||
}
|
||||
break;
|
||||
case GL_TEXTURE_3D:
|
||||
@@ -1879,6 +1883,11 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
|
||||
CHECK_GL_ERROR()
|
||||
}
|
||||
|
||||
// We don't need to resolve attachments that match the rendertarget's sample count.
|
||||
if (rt->gl.samples == t->samples) {
|
||||
resolveFlags = TargetBufferFlags::NONE;
|
||||
}
|
||||
|
||||
rt->gl.resolve |= resolveFlags;
|
||||
|
||||
CHECK_GL_ERROR()
|
||||
@@ -3768,20 +3777,6 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
// each render-pass starts with a disabled scissor
|
||||
gl.disable(GL_SCISSOR_TEST);
|
||||
|
||||
if (gl.ext.EXT_discard_framebuffer
|
||||
&& !gl.bugs.disable_invalidate_framebuffer) {
|
||||
AttachmentArray attachments; // NOLINT
|
||||
if (GLsizei const attachmentCount = getAttachments(attachments, discardFlags, !fbo)) {
|
||||
gl.procs.invalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
|
||||
}
|
||||
CHECK_GL_ERROR()
|
||||
} else {
|
||||
// It's important to clear the framebuffer before drawing, as it resets
|
||||
// the fb to a known state (resets fb compression and possibly other things).
|
||||
// So we use glClear instead of glInvalidateFramebuffer
|
||||
clearWithRasterPipe(discardFlags & ~clearFlags, { 0.0f }, 0.0f, 0);
|
||||
}
|
||||
|
||||
if (rt->gl.fbo_read) {
|
||||
// we have a multi-sample RenderTarget with non multi-sample attachments (i.e. this is the
|
||||
// EXT_multisampled_render_to_texture emulation).
|
||||
@@ -3793,9 +3788,26 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
discardFlags |= rt->gl.resolve;
|
||||
}
|
||||
|
||||
// we don't discard attachments that are cleared (because clear is an implicit discard)
|
||||
TargetBufferFlags const discardOnlyFlags = discardFlags & ~clearFlags;
|
||||
|
||||
if (any(discardOnlyFlags)) {
|
||||
if (gl.ext.EXT_discard_framebuffer && !gl.bugs.disable_invalidate_framebuffer) {
|
||||
AttachmentArray attachments; // NOLINT
|
||||
if (GLsizei const attachmentCount = getAttachments(attachments, discardOnlyFlags, !fbo)) {
|
||||
gl.procs.invalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
|
||||
}
|
||||
CHECK_GL_ERROR()
|
||||
} else {
|
||||
// It's important to clear the framebuffer before drawing, as it resets
|
||||
// the fb to a known state (resets fb compression and possibly other things).
|
||||
// So we use glClear instead of glInvalidateFramebuffer
|
||||
clearWithRasterPipe(discardOnlyFlags, { 0.0f }, 0.0f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (any(clearFlags)) {
|
||||
clearWithRasterPipe(clearFlags,
|
||||
params.clearColor, GLfloat(params.clearDepth), GLint(params.clearStencil));
|
||||
clearWithRasterPipe(clearFlags, params.clearColor, GLfloat(params.clearDepth), GLint(params.clearStencil));
|
||||
}
|
||||
|
||||
// we need to reset those after we call clearWithRasterPipe()
|
||||
@@ -3812,8 +3824,7 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
|
||||
#ifndef NDEBUG
|
||||
// clear the discarded (but not the cleared ones) buffers in debug builds
|
||||
clearWithRasterPipe(discardFlags & ~clearFlags,
|
||||
{ 1, 0, 0, 1 }, 1.0, 0);
|
||||
clearWithRasterPipe(discardOnlyFlags, { 1, 0, 0, 1 }, 1.0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.7 KiB |
@@ -31,10 +31,7 @@ using namespace filament;
|
||||
using namespace filament::backend;
|
||||
using namespace filament::math;
|
||||
|
||||
TEST_F(BackendTest, AutoresolveDifferingSampleCounts) {
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::OPENGL), "see b/486954356");
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::VULKAN), "see b/486954356");
|
||||
|
||||
TEST_F(BackendTest, Autoresolve) {
|
||||
auto& api = getDriverApi();
|
||||
constexpr int kRenderTargetSize = 512;
|
||||
|
||||
@@ -61,33 +58,7 @@ TEST_F(BackendTest, AutoresolveDifferingSampleCounts) {
|
||||
TextureFormat::RGBA8, 1, kRenderTargetSize, kRenderTargetSize, 1,
|
||||
TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE));
|
||||
|
||||
// First render pass: render a red triangle to a RenderTarget with 8 samples.
|
||||
{
|
||||
Handle<HwRenderTarget> renderTarget =
|
||||
addCleanup(api.createRenderTarget(TargetBufferFlags::COLOR, kRenderTargetSize,
|
||||
kRenderTargetSize, 8, 1, { { texture } }, {}, {}));
|
||||
|
||||
shader.uploadUniform(api, ubuffer,
|
||||
SimpleMaterialParams{
|
||||
.color = float4(1, 0, 0, 1),
|
||||
});
|
||||
|
||||
RenderPassParams params = getClearColorRenderPass(float4(0));
|
||||
params.viewport = { 0, 0, kRenderTargetSize, kRenderTargetSize };
|
||||
|
||||
RenderFrame frame(api);
|
||||
api.beginRenderPass(renderTarget, params);
|
||||
ps.primitiveType = PrimitiveType::TRIANGLES;
|
||||
ps.vertexBufferInfo = triangle.getVertexBufferInfo();
|
||||
api.bindPipeline(ps);
|
||||
api.bindRenderPrimitive(triangle.getRenderPrimitive());
|
||||
api.draw2(0, 3, 1);
|
||||
api.endRenderPass();
|
||||
api.commit(swapChain);
|
||||
}
|
||||
|
||||
// Second render pass: render a green triangle to a RenderTarget with 4 samples, attached to
|
||||
// the same texture.
|
||||
// render a red triangle to a RenderTarget with 4 samples.
|
||||
{
|
||||
Handle<HwRenderTarget> renderTarget =
|
||||
addCleanup(api.createRenderTarget(TargetBufferFlags::COLOR, kRenderTargetSize,
|
||||
@@ -95,10 +66,10 @@ TEST_F(BackendTest, AutoresolveDifferingSampleCounts) {
|
||||
|
||||
shader.uploadUniform(api, ubuffer,
|
||||
SimpleMaterialParams{
|
||||
.color = float4(0, 1, 0, 1),
|
||||
.color = float4(1, 0, 0, 1),
|
||||
});
|
||||
|
||||
RenderPassParams params = getClearColorRenderPass(float4(0));
|
||||
RenderPassParams params = getClearColorRenderPass(float4(1));
|
||||
params.viewport = { 0, 0, kRenderTargetSize, kRenderTargetSize };
|
||||
|
||||
RenderFrame frame(api);
|
||||
@@ -109,11 +80,10 @@ TEST_F(BackendTest, AutoresolveDifferingSampleCounts) {
|
||||
api.bindRenderPrimitive(triangle.getRenderPrimitive());
|
||||
api.draw2(0, 3, 1);
|
||||
api.endRenderPass();
|
||||
api.commit(swapChain);
|
||||
|
||||
EXPECT_IMAGE(renderTarget, ScreenshotParams(kRenderTargetSize, kRenderTargetSize,
|
||||
"AutoresolveDifferingSampleCounts", 1048576));
|
||||
|
||||
api.commit(swapChain);
|
||||
"Autoresolve", 545665143));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ static void createFaces(DriverApi& dapi, Handle<HwTexture> texture, int baseWidt
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, ColorMagnify) {
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::OPENGL), "b/453757697");
|
||||
// b/453757697: MESA glBlitFramebuffer linear interpolation fallback precision slightly mismatches.
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::VULKAN), "b/453777397");
|
||||
SKIP_IF(Backend::WEBGPU, "test cases fail in WebGPU, see b/424157731");
|
||||
|
||||
@@ -206,15 +206,13 @@ TEST_F(BlitTest, ColorMagnify) {
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
EXPECT_IMAGE(dstRenderTargets[0],
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMagnify", 0x410bdd31));
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMagnify", 0x410bdd31, false, 8000, 5));
|
||||
api.commit(swapChain);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, ColorMinify) {
|
||||
SKIP_IF(Backend::WEBGPU, "test cases fail in WebGPU, see b/424157731");
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::OPENGL), "b/453758045");
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::VULKAN), "b/453776623");
|
||||
|
||||
auto& api = getDriverApi();
|
||||
mCleanup.addPostCall([&]() { executeCommands(); });
|
||||
@@ -268,7 +266,7 @@ TEST_F(BlitTest, ColorMinify) {
|
||||
SamplerMagFilter::LINEAR);
|
||||
|
||||
EXPECT_IMAGE(dstRenderTargets[0],
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMinify", 0xf3d9c53f));
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorMinify", 0xf3d9c53f, false, 8000, 5));
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, ColorResolve) {
|
||||
@@ -355,7 +353,7 @@ TEST_F(BlitTest, ColorResolve) {
|
||||
SamplerMagFilter::NEAREST);
|
||||
|
||||
EXPECT_IMAGE(dstRenderTarget,
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorResolve", 531759687));
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorResolve", 531759687, false, 8000, 5));
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, Blit2DTextureArray) {
|
||||
|
||||
@@ -391,7 +391,6 @@ TEST_F(LoadImageTest, UpdateImage2D) {
|
||||
}
|
||||
|
||||
TEST_F(LoadImageTest, UpdateImageSRGB) {
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::OPENGL), "see b/453756688");
|
||||
SKIP_IF(Backend::VULKAN, "b/454040142");
|
||||
|
||||
auto& api = getDriverApi();
|
||||
@@ -468,7 +467,7 @@ TEST_F(LoadImageTest, UpdateImageSRGB) {
|
||||
api.endRenderPass();
|
||||
|
||||
EXPECT_IMAGE(defaultRenderTarget,
|
||||
ScreenshotParams(kTexSize, kTexSize, "UpdateImageSRGB", 3300305265));
|
||||
ScreenshotParams(kTexSize, kTexSize, "UpdateImageSRGB", 3300305265, false, 8000, 5));
|
||||
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
@@ -177,9 +177,7 @@ TEST_F(BasicStencilBufferTest, DepthAndStencilBuffer) {
|
||||
|
||||
TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
|
||||
SKIP_IF(Backend::WEBGPU, "test cases fail in WebGPU, see b/424157731");
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL), "Stencil isn't applied");
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::CI, Backend::OPENGL), "see b/453757787");
|
||||
SKIP_IF(Backend::VULKAN, "b/453777217");
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN), "Stencil not preserved");
|
||||
|
||||
auto& api = getDriverApi();
|
||||
|
||||
|
||||
@@ -442,6 +442,24 @@ public:
|
||||
* invoking asynchronous methods.
|
||||
*/
|
||||
AsynchronousMode asynchronousMode = AsynchronousMode::NONE;
|
||||
|
||||
/**
|
||||
* Capacity of the LRU cache for material definitions.
|
||||
*
|
||||
* A value of 0 indicates that definitions will be destroyed immediately when they are no
|
||||
* longer referenced by any material instances or scenes. A value greater than 0 defines
|
||||
* the maximum number of unreferenced definitions to keep alive to avoid re-compilation.
|
||||
*/
|
||||
uint32_t materialCacheCapacity = 0;
|
||||
|
||||
/**
|
||||
* Capacity of the LRU cache for program specializations.
|
||||
*
|
||||
* Similar to materialCacheCapacity, but applies to the underlying shader programs generated
|
||||
* for materials. A value of 0 means immediate destruction of unreferenced programs. A
|
||||
* positive value caches up to that number of programs.
|
||||
*/
|
||||
uint32_t programCacheCapacity = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@ bool MaterialCache::MaterialKey::operator==(MaterialKey const& rhs) const noexce
|
||||
return parser == rhs.parser;
|
||||
}
|
||||
|
||||
MaterialCache::MaterialCache()
|
||||
: mDefinitions("MaterialCache::mDefinitions", 0),
|
||||
mPrograms("MaterialCache::mPrograms", 0) {}
|
||||
MaterialCache::MaterialCache(uint32_t materialCapacity, uint32_t programCapacity)
|
||||
: mDefinitions("MaterialCache::mDefinitions", materialCapacity),
|
||||
mPrograms("MaterialCache::mPrograms", programCapacity) {}
|
||||
|
||||
MaterialCache::~MaterialCache() {
|
||||
assert_invariant(mDefinitions.empty());
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
using ProgramCache =
|
||||
utils::RefCountedMap<ProgramSpecialization, backend::Handle<backend::HwProgram>>;
|
||||
|
||||
MaterialCache();
|
||||
MaterialCache(uint32_t materialCapacity, uint32_t programCapacity);
|
||||
~MaterialCache();
|
||||
|
||||
// All reference-counted resources should be freed by the time MaterialCache is destructed, but
|
||||
|
||||
@@ -271,6 +271,7 @@ FEngine::FEngine(Builder const& builder) :
|
||||
mRenderableManager(*this),
|
||||
mLightManager(*this),
|
||||
mCameraManager(*this),
|
||||
mMaterialCache(builder->mConfig.materialCacheCapacity, builder->mConfig.programCacheCapacity),
|
||||
mCommandBufferQueue(
|
||||
builder->mConfig.minCommandBufferSizeMB * MiB,
|
||||
builder->mConfig.commandBufferSizeMB * MiB,
|
||||
|
||||
@@ -244,6 +244,9 @@ bool MaterialChunk::getTextShader(Unflattener unflattener,
|
||||
buf[0] = '_';
|
||||
auto const [ptr, ec] = std::to_chars(buf + 1, buf + 16, numericLiteral);
|
||||
size_t const len = ptr - buf;
|
||||
if (UTILS_UNLIKELY(cursor + len >= shaderSize)) {
|
||||
return false;
|
||||
}
|
||||
memcpy(&shaderContent[cursor], buf, len);
|
||||
cursor += len;
|
||||
continue;
|
||||
@@ -263,7 +266,7 @@ bool MaterialChunk::getTextShader(Unflattener unflattener,
|
||||
const auto& content = dictionary[globalIndex];
|
||||
|
||||
// Ensure string is correctly formed and doesn't exceed reserved shader space.
|
||||
if (UTILS_UNLIKELY(content.size() == 0 || cursor + content.size() - 1 > shaderSize)) {
|
||||
if (UTILS_UNLIKELY(content.size() == 0 || cursor + content.size() - 1 >= shaderSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,16 +90,23 @@ TEST_F(FilaflatSecurityTest, DictionaryTextOOBRead) {
|
||||
// 2. Heap Buffer Overflow writing dictionary arrays to undersized output buffers
|
||||
TEST_F(FilaflatSecurityTest, MaterialChunkHeapOverflow) {
|
||||
std::vector<uint8_t> payload;
|
||||
write16(payload, 0); // mSharedStrings
|
||||
write16(payload, 0); // mVertexStrings
|
||||
write16(payload, 0); // mFragmentStrings
|
||||
write16(payload, 0); // mComputeStrings
|
||||
write64(payload, 1); // numShaders
|
||||
payload.push_back(1); // model
|
||||
payload.push_back(0); // variant
|
||||
payload.push_back(0); // stage
|
||||
write32(payload, 15); // offset (8 + 1 + 1 + 1 + 4 = 15)
|
||||
write32(payload, 23); // offset (4*2 + 8 + 1 + 1 + 1 + 4 = 23)
|
||||
|
||||
// Shader content layout
|
||||
write32(payload, 4); // shaderSize (vulnerable tiny size)
|
||||
write32(payload, 1); // lineCount = 1
|
||||
write16(payload, 0); // lineIndex = 0
|
||||
write32(payload, 0); // extLength
|
||||
write32(payload, 0); // baseLength
|
||||
write32(payload, 0); // numericLength
|
||||
payload.push_back(0); // lineIndex = 0
|
||||
|
||||
std::vector<uint8_t> fileData;
|
||||
write64(fileData, (uint64_t)filamat::ChunkType::MaterialGlsl);
|
||||
@@ -132,14 +139,21 @@ TEST_F(FilaflatSecurityTest, MaterialChunkHeapOverflow) {
|
||||
// 3. Out of Bounds Read via index mapping evasion (Text mode)
|
||||
TEST_F(FilaflatSecurityTest, MaterialChunkOOBReadText) {
|
||||
std::vector<uint8_t> payload;
|
||||
write16(payload, 0); // mSharedStrings
|
||||
write16(payload, 0); // mVertexStrings
|
||||
write16(payload, 0); // mFragmentStrings
|
||||
write16(payload, 0); // mComputeStrings
|
||||
write64(payload, 1); // numShaders
|
||||
payload.push_back(1); // model
|
||||
payload.push_back(0); // variant
|
||||
payload.push_back(0); // stage
|
||||
write32(payload, 15); // offset (8 + 1 + 1 + 1 + 4 = 15)
|
||||
write32(payload, 23); // offset
|
||||
write32(payload, 100); // shaderSize
|
||||
write32(payload, 1); // lineCount = 1
|
||||
write16(payload, 9999); // lineIndex = 9999 (VULNERABLE ACCESS)
|
||||
write32(payload, 0); // extLength
|
||||
write32(payload, 0); // baseLength
|
||||
write32(payload, 0); // numericLength
|
||||
payload.push_back(1); // lineIndex = 1 (OOB for empty dict)
|
||||
|
||||
std::vector<uint8_t> fileData;
|
||||
write64(fileData, (uint64_t)filamat::ChunkType::MaterialGlsl);
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace filamat {
|
||||
// when the container is about to be flattened.
|
||||
|
||||
size_t ChunkContainer::getSize() const {
|
||||
return flatten(Flattener::getDryRunner());
|
||||
auto flattener = Flattener::getDryRunner();
|
||||
return flatten(flattener);
|
||||
}
|
||||
|
||||
size_t ChunkContainer::flatten(Flattener& f) const {
|
||||
|
||||
@@ -48,14 +48,8 @@ public:
|
||||
// flattening. If we set mStart = nullptr and mEnd=nullptr, we would hit an error about
|
||||
// offsetting on null when ubsan is enabled. Instead we point mStart to a fake address, and
|
||||
// mCursor is offset from that.
|
||||
static Flattener& getDryRunner() {
|
||||
static Flattener dryRunner = Flattener(nullptr);
|
||||
dryRunner.mStart = (uint8_t*) FAKE_DRY_RUNNER_START_ADDR;
|
||||
dryRunner.mCursor = (uint8_t*) FAKE_DRY_RUNNER_START_ADDR;
|
||||
dryRunner.mOffsetPlaceholders.clear();
|
||||
dryRunner.mSizePlaceholders.clear();
|
||||
dryRunner.mValuePlaceholders.clear();
|
||||
return dryRunner;
|
||||
static Flattener getDryRunner() {
|
||||
return Flattener((uint8_t*) FAKE_DRY_RUNNER_START_ADDR);
|
||||
}
|
||||
|
||||
bool isDryRunner() {
|
||||
|
||||
@@ -250,7 +250,9 @@ void ShaderGenerator::generateVertexDomainDefines(io::sstream& out, VertexDomain
|
||||
}
|
||||
|
||||
void ShaderGenerator::generatePostProcessMaterialVariantDefines(io::sstream& out,
|
||||
PostProcessVariant const variant) noexcept {
|
||||
ShaderStage const, MaterialBuilder::FeatureLevel const featureLevel,
|
||||
MaterialInfo const&, PostProcessVariant const variant) noexcept {
|
||||
CodeGenerator::generateDefine(out, "MATERIAL_FEATURE_LEVEL", uint32_t(featureLevel));
|
||||
switch (variant) {
|
||||
case PostProcessVariant::OPAQUE:
|
||||
CodeGenerator::generateDefine(out, "POST_PROCESS_OPAQUE", 1u);
|
||||
@@ -737,7 +739,8 @@ std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel const sm
|
||||
}
|
||||
|
||||
CodeGenerator::generatePostProcessInputs(vs, ShaderStage::VERTEX);
|
||||
generatePostProcessMaterialVariantDefines(vs, PostProcessVariant(variantKey));
|
||||
generatePostProcessMaterialVariantDefines(vs, ShaderStage::VERTEX,
|
||||
featureLevel, material, PostProcessVariant(variantKey));
|
||||
|
||||
cg.generateUniforms(vs, ShaderStage::VERTEX,
|
||||
DescriptorSetBindingPoints::PER_VIEW,
|
||||
@@ -765,14 +768,16 @@ std::string ShaderGenerator::createPostProcessVertexProgram(ShaderModel const sm
|
||||
std::string ShaderGenerator::createPostProcessFragmentProgram(ShaderModel const sm,
|
||||
MaterialBuilder::TargetApi const targetApi, MaterialBuilder::TargetLanguage const targetLanguage,
|
||||
MaterialBuilder::FeatureLevel const featureLevel,
|
||||
MaterialInfo const& material, uint8_t variant, uint32_t apiLevel) const noexcept {
|
||||
MaterialInfo const& material, filament::Variant::type_t variantKey,
|
||||
uint32_t apiLevel) const noexcept {
|
||||
const CodeGenerator cg(sm, targetApi, targetLanguage, featureLevel);
|
||||
io::sstream fs;
|
||||
cg.generateCommonProlog(fs, ShaderStage::FRAGMENT, material, {}, apiLevel);
|
||||
|
||||
generateUserSpecConstants(cg, fs, mConstants);
|
||||
|
||||
generatePostProcessMaterialVariantDefines(fs, PostProcessVariant(variant));
|
||||
generatePostProcessMaterialVariantDefines(fs, ShaderStage::FRAGMENT,
|
||||
featureLevel, material, PostProcessVariant(variantKey));
|
||||
|
||||
// custom material variables
|
||||
size_t variableIndex = 0;
|
||||
|
||||
@@ -102,7 +102,9 @@ private:
|
||||
MaterialInfo const& material, filament::Variant variant) noexcept;
|
||||
|
||||
static void generatePostProcessMaterialVariantDefines(utils::io::sstream& out,
|
||||
filament::PostProcessVariant variant) noexcept;
|
||||
filament::backend::ShaderStage stage,
|
||||
MaterialBuilder::FeatureLevel featureLevel,
|
||||
MaterialInfo const& material, filament::PostProcessVariant variant) noexcept;
|
||||
|
||||
static void generateUserSpecConstants(
|
||||
const CodeGenerator& cg, utils::io::sstream& fs,
|
||||
@@ -117,7 +119,8 @@ private:
|
||||
std::string createPostProcessFragmentProgram(filament::backend::ShaderModel sm,
|
||||
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
|
||||
MaterialBuilder::FeatureLevel featureLevel,
|
||||
MaterialInfo const& material, uint8_t variant, uint32_t apiLevel) const noexcept;
|
||||
MaterialInfo const& material, filament::Variant::type_t variantKey,
|
||||
uint32_t apiLevel) const noexcept;
|
||||
|
||||
static void appendShader(utils::io::sstream& ss,
|
||||
const utils::CString& shader, size_t lineOffset) noexcept;
|
||||
|
||||
@@ -4,6 +4,14 @@ void main() {
|
||||
// Invoke user code
|
||||
postProcess(inputs);
|
||||
|
||||
#if MATERIAL_FEATURE_LEVEL == 0
|
||||
if (CONFIG_SRGB_SWAPCHAIN_EMULATION) {
|
||||
if (frameUniforms.rec709 != 0) {
|
||||
inputs.FRAG_OUTPUT0.rgb = pow(inputs.FRAG_OUTPUT0.rgb, vec3(0.45454));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FRAG_OUTPUT0)
|
||||
FRAG_OUTPUT_AT0 FRAG_OUTPUT_SWIZZLE0 = inputs.FRAG_OUTPUT0;
|
||||
#endif
|
||||
|
||||
@@ -114,9 +114,7 @@ void main() {
|
||||
#if MATERIAL_FEATURE_LEVEL == 0
|
||||
if (CONFIG_SRGB_SWAPCHAIN_EMULATION) {
|
||||
if (frameUniforms.rec709 != 0) {
|
||||
fragColor.r = pow(fragColor.r, 0.45454);
|
||||
fragColor.g = pow(fragColor.g, 0.45454);
|
||||
fragColor.b = pow(fragColor.b, 0.45454);
|
||||
fragColor.rgb = pow(fragColor.rgb, vec3(0.45454));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user