mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
WIP on buffer management.
This commit is contained in:
parent
d7c12d7638
commit
88cc8570da
@ -10,6 +10,8 @@ impeller_component("compositor") {
|
||||
"allocator.mm",
|
||||
"buffer.h",
|
||||
"buffer.mm",
|
||||
"buffer_view.h",
|
||||
"buffer_view.mm",
|
||||
"command.h",
|
||||
"command.mm",
|
||||
"command_buffer.h",
|
||||
@ -18,10 +20,14 @@ impeller_component("compositor") {
|
||||
"comparable.h",
|
||||
"context.h",
|
||||
"context.mm",
|
||||
"device_buffer.h",
|
||||
"device_buffer.mm",
|
||||
"formats.cc",
|
||||
"formats.h",
|
||||
"formats_metal.h",
|
||||
"formats_metal.mm",
|
||||
"host_buffer.h",
|
||||
"host_buffer.mm",
|
||||
"pipeline.h",
|
||||
"pipeline.mm",
|
||||
"pipeline_descriptor.h",
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "impeller/compositor/allocator.h"
|
||||
|
||||
#include "impeller/compositor/buffer.h"
|
||||
#include "impeller/compositor/device_buffer.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
|
||||
@ -28,8 +28,6 @@ class BufferView final : public BufferBase {
|
||||
// |BufferBase|
|
||||
~BufferView() = default;
|
||||
|
||||
const BufferBase* GetBuffer() const { return parent_.get(); }
|
||||
|
||||
// |BufferBase|
|
||||
uint8_t* GetMapping() const override {
|
||||
return parent_->GetMapping() + range_in_parent_.offset;
|
||||
@ -48,55 +46,4 @@ class BufferView final : public BufferBase {
|
||||
: parent_(std::move(parent)), range_in_parent_(range_in_parent) {}
|
||||
};
|
||||
|
||||
class Buffer {
|
||||
public:
|
||||
~Buffer();
|
||||
|
||||
private:
|
||||
friend class Allocator;
|
||||
|
||||
const id<MTLBuffer> buffer_;
|
||||
const size_t size_;
|
||||
const StorageMode mode_;
|
||||
const std::string label_;
|
||||
|
||||
Buffer(id<MTLBuffer> buffer,
|
||||
size_t size,
|
||||
StorageMode mode,
|
||||
std::string label);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(Buffer);
|
||||
};
|
||||
|
||||
class HostBuffer : public std::enable_shared_from_this<HostBuffer>,
|
||||
public BufferBase {
|
||||
public:
|
||||
std::shared_ptr<HostBuffer> Create();
|
||||
|
||||
std::shared_ptr<BufferView> Emplace(size_t length);
|
||||
|
||||
virtual ~HostBuffer();
|
||||
|
||||
// |BufferBase|
|
||||
uint8_t* GetMapping() const override { return buffer_; }
|
||||
|
||||
// |BufferBase|
|
||||
size_t GetLength() const override { return length_; }
|
||||
|
||||
[[nodiscard]] bool Truncate(size_t length);
|
||||
|
||||
private:
|
||||
uint8_t* buffer_ = nullptr;
|
||||
size_t length_ = 0;
|
||||
size_t reserved_ = 0;
|
||||
|
||||
[[nodiscard]] bool Reserve(size_t reserved);
|
||||
|
||||
[[nodiscard]] bool ReserveNPOT(size_t reserved);
|
||||
|
||||
HostBuffer();
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(HostBuffer);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -4,80 +4,8 @@
|
||||
|
||||
#include "impeller/compositor/buffer.h"
|
||||
|
||||
#include "flutter/fml/logging.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
Buffer::Buffer(id<MTLBuffer> buffer,
|
||||
size_t size,
|
||||
StorageMode mode,
|
||||
std::string label)
|
||||
: buffer_(buffer), size_(size), mode_(mode), label_(std::move(label)) {}
|
||||
|
||||
Buffer::~Buffer() = default;
|
||||
|
||||
std::shared_ptr<HostBuffer> HostBuffer::Create() {
|
||||
return std::shared_ptr<HostBuffer>(new HostBuffer());
|
||||
}
|
||||
|
||||
HostBuffer::HostBuffer() = default;
|
||||
|
||||
HostBuffer::~HostBuffer() {
|
||||
::free(buffer_);
|
||||
}
|
||||
|
||||
std::shared_ptr<BufferView> HostBuffer::Emplace(size_t length) {
|
||||
auto old_length = length_;
|
||||
if (!Truncate(length_ + length)) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::shared_ptr<BufferView>(
|
||||
new BufferView(shared_from_this(), Range{old_length, length}));
|
||||
}
|
||||
|
||||
bool HostBuffer::Truncate(size_t length) {
|
||||
if (!ReserveNPOT(length)) {
|
||||
return false;
|
||||
}
|
||||
length_ = length;
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t NextPowerOfTwoSize(uint32_t x) {
|
||||
if (x == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
--x;
|
||||
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
bool HostBuffer::ReserveNPOT(size_t reserved) {
|
||||
return Reserve(NextPowerOfTwoSize(reserved));
|
||||
}
|
||||
|
||||
bool HostBuffer::Reserve(size_t reserved) {
|
||||
if (reserved == reserved_) {
|
||||
return true;
|
||||
}
|
||||
auto new_allocation = ::realloc(buffer_, reserved);
|
||||
if (!new_allocation) {
|
||||
// If new length is zero, a minimum non-zero sized allocation is returned.
|
||||
// So this check will not trip and this routine will indicate success as
|
||||
// expected.
|
||||
FML_LOG(ERROR) << "Allocation failed. Out of memory.";
|
||||
return false;
|
||||
}
|
||||
buffer_ = static_cast<uint8_t*>(new_allocation);
|
||||
reserved_ = reserved;
|
||||
return true;
|
||||
}
|
||||
//
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -19,7 +19,7 @@ class Sampler;
|
||||
struct Bindings {
|
||||
std::map<size_t, BufferView> buffers;
|
||||
std::map<size_t, std::shared_ptr<Texture>> textures;
|
||||
std::map<size_t, std::shared_ptr<Texture>> samplers;
|
||||
std::map<size_t, std::shared_ptr<Sampler>> samplers;
|
||||
};
|
||||
|
||||
struct Command {
|
||||
@ -27,6 +27,7 @@ struct Command {
|
||||
Bindings vertex_bindings;
|
||||
Bindings fragment_bindings;
|
||||
BufferView index_buffer;
|
||||
size_t index_count = 0u;
|
||||
|
||||
constexpr operator bool() const { return pipeline && pipeline->IsValid(); }
|
||||
};
|
||||
|
||||
@ -4,4 +4,10 @@
|
||||
|
||||
#include "impeller/compositor/command.h"
|
||||
|
||||
namespace impeller {} // namespace impeller
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
namespace impeller {
|
||||
|
||||
//
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
36
engine/src/flutter/impeller/compositor/device_buffer.h
Normal file
36
engine/src/flutter/impeller/compositor/device_buffer.h
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/compositor/allocator.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class Buffer {
|
||||
public:
|
||||
~Buffer();
|
||||
|
||||
private:
|
||||
friend class Allocator;
|
||||
|
||||
const id<MTLBuffer> buffer_;
|
||||
const size_t size_;
|
||||
const StorageMode mode_;
|
||||
const std::string label_;
|
||||
|
||||
Buffer(id<MTLBuffer> buffer,
|
||||
size_t size,
|
||||
StorageMode mode,
|
||||
std::string label);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(Buffer);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
17
engine/src/flutter/impeller/compositor/device_buffer.mm
Normal file
17
engine/src/flutter/impeller/compositor/device_buffer.mm
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/compositor/device_buffer.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
Buffer::Buffer(id<MTLBuffer> buffer,
|
||||
size_t size,
|
||||
StorageMode mode,
|
||||
std::string label)
|
||||
: buffer_(buffer), size_(size), mode_(mode), label_(std::move(label)) {}
|
||||
|
||||
Buffer::~Buffer() = default;
|
||||
|
||||
} // namespace impeller
|
||||
46
engine/src/flutter/impeller/compositor/host_buffer.h
Normal file
46
engine/src/flutter/impeller/compositor/host_buffer.h
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/compositor/buffer.h"
|
||||
#include "impeller/compositor/host_buffer.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class HostBuffer : public std::enable_shared_from_this<HostBuffer>,
|
||||
public BufferBase {
|
||||
public:
|
||||
std::shared_ptr<HostBuffer> Create();
|
||||
|
||||
std::shared_ptr<BufferView> Emplace(size_t length);
|
||||
|
||||
virtual ~HostBuffer();
|
||||
|
||||
// |BufferBase|
|
||||
uint8_t* GetMapping() const override { return buffer_; }
|
||||
|
||||
// |BufferBase|
|
||||
size_t GetLength() const override { return length_; }
|
||||
|
||||
[[nodiscard]] bool Truncate(size_t length);
|
||||
|
||||
private:
|
||||
uint8_t* buffer_ = nullptr;
|
||||
size_t length_ = 0;
|
||||
size_t reserved_ = 0;
|
||||
|
||||
[[nodiscard]] bool Reserve(size_t reserved);
|
||||
|
||||
[[nodiscard]] bool ReserveNPOT(size_t reserved);
|
||||
|
||||
HostBuffer();
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(HostBuffer);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
75
engine/src/flutter/impeller/compositor/host_buffer.mm
Normal file
75
engine/src/flutter/impeller/compositor/host_buffer.mm
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/compositor/host_buffer.h"
|
||||
|
||||
#include "flutter/fml/logging.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
std::shared_ptr<HostBuffer> HostBuffer::Create() {
|
||||
return std::shared_ptr<HostBuffer>(new HostBuffer());
|
||||
}
|
||||
|
||||
HostBuffer::HostBuffer() = default;
|
||||
|
||||
HostBuffer::~HostBuffer() {
|
||||
::free(buffer_);
|
||||
}
|
||||
|
||||
std::shared_ptr<BufferView> HostBuffer::Emplace(size_t length) {
|
||||
auto old_length = length_;
|
||||
if (!Truncate(length_ + length)) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::shared_ptr<BufferView>(
|
||||
new BufferView(shared_from_this(), Range{old_length, length}));
|
||||
}
|
||||
|
||||
bool HostBuffer::Truncate(size_t length) {
|
||||
if (!ReserveNPOT(length)) {
|
||||
return false;
|
||||
}
|
||||
length_ = length;
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t NextPowerOfTwoSize(uint32_t x) {
|
||||
if (x == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
--x;
|
||||
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
bool HostBuffer::ReserveNPOT(size_t reserved) {
|
||||
return Reserve(NextPowerOfTwoSize(reserved));
|
||||
}
|
||||
|
||||
bool HostBuffer::Reserve(size_t reserved) {
|
||||
if (reserved == reserved_) {
|
||||
return true;
|
||||
}
|
||||
auto new_allocation = ::realloc(buffer_, reserved);
|
||||
if (!new_allocation) {
|
||||
// If new length is zero, a minimum non-zero sized allocation is returned.
|
||||
// So this check will not trip and this routine will indicate success as
|
||||
// expected.
|
||||
FML_LOG(ERROR) << "Allocation failed. Out of memory.";
|
||||
return false;
|
||||
}
|
||||
buffer_ = static_cast<uint8_t*>(new_allocation);
|
||||
reserved_ = reserved;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@ -23,11 +23,15 @@ class Pipeline {
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
id<MTLRenderPipelineState> GetMTLRenderPipelineState() const;
|
||||
|
||||
id<MTLDepthStencilState> GetMTLDepthStencilState() const;
|
||||
|
||||
private:
|
||||
friend class PipelineLibrary;
|
||||
|
||||
Type type_ = Type::kUnknown;
|
||||
id<MTLRenderPipelineState> state_;
|
||||
id<MTLRenderPipelineState> pipeline_state_;
|
||||
id<MTLDepthStencilState> depth_stencil_state_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
|
||||
@ -8,8 +8,8 @@ namespace impeller {
|
||||
|
||||
Pipeline::Pipeline(id<MTLRenderPipelineState> state,
|
||||
id<MTLDepthStencilState> depth_stencil_state)
|
||||
: state_(state), depth_stencil_state_(depth_stencil_state) {
|
||||
if (!state_) {
|
||||
: pipeline_state_(state), depth_stencil_state_(depth_stencil_state) {
|
||||
if (!pipeline_state_) {
|
||||
return;
|
||||
}
|
||||
type_ = Type::kRender;
|
||||
@ -22,4 +22,12 @@ bool Pipeline::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
id<MTLRenderPipelineState> Pipeline::GetMTLRenderPipelineState() const {
|
||||
return pipeline_state_;
|
||||
}
|
||||
|
||||
id<MTLDepthStencilState> Pipeline::GetMTLDepthStencilState() const {
|
||||
return depth_stencil_state_;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -84,6 +84,8 @@ class RenderPass {
|
||||
|
||||
RenderPass(id<MTLCommandBuffer> buffer, const RenderPassDescriptor& desc);
|
||||
|
||||
bool EncodeCommands(id<MTLRenderCommandEncoder> pass) const;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(RenderPass);
|
||||
};
|
||||
|
||||
|
||||
@ -4,8 +4,10 @@
|
||||
|
||||
#include "impeller/compositor/render_pass.h"
|
||||
|
||||
#include "flutter/fml/closure.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "impeller/compositor/formats_metal.h"
|
||||
#include "impeller/shader_glue/shader_types.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@ -136,7 +138,51 @@ bool RenderPass::Encode() const {
|
||||
if (!pass) {
|
||||
return false;
|
||||
}
|
||||
[pass endEncoding];
|
||||
// Success or failure, the pass must end. The buffer can only process one pass
|
||||
// at a time.
|
||||
fml::ScopedCleanupClosure auto_end([pass]() { [pass endEncoding]; });
|
||||
|
||||
return EncodeCommands(pass);
|
||||
}
|
||||
|
||||
void Bind(ShaderStage stage, const BufferView& view) {}
|
||||
|
||||
void Bind(ShaderStage stage, const Texture& view) {}
|
||||
|
||||
void Bind(ShaderStage stage, const Sampler& view) {}
|
||||
|
||||
bool RenderPass::EncodeCommands(id<MTLRenderCommandEncoder> pass) const {
|
||||
// There a numerous opportunities here to ensure bindings are not repeated.
|
||||
// Stuff like setting the vertex buffer bindings over and over when just the
|
||||
// offsets could be updated (as recommended in best practices).
|
||||
|
||||
auto bind_stage_resources = [](const Bindings& bindings, ShaderStage stage) {
|
||||
for (const auto buffer : bindings.buffers) {
|
||||
Bind(stage, buffer.second);
|
||||
}
|
||||
for (const auto texture : bindings.textures) {
|
||||
Bind(stage, *texture.second);
|
||||
}
|
||||
for (const auto sampler : bindings.samplers) {
|
||||
Bind(stage, *sampler.second);
|
||||
}
|
||||
};
|
||||
for (const auto& command : commands_) {
|
||||
[pass setRenderPipelineState:command.pipeline->GetMTLRenderPipelineState()];
|
||||
[pass setDepthStencilState:command.pipeline->GetMTLDepthStencilState()];
|
||||
[pass setFrontFacingWinding:MTLWindingClockwise];
|
||||
[pass setCullMode:MTLCullModeBack];
|
||||
bind_stage_resources(command.vertex_bindings, ShaderStage::kVertex);
|
||||
bind_stage_resources(command.fragment_bindings, ShaderStage::kFragment);
|
||||
// [pass drawIndexedPrimitives:MTLPrimitiveTypeTriangleStrip
|
||||
// indexCount:command.index_count
|
||||
// indexType:MTLIndexTypeUInt32
|
||||
// indexBuffer:command.index_buffer
|
||||
// indexBufferOffset:(NSUInteger)indexBufferOffset
|
||||
// instanceCount:1u
|
||||
// baseVertex:0u
|
||||
// baseInstance:0u];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user