Skip to content

Commit

Permalink
avoid heap allocations for each draw call
Browse files Browse the repository at this point in the history
  • Loading branch information
pixelflinger committed May 23, 2024
1 parent 3c77815 commit 79a7528
Show file tree
Hide file tree
Showing 16 changed files with 143 additions and 14 deletions.
1 change: 1 addition & 0 deletions filament/backend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ set(PUBLIC_HDRS
include/backend/AcquiredImage.h
include/backend/BufferDescriptor.h
include/backend/CallbackHandler.h
include/backend/DescriptorSetOffsetArray.h
include/backend/DriverApiForward.h
include/backend/DriverEnums.h
include/backend/Handle.h
Expand Down
101 changes: 101 additions & 0 deletions filament/backend/include/backend/DescriptorSetOffsetArray.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef TNT_FILAMENT_BACKEND_COMMANDSTREAMVECTOR_H
#define TNT_FILAMENT_BACKEND_COMMANDSTREAMVECTOR_H

#include <backend/DriverApiForward.h>

#include <initializer_list>
#include <memory>

#include <stddef.h>
#include <stdint.h>


namespace filament::backend {

void* allocateFromCommandStream(DriverApi& driver, size_t size, size_t alignment) noexcept;

class DescriptorSetOffsetArray {
public:
using value_type = uint32_t;
using reference = value_type&;
using const_reference = value_type const&;
using size_type = uint32_t;
using difference_type = int32_t;
using pointer = value_type*;
using const_pointer = value_type const*;
using iterator = pointer;
using const_iterator = const_pointer;

DescriptorSetOffsetArray() noexcept = default;

~DescriptorSetOffsetArray() noexcept = default;

DescriptorSetOffsetArray(size_type size, DriverApi& driver) noexcept {
mOffsets = (value_type *)allocateFromCommandStream(driver,
size * sizeof(value_type), alignof(value_type));
std::uninitialized_fill_n(mOffsets, size, 0);
}

DescriptorSetOffsetArray(std::initializer_list<uint32_t> list, DriverApi& driver) noexcept {
mOffsets = (value_type *)allocateFromCommandStream(driver,
list.size() * sizeof(value_type), alignof(value_type));
std::uninitialized_copy(list.begin(), list.end(), mOffsets);
}

DescriptorSetOffsetArray(DescriptorSetOffsetArray const&) = delete;
DescriptorSetOffsetArray& operator=(DescriptorSetOffsetArray const&) = delete;

DescriptorSetOffsetArray(DescriptorSetOffsetArray&& rhs) noexcept
: mOffsets(rhs.mOffsets) {
rhs.mOffsets = nullptr;
}

DescriptorSetOffsetArray& operator=(DescriptorSetOffsetArray&& rhs) noexcept {
if (this != &rhs) {
mOffsets = rhs.mOffsets;
rhs.mOffsets = nullptr;
}
return *this;
}

bool empty() const noexcept { return mOffsets == nullptr; }

value_type* data() noexcept { return mOffsets; }
const value_type* data() const noexcept { return mOffsets; }


reference operator[](size_type n) noexcept {
return *(data() + n);
}

const_reference operator[](size_type n) const noexcept {
return *(data() + n);
}

void clear() noexcept {
mOffsets = nullptr;
}

private:
value_type *mOffsets = nullptr;
};

} // namespace filament::backend

#endif //TNT_FILAMENT_BACKEND_COMMANDSTREAMVECTOR_H
1 change: 1 addition & 0 deletions filament/backend/include/private/backend/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define TNT_FILAMENT_BACKEND_PRIVATE_DRIVER_H

#include <backend/CallbackHandler.h>
#include <backend/DescriptorSetOffsetArray.h>
#include <backend/DriverApiForward.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
Expand Down
2 changes: 1 addition & 1 deletion filament/backend/include/private/backend/DriverAPI.inc
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ DECL_DRIVER_API_N(updateDescriptorSetTexture,
DECL_DRIVER_API_N(bindDescriptorSet,
backend::DescriptorSetHandle, dsh,
backend::descriptor_set_t, set,
utils::FixedCapacityVector<uint32_t>&&, offsets
backend::DescriptorSetOffsetArray&&, offsets
)


Expand Down
11 changes: 11 additions & 0 deletions filament/backend/include/private/backend/DriverApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@
#define TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPI_H

#include "backend/DriverApiForward.h"

#include "private/backend/CommandStream.h"

#include <stddef.h>

namespace filament::backend {

inline void* allocateFromCommandStream(DriverApi& driver, size_t size, size_t alignment) noexcept {
return driver.allocate(size, alignment);
}

} // namespace filament::backend

#endif // TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPI_H
2 changes: 1 addition & 1 deletion filament/backend/src/metal/MetalDriver.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1862,7 +1862,7 @@
void MetalDriver::bindDescriptorSet(
backend::DescriptorSetHandle dsh,
backend::descriptor_set_t set,
utils::FixedCapacityVector<uint32_t>&& offsets) {
backend::DescriptorSetOffsetArray&& offsets) {
}

void MetalDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
Expand Down
2 changes: 1 addition & 1 deletion filament/backend/src/noop/NoopDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ void NoopDriver::updateDescriptorSetTexture(
void NoopDriver::bindDescriptorSet(
backend::DescriptorSetHandle dsh,
backend::descriptor_set_t set,
utils::FixedCapacityVector<uint32_t>&& offsets) {
backend::DescriptorSetOffsetArray&& offsets) {
}

} // namespace filament
3 changes: 3 additions & 0 deletions filament/backend/src/opengl/GLDescriptorSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ GLDescriptorSet::GLDescriptorSet(OpenGLContext& gl,
bool const dynamicOffset = any(entry.flags & DescriptorFlags::DYNAMIC_OFFSET);
dynamicBuffers.set(index, dynamicOffset);
if (UTILS_UNLIKELY(gl.isES2())) {
dynamicBufferCount++;
desc.emplace<BufferGLES2>(dynamicOffset);
} else {
auto const type = GLUtils::getBufferBindingType(BufferObjectBinding::UNIFORM);
if (dynamicOffset) {
dynamicBufferCount++;
desc.emplace<DynamicBuffer>(type);
} else {
desc.emplace<Buffer>(type);
Expand All @@ -78,6 +80,7 @@ GLDescriptorSet::GLDescriptorSet(OpenGLContext& gl,
dynamicBuffers.set(index, dynamicOffset);
auto const type = GLUtils::getBufferBindingType(BufferObjectBinding::SHADER_STORAGE);
if (dynamicOffset) {
dynamicBufferCount++;
desc.emplace<DynamicBuffer>(type);
} else {
desc.emplace<Buffer>(type);
Expand Down
5 changes: 5 additions & 0 deletions filament/backend/src/opengl/GLDescriptorSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ struct GLDescriptorSet : public HwDescriptorSet {
void bind(OpenGLContext& gl, OpenGLProgram const& p,
descriptor_set_t set, uint32_t const* offsets, bool offsetsOnly) const noexcept;

uint32_t getDynamicBufferCount() const noexcept {
return dynamicBufferCount;
}

private:
// a Buffer Descriptor such as SSBO or UBO with static offset
struct Buffer {
Expand Down Expand Up @@ -120,6 +124,7 @@ struct GLDescriptorSet : public HwDescriptorSet {
};
utils::FixedCapacityVector<Descriptor> descriptors;
utils::bitset64 dynamicBuffers;
uint8_t dynamicBufferCount = 0;
static_assert(sizeof(Descriptor) <= 32);
};

Expand Down
16 changes: 11 additions & 5 deletions filament/backend/src/opengl/OpenGLDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@

#include <backend/BufferDescriptor.h>
#include <backend/CallbackHandler.h>
#include <backend/DescriptorSetOffsetArray.h>
#include <backend/DriverApiForward.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <backend/PipelineState.h>
#include <backend/Platform.h>
#include <backend/Program.h>
#include <backend/SamplerDescriptor.h>
#include <backend/TargetBufferInfo.h>

#include "private/backend/Dispatcher.h"
Expand Down Expand Up @@ -3818,9 +3818,10 @@ void OpenGLDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
void OpenGLDriver::bindDescriptorSet(
backend::DescriptorSetHandle dsh,
backend::descriptor_set_t set,
utils::FixedCapacityVector<uint32_t>&& offsets) {
// handle_cast<> here serves to validate the handle (it actually cannot return nullptr)
if (handle_cast<GLDescriptorSet*>(dsh)) {
backend::DescriptorSetOffsetArray&& offsets) {
// handle_cast<> here also serves to validate the handle (it actually cannot return nullptr)
GLDescriptorSet const* const ds = handle_cast<GLDescriptorSet*>(dsh);
if (ds) {
assert_invariant(set < MAX_DESCRIPTOR_SET_COUNT);
if (mBoundDescriptorSets[set].dsh != dsh) {
// if the descriptor itself changed, we mark this descriptor binding
Expand All @@ -3831,7 +3832,12 @@ void OpenGLDriver::bindDescriptorSet(
// be re-bound at the next draw.
mInvalidDescriptorSetBindingOffsets.set(set, true);
}
mBoundDescriptorSets[set] = { dsh, std::move(offsets) };

// `offsets` data's lifetime will end when this function returns. We have to make a copy.
// (the data is allocated inside the CommandStream)
mBoundDescriptorSets[set].dsh = dsh;
std::copy_n(offsets.data(), ds->getDynamicBufferCount(),
mBoundDescriptorSets[set].offsets.data());
}
}

Expand Down
2 changes: 1 addition & 1 deletion filament/backend/src/opengl/OpenGLDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ class OpenGLDriver final : public DriverBase {

struct {
backend::DescriptorSetHandle dsh;
utils::FixedCapacityVector<uint32_t> offsets;
std::array<uint32_t, CONFIG_UNIFORM_BINDING_COUNT> offsets;
} mBoundDescriptorSets[MAX_DESCRIPTOR_SET_COUNT];


Expand Down
2 changes: 1 addition & 1 deletion filament/backend/src/vulkan/VulkanDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1949,7 +1949,7 @@ void VulkanDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
void VulkanDriver::bindDescriptorSet(
backend::DescriptorSetHandle dsh,
backend::descriptor_set_t set,
utils::FixedCapacityVector<uint32_t>&& offsets) {
backend::DescriptorSetOffsetArray&& offsets) {
}

void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
Expand Down
2 changes: 1 addition & 1 deletion filament/src/RenderPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1018,7 +1018,7 @@ void RenderPass::Executor::execute(FEngine& engine,
assert_invariant(info.dsh);
driver.bindDescriptorSet(info.dsh,
+DescriptorSetBindingPoints::PER_RENDERABLE,
{ offset, info.skinningOffset }); // FIXME: this creates a vector each time
{{ offset, info.skinningOffset }, driver});

driver.draw2(info.indexOffset, info.indexCount, info.instanceCount);
}
Expand Down
2 changes: 1 addition & 1 deletion filament/src/ds/DescriptorSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ void DescriptorSet::bind(FEngine::DriverApi& driver, DescriptorSetBindingPoints
}

void DescriptorSet::bind(FEngine::DriverApi& driver, DescriptorSetBindingPoints set,
utils::FixedCapacityVector<uint32_t> dynamicOffsets) const noexcept {
backend::DescriptorSetOffsetArray dynamicOffsets) const noexcept {
// TODO: on debug check that dynamicOffsets is large enough
assert_invariant(mDirty.none());
assert_invariant(mDescriptorSetHandle);
Expand Down
3 changes: 2 additions & 1 deletion filament/src/ds/DescriptorSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <private/filament/EngineEnums.h>

#include <backend/DescriptorSetOffsetArray.h>
#include <backend/DriverApiForward.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
Expand Down Expand Up @@ -57,7 +58,7 @@ class DescriptorSet {
void bind(backend::DriverApi& driver, DescriptorSetBindingPoints set) const noexcept;

void bind(backend::DriverApi& driver, DescriptorSetBindingPoints set,
utils::FixedCapacityVector<uint32_t> dynamicOffsets) const noexcept;
backend::DescriptorSetOffsetArray dynamicOffsets) const noexcept;

// sets a ubo/ssbo descriptor
void setBuffer(backend::descriptor_binding_t binding,
Expand Down
2 changes: 1 addition & 1 deletion libs/utils/include/utils/FixedCapacityVector.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class UTILS_PUBLIC FixedCapacityVector {
FixedCapacityVector() = default;

explicit FixedCapacityVector(const allocator_type& allocator) noexcept
: mCapacityAllocator({}, allocator) {
: mCapacityAllocator(0, allocator) {
}

explicit FixedCapacityVector(size_type size, const allocator_type& allocator = allocator_type())
Expand Down

0 comments on commit 79a7528

Please sign in to comment.