Compare commits
1 Commits
idris/rend
...
mhoff/text
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
667da2aabe |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user