Compare commits

..

1 Commits

Author SHA1 Message Date
Matt Hoffman
667da2aabe Create a helper for setting texture uniforms in backend tests.
BUGS=[407799122]
2025-04-14 16:06:03 -05:00
28 changed files with 124 additions and 683 deletions

View File

@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.59.2'
implementation 'com.google.android.filament:filament-android:1.59.1'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.59.2'
pod 'Filament', '~> 1.59.1'
```
## Documentation

View File

@@ -7,9 +7,6 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.59.3
## v1.59.2
- Fix build/compile errors when upgrading to MacOS 15.4

View File

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

View File

@@ -507,10 +507,8 @@ if (APPLE OR LINUX)
test/Arguments.cpp
test/ImageExpectations.cpp
test/Lifetimes.cpp
test/PlatformRunner.cpp
test/Shader.cpp
test/SharedShaders.cpp
test/Skip.cpp
test/test_FeedbackLoops.cpp
test/test_Blit.cpp
test/test_MissingRequiredAttributes.cpp

View File

@@ -55,9 +55,4 @@ public:
} // namespace filament::backend
#if !defined(NDEBUG)
utils::io::ostream& operator<<(utils::io::ostream& out,
const filament::backend::BufferObjectStreamDescriptor& b);
#endif
#endif // TNT_FILAMENT_BACKEND_BUFFEROBJECTSTREAMDESCRIPTOR_H

View File

@@ -15,7 +15,6 @@
*/
#include <backend/BufferDescriptor.h>
#include <backend/BufferObjectStreamDescriptor.h>
#include <backend/DescriptorSetOffsetArray.h>
#include <backend/DriverEnums.h>
#include <backend/PipelineState.h>
@@ -438,10 +437,6 @@ io::ostream& operator<<(io::ostream& out, BufferDescriptor const& b) {
<< ", user=" << b.getUser() << " }";
}
io::ostream& operator<<(io::ostream& out, const BufferObjectStreamDescriptor& b) {
return out << "BufferObjectStreamDescriptor{ streams(" << b.mStreams.size() << ")=... }";
}
io::ostream& operator<<(io::ostream& out, PixelBufferDescriptor const& b) {
BufferDescriptor const& base = static_cast<BufferDescriptor const&>(b);
return out << "PixelBufferDescriptor{ " << base

View File

@@ -228,14 +228,6 @@ WebGPUDriver::WebGPUDriver(WebGPUPlatform& platform, const Platform::DriverConfi
driverConfig.disableHeapHandleTags) {
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
printInstanceDetails(mPlatform.getInstance());
#endif
mAdapter = mPlatform.requestAdapter(nullptr);
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
printAdapterDetails(mAdapter);
#endif
mDevice = mPlatform.requestDevice(mAdapter);
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
printDeviceDetails(mDevice);
#endif
}
@@ -344,9 +336,6 @@ void WebGPUDriver::destroyTimerQuery(Handle<HwTimerQuery> tqh) {
}
void WebGPUDriver::destroyDescriptorSetLayout(Handle<HwDescriptorSetLayout> tqh) {
if (tqh) {
destructHandle<WebGPUDescriptorSetLayout>(tqh);
}
}
void WebGPUDriver::destroyDescriptorSet(Handle<HwDescriptorSet> tqh) {
@@ -421,7 +410,8 @@ Handle<HwRenderTarget> WebGPUDriver::createDefaultRenderTargetS() noexcept {
}
Handle<HwDescriptorSetLayout> WebGPUDriver::createDescriptorSetLayoutS() noexcept {
return allocHandle<WebGPUDescriptorSetLayout>();
return Handle<HwDescriptorSetLayout>(
(Handle<HwDescriptorSetLayout>::HandleId) mNextFakeHandle++);
}
Handle<HwTexture> WebGPUDriver::createTextureExternalImageS() noexcept {
@@ -440,7 +430,14 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
mNativeWindow = nativeWindow;
assert_invariant(!mSwapChain);
wgpu::Surface surface = mPlatform.createSurface(nativeWindow, flags);
mAdapter = mPlatform.requestAdapter(surface);
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
printAdapterDetails(mAdapter);
#endif
mDevice = mPlatform.requestDevice(mAdapter);
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
printDeviceDetails(mDevice);
#endif
mQueue = mDevice.GetQueue();
wgpu::Extent2D surfaceSize = mPlatform.getSurfaceExtent(mNativeWindow);
mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter,
@@ -464,21 +461,13 @@ void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t wi
uint32_t height, uint64_t flags) {}
void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
uint8_t attributeCount, AttributeArray attributes) {
constructHandle<WGPUVertexBufferInfo>(vbih, bufferCount, attributeCount, attributes);
}
uint8_t attributeCount, AttributeArray attributes) {}
void WebGPUDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
Handle<HwVertexBufferInfo> vbih) {
auto* vertexBufferInfo = handleCast<WGPUVertexBufferInfo>(vbih);
constructHandle<WGPUVertexBuffer>(vbh, mDevice, vertexCount,vertexBufferInfo->bufferCount, vbih);
}
Handle<HwVertexBufferInfo> vbih) {}
void WebGPUDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
uint32_t indexCount, BufferUsage usage) {
auto elementSize = (uint8_t)getElementTypeSize(elementType);
constructHandle<WGPUIndexBuffer>(ibh, mDevice, elementSize, indexCount);
}
uint32_t indexCount, BufferUsage usage) {}
void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage) {}
@@ -511,18 +500,7 @@ void WebGPUDriver::importTextureR(Handle<HwTexture> th, intptr_t id, SamplerType
uint32_t depth, TextureUsage usage) {}
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, Handle<HwVertexBuffer> vbh,
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {
assert_invariant(mDevice);
auto* renderPrimitive = handleCast<WGPURenderPrimitive>(rph);
auto* vertexBuffer = handleCast<WGPUVertexBuffer>(vbh);
auto* indexBuffer = handleCast<WGPUIndexBuffer>(ibh);
// auto* vertexBufferInfo = handleCast<WGPUVertexBufferInfo>(vertexBuffer->vbih);
// renderPrimitive->setBuffers(vertexBufferInfo, vertexBuffer, indexBuffer);
renderPrimitive->vertexBuffer = vertexBuffer;
renderPrimitive->indexBuffer = indexBuffer;
renderPrimitive->type = pt;
}
Handle<HwIndexBuffer> ibh, PrimitiveType pt) {}
void WebGPUDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {}
@@ -541,9 +519,7 @@ void WebGPUDriver::createFenceR(Handle<HwFence> fh, int) {}
void WebGPUDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {}
void WebGPUDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
backend::DescriptorSetLayout&& info) {
constructHandle<WebGPUDescriptorSetLayout>(dslh, std::move(info), &mDevice);
}
backend::DescriptorSetLayout&& info) {}
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
Handle<HwDescriptorSetLayout> dslh) {}
@@ -734,7 +710,6 @@ void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
};
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
assert_invariant(mCommandEncoder);
// TODO: Remove this code once WebGPU pipeline is implemented
static float red = 1.0f;
if (red - 0.01 > 0) {
@@ -848,70 +823,6 @@ void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
}
void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
// VulkanCommandBuffer* commands = mCurrentRenderPass.commandBuffer;
// VkCommandBuffer cmdbuffer = commands->buffer();
// auto prim = resource_ptr<VulkanRenderPrimitive>::cast(&mResourceManager, rph);
auto* renderPrimitive = handleCast<WGPURenderPrimitive>(rph);
// commands->acquire(prim);
// This *must* match the VulkanVertexBufferInfo that was bound in bindPipeline(). But we want
// to allow to call this before bindPipeline(), so the validation can only happen in draw()
auto vbi = handleCast<WGPUVertexBufferInfo>(renderPrimitive->vertexBuffer->vbih);
(void) vbi;
// mRenderPassEncoder.SetVertexBuffer(uint32_t slot, Buffer const& buffer = nullptr, uint64_t offset = 0, uint64_t size = kWholeSize);
mRenderPassEncoder.SetIndexBuffer(renderPrimitive->indexBuffer->buffer, renderPrimitive->indexBuffer->indexFormat);
// uint32_t const bufferCount = vbi->getAttributeCount();
// VkDeviceSize const* offsets = vbi->getOffsets();
// VkBuffer const* buffers = prim->vertexBuffer->getVkBuffers();
//
// // Next bind the vertex buffers and index buffer. One potential performance improvement is to
// // avoid rebinding these if they are already bound, but since we do not (yet) support subranges
// // it would be rare for a client to make consecutive draw calls with the same render primitive.
// vkCmdBindVertexBuffers(cmdbuffer, 0, bufferCount, buffers, offsets);
// vkCmdBindIndexBuffer(cmdbuffer, prim->indexBuffer->buffer.getGpuBuffer(), 0,
// prim->indexBuffer->indexType);
// METAL
// if (UTILS_UNLIKELY(mContext->currentRenderPassAbandoned)) {
// return;
// }
// FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder != nullptr)
// << "bindRenderPrimitive() without a valid command encoder.";
//
// // Bind the user vertex buffers.
// MetalBuffer* vertexBuffers[MAX_VERTEX_BUFFER_COUNT] = {};
// size_t vertexBufferOffsets[MAX_VERTEX_BUFFER_COUNT] = {};
// size_t maxBufferIndex = 0;
//
// MetalRenderPrimitive const* const primitive = handle_cast<MetalRenderPrimitive>(rph);
// MetalVertexBufferInfo const* const vbi =
// handle_cast<MetalVertexBufferInfo>(primitive->vertexBuffer->vbih);
//
// mContext->currentRenderPrimitive = rph;
//
// auto vb = primitive->vertexBuffer;
// for (auto m : vbi->bufferMapping) {
// assert_invariant(
// m.bufferArgumentIndex >= USER_VERTEX_BUFFER_BINDING_START &&
// m.bufferArgumentIndex < USER_VERTEX_BUFFER_BINDING_START + MAX_VERTEX_BUFFER_COUNT);
// size_t const vertexBufferIndex = m.bufferArgumentIndex - USER_VERTEX_BUFFER_BINDING_START;
// vertexBuffers[vertexBufferIndex] = vb->buffers[m.sourceBufferIndex];
// maxBufferIndex = std::max(maxBufferIndex, vertexBufferIndex);
// }
//
// const auto bufferCount = maxBufferIndex + 1;
// MetalBuffer::bindBuffers(getPendingCommandBuffer(mContext), mContext->currentRenderPassEncoder,
// USER_VERTEX_BUFFER_BINDING_START, MetalBuffer::Stage::VERTEX, vertexBuffers,
// vertexBufferOffsets, bufferCount);
//
// // Bind the zero buffer, used for missing vertex attributes.
// static const char bytes[16] = { 0 };
// [mContext->currentRenderPassEncoder setVertexBytes:bytes
// length:16
// atIndex:ZERO_VERTEX_BUFFER_BINDING];
}
void WebGPUDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {

View File

@@ -112,7 +112,7 @@ private:
template<typename D, typename B>
void destructHandle(Handle<B>& handle) noexcept {
auto* p = mHandleAllocator.handle_cast<D*>(handle);
mHandleAllocator.deallocate(handle, p);
return mHandleAllocator.deallocate(handle, p);
}
};

View File

@@ -27,126 +27,18 @@ wgpu::Buffer createIndexBuffer(wgpu::Device const& device, uint8_t elementSize,
.mappedAtCreation = false };
return device.CreateBuffer(&descriptor);
}
wgpu::VertexFormat getVertexFormat(filament::backend::ElementType type, bool normalized, bool integer) {
using ElementType = filament::backend::ElementType;
// using VertexFormat = wgpu::VertexFormat;
if (normalized) {
switch (type) {
// Single Component Types
case ElementType::BYTE: return wgpu::VertexFormat::Snorm8;
case ElementType::UBYTE: return wgpu::VertexFormat::Unorm8;
case ElementType::SHORT: return wgpu::VertexFormat::Snorm16;
case ElementType::USHORT: return wgpu::VertexFormat::Unorm16;
// Two Component Types
case ElementType::BYTE2: return wgpu::VertexFormat::Snorm8x2;
case ElementType::UBYTE2: return wgpu::VertexFormat::Unorm8x2;
case ElementType::SHORT2: return wgpu::VertexFormat::Snorm16x2;
case ElementType::USHORT2: return wgpu::VertexFormat::Unorm16x2;
// Three Component Types
// There is no vertex format type for 3 byte data in webgpu. Use
// 4 byte signed normalized type and ignore the last byte.
// TODO: This is to be verified.
case ElementType::BYTE3: return wgpu::VertexFormat::Snorm8x4; // NOT MINSPEC
case ElementType::UBYTE3: return wgpu::VertexFormat::Unorm8x4; // NOT MINSPEC
case ElementType::SHORT3: return wgpu::VertexFormat::Snorm16x4; // NOT MINSPEC
case ElementType::USHORT3: return wgpu::VertexFormat::Unorm16x4; // NOT MINSPEC
// Four Component Types
case ElementType::BYTE4: return wgpu::VertexFormat::Snorm8x4;
case ElementType::UBYTE4: return wgpu::VertexFormat::Unorm8x4;
case ElementType::SHORT4: return wgpu::VertexFormat::Snorm16x4;
case ElementType::USHORT4: return wgpu::VertexFormat::Unorm8x4;
default:
FILAMENT_CHECK_POSTCONDITION(false) << "Normalized format does not exist.";
return wgpu::VertexFormat::Float32x3;
}
}
switch (type) {
// Single Component Types
// There is no direct alternative for SSCALED in webgpu. Convert them to Float32 directly.
// This will result in increased memory on the cpu side.
// TODO: Is Float16 acceptable instead with some potential accuracy errors?
case ElementType::BYTE: return integer ? wgpu::VertexFormat::Sint8 : wgpu::VertexFormat::Float32;
case ElementType::UBYTE: return integer ? wgpu::VertexFormat::Uint8 : wgpu::VertexFormat::Float32;
case ElementType::SHORT: return integer ? wgpu::VertexFormat::Sint16 : wgpu::VertexFormat::Float32;
case ElementType::USHORT: return integer ? wgpu::VertexFormat::Uint16 : wgpu::VertexFormat::Float32;
case ElementType::HALF: return wgpu::VertexFormat::Float16;
case ElementType::INT: return wgpu::VertexFormat::Sint32;
case ElementType::UINT: return wgpu::VertexFormat::Uint32;
case ElementType::FLOAT: return wgpu::VertexFormat::Float32;
// Two Component Types
case ElementType::BYTE2: return integer ? wgpu::VertexFormat::Sint8x2 : wgpu::VertexFormat::Float32x2;
case ElementType::UBYTE2: return integer ? wgpu::VertexFormat::Uint8x2 : wgpu::VertexFormat::Float32x2;
case ElementType::SHORT2: return integer ? wgpu::VertexFormat::Sint16x2 : wgpu::VertexFormat::Float32x2;
case ElementType::USHORT2: return integer ? wgpu::VertexFormat::Uint16x2 : wgpu::VertexFormat::Float32x2;
case ElementType::HALF2: return wgpu::VertexFormat::Float16x2;
case ElementType::FLOAT2: return wgpu::VertexFormat::Float32x2;
// Three Component Types
case ElementType::BYTE3: return wgpu::VertexFormat::Sint8x4; // NOT MINSPEC
case ElementType::UBYTE3: return wgpu::VertexFormat::Uint8x4; // NOT MINSPEC
case ElementType::SHORT3: return wgpu::VertexFormat::Sint16x4; // NOT MINSPEC
case ElementType::USHORT3: return wgpu::VertexFormat::Uint16x4; // NOT MINSPEC
case ElementType::HALF3: return wgpu::VertexFormat::Float16x4; // NOT MINSPEC
case ElementType::FLOAT3: return wgpu::VertexFormat::Float32x3;
// Four Component Types
case ElementType::BYTE4: return integer ? wgpu::VertexFormat::Sint8x4 : wgpu::VertexFormat::Float32x4;
case ElementType::UBYTE4: return integer ? wgpu::VertexFormat::Uint8x4 : wgpu::VertexFormat::Float32x4;
case ElementType::SHORT4: return integer ? wgpu::VertexFormat::Sint16x4 : wgpu::VertexFormat::Float32x4;
case ElementType::USHORT4: return integer ? wgpu::VertexFormat::Uint16x4 : wgpu::VertexFormat::Float32x4;
case ElementType::HALF4: return wgpu::VertexFormat::Float16x4;
case ElementType::FLOAT4: return wgpu::VertexFormat::Float32x4;
}
FILAMENT_CHECK_POSTCONDITION(false) << "Vertex format should always be defined.";
return wgpu::VertexFormat::Float32x3;
}
} // namespace
namespace filament::backend {
WGPUVertexBufferInfo::WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount,
AttributeArray const& attributes)
: HwVertexBufferInfo(bufferCount, attributeCount),
mVertexBufferLayout(bufferCount),
mAttributes(bufferCount) {
for (uint32_t attribIndex = 0; attribIndex < attributes.size(); attribIndex++) {
Attribute attrib = attributes[attribIndex];
// Ignore the attributes which are not bind to vertex buffers.
if (attrib.buffer == Attribute::BUFFER_UNUSED) {
continue;
}
assert_invariant(attrib.buffer < bufferCount);
bool const isInteger = attrib.flags & Attribute::FLAG_INTEGER_TARGET;
bool const isNormalized = attrib.flags & Attribute::FLAG_NORMALIZED;
wgpu::VertexFormat vertexFormat = getVertexFormat(attrib.type, isNormalized, isInteger);
mAttributes[attrib.buffer].push_back({
.format = vertexFormat,
.offset = attrib.offset,
.shaderLocation = attribIndex,
});
mVertexBufferLayout[attrib.buffer] = {
.arrayStride = attrib.stride,
};
}
for (uint32_t bufferIndex = 0; bufferIndex < bufferCount; bufferIndex++) {
mVertexBufferLayout[bufferIndex] = {
.attributeCount = mAttributes[bufferIndex].size(),
.attributes = mAttributes[bufferIndex].data(),
};
}
}
WGPUIndexBuffer::WGPUIndexBuffer(wgpu::Device const& device, uint8_t elementSize,
uint32_t indexCount)
: buffer(createIndexBuffer(device, elementSize, indexCount)),
indexFormat(elementSize == 2 ? wgpu::IndexFormat::Uint16 : wgpu::IndexFormat::Uint32) {}
: buffer(createIndexBuffer(device, elementSize, indexCount)) {}
WGPUVertexBuffer::WGPUVertexBuffer(wgpu::Device const &device, uint32_t vextexCount, uint32_t bufferCount,
Handle<HwVertexBufferInfo> vbih)
Handle<WGPUVertexBufferInfo> vbih)
: HwVertexBuffer(vextexCount),
vbih(vbih),
buffers(bufferCount) {
@@ -168,100 +60,4 @@ void WGPUVertexBuffer::setBuffer(WGPUBufferObject* bufferObject, uint32_t index)
WGPUBufferObject::WGPUBufferObject(BufferObjectBinding bindingType, uint32_t byteCount)
: HwBufferObject(byteCount),
bufferObjectBinding(bindingType) {}
wgpu::ShaderStage WebGPUDescriptorSetLayout::filamentStageToWGPUStage(ShaderStageFlags fFlags) {
wgpu::ShaderStage retStages = wgpu::ShaderStage::None;
if (any(ShaderStageFlags::VERTEX & fFlags)) {
retStages |= wgpu::ShaderStage::Vertex;
}
if (any(ShaderStageFlags::FRAGMENT & fFlags)) {
retStages |= wgpu::ShaderStage::Fragment;
}
if (any(ShaderStageFlags::COMPUTE & fFlags)) {
retStages |= wgpu::ShaderStage::Compute;
}
return retStages;
}
WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const& layout,
wgpu::Device const* device) {
assert_invariant(device->Get());
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
// debugging. For now, hack an incrementing value.
static int layoutNum = 0;
uint samplerCount =
std::count_if(layout.bindings.begin(), layout.bindings.end(), [](auto& fEntry) {
return fEntry.type == DescriptorType::SAMPLER ||
fEntry.type == DescriptorType::SAMPLER_EXTERNAL;
});
std::vector<wgpu::BindGroupLayoutEntry> wEntries;
wEntries.reserve(layout.bindings.size() + samplerCount);
for (auto fEntry: layout.bindings) {
auto& wEntry = wEntries.emplace_back();
wEntry.visibility = filamentStageToWGPUStage(fEntry.stageFlags);
wEntry.binding = fEntry.binding * 2;
switch (fEntry.type) {
// TODO Metal treats these the same. Is this fine?
case DescriptorType::SAMPLER_EXTERNAL:
case DescriptorType::SAMPLER: {
// Sampler binding is 2n+1 due to split.
auto& samplerEntry = wEntries.emplace_back();
samplerEntry.binding = fEntry.binding * 2 + 1;
samplerEntry.visibility = wEntry.visibility;
// We are simply hoping that undefined and defaults suffices here.
samplerEntry.sampler.type = wgpu::SamplerBindingType::Undefined;
wEntry.texture.sampleType = wgpu::TextureSampleType::Undefined;
break;
}
case DescriptorType::UNIFORM_BUFFER: {
wEntry.buffer.hasDynamicOffset =
any(fEntry.flags & DescriptorFlags::DYNAMIC_OFFSET);
wEntry.buffer.type = wgpu::BufferBindingType::Uniform;
// TODO: Ideally we fill minBindingSize
break;
}
case DescriptorType::INPUT_ATTACHMENT: {
// TODO: support INPUT_ATTACHMENT. Metal does not currently.
PANIC_POSTCONDITION("Input Attachment is not supported");
break;
}
case DescriptorType::SHADER_STORAGE_BUFFER: {
// TODO: Vulkan does not support this, can we?
PANIC_POSTCONDITION("Shader storage is not supported");
break;
}
}
// Currently flags are only used to specify dynamic offset.
// UNUSED
// fEntry.count
}
wgpu::BindGroupLayoutDescriptor layoutDescriptor{
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
// debugging. For now, hack an incrementing value.
.label{ "layout_" + std::to_string(++layoutNum) },
.entryCount = wEntries.size(),
.entries = wEntries.data()
};
// TODO Do we need to defer this until we have more info on textures and samplers??
mLayout = device->CreateBindGroupLayout(&layoutDescriptor);
}
WebGPUDescriptorSetLayout::~WebGPUDescriptorSetLayout() {}
void WGPURenderPrimitive::setBuffers(WGPUVertexBufferInfo const* const vbi,
WGPUVertexBuffer* vertexBuffer, WGPUIndexBuffer* indexBuffer) {
}
}// namespace filament::backend

View File

@@ -24,7 +24,6 @@
#include <backend/Handle.h>
#include <utils/FixedCapacityVector.h>
// #include <utils/StructureOfArrays.h>
#include <webgpu/webgpu_cpp.h>
@@ -33,40 +32,23 @@
namespace filament::backend {
struct WGPUBufferObject;
// VertexBufferInfo contains layout info for Vertex Buffer based on WebGPU structs. In WebGPU each
// VertexBufferLayout is associated with a single vertex buffer. So number of mVertexBufferLayout
// is equal to bufferCount. Each VertexBufferLayout can contain multiple VertexAttribute. Bind index
// of vertex buffer is implicitly calculated by the position of VertexBufferLayout in an array.
// TODO: Currently WGPUVertexBufferInfo is not used by WebGPU for useful task.
// Update the struct when used by WebGPU driver.
struct WGPUVertexBufferInfo : public HwVertexBufferInfo {
WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount,
AttributeArray const& attributes);
inline wgpu::VertexBufferLayout const* getVertexBufferLayout() const {
return mVertexBufferLayout.data();
}
inline uint32_t getVertexBufferLayoutSize() const {
return mVertexBufferLayout.size();
}
inline wgpu::VertexAttribute const* getVertexAttributeForIndex(uint32_t index) const {
return mAttributes[index].data();
}
inline uint32_t getVertexAttributeSize(uint32_t index) const {
return mAttributes[index].size();
}
private:
std::vector<wgpu::VertexBufferLayout> mVertexBufferLayout;
std::vector<std::vector<wgpu::VertexAttribute>> mAttributes;
AttributeArray const& attributes)
: HwVertexBufferInfo(bufferCount, attributeCount),
attributes(attributes) {}
AttributeArray attributes;
};
struct WGPUVertexBuffer : public HwVertexBuffer {
WGPUVertexBuffer(wgpu::Device const &device, uint32_t vextexCount, uint32_t bufferCount,
Handle<HwVertexBufferInfo> vbih);
Handle<WGPUVertexBufferInfo> vbih);
void setBuffer(WGPUBufferObject *bufferObject, uint32_t index);
Handle<HwVertexBufferInfo> vbih;
Handle<WGPUVertexBufferInfo> vbih;
utils::FixedCapacityVector<wgpu::Buffer> buffers;
};
@@ -75,10 +57,9 @@ struct WGPUIndexBuffer : public HwIndexBuffer {
uint32_t indexCount);
wgpu::Buffer buffer;
wgpu::IndexFormat indexFormat;
};
// TODO: Currently WGPUBufferObject is not used by WebGPU for useful task.
// TODO: Currently WGPUVertexBufferInfo is not used by WebGPU for useful task.
// Update the struct when used by WebGPU driver.
struct WGPUBufferObject : HwBufferObject {
WGPUBufferObject(BufferObjectBinding bindingType, uint32_t byteCount);
@@ -87,19 +68,6 @@ struct WGPUBufferObject : HwBufferObject {
const BufferObjectBinding bufferObjectBinding;
};
class WebGPUDescriptorSetLayout : public HwDescriptorSetLayout {
public:
WebGPUDescriptorSetLayout(DescriptorSetLayout const& layout, wgpu::Device const* device);
~WebGPUDescriptorSetLayout();
private:
// TODO: If this is useful elsewhere, remove it from this class
// Convert Filament Shader Stage Flags bitmask to webgpu equivilant
static wgpu::ShaderStage filamentStageToWGPUStage(ShaderStageFlags fFlags);
wgpu::BindGroupLayout mLayout;
};
// TODO: Currently WGPUTexture is not used by WebGPU for useful task.
// Update the struct when used by WebGPU driver.
struct WGPUTexture : public HwTexture {

View File

@@ -43,12 +43,10 @@ using namespace image;
namespace test {
Backend BackendTest::sBackend = Backend::NOOP;
OperatingSystem BackendTest::sOperatingSystem = OperatingSystem::OTHER;
bool BackendTest::sIsMobilePlatform = false;
void BackendTest::init(Backend backend, OperatingSystem operatingSystem, bool isMobilePlatform) {
void BackendTest::init(Backend backend, bool isMobilePlatform) {
sBackend = backend;
sOperatingSystem = operatingSystem;
sIsMobilePlatform = isMobilePlatform;
}
@@ -201,18 +199,6 @@ void BackendTest::readPixelsAndAssertHash(const char* testName, size_t width, si
getDriverApi().readPixels(rt, 0, 0, width, height, std::move(pbd));
}
bool BackendTest::matchesEnvironment(Backend backend) {
return sBackend == backend;
}
bool BackendTest::matchesEnvironment(OperatingSystem operatingSystem) {
return sOperatingSystem == operatingSystem;
}
bool BackendTest::matchesEnvironment(OperatingSystem operatingSystem, Backend backend) {
return matchesEnvironment(operatingSystem) && matchesEnvironment(backend);
}
class Environment : public ::testing::Environment {
public:
virtual void SetUp() override {
@@ -224,8 +210,8 @@ public:
}
};
void initTests(Backend backend, OperatingSystem operatingSystem, bool isMobile, int& argc, char* argv[]) {
BackendTest::init(backend, operatingSystem, isMobile);
void initTests(Backend backend, bool isMobile, int& argc, char* argv[]) {
BackendTest::init(backend, isMobile);
::testing::InitGoogleTest(&argc, argv);
::testing::AddGlobalTestEnvironment(new Environment);
}

View File

@@ -31,10 +31,9 @@ namespace test {
class BackendTest : public ::testing::Test {
public:
static void init(Backend backend, OperatingSystem operatingSystem, bool isMobilePlatform);
static void init(Backend backend, bool isMobilePlatform);
static Backend sBackend;
static OperatingSystem sOperatingSystem;
static bool sIsMobilePlatform;
protected:
@@ -72,10 +71,6 @@ protected:
filament::backend::DriverApi& getDriverApi() { return *commandStream; }
filament::backend::Driver& getDriver() { return *driver; }
static bool matchesEnvironment(Backend backend);
static bool matchesEnvironment(OperatingSystem operatingSystem);
static bool matchesEnvironment(OperatingSystem operatingSystem, Backend backend);
private:
filament::backend::Driver* driver = nullptr;

View File

@@ -1,60 +0,0 @@
/*
* Copyright (C) 2019 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 "PlatformRunner.h"
namespace utils {
template<>
CString to_string<test::Backend>(test::Backend backend) noexcept {
switch (backend) {
case test::Backend::OPENGL: {
return "OpenGL";
}
case test::Backend::VULKAN: {
return "Vulkan";
}
case test::Backend::METAL: {
return "Metal";
}
case test::Backend::WEBGPU: {
return "WebGPU";
}
case test::Backend::NOOP:
default: {
return "No-op";
}
}
}
template<>
CString to_string(test::OperatingSystem os) noexcept {
switch (os) {
case test::OperatingSystem::LINUX: {
return "Linux";
}
case test::OperatingSystem::APPLE: {
return "Apple";
}
case test::OperatingSystem::OTHER:
default: {
return "Other";
}
}
}
} // namespace utils

View File

@@ -19,7 +19,6 @@
#include <stdint.h>
#include <stddef.h>
#include "utils/CString.h"
namespace test {
@@ -35,15 +34,6 @@ enum class Backend : uint8_t {
NOOP = 5,
};
enum class OperatingSystem: uint8_t {
OTHER = 1,
// Also represents android phones.
LINUX = 2,
// Also represents iOS phones.
APPLE = 3,
// TODO: When tests support windows add it here.
};
struct NativeView {
void* ptr = nullptr;
size_t width = 0, height = 0;
@@ -61,10 +51,9 @@ NativeView getNativeView();
* No tests will be run yet.
*
* @param backend The backend to run the tests on.
* @param operatingSystem The operating system the tests are being run on.
* @param isMobile True if the platform is a mobile platform (iOS or Android).
*/
void initTests(Backend backend, OperatingSystem operatingSystem, bool isMobile, int& argc, char* argv[]);
void initTests(Backend backend, bool isMobile, int& argc, char* argv[]);
/**
* Test runners should call runTests when they are ready for tests to be run.
@@ -79,6 +68,6 @@ int runTests();
*/
Backend parseArgumentsForBackend(int argc, char* argv[]);
} // namespace test
}
#endif

View File

@@ -23,6 +23,14 @@ namespace test {
using namespace filament::backend;
filament::backend::descriptor_binding_t TextureBindingConfig::getBinding() const {
return binding.value_or(0);
}
filament::backend::SamplerParams TextureBindingConfig::getParams() const {
return samplerParams.value_or(SamplerParams{});
}
Shader::Shader(DriverApi& api, Cleanup& cleanup, ShaderConfig config) : mCleanup(cleanup) {
utils::FixedCapacityVector<DescriptorSetLayoutBinding> kLayouts(config.uniforms.size());
for (unsigned char i = 0; i < config.uniforms.size(); ++i) {
@@ -57,6 +65,19 @@ Shader::Shader(DriverApi& api, Cleanup& cleanup, ShaderConfig config) : mCleanup
mDescriptorSetLayout = cleanup.add(
api.createDescriptorSetLayout(DescriptorSetLayout{ kLayouts }));
mDefaultDescriptorSet = createDescriptorSet(api);
}
void Shader::updateTextureUniform(filament::backend::DriverApi& api,
TextureBindingConfig config) const {
DescriptorSetHandle descriptorSet = config.descriptorSet.value_or(mDefaultDescriptorSet);
api.updateDescriptorSetTexture(descriptorSet, config.getBinding(), config.textureHandle,
config.getParams());
if (config.alsoBindToSet.has_value()) {
api.bindDescriptorSet(descriptorSet, *config.alsoBindToSet, {});
}
}
filament::backend::DescriptorSetHandle Shader::createDescriptorSet(DriverApi& api) const {

View File

@@ -61,6 +61,18 @@ struct UniformBindingConfig {
ResolvedUniformBindingConfig resolve();
};
struct TextureBindingConfig {
filament::backend::TextureHandle textureHandle;
std::optional<filament::backend::DescriptorSetHandle> descriptorSet;
std::optional<filament::backend::descriptor_binding_t> binding;
std::optional<filament::backend::SamplerParams> samplerParams;
// If present then the call to update the texture will also bind the descriptor set.
std::optional<filament::backend::descriptor_set_t> alsoBindToSet;
filament::backend::descriptor_binding_t getBinding() const;
filament::backend::SamplerParams getParams() const;
};
class Shader {
public:
// All graphics resources have their lifetime controlled by the Cleanup and not this object.
@@ -86,17 +98,20 @@ public:
void bindUniform(filament::backend::DriverApi& api,
filament::backend::Handle<filament::backend::HwBufferObject> hwBuffer,
UniformBindingConfig config) const;
filament::backend::ProgramHandle getProgram() const;
filament::backend::DescriptorSetLayoutHandle getDescriptorSetLayout() const;
void updateTextureUniform(filament::backend::DriverApi& api, TextureBindingConfig config) const;
filament::backend::DescriptorSetHandle createDescriptorSet(
filament::backend::DriverApi& api) const;
filament::backend::ProgramHandle getProgram() const;
filament::backend::DescriptorSetLayoutHandle getDescriptorSetLayout() const;
protected:
Cleanup& mCleanup;
filament::backend::ProgramHandle mProgram;
filament::backend::DescriptorSetLayoutHandle mDescriptorSetLayout;
// Used whenever the caller doesn't provide a descriptor set.
filament::backend::DescriptorSetHandle mDefaultDescriptorSet;
};
template<typename UniformType>
@@ -133,12 +148,8 @@ void Shader::bindUniform(filament::backend::DriverApi& api,
UniformBindingConfig config) const {
auto resolvedConfig = config.resolve<UniformType>();
filament::backend::DescriptorSetHandle descriptorSet;
if (resolvedConfig.descriptorSet.has_value()) {
descriptorSet = *resolvedConfig.descriptorSet;
} else {
descriptorSet = createDescriptorSet(api);
}
filament::backend::DescriptorSetHandle descriptorSet =
resolvedConfig.descriptorSet.value_or(mDefaultDescriptorSet);
api.updateDescriptorSetBuffer(descriptorSet, resolvedConfig.binding, hwBuffer, 0,
resolvedConfig.bufferSize);

View File

@@ -1,96 +0,0 @@
/*
* 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 "Skip.h"
#include <sstream>
namespace test {
SkipEnvironment::SkipEnvironment(test::Backend backend) : backend(backend) {}
SkipEnvironment::SkipEnvironment(test::OperatingSystem os) : os(os) {}
SkipEnvironment::SkipEnvironment(test::OperatingSystem os, test::Backend backend)
: backend(backend),
os(os) {}
bool SkipEnvironment::matches() {
bool backendMatches = !backend.has_value() || *backend == BackendTest::sBackend;
bool osMatches = !os.has_value() || *os == BackendTest::sOperatingSystem;
bool isMobileMatches = !isMobile.has_value() || *isMobile == BackendTest::sIsMobilePlatform;
return backendMatches && osMatches && isMobileMatches;
}
std::string SkipEnvironment::describe() {
std::stringstream result;
if (matches()) {
result << "environment matches because " << describe_actual_environment() << ".";
} else {
result << "environment does not match because " << describe_requirements() << " but "
<< describe_actual_environment() << ".";
}
return result.str();
}
std::string SkipEnvironment::describe_actual_environment() {
bool resultWritten = false;
std::stringstream reality;
if (backend.has_value()) {
reality << "backend was " << utils::to_string(BackendTest::sBackend).c_str();
resultWritten = true;
}
if (os.has_value()) {
if (resultWritten) {
reality << ", and ";
}
reality << "operating system was "
<< utils::to_string(BackendTest::sOperatingSystem).c_str();
resultWritten = true;
}
if (isMobile.has_value()) {
if (resultWritten) {
reality << ", and ";
}
reality << "device " << (BackendTest::sIsMobilePlatform ? "was" : "was not") << " mobile";
resultWritten = true;
}
return reality.str();
}
std::string SkipEnvironment::describe_requirements() {
bool resultWritten = false;
std::stringstream requirement;
if (backend.has_value()) {
requirement << "backend needs to be " << utils::to_string(*backend).c_str();
resultWritten = true;
}
if (os.has_value()) {
if (resultWritten) {
requirement << ", and ";
}
requirement << "operating system needs to be " << utils::to_string(*os).c_str();
resultWritten = true;
}
if (isMobile.has_value() && BackendTest::sIsMobilePlatform != isMobile) {
if (resultWritten) {
requirement << ", and ";
}
requirement << "device needs to " << (*isMobile ? "be" : "not be") << " mobile";
resultWritten = true;
}
return requirement.str();
}
} // namespace test

View File

@@ -1,55 +0,0 @@
/*
* 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_SKIP_H
#define TNT_SKIP_H
#include <gtest/gtest.h>
#include "BackendTest.h"
// skipEnvironment must be a test::SkipEnvironment
#define SKIP_IF(skipEnvironment) \
do { \
SkipEnvironment skip(skipEnvironment); \
if (skip.matches()) { \
GTEST_SKIP() << "Skipping test as the " << skip.describe(); \
} \
} while (false)
namespace test {
struct SkipEnvironment {
SkipEnvironment(const SkipEnvironment&) = default;
explicit SkipEnvironment(test::Backend backend);
explicit SkipEnvironment(test::OperatingSystem os);
SkipEnvironment(test::OperatingSystem os, test::Backend backend);
std::optional<test::Backend> backend;
std::optional<test::OperatingSystem> os;
std::optional<bool> isMobile;
bool matches();
// Describes the current state of either matching or mismatching.
std::string describe();
// Describe all the non-null requirements.
std::string describe_requirements();
// Describes the environment's status for all the attributes that are non-null.
std::string describe_actual_environment();
};
} // namespace test
#endif// TNT_SKIP_H

View File

@@ -51,6 +51,6 @@ int main(int argc, char* argv[]) {
return 1;
}
test::initTests(backend, test::OperatingSystem::LINUX, false, argc, argv);
test::initTests(backend, false, argc, argv);
return test::runTests();
}

View File

@@ -98,7 +98,7 @@ test::NativeView getNativeView() {
int main(int argc, char* argv[]) {
auto backend = test::parseArgumentsForBackend(argc, argv);
test::initTests(backend, test::OperatingSystem::APPLE, false, argc, argv);
test::initTests(backend, false, argc, argv);
AppDelegate* delegate = [AppDelegate new];
delegate.backend = backend;
NSApplication* app = [NSApplication sharedApplication];

View File

@@ -17,7 +17,6 @@
#include "BackendTest.h"
#include "Lifetimes.h"
#include "Skip.h"
using namespace filament;
using namespace filament::backend;
@@ -25,8 +24,6 @@ using namespace filament::backend;
namespace test {
TEST_F(BackendTest, FrameScheduledCallback) {
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL));
auto& api = getDriverApi();
Cleanup cleanup(api);
@@ -84,8 +81,6 @@ TEST_F(BackendTest, FrameScheduledCallback) {
}
TEST_F(BackendTest, FrameCompletedCallback) {
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL));
auto& api = getDriverApi();
Cleanup cleanup(api);

View File

@@ -198,12 +198,14 @@ TEST_F(BackendTest, FeedbackLoops) {
params.viewport.width = kTexWidth >> targetLevel;
params.viewport.height = kTexHeight >> targetLevel;
// Each pass needs its own descriptor set.
auto descriptorSet = shader.createDescriptorSet(api);
auto textureView = passCleanup.add(api.createTextureView(texture, sourceLevel, 1));
api.updateDescriptorSetTexture(descriptorSet, 0, textureView, {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST
});
shader.updateTextureUniform(api,
TextureBindingConfig{ .textureHandle = textureView,
.descriptorSet = descriptorSet,
.samplerParams = SamplerParams{ .filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST } });
UniformBindingConfig uniformBinding{
.binding = 1,

View File

@@ -329,12 +329,14 @@ TEST_F(LoadImageTest, UpdateImage2D) {
checkerboardPixelBuffer(t.pixelFormat, t.pixelType, 512, t.bufferPadding));
}
// Each loop needs its own descriptor set.
DescriptorSetHandle descriptorSet = shader.createDescriptorSet(api);
api.updateDescriptorSetTexture(descriptorSet, 0, texture, {
.filterMag = SamplerMagFilter::NEAREST,
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
api.bindDescriptorSet(descriptorSet, 1, {});
shader.updateTextureUniform(api,
TextureBindingConfig{ .textureHandle = texture,
.descriptorSet = descriptorSet,
.samplerParams = SamplerParams{ .filterMag = SamplerMagFilter::NEAREST,
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST },
.alsoBindToSet = 1 });
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
defaultRenderTarget, swapChain, shader.getProgram());
@@ -405,13 +407,11 @@ TEST_F(LoadImageTest, UpdateImageSRGB) {
api.beginFrame(0, 0, 0);
// Update samplers.
DescriptorSetHandle descriptorSet = shader.createDescriptorSet(api);
api.updateDescriptorSetTexture(descriptorSet, 0, texture, {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST
});
api.bindDescriptorSet(descriptorSet, 1, {});
shader.updateTextureUniform(api,
TextureBindingConfig{ .textureHandle = texture,
.samplerParams = SamplerParams{ .filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST },
.alsoBindToSet = 1 });
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
defaultRenderTarget, swapChain, shader.getProgram());
@@ -467,13 +467,11 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
api.beginFrame(0, 0, 0);
// Update samplers.
DescriptorSetHandle descriptorSet = shader.createDescriptorSet(api);
api.updateDescriptorSetTexture(descriptorSet, 0, texture, {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST
});
api.bindDescriptorSet(descriptorSet, 1, {});
shader.updateTextureUniform(api,
TextureBindingConfig{ .textureHandle = texture,
.samplerParams = SamplerParams{ .filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST },
.alsoBindToSet = 1 });
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
defaultRenderTarget, swapChain, shader.getProgram());
@@ -541,13 +539,11 @@ TEST_F(LoadImageTest, UpdateImage3D) {
api.beginFrame(0, 0, 0);
// Update samplers.
DescriptorSetHandle descriptorSet = shader.createDescriptorSet(api);
api.updateDescriptorSetTexture(descriptorSet, 0, texture, {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST
});
api.bindDescriptorSet(descriptorSet, 1, {});
shader.updateTextureUniform(api,
TextureBindingConfig{ .textureHandle = texture,
.samplerParams = SamplerParams{ .filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_NEAREST },
.alsoBindToSet = 1 });
renderTriangle({{ DescriptorSetLayoutHandle{}, shader.getDescriptorSetLayout() }},
defaultRenderTarget, swapChain, shader.getProgram());

View File

@@ -171,11 +171,12 @@ TEST_F(BackendTest, TextureViewLod) {
state.rasterState.culling = CullingMode::NONE;
DescriptorSetHandle descriptorSet13 = texturedShader.createDescriptorSet(api);
api.updateDescriptorSetTexture(descriptorSet13, 0, texture13, {
.filterMag = SamplerMagFilter::NEAREST,
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
api.bindDescriptorSet(descriptorSet13, 0, {});
texturedShader.updateTextureUniform(api,
TextureBindingConfig{ .textureHandle = texture13,
.descriptorSet = descriptorSet13,
.samplerParams = SamplerParams{ .filterMag = SamplerMagFilter::NEAREST,
.filterMin = SamplerMinFilter::NEAREST },
.alsoBindToSet = 0 });
// Render a triangle to the screen, sampling from mip level 1.
// Because the min level is 1, the result color should be the white triangle drawn in the
@@ -189,11 +190,12 @@ TEST_F(BackendTest, TextureViewLod) {
auto texture22 = cleanup.add(api.createTextureView(texture, 2, 2));
DescriptorSetHandle descriptorSet22 = texturedShader.createDescriptorSet(api);
api.updateDescriptorSetTexture(descriptorSet22, 0, texture22, {
.filterMag = SamplerMagFilter::NEAREST,
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
api.bindDescriptorSet(descriptorSet22, 0, {});
texturedShader.updateTextureUniform(api,
TextureBindingConfig{ .textureHandle = texture22,
.descriptorSet = descriptorSet22,
.samplerParams = SamplerParams{ .filterMag = SamplerMagFilter::NEAREST,
.filterMin = SamplerMinFilter::NEAREST },
.alsoBindToSet = 0 });
// Render a second, smaller, triangle, again sampling from mip level 1.
// This triangle should be yellow striped.

View File

@@ -18,7 +18,6 @@
#include "Lifetimes.h"
#include "ShaderGenerator.h"
#include "Skip.h"
#include "TrianglePrimitive.h"
#include <utils/Hash.h>
@@ -79,8 +78,6 @@ void main() {
})";
TEST_F(BackendTest, PushConstants) {
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL));
auto& api = getDriverApi();
api.startCapture(0);

View File

@@ -84,14 +84,12 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
state.rasterState.depthFunc = RasterState::DepthFunc::A;
state.rasterState.culling = CullingMode::NONE;
DescriptorSetHandle descriptorSet = shader.createDescriptorSet(api);
api.startCapture(0);
api.makeCurrent(swapChain, swapChain);
api.beginFrame(0, 0, 0);
api.updateDescriptorSetTexture(descriptorSet, 0, texture, {});
api.bindDescriptorSet(descriptorSet, 1, {});
shader.updateTextureUniform(api,
TextureBindingConfig{ .textureHandle = texture, .alsoBindToSet = 1 });
// Render a triangle.
api.beginRenderPass(defaultRenderTarget, params);

View File

@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.59.2"
spec.version = "1.59.1"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.59.2/filament-v1.59.2-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.59.1/filament-v1.59.1-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {

View File

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