Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cecf38f51e | ||
|
|
79551eacb2 | ||
|
|
e181c74b6c | ||
|
|
418704dbb1 | ||
|
|
eeb4fe219b | ||
|
|
7d227630fc | ||
|
|
d84e42861c | ||
|
|
3a75dc6d2d | ||
|
|
66b67849af | ||
|
|
ba5900efcf | ||
|
|
2d518b5fd1 | ||
|
|
ee8d0e6ebf | ||
|
|
b4c9b9f489 | ||
|
|
e59972b41f | ||
|
|
5fb9fad3ce | ||
|
|
44bbab158b |
+1
-1
@@ -22,7 +22,6 @@ project(TNT)
|
||||
option(FILAMENT_USE_EXTERNAL_GLES3 "Experimental: Compile Filament against OpenGL ES 3" OFF)
|
||||
|
||||
option(FILAMENT_ENABLE_LTO "Enable link-time optimizations if supported by the compiler" OFF)
|
||||
|
||||
option(FILAMENT_SKIP_SAMPLES "Don't build samples" OFF)
|
||||
|
||||
option(FILAMENT_SUPPORTS_XCB "Include XCB support in Linux builds" ON)
|
||||
@@ -871,6 +870,7 @@ if (IS_HOST_PLATFORM)
|
||||
add_subdirectory(${LIBRARIES}/filamentapp)
|
||||
endif()
|
||||
add_subdirectory(${LIBRARIES}/imageio)
|
||||
add_subdirectory(${LIBRARIES}/filament-matp)
|
||||
|
||||
add_subdirectory(${FILAMENT}/samples)
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.63.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.62.2'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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.63.0'
|
||||
pod 'Filament', '~> 1.62.2'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
@@ -331,6 +331,7 @@ and tools.
|
||||
- `filamesh`: Mesh converter
|
||||
- `glslminifier`: Minifies GLSL source code
|
||||
- `matc`: Material compiler
|
||||
- `filament-matp`: Material parser
|
||||
- `matinfo` Displays information about materials compiled with `matc`
|
||||
- `mipgen` Generates a series of miplevels from a source image
|
||||
- `normal-blending`: Tool to blend normal maps
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.63.0
|
||||
VERSION_NAME=1.62.2
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ libs/math/test_math
|
||||
libs/image/test_image compare libs/image/tests/reference/
|
||||
libs/utils/test_utils
|
||||
libs/filamat/test_filamat
|
||||
tools/matc/test_matc
|
||||
libs/filament-matp/test_matp
|
||||
tools/cmgen/test_cmgen compare
|
||||
tools/glslminifier/test_glslminifier
|
||||
libs/filameshio/test_filameshio
|
||||
|
||||
+2
-2
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.62.1'
|
||||
implementation 'com.google.android.filament:filament-android:1.62.2'
|
||||
}
|
||||
</code></pre>
|
||||
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
|
||||
@@ -196,7 +196,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.62.1'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.62.2'
|
||||
</code></pre>
|
||||
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
|
||||
<ul>
|
||||
|
||||
+2
-2
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.62.1'
|
||||
implementation 'com.google.android.filament:filament-android:1.62.2'
|
||||
}
|
||||
</code></pre>
|
||||
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
|
||||
@@ -196,7 +196,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.62.1'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.62.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
@@ -136,6 +136,10 @@ void WebGPUDriver::setPresentationTime(int64_t monotonic_clock_ns) {
|
||||
void WebGPUDriver::endFrame(const uint32_t /* frameId */) {
|
||||
mPipelineLayoutCache.onFrameEnd();
|
||||
mPipelineCache.onFrameEnd();
|
||||
|
||||
for (size_t i = 0; i < MAX_DESCRIPTOR_SET_COUNT; i++) {
|
||||
mCurrentDescriptorSets[i] = {};
|
||||
}
|
||||
}
|
||||
|
||||
void WebGPUDriver::flush(int) {
|
||||
@@ -1480,8 +1484,8 @@ void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
|
||||
assert_invariant(bindGroupLayouts.size() >= pipelineState.pipelineLayout.setLayout.size());
|
||||
size_t bindGroupLayoutCount{ 0 };
|
||||
for (size_t i{ 0 }; i < bindGroupLayouts.size(); i++) {
|
||||
const auto handle{ pipelineState.pipelineLayout.setLayout[bindGroupLayoutCount] };
|
||||
if (handle.getId() == HandleBase::nullid) {
|
||||
const auto handle{ pipelineState.pipelineLayout.setLayout[i] };
|
||||
if (!handle) {
|
||||
continue;
|
||||
}
|
||||
bindGroupLayouts[bindGroupLayoutCount++] =
|
||||
@@ -1661,6 +1665,12 @@ void WebGPUDriver::updateDescriptorSetTexture(Handle<HwDescriptorSet> descriptor
|
||||
void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> descriptorSetHandle,
|
||||
const backend::descriptor_set_t setIndex, backend::DescriptorSetOffsetArray&& offsets) {
|
||||
assert_invariant(setIndex < MAX_DESCRIPTOR_SET_COUNT);
|
||||
|
||||
// An empty handle signifies we need to release this bind point
|
||||
if (!descriptorSetHandle) {
|
||||
mCurrentDescriptorSets[setIndex] = {};
|
||||
return;
|
||||
}
|
||||
const auto bindGroup = handleCast<WebGPUDescriptorSet>(descriptorSetHandle);
|
||||
const auto wbg = bindGroup->lockAndReturn(mDevice);
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include "details/Engine.h"
|
||||
|
||||
#include "ds/DescriptorSet.h"
|
||||
#include "ds/SsrPassDescriptorSet.h"
|
||||
#include "ds/TypedUniformBuffer.h"
|
||||
|
||||
@@ -251,6 +252,11 @@ void PostProcessManager::bindPostProcessDescriptorSet(DriverApi& driver) const n
|
||||
mPostProcessDescriptorSet.bind(driver);
|
||||
}
|
||||
|
||||
void PostProcessManager::bindPerRenderableDescriptorSet(DriverApi& driver) noexcept {
|
||||
driver.bindDescriptorSet(mDummyPerRenderableDsh, +DescriptorSetBindingPoints::PER_RENDERABLE,
|
||||
{ { 0, 0 }, driver });
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
void PostProcessManager::registerPostProcessMaterial(std::string_view const name,
|
||||
StaticMaterialInfo const& info) {
|
||||
@@ -314,6 +320,32 @@ void PostProcessManager::init() noexcept {
|
||||
mFullScreenQuadVbih = engine.getFullScreenVertexBuffer()->getVertexBufferInfoHandle();
|
||||
mPerRenderableDslh = engine.getPerRenderableDescriptorSetLayout().getHandle();
|
||||
|
||||
mDummyPerRenderableDsh = driver.createDescriptorSet(mPerRenderableDslh);
|
||||
|
||||
driver.updateDescriptorSetBuffer(mDummyPerRenderableDsh,
|
||||
+PerRenderableBindingPoints::OBJECT_UNIFORMS, engine.getDummyUniformBuffer(), 0,
|
||||
sizeof(PerRenderableUib));
|
||||
|
||||
driver.updateDescriptorSetBuffer(mDummyPerRenderableDsh,
|
||||
+PerRenderableBindingPoints::BONES_UNIFORMS, engine.getDummyUniformBuffer(), 0,
|
||||
sizeof(PerRenderableBoneUib));
|
||||
|
||||
driver.updateDescriptorSetBuffer(mDummyPerRenderableDsh,
|
||||
+PerRenderableBindingPoints::MORPHING_UNIFORMS, engine.getDummyUniformBuffer(), 0,
|
||||
sizeof(PerRenderableMorphingUib));
|
||||
|
||||
driver.updateDescriptorSetTexture(mDummyPerRenderableDsh,
|
||||
+PerRenderableBindingPoints::MORPH_TARGET_POSITIONS,
|
||||
engine.getDummyMorphTargetBuffer()->getPositionsHandle(), {});
|
||||
|
||||
driver.updateDescriptorSetTexture(mDummyPerRenderableDsh,
|
||||
+PerRenderableBindingPoints::MORPH_TARGET_TANGENTS,
|
||||
engine.getDummyMorphTargetBuffer()->getTangentsHandle(), {});
|
||||
|
||||
driver.updateDescriptorSetTexture(mDummyPerRenderableDsh,
|
||||
+PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS, engine.getZeroTextureArray(),
|
||||
{});
|
||||
|
||||
mSsrPassDescriptorSet.init(engine);
|
||||
mPostProcessDescriptorSet.init(engine);
|
||||
mStructureDescriptorSet.init(engine);
|
||||
@@ -384,6 +416,8 @@ void PostProcessManager::terminate(DriverApi& driver) noexcept {
|
||||
FEngine& engine = mEngine;
|
||||
driver.destroyTexture(mStarburstTexture);
|
||||
|
||||
driver.destroyDescriptorSet(mDummyPerRenderableDsh);
|
||||
|
||||
// Must destroy the instances before the materials
|
||||
mMaterialInstanceManager.terminate(engine);
|
||||
|
||||
@@ -420,6 +454,12 @@ void PostProcessManager::resetForRender() {
|
||||
mFixedMaterialInstanceIndex = {};
|
||||
}
|
||||
|
||||
void PostProcessManager::unbindAllDescriptorSets(DriverApi& driver) noexcept {
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_VIEW);
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_RENDERABLE);
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
PipelineState PostProcessManager::getPipelineState(
|
||||
FMaterial const* const ma, PostProcessVariant variant) const noexcept {
|
||||
@@ -483,6 +523,7 @@ void PostProcessManager::commitAndRenderFullScreenQuad(DriverApi& driver,
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
driver.draw(pipeline, mFullScreenQuadRph, 0, 3, 1);
|
||||
driver.endRenderPass();
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -545,6 +586,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
|
||||
// bind the per-view descriptorSet that is used for the structure pass
|
||||
getStructureDescriptorSet().bind(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
passBuilder.renderFlags(structureRenderFlags);
|
||||
passBuilder.variant(structureVariant);
|
||||
@@ -555,6 +597,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
pass.getExecutor().execute(mEngine, driver);
|
||||
driver.endRenderPass();
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
auto const depth = structurePass->depth;
|
||||
@@ -581,7 +624,8 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
}
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
getStructureDescriptorSet().bind(driver);
|
||||
getStructureDescriptorSet().bind(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto in = resources.getTexture(data.depth);
|
||||
auto& material = getPostProcessMaterial("mipmapDepth");
|
||||
@@ -601,8 +645,10 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
mi->commit(driver);
|
||||
mi->use(driver);
|
||||
renderFullScreenQuad(out, pipeline, driver);
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||
driver.destroyTexture(th);
|
||||
}
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return { depth, structurePass->picking };
|
||||
@@ -650,6 +696,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::transparentPicking(FrameGrap
|
||||
|
||||
// bind the per-view descriptorSet that is used for the structure pass
|
||||
getStructureDescriptorSet().bind(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto [target, params] = resources.getRenderPassInfo();
|
||||
passBuilder.renderFlags(structureRenderFlags);
|
||||
@@ -660,6 +707,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::transparentPicking(FrameGrap
|
||||
driver.beginRenderPass(target, params);
|
||||
pass.getExecutor().execute(mEngine, driver);
|
||||
driver.endRenderPass();
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return pickingRenderPass->picking;
|
||||
@@ -670,9 +718,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::transparentPicking(FrameGrap
|
||||
FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
|
||||
RenderPassBuilder const& passBuilder,
|
||||
FrameHistory const& frameHistory,
|
||||
CameraInfo const& cameraInfo,
|
||||
FrameGraphId<FrameGraphTexture> const structure,
|
||||
ScreenSpaceReflectionsOptions const& options,
|
||||
FrameGraphTexture::Descriptor const& desc) noexcept {
|
||||
|
||||
struct SSRPassData {
|
||||
@@ -693,8 +739,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
|
||||
|
||||
FrameGraphId<FrameGraphTexture> const history = fg.import("SSR history", previous.desc,
|
||||
FrameGraphTexture::Usage::SAMPLEABLE, previous.color);
|
||||
mat4 const& historyProjection = previous.projection;
|
||||
auto const& uvFromClipMatrix = mEngine.getUvFromClipMatrix();
|
||||
|
||||
auto const& ssrPass = fg.addPass<SSRPassData>("SSR Pass",
|
||||
[&](FrameGraph::Builder& builder, auto& data) {
|
||||
@@ -728,28 +772,23 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
|
||||
data.history = builder.sample(history);
|
||||
}
|
||||
},
|
||||
[this, projection = cameraInfo.projection,
|
||||
userViewMatrix = cameraInfo.getUserViewMatrix(), uvFromClipMatrix, historyProjection,
|
||||
options, passBuilder = passBuilder]
|
||||
(FrameGraphResources const& resources, auto const& data, DriverApi& driver) mutable {
|
||||
[this, passBuilder = passBuilder](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) mutable {
|
||||
// set structure sampler
|
||||
mSsrPassDescriptorSet.prepareStructure(mEngine, data.structure ?
|
||||
resources.getTexture(data.structure) : getOneTexture());
|
||||
|
||||
// set screen-space reflections and screen-space refractions
|
||||
mat4f const uvFromViewMatrix = uvFromClipMatrix * projection;
|
||||
mat4f const reprojection = uvFromClipMatrix *
|
||||
mat4f{ historyProjection * inverse(userViewMatrix) };
|
||||
|
||||
// the history sampler is a regular texture2D
|
||||
TextureHandle const history = data.history ?
|
||||
resources.getTexture(data.history) : getZeroTexture();
|
||||
mSsrPassDescriptorSet.prepareHistorySSR(mEngine, history, reprojection, uvFromViewMatrix, options);
|
||||
mSsrPassDescriptorSet.prepareHistorySSR(mEngine, history);
|
||||
|
||||
mSsrPassDescriptorSet.commit(mEngine);
|
||||
|
||||
mSsrPassDescriptorSet.bind(driver);
|
||||
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const out = resources.getRenderPassInfo();
|
||||
|
||||
// Remove the HAS_SHADOWING RenderFlags, since it's irrelevant when rendering reflections
|
||||
@@ -766,6 +805,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
pass.getExecutor().execute(mEngine, driver);
|
||||
driver.endRenderPass();
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return ssrPass->reflections;
|
||||
@@ -916,6 +956,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
// bind the per-view descriptorSet that is used for the structure pass
|
||||
getStructureDescriptorSet().bind(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto depth = resources.getTexture(data.depth);
|
||||
auto ssao = resources.getRenderPassInfo();
|
||||
@@ -1031,6 +1072,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
pipeline.rasterState.depthFunc = RasterState::DepthFunc::L;
|
||||
assert_invariant(ssao.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH);
|
||||
renderFullScreenQuad(ssao, pipeline, driver);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
FrameGraphId<FrameGraphTexture> ssao = SSAOPass->ssao;
|
||||
@@ -1109,6 +1151,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::bilateralBlurPass(FrameGraph
|
||||
auto const& data, DriverApi& driver) {
|
||||
// TODO: the structure descriptor set might not be the best fit.
|
||||
getStructureDescriptorSet().bind(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto ssao = resources.getTexture(data.input);
|
||||
auto blurred = resources.getRenderPassInfo();
|
||||
@@ -1149,6 +1192,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::bilateralBlurPass(FrameGraph
|
||||
auto pipeline = getPipelineState(ma);
|
||||
pipeline.rasterState.depthFunc = RasterState::DepthFunc::L;
|
||||
renderFullScreenQuad(blurred, pipeline, driver);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return blurPass->blurred;
|
||||
@@ -1274,6 +1318,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
|
||||
[=](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
// don't use auto for those, b/c the ide can't resolve them
|
||||
using FGTD = FrameGraphTexture::Descriptor;
|
||||
@@ -1365,6 +1410,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
|
||||
|
||||
commitAndRenderFullScreenQuad(driver, hwOutRT, mi);
|
||||
}
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return blurPass->out;
|
||||
@@ -1749,6 +1795,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
auto color = resources.getTexture(data.color);
|
||||
auto depth = resources.getTexture(data.depth);
|
||||
@@ -1767,6 +1815,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
1.0f / float(colorDesc.width),
|
||||
1.0f / float(colorDesc.height) });
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
/*
|
||||
@@ -1807,6 +1856,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
[=](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto desc = resources.getDescriptor(data.inOutColor);
|
||||
auto inOutColor = resources.getTexture(data.inOutColor);
|
||||
@@ -1833,10 +1883,12 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
mi->use(driver);
|
||||
|
||||
renderFullScreenQuad(out, pipeline, driver);
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||
|
||||
driver.destroyTexture(inColor);
|
||||
driver.destroyTexture(inCoc);
|
||||
}
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
/*
|
||||
@@ -1882,6 +1934,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
[=](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
auto const& inputDesc = resources.getDescriptor(data.inCocMinMax);
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
auto inCocMinMax = resources.getTexture(data.inCocMinMax);
|
||||
@@ -1892,6 +1945,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
mi->setParameter("cocMinMax", inCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
|
||||
mi->setParameter("texelSize", float2{ 1.0f / inputDesc.width, 1.0f / inputDesc.height });
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
inTilesCocMinMax = ppDoFTiling->outTilesCocMinMax;
|
||||
}
|
||||
@@ -1918,12 +1972,15 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
[=](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
auto inTilesCocMinMax = resources.getTexture(data.inTilesCocMinMax);
|
||||
auto const& material = getPostProcessMaterial("dofDilate");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("tiles", inTilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
return ppDoFDilate->outTilesCocMinMax;
|
||||
};
|
||||
@@ -1971,6 +2028,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
|
||||
auto color = resources.getTexture(data.color);
|
||||
@@ -2003,6 +2062,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
});
|
||||
mi->setParameter("bokehAngle", bokehAngle);
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
/*
|
||||
@@ -2034,6 +2094,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
|
||||
auto inColor = resources.getTexture(data.inColor);
|
||||
@@ -2046,6 +2108,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
mi->setParameter("alpha", inAlpha, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||
mi->setParameter("tiles", tilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
|
||||
@@ -2081,6 +2144,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
[=](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
|
||||
auto color = resources.getTexture(data.color);
|
||||
@@ -2095,6 +2160,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
|
||||
mi->setParameter("alpha", alpha, { .filterMag = SamplerMagFilter::NEAREST });
|
||||
mi->setParameter("tiles", tilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return ppDoFCombine->output;
|
||||
@@ -2117,6 +2183,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::downscalePass(FrameGraph& fg
|
||||
[=](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
auto const& material = getPostProcessMaterial("bloomDownsample2x");
|
||||
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
|
||||
@@ -2129,7 +2197,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::downscalePass(FrameGraph& fg
|
||||
mi->setParameter("fireflies", fireflies ? 1.0f : 0.0f);
|
||||
mi->setParameter("invHighlight", std::isinf(highlight) ? 0.0f : 1.0f / highlight);
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
return downsamplePass->output;
|
||||
}
|
||||
@@ -2250,6 +2318,7 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
|
||||
[=](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
// TODO: if downsampling is not exactly a multiple of two, use the 13 samples
|
||||
// filter. This is generally the accepted solution, however, the 13 samples
|
||||
@@ -2285,6 +2354,7 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
|
||||
commitAndRenderFullScreenQuad(driver, hwDstRT, mi);
|
||||
driver.destroyTexture(hwOutView);
|
||||
}
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
// output of bloom downsample pass becomes input of next (flare) pass
|
||||
@@ -2304,6 +2374,7 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
auto hwOut = resources.getTexture(data.out);
|
||||
auto const& outDesc = resources.getDescriptor(data.out);
|
||||
|
||||
@@ -2332,8 +2403,10 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
|
||||
mi->commit(driver);
|
||||
mi->use(driver);
|
||||
renderFullScreenQuad(hwDstRT, pipeline, driver);
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||
driver.destroyTexture(hwOutView);
|
||||
}
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return { bloomUpsamplePass->out, flare };
|
||||
@@ -2363,6 +2436,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::flarePass(FrameGraph& fg,
|
||||
[=](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
auto in = resources.getTexture(data.in);
|
||||
auto const out = resources.getRenderPassInfo(0);
|
||||
const float aspectRatio = float(width) / float(height);
|
||||
@@ -2387,6 +2461,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::flarePass(FrameGraph& fg,
|
||||
mi->setParameter("haloThickness", bloomOptions.haloThickness);
|
||||
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
constexpr float kernelWidth = 9;
|
||||
@@ -2440,6 +2515,7 @@ void PostProcessManager::colorGradingSubpass(DriverApi& driver,
|
||||
ColorGradingConfig const& colorGradingConfig) noexcept {
|
||||
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
PostProcessVariant const variant = colorGradingConfig.translucent ?
|
||||
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
|
||||
@@ -2471,6 +2547,7 @@ void PostProcessManager::customResolvePrepareSubpass(DriverApi& driver, CustomRe
|
||||
|
||||
void PostProcessManager::customResolveSubpass(DriverApi& driver) noexcept {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
FEngine const& engine = mEngine;
|
||||
Handle<HwRenderPrimitive> const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive();
|
||||
@@ -2505,6 +2582,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::customResolveUncompressPass(
|
||||
auto out = resources.getRenderPassInfo();
|
||||
out.params.subpassMask = 1;
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
customResolveSubpass(driver);
|
||||
driver.endRenderPass();
|
||||
@@ -2579,6 +2657,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
auto colorTexture = resources.getTexture(data.input);
|
||||
|
||||
auto bloomTexture =
|
||||
@@ -2645,6 +2724,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
|
||||
commitAndRenderFullScreenQuad(driver, out, mi,
|
||||
colorGradingConfig.translucent
|
||||
? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE);
|
||||
|
||||
unbindAllDescriptorSets(driver);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2672,6 +2753,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::fxaa(FrameGraph& fg,
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
auto const& inDesc = resources.getDescriptor(data.input);
|
||||
auto const& texture = resources.getTexture(data.input);
|
||||
auto const& out = resources.getRenderPassInfo();
|
||||
@@ -2697,6 +2779,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::fxaa(FrameGraph& fg,
|
||||
mi->setParameter("texelSize", 1.0f / float2{ inDesc.width, inDesc.height });
|
||||
|
||||
commitAndRenderFullScreenQuad(driver, out, mi, variant);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return ppFXAA->output;
|
||||
@@ -2889,6 +2972,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
|
||||
},
|
||||
[=, ¤t](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
constexpr mat4f normalizedToClip{mat4f::row_major_init{
|
||||
2, 0, 0, -1,
|
||||
@@ -2981,6 +3065,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
|
||||
colorGradingSubpass(driver, colorGradingConfig);
|
||||
}
|
||||
driver.endRenderPass();
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
input = colorGradingConfig.asSubpass ? taaPass->tonemappedOutput : taaPass->output;
|
||||
@@ -3030,6 +3115,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
|
||||
[=](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto const input = resources.getTexture(data.input);
|
||||
auto const out = resources.getRenderPassInfo();
|
||||
@@ -3050,6 +3136,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
|
||||
outputDesc.width, outputDesc.height,
|
||||
1.0f / outputDesc.width, 1.0f / outputDesc.height });
|
||||
commitAndRenderFullScreenQuad(driver, out, mi, variant);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return ppFsrRcas->output;
|
||||
@@ -3100,6 +3187,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph&
|
||||
[this, vp, filter](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto color = resources.getTexture(data.input);
|
||||
auto const& inputDesc = resources.getDescriptor(data.input);
|
||||
@@ -3129,6 +3217,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph&
|
||||
|
||||
auto pipeline = getPipelineState(material.getMaterial(mEngine));
|
||||
renderFullScreenQuad(out, pipeline, driver);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
auto output = ppQuadBlit->output;
|
||||
@@ -3164,6 +3253,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleSGSR1(FrameGraph& fg,
|
||||
[this, vp, sourceHasLuminance](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto color = resources.getTexture(data.input);
|
||||
auto const& inputDesc = resources.getDescriptor(data.input);
|
||||
@@ -3203,9 +3293,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleSGSR1(FrameGraph& fg,
|
||||
mi->commit(driver);
|
||||
mi->use(driver);
|
||||
|
||||
auto out = resources.getRenderPassInfo();
|
||||
auto const out = resources.getRenderPassInfo();
|
||||
commitAndRenderFullScreenQuad(driver, out, mi, variant);
|
||||
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
auto output = ppQuadBlit->output;
|
||||
@@ -3251,6 +3341,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
|
||||
[this, twoPassesEASU, dsrOptions, vp](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
// helper to set the EASU uniforms
|
||||
auto setEasuUniforms = [vp, backend = mEngine.getBackend()](FMaterialInstance* mi,
|
||||
@@ -3342,6 +3433,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
|
||||
auto pipeline = getPipelineState(easuMaterial->getMaterial(mEngine));
|
||||
renderFullScreenQuad(out, pipeline, driver);
|
||||
}
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
auto output = ppQuadBlit->output;
|
||||
@@ -3380,6 +3472,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blit(FrameGraph& fg, bool co
|
||||
[=](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
auto color = resources.getTexture(data.input);
|
||||
auto const& inputDesc = resources.getDescriptor(data.input);
|
||||
auto out = resources.getRenderPassInfo();
|
||||
@@ -3416,6 +3509,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blit(FrameGraph& fg, bool co
|
||||
pipeline.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
renderFullScreenQuad(out, pipeline, driver);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return ppQuadBlit->output;
|
||||
@@ -3480,6 +3574,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blitDepth(FrameGraph& fg,
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
getStructureDescriptorSet().bind(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
auto depth = resources.getTexture(data.input);
|
||||
auto const& inputDesc = resources.getDescriptor(data.input);
|
||||
auto const out = resources.getRenderPassInfo();
|
||||
@@ -3499,6 +3594,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blitDepth(FrameGraph& fg,
|
||||
float(vp.bottom) / inputDesc.height, float(vp.width) / inputDesc.width,
|
||||
float(vp.height) / inputDesc.height});
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return ppQuadBlit->output;
|
||||
@@ -3597,12 +3693,14 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::resolveDepth(FrameGraph& fg,
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
auto const& input = resources.getTexture(data.input);
|
||||
auto const& material = getPostProcessMaterial("resolveDepth");
|
||||
FMaterialInstance* const mi =
|
||||
getMaterialInstance(mEngine, material);
|
||||
mi->setParameter("depth", input, {}); // NEAREST
|
||||
commitAndRenderFullScreenQuad(driver, resources.getRenderPassInfo(), mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return ppResolve->output;
|
||||
@@ -3634,6 +3732,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
|
||||
[=](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
|
||||
auto in = driver.createTextureView(resources.getTexture(data.in), level, 1);
|
||||
auto out = resources.getRenderPassInfo();
|
||||
@@ -3662,6 +3761,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
|
||||
mi->use(driver);
|
||||
|
||||
renderFullScreenQuadWithScissor(out, pipeline, scissor, driver);
|
||||
unbindAllDescriptorSets(driver);
|
||||
|
||||
driver.destroyTexture(in); // `in` is just a view on `data.in`
|
||||
});
|
||||
@@ -3689,6 +3789,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugShadowCascades(FrameGra
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
auto color = resources.getTexture(data.color);
|
||||
auto depth = resources.getTexture(data.depth);
|
||||
auto const out = resources.getRenderPassInfo();
|
||||
@@ -3698,6 +3799,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugShadowCascades(FrameGra
|
||||
mi->setParameter("color", color, {}); // nearest
|
||||
mi->setParameter("depth", depth, {}); // nearest
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return debugShadowCascadePass->output;
|
||||
@@ -3734,6 +3836,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
auto color = resources.getTexture(data.input);
|
||||
auto const& inputDesc = resources.getDescriptor(data.input);
|
||||
auto out = resources.getRenderPassInfo();
|
||||
@@ -3775,11 +3878,13 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
|
||||
mi->setParameter("layerIndex", i);
|
||||
mi->commit(driver);
|
||||
renderFullScreenQuad(out, pipeline, driver);
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||
// From the second draw, don't clear the targetbuffer.
|
||||
out.params.flags.clear = TargetBufferFlags::NONE;
|
||||
out.params.flags.discardStart = TargetBufferFlags::NONE;
|
||||
out.params.viewport.left += out.params.viewport.width;
|
||||
}
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
|
||||
return ppQuadBlit->output;
|
||||
@@ -3814,6 +3919,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugDisplayShadowTexture(
|
||||
},
|
||||
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
bindPostProcessDescriptorSet(driver);
|
||||
bindPerRenderableDescriptorSet(driver);
|
||||
auto const out = resources.getRenderPassInfo();
|
||||
auto in = resources.getTexture(data.depth);
|
||||
auto const& material = getPostProcessMaterial("shadowmap");
|
||||
@@ -3826,6 +3932,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugDisplayShadowTexture(
|
||||
mi->setParameter("channel", (uint32_t)channel);
|
||||
mi->setParameter("power", power);
|
||||
commitAndRenderFullScreenQuad(driver, out, mi);
|
||||
unbindAllDescriptorSets(driver);
|
||||
});
|
||||
input = shadomapDebugPass->color;
|
||||
}
|
||||
|
||||
@@ -114,9 +114,7 @@ public:
|
||||
FrameGraphId<FrameGraphTexture> ssr(FrameGraph& fg,
|
||||
RenderPassBuilder const& passBuilder,
|
||||
FrameHistory const& frameHistory,
|
||||
CameraInfo const& cameraInfo,
|
||||
FrameGraphId<FrameGraphTexture> structure,
|
||||
ScreenSpaceReflectionsOptions const& options,
|
||||
FrameGraphTexture::Descriptor const& desc) noexcept;
|
||||
|
||||
// SSAO
|
||||
@@ -395,6 +393,9 @@ public:
|
||||
void resetForRender();
|
||||
|
||||
private:
|
||||
static void unbindAllDescriptorSets(backend::DriverApi& driver) noexcept;
|
||||
|
||||
void bindPerRenderableDescriptorSet(backend::DriverApi& driver) noexcept;
|
||||
|
||||
// Helper to get a MaterialInstance from a FMaterial
|
||||
// This currently just call FMaterial::getDefaultInstance().
|
||||
@@ -413,6 +414,11 @@ private:
|
||||
backend::VertexBufferInfoHandle mFullScreenQuadVbih;
|
||||
backend::DescriptorSetLayoutHandle mPerRenderableDslh;
|
||||
|
||||
// We need to have a dummy descriptor set because each post processing pass is expected to have
|
||||
// a descriptor set bound at the renderable bind point. But the set itself contains dummy
|
||||
// values.
|
||||
backend::DescriptorSetHandle mDummyPerRenderableDsh;
|
||||
|
||||
FEngine& mEngine;
|
||||
|
||||
mutable SsrPassDescriptorSet mSsrPassDescriptorSet;
|
||||
|
||||
@@ -21,11 +21,15 @@
|
||||
#include "details/Engine.h"
|
||||
#include "details/View.h"
|
||||
|
||||
#include "ds/DescriptorSet.h"
|
||||
|
||||
#include "fg/FrameGraph.h"
|
||||
#include "fg/FrameGraphId.h"
|
||||
#include "fg/FrameGraphResources.h"
|
||||
#include "fg/FrameGraphTexture.h"
|
||||
|
||||
#include <private/filament/EngineEnums.h>
|
||||
|
||||
#include <filament/Options.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/Viewport.h>
|
||||
@@ -113,7 +117,7 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
|
||||
clearDepthFlags = TargetBufferFlags::DEPTH;
|
||||
clearStencilFlags = config.enabledStencilBuffer ?
|
||||
TargetBufferFlags::STENCIL : TargetBufferFlags::NONE;
|
||||
const char* const name = config.enabledStencilBuffer ?
|
||||
const char* const textureName = config.enabledStencilBuffer ?
|
||||
"Depth/Stencil Buffer" : "Depth Buffer";
|
||||
|
||||
bool const isES2 =
|
||||
@@ -128,7 +132,7 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
|
||||
TextureFormat const format = config.enabledStencilBuffer ?
|
||||
stencilFormat : depthOnlyFormat;
|
||||
|
||||
data.depth = builder.createTexture(name, {
|
||||
data.depth = builder.createTexture(textureName, {
|
||||
.width = colorBufferDesc.width,
|
||||
.height = colorBufferDesc.height,
|
||||
// If the color attachment requested MS, we assume this means the MS
|
||||
@@ -204,37 +208,23 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
|
||||
view.prepareSSAO(data.ssao ?
|
||||
resources.getTexture(data.ssao) : engine.getOneTextureArray());
|
||||
|
||||
view.prepareShadowMapping(engine, view.getVsmShadowOptions().highPrecision);
|
||||
|
||||
// set shadow sampler
|
||||
view.prepareShadow(data.shadows ?
|
||||
resources.getTexture(data.shadows) :
|
||||
(view.getShadowType() != ShadowType::PCF ?
|
||||
engine.getOneTextureArray() : engine.getOneTextureArrayDepth()));
|
||||
// set screen-space reflections and screen-space refractions
|
||||
view.prepareSSR(data.ssr ?
|
||||
resources.getTexture(data.ssr) : engine.getOneTextureArray());
|
||||
|
||||
// set structure sampler
|
||||
view.prepareStructure(data.structure ?
|
||||
resources.getTexture(data.structure) : engine.getOneTexture());
|
||||
|
||||
// set screen-space reflections and screen-space refractions
|
||||
TextureHandle const ssr = data.ssr ?
|
||||
resources.getTexture(data.ssr) : engine.getOneTextureArray();
|
||||
// set shadow sampler
|
||||
view.prepareShadowMapping(engine,
|
||||
data.shadows
|
||||
? resources.getTexture(data.shadows)
|
||||
: (view.getShadowType() != ShadowType::PCF
|
||||
? engine.getOneTextureArray()
|
||||
: engine.getOneTextureArrayDepth()));
|
||||
|
||||
view.prepareSSR(ssr, config.screenSpaceReflectionHistoryNotReady,
|
||||
config.ssrLodOffset, view.getScreenSpaceReflectionsOptions());
|
||||
|
||||
// Note: here we can't use data.color's descriptor for the viewport because
|
||||
// the actual viewport might be offset when the target is the swapchain.
|
||||
// However, the width/height should be the same.
|
||||
assert_invariant(
|
||||
out.params.viewport.width == resources.getDescriptor(data.color).width);
|
||||
assert_invariant(
|
||||
out.params.viewport.height == resources.getDescriptor(data.color).height);
|
||||
|
||||
view.prepareViewport(static_cast<filament::Viewport&>(out.params.viewport),
|
||||
config.logicalViewport);
|
||||
|
||||
view.commitUniformsAndSamplers(driver);
|
||||
view.commitDescriptorSet(driver);
|
||||
|
||||
// TODO: this should be a parameter of FrameGraphRenderPass::Descriptor
|
||||
out.params.clearStencil = config.clearStencil;
|
||||
@@ -254,6 +244,11 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
passExecutor.execute(engine, driver);
|
||||
driver.endRenderPass();
|
||||
|
||||
// unbind all descriptor sets to avoid false dependencies with the next pass
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_VIEW);
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_RENDERABLE);
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -65,16 +65,12 @@ public:
|
||||
math::float4 clearColor = {};
|
||||
// Clear stencil
|
||||
uint8_t clearStencil = 0u;
|
||||
// Lod offset for the SSR passes
|
||||
float ssrLodOffset;
|
||||
// Contact shadow enabled?
|
||||
bool hasContactShadows;
|
||||
// Screen space reflections enabled
|
||||
bool hasScreenSpaceReflectionsOrRefractions;
|
||||
// Use a depth format with a stencil component.
|
||||
bool enabledStencilBuffer;
|
||||
// whether the screenspace reflections history buffer is initialized
|
||||
bool screenSpaceReflectionHistoryNotReady;
|
||||
};
|
||||
|
||||
struct ColorPassInput {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <filament/LightManager.h>
|
||||
#include <filament/Options.h>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <private/filament/EngineEnums.h>
|
||||
|
||||
#include "components/RenderableManager.h"
|
||||
@@ -33,6 +33,8 @@
|
||||
#include "details/Texture.h"
|
||||
#include "details/View.h"
|
||||
|
||||
#include "ds/DescriptorSet.h"
|
||||
|
||||
#include "fg/FrameGraph.h"
|
||||
#include "fg/FrameGraphId.h"
|
||||
#include "fg/FrameGraphRenderPass.h"
|
||||
@@ -57,6 +59,7 @@
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <new>
|
||||
#include <memory>
|
||||
@@ -433,6 +436,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
|
||||
// Finally update our UBO in one batch
|
||||
if (mShadowUb.isDirty()) {
|
||||
mShadowUb.clean();
|
||||
driver.updateBufferObject(mShadowUbh,
|
||||
mShadowUb.toBufferDescriptor(driver), 0);
|
||||
}
|
||||
@@ -560,14 +564,19 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
// if we know there are no visible shadows, we can skip rendering, but
|
||||
// we need the render-pass to clear/initialize the shadow-map
|
||||
// Note: this is always true for directional/cascade shadows.
|
||||
if (curr->shadowMap->hasVisibleShadows()) {
|
||||
curr->shadowMap->bind(driver);
|
||||
curr->executor.overrideScissor(curr->shadowMap->getScissor());
|
||||
if (ShadowMap const* const shadowMap = curr->shadowMap; shadowMap->hasVisibleShadows()) {
|
||||
shadowMap->bind(driver);
|
||||
curr->executor.overrideScissor(shadowMap->getScissor());
|
||||
curr->executor.execute(engine, driver);
|
||||
}
|
||||
}
|
||||
|
||||
driver.endRenderPass();
|
||||
|
||||
// unbind all descriptor sets to avoid false dependencies with the next pass
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_VIEW);
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_RENDERABLE);
|
||||
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
|
||||
});
|
||||
|
||||
first = last;
|
||||
|
||||
@@ -1235,13 +1235,20 @@ bool FEngine::destroy(const FMaterialInstance* p) {
|
||||
size_t const primitiveCount = rcm.getPrimitiveCount(ri, 0);
|
||||
for (size_t j = 0; j < primitiveCount; j++) {
|
||||
auto const* const mi = rcm.getMaterialInstanceAt(ri, 0, j);
|
||||
auto const& featureFlags = features.engine.debug;
|
||||
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(
|
||||
mi != p,
|
||||
featureFlags.assert_material_instance_in_use)
|
||||
<< "destroying MaterialInstance \"" << mi->getName()
|
||||
<< "\" which is still in use by Renderable (entity=" << entity.getId()
|
||||
<< ", instance=" << ri.asValue() << ", index=" << j << ")";
|
||||
if (features.engine.debug.assert_material_instance_in_use) {
|
||||
FILAMENT_CHECK_PRECONDITION(mi != p)
|
||||
<< "destroying MaterialInstance \""
|
||||
<< mi->getName() << "\" which is still in use by Renderable (entity="
|
||||
<< entity.getId() << ", instance="
|
||||
<< ri.asValue() << ", index=" << j << ")";
|
||||
} else {
|
||||
if (UTILS_UNLIKELY(mi == p)) {
|
||||
LOG(ERROR) << "destroying MaterialInstance \"" << mi->getName()
|
||||
<< "\" which is still in use by Renderable (entity="
|
||||
<< entity.getId() << ", instance=" << ri.asValue()
|
||||
<< ", index=" << j << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,8 +731,6 @@ public:
|
||||
bool assert_vertex_buffer_count_exceeds_8 = CORRECTNESS_ASSERTION_DEFAULT;
|
||||
bool assert_vertex_buffer_attribute_stride_mult_of_4 =
|
||||
CORRECTNESS_ASSERTION_DEFAULT;
|
||||
bool assert_material_instance_texture_descriptor_set_compatible =
|
||||
CORRECTNESS_ASSERTION_DEFAULT;
|
||||
} debug;
|
||||
} engine;
|
||||
struct {
|
||||
@@ -785,9 +783,6 @@ public:
|
||||
{ "backend.vulkan.enable_staging_buffer_bypass",
|
||||
"vulkan: enable a staging bypass logic for unified memory architecture",
|
||||
&features.backend.vulkan.enable_staging_buffer_bypass, false },
|
||||
{ "engine.debug.assert_material_instance_texture_descriptor_set_compatible",
|
||||
"Assert that the textures in a material instance are compatible with descriptor set.",
|
||||
&features.engine.debug.assert_material_instance_texture_descriptor_set_compatible, false },
|
||||
}};
|
||||
|
||||
utils::Slice<const FeatureFlag> getFeatureFlags() const noexcept {
|
||||
|
||||
@@ -391,11 +391,16 @@ void FMaterial::terminate(FEngine& engine) {
|
||||
auto const& materialInstanceResourceList = engine.getMaterialInstanceResourceList();
|
||||
auto pos = materialInstanceResourceList.find(this);
|
||||
if (UTILS_LIKELY(pos != materialInstanceResourceList.cend())) {
|
||||
auto const& featureFlags = engine.features.engine.debug;
|
||||
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(pos->second.empty(),
|
||||
featureFlags.assert_destroy_material_before_material_instance)
|
||||
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive.";
|
||||
if (engine.features.engine.debug.assert_destroy_material_before_material_instance) {
|
||||
FILAMENT_CHECK_PRECONDITION(pos->second.empty())
|
||||
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive.";
|
||||
} else {
|
||||
if (UTILS_UNLIKELY(!pos->second.empty())) {
|
||||
LOG(ERROR) << "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
|
||||
@@ -222,6 +222,7 @@ void FMaterialInstance::commit(FEngine& engine) const {
|
||||
void FMaterialInstance::commit(DriverApi& driver) const {
|
||||
// update uniforms if needed
|
||||
if (mUniforms.isDirty() || mHasStreamUniformAssociations) {
|
||||
mUniforms.clean();
|
||||
driver.updateBufferObject(mUbHandle, mUniforms.toBufferDescriptor(driver), 0);
|
||||
}
|
||||
if (!mTextureParameters.empty()) {
|
||||
@@ -285,11 +286,9 @@ void FMaterialInstance::setParameterImpl(std::string_view const name,
|
||||
DescriptorType const descriptorType = descriptorSetLayout.getDescriptorType(binding);
|
||||
TextureType const textureType = texture->getTextureType();
|
||||
SamplerType const samplerType = texture->getTarget();
|
||||
auto const& featureFlags = mMaterial->getEngine().features.engine.debug;
|
||||
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(
|
||||
DescriptorSet::isTextureCompatibleWithDescriptor(
|
||||
textureType, samplerType, descriptorType),
|
||||
featureFlags.assert_material_instance_texture_descriptor_set_compatible)
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(
|
||||
DescriptorSet::isTextureCompatibleWithDescriptor(textureType, samplerType, descriptorType))
|
||||
<< "Texture format " << int(texture->getFormat())
|
||||
<< " of type " << to_string(textureType)
|
||||
<< " with sampler type " << to_string(samplerType)
|
||||
|
||||
@@ -574,12 +574,20 @@ void FRenderer::renderStandaloneView(FView const* view) {
|
||||
1'000'000'000.0 / mDisplayInfo.refreshRate),
|
||||
mFrameId);
|
||||
|
||||
renderInternal(view);
|
||||
// because we don't have a "present" call, we use flush so the driver can submit
|
||||
// the command buffer; we do this before driver.endFrame() to mimic what would
|
||||
// happen with Renderer::beginFrame/endFrame.
|
||||
renderInternal(view, true);
|
||||
|
||||
driver.endFrame(mFrameId);
|
||||
|
||||
// This is a workaround for internal bug b/361822355.
|
||||
// TODO: properly address the bug and remove this workaround.
|
||||
// engine.flush() has already been called by renderInternal(), but we need an extra one
|
||||
// for endFrame() above. This operation in actually not too heavy, it just kicks the
|
||||
// driver thread, which is mostlikely already running.
|
||||
engine.flush();
|
||||
|
||||
// FIXME: This is a workaround for internal bug b/361822355.
|
||||
// properly address the bug and remove this workaround.
|
||||
if (engine.getBackend() == Backend::VULKAN) {
|
||||
engine.flushAndWait();
|
||||
}
|
||||
@@ -600,11 +608,11 @@ void FRenderer::render(FView const* view) {
|
||||
assert_invariant(mSwapChain);
|
||||
|
||||
if (UTILS_LIKELY(view && view->getScene() && view->hasCamera())) {
|
||||
renderInternal(view);
|
||||
renderInternal(view, false);
|
||||
}
|
||||
}
|
||||
|
||||
void FRenderer::renderInternal(FView const* view) {
|
||||
void FRenderer::renderInternal(FView const* view, bool flush) {
|
||||
FEngine& engine = mEngine;
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(!view->hasPostProcessPass() ||
|
||||
@@ -621,6 +629,10 @@ void FRenderer::renderInternal(FView const* view) {
|
||||
// execute the render pass
|
||||
renderJob(rootArenaScope, const_cast<FView&>(*view));
|
||||
|
||||
if (flush) {
|
||||
engine.getDriverApi().flush();
|
||||
}
|
||||
|
||||
// make sure to flush the command buffer
|
||||
engine.flush();
|
||||
|
||||
@@ -818,29 +830,57 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
xvp.bottom = int32_t(guardBand);
|
||||
}
|
||||
|
||||
/*
|
||||
* Frame graph
|
||||
*/
|
||||
FrameGraph fg(*mResourceAllocator,
|
||||
isProtectedContent ? FrameGraph::Mode::PROTECTED : FrameGraph::Mode::UNPROTECTED);
|
||||
auto& blackboard = fg.getBlackboard();
|
||||
|
||||
PostProcessManager::ScreenSpaceRefConfig const ssrConfig = PostProcessManager::prepareMipmapSSR(
|
||||
fg, svp.width, svp.height,
|
||||
ssReflectionsOptions.enabled ? TextureFormat::RGBA16F : TextureFormat::R11F_G11F_B10F,
|
||||
view.getCameraUser().getFieldOfView(Camera::Fov::VERTICAL), scale);
|
||||
|
||||
/*
|
||||
* Update the PER_VIEW UBO used for the color, ssr and postfx passes. This UBO is never
|
||||
* updated again during the frame.
|
||||
*/
|
||||
|
||||
auto [bias, derivativeScale] = prepareUpscaler(scale, taaOptions, dsrOptions);
|
||||
|
||||
view.prepare(engine, driver, rootArenaScope, svp, cameraInfo, getShaderUserTime(), needsAlphaChannel);
|
||||
|
||||
view.prepareLodBias(bias, derivativeScale);
|
||||
view.prepareSSAO(aoOptions);
|
||||
view.prepareSSR(engine, cameraInfo, ssrConfig.lodOffset, ssReflectionsOptions);
|
||||
view.prepareShadowMapping();
|
||||
// There might be a bug here with svp's origin; normally the origin could offset when the
|
||||
// target is the swapchain (width/height are the same though). This would mean that we'd have
|
||||
// to wait for the color pass to execute to set the viewport. For now, I wasn't able to
|
||||
// get into such a case though.
|
||||
view.prepareViewport(svp, xvp);
|
||||
view.commitUniforms(driver);
|
||||
|
||||
/*
|
||||
* Update the PER_VIEW UBO use for the structure pass. It never updated again after this point.
|
||||
*/
|
||||
|
||||
// Set the PER_VIEW UBO for the passes that use the user materials, but are not the color pass
|
||||
// (e.g. structure, ssao). The PER_VIEW UBO may be different because these passes don't run
|
||||
// at the same resolution. We set only the values that are relevant to both user-materials
|
||||
// and the concerned passes. The PER_VIEW UBO contains data that is needed by the user
|
||||
// materials public APIs.
|
||||
StructureDescriptorSet& descriptorSet = ppm.getStructureDescriptorSet();
|
||||
descriptorSet.prepareCamera(engine, cameraInfo);
|
||||
descriptorSet.prepareTime(engine, getShaderUserTime());
|
||||
descriptorSet.prepareViewport(svp, {
|
||||
{ // the scope helps to guarantee that we're not modifying the descriptor-set later
|
||||
StructureDescriptorSet& ds = ppm.getStructureDescriptorSet();
|
||||
ds.prepareCamera(engine, cameraInfo);
|
||||
ds.prepareTime(engine, getShaderUserTime());
|
||||
ds.prepareViewport(svp, {
|
||||
int32_t(float(xvp.left) * aoOptions.resolution),
|
||||
int32_t(float(xvp.bottom) * aoOptions.resolution),
|
||||
uint32_t(float(xvp.width) * aoOptions.resolution),
|
||||
uint32_t(float(xvp.height) * aoOptions.resolution) });
|
||||
descriptorSet.prepareLodBias(bias, derivativeScale);
|
||||
descriptorSet.prepareMaterialGlobals(view.getMaterialGlobals());
|
||||
descriptorSet.commit(driver);
|
||||
|
||||
ds.prepareLodBias(bias, derivativeScale);
|
||||
ds.prepareMaterialGlobals(view.getMaterialGlobals());
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate command buffer
|
||||
@@ -874,14 +914,6 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
variant.setVsm(view.hasShadowing() && view.getShadowType() != ShadowType::PCF);
|
||||
variant.setStereo(view.hasStereo());
|
||||
|
||||
/*
|
||||
* Frame graph
|
||||
*/
|
||||
|
||||
FrameGraph fg(*mResourceAllocator,
|
||||
isProtectedContent ? FrameGraph::Mode::PROTECTED : FrameGraph::Mode::UNPROTECTED);
|
||||
auto& blackboard = fg.getBlackboard();
|
||||
|
||||
/*
|
||||
* Shadow pass
|
||||
*/
|
||||
@@ -957,7 +989,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
// the clearFlags and clearColor specified below will only apply when rendering into the
|
||||
// temporary color buffer. In particular, they won't apply when rendering into the main
|
||||
// swapchain (imported render target above)
|
||||
RendererUtils::ColorPassConfig config{
|
||||
RendererUtils::ColorPassConfig const config{
|
||||
.physicalViewport = svp,
|
||||
.logicalViewport = xvp,
|
||||
.scale = scale,
|
||||
@@ -966,7 +998,6 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
.clearFlags = getClearFlags(),
|
||||
.clearColor = clearColor,
|
||||
.clearStencil = clearStencil,
|
||||
.ssrLodOffset = 0.0f,
|
||||
.hasContactShadows = scene.hasContactShadows(),
|
||||
// at this point we don't know if we have refraction, but that's handled later
|
||||
.hasScreenSpaceReflectionsOrRefractions = ssReflectionsOptions.enabled,
|
||||
@@ -1052,23 +1083,12 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
blackboard["ssao"] = ssao;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// prepare screen-space reflection/refraction passes
|
||||
|
||||
PostProcessManager::ScreenSpaceRefConfig const ssrConfig = PostProcessManager::prepareMipmapSSR(
|
||||
fg, svp.width, svp.height,
|
||||
ssReflectionsOptions.enabled ? TextureFormat::RGBA16F : TextureFormat::R11F_G11F_B10F,
|
||||
view.getCameraUser().getFieldOfView(Camera::Fov::VERTICAL), config.scale);
|
||||
config.ssrLodOffset = ssrConfig.lodOffset;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// screen-space reflections pass
|
||||
|
||||
if (ssReflectionsOptions.enabled) {
|
||||
auto reflections = ppm.ssr(fg, passBuilder,
|
||||
view.getFrameHistory(), cameraInfo,
|
||||
structure,
|
||||
ssReflectionsOptions,
|
||||
view.getFrameHistory(), structure,
|
||||
{ .width = svp.width, .height = svp.height });
|
||||
|
||||
if (UTILS_LIKELY(reflections)) {
|
||||
@@ -1076,7 +1096,6 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
PostProcessManager::generateMipmapSSR(ppm, fg,
|
||||
reflections, ssrConfig.reflection, false, ssrConfig);
|
||||
}
|
||||
config.screenSpaceReflectionHistoryNotReady = !reflections;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -189,7 +189,7 @@ private:
|
||||
return mCommandsHighWatermark;
|
||||
}
|
||||
|
||||
void renderInternal(FView const* view);
|
||||
void renderInternal(FView const* view, bool flush);
|
||||
void renderJob(RootArenaScope& rootArenaScope, FView& view);
|
||||
|
||||
static std::pair<float, math::float2> prepareUpscaler(math::float2 scale,
|
||||
|
||||
@@ -158,11 +158,12 @@ VertexBuffer* VertexBuffer::Builder::build(Engine& engine) {
|
||||
|
||||
static_assert(DOCUMENTED_MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_BUFFER_COUNT);
|
||||
|
||||
auto const& featureFlags = static_cast<FEngine*>(&engine)->features.engine.debug;
|
||||
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(
|
||||
mImpl->mBufferCount <= DOCUMENTED_MAX_VERTEX_BUFFER_COUNT,
|
||||
featureFlags.assert_vertex_buffer_count_exceeds_8)
|
||||
<< "bufferCount cannot be more than " << DOCUMENTED_MAX_VERTEX_BUFFER_COUNT;
|
||||
if (downcast(engine).features.engine.debug.assert_vertex_buffer_count_exceeds_8) {
|
||||
FILAMENT_CHECK_PRECONDITION(mImpl->mBufferCount <= DOCUMENTED_MAX_VERTEX_BUFFER_COUNT)
|
||||
<< "bufferCount cannot be more than " << DOCUMENTED_MAX_VERTEX_BUFFER_COUNT;
|
||||
} else if (mImpl->mBufferCount > DOCUMENTED_MAX_VERTEX_BUFFER_COUNT) {
|
||||
LOG(WARNING) << "bufferCount cannot be more than " << DOCUMENTED_MAX_VERTEX_BUFFER_COUNT;
|
||||
}
|
||||
|
||||
// Next we check if any unused buffer slots have been allocated. This helps prevent errors
|
||||
// because uploading to an unused slot can trigger undefined behavior in the backend.
|
||||
@@ -176,10 +177,15 @@ VertexBuffer* VertexBuffer::Builder::build(Engine& engine) {
|
||||
<< "attribute " << j << " offset=" << attributes[j].offset
|
||||
<< " is not multiple of 4";
|
||||
|
||||
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION((attributes[j].stride & 0x3u) == 0,
|
||||
featureFlags.assert_vertex_buffer_attribute_stride_mult_of_4)
|
||||
<< "attribute " << j << " stride=" << +attributes[j].stride
|
||||
<< " is not multiple of 4";
|
||||
FEngine* fengine = static_cast<FEngine*>(&engine);
|
||||
if (fengine->features.engine.debug.assert_vertex_buffer_attribute_stride_mult_of_4) {
|
||||
FILAMENT_CHECK_PRECONDITION((attributes[j].stride & 0x3u) == 0)
|
||||
<< "attribute " << j << " stride=" << attributes[j].stride
|
||||
<< " is not multiple of 4";
|
||||
} else if ((attributes[j].stride & 0x3u) != 0) {
|
||||
LOG(WARNING) << "attribute " << j << " stride=" << attributes[j].stride
|
||||
<< " is not multiple of 4";
|
||||
}
|
||||
|
||||
if (engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0) {
|
||||
FILAMENT_CHECK_PRECONDITION(!(attributes[j].flags & Attribute::FLAG_INTEGER_TARGET))
|
||||
|
||||
+114
-35
@@ -948,61 +948,140 @@ void FView::prepareSSAO(Handle<HwTexture> ssao) const noexcept {
|
||||
getColorPassDescriptorSet().prepareSSAO(ssao, mAmbientOcclusionOptions);
|
||||
}
|
||||
|
||||
void FView::prepareSSR(Handle<HwTexture> ssr,
|
||||
bool const disableSSR,
|
||||
float const refractionLodOffset,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept {
|
||||
getColorPassDescriptorSet().prepareSSR(ssr, disableSSR, refractionLodOffset, ssrOptions);
|
||||
void FView::prepareSSAO(AmbientOcclusionOptions const& options) const noexcept {
|
||||
// High quality sampling is enabled only if AO itself is enabled and upsampling quality is at
|
||||
// least set to high and of course only if upsampling is needed.
|
||||
const bool highQualitySampling = options.upsampling >= QualityLevel::HIGH
|
||||
&& options.resolution < 1.0f;
|
||||
|
||||
const float edgeDistance = 1.0f / options.bilateralThreshold;
|
||||
auto& s = mUniforms.edit();
|
||||
s.aoSamplingQualityAndEdgeDistance =
|
||||
options.enabled ? (highQualitySampling ? edgeDistance : 0.0f) : -1.0f;
|
||||
s.aoBentNormals = options.enabled && options.bentNormals ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
void FView::prepareSSR(Handle<HwTexture> ssr) const noexcept {
|
||||
getColorPassDescriptorSet().prepareScreenSpaceRefraction(ssr);
|
||||
}
|
||||
|
||||
void FView::prepareSSR(FEngine& engine, CameraInfo const& cameraInfo,
|
||||
float const refractionLodOffset,
|
||||
ScreenSpaceReflectionsOptions const& options) const noexcept {
|
||||
|
||||
auto const& ssr = getFrameHistory().getPrevious().ssr;
|
||||
|
||||
bool const disableSSR = !ssr.color.handle;
|
||||
mat4 const& historyProjection = ssr.projection;
|
||||
mat4f const& uvFromClipMatrix = engine.getUvFromClipMatrix();
|
||||
mat4f const projection = cameraInfo.projection;
|
||||
mat4 const userViewMatrix = cameraInfo.getUserViewMatrix();
|
||||
|
||||
// set screen-space reflections and screen-space refractions
|
||||
mat4f const uvFromViewMatrix = uvFromClipMatrix * projection;
|
||||
mat4f const reprojection = uvFromClipMatrix *
|
||||
mat4f{ historyProjection * inverse(userViewMatrix) };
|
||||
|
||||
auto& s = mUniforms.edit();
|
||||
s.ssrReprojection = reprojection;
|
||||
s.ssrUvFromViewMatrix = uvFromViewMatrix;
|
||||
s.ssrThickness = options.thickness;
|
||||
s.ssrBias = options.bias;
|
||||
s.ssrStride = options.stride;
|
||||
s.refractionLodOffset = refractionLodOffset;
|
||||
s.ssrDistance = (options.enabled && !disableSSR) ? options.maxDistance : 0.0f;
|
||||
}
|
||||
|
||||
|
||||
void FView::prepareStructure(Handle<HwTexture> structure) const noexcept {
|
||||
// sampler must be NEAREST
|
||||
getColorPassDescriptorSet().prepareStructure(structure);
|
||||
}
|
||||
|
||||
void FView::prepareShadow(Handle<HwTexture> texture) const noexcept {
|
||||
void FView::prepareShadowMapping(FEngine const& engine, Handle<HwTexture> texture) const noexcept {
|
||||
// when needsShadowMap() is not set, this method only just sets a dummy texture
|
||||
// in the needed samplers (in that case `texture` is actually a dummy texture).
|
||||
ShadowMapManager::ShadowMappingUniforms uniforms;
|
||||
if (needsShadowMap()) {
|
||||
uniforms = mShadowMapManager->getShadowMappingUniforms();
|
||||
}
|
||||
switch (mShadowType) {
|
||||
case ShadowType::PCF:
|
||||
getColorPassDescriptorSet().prepareShadowPCF(texture, uniforms);
|
||||
break;
|
||||
case ShadowType::VSM:
|
||||
getColorPassDescriptorSet().prepareShadowVSM(texture, uniforms, mVsmShadowOptions);
|
||||
break;
|
||||
case ShadowType::DPCF:
|
||||
getColorPassDescriptorSet().prepareShadowDPCF(texture, uniforms, mSoftShadowOptions);
|
||||
break;
|
||||
case ShadowType::PCSS:
|
||||
getColorPassDescriptorSet().prepareShadowPCSS(texture, uniforms, mSoftShadowOptions);
|
||||
break;
|
||||
case ShadowType::PCFd:
|
||||
getColorPassDescriptorSet().prepareShadowPCFDebug(texture, uniforms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FView::prepareShadowMapping(FEngine const& engine, bool const highPrecision) const noexcept {
|
||||
BufferObjectHandle ubo{ engine.getDummyUniformBuffer() };
|
||||
if (mHasShadowing) {
|
||||
assert_invariant(mShadowMapManager);
|
||||
ubo = mShadowMapManager->getShadowUniformsHandle();
|
||||
}
|
||||
getColorPassDescriptorSet().prepareShadowMapping(ubo, highPrecision);
|
||||
getColorPassDescriptorSet().prepareShadowMapping(ubo);
|
||||
|
||||
switch (mShadowType) {
|
||||
case ShadowType::PCF:
|
||||
getColorPassDescriptorSet().prepareShadowPCF(texture);
|
||||
break;
|
||||
case ShadowType::VSM:
|
||||
getColorPassDescriptorSet().prepareShadowVSM(texture, mVsmShadowOptions);
|
||||
break;
|
||||
case ShadowType::DPCF:
|
||||
getColorPassDescriptorSet().prepareShadowDPCF(texture);
|
||||
break;
|
||||
case ShadowType::PCSS:
|
||||
getColorPassDescriptorSet().prepareShadowPCSS(texture);
|
||||
break;
|
||||
case ShadowType::PCFd:
|
||||
getColorPassDescriptorSet().prepareShadowPCFDebug(texture);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FView::commitUniformsAndSamplers(DriverApi& driver) const noexcept {
|
||||
void FView::prepareShadowMapping() const noexcept {
|
||||
|
||||
ShadowMapManager::ShadowMappingUniforms uniforms{};
|
||||
if (needsShadowMap()) {
|
||||
uniforms = mShadowMapManager->getShadowMappingUniforms();
|
||||
}
|
||||
|
||||
constexpr float low = 5.54f; // ~ std::log(std::numeric_limits<math::half>::max()) * 0.5f;
|
||||
constexpr float high = 42.0f; // ~ std::log(std::numeric_limits<float>::max()) * 0.5f;
|
||||
constexpr uint32_t SHADOW_SAMPLING_RUNTIME_PCF = 0u;
|
||||
constexpr uint32_t SHADOW_SAMPLING_RUNTIME_EVSM = 1u;
|
||||
constexpr uint32_t SHADOW_SAMPLING_RUNTIME_DPCF = 2u;
|
||||
constexpr uint32_t SHADOW_SAMPLING_RUNTIME_PCSS = 3u;
|
||||
auto& s = mUniforms.edit();
|
||||
s.cascadeSplits = uniforms.cascadeSplits;
|
||||
s.ssContactShadowDistance = uniforms.ssContactShadowDistance;
|
||||
s.directionalShadows = int32_t(uniforms.directionalShadows);
|
||||
s.cascades = int32_t(uniforms.cascades);
|
||||
switch (mShadowType) {
|
||||
case ShadowType::PCF:
|
||||
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCF;
|
||||
break;
|
||||
case ShadowType::VSM:
|
||||
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_EVSM;
|
||||
s.vsmExponent = mVsmShadowOptions.highPrecision ? high : low;
|
||||
s.vsmDepthScale = mVsmShadowOptions.minVarianceScale * 0.01f * s.vsmExponent;
|
||||
s.vsmLightBleedReduction = mVsmShadowOptions.lightBleedReduction;
|
||||
break;
|
||||
case ShadowType::DPCF:
|
||||
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_DPCF;
|
||||
s.shadowPenumbraRatioScale = mSoftShadowOptions.penumbraRatioScale;
|
||||
break;
|
||||
case ShadowType::PCSS:
|
||||
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCSS;
|
||||
s.shadowPenumbraRatioScale = mSoftShadowOptions.penumbraRatioScale;
|
||||
break;
|
||||
case ShadowType::PCFd:
|
||||
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FView::commitUniforms(DriverApi& driver) const noexcept {
|
||||
if (mUniforms.isDirty()) {
|
||||
mUniforms.clean();
|
||||
driver.updateBufferObject(mUniforms.getUboHandle(),
|
||||
mUniforms.toBufferDescriptor(driver), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void FView::commitDescriptorSet(DriverApi& driver) const noexcept {
|
||||
getColorPassDescriptorSet().commit(driver);
|
||||
}
|
||||
|
||||
void FView::unbindSamplers(FEngine& engine) noexcept {
|
||||
getColorPassDescriptorSet().unbindSamplers(engine);
|
||||
}
|
||||
|
||||
void FView::commitFroxels(DriverApi& driverApi) const noexcept {
|
||||
if (mHasDynamicLighting) {
|
||||
mFroxelizer.commit(driverApi);
|
||||
|
||||
@@ -173,16 +173,19 @@ public:
|
||||
void prepareLighting(FEngine& engine, CameraInfo const& cameraInfo) noexcept;
|
||||
|
||||
void prepareSSAO(backend::Handle<backend::HwTexture> ssao) const noexcept;
|
||||
void prepareSSR(backend::Handle<backend::HwTexture> ssr, bool disableSSR,
|
||||
float refractionLodOffset,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept;
|
||||
void prepareSSAO(AmbientOcclusionOptions const& options) const noexcept;
|
||||
|
||||
void prepareSSR(backend::Handle<backend::HwTexture> ssr) const noexcept;
|
||||
void prepareSSR(FEngine& engine, CameraInfo const& cameraInfo,
|
||||
float refractionLodOffset, ScreenSpaceReflectionsOptions const& options) const noexcept;
|
||||
|
||||
void prepareStructure(backend::Handle<backend::HwTexture> structure) const noexcept;
|
||||
void prepareShadow(backend::Handle<backend::HwTexture> structure) const noexcept;
|
||||
void prepareShadowMapping(FEngine const& engine, bool highPrecision) const noexcept;
|
||||
void prepareShadowMapping(FEngine const& engine, backend::Handle<backend::HwTexture> structure) const noexcept;
|
||||
void prepareShadowMapping() const noexcept;
|
||||
|
||||
void commitFroxels(backend::DriverApi& driverApi) const noexcept;
|
||||
void commitUniformsAndSamplers(backend::DriverApi& driver) const noexcept;
|
||||
void unbindSamplers(FEngine& engine) noexcept;
|
||||
void commitUniforms(backend::DriverApi& driver) const noexcept;
|
||||
void commitDescriptorSet(backend::DriverApi& driver) const noexcept;
|
||||
|
||||
utils::JobSystem::Job* getFroxelizerSync() const noexcept { return mFroxelizerSync; }
|
||||
void setFroxelizerSync(utils::JobSystem::Job* sync) noexcept { mFroxelizerSync = sync; }
|
||||
|
||||
@@ -257,7 +257,6 @@ void ColorPassDescriptorSet::prepareFog(FEngine& engine, const CameraInfo& camer
|
||||
|
||||
void ColorPassDescriptorSet::prepareSSAO(Handle<HwTexture> ssao,
|
||||
AmbientOcclusionOptions const& options) noexcept {
|
||||
|
||||
// High quality sampling is enabled only if AO itself is enabled and upsampling quality is at
|
||||
// least set to high and of course only if upsampling is needed.
|
||||
const bool highQualitySampling = options.upsampling >= QualityLevel::HIGH
|
||||
@@ -268,12 +267,6 @@ void ColorPassDescriptorSet::prepareSSAO(Handle<HwTexture> ssao,
|
||||
.filterMag = options.enabled && !highQualitySampling ?
|
||||
SamplerMagFilter::LINEAR : SamplerMagFilter::NEAREST
|
||||
});
|
||||
|
||||
const float edgeDistance = 1.0f / options.bilateralThreshold;
|
||||
auto& s = mUniforms.edit();
|
||||
s.aoSamplingQualityAndEdgeDistance =
|
||||
options.enabled ? (highQualitySampling ? edgeDistance : 0.0f) : -1.0f;
|
||||
s.aoBentNormals = options.enabled && options.bentNormals ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::prepareBlending(bool const needsAlphaChannel) noexcept {
|
||||
@@ -285,19 +278,11 @@ void ColorPassDescriptorSet::prepareMaterialGlobals(
|
||||
PerViewDescriptorSetUtils::prepareMaterialGlobals(mUniforms.edit(), materialGlobals);
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::prepareSSR(Handle<HwTexture> ssr,
|
||||
bool const disableSSR,
|
||||
float const refractionLodOffset,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept {
|
||||
|
||||
void ColorPassDescriptorSet::prepareScreenSpaceRefraction(Handle<HwTexture> ssr) noexcept {
|
||||
setSampler(+PerViewBindingPoints::SSR, ssr, {
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_LINEAR
|
||||
});
|
||||
|
||||
auto& s = mUniforms.edit();
|
||||
s.refractionLodOffset = refractionLodOffset;
|
||||
s.ssrDistance = (ssrOptions.enabled && !disableSSR) ? ssrOptions.maxDistance : 0.0f;
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::prepareStructure(Handle<HwTexture> structure) noexcept {
|
||||
@@ -379,27 +364,12 @@ void ColorPassDescriptorSet::prepareDynamicLights(Froxelizer& froxelizer) noexce
|
||||
s.lightFarAttenuationParams = 0.5f * float2{ 10.0f, 10.0f / (f * f) };
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::prepareShadowMapping(BufferObjectHandle shadowUniforms, bool const highPrecision) noexcept {
|
||||
auto& s = mUniforms.edit();
|
||||
constexpr float low = 5.54f; // ~ std::log(std::numeric_limits<math::half>::max()) * 0.5f;
|
||||
constexpr float high = 42.0f; // ~ std::log(std::numeric_limits<float>::max()) * 0.5f;
|
||||
s.vsmExponent = highPrecision ? high : low;
|
||||
void ColorPassDescriptorSet::prepareShadowMapping(BufferObjectHandle shadowUniforms) noexcept {
|
||||
setBuffer(+PerViewBindingPoints::SHADOWS, shadowUniforms, 0, sizeof(ShadowUib));
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::prepareShadowSampling(PerViewUib& uniforms,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms) noexcept {
|
||||
uniforms.cascadeSplits = shadowMappingUniforms.cascadeSplits;
|
||||
uniforms.ssContactShadowDistance = shadowMappingUniforms.ssContactShadowDistance;
|
||||
uniforms.directionalShadows = int32_t(shadowMappingUniforms.directionalShadows);
|
||||
uniforms.cascades = int32_t(shadowMappingUniforms.cascades);
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::prepareShadowVSM(Handle<HwTexture> texture,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms,
|
||||
VsmShadowOptions const& options) noexcept {
|
||||
constexpr float low = 5.54f; // ~ std::log(std::numeric_limits<math::half>::max()) * 0.5f;
|
||||
constexpr float high = 42.0f; // ~ std::log(std::numeric_limits<float>::max()) * 0.5f;
|
||||
SamplerMinFilter filterMin = SamplerMinFilter::LINEAR;
|
||||
if (options.anisotropy > 0 || options.mipmapping) {
|
||||
filterMin = SamplerMinFilter::LINEAR_MIPMAP_LINEAR;
|
||||
@@ -410,16 +380,9 @@ void ColorPassDescriptorSet::prepareShadowVSM(Handle<HwTexture> texture,
|
||||
.filterMin = filterMin,
|
||||
.anisotropyLog2 = options.anisotropy,
|
||||
});
|
||||
auto& s = mUniforms.edit();
|
||||
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_EVSM;
|
||||
s.vsmExponent = options.highPrecision ? high : low;
|
||||
s.vsmDepthScale = options.minVarianceScale * 0.01f * s.vsmExponent;
|
||||
s.vsmLightBleedReduction = options.lightBleedReduction;
|
||||
prepareShadowSampling(s, shadowMappingUniforms);
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::prepareShadowPCF(Handle<HwTexture> texture,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms) noexcept {
|
||||
void ColorPassDescriptorSet::prepareShadowPCF(Handle<HwTexture> texture) noexcept {
|
||||
setSampler(+PerViewBindingPoints::SHADOW_MAP,
|
||||
texture, {
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
@@ -427,71 +390,29 @@ void ColorPassDescriptorSet::prepareShadowPCF(Handle<HwTexture> texture,
|
||||
.compareMode = SamplerCompareMode::COMPARE_TO_TEXTURE,
|
||||
.compareFunc = SamplerCompareFunc::GE
|
||||
});
|
||||
auto& s = mUniforms.edit();
|
||||
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCF;
|
||||
prepareShadowSampling(s, shadowMappingUniforms);
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::prepareShadowDPCF(Handle<HwTexture> texture,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms,
|
||||
SoftShadowOptions const& options) noexcept {
|
||||
void ColorPassDescriptorSet::prepareShadowDPCF(Handle<HwTexture> texture) noexcept {
|
||||
setSampler(+PerViewBindingPoints::SHADOW_MAP, texture, {});
|
||||
auto& s = mUniforms.edit();
|
||||
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_DPCF;
|
||||
s.shadowPenumbraRatioScale = options.penumbraRatioScale;
|
||||
prepareShadowSampling(s, shadowMappingUniforms);
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::prepareShadowPCSS(Handle<HwTexture> texture,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms,
|
||||
SoftShadowOptions const& options) noexcept {
|
||||
void ColorPassDescriptorSet::prepareShadowPCSS(Handle<HwTexture> texture) noexcept {
|
||||
setSampler(+PerViewBindingPoints::SHADOW_MAP, texture, {});
|
||||
auto& s = mUniforms.edit();
|
||||
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCSS;
|
||||
s.shadowPenumbraRatioScale = options.penumbraRatioScale;
|
||||
prepareShadowSampling(s, shadowMappingUniforms);
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::prepareShadowPCFDebug(Handle<HwTexture> texture,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms) noexcept {
|
||||
void ColorPassDescriptorSet::prepareShadowPCFDebug(Handle<HwTexture> texture) noexcept {
|
||||
setSampler(+PerViewBindingPoints::SHADOW_MAP, texture, {
|
||||
.filterMag = SamplerMagFilter::NEAREST,
|
||||
.filterMin = SamplerMinFilter::NEAREST
|
||||
});
|
||||
auto& s = mUniforms.edit();
|
||||
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCF;
|
||||
prepareShadowSampling(s, shadowMappingUniforms);
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::commit(DriverApi& driver) noexcept {
|
||||
if (mUniforms.isDirty()) {
|
||||
driver.updateBufferObject(mUniforms.getUboHandle(),
|
||||
mUniforms.toBufferDescriptor(driver), 0);
|
||||
}
|
||||
|
||||
|
||||
for (size_t i = 0; i < DESCRIPTOR_LAYOUT_COUNT; i++) {
|
||||
mDescriptorSet[i].commit(mDescriptorSetLayout[i], driver);
|
||||
}
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::unbindSamplers(FEngine& engine) noexcept {
|
||||
// this needs to reset the sampler that are only set in RendererUtils::colorPass(), because
|
||||
// this descriptor-set is also used for ssr/picking/structure and these could be stale
|
||||
// it would be better to use a separate descriptor-set for those two cases so that we don't
|
||||
// have to do this
|
||||
setBuffer(+PerViewBindingPoints::SHADOWS,
|
||||
engine.getDummyUniformBuffer(), 0, sizeof(ShadowUib));
|
||||
setSampler(+PerViewBindingPoints::STRUCTURE,
|
||||
engine.getZeroTexture(), {});
|
||||
setSampler(+PerViewBindingPoints::SHADOW_MAP,
|
||||
engine.getOneTextureArrayDepth(), {});
|
||||
setSampler(+PerViewBindingPoints::SSAO,
|
||||
engine.getZeroTextureArray(), {});
|
||||
setSampler(+PerViewBindingPoints::SSR,
|
||||
engine.getZeroTextureArray(), {});
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::setSampler(descriptor_binding_t const binding,
|
||||
TextureHandle th, SamplerParams const params) noexcept {
|
||||
for (size_t i = 0; i < DESCRIPTOR_LAYOUT_COUNT; i++) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "TypedUniformBuffer.h"
|
||||
|
||||
#include <private/filament/EngineEnums.h>
|
||||
#include <private/filament/UibStructs.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
@@ -66,11 +67,6 @@ class ColorPassDescriptorSet {
|
||||
using LightManagerInstance = utils::EntityInstance<LightManager>;
|
||||
using TextureHandle = backend::Handle<backend::HwTexture>;
|
||||
|
||||
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_PCF = 0u;
|
||||
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_EVSM = 1u;
|
||||
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_DPCF = 2u;
|
||||
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_PCSS = 3u;
|
||||
|
||||
public:
|
||||
|
||||
static uint8_t getIndex(bool lit, bool ssr, bool fog) noexcept;
|
||||
@@ -112,12 +108,9 @@ public:
|
||||
void prepareMaterialGlobals(std::array<math::float4, 4> const& materialGlobals) noexcept;
|
||||
|
||||
// screen-space reflection and/or refraction (SSR)
|
||||
void prepareSSR(TextureHandle ssr,
|
||||
bool disableSSR,
|
||||
float refractionLodOffset,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept;
|
||||
void prepareScreenSpaceRefraction(TextureHandle ssr) noexcept;
|
||||
|
||||
void prepareShadowMapping(backend::BufferObjectHandle shadowUniforms, bool highPrecision) noexcept;
|
||||
void prepareShadowMapping(backend::BufferObjectHandle shadowUniforms) noexcept;
|
||||
|
||||
void prepareDirectionalLight(FEngine& engine, float exposure,
|
||||
math::float3 const& sceneSpaceDirection, LightManagerInstance instance) noexcept;
|
||||
@@ -128,28 +121,19 @@ public:
|
||||
void prepareDynamicLights(Froxelizer& froxelizer) noexcept;
|
||||
|
||||
void prepareShadowVSM(TextureHandle texture,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms,
|
||||
VsmShadowOptions const& options) noexcept;
|
||||
|
||||
void prepareShadowPCF(TextureHandle texture,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms) noexcept;
|
||||
void prepareShadowPCF(TextureHandle texture) noexcept;
|
||||
|
||||
void prepareShadowDPCF(TextureHandle texture,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms,
|
||||
SoftShadowOptions const& options) noexcept;
|
||||
void prepareShadowDPCF(TextureHandle texture) noexcept;
|
||||
|
||||
void prepareShadowPCSS(TextureHandle texture,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms,
|
||||
SoftShadowOptions const& options) noexcept;
|
||||
void prepareShadowPCSS(TextureHandle texture) noexcept;
|
||||
|
||||
void prepareShadowPCFDebug(TextureHandle texture,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms) noexcept;
|
||||
void prepareShadowPCFDebug(TextureHandle texture) noexcept;
|
||||
|
||||
// update local data into GPU UBO
|
||||
void commit(backend::DriverApi& driver) noexcept;
|
||||
|
||||
void unbindSamplers(FEngine& engine) noexcept;
|
||||
|
||||
// bind this UBO
|
||||
void bind(backend::DriverApi& driver, uint8_t const index) const noexcept {
|
||||
mDescriptorSet[index].bind(driver, DescriptorSetBindingPoints::PER_VIEW);
|
||||
@@ -166,9 +150,6 @@ private:
|
||||
void setBuffer(backend::descriptor_binding_t binding,
|
||||
backend::BufferObjectHandle boh, uint32_t offset, uint32_t size) noexcept;
|
||||
|
||||
static void prepareShadowSampling(PerViewUib& uniforms,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms) noexcept;
|
||||
|
||||
TypedUniformBuffer<PerViewUib>& mUniforms;
|
||||
std::array<DescriptorSetLayout, DESCRIPTOR_LAYOUT_COUNT> mDescriptorSetLayout;
|
||||
std::array<DescriptorSet, DESCRIPTOR_LAYOUT_COUNT> mDescriptorSet;
|
||||
|
||||
@@ -139,6 +139,11 @@ void DescriptorSet::bind(FEngine::DriverApi& driver, DescriptorSetBindingPoints
|
||||
driver.bindDescriptorSet(mDescriptorSetHandle, +set, std::move(dynamicOffsets));
|
||||
}
|
||||
|
||||
void DescriptorSet::unbind(backend::DriverApi& driver,
|
||||
DescriptorSetBindingPoints set) noexcept {
|
||||
driver.bindDescriptorSet({}, +set, {});
|
||||
}
|
||||
|
||||
void DescriptorSet::setBuffer(DescriptorSetLayout const& layout,
|
||||
backend::descriptor_binding_t const binding,
|
||||
backend::Handle<backend::HwBufferObject> boh, uint32_t const offset, uint32_t const size) {
|
||||
|
||||
@@ -62,6 +62,9 @@ public:
|
||||
void bind(backend::DriverApi& driver, DescriptorSetBindingPoints set,
|
||||
backend::DescriptorSetOffsetArray dynamicOffsets) const noexcept;
|
||||
|
||||
// unbind the descriptor set
|
||||
static void unbind(backend::DriverApi& driver, DescriptorSetBindingPoints set) noexcept;
|
||||
|
||||
// sets a ubo/ssbo descriptor
|
||||
void setBuffer(DescriptorSetLayout const& layout,
|
||||
backend::descriptor_binding_t binding,
|
||||
|
||||
@@ -66,29 +66,14 @@ void SsrPassDescriptorSet::setFrameUniforms(FEngine const& engine,
|
||||
// and GL would be okay without this, but Vulkan's validation layer would complain.
|
||||
mDescriptorSet.setBuffer(engine.getPerViewDescriptorSetLayoutSsrVariant(),
|
||||
+PerViewBindingPoints::SHADOWS, mShadowUbh, 0, sizeof(ShadowUib));
|
||||
|
||||
mUniforms = std::addressof(uniforms);
|
||||
}
|
||||
|
||||
void SsrPassDescriptorSet::prepareHistorySSR(FEngine const& engine, Handle<HwTexture> ssr,
|
||||
mat4f const& historyProjection,
|
||||
mat4f const& uvFromViewMatrix,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept {
|
||||
|
||||
void SsrPassDescriptorSet::prepareHistorySSR(FEngine const& engine, Handle<HwTexture> ssr) noexcept {
|
||||
mDescriptorSet.setSampler(engine.getPerViewDescriptorSetLayoutSsrVariant(),
|
||||
+PerViewBindingPoints::SSR_HISTORY, ssr, {
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
.filterMin = SamplerMinFilter::LINEAR
|
||||
});
|
||||
|
||||
assert_invariant(mUniforms);
|
||||
auto& s = mUniforms->edit();
|
||||
s.ssrReprojection = historyProjection;
|
||||
s.ssrUvFromViewMatrix = uvFromViewMatrix;
|
||||
s.ssrThickness = ssrOptions.thickness;
|
||||
s.ssrBias = ssrOptions.bias;
|
||||
s.ssrDistance = ssrOptions.enabled ? ssrOptions.maxDistance : 0.0f;
|
||||
s.ssrStride = ssrOptions.stride;
|
||||
}
|
||||
|
||||
void SsrPassDescriptorSet::prepareStructure(FEngine const& engine,
|
||||
@@ -99,12 +84,7 @@ void SsrPassDescriptorSet::prepareStructure(FEngine const& engine,
|
||||
}
|
||||
|
||||
void SsrPassDescriptorSet::commit(FEngine& engine) noexcept {
|
||||
assert_invariant(mUniforms);
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
if (mUniforms->isDirty()) {
|
||||
driver.updateBufferObject(mUniforms->getUboHandle(),
|
||||
mUniforms->toBufferDescriptor(driver), 0);
|
||||
}
|
||||
mDescriptorSet.commit(engine.getPerViewDescriptorSetLayoutSsrVariant(), driver);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
|
||||
#include "DescriptorSet.h"
|
||||
|
||||
#include "DescriptorSetLayout.h"
|
||||
|
||||
#include "TypedUniformBuffer.h"
|
||||
|
||||
#include <private/filament/UibStructs.h>
|
||||
@@ -28,8 +26,6 @@
|
||||
#include <backend/DriverApiForward.h>
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <math/mat4.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
class FEngine;
|
||||
@@ -51,11 +47,7 @@ public:
|
||||
|
||||
void prepareStructure(FEngine const& engine, TextureHandle structure) noexcept;
|
||||
|
||||
void prepareHistorySSR(FEngine const& engine, TextureHandle ssr,
|
||||
math::mat4f const& historyProjection,
|
||||
math::mat4f const& uvFromViewMatrix,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept;
|
||||
|
||||
void prepareHistorySSR(FEngine const& engine, TextureHandle ssr) noexcept;
|
||||
|
||||
// update local data into GPU UBO
|
||||
void commit(FEngine& engine) noexcept;
|
||||
@@ -64,7 +56,6 @@ public:
|
||||
void bind(backend::DriverApi& driver) noexcept;
|
||||
|
||||
private:
|
||||
TypedUniformBuffer<PerViewUib>* mUniforms = nullptr;
|
||||
DescriptorSet mDescriptorSet;
|
||||
backend::BufferObjectHandle mShadowUbh;
|
||||
};
|
||||
|
||||
@@ -63,14 +63,14 @@ void StructureDescriptorSet::terminate(DriverApi& driver) {
|
||||
mUniforms.terminate(driver);
|
||||
}
|
||||
|
||||
void StructureDescriptorSet::commit(DriverApi& driver) noexcept {
|
||||
assert_invariant(mDescriptorSetLayout);
|
||||
driver.updateBufferObject(mUniforms.getUboHandle(),
|
||||
mUniforms.toBufferDescriptor(driver), 0);
|
||||
mDescriptorSet.commit(*mDescriptorSetLayout, driver);
|
||||
}
|
||||
|
||||
void StructureDescriptorSet::bind(DriverApi& driver) const noexcept {
|
||||
assert_invariant(mDescriptorSetLayout);
|
||||
if (mUniforms.isDirty()) {
|
||||
mUniforms.clean();
|
||||
driver.updateBufferObject(mUniforms.getUboHandle(),
|
||||
mUniforms.toBufferDescriptor(driver), 0);
|
||||
mDescriptorSet.commit(*mDescriptorSetLayout, driver);
|
||||
}
|
||||
mDescriptorSet.bind(driver, DescriptorSetBindingPoints::PER_VIEW);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,7 @@ public:
|
||||
|
||||
void terminate(backend::DriverApi& driver);
|
||||
|
||||
void commit(backend::DriverApi& driver) noexcept;
|
||||
|
||||
// this commits the UBO if needed and binds the descriptor set
|
||||
void bind(backend::DriverApi& driver) const noexcept;
|
||||
|
||||
|
||||
@@ -65,7 +64,7 @@ public:
|
||||
|
||||
private:
|
||||
DescriptorSetLayout const* mDescriptorSetLayout = nullptr;
|
||||
DescriptorSet mDescriptorSet;
|
||||
mutable DescriptorSet mDescriptorSet;
|
||||
TypedUniformBuffer<PerViewUib> mUniforms;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.63.0"
|
||||
spec.version = "1.62.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.63.0/filament-v1.63.0-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.62.2/filament-v1.62.2-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
project(matp)
|
||||
|
||||
set(TARGET matp)
|
||||
set(PUBLIC_HDR_DIR include)
|
||||
|
||||
# ==================================================================================================
|
||||
# Sources and headers
|
||||
# ==================================================================================================
|
||||
set(PUBLIC_HDRS
|
||||
include/filament-matp/Config.h
|
||||
include/filament-matp/MaterialParser.h
|
||||
)
|
||||
|
||||
set(SRCS
|
||||
src/DirIncluder.h
|
||||
src/JsonishLexeme.h
|
||||
src/JsonishLexer.h
|
||||
src/JsonishParser.h
|
||||
src/Lexeme.h
|
||||
src/Lexer.h
|
||||
src/MaterialLexeme.h
|
||||
src/MaterialLexer.h
|
||||
src/ParametersProcessor.h
|
||||
src/DirIncluder.cpp
|
||||
src/JsonishLexer.cpp
|
||||
src/JsonishParser.cpp
|
||||
src/MaterialLexer.cpp
|
||||
src/MaterialParser.cpp
|
||||
src/ParametersProcessor.cpp
|
||||
)
|
||||
|
||||
# ==================================================================================================
|
||||
# Include and target definitions
|
||||
# ==================================================================================================
|
||||
include_directories(${PUBLIC_HDR_DIR})
|
||||
|
||||
add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS})
|
||||
|
||||
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
target_include_directories(${TARGET} PRIVATE ${filamat_SOURCE_DIR}/src)
|
||||
|
||||
set_target_properties(${TARGET} PROPERTIES FOLDER Libs)
|
||||
target_link_libraries(${TARGET} getopt filamat filabridge utils)
|
||||
|
||||
# ==================================================================================================
|
||||
# Installation
|
||||
# ==================================================================================================
|
||||
install(TARGETS ${TARGET} ARCHIVE DESTINATION lib/${DIST_DIR})
|
||||
install(DIRECTORY ${PUBLIC_HDR_DIR}/ DESTINATION include)
|
||||
|
||||
# ==================================================================================================
|
||||
# Tests
|
||||
# ==================================================================================================
|
||||
project(test_matp)
|
||||
set(TARGET test_matp)
|
||||
set(SRCS
|
||||
tests/test_matp.cpp
|
||||
tests/test_includer.cpp
|
||||
tests/TestMaterialParser.h
|
||||
tests/test_compute_material.cpp
|
||||
)
|
||||
|
||||
add_executable(${TARGET} ${SRCS})
|
||||
|
||||
target_link_libraries(${TARGET} matp gtest)
|
||||
|
||||
set_target_properties(test_matp PROPERTIES FOLDER Tests)
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
class Config {
|
||||
public:
|
||||
@@ -167,6 +167,6 @@ protected:
|
||||
bool mIncludeEssl1 = true;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace matp
|
||||
|
||||
#endif //TNT_CONFIG_H
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TNT_MATERIALPARSER_H
|
||||
#define TNT_MATERIALPARSER_H
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
namespace filamat {
|
||||
class MaterialBuilder;
|
||||
}
|
||||
class TestMaterialParser;
|
||||
|
||||
namespace matp {
|
||||
|
||||
class JsonishValue;
|
||||
class MaterialLexeme;
|
||||
|
||||
class MaterialParser {
|
||||
public:
|
||||
MaterialParser();
|
||||
|
||||
// Parses a string material so that it can be used in MaterialBuilder.
|
||||
// Call MaterialBuilder::init before passing in the builder; call MaterialBuilder::build to
|
||||
// create filamat::Package after.
|
||||
bool parse(
|
||||
filamat::MaterialBuilder& builder,
|
||||
const Config& config,
|
||||
Config::Input* input, ssize_t& size, std::unique_ptr<const char[]>& buffer);
|
||||
// Replaces macro keywords with user specified ones. Must be called before parse.
|
||||
bool processTemplateSubstitutions(
|
||||
const Config& config, ssize_t& size, std::unique_ptr<const char[]>& buffer);
|
||||
private:
|
||||
friend class ::TestMaterialParser;
|
||||
|
||||
bool parseMaterial(const char* buffer, size_t size,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processMaterial(const MaterialLexeme&,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processVertexShader(const MaterialLexeme&,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processFragmentShader(const MaterialLexeme&,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processComputeShader(const MaterialLexeme&,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool ignoreLexeme(const MaterialLexeme&, filamat::MaterialBuilder& builder) const noexcept;
|
||||
|
||||
bool parseMaterialAsJSON(const char* buffer, size_t size,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processMaterialJSON(const JsonishValue*,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processVertexShaderJSON(const JsonishValue*,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processFragmentShaderJSON(const JsonishValue*,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processComputeShaderJSON(const JsonishValue*,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool ignoreLexemeJSON(const JsonishValue*, filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool isValidJsonStart(const char* buffer, size_t size) const noexcept;
|
||||
|
||||
bool processMaterialParameters(filamat::MaterialBuilder& builder, const Config& config) const;
|
||||
|
||||
// Member function pointer type, this is used to implement a Command design
|
||||
// pattern.
|
||||
using MaterialConfigProcessor = bool (MaterialParser::*)
|
||||
(const MaterialLexeme&, filamat::MaterialBuilder& builder) const;
|
||||
// Map used to store Command pattern function pointers.
|
||||
std::unordered_map<std::string, MaterialConfigProcessor> mConfigProcessor;
|
||||
|
||||
// The same, but for pure JSON syntax
|
||||
using MaterialConfigProcessorJSON = bool (MaterialParser::*)
|
||||
(const JsonishValue*, filamat::MaterialBuilder& builder) const;
|
||||
std::unordered_map<std::string, MaterialConfigProcessorJSON> mConfigProcessorJSON;
|
||||
};
|
||||
|
||||
} // namespace matp
|
||||
|
||||
|
||||
#endif // TNT_MATERIALPARSER_H
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
bool DirIncluder::operator()(const utils::CString& includedBy, filamat::IncludeResult& result) {
|
||||
auto getHeaderPath = [&result, &includedBy, this]() {
|
||||
@@ -66,5 +66,5 @@ bool DirIncluder::operator()(const utils::CString& includedBy, filamat::IncludeR
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include <utils/Path.h>
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
// Functor callback handler used to resolve includes relative to a root include directory.
|
||||
class DirIncluder {
|
||||
@@ -38,6 +38,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
|
||||
#endif
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "Lexeme.h"
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
enum JsonType {
|
||||
BOOLEAN,
|
||||
@@ -68,6 +68,6 @@ public:
|
||||
|
||||
};
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
|
||||
#endif //TNT_JSONLEXEME_H
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
JsonType JsonishLexer::readIdentifier() noexcept {
|
||||
const char* lexemeStart = mCursor;
|
||||
@@ -148,4 +148,4 @@ bool JsonishLexer::readLexeme() noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "Lexer.h"
|
||||
#include "JsonishLexeme.h"
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
// Breaks down a stream of chars into JsonLexemes.
|
||||
class JsonishLexer final: public Lexer<JsonLexeme> {
|
||||
@@ -33,6 +33,6 @@ private:
|
||||
JsonType readPunctuation() noexcept;
|
||||
};
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
|
||||
#endif //TNT_JSONLEXER_H
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#include <utils/string.h>
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
static std::string resolveEscapes(const std::string& s) {
|
||||
std::string out;
|
||||
@@ -318,4 +318,4 @@ void JsonishParser::reportError(const char* message) noexcept {
|
||||
mErrorReported = true;
|
||||
}
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
// Follows the LL(1) grammar described at http://json.org:
|
||||
// with the following productions.
|
||||
@@ -279,6 +279,6 @@ private:
|
||||
bool mErrorReported = false;
|
||||
};
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
|
||||
#endif //TNT_JSONPARSER_H
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
// A lexeme MUST be templated on the family, e.g: Material config, json or glsl.
|
||||
template <class T>
|
||||
@@ -65,6 +65,6 @@ protected:
|
||||
T mType;
|
||||
};
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
|
||||
#endif // TNT_LEXEME_H
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "Lexeme.h"
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
// Templated on the class of Lexemes to parse: Material lexeme, JSON Lexemes, GLSL lexemes.
|
||||
template <class T>
|
||||
@@ -121,6 +121,7 @@ protected:
|
||||
size_t mLineCounter = 1;
|
||||
size_t mLinePosition = 0;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace matp
|
||||
|
||||
#endif //TNT_LEXER_H
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "Lexeme.h"
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
enum MaterialType {
|
||||
BLOCK,
|
||||
@@ -38,6 +38,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
|
||||
#endif //TNT_MATERIALLEXEME_H
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "MaterialLexer.h"
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
bool MaterialLexer::readBlock() noexcept {
|
||||
size_t braceCount = 0;
|
||||
@@ -97,4 +97,4 @@ bool MaterialLexer::readLexeme() noexcept {
|
||||
return nextMaterialType != UNKNOWN;
|
||||
}
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "Lexer.h"
|
||||
#include "MaterialLexeme.h"
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
class MaterialLexer final: public Lexer<MaterialLexeme> {
|
||||
public:
|
||||
@@ -35,6 +35,6 @@ private:
|
||||
void readUnknown() noexcept;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace matp
|
||||
|
||||
#endif //TNT_MATERIALLEXER_H
|
||||
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <filament-matp/MaterialParser.h>
|
||||
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
#include <filamat/MaterialBuilder.h>
|
||||
|
||||
#include <filamat/Enums.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/JobSystem.h>
|
||||
|
||||
#include "DirIncluder.h"
|
||||
#include "JsonishLexer.h"
|
||||
#include "JsonishParser.h"
|
||||
#include "MaterialLexeme.h"
|
||||
#include "MaterialLexer.h"
|
||||
#include "ParametersProcessor.h"
|
||||
#include <filament-matp/Config.h>
|
||||
|
||||
using namespace utils;
|
||||
using namespace filamat;
|
||||
using namespace std::placeholders;
|
||||
|
||||
namespace matp {
|
||||
|
||||
static constexpr const char* CONFIG_KEY_MATERIAL= "material";
|
||||
static constexpr const char* CONFIG_KEY_VERTEX_SHADER = "vertex";
|
||||
static constexpr const char* CONFIG_KEY_FRAGMENT_SHADER = "fragment";
|
||||
static constexpr const char* CONFIG_KEY_COMPUTE_SHADER = "compute";
|
||||
static constexpr const char* CONFIG_KEY_TOOL = "tool";
|
||||
|
||||
MaterialParser::MaterialParser() {
|
||||
mConfigProcessor[CONFIG_KEY_MATERIAL] = &MaterialParser::processMaterial;
|
||||
mConfigProcessor[CONFIG_KEY_VERTEX_SHADER] = &MaterialParser::processVertexShader;
|
||||
mConfigProcessor[CONFIG_KEY_FRAGMENT_SHADER] = &MaterialParser::processFragmentShader;
|
||||
mConfigProcessor[CONFIG_KEY_COMPUTE_SHADER] = &MaterialParser::processComputeShader;
|
||||
mConfigProcessor[CONFIG_KEY_TOOL] = &MaterialParser::ignoreLexeme;
|
||||
|
||||
mConfigProcessorJSON[CONFIG_KEY_MATERIAL] = &MaterialParser::processMaterialJSON;
|
||||
mConfigProcessorJSON[CONFIG_KEY_VERTEX_SHADER] = &MaterialParser::processVertexShaderJSON;
|
||||
mConfigProcessorJSON[CONFIG_KEY_FRAGMENT_SHADER] = &MaterialParser::processFragmentShaderJSON;
|
||||
mConfigProcessorJSON[CONFIG_KEY_COMPUTE_SHADER] = &MaterialParser::processComputeShaderJSON;
|
||||
mConfigProcessorJSON[CONFIG_KEY_TOOL] = &MaterialParser::ignoreLexemeJSON;
|
||||
}
|
||||
|
||||
bool MaterialParser::processMaterial(const MaterialLexeme& jsonLexeme,
|
||||
MaterialBuilder& builder) const noexcept {
|
||||
|
||||
JsonishLexer jlexer;
|
||||
jlexer.lex(jsonLexeme.getStart(), jsonLexeme.getSize(), jsonLexeme.getLine());
|
||||
|
||||
JsonishParser parser(jlexer.getLexemes());
|
||||
std::unique_ptr<JsonishObject> const json = parser.parse();
|
||||
|
||||
if (json == nullptr) {
|
||||
std::cerr << "JsonishParser error (see above)." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ParametersProcessor parametersProcessor;
|
||||
bool const ok = parametersProcessor.process(builder, *json);
|
||||
if (!ok) {
|
||||
std::cerr << "Error while processing material." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialParser::processVertexShader(const MaterialLexeme& lexeme,
|
||||
MaterialBuilder& builder) const noexcept {
|
||||
|
||||
MaterialLexeme const trimmedLexeme = lexeme.trimBlockMarkers();
|
||||
std::string const shaderStr = trimmedLexeme.getStringValue();
|
||||
|
||||
// getLine() returns a line number, with 1 being the first line, but .material wants a 0-based
|
||||
// line number offset, where 0 is the first line.
|
||||
builder.materialVertex(shaderStr.c_str(), trimmedLexeme.getLine() - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialParser::processFragmentShader(const MaterialLexeme& lexeme,
|
||||
MaterialBuilder& builder) const noexcept {
|
||||
|
||||
MaterialLexeme const trimmedLexeme = lexeme.trimBlockMarkers();
|
||||
std::string const shaderStr = trimmedLexeme.getStringValue();
|
||||
|
||||
// getLine() returns a line number, with 1 being the first line, but .material wants a 0-based
|
||||
// line number offset, where 0 is the first line.
|
||||
builder.material(shaderStr.c_str(), trimmedLexeme.getLine() - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialParser::processComputeShader(const MaterialLexeme& lexeme,
|
||||
MaterialBuilder& builder) const noexcept {
|
||||
return MaterialParser::processFragmentShader(lexeme, builder);
|
||||
}
|
||||
|
||||
bool MaterialParser::ignoreLexeme(const MaterialLexeme&, MaterialBuilder&) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reflectParameters(const MaterialBuilder& builder) {
|
||||
uint8_t const count = builder.getParameterCount();
|
||||
const MaterialBuilder::ParameterList& parameters = builder.getParameters();
|
||||
|
||||
std::cout << "{" << std::endl;
|
||||
std::cout << " \"parameters\": [" << std::endl;
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
const MaterialBuilder::Parameter& parameter = parameters[i];
|
||||
std::cout << " {" << std::endl;
|
||||
std::cout << R"( "name": ")" << parameter.name.c_str() << "\"," << std::endl;
|
||||
if (parameter.isSampler()) {
|
||||
std::cout << R"( "type": ")" <<
|
||||
Enums::toString(parameter.samplerType) << "\"," << std::endl;
|
||||
std::cout << R"( "format": ")" <<
|
||||
Enums::toString(parameter.format) << "\"," << std::endl;
|
||||
std::cout << R"( "precision": ")" <<
|
||||
Enums::toString(parameter.precision) << "\"," << std::endl;
|
||||
std::cout << R"( "multisample": ")" <<
|
||||
(parameter.multisample ? "true" : "false")<< "\"" << std::endl;
|
||||
} else if (parameter.isUniform()) {
|
||||
std::cout << R"( "type": ")" <<
|
||||
Enums::toString(parameter.uniformType) << "\"," << std::endl;
|
||||
std::cout << R"( "size": ")" << parameter.size << "\"" << std::endl;
|
||||
} else if (parameter.isSubpass()) {
|
||||
std::cout << R"( "type": ")" <<
|
||||
Enums::toString(parameter.subpassType) << "\"," << std::endl;
|
||||
std::cout << R"( "format": ")" <<
|
||||
Enums::toString(parameter.format) << "\"," << std::endl;
|
||||
std::cout << R"( "precision": ")" <<
|
||||
Enums::toString(parameter.precision) << "\"" << std::endl;
|
||||
}
|
||||
std::cout << " }";
|
||||
if (i < count - 1) std::cout << ",";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << " ]" << std::endl;
|
||||
std::cout << "}" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialParser::processMaterialJSON(const JsonishValue* value,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
if (!value) {
|
||||
std::cerr << "'material' block does not have a value, one is required." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value->getType() != JsonishValue::OBJECT) {
|
||||
std::cerr << "'material' block has an invalid type: "
|
||||
<< JsonishValue::typeToString(value->getType())
|
||||
<< ", should be OBJECT."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ParametersProcessor parametersProcessor;
|
||||
bool const ok = parametersProcessor.process(builder, *value->toJsonObject());
|
||||
if (!ok) {
|
||||
std::cerr << "Error while processing material." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialParser::processVertexShaderJSON(const JsonishValue* value,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
if (!value) {
|
||||
std::cerr << "'vertex' block does not have a value, one is required." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value->getType() != JsonishValue::STRING) {
|
||||
std::cerr << "'vertex' block has an invalid type: "
|
||||
<< JsonishValue::typeToString(value->getType())
|
||||
<< ", should be STRING."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
builder.materialVertex(value->toJsonString()->getString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialParser::processFragmentShaderJSON(const JsonishValue* value,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
if (!value) {
|
||||
std::cerr << "'fragment' block does not have a value, one is required." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value->getType() != JsonishValue::STRING) {
|
||||
std::cerr << "'fragment' block has an invalid type: "
|
||||
<< JsonishValue::typeToString(value->getType())
|
||||
<< ", should be STRING."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
builder.material(value->toJsonString()->getString().c_str());
|
||||
return true;
|
||||
}
|
||||
bool MaterialParser::processComputeShaderJSON(const JsonishValue* value,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
if (!value) {
|
||||
std::cerr << "'compute' block does not have a value, one is required." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value->getType() != JsonishValue::STRING) {
|
||||
std::cerr << "'compute' block has an invalid type: "
|
||||
<< JsonishValue::typeToString(value->getType())
|
||||
<< ", should be STRING."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
builder.material(value->toJsonString()->getString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialParser::ignoreLexemeJSON(const JsonishValue*,
|
||||
filamat::MaterialBuilder&) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialParser::isValidJsonStart(const char* buffer, size_t size) const noexcept {
|
||||
// Skip all whitespace characters.
|
||||
const char* end = buffer + size;
|
||||
while (buffer != end && isspace(buffer[0])) {
|
||||
buffer++;
|
||||
}
|
||||
|
||||
// A buffer made only of whitespace is not a valid JSON start.
|
||||
if (buffer == end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char c = buffer[0];
|
||||
|
||||
// Take care of block, array, and string
|
||||
if (c == '{' || c == '[' || c == '"') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// boolean true
|
||||
if (c == 't' && (end - buffer) > 3 && strncmp(buffer, "true", 4) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// boolean false
|
||||
if (c == 'f' && (end - buffer) > 4 && strncmp(buffer, "false", 5) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// null literal
|
||||
return c == 'n' && (end - buffer) > 3 && strncmp(buffer, "null", 5) != 0;
|
||||
}
|
||||
|
||||
bool MaterialParser::parseMaterialAsJSON(const char* buffer, size_t size,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
JsonishLexer jlexer;
|
||||
jlexer.lex(buffer, size, 1);
|
||||
|
||||
JsonishParser parser(jlexer.getLexemes());
|
||||
std::unique_ptr<JsonishObject> json = parser.parse();
|
||||
if (json == nullptr) {
|
||||
std::cerr << "Could not parse JSON material file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& entry : json->getEntries()) {
|
||||
const std::string& key = entry.first;
|
||||
if (mConfigProcessorJSON.find(key) == mConfigProcessorJSON.end()) {
|
||||
std::cerr << "Unknown identifier '" << key << "'" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retrieve function member pointer
|
||||
MaterialConfigProcessorJSON const p = mConfigProcessorJSON.at(key);
|
||||
// Call it.
|
||||
bool const ok = (*this.*p)(entry.second, builder);
|
||||
if (!ok) {
|
||||
std::cerr << "Error while processing block with key:'" << key << "'" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialParser::parseMaterial(const char* buffer, size_t size,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
MaterialLexer materialLexer;
|
||||
materialLexer.lex(buffer, size);
|
||||
auto lexemes = materialLexer.getLexemes();
|
||||
|
||||
// Make sure the lexer did not stumble upon unknown character. This could mean we received
|
||||
// a binary file.
|
||||
for (auto lexeme : lexemes) {
|
||||
if (lexeme.getType() == MaterialType::UNKNOWN) {
|
||||
std::cerr << "Unexpected character at line:" << lexeme.getLine()
|
||||
<< " position:" << lexeme.getLinePosition() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make a first quick pass just to make sure the format was respected (the material format is
|
||||
// a series of IDENTIFIER, BLOCK pairs).
|
||||
if (lexemes.size() < 2) {
|
||||
std::cerr << "Input MUST be an alternation of [identifier, block] pairs." << std::endl;
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < lexemes.size(); i += 2) {
|
||||
auto lexeme = lexemes.at(i);
|
||||
if (lexeme.getType() != MaterialType::IDENTIFIER) {
|
||||
std::cerr << "An identifier was expected at line:" << lexeme.getLine()
|
||||
<< " position:" << lexeme.getLinePosition() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i == lexemes.size() - 1) {
|
||||
std::cerr << "Identifier at line:" << lexeme.getLine()
|
||||
<< " position:" << lexeme.getLinePosition()
|
||||
<< " must be followed by a block." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto nextLexeme = lexemes.at(i + 1);
|
||||
if (nextLexeme.getType() != MaterialType::BLOCK) {
|
||||
std::cerr << "A block was expected at line:" << lexeme.getLine()
|
||||
<< " position:" << lexeme.getLinePosition() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string identifier;
|
||||
for (auto lexeme : lexemes) {
|
||||
if (lexeme.getType() == MaterialType::IDENTIFIER) {
|
||||
identifier = lexeme.getStringValue();
|
||||
if (mConfigProcessor.find(identifier) == mConfigProcessor.end()) {
|
||||
std::cerr << "Unknown identifier '"
|
||||
<< lexeme.getStringValue()
|
||||
<< "' at line:" << lexeme.getLine()
|
||||
<< " position:" << lexeme.getLinePosition() << std::endl;
|
||||
return false;
|
||||
}
|
||||
} else if (lexeme.getType() == MaterialType::BLOCK) {
|
||||
MaterialConfigProcessor const processor = mConfigProcessor.at(identifier);
|
||||
if (!(*this.*processor)(lexeme, builder)) {
|
||||
std::cerr << "Error while processing block with key:'" << identifier << "'"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialParser::processMaterialParameters(filamat::MaterialBuilder& builder,
|
||||
const Config& config) const {
|
||||
ParametersProcessor parametersProcessor;
|
||||
bool ok = true;
|
||||
for (const auto& param : config.getMaterialParameters()) {
|
||||
ok &= parametersProcessor.process(builder, param.first, param.second);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool MaterialParser::processTemplateSubstitutions(
|
||||
const Config& config, ssize_t& size, std::unique_ptr<const char[]>& buffer) {
|
||||
const auto& templateMap = config.getTemplateMap();
|
||||
ssize_t modifiedSize = size;
|
||||
bool modified = false;
|
||||
if (!templateMap.empty()) {
|
||||
for (ssize_t cursor = 0, n = size - 1; cursor < n; ++cursor) {
|
||||
if (UTILS_LIKELY(buffer[cursor] != '$' || buffer[cursor + 1] != '{')) {
|
||||
continue;
|
||||
}
|
||||
cursor += 2;
|
||||
ssize_t endCursor = cursor;
|
||||
while (true) {
|
||||
if (endCursor == size) {
|
||||
std::cerr << "Unexpected end of file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (buffer[endCursor] == '}') {
|
||||
break;
|
||||
}
|
||||
++endCursor;
|
||||
}
|
||||
// At this point, cursor points to the F in ${FOO} and endCursor points to the }.
|
||||
std::string_view const macro(&buffer[cursor], endCursor - cursor);
|
||||
if (auto iter = templateMap.find(macro); iter != templateMap.end()) {
|
||||
modifiedSize -= macro.size() + 3;
|
||||
modifiedSize += iter->second.size();
|
||||
} else {
|
||||
std::cerr << "Undefined template macro:" << macro << std::endl;
|
||||
return false;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass of template substitution allocates a new buffer and performs the actual
|
||||
// substitutions. Since the first pass did not return early, we can safely assume no errors.
|
||||
if (modified) {
|
||||
auto modifiedBuffer = std::make_unique<char[]>(modifiedSize);
|
||||
for (ssize_t cursor = 0, dstCursor = 0; cursor < size; ++cursor) {
|
||||
const ssize_t next = cursor + 1;
|
||||
if (UTILS_LIKELY(buffer[cursor] != '$' || next >= size || buffer[next] != '{')) {
|
||||
modifiedBuffer[dstCursor++] = buffer[cursor];
|
||||
continue;
|
||||
}
|
||||
cursor += 2;
|
||||
ssize_t endCursor = cursor;
|
||||
while (buffer[endCursor] != '}') ++endCursor;
|
||||
// At this point, cursor points to the F in ${FOO} and endCursor points to the }.
|
||||
std::string_view const macro(&buffer[cursor], endCursor - cursor);
|
||||
const std::string& val = templateMap.find(macro)->second;
|
||||
for (size_t i = 0, n = val.size(); i < n; ++i, ++dstCursor) {
|
||||
modifiedBuffer[dstCursor] = val[i];
|
||||
}
|
||||
cursor = endCursor;
|
||||
}
|
||||
buffer = std::move(modifiedBuffer);
|
||||
size = modifiedSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialParser::parse(filamat::MaterialBuilder& builder,
|
||||
const Config& config,
|
||||
Config::Input* input, ssize_t& size, std::unique_ptr<const char[]>& buffer) {
|
||||
|
||||
utils::Path const materialFilePath = utils::Path(input->getName()).getAbsolutePath();
|
||||
assert(materialFilePath.isFile());
|
||||
|
||||
if (builder.getFeatureLevel() > config.getFeatureLevel()) {
|
||||
std::cerr << "Material feature level (" << +builder.getFeatureLevel()
|
||||
<< ") is higher than maximum allowed (" << +config.getFeatureLevel() << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Before attempting an expensive lex, let's find out if we were sent pure JSON.
|
||||
bool parsed;
|
||||
if (isValidJsonStart(buffer.get(), size_t(size))) {
|
||||
parsed = parseMaterialAsJSON(buffer.get(), size_t(size), builder);
|
||||
} else {
|
||||
parsed = parseMaterial(buffer.get(), size_t(size), builder);
|
||||
}
|
||||
|
||||
if (!parsed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (config.getReflectionTarget()) {
|
||||
case Config::Metadata::NONE:
|
||||
break;
|
||||
case Config::Metadata::PARAMETERS:
|
||||
return reflectParameters(builder);
|
||||
}
|
||||
|
||||
// Set the root include directory to the directory containing the material file.
|
||||
DirIncluder includer;
|
||||
includer.setIncludeDirectory(materialFilePath.getParent());
|
||||
|
||||
builder
|
||||
.noSamplerValidation(config.noSamplerValidation())
|
||||
.includeEssl1(config.includeEssl1())
|
||||
.includeCallback(includer)
|
||||
.fileName(materialFilePath.getName().c_str())
|
||||
.platform(config.getPlatform())
|
||||
.targetApi(config.getTargetApi())
|
||||
.optimization(config.getOptimizationLevel())
|
||||
.printShaders(config.printShaders())
|
||||
.saveRawVariants(config.saveRawVariants())
|
||||
.generateDebugInfo(config.isDebug())
|
||||
.variantFilter(config.getVariantFilter() | builder.getVariantFilter());
|
||||
|
||||
for (const auto& define : config.getDefines()) {
|
||||
builder.shaderDefine(define.first.c_str(), define.second.c_str());
|
||||
}
|
||||
|
||||
if (!processMaterialParameters(builder, config)) {
|
||||
std::cerr << "Error while processing material parameters." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace matp
|
||||
+2
-2
@@ -34,7 +34,7 @@
|
||||
using namespace filamat;
|
||||
using namespace utils;
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
template <class T>
|
||||
static bool logEnumIssue(const std::string& key, const JsonishString& value,
|
||||
@@ -1467,4 +1467,4 @@ bool ParametersProcessor::process(filamat::MaterialBuilder& builder, const std::
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
+2
-2
@@ -26,7 +26,7 @@
|
||||
|
||||
#include <filamat/MaterialBuilder.h>
|
||||
|
||||
namespace matc {
|
||||
namespace matp {
|
||||
|
||||
class ParametersProcessor {
|
||||
|
||||
@@ -48,6 +48,6 @@ private:
|
||||
std::unordered_map<std::string, ParameterInfo> mParameters;
|
||||
};
|
||||
|
||||
} // namespace matc
|
||||
} // namespace matp
|
||||
|
||||
#endif //TNT_PARAMETERSPROCESSOR_H
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_TESTMATERIALPARSER_H
|
||||
#define TNT_TESTMATERIALPARSER_H
|
||||
|
||||
#include "filamat/MaterialBuilder.h"
|
||||
#include <filament-matp/MaterialParser.h>
|
||||
|
||||
class TestMaterialParser {
|
||||
public:
|
||||
explicit TestMaterialParser(const matp::MaterialParser& materialParser) :
|
||||
mMaterialParser(materialParser) {}
|
||||
|
||||
bool parseMaterial(const char* buffer, size_t size, filamat::MaterialBuilder& builder)
|
||||
noexcept{
|
||||
return mMaterialParser.parseMaterial(buffer, size, builder);
|
||||
}
|
||||
|
||||
bool parseMaterialAsJSON(const char* buffer, size_t size, filamat::MaterialBuilder& builder)
|
||||
noexcept{
|
||||
return mMaterialParser.parseMaterialAsJSON(buffer, size, builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const matp::MaterialParser mMaterialParser;
|
||||
};
|
||||
|
||||
#endif // TNT_TESTMATERIALPARSER_H
|
||||
+7
-9
@@ -16,11 +16,9 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <matc/MaterialCompiler.h>
|
||||
|
||||
#include "TestMaterialCompiler.h"
|
||||
|
||||
#include <utils/JobSystem.h>
|
||||
#include "TestMaterialParser.h"
|
||||
#include "utils/JobSystem.h"
|
||||
#include <filament-matp/MaterialParser.h>
|
||||
|
||||
static std::string_view jsonMaterialSourceSimple(R"(
|
||||
material {
|
||||
@@ -36,14 +34,14 @@ compute {
|
||||
}
|
||||
)");
|
||||
|
||||
TEST(TestComputeMaterial, JsonMaterialCompilerSimple) {
|
||||
matc::MaterialCompiler rawCompiler;
|
||||
TestMaterialCompiler compiler(rawCompiler);
|
||||
TEST(TestParseAndComputeMaterial, JsonMaterialCompilerSimple) {
|
||||
matp::MaterialParser parser;
|
||||
TestMaterialParser testParser(parser);
|
||||
|
||||
filamat::MaterialBuilder::init();
|
||||
filamat::MaterialBuilder builder;
|
||||
|
||||
bool result = compiler.parseMaterial(jsonMaterialSourceSimple.data(), jsonMaterialSourceSimple.size(), builder);
|
||||
bool result = testParser.parseMaterial(jsonMaterialSourceSimple.data(), jsonMaterialSourceSimple.size(), builder);
|
||||
|
||||
EXPECT_TRUE(result);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <matc/DirIncluder.h>
|
||||
#include "../src/DirIncluder.h"
|
||||
|
||||
using namespace utils;
|
||||
using namespace filamat;
|
||||
@@ -26,7 +26,7 @@ const utils::Path root = utils::Path(__FILE__).getParent();
|
||||
// TODO: these tests are disabled as they fail on CI, which needs investigation.
|
||||
|
||||
TEST(DirIncluder, DISABLED_IncludeNonexistent) {
|
||||
matc::DirIncluder includer;
|
||||
matp::DirIncluder includer;
|
||||
{
|
||||
IncludeResult i {
|
||||
.includeName = CString("nonexistent.h")
|
||||
@@ -45,7 +45,7 @@ TEST(DirIncluder, DISABLED_IncludeNonexistent) {
|
||||
}
|
||||
|
||||
TEST(DirIncluder, DISABLED_IncludeFile) {
|
||||
matc::DirIncluder includer;
|
||||
matp::DirIncluder includer;
|
||||
includer.setIncludeDirectory(root);
|
||||
|
||||
IncludeResult result {
|
||||
@@ -63,7 +63,7 @@ TEST(DirIncluder, DISABLED_IncludeFile) {
|
||||
}
|
||||
|
||||
TEST(DirIncluder, DISABLED_IncludeFileFromIncluder) {
|
||||
matc::DirIncluder includer;
|
||||
matp::DirIncluder includer;
|
||||
includer.setIncludeDirectory(root);
|
||||
|
||||
utils::CString includerFile((root + "Dir/Baz.h").c_str());
|
||||
@@ -1,28 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "MockConfig.h"
|
||||
#include "TestMaterialCompiler.h"
|
||||
#include "TestMaterialParser.h"
|
||||
|
||||
#include <matc/MaterialCompiler.h>
|
||||
#include <matc/MaterialLexer.h>
|
||||
#include <matc/JsonishLexer.h>
|
||||
#include <matc/JsonishParser.h>
|
||||
#include <filament-matp/MaterialParser.h>
|
||||
#include "../src/JsonishLexer.h"
|
||||
#include "../src/JsonishParser.h"
|
||||
#include "../src/MaterialLexer.h"
|
||||
|
||||
class MaterialLexer: public ::testing::Test {
|
||||
protected:
|
||||
@@ -80,7 +79,7 @@ static std::string materialSourceWithCommentedBraces(R"(
|
||||
)");
|
||||
|
||||
TEST_F(MaterialLexer, NormalMaterialLexing) {
|
||||
matc::MaterialLexer materialLexer;
|
||||
matp::MaterialLexer materialLexer;
|
||||
materialLexer.lex(materialSource.c_str(), materialSource.size(), 1);
|
||||
auto lexemes = materialLexer.getLexemes();
|
||||
// A material grammar is made of identifiers and blocks. The source provided has one identifier,
|
||||
@@ -88,27 +87,27 @@ TEST_F(MaterialLexer, NormalMaterialLexing) {
|
||||
EXPECT_EQ(lexemes.size(), 4);
|
||||
}
|
||||
|
||||
TEST_F(MaterialLexer, MaterialCompiler) {
|
||||
matc::MaterialCompiler rawCompiler;
|
||||
TestMaterialCompiler compiler(rawCompiler);
|
||||
filamat::MaterialBuilder unused;
|
||||
bool result = compiler.parseMaterial(materialSource.c_str(), materialSource.size(), unused);
|
||||
EXPECT_EQ(result, true);
|
||||
}
|
||||
|
||||
TEST_F(MaterialLexer, MaterialCompilerWithToolSection) {
|
||||
matc::MaterialCompiler rawCompiler;
|
||||
TestMaterialCompiler compiler(rawCompiler);
|
||||
TEST_F(MaterialLexer, MaterialParser) {
|
||||
matp::MaterialParser parser;
|
||||
TestMaterialParser testParser(parser);
|
||||
filamat::MaterialBuilder unused;
|
||||
bool result = compiler.parseMaterial(materialSourceWithTool.c_str(), materialSourceWithTool.size(), unused);
|
||||
bool result = testParser.parseMaterial(materialSource.c_str(), materialSource.size(), unused);
|
||||
EXPECT_EQ(result, true);
|
||||
}
|
||||
|
||||
TEST_F(MaterialLexer, MaterialCompilerWithCommentedBraces) {
|
||||
matc::MaterialCompiler rawCompiler;
|
||||
TestMaterialCompiler compiler(rawCompiler);
|
||||
TEST_F(MaterialLexer, MaterialParserWithToolSection) {
|
||||
matp::MaterialParser parser;
|
||||
TestMaterialParser testParser(parser);
|
||||
filamat::MaterialBuilder unused;
|
||||
bool result = compiler.parseMaterial(materialSourceWithCommentedBraces.c_str(), materialSourceWithCommentedBraces.size(), unused);
|
||||
bool result = testParser.parseMaterial(materialSourceWithTool.c_str(), materialSourceWithTool.size(), unused);
|
||||
EXPECT_EQ(result, true);
|
||||
}
|
||||
|
||||
TEST_F(MaterialLexer, MaterialParserWithCommentedBraces) {
|
||||
matp::MaterialParser parser;
|
||||
TestMaterialParser testParser(parser);
|
||||
filamat::MaterialBuilder unused;
|
||||
bool result = testParser.parseMaterial(materialSourceWithCommentedBraces.c_str(), materialSourceWithCommentedBraces.size(), unused);
|
||||
EXPECT_EQ(result, true);
|
||||
}
|
||||
|
||||
@@ -116,46 +115,46 @@ TEST_F(MaterialLexer, MaterialParserErrorOnlyIdentifier) {
|
||||
std::string sourceMissingIdentifier(R"(
|
||||
singleIdentifier
|
||||
)");
|
||||
matc::MaterialCompiler rawCompiler;
|
||||
TestMaterialCompiler compiler(rawCompiler);
|
||||
matp::MaterialParser parser;
|
||||
TestMaterialParser testParser(parser);
|
||||
filamat::MaterialBuilder unused;
|
||||
bool result = compiler.parseMaterial(
|
||||
bool result = testParser.parseMaterial(
|
||||
sourceMissingIdentifier.c_str(), sourceMissingIdentifier.size(), unused);
|
||||
EXPECT_EQ(result, false);
|
||||
}
|
||||
|
||||
TEST_F(MaterialLexer, MaterialParserErrorMissingBlock) {
|
||||
std::string sourceMissingBlock(R"(
|
||||
std::string sourceMissingBlock(R"(
|
||||
identifier1 {}
|
||||
identifier1
|
||||
)");
|
||||
matc::MaterialCompiler rawCompiler;
|
||||
TestMaterialCompiler compiler(rawCompiler);
|
||||
matp::MaterialParser parser;
|
||||
TestMaterialParser testParser(parser);
|
||||
filamat::MaterialBuilder unused;
|
||||
bool result = compiler.parseMaterial(
|
||||
bool result = testParser.parseMaterial(
|
||||
sourceMissingBlock.c_str(), sourceMissingBlock.size(), unused);
|
||||
EXPECT_EQ(result, false);
|
||||
}
|
||||
|
||||
TEST_F(MaterialLexer, MaterialParserErrorTwoBlock) {
|
||||
std::string sourceTwoBlock(R"(
|
||||
std::string sourceTwoBlock(R"(
|
||||
identifier1 {} {}
|
||||
)");
|
||||
matc::MaterialCompiler rawCompiler;
|
||||
TestMaterialCompiler compiler(rawCompiler);
|
||||
filamat::MaterialBuilder unused;
|
||||
bool result = compiler.parseMaterial(sourceTwoBlock.c_str(), sourceTwoBlock.size(), unused);
|
||||
EXPECT_EQ(result, false);
|
||||
matp::MaterialParser parser;
|
||||
TestMaterialParser testParser(parser);
|
||||
filamat::MaterialBuilder unused;
|
||||
bool result = testParser.parseMaterial(sourceTwoBlock.c_str(), sourceTwoBlock.size(), unused);
|
||||
EXPECT_EQ(result, false);
|
||||
}
|
||||
|
||||
TEST_F(MaterialLexer, MaterialParserSyntaxError) {
|
||||
std::string sourceSyntaxError(R"(
|
||||
identifier1 {} # identified2 {}
|
||||
)");
|
||||
matc::MaterialCompiler rawCompiler;
|
||||
TestMaterialCompiler compiler(rawCompiler);
|
||||
matp::MaterialParser parser;
|
||||
TestMaterialParser testParser(parser);
|
||||
filamat::MaterialBuilder unused;
|
||||
bool result = compiler.parseMaterial(sourceSyntaxError.c_str(), sourceSyntaxError.size(), unused);
|
||||
bool result = testParser.parseMaterial(sourceSyntaxError.c_str(), sourceSyntaxError.size(), unused);
|
||||
EXPECT_EQ(result, false);
|
||||
}
|
||||
|
||||
@@ -245,14 +244,14 @@ material: {
|
||||
})");
|
||||
|
||||
TEST_F(MaterialLexer, JsonMaterialLexingAndParsing) {
|
||||
matc::JsonishLexer jsonishLexer;
|
||||
matp::JsonishLexer jsonishLexer;
|
||||
jsonishLexer.lex(jsonMaterialSource.c_str(), jsonMaterialSource.size(), 1);
|
||||
auto lexemes = jsonishLexer.getLexemes();
|
||||
|
||||
EXPECT_TRUE(!lexemes.empty());
|
||||
|
||||
matc::JsonishParser jsonishParser(lexemes);
|
||||
std::unique_ptr<matc::JsonishObject> root = jsonishParser.parse();
|
||||
matp::JsonishParser jsonishParser(lexemes);
|
||||
std::unique_ptr<matp::JsonishObject> root = jsonishParser.parse();
|
||||
|
||||
auto entries = root->getEntries();
|
||||
EXPECT_TRUE(entries.size() == 2);
|
||||
@@ -261,29 +260,29 @@ TEST_F(MaterialLexer, JsonMaterialLexingAndParsing) {
|
||||
}
|
||||
|
||||
TEST_F(MaterialLexer, JsonMaterialLexingAndParsingNoQuotes) {
|
||||
matc::JsonishLexer jsonishLexer;
|
||||
matp::JsonishLexer jsonishLexer;
|
||||
jsonishLexer.lex(jsonMaterialSourceNoQuotes.c_str(), jsonMaterialSourceNoQuotes.size(), 1);
|
||||
auto lexemes = jsonishLexer.getLexemes();
|
||||
|
||||
EXPECT_TRUE(!lexemes.empty());
|
||||
|
||||
matc::JsonishParser jsonishParser(lexemes);
|
||||
std::unique_ptr<matc::JsonishObject> root = jsonishParser.parse();
|
||||
matp::JsonishParser jsonishParser(lexemes);
|
||||
std::unique_ptr<matp::JsonishObject> root = jsonishParser.parse();
|
||||
|
||||
auto entries = root->getEntries();
|
||||
EXPECT_TRUE(entries.size() == 1);
|
||||
EXPECT_TRUE(entries.find("material") != entries.end());
|
||||
}
|
||||
|
||||
TEST_F(MaterialLexer, JsonMaterialCompiler) {
|
||||
matc::MaterialCompiler rawCompiler;
|
||||
TestMaterialCompiler compiler(rawCompiler);
|
||||
filamat::MaterialBuilder unused;
|
||||
bool result = compiler.parseMaterialAsJSON(jsonMaterialSource.c_str(), jsonMaterialSource.size(), unused);
|
||||
EXPECT_EQ(result, true);
|
||||
TEST_F(MaterialLexer, JsonMaterialParser) {
|
||||
matp::MaterialParser parser;
|
||||
TestMaterialParser testParser(parser);
|
||||
filamat::MaterialBuilder unused;
|
||||
bool result = testParser.parseMaterialAsJSON(jsonMaterialSource.c_str(), jsonMaterialSource.size(), unused);
|
||||
EXPECT_EQ(result, true);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
}
|
||||
@@ -544,27 +544,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename PanicType>
|
||||
class FlagGuardedStream : public PanicStream {
|
||||
public:
|
||||
FlagGuardedStream(bool enable, char const* function, char const* file, int line,
|
||||
char const* condition)
|
||||
: PanicStream(function, file, line, condition),
|
||||
mEnablePanic(enable) {}
|
||||
~FlagGuardedStream() noexcept(false) {
|
||||
if (mEnablePanic) {
|
||||
PanicType::panic(mFunction, mFile, mLine, mLiteral, mStream.c_str());
|
||||
} else {
|
||||
logWarning();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void logWarning() noexcept;
|
||||
|
||||
bool mEnablePanic;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@@ -603,20 +582,6 @@ private:
|
||||
FILAMENT_CHECK_CONDITION_IMPL(condition) FILAMENT_PANIC_IMPL(#condition, ArithmeticPanic)
|
||||
#endif
|
||||
|
||||
#define FILAMENT_FLAG_GUARDED_PANIC_IMPL(flag, condition, TYPE) \
|
||||
::utils::details::FlagGuardedStream<::utils::TYPE>(flag, PANIC_FUNCTION, PANIC_FILE(__FILE__), \
|
||||
__LINE__, #condition)
|
||||
|
||||
#ifndef FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION
|
||||
#define FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(condition, flag) \
|
||||
FILAMENT_CHECK_CONDITION_IMPL(condition) FILAMENT_FLAG_GUARDED_PANIC_IMPL(flag, condition, PreconditionPanic)
|
||||
#endif
|
||||
|
||||
#ifndef FILAMENT_FLAG_GUARDED_CHECK_POSTCONDITION
|
||||
#define FILAMENT_FLAG_GUARDED_CHECK_POSTCONDITION(condition, flag) \
|
||||
FILAMENT_CHECK_CONDITION_IMPL(condition) FILAMENT_FLAG_GUARDED_PANIC_IMPL(flag, condition, PostconditionPanic)
|
||||
#endif
|
||||
|
||||
#define PANIC_PRECONDITION_IMPL(cond, format, ...) \
|
||||
::utils::PreconditionPanic::panic(PANIC_FUNCTION, \
|
||||
PANIC_FILE(__FILE__), __LINE__, #cond, format, ##__VA_ARGS__)
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <utils/CallStack.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
@@ -353,17 +352,6 @@ PanicStream& PanicStream::operator<<(std::string_view const& value) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename PanicType>
|
||||
void FlagGuardedStream<PanicType>::logWarning() noexcept {
|
||||
LOG(WARNING) << "Failed [" << mLiteral << "]" << "\n file=" << mFile
|
||||
<< "\n function=" << mFunction << "\n line=" << mLine << "\n info=\""
|
||||
<< mStream.c_str() << "\"";
|
||||
|
||||
}
|
||||
|
||||
template void FlagGuardedStream<PreconditionPanic>::logWarning() noexcept;
|
||||
template void FlagGuardedStream<PostconditionPanic>::logWarning() noexcept;
|
||||
|
||||
} // namespace details
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
# 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.
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
source test/renderdiff/src/preamble.sh
|
||||
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
echo "This is meant to run locally (not part of the CI)"
|
||||
exit 1
|
||||
else
|
||||
GOLDEN_BRANCH=$(git log -1 | python3 test/renderdiff/src/commit_msg.py)
|
||||
fi
|
||||
|
||||
./build.sh -f "$@" -p desktop debug gltf_viewer
|
||||
# -f -W -q arm64-v8a
|
||||
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Directory containing the GLTF files
|
||||
GLTF_DIR="path/to/your/gltf/files"
|
||||
GLTF_VIEWER_PATH="out/cmake-debug/samples/gltf_viewer"
|
||||
|
||||
GLTF_OUT_DIR="`dirname $0`/generated"
|
||||
|
||||
echo "The dirname is $GLTF_OUT_DIR"
|
||||
# echo `dirname $0`
|
||||
rm -rf $GLTF_OUT_DIR
|
||||
mkdir -p $GLTF_OUT_DIR
|
||||
# exit 0
|
||||
|
||||
# Base directory for the glTF-Sample-Assets repository
|
||||
GLTF_SAMPLES_DIR="../glTF-Sample-Assets/Models"
|
||||
|
||||
# Loop through each subdirectory in the base directory
|
||||
find "$GLTF_SAMPLES_DIR" -type f -name "*.gltf" | while read -r gltf_file; do
|
||||
# Get the base name of the file (e.g., "Box")
|
||||
base_name=$(basename "$gltf_file" .gltf)
|
||||
|
||||
echo "Processing $gltf_file..."
|
||||
|
||||
# Run the gltf_viewer command
|
||||
# You may need to adjust this path based on your project structure
|
||||
./out/cmake-debug/samples/gltf_viewer --api vulkan --batch=test/gltf-compare/test.json --headless "$gltf_file"
|
||||
|
||||
# Rename the generated .js and .tif files
|
||||
# The generated files are assumed to be in the same directory where the script is run
|
||||
|
||||
mv "Base0.tif" "${base_name}.tif"
|
||||
|
||||
# Move the newly renamed files to the Output directory
|
||||
|
||||
mv "${base_name}.tif" "$GLTF_OUT_DIR/"
|
||||
|
||||
echo "Generated files moved to $GLTF_OUT_DIR"
|
||||
echo "---"
|
||||
done
|
||||
|
||||
echo "Script finished."
|
||||
@@ -0,0 +1,9 @@
|
||||
[
|
||||
{
|
||||
"name": "Base",
|
||||
"base": {
|
||||
"view.postProcessingEnabled": true,
|
||||
"view.dithering": "NONE"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -12,28 +12,13 @@ set(TARGET matlang)
|
||||
set(HDRS
|
||||
src/matc/CommandlineConfig.h
|
||||
src/matc/Compiler.h
|
||||
src/matc/Config.h
|
||||
src/matc/JsonishLexeme.h
|
||||
src/matc/JsonishLexer.h
|
||||
src/matc/JsonishParser.h
|
||||
src/matc/Lexeme.h
|
||||
src/matc/Lexer.h
|
||||
src/matc/MaterialCompiler.h
|
||||
src/matc/MaterialLexeme.h
|
||||
src/matc/MaterialLexer.h
|
||||
src/matc/ParametersProcessor.h
|
||||
src/matc/DirIncluder.h
|
||||
)
|
||||
|
||||
set(SRCS
|
||||
src/matc/Compiler.cpp
|
||||
src/matc/CommandlineConfig.cpp
|
||||
src/matc/JsonishLexer.cpp
|
||||
src/matc/JsonishParser.cpp
|
||||
src/matc/MaterialCompiler.cpp
|
||||
src/matc/MaterialLexer.cpp
|
||||
src/matc/ParametersProcessor.cpp
|
||||
src/matc/DirIncluder.cpp
|
||||
src/matc/CommandlineConfig.cpp
|
||||
)
|
||||
|
||||
# ==================================================================================================
|
||||
@@ -44,7 +29,7 @@ add_library(${TARGET} STATIC ${SRCS} ${HDRS})
|
||||
target_include_directories(${TARGET} PUBLIC src)
|
||||
target_include_directories(${TARGET} PRIVATE ${filamat_SOURCE_DIR}/src)
|
||||
|
||||
target_link_libraries(${TARGET} getopt filamat filabridge utils)
|
||||
target_link_libraries(${TARGET} getopt filamat filabridge utils matp)
|
||||
set_target_properties(${TARGET} PROPERTIES FOLDER Tools)
|
||||
|
||||
# =================================================================================================
|
||||
@@ -77,22 +62,3 @@ set_target_properties(${TARGET} PROPERTIES FOLDER Tools)
|
||||
# Installation
|
||||
# ==================================================================================================
|
||||
install(TARGETS ${TARGET} RUNTIME DESTINATION bin)
|
||||
|
||||
# ==================================================================================================
|
||||
# Tests
|
||||
# ==================================================================================================
|
||||
project(test_matc)
|
||||
set(TARGET test_matc)
|
||||
set(SRCS
|
||||
tests/test_matc.cpp
|
||||
tests/test_includer.cpp
|
||||
tests/TestMaterialCompiler.h
|
||||
tests/test_compute_material.cpp
|
||||
tests/MockConfig.cpp
|
||||
tests/MockConfig.h)
|
||||
|
||||
add_executable(${TARGET} ${SRCS})
|
||||
|
||||
target_link_libraries(${TARGET} matlang gtest)
|
||||
|
||||
set_target_properties(test_matc PROPERTIES FOLDER Tests)
|
||||
|
||||
@@ -154,7 +154,7 @@ CommandlineConfig::CommandlineConfig(int argc, char** argv) : Config(), mArgc(ar
|
||||
mIsValid = parse();
|
||||
}
|
||||
|
||||
static void parseDefine(std::string defineString, Config::StringReplacementMap& defines) {
|
||||
static void parseDefine(std::string defineString, matp::Config::StringReplacementMap& defines) {
|
||||
const char* const defineArg = defineString.c_str();
|
||||
const size_t length = defineString.length();
|
||||
|
||||
|
||||
@@ -17,15 +17,14 @@
|
||||
#ifndef TNT_COMPILERPARAMETERS_H
|
||||
#define TNT_COMPILERPARAMETERS_H
|
||||
|
||||
#include <filament-matp/Config.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
namespace matc {
|
||||
|
||||
class FilesystemOutput : public Config::Output {
|
||||
class FilesystemOutput : public matp::Config::Output {
|
||||
public:
|
||||
explicit FilesystemOutput(const char* path) : mPath(path) {
|
||||
}
|
||||
@@ -55,7 +54,7 @@ private:
|
||||
std::ofstream mFile;
|
||||
};
|
||||
|
||||
class FilesystemInput : public Config::Input {
|
||||
class FilesystemInput : public matp::Config::Input {
|
||||
public:
|
||||
explicit FilesystemInput(const char* path) : mPath(path) {
|
||||
}
|
||||
@@ -97,7 +96,7 @@ private:
|
||||
ssize_t mFilesize = 0;
|
||||
};
|
||||
|
||||
class CommandlineConfig : public Config {
|
||||
class CommandlineConfig : public matp::Config {
|
||||
public:
|
||||
|
||||
CommandlineConfig(int argc, char** argv);
|
||||
@@ -106,11 +105,11 @@ public:
|
||||
delete mOutput;
|
||||
};
|
||||
|
||||
Output* getOutput() const noexcept override {
|
||||
matp::Config::Output* getOutput() const noexcept override {
|
||||
return mOutput;
|
||||
}
|
||||
|
||||
Input* getInput() const noexcept override {
|
||||
matp::Config::Input* getInput() const noexcept override {
|
||||
return mInput;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ using namespace filamat;
|
||||
|
||||
namespace matc {
|
||||
|
||||
bool Compiler::writeBlob(const Package &pkg, const Config& config) const noexcept {
|
||||
Config::Output* output = config.getOutput();
|
||||
bool Compiler::writeBlob(const Package &pkg, const matp::Config& config) const noexcept {
|
||||
matp::Config::Output* output = config.getOutput();
|
||||
if (!output->open()) {
|
||||
std::cerr << "Unable to create blob file." << std::endl;
|
||||
return false;
|
||||
@@ -37,10 +37,10 @@ bool Compiler::writeBlob(const Package &pkg, const Config& config) const noexcep
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Compiler::writeBlobAsHeader(const Package &pkg, const Config& config) const noexcept {
|
||||
bool Compiler::writeBlobAsHeader(const Package &pkg, const matp::Config& config) const noexcept {
|
||||
uint8_t* data = pkg.getData();
|
||||
|
||||
Config::Output* output = config.getOutput();
|
||||
matp::Config::Output* output = config.getOutput();
|
||||
if (!output->open()) {
|
||||
std::cerr << "Unable to create header file." << std::endl;
|
||||
return false;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define TNT_COMPILER_H
|
||||
|
||||
#include "CommandlineConfig.h"
|
||||
#include <filament-matp/Config.h>
|
||||
|
||||
#include <filamat/Package.h>
|
||||
|
||||
@@ -27,7 +28,7 @@ class Compiler {
|
||||
public:
|
||||
virtual ~Compiler() = default;
|
||||
|
||||
bool compile(const Config& config) {
|
||||
bool compile(const matp::Config& config) {
|
||||
if (!checkParameters(config)) {
|
||||
return false;
|
||||
}
|
||||
@@ -35,22 +36,22 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
bool writePackage(const filamat::Package& package, const Config& config) {
|
||||
bool writePackage(const filamat::Package& package, const matp::Config& config) {
|
||||
if (config.getOutputFormat() == CommandlineConfig::OutputFormat::BLOB) {
|
||||
return writeBlob(package, config);
|
||||
} else {
|
||||
return writeBlobAsHeader(package, config);
|
||||
}
|
||||
}
|
||||
virtual bool run(const Config& config) = 0;
|
||||
virtual bool checkParameters(const Config& config) = 0;
|
||||
virtual bool run(const matp::Config& config) = 0;
|
||||
virtual bool checkParameters(const matp::Config& config) = 0;
|
||||
|
||||
// Write Package as binary to target filename
|
||||
bool writeBlob(const filamat::Package& pkg, const Config& config) const noexcept;
|
||||
bool writeBlob(const filamat::Package& pkg, const matp::Config& config) const noexcept;
|
||||
|
||||
// Write package as a C++ array content. Use this to include material
|
||||
// in your executable/library.
|
||||
bool writeBlobAsHeader(const filamat::Package& pkg, const Config& config) const noexcept;
|
||||
bool writeBlobAsHeader(const filamat::Package& pkg, const matp::Config& config) const noexcept;
|
||||
};
|
||||
|
||||
} // namespace matc
|
||||
|
||||
@@ -22,17 +22,11 @@
|
||||
|
||||
#include <filamat/MaterialBuilder.h>
|
||||
|
||||
#include <filamat/Enums.h>
|
||||
#include <filament-matp/Config.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/JobSystem.h>
|
||||
|
||||
#include "DirIncluder.h"
|
||||
#include "MaterialLexeme.h"
|
||||
#include "MaterialLexer.h"
|
||||
#include "JsonishLexer.h"
|
||||
#include "JsonishParser.h"
|
||||
#include "ParametersProcessor.h"
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Path.h>
|
||||
|
||||
#include <GlslangToSpv.h>
|
||||
#include "glslang/Include/intermediate.h"
|
||||
@@ -47,249 +41,8 @@ using namespace std::placeholders;
|
||||
|
||||
namespace matc {
|
||||
|
||||
static constexpr const char* CONFIG_KEY_MATERIAL= "material";
|
||||
static constexpr const char* CONFIG_KEY_VERTEX_SHADER = "vertex";
|
||||
static constexpr const char* CONFIG_KEY_FRAGMENT_SHADER = "fragment";
|
||||
static constexpr const char* CONFIG_KEY_COMPUTE_SHADER = "compute";
|
||||
static constexpr const char* CONFIG_KEY_TOOL = "tool";
|
||||
|
||||
MaterialCompiler::MaterialCompiler() {
|
||||
mConfigProcessor[CONFIG_KEY_MATERIAL] = &MaterialCompiler::processMaterial;
|
||||
mConfigProcessor[CONFIG_KEY_VERTEX_SHADER] = &MaterialCompiler::processVertexShader;
|
||||
mConfigProcessor[CONFIG_KEY_FRAGMENT_SHADER] = &MaterialCompiler::processFragmentShader;
|
||||
mConfigProcessor[CONFIG_KEY_COMPUTE_SHADER] = &MaterialCompiler::processComputeShader;
|
||||
mConfigProcessor[CONFIG_KEY_TOOL] = &MaterialCompiler::ignoreLexeme;
|
||||
|
||||
mConfigProcessorJSON[CONFIG_KEY_MATERIAL] = &MaterialCompiler::processMaterialJSON;
|
||||
mConfigProcessorJSON[CONFIG_KEY_VERTEX_SHADER] = &MaterialCompiler::processVertexShaderJSON;
|
||||
mConfigProcessorJSON[CONFIG_KEY_FRAGMENT_SHADER] = &MaterialCompiler::processFragmentShaderJSON;
|
||||
mConfigProcessorJSON[CONFIG_KEY_COMPUTE_SHADER] = &MaterialCompiler::processComputeShaderJSON;
|
||||
mConfigProcessorJSON[CONFIG_KEY_TOOL] = &MaterialCompiler::ignoreLexemeJSON;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::processMaterial(const MaterialLexeme& jsonLexeme,
|
||||
MaterialBuilder& builder) const noexcept {
|
||||
|
||||
JsonishLexer jlexer;
|
||||
jlexer.lex(jsonLexeme.getStart(), jsonLexeme.getSize(), jsonLexeme.getLine());
|
||||
|
||||
JsonishParser parser(jlexer.getLexemes());
|
||||
std::unique_ptr<JsonishObject> const json = parser.parse();
|
||||
|
||||
if (json == nullptr) {
|
||||
std::cerr << "JsonishParser error (see above)." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ParametersProcessor parametersProcessor;
|
||||
bool const ok = parametersProcessor.process(builder, *json);
|
||||
if (!ok) {
|
||||
std::cerr << "Error while processing material." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::processVertexShader(const MaterialLexeme& lexeme,
|
||||
MaterialBuilder& builder) const noexcept {
|
||||
|
||||
MaterialLexeme const trimmedLexeme = lexeme.trimBlockMarkers();
|
||||
std::string const shaderStr = trimmedLexeme.getStringValue();
|
||||
|
||||
// getLine() returns a line number, with 1 being the first line, but .material wants a 0-based
|
||||
// line number offset, where 0 is the first line.
|
||||
builder.materialVertex(shaderStr.c_str(), trimmedLexeme.getLine() - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::processFragmentShader(const MaterialLexeme& lexeme,
|
||||
MaterialBuilder& builder) const noexcept {
|
||||
|
||||
MaterialLexeme const trimmedLexeme = lexeme.trimBlockMarkers();
|
||||
std::string const shaderStr = trimmedLexeme.getStringValue();
|
||||
|
||||
// getLine() returns a line number, with 1 being the first line, but .material wants a 0-based
|
||||
// line number offset, where 0 is the first line.
|
||||
builder.material(shaderStr.c_str(), trimmedLexeme.getLine() - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::processComputeShader(const MaterialLexeme& lexeme,
|
||||
MaterialBuilder& builder) const noexcept {
|
||||
return MaterialCompiler::processFragmentShader(lexeme, builder);
|
||||
}
|
||||
|
||||
bool MaterialCompiler::ignoreLexeme(const MaterialLexeme&, MaterialBuilder&) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::processMaterialJSON(const JsonishValue* value,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
if (!value) {
|
||||
std::cerr << "'material' block does not have a value, one is required." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value->getType() != JsonishValue::OBJECT) {
|
||||
std::cerr << "'material' block has an invalid type: "
|
||||
<< JsonishValue::typeToString(value->getType())
|
||||
<< ", should be OBJECT."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ParametersProcessor parametersProcessor;
|
||||
bool const ok = parametersProcessor.process(builder, *value->toJsonObject());
|
||||
if (!ok) {
|
||||
std::cerr << "Error while processing material." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::processVertexShaderJSON(const JsonishValue* value,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
if (!value) {
|
||||
std::cerr << "'vertex' block does not have a value, one is required." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value->getType() != JsonishValue::STRING) {
|
||||
std::cerr << "'vertex' block has an invalid type: "
|
||||
<< JsonishValue::typeToString(value->getType())
|
||||
<< ", should be STRING."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
builder.materialVertex(value->toJsonString()->getString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::processFragmentShaderJSON(const JsonishValue* value,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
if (!value) {
|
||||
std::cerr << "'fragment' block does not have a value, one is required." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value->getType() != JsonishValue::STRING) {
|
||||
std::cerr << "'fragment' block has an invalid type: "
|
||||
<< JsonishValue::typeToString(value->getType())
|
||||
<< ", should be STRING."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
builder.material(value->toJsonString()->getString().c_str());
|
||||
return true;
|
||||
}
|
||||
bool MaterialCompiler::processComputeShaderJSON(const JsonishValue* value,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
if (!value) {
|
||||
std::cerr << "'compute' block does not have a value, one is required." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value->getType() != JsonishValue::STRING) {
|
||||
std::cerr << "'compute' block has an invalid type: "
|
||||
<< JsonishValue::typeToString(value->getType())
|
||||
<< ", should be STRING."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
builder.material(value->toJsonString()->getString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::ignoreLexemeJSON(const JsonishValue*,
|
||||
filamat::MaterialBuilder&) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reflectParameters(const MaterialBuilder& builder) {
|
||||
uint8_t const count = builder.getParameterCount();
|
||||
const MaterialBuilder::ParameterList& parameters = builder.getParameters();
|
||||
|
||||
std::cout << "{" << std::endl;
|
||||
std::cout << " \"parameters\": [" << std::endl;
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
const MaterialBuilder::Parameter& parameter = parameters[i];
|
||||
std::cout << " {" << std::endl;
|
||||
std::cout << R"( "name": ")" << parameter.name.c_str() << "\"," << std::endl;
|
||||
if (parameter.isSampler()) {
|
||||
std::cout << R"( "type": ")" <<
|
||||
Enums::toString(parameter.samplerType) << "\"," << std::endl;
|
||||
std::cout << R"( "format": ")" <<
|
||||
Enums::toString(parameter.format) << "\"," << std::endl;
|
||||
std::cout << R"( "precision": ")" <<
|
||||
Enums::toString(parameter.precision) << "\"," << std::endl;
|
||||
std::cout << R"( "multisample": ")" <<
|
||||
(parameter.multisample ? "true" : "false")<< "\"" << std::endl;
|
||||
} else if (parameter.isUniform()) {
|
||||
std::cout << R"( "type": ")" <<
|
||||
Enums::toString(parameter.uniformType) << "\"," << std::endl;
|
||||
std::cout << R"( "size": ")" << parameter.size << "\"" << std::endl;
|
||||
} else if (parameter.isSubpass()) {
|
||||
std::cout << R"( "type": ")" <<
|
||||
Enums::toString(parameter.subpassType) << "\"," << std::endl;
|
||||
std::cout << R"( "format": ")" <<
|
||||
Enums::toString(parameter.format) << "\"," << std::endl;
|
||||
std::cout << R"( "precision": ")" <<
|
||||
Enums::toString(parameter.precision) << "\"" << std::endl;
|
||||
}
|
||||
std::cout << " }";
|
||||
if (i < count - 1) std::cout << ",";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << " ]" << std::endl;
|
||||
std::cout << "}" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::isValidJsonStart(const char* buffer, size_t size) const noexcept {
|
||||
// Skip all whitespace characters.
|
||||
const char* end = buffer + size;
|
||||
while (buffer != end && isspace(buffer[0])) {
|
||||
buffer++;
|
||||
}
|
||||
|
||||
// A buffer made only of whitespace is not a valid JSON start.
|
||||
if (buffer == end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char c = buffer[0];
|
||||
|
||||
// Take care of block, array, and string
|
||||
if (c == '{' || c == '[' || c == '"') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// boolean true
|
||||
if (c == 't' && (end - buffer) > 3 && strncmp(buffer, "true", 4) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// boolean false
|
||||
if (c == 'f' && (end - buffer) > 4 && strncmp(buffer, "false", 5) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// null literal
|
||||
return c == 'n' && (end - buffer) > 3 && strncmp(buffer, "null", 5) != 0;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::run(const Config& config) {
|
||||
Config::Input* input = config.getInput();
|
||||
bool MaterialCompiler::run(const matp::Config& config) {
|
||||
matp::Config::Input* input = config.getInput();
|
||||
ssize_t size = input->open();
|
||||
if (size <= 0) {
|
||||
std::cerr << "Input file is empty" << std::endl;
|
||||
@@ -297,70 +50,11 @@ bool MaterialCompiler::run(const Config& config) {
|
||||
}
|
||||
std::unique_ptr<const char[]> buffer = input->read();
|
||||
|
||||
// Perform template substitutions in two passes: the first pass determines the size of the
|
||||
// modified buffer and checks for errors. The second pass rebuilds the buffer.
|
||||
const auto& templateMap = config.getTemplateMap();
|
||||
ssize_t modifiedSize = size;
|
||||
bool modified = false;
|
||||
if (!templateMap.empty()) {
|
||||
for (ssize_t cursor = 0, n = size - 1; cursor < n; ++cursor) {
|
||||
if (UTILS_LIKELY(buffer[cursor] != '$' || buffer[cursor + 1] != '{')) {
|
||||
continue;
|
||||
}
|
||||
cursor += 2;
|
||||
ssize_t endCursor = cursor;
|
||||
while (true) {
|
||||
if (endCursor == size) {
|
||||
std::cerr << "Unexpected end of file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (buffer[endCursor] == '}') {
|
||||
break;
|
||||
}
|
||||
++endCursor;
|
||||
}
|
||||
// At this point, cursor points to the F in ${FOO} and endCursor points to the }.
|
||||
std::string_view const macro(&buffer[cursor], endCursor - cursor);
|
||||
if (auto iter = templateMap.find(macro); iter != templateMap.end()) {
|
||||
modifiedSize -= macro.size() + 3;
|
||||
modifiedSize += iter->second.size();
|
||||
} else {
|
||||
std::cerr << "Undefined template macro:" << macro << std::endl;
|
||||
return false;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass of template substitution allocates a new buffer and performs the actual
|
||||
// substitutions. Since the first pass did not return early, we can safely assume no errors.
|
||||
if (modified) {
|
||||
auto modifiedBuffer = std::make_unique<char[]>(modifiedSize);
|
||||
for (ssize_t cursor = 0, dstCursor = 0; cursor < size; ++cursor) {
|
||||
const ssize_t next = cursor + 1;
|
||||
if (UTILS_LIKELY(buffer[cursor] != '$' || next >= size || buffer[next] != '{')) {
|
||||
modifiedBuffer[dstCursor++] = buffer[cursor];
|
||||
continue;
|
||||
}
|
||||
cursor += 2;
|
||||
ssize_t endCursor = cursor;
|
||||
while (buffer[endCursor] != '}') ++endCursor;
|
||||
// At this point, cursor points to the F in ${FOO} and endCursor points to the }.
|
||||
std::string_view const macro(&buffer[cursor], endCursor - cursor);
|
||||
const std::string& val = templateMap.find(macro)->second;
|
||||
for (size_t i = 0, n = val.size(); i < n; ++i, ++dstCursor) {
|
||||
modifiedBuffer[dstCursor] = val[i];
|
||||
}
|
||||
cursor = endCursor;
|
||||
}
|
||||
buffer = std::move(modifiedBuffer);
|
||||
size = modifiedSize;
|
||||
}
|
||||
|
||||
utils::Path const materialFilePath = utils::Path(input->getName()).getAbsolutePath();
|
||||
assert(materialFilePath.isFile());
|
||||
mParser.processTemplateSubstitutions(config, size, buffer);
|
||||
|
||||
if (config.rawShaderMode()) {
|
||||
utils::Path const materialFilePath = utils::Path(config.getInput()->getName()).getAbsolutePath();
|
||||
assert(materialFilePath.isFile());
|
||||
const std::string extension = materialFilePath.getExtension();
|
||||
glslang::InitializeProcess();
|
||||
bool const success = compileRawShader(buffer.get(), size, config.isDebug(), config.getOutput(),
|
||||
@@ -371,54 +65,8 @@ bool MaterialCompiler::run(const Config& config) {
|
||||
|
||||
MaterialBuilder::init();
|
||||
MaterialBuilder builder;
|
||||
// Before attempting an expensive lex, let's find out if we were sent pure JSON.
|
||||
bool parsed;
|
||||
if (isValidJsonStart(buffer.get(), size_t(size))) {
|
||||
parsed = parseMaterialAsJSON(buffer.get(), size_t(size), builder);
|
||||
} else {
|
||||
parsed = parseMaterial(buffer.get(), size_t(size), builder);
|
||||
}
|
||||
|
||||
if (!parsed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (builder.getFeatureLevel() > config.getFeatureLevel()) {
|
||||
std::cerr << "Material feature level (" << +builder.getFeatureLevel() << ") is higher "
|
||||
"than maximum allowed (" << +config.getFeatureLevel() << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (config.getReflectionTarget()) {
|
||||
case Config::Metadata::NONE:
|
||||
break;
|
||||
case Config::Metadata::PARAMETERS:
|
||||
return reflectParameters(builder);
|
||||
}
|
||||
|
||||
// Set the root include directory to the directory containing the material file.
|
||||
DirIncluder includer;
|
||||
includer.setIncludeDirectory(materialFilePath.getParent());
|
||||
|
||||
builder
|
||||
.noSamplerValidation(config.noSamplerValidation())
|
||||
.includeEssl1(config.includeEssl1())
|
||||
.includeCallback(includer)
|
||||
.fileName(materialFilePath.getName().c_str())
|
||||
.platform(config.getPlatform())
|
||||
.targetApi(config.getTargetApi())
|
||||
.optimization(config.getOptimizationLevel())
|
||||
.printShaders(config.printShaders())
|
||||
.saveRawVariants(config.saveRawVariants())
|
||||
.generateDebugInfo(config.isDebug())
|
||||
.variantFilter(config.getVariantFilter() | builder.getVariantFilter());
|
||||
|
||||
for (const auto& define : config.getDefines()) {
|
||||
builder.shaderDefine(define.first.c_str(), define.second.c_str());
|
||||
}
|
||||
|
||||
if (!processMaterialParameters(builder, config)) {
|
||||
std::cerr << "Error while processing material parameters." << std::endl;
|
||||
if (!mParser.parse(builder, config, input, size, buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -432,13 +80,14 @@ bool MaterialCompiler::run(const Config& config) {
|
||||
MaterialBuilder::shutdown();
|
||||
|
||||
if (!package.isValid()) {
|
||||
std::cerr << "Could not compile material " << input->getName() << std::endl;
|
||||
std::cerr << "Could not compile material " << config.getInput()->getName() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return writePackage(package, config);
|
||||
}
|
||||
|
||||
bool MaterialCompiler::checkParameters(const Config& config) {
|
||||
bool MaterialCompiler::checkParameters(const matp::Config& config) {
|
||||
// Check for input file.
|
||||
if (config.getInput() == nullptr) {
|
||||
std::cerr << "Missing input filename." << std::endl;
|
||||
@@ -446,7 +95,7 @@ bool MaterialCompiler::checkParameters(const Config& config) {
|
||||
}
|
||||
|
||||
// If we have reflection we don't need an output file
|
||||
if (config.getReflectionTarget() != Config::Metadata::NONE) {
|
||||
if (config.getReflectionTarget() != matp::Config::Metadata::NONE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -459,111 +108,9 @@ bool MaterialCompiler::checkParameters(const Config& config) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::parseMaterialAsJSON(const char* buffer, size_t size,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
JsonishLexer jlexer;
|
||||
jlexer.lex(buffer, size, 1);
|
||||
|
||||
JsonishParser parser(jlexer.getLexemes());
|
||||
std::unique_ptr<JsonishObject> json = parser.parse();
|
||||
if (json == nullptr) {
|
||||
std::cerr << "Could not parse JSON material file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& entry : json->getEntries()) {
|
||||
const std::string& key = entry.first;
|
||||
if (mConfigProcessorJSON.find(key) == mConfigProcessorJSON.end()) {
|
||||
std::cerr << "Unknown identifier '" << key << "'" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retrieve function member pointer
|
||||
MaterialConfigProcessorJSON const p = mConfigProcessorJSON.at(key);
|
||||
// Call it.
|
||||
bool const ok = (*this.*p)(entry.second, builder);
|
||||
if (!ok) {
|
||||
std::cerr << "Error while processing block with key:'" << key << "'" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::parseMaterial(const char* buffer, size_t size,
|
||||
filamat::MaterialBuilder& builder) const noexcept {
|
||||
|
||||
MaterialLexer materialLexer;
|
||||
materialLexer.lex(buffer, size);
|
||||
auto lexemes = materialLexer.getLexemes();
|
||||
|
||||
// Make sure the lexer did not stumble upon unknown character. This could mean we received
|
||||
// a binary file.
|
||||
for (auto lexeme : lexemes) {
|
||||
if (lexeme.getType() == MaterialType::UNKNOWN) {
|
||||
std::cerr << "Unexpected character at line:" << lexeme.getLine()
|
||||
<< " position:" << lexeme.getLinePosition() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make a first quick pass just to make sure the format was respected (the material format is
|
||||
// a series of IDENTIFIER, BLOCK pairs).
|
||||
if (lexemes.size() < 2) {
|
||||
std::cerr << "Input MUST be an alternation of [identifier, block] pairs." << std::endl;
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < lexemes.size(); i += 2) {
|
||||
auto lexeme = lexemes.at(i);
|
||||
if (lexeme.getType() != MaterialType::IDENTIFIER) {
|
||||
std::cerr << "An identifier was expected at line:" << lexeme.getLine()
|
||||
<< " position:" << lexeme.getLinePosition() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i == lexemes.size() - 1) {
|
||||
std::cerr << "Identifier at line:" << lexeme.getLine()
|
||||
<< " position:" << lexeme.getLinePosition()
|
||||
<< " must be followed by a block." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto nextLexeme = lexemes.at(i + 1);
|
||||
if (nextLexeme.getType() != MaterialType::BLOCK) {
|
||||
std::cerr << "A block was expected at line:" << lexeme.getLine()
|
||||
<< " position:" << lexeme.getLinePosition() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string identifier;
|
||||
for (auto lexeme : lexemes) {
|
||||
if (lexeme.getType() == MaterialType::IDENTIFIER) {
|
||||
identifier = lexeme.getStringValue();
|
||||
if (mConfigProcessor.find(identifier) == mConfigProcessor.end()) {
|
||||
std::cerr << "Unknown identifier '"
|
||||
<< lexeme.getStringValue()
|
||||
<< "' at line:" << lexeme.getLine()
|
||||
<< " position:" << lexeme.getLinePosition() << std::endl;
|
||||
return false;
|
||||
}
|
||||
} else if (lexeme.getType() == MaterialType::BLOCK) {
|
||||
MaterialConfigProcessor const processor = mConfigProcessor.at(identifier);
|
||||
if (!(*this.*processor)(lexeme, builder)) {
|
||||
std::cerr << "Error while processing block with key:'" << identifier << "'"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// this can either be here or material parser
|
||||
bool MaterialCompiler::compileRawShader(const char* glsl, size_t size, bool isDebug,
|
||||
Config::Output* output, const char* ext) const noexcept {
|
||||
matp::Config::Output* output, const char* ext) const noexcept {
|
||||
using namespace glslang;
|
||||
using namespace filament::backend;
|
||||
using SpirvBlob = std::vector<uint32_t>;
|
||||
@@ -627,14 +174,4 @@ bool MaterialCompiler::compileRawShader(const char* glsl, size_t size, bool isDe
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MaterialCompiler::processMaterialParameters(filamat::MaterialBuilder& builder,
|
||||
const Config& config) const {
|
||||
ParametersProcessor parametersProcessor;
|
||||
bool ok = true;
|
||||
for (const auto& param : config.getMaterialParameters()) {
|
||||
ok &= parametersProcessor.process(builder, param.first, param.second);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
} // namespace matc
|
||||
|
||||
@@ -20,70 +20,31 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <filament-matp/Config.h>
|
||||
#include <filament-matp/MaterialParser.h>
|
||||
#include "Compiler.h"
|
||||
#include "MaterialLexeme.h"
|
||||
|
||||
namespace filamat {
|
||||
class MaterialBuilder;
|
||||
}
|
||||
class TestMaterialCompiler;
|
||||
|
||||
namespace matc {
|
||||
|
||||
class JsonishValue;
|
||||
class MaterialCompiler final: public Compiler {
|
||||
public:
|
||||
MaterialCompiler();
|
||||
|
||||
bool run(const Config& config) override;
|
||||
bool run(const matp::Config& config) override;
|
||||
|
||||
bool checkParameters(const Config& config) override;
|
||||
bool checkParameters(const matp::Config& config) override;
|
||||
|
||||
private:
|
||||
friend class ::TestMaterialCompiler;
|
||||
|
||||
bool parseMaterial(const char* buffer, size_t size,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processMaterial(const MaterialLexeme&,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processVertexShader(const MaterialLexeme&,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processFragmentShader(const MaterialLexeme&,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processComputeShader(const MaterialLexeme&,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool ignoreLexeme(const MaterialLexeme&, filamat::MaterialBuilder& builder) const noexcept;
|
||||
matp::MaterialParser mParser;
|
||||
|
||||
bool parseMaterialAsJSON(const char* buffer, size_t size,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processMaterialJSON(const JsonishValue*,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processVertexShaderJSON(const JsonishValue*,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processFragmentShaderJSON(const JsonishValue*,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool processComputeShaderJSON(const JsonishValue*,
|
||||
filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool ignoreLexemeJSON(const JsonishValue*, filamat::MaterialBuilder& builder) const noexcept;
|
||||
bool isValidJsonStart(const char* buffer, size_t size) const noexcept;
|
||||
|
||||
bool compileRawShader(const char* glsl, size_t size, bool isDebug, Config::Output* output,
|
||||
bool compileRawShader(const char* glsl, size_t size, bool isDebug, matp::Config::Output* output,
|
||||
const char* ext) const noexcept;
|
||||
|
||||
bool processMaterialParameters(filamat::MaterialBuilder& builder, const Config& config) const;
|
||||
|
||||
// Member function pointer type, this is used to implement a Command design
|
||||
// pattern.
|
||||
using MaterialConfigProcessor = bool (MaterialCompiler::*)
|
||||
(const MaterialLexeme&, filamat::MaterialBuilder& builder) const;
|
||||
// Map used to store Command pattern function pointers.
|
||||
std::unordered_map<std::string, MaterialConfigProcessor> mConfigProcessor;
|
||||
|
||||
// The same, but for pure JSON syntax
|
||||
using MaterialConfigProcessorJSON = bool (MaterialCompiler::*)
|
||||
(const JsonishValue*, filamat::MaterialBuilder& builder) const;
|
||||
std::unordered_map<std::string, MaterialConfigProcessorJSON> mConfigProcessorJSON;
|
||||
};
|
||||
|
||||
} // namespace matc
|
||||
|
||||
#endif //TNT_MATERIALCOMPILER_H
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 "MockConfig.h"
|
||||
|
||||
bool NullOutput::open() noexcept {
|
||||
return true;
|
||||
}
|
||||
bool NullOutput::write(const uint8_t* data, size_t size) noexcept {
|
||||
return true;
|
||||
}
|
||||
std::ostream& NullOutput::getOutputStream() noexcept {
|
||||
return mNullStream;
|
||||
}
|
||||
bool NullOutput::close() noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
MockInput::MockInput(uint8_t* data, size_t size) : mSize(size) {
|
||||
mData = new uint8_t[size];
|
||||
memcpy(mData, data, size);
|
||||
}
|
||||
|
||||
ssize_t MockInput::open() noexcept {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
std::unique_ptr<const char[]> MockInput::read() noexcept {
|
||||
char* rawBuffer = new char[mSize];
|
||||
memcpy(rawBuffer, mData, mSize);
|
||||
return std::unique_ptr<const char[]>(rawBuffer);
|
||||
}
|
||||
|
||||
bool MockInput::close() noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
MockInput::~MockInput() {
|
||||
delete mData;
|
||||
}
|
||||
|
||||
matc::Config::Output* MockConfig::getOutput() const noexcept {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
matc::Config::Input* MockConfig::getInput() const noexcept {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string MockConfig::toString() const noexcept {
|
||||
return {};
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
|
||||
#ifndef TNT_MOCKCONFIG_H
|
||||
#define TNT_MOCKCONFIG_H
|
||||
|
||||
|
||||
#include <matc/Config.h>
|
||||
|
||||
class NullOutput : public matc::Config::Output {
|
||||
|
||||
public:
|
||||
NullOutput() : mNullStream(&mNull){
|
||||
|
||||
}
|
||||
bool open() noexcept override;
|
||||
bool write(const uint8_t* data, size_t size) noexcept override;
|
||||
std::ostream& getOutputStream() noexcept override;
|
||||
bool close() noexcept override;
|
||||
|
||||
private:
|
||||
class NullBuffer : public std::streambuf {
|
||||
public:
|
||||
int overflow(int c) override { return c; }
|
||||
};
|
||||
NullBuffer mNull;
|
||||
std::ostream mNullStream;
|
||||
};
|
||||
|
||||
class MockInput : public matc::Config::Input {
|
||||
public:
|
||||
MockInput(uint8_t* data, size_t size);
|
||||
~MockInput() override;
|
||||
ssize_t open() noexcept override;
|
||||
std::unique_ptr<const char[]> read() noexcept override;
|
||||
bool close() noexcept override;
|
||||
const char* getName() const noexcept override { return "mock"; };
|
||||
private:
|
||||
uint8_t* mData;
|
||||
size_t mSize;
|
||||
};
|
||||
|
||||
class MockConfig : public matc::Config {
|
||||
public:
|
||||
Output* getOutput() const noexcept override;
|
||||
Input* getInput() const noexcept override;
|
||||
std::string toString() const noexcept override;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
#endif //TNT_MOCKCONFIG_H
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#ifndef TNT_TESTMATERIALCOMPILER_H
|
||||
#define TNT_TESTMATERIALCOMPILER_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <matc/MaterialCompiler.h>
|
||||
|
||||
class TestMaterialCompiler {
|
||||
public:
|
||||
explicit TestMaterialCompiler(const matc::MaterialCompiler& materialCompiler) :
|
||||
mMaterialCompiler(materialCompiler) {}
|
||||
|
||||
bool parseMaterial(const char* buffer, size_t size, filamat::MaterialBuilder& builder)
|
||||
const noexcept{
|
||||
return mMaterialCompiler.parseMaterial(buffer, size, builder);
|
||||
}
|
||||
|
||||
bool parseMaterialAsJSON(const char* buffer, size_t size, filamat::MaterialBuilder& builder)
|
||||
const noexcept{
|
||||
return mMaterialCompiler.parseMaterialAsJSON(buffer, size, builder);
|
||||
}
|
||||
|
||||
private:
|
||||
const matc::MaterialCompiler& mMaterialCompiler;
|
||||
};
|
||||
|
||||
#endif //TNT_TESTMATERIALCOMPILER_H
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.63.0",
|
||||
"version": "1.62.2",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user