[scenic] New Gpu Allocator Interface
GpuAllocator now allocates Memory, Buffers, and Images. All factory functions that allocate new memory are expected to go through some instance of a GpuAllocator (mostly, for tracking purposes).
All other related factory functions (e.g., GpuMem::New) have been removed. All remaining functions have been renamed to reflect their usage (e.g., Image::New has been renamed to Image::AdoptImage, since it does not allocate a new Image object, but only wraps an existing image and/or allocation).
This also converts Image, similar to Buffer, to not have its own concept of a buffer offset. A suballocated GpuMem object is passed in instead.
Finally, this fixes SCN-273, as escher::Buffer objects can now be constructed that point to host memory.
tested=scenic_tests, manual running of sketchy_service, hello_scenic
SCN-273 #done
Change-Id: Ie870f1c9795db7f29ad33c6f67ff335d29c41270
diff --git a/bin/ui/sketchy/buffer/shared_buffer.cc b/bin/ui/sketchy/buffer/shared_buffer.cc
index 8358947..43d5702 100644
--- a/bin/ui/sketchy/buffer/shared_buffer.cc
+++ b/bin/ui/sketchy/buffer/shared_buffer.cc
@@ -47,24 +47,20 @@
namespace sketchy_service {
SharedBufferPtr SharedBuffer::New(scenic::Session* session,
- escher::ResourceRecycler* recycler,
+ escher::BufferFactory* factory,
vk::DeviceSize capacity) {
- return fxl::AdoptRef(new SharedBuffer(session, recycler, capacity));
+ return fxl::AdoptRef(new SharedBuffer(session, factory, capacity));
}
SharedBuffer::SharedBuffer(scenic::Session* session,
- escher::ResourceRecycler* recycler,
+ escher::BufferFactory* factory,
vk::DeviceSize capacity) {
- // Normally, this code might use a buffer factory or a gpu_allocator
- // to construct its buffer. However, if we did that, then we might not have a
- // unique VMO just for this one resource. Instead, we might get a VMO for a
- // managed pool or a circular buffer. Therefore, we go through the steps here
- // to create our own fresh slab, to make sure that the VMO is isolated in its
- // contents.
+ // By passing an empty GpuMemPtr into NewBuffer, we are signalling to the
+ // factory that we want a dedicated allocation. This gives us the guarantees
+ // for VMO extraction described above.
escher::GpuMemPtr mem;
- escher_buffer_ =
- escher::Buffer::New(recycler, nullptr, capacity, kBufferUsageFlags,
- kMemoryPropertyFlags, &mem);
+ escher_buffer_ = factory->NewBuffer(capacity, kBufferUsageFlags,
+ kMemoryPropertyFlags, &mem);
scenic_buffer_ =
NewScenicBufferFromEscherBuffer(escher_buffer_, session, mem);
}
diff --git a/bin/ui/sketchy/buffer/shared_buffer.h b/bin/ui/sketchy/buffer/shared_buffer.h
index 748addf..20db280 100644
--- a/bin/ui/sketchy/buffer/shared_buffer.h
+++ b/bin/ui/sketchy/buffer/shared_buffer.h
@@ -7,7 +7,7 @@
#include "garnet/public/lib/escher/impl/compute_shader.h"
#include "lib/escher/resources/resource_recycler.h"
-#include "lib/escher/vk/buffer.h"
+#include "lib/escher/vk/buffer_factory.h"
#include "lib/ui/scenic/cpp/resources.h"
#include "lib/ui/scenic/cpp/session.h"
@@ -25,7 +25,7 @@
class SharedBuffer final : public fxl::RefCountedThreadSafe<SharedBuffer> {
public:
static SharedBufferPtr New(scenic::Session* session,
- escher::ResourceRecycler* recycler,
+ escher::BufferFactory* factory,
vk::DeviceSize capacity);
// Reserve a chunk of |size| for use. The requested |size| MUST fit in the
@@ -49,7 +49,7 @@
private:
friend class SharedBufferPool;
- SharedBuffer(scenic::Session* session, escher::ResourceRecycler* recycler,
+ SharedBuffer(scenic::Session* session, escher::BufferFactory* factory,
vk::DeviceSize capacity);
escher::BufferPtr escher_buffer_;
diff --git a/bin/ui/sketchy/buffer/shared_buffer_pool.cc b/bin/ui/sketchy/buffer/shared_buffer_pool.cc
index a3275dd..f5ab350 100644
--- a/bin/ui/sketchy/buffer/shared_buffer_pool.cc
+++ b/bin/ui/sketchy/buffer/shared_buffer_pool.cc
@@ -15,8 +15,8 @@
namespace sketchy_service {
SharedBufferPool::SharedBufferPool(scenic::Session* session,
- escher::ResourceRecycler* recycler)
- : session_(session), recycler_(recycler), weak_factory_(this) {}
+ escher::BufferFactory* factory)
+ : session_(session), buffer_factory_(factory), weak_factory_(this) {}
SharedBufferPtr SharedBufferPool::GetBuffer(vk::DeviceSize capacity_req) {
SharedBufferPtr buffer;
@@ -25,7 +25,7 @@
buffer = std::move(free_buffers_[capacity].back());
free_buffers_[capacity].pop_back();
} else {
- buffer = SharedBuffer::New(session_, recycler_, capacity);
+ buffer = SharedBuffer::New(session_, buffer_factory_, capacity);
}
used_buffers_.insert(buffer);
return buffer;
diff --git a/bin/ui/sketchy/buffer/shared_buffer_pool.h b/bin/ui/sketchy/buffer/shared_buffer_pool.h
index 24d3108..e4f5b90 100644
--- a/bin/ui/sketchy/buffer/shared_buffer_pool.h
+++ b/bin/ui/sketchy/buffer/shared_buffer_pool.h
@@ -19,8 +19,7 @@
// management and multi-buffering.
class SharedBufferPool final {
public:
- SharedBufferPool(scenic::Session* session,
- escher::ResourceRecycler* recycler);
+ SharedBufferPool(scenic::Session* session, escher::BufferFactory* factory);
// Gets a buffer with at least |capacity_req|.
SharedBufferPtr GetBuffer(vk::DeviceSize capacity_req);
@@ -42,7 +41,7 @@
void RecycleBuffer(SharedBufferPtr buffer);
scenic::Session* const session_;
- escher::ResourceRecycler* const recycler_;
+ escher::BufferFactory* const buffer_factory_;
std::set<SharedBufferPtr> used_buffers_;
// Groups free buffers into lists that contain buffers that have the same
// capacity.
diff --git a/bin/ui/sketchy/canvas.cc b/bin/ui/sketchy/canvas.cc
index b6e4856..a63e96c 100644
--- a/bin/ui/sketchy/canvas.cc
+++ b/bin/ui/sketchy/canvas.cc
@@ -16,8 +16,9 @@
: loop_(loop),
session_(session),
escher_(weak_escher),
- shared_buffer_pool_(session, weak_escher->resource_recycler()),
- unshared_buffer_factory_(weak_escher),
+ buffer_factory_(weak_escher->gpu_allocator(),
+ weak_escher->resource_recycler()),
+ shared_buffer_pool_(session, &buffer_factory_),
stroke_manager_(std::move(weak_escher)) {}
void CanvasImpl::Init(
@@ -67,8 +68,7 @@
};
callbacks_.clear();
- auto frame =
- Frame(escher_.get(), &shared_buffer_pool_, &unshared_buffer_factory_);
+ auto frame = Frame(escher_.get(), &shared_buffer_pool_, &buffer_factory_);
if (frame.init_failed()) {
session_->Present(presentation_time, std::move(session_callback));
return;
@@ -130,7 +130,7 @@
::fuchsia::ui::sketchy::Stroke stroke) {
return resource_map_.AddResource(
id, fxl::MakeRefCounted<Stroke>(stroke_manager_.stroke_tessellator(),
- &unshared_buffer_factory_));
+ &buffer_factory_));
}
bool CanvasImpl::CreateStrokeGroup(
diff --git a/bin/ui/sketchy/canvas.h b/bin/ui/sketchy/canvas.h
index 5888fbe..bb8348c 100644
--- a/bin/ui/sketchy/canvas.h
+++ b/bin/ui/sketchy/canvas.h
@@ -72,10 +72,9 @@
async::Loop* const loop_;
scenic::Session* const session_;
const escher::EscherWeakPtr escher_;
+ escher::BufferFactoryAdapter buffer_factory_;
// Buffers which are sent over the wire are constructed using this pool.
SharedBufferPool shared_buffer_pool_;
- // For non-shared buffers, we use this factory instead.
- escher::BufferFactory unshared_buffer_factory_;
::fidl::VectorPtr<::fuchsia::ui::sketchy::Command> commands_;
ResourceMap resource_map_;
diff --git a/examples/escher/common/demo_harness.cc b/examples/escher/common/demo_harness.cc
index 180f99f..1180a08 100644
--- a/examples/escher/common/demo_harness.cc
+++ b/examples/escher/common/demo_harness.cc
@@ -239,8 +239,8 @@
image_info.height = swapchain_extent.height;
image_info.usage = kImageUsageFlags;
- auto escher_image = escher::Image::New(swapchain_image_owner_.get(),
- image_info, im, nullptr);
+ auto escher_image = escher::Image::WrapVkImage(
+ swapchain_image_owner_.get(), image_info, im);
FXL_CHECK(escher_image);
escher_images.push_back(escher_image);
}
diff --git a/examples/ui/shadertoy/service/imagepipe_shadertoy.cc b/examples/ui/shadertoy/service/imagepipe_shadertoy.cc
index 5b8acac..61d1e5d 100644
--- a/examples/ui/shadertoy/service/imagepipe_shadertoy.cc
+++ b/examples/ui/shadertoy/service/imagepipe_shadertoy.cc
@@ -6,11 +6,12 @@
#include "garnet/examples/ui/shadertoy/service/renderer.h"
#include "lib/escher/flib/fence.h"
+#include "lib/escher/resources/resource_recycler.h"
#include "lib/escher/util/fuchsia_utils.h"
#include "lib/escher/vk/framebuffer.h"
#include "lib/escher/vk/gpu_mem.h"
#include "lib/escher/vk/image.h"
-#include "lib/escher/vk/simple_image_factory.h"
+#include "lib/escher/vk/image_factory.h"
namespace shadertoy {
@@ -52,8 +53,8 @@
escher_image_info.sample_count = 1;
escher_image_info.usage = vk::ImageUsageFlagBits::eColorAttachment;
- escher::SimpleImageFactory factory(escher()->resource_recycler(),
- escher()->gpu_allocator());
+ escher::ImageFactoryAdapter factory(escher()->gpu_allocator(),
+ escher()->resource_recycler());
for (size_t i = 0; i < kNumFramebuffers; ++i) {
auto& fb = framebuffers_[i];
@@ -95,7 +96,7 @@
image_info.tiling = fuchsia::images::Tiling::GPU_OPTIMAL;
image_pipe_->AddImage(fb.image_pipe_id, std::move(image_info),
- std::move(vmo), image->memory_offset(),
+ std::move(vmo), image->memory()->offset(),
image->memory()->size(),
fuchsia::images::MemoryType::VK_DEVICE_MEMORY);
}
diff --git a/examples/ui/shadertoy/service/renderer.cc b/examples/ui/shadertoy/service/renderer.cc
index 882291b..5cba891 100644
--- a/examples/ui/shadertoy/service/renderer.cc
+++ b/examples/ui/shadertoy/service/renderer.cc
@@ -13,7 +13,7 @@
#include "lib/escher/util/image_utils.h"
#include "lib/escher/vk/framebuffer.h"
#include "lib/escher/vk/image.h"
-#include "lib/escher/vk/simple_image_factory.h"
+#include "lib/escher/vk/image_factory.h"
#include "lib/escher/vk/texture.h"
namespace shadertoy {
@@ -196,8 +196,8 @@
uint8_t channels[4];
channels[0] = channels[1] = channels[2] = channels[3] = 255;
- escher::SimpleImageFactory image_factory(escher()->resource_recycler(),
- escher()->gpu_allocator());
+ escher::ImageFactoryAdapter image_factory(escher()->gpu_allocator(),
+ escher()->resource_recycler());
auto image = escher::image_utils::NewRgbaImage(
&image_factory, escher()->gpu_uploader(), 1, 1, channels);
diff --git a/lib/ui/gfx/engine/engine.cc b/lib/ui/gfx/engine/engine.cc
index dbadd1d..f8f0184 100644
--- a/lib/ui/gfx/engine/engine.cc
+++ b/lib/ui/gfx/engine/engine.cc
@@ -78,8 +78,8 @@
: display_manager_(display_manager),
escher_(std::move(weak_escher)),
engine_renderer_(std::make_unique<EngineRenderer>(escher_)),
- image_factory_(std::make_unique<escher::SimpleImageFactory>(
- escher()->resource_recycler(), escher()->gpu_allocator())),
+ image_factory_(std::make_unique<escher::ImageFactoryAdapter>(
+ escher()->gpu_allocator(), escher()->resource_recycler())),
rounded_rect_factory_(
std::make_unique<escher::RoundedRectFactory>(escher_)),
release_fence_signaller_(std::make_unique<escher::ReleaseFenceSignaller>(
diff --git a/lib/ui/gfx/engine/engine.h b/lib/ui/gfx/engine/engine.h
index 5955daf..edbc39a 100644
--- a/lib/ui/gfx/engine/engine.h
+++ b/lib/ui/gfx/engine/engine.h
@@ -16,7 +16,7 @@
#include "lib/escher/renderer/batch_gpu_uploader.h"
#include "lib/escher/resources/resource_recycler.h"
#include "lib/escher/shape/rounded_rect_factory.h"
-#include "lib/escher/vk/simple_image_factory.h"
+#include "lib/escher/vk/image_factory.h"
#include "garnet/lib/ui/gfx/displays/display_manager.h"
#include "garnet/lib/ui/gfx/engine/frame_scheduler.h"
@@ -196,7 +196,7 @@
ViewLinker view_linker_;
EventTimestamper event_timestamper_;
- std::unique_ptr<escher::SimpleImageFactory> image_factory_;
+ std::unique_ptr<escher::ImageFactoryAdapter> image_factory_;
std::unique_ptr<escher::RoundedRectFactory> rounded_rect_factory_;
std::unique_ptr<escher::ReleaseFenceSignaller> release_fence_signaller_;
std::unique_ptr<SessionManager> session_manager_;
diff --git a/lib/ui/gfx/engine/session.cc b/lib/ui/gfx/engine/session.cc
index 3b24cc4..d5b26e6 100644
--- a/lib/ui/gfx/engine/session.cc
+++ b/lib/ui/gfx/engine/session.cc
@@ -1134,14 +1134,6 @@
ResourcePtr Session::CreateBuffer(ResourceId id, MemoryPtr memory,
uint32_t memory_offset, uint32_t num_bytes) {
- // TODO(SCN-273): host memory should also be supported.
- if (memory->is_host()) {
- error_reporter_->ERROR() << "scenic_impl::gfx::Session::CreateBuffer(): "
- "memory must be of type "
- "ui.gfx.MemoryType.VK_DEVICE_MEMORY";
- return ResourcePtr();
- }
-
if (memory_offset + num_bytes > memory->size()) {
error_reporter_->ERROR() << "scenic_impl::gfx::Session::CreateBuffer(): "
"buffer does not fit within memory (buffer "
@@ -1154,8 +1146,8 @@
// Make a pointer to a subregion of the memory, if necessary.
escher::GpuMemPtr gpu_mem =
(memory_offset > 0 || num_bytes < memory->size())
- ? memory->gpu_mem()->Allocate(num_bytes, memory_offset)
- : memory->gpu_mem();
+ ? memory->GetGpuMem()->Suballocate(num_bytes, memory_offset)
+ : memory->GetGpuMem();
return fxl::MakeRefCounted<Buffer>(this, id, std::move(gpu_mem),
std::move(memory));
diff --git a/lib/ui/gfx/resources/gpu_image.cc b/lib/ui/gfx/resources/gpu_image.cc
index 07c4203..0ad21af 100644
--- a/lib/ui/gfx/resources/gpu_image.cc
+++ b/lib/ui/gfx/resources/gpu_image.cc
@@ -15,13 +15,12 @@
ResourceType::kGpuImage | ResourceType::kImage | ResourceType::kImageBase,
"GpuImage"};
-GpuImage::GpuImage(Session* session, ResourceId id, MemoryPtr memory,
- uint64_t memory_offset, escher::ImageInfo image_info,
- vk::Image vk_image)
- : Image(session, id, GpuImage::kTypeInfo), memory_(std::move(memory)) {
- image_ = escher::Image::New(session->engine()->escher_resource_recycler(),
- image_info, vk_image, memory_->gpu_mem(),
- memory_offset);
+GpuImage::GpuImage(Session* session, ResourceId id, escher::GpuMemPtr gpu_mem,
+ escher::ImageInfo image_info, vk::Image vk_image)
+ : Image(session, id, GpuImage::kTypeInfo) {
+ image_ =
+ escher::Image::AdoptVkImage(session->engine()->escher_resource_recycler(),
+ image_info, vk_image, std::move(gpu_mem));
FXL_CHECK(image_);
}
@@ -105,9 +104,14 @@
return nullptr;
}
- return fxl::AdoptRef(new GpuImage(session, id, std::move(memory),
- memory_offset, escher_image_info,
- vk_image));
+ // Make a pointer to a subregion of the memory, if necessary.
+ escher::GpuMemPtr gpu_mem =
+ (memory_offset > 0 || memory_reqs.size < memory->size())
+ ? memory->GetGpuMem()->Suballocate(memory_reqs.size, memory_offset)
+ : memory->GetGpuMem();
+
+ return fxl::AdoptRef(new GpuImage(session, id, std::move(gpu_mem),
+ escher_image_info, vk_image));
}
bool GpuImage::UpdatePixels() { return false; }
diff --git a/lib/ui/gfx/resources/gpu_image.h b/lib/ui/gfx/resources/gpu_image.h
index 35b23476..e65784f 100644
--- a/lib/ui/gfx/resources/gpu_image.h
+++ b/lib/ui/gfx/resources/gpu_image.h
@@ -46,17 +46,13 @@
private:
// Create an Image object from a VkImage.
// |session| is the Session that this image can be referenced from.
+ // |id| is the ID of the resource.
+ // |gpu_mem| is the GPU memory that is associated with this image.
// |image_info| specifies size, format, and other properties.
// |vk_image| is the VkImage, whose lifetime is now controlled by this
// object.
- // |memory| is the GPU memory that is associated with this image.
- // |memory_offset| is the offset in bytes into the memory where the image is
- // stored.
- GpuImage(Session* session, ResourceId id, MemoryPtr memory,
- uint64_t memory_offset, escher::ImageInfo image_info,
- vk::Image vk_image_);
-
- MemoryPtr memory_;
+ GpuImage(Session* session, ResourceId id, escher::GpuMemPtr gpu_mem,
+ escher::ImageInfo image_info, vk::Image vk_image);
};
} // namespace gfx
diff --git a/lib/ui/gfx/resources/memory.cc b/lib/ui/gfx/resources/memory.cc
index 9812273..094f542 100644
--- a/lib/ui/gfx/resources/memory.cc
+++ b/lib/ui/gfx/resources/memory.cc
@@ -92,11 +92,13 @@
return nullptr;
}
- // TODO(SCN-1115): This currently does not request a mapped ptr, as it gets
- // the uint8_t* directly from the VMO.
- return escher::GpuMem::New(session()->engine()->vk_device(),
- vk::DeviceMemory(memory), vk::DeviceSize(size()),
- false /* needs_mapped_ptr */, memory_type_index);
+ // TODO(SCN-1115): If we can rely on all memory being importable into Vulkan
+ // (either as host or device memory), then we can always make a GpuMem object,
+ // and rely on its mapped pointer accessor instead of storing our own local
+ // uint8_t*.
+ return escher::GpuMem::AdoptVkMemory(
+ session()->engine()->vk_device(), vk::DeviceMemory(memory),
+ vk::DeviceSize(size()), is_host_ /* needs_mapped_ptr */);
}
zx::vmo Memory::DuplicateVmo() {
diff --git a/lib/ui/gfx/resources/memory.h b/lib/ui/gfx/resources/memory.h
index e1b5df0..0efa2f0 100644
--- a/lib/ui/gfx/resources/memory.h
+++ b/lib/ui/gfx/resources/memory.h
@@ -46,7 +46,7 @@
// don't need additional logic here.
return shared_vmo_->Map();
}
- const escher::GpuMemPtr& gpu_mem() {
+ const escher::GpuMemPtr& GetGpuMem() {
// TODO(SCN-999): Passive lazy instantiation may not be ideal, either from a
// performance standpoint, or from an external logic standpoint. Consider
// acquire/release semantics. This would also map well to vkCopyBuffer
diff --git a/lib/ui/gfx/resources/snapshot/snapshotter.cc b/lib/ui/gfx/resources/snapshot/snapshotter.cc
index 8f4a009..16ea029 100644
--- a/lib/ui/gfx/resources/snapshot/snapshotter.cc
+++ b/lib/ui/gfx/resources/snapshot/snapshotter.cc
@@ -343,7 +343,7 @@
region.imageExtent.width = image->width();
region.imageExtent.height = image->height();
region.imageExtent.depth = 1;
- region.bufferOffset = image->memory_offset();
+ region.bufferOffset = image->memory()->offset();
auto reader = gpu_uploader_->AcquireReader(image->memory()->size());
reader->ReadImage(image, region, escher::SemaphorePtr());
diff --git a/lib/ui/gfx/swapchain/display_swapchain.cc b/lib/ui/gfx/swapchain/display_swapchain.cc
index f3c5d53..9d07531 100644
--- a/lib/ui/gfx/swapchain/display_swapchain.cc
+++ b/lib/ui/gfx/swapchain/display_swapchain.cc
@@ -179,9 +179,9 @@
}
Framebuffer buffer;
- buffer.device_memory =
- escher::GpuMem::New(device_, mem_result.value, memory_requirements.size,
- false /* needs_mapped_ptr */, memory_type_index);
+ buffer.device_memory = escher::GpuMem::AdoptVkMemory(
+ device_, mem_result.value, memory_requirements.size,
+ false /* needs_mapped_ptr */);
FXL_CHECK(buffer.device_memory);
// Wrap the image and device memory in a escher::Image.
@@ -191,10 +191,10 @@
image_info.height = height_in_px;
image_info.usage = image_usage;
- // escher::Image::New() binds the memory to the image.
+ // escher::Image::AdoptVkImage() binds the memory to the image.
buffer.escher_image =
- escher::Image::New(resource_recycler, image_info, image_result.value,
- buffer.device_memory);
+ escher::Image::AdoptVkImage(resource_recycler, image_info,
+ image_result.value, buffer.device_memory);
if (!buffer.escher_image) {
FXL_LOG(ERROR) << "Creating escher::EscherImage failed.";
diff --git a/lib/ui/gfx/swapchain/vulkan_display_swapchain.cc b/lib/ui/gfx/swapchain/vulkan_display_swapchain.cc
index ec9bd66..50465c9 100644
--- a/lib/ui/gfx/swapchain/vulkan_display_swapchain.cc
+++ b/lib/ui/gfx/swapchain/vulkan_display_swapchain.cc
@@ -226,7 +226,9 @@
image_info.width = swapchain_extent.width;
image_info.height = swapchain_extent.height;
image_info.usage = vk::ImageUsageFlagBits::eColorAttachment;
- auto escher_image = escher::Image::New(recycler, image_info, im, nullptr);
+ // The swapchain maintains ownership of the vk::Image objects in the
+ // images array, so we only wrap them here, instead of adopting them.
+ auto escher_image = escher::Image::WrapVkImage(recycler, image_info, im);
FXL_CHECK(escher_image);
escher_images.push_back(escher_image);
}
diff --git a/lib/ui/gfx/tests/image_pipe_unittest.cc b/lib/ui/gfx/tests/image_pipe_unittest.cc
index 1f5a8d3..27d9333 100644
--- a/lib/ui/gfx/tests/image_pipe_unittest.cc
+++ b/lib/ui/gfx/tests/image_pipe_unittest.cc
@@ -104,8 +104,8 @@
escher::ImageInfo escher_info;
escher_info.width = image_info.width;
escher_info.height = image_info.height;
- escher::ImagePtr escher_image = escher::Image::New(
- dummy_resource_manager_, escher_info, vk::Image(), nullptr);
+ escher::ImagePtr escher_image = escher::Image::WrapVkImage(
+ dummy_resource_manager_, escher_info, vk::Image());
FXL_CHECK(escher_image);
auto image = fxl::AdoptRef(new DummyImage(session, id, escher_image));
diff --git a/lib/ui/gfx/tests/session_unittest.cc b/lib/ui/gfx/tests/session_unittest.cc
index f8b5279..258eb51 100644
--- a/lib/ui/gfx/tests/session_unittest.cc
+++ b/lib/ui/gfx/tests/session_unittest.cc
@@ -121,11 +121,9 @@
status = vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup_vmo);
EXPECT_TRUE(status == ZX_OK);
- // TODO(SCN-273): When VK_HOST_MEMORY is supported, this test should be
- // converted over. It only works now because we test on UMA platforms.
- EXPECT_TRUE(Apply(scenic::NewCreateMemoryCmd(
- 1, std::move(dup_vmo), vmo_size,
- fuchsia::images::MemoryType::VK_DEVICE_MEMORY)));
+ EXPECT_TRUE(Apply(
+ scenic::NewCreateMemoryCmd(1, std::move(dup_vmo), vmo_size,
+ fuchsia::images::MemoryType::HOST_MEMORY)));
EXPECT_TRUE(Apply(scenic::NewCreateBufferCmd(2, 1, 0, vmo_size)));
EXPECT_TRUE(
Apply(scenic::NewCreateBufferCmd(3, 1, offset, vmo_size - offset)));
diff --git a/public/lib/escher/BUILD.gn b/public/lib/escher/BUILD.gn
index f8ef6cf..4b55b9c 100644
--- a/public/lib/escher/BUILD.gn
+++ b/public/lib/escher/BUILD.gn
@@ -452,12 +452,10 @@
"util/tracer.h",
"vk/buffer.cc",
"vk/buffer.h",
- "vk/buffer_factory.cc",
"vk/buffer_factory.h",
"vk/command_buffer.h",
"vk/framebuffer.cc",
"vk/framebuffer.h",
- "vk/gpu_allocator.cc",
"vk/gpu_allocator.h",
"vk/gpu_mem.cc",
"vk/gpu_mem.h",
@@ -490,8 +488,6 @@
"vk/shader_program_factory.h",
"vk/shader_variant_args.cc",
"vk/shader_variant_args.h",
- "vk/simple_image_factory.cc",
- "vk/simple_image_factory.h",
"vk/texture.cc",
"vk/texture.h",
"vk/vulkan_context.h",
diff --git a/public/lib/escher/escher.cc b/public/lib/escher/escher.cc
index c9886c8..81c7db6 100644
--- a/public/lib/escher/escher.cc
+++ b/public/lib/escher/escher.cc
@@ -196,8 +196,8 @@
vk::BufferUsageFlags usage_flags,
vk::MemoryPropertyFlags memory_property_flags) {
TRACE_DURATION("gfx", "Escher::NewBuffer");
- return Buffer::New(resource_recycler(), gpu_allocator(), size, usage_flags,
- memory_property_flags);
+ return gpu_allocator()->AllocateBuffer(resource_recycler(), size, usage_flags,
+ memory_property_flags);
}
TexturePtr Escher::NewTexture(vk::Format format, uint32_t width,
@@ -212,7 +212,8 @@
.height = height,
.sample_count = sample_count,
.usage = usage_flags};
- ImagePtr image = Image::New(resource_recycler(), image_info, gpu_allocator());
+ ImagePtr image =
+ gpu_allocator()->AllocateImage(resource_recycler(), image_info);
return fxl::MakeRefCounted<Texture>(resource_recycler(), std::move(image),
filter, aspect_flags,
use_unnormalized_coordinates);
@@ -274,7 +275,7 @@
}
uint64_t Escher::GetNumGpuBytesAllocated() {
- return gpu_allocator()->total_slab_bytes();
+ return gpu_allocator()->GetTotalBytesAllocated();
}
uint32_t Escher::GetNumOutstandingFrames() const {
diff --git a/public/lib/escher/hmd/pose_buffer_latching_shader.cc b/public/lib/escher/hmd/pose_buffer_latching_shader.cc
index 23c37b3..7628af6 100644
--- a/public/lib/escher/hmd/pose_buffer_latching_shader.cc
+++ b/public/lib/escher/hmd/pose_buffer_latching_shader.cc
@@ -10,6 +10,7 @@
#include "garnet/public/lib/escher/resources/resource_recycler.h"
#include "garnet/public/lib/escher/scene/camera.h"
#include "garnet/public/lib/escher/vk/buffer.h"
+#include "garnet/public/lib/escher/vk/gpu_allocator.h"
#include "garnet/public/lib/escher/vk/texture.h"
namespace escher {
@@ -126,9 +127,9 @@
vk::BufferUsageFlagBits::eUniformBuffer |
vk::BufferUsageFlagBits::eStorageBuffer;
- auto output_buffer = Buffer::New(
- escher_->resource_recycler(), frame->gpu_allocator(), buffer_size,
- kOutputBufferUsageFlags, kOutputMemoryPropertyFlags);
+ auto output_buffer = frame->gpu_allocator()->AllocateBuffer(
+ escher_->resource_recycler(), buffer_size, kOutputBufferUsageFlags,
+ kOutputMemoryPropertyFlags);
const vk::MemoryPropertyFlags kVpMemoryPropertyFlags =
vk::MemoryPropertyFlagBits::eHostVisible |
@@ -136,9 +137,9 @@
const vk::BufferUsageFlags kVpBufferUsageFlags =
vk::BufferUsageFlagBits::eUniformBuffer;
- auto vp_matrices_buffer = Buffer::New(
- escher_->resource_recycler(), frame->gpu_allocator(), 4 * k4x4MatrixSize,
- kVpBufferUsageFlags, kVpMemoryPropertyFlags);
+ auto vp_matrices_buffer = frame->gpu_allocator()->AllocateBuffer(
+ escher_->resource_recycler(), 4 * k4x4MatrixSize, kVpBufferUsageFlags,
+ kVpMemoryPropertyFlags);
auto command_buffer = frame->command_buffer();
diff --git a/public/lib/escher/impl/gpu_mem_slab.cc b/public/lib/escher/impl/gpu_mem_slab.cc
index 7a133aa..8fcfb8d 100644
--- a/public/lib/escher/impl/gpu_mem_slab.cc
+++ b/public/lib/escher/impl/gpu_mem_slab.cc
@@ -6,7 +6,7 @@
#include "lib/escher/impl/vulkan_utils.h"
#include "lib/escher/util/trace_macros.h"
-#include "lib/escher/vk/gpu_allocator.h"
+#include "lib/escher/vk/naive_gpu_allocator.h"
#include "lib/fxl/logging.h"
namespace {
@@ -25,58 +25,16 @@
GpuMemSlab::GpuMemSlab(vk::Device device, vk::DeviceMemory base,
vk::DeviceSize size, bool needs_mapped_ptr,
- uint32_t memory_type_index, GpuAllocator* allocator)
+ NaiveGpuAllocator* allocator)
: GpuMem(base, size, 0,
needs_mapped_ptr ? GetMappedPtr(device, base, size) : nullptr),
device_(device),
- memory_type_index_(memory_type_index),
allocator_(allocator) {
if (allocator_) {
- allocator_->OnSlabCreated(size);
+ allocator_->OnSlabCreated(this->size());
}
}
-GpuMemSlabPtr GpuMemSlab::New(vk::Device device,
- vk::PhysicalDevice physical_device,
- vk::MemoryRequirements reqs,
- vk::MemoryPropertyFlags flags,
- GpuAllocator* allocator) {
- TRACE_DURATION("gfx", "escher::GpuMemSlab::New");
- vk::DeviceMemory vk_mem;
- uint32_t memory_type_index = 0;
- bool needs_mapped_ptr = false;
- if (!device) {
- // To support testing, we allow a null device, and respond by creating
- // a GpuMemSlab with a null vk::DeviceMemory.
- } else {
- // Determine whether we will need to map the memory.
- if (flags & vk::MemoryPropertyFlagBits::eHostVisible) {
- // We don't currently provide an interface for flushing mapped data, so
- // ensure that the allocated memory is cache-coherent. This is more
- // convenient anyway.
- flags |= vk::MemoryPropertyFlagBits::eHostCoherent;
- needs_mapped_ptr = true;
- }
-
- // TODO: cache flags for efficiency? Or perhaps change signature of this
- // method to directly take the memory-type index.
- memory_type_index =
- GetMemoryTypeIndex(physical_device, reqs.memoryTypeBits, flags);
-
- {
- TRACE_DURATION("gfx", "escher::GpuMemSlab::New[alloc]");
- vk::MemoryAllocateInfo info;
- info.allocationSize = reqs.size;
- info.memoryTypeIndex = memory_type_index;
- vk_mem = ESCHER_CHECKED_VK_RESULT(device.allocateMemory(info));
- }
- }
-
- return fxl::AdoptRef(new GpuMemSlab(device, vk_mem, reqs.size,
- needs_mapped_ptr, memory_type_index,
- allocator));
-}
-
GpuMemSlab::~GpuMemSlab() {
if (device_ && base()) {
if (mapped_ptr()) {
@@ -89,12 +47,5 @@
}
}
-void GpuMemSlab::OnAllocationDestroyed(vk::DeviceSize size,
- vk::DeviceSize offset) {
- if (allocator_) {
- allocator_->OnSuballocationDestroyed(this, size, offset);
- }
-}
-
} // namespace impl
} // namespace escher
diff --git a/public/lib/escher/impl/gpu_mem_slab.h b/public/lib/escher/impl/gpu_mem_slab.h
index 34f7930..350a0ba 100644
--- a/public/lib/escher/impl/gpu_mem_slab.h
+++ b/public/lib/escher/impl/gpu_mem_slab.h
@@ -12,41 +12,31 @@
namespace escher {
-class GpuAllocator;
+class NaiveGpuAllocator;
namespace impl {
class GpuMemSlab;
typedef fxl::RefPtr<GpuMemSlab> GpuMemSlabPtr;
-// GpuMemSlab represents a single Vulkan memory allocation, which a GpuAllocator
-// may use to sub-allocate multiple GpuMem instances. It can only be created
-// via GpuMem::New() and GpuAllocator::AllocateSlab(). See class comment of
-// GpuAllocator for more details.
+// GpuMemSlab represents a single Vulkan memory allocation, created directly
+// through a vkDevice. It should only be created via specific subclasses of
+// GpuAllocator, or through GpuMem::AdoptMemory when transferring ownership of a
+// existing vk::DeviceMemory object.
class GpuMemSlab final : public GpuMem {
public:
~GpuMemSlab() override;
private:
- // Instances of GpuMemSlab may only be created by GpuAllocator::AllocateSlab()
- // and GpuMem::New().
- friend class ::escher::GpuAllocator;
+ // Instances of GpuMemSlab may only be created by
+ // NaiveGpuAllocator::AllocateMemory() and GpuMem::AdoptMemory.
+ friend class ::escher::NaiveGpuAllocator;
friend class ::escher::GpuMem;
- static GpuMemSlabPtr New(vk::Device device,
- vk::PhysicalDevice physical_device,
- vk::MemoryRequirements reqs,
- vk::MemoryPropertyFlags flags,
- GpuAllocator* allocator);
GpuMemSlab(vk::Device device, vk::DeviceMemory base, vk::DeviceSize size,
- bool needs_mapped_ptr, uint32_t memory_type_index,
- GpuAllocator* allocator);
-
- void OnAllocationDestroyed(vk::DeviceSize size,
- vk::DeviceSize offset) override;
+ bool needs_mapped_ptr, NaiveGpuAllocator* allocator);
vk::Device device_;
- uint32_t memory_type_index_;
- GpuAllocator* allocator_;
+ NaiveGpuAllocator* allocator_;
FXL_DISALLOW_COPY_AND_ASSIGN(GpuMemSlab);
};
diff --git a/public/lib/escher/impl/gpu_mem_suballocation.cc b/public/lib/escher/impl/gpu_mem_suballocation.cc
index 00ece9d..557ca4c 100644
--- a/public/lib/escher/impl/gpu_mem_suballocation.cc
+++ b/public/lib/escher/impl/gpu_mem_suballocation.cc
@@ -13,9 +13,5 @@
mem->mapped_ptr() ? mem->mapped_ptr() + offset : nullptr),
mem_(std::move(mem)) {}
-GpuMemSuballocation::~GpuMemSuballocation() {
- mem_->OnAllocationDestroyed(size(), offset());
-}
-
} // namespace impl
} // namespace escher
diff --git a/public/lib/escher/impl/gpu_mem_suballocation.h b/public/lib/escher/impl/gpu_mem_suballocation.h
index 5f77042..61041f1 100644
--- a/public/lib/escher/impl/gpu_mem_suballocation.h
+++ b/public/lib/escher/impl/gpu_mem_suballocation.h
@@ -10,13 +10,10 @@
namespace escher {
namespace impl {
-// Helper class for GpuMem::Allocate(), which returns an instance of this class.
-// When the instance is destroyed, it notifies the GpuMem that it was allocated
-// from.
+// Helper class for GpuMem::Suballocate(), which returns an instance of this
+// class. When this instance is destroyed, it releases its strong reference on
+// the backing memory object.
class GpuMemSuballocation final : public GpuMem {
- public:
- ~GpuMemSuballocation() override;
-
private:
friend class ::escher::GpuMem;
GpuMemSuballocation(GpuMemPtr mem, vk::DeviceSize size,
diff --git a/public/lib/escher/impl/gpu_uploader.cc b/public/lib/escher/impl/gpu_uploader.cc
index fa8b9a0..b332bb9 100644
--- a/public/lib/escher/impl/gpu_uploader.cc
+++ b/public/lib/escher/impl/gpu_uploader.cc
@@ -170,9 +170,8 @@
size = std::max(kMinBufferSize, size * kOverAllocationFactor);
auto memory_properties = vk::MemoryPropertyFlagBits::eHostVisible |
vk::MemoryPropertyFlagBits::eHostCoherent;
- current_buffer_ =
- Buffer::New(this, allocator_, size, vk::BufferUsageFlagBits::eTransferSrc,
- memory_properties);
+ current_buffer_ = allocator_->AllocateBuffer(
+ this, size, vk::BufferUsageFlagBits::eTransferSrc, memory_properties);
}
void GpuUploader::RecycleResource(std::unique_ptr<Resource> resource) {
diff --git a/public/lib/escher/impl/image_cache.cc b/public/lib/escher/impl/image_cache.cc
index b875e59..dce8c60 100644
--- a/public/lib/escher/impl/image_cache.cc
+++ b/public/lib/escher/impl/image_cache.cc
@@ -29,9 +29,10 @@
// Allocate memory and bind it to the image.
vk::MemoryRequirements reqs = vk_device().getImageMemoryRequirements(image);
- GpuMemPtr memory = allocator_->Allocate(reqs, info.memory_flags);
+ GpuMemPtr memory = allocator_->AllocateMemory(reqs, info.memory_flags);
- ImagePtr escher_image = Image::New(this, info, image, std::move(memory));
+ ImagePtr escher_image =
+ Image::AdoptVkImage(this, info, image, std::move(memory));
FXL_CHECK(escher_image);
return escher_image;
diff --git a/public/lib/escher/impl/mesh_manager.cc b/public/lib/escher/impl/mesh_manager.cc
index c1f63e0..61e1e98 100644
--- a/public/lib/escher/impl/mesh_manager.cc
+++ b/public/lib/escher/impl/mesh_manager.cc
@@ -11,6 +11,7 @@
#include "lib/escher/impl/vulkan_utils.h"
#include "lib/escher/resources/resource_recycler.h"
#include "lib/escher/vk/buffer.h"
+#include "lib/escher/vk/gpu_allocator.h"
#include "lib/escher/vk/vulkan_context.h"
namespace escher {
@@ -114,18 +115,18 @@
GpuAllocator* allocator = manager_->allocator_;
// TODO: use eTransferDstOptimal instead of eTransferDst?
- auto vertex_buffer = Buffer::New(manager_->resource_recycler(), allocator,
- vertex_count_ * vertex_stride_,
- vk::BufferUsageFlagBits::eVertexBuffer |
- vk::BufferUsageFlagBits::eTransferSrc |
- vk::BufferUsageFlagBits::eTransferDst,
- vk::MemoryPropertyFlagBits::eDeviceLocal);
- auto index_buffer = Buffer::New(manager_->resource_recycler(), allocator,
- index_count_ * sizeof(uint32_t),
- vk::BufferUsageFlagBits::eIndexBuffer |
- vk::BufferUsageFlagBits::eTransferSrc |
- vk::BufferUsageFlagBits::eTransferDst,
- vk::MemoryPropertyFlagBits::eDeviceLocal);
+ auto vertex_buffer = allocator->AllocateBuffer(
+ manager_->resource_recycler(), vertex_count_ * vertex_stride_,
+ vk::BufferUsageFlagBits::eVertexBuffer |
+ vk::BufferUsageFlagBits::eTransferSrc |
+ vk::BufferUsageFlagBits::eTransferDst,
+ vk::MemoryPropertyFlagBits::eDeviceLocal);
+ auto index_buffer = allocator->AllocateBuffer(
+ manager_->resource_recycler(), index_count_ * sizeof(uint32_t),
+ vk::BufferUsageFlagBits::eIndexBuffer |
+ vk::BufferUsageFlagBits::eTransferSrc |
+ vk::BufferUsageFlagBits::eTransferDst,
+ vk::MemoryPropertyFlagBits::eDeviceLocal);
vertex_writer_.WriteBuffer(vertex_buffer, {0, 0, vertex_buffer->size()},
Semaphore::New(device));
diff --git a/public/lib/escher/impl/uniform_buffer_pool.cc b/public/lib/escher/impl/uniform_buffer_pool.cc
index 271b139..ffa5241 100644
--- a/public/lib/escher/impl/uniform_buffer_pool.cc
+++ b/public/lib/escher/impl/uniform_buffer_pool.cc
@@ -58,7 +58,7 @@
// Allocate enough memory for all of the buffers.
reqs.size *= kBufferBatchSize;
- auto batch_mem = allocator_->Allocate(reqs, flags_);
+ auto batch_mem = allocator_->AllocateMemory(reqs, flags_);
// See below: when OnReceiveOwnable() receives the newly-allocated buffer we
// need to know that it is new and can therefore be used immediately instead
@@ -73,7 +73,7 @@
vk_device().getBufferMemoryRequirements(new_buffers[i]);
// Sub-allocate memory for each buffer.
- auto mem = batch_mem->Allocate(buffer_size_, i * buffer_size_);
+ auto mem = batch_mem->Suballocate(buffer_size_, i * buffer_size_);
// Workaround for dealing with RefPtr/Reffable Adopt() semantics. Let the
// RefPtr go out of scope immediately; the Buffer will be added to
diff --git a/public/lib/escher/impl/vulkan_utils.cc b/public/lib/escher/impl/vulkan_utils.cc
index 8ef6f31..1eef9d5 100644
--- a/public/lib/escher/impl/vulkan_utils.cc
+++ b/public/lib/escher/impl/vulkan_utils.cc
@@ -55,7 +55,8 @@
}
type_bits >>= 1;
}
- FXL_CHECK(false);
+ FXL_CHECK(false) << "Could not find memory with properties "
+ << (VkMemoryPropertyFlags)required_properties;
return 0;
}
diff --git a/public/lib/escher/impl/wobble_modifier_absorber.cc b/public/lib/escher/impl/wobble_modifier_absorber.cc
index a96f167..d2d234f 100644
--- a/public/lib/escher/impl/wobble_modifier_absorber.cc
+++ b/public/lib/escher/impl/wobble_modifier_absorber.cc
@@ -6,6 +6,7 @@
#include "lib/escher/escher.h"
#include "lib/escher/impl/command_buffer_pool.h"
#include "lib/escher/resources/resource_recycler.h"
+#include "lib/escher/vk/gpu_allocator.h"
namespace escher {
namespace impl {
@@ -131,11 +132,11 @@
auto& vertex_buffer = object.shape().mesh()->attribute_buffer(0).buffer;
auto compute_buffer =
- Buffer::New(recycler_, allocator_, vertex_buffer->size(),
- vk::BufferUsageFlagBits::eVertexBuffer |
- vk::BufferUsageFlagBits::eStorageBuffer |
- vk::BufferUsageFlagBits::eTransferDst,
- vk::MemoryPropertyFlagBits::eDeviceLocal);
+ allocator_->AllocateBuffer(recycler_, vertex_buffer->size(),
+ vk::BufferUsageFlagBits::eVertexBuffer |
+ vk::BufferUsageFlagBits::eStorageBuffer |
+ vk::BufferUsageFlagBits::eTransferDst,
+ vk::MemoryPropertyFlagBits::eDeviceLocal);
// TODO(longqic): Do not allocate a new uniform buffer for each new object.
// See ModelDisplayListBuilder::PrepareUniformBufferForWriteOfSize().
auto per_object_uniform_buffer =
@@ -212,9 +213,9 @@
}
BufferPtr WobbleModifierAbsorber::NewUniformBuffer(vk::DeviceSize size) {
- return Buffer::New(recycler_, allocator_, size,
- vk::BufferUsageFlagBits::eUniformBuffer,
- vk::MemoryPropertyFlagBits::eHostVisible);
+ return allocator_->AllocateBuffer(recycler_, size,
+ vk::BufferUsageFlagBits::eUniformBuffer,
+ vk::MemoryPropertyFlagBits::eHostVisible);
}
void WobbleModifierAbsorber::ApplyBarrierForUniformBuffer(
diff --git a/public/lib/escher/renderer/buffer_cache.cc b/public/lib/escher/renderer/buffer_cache.cc
index dfe3a0f..025fbe3 100644
--- a/public/lib/escher/renderer/buffer_cache.cc
+++ b/public/lib/escher/renderer/buffer_cache.cc
@@ -66,8 +66,8 @@
free_buffers_by_id_.erase(info_itr);
} else {
// Construct a new buffer of the requested size.
- buffer = Buffer::New(this, gpu_allocator_.get(), vk_size, kUsageFlags,
- kMemoryPropertyFlags);
+ buffer = gpu_allocator_->AllocateBuffer(this, vk_size, kUsageFlags,
+ kMemoryPropertyFlags);
}
return buffer;
diff --git a/public/lib/escher/shape/rounded_rect_factory.cc b/public/lib/escher/shape/rounded_rect_factory.cc
index 028f0f9..f1385e3 100644
--- a/public/lib/escher/shape/rounded_rect_factory.cc
+++ b/public/lib/escher/shape/rounded_rect_factory.cc
@@ -14,7 +14,8 @@
RoundedRectFactory::RoundedRectFactory(EscherWeakPtr weak_escher)
: ResourceRecycler(std::move(weak_escher)),
- buffer_factory_(std::make_unique<BufferFactory>(GetEscherWeakPtr())) {}
+ buffer_factory_(GetEscherWeakPtr()->gpu_allocator(),
+ GetEscherWeakPtr()->resource_recycler()) {}
RoundedRectFactory::~RoundedRectFactory() {}
@@ -35,10 +36,10 @@
vertex_count * (primary_buffer_stride + secondary_buffer_stride);
auto vertex_buffer =
- buffer_factory_->NewBuffer(vertex_buffer_size,
- vk::BufferUsageFlagBits::eVertexBuffer |
- vk::BufferUsageFlagBits::eTransferDst,
- vk::MemoryPropertyFlagBits::eDeviceLocal);
+ buffer_factory_.NewBuffer(vertex_buffer_size,
+ vk::BufferUsageFlagBits::eVertexBuffer |
+ vk::BufferUsageFlagBits::eTransferDst,
+ vk::MemoryPropertyFlagBits::eDeviceLocal);
const auto bounding_box =
BoundingBox::NewChecked(-0.5f * vec3(spec.width, spec.height, 0),
@@ -92,10 +93,10 @@
size_t index_buffer_size = index_count * sizeof(MeshSpec::IndexType);
index_buffer_ =
- buffer_factory_->NewBuffer(index_buffer_size,
- vk::BufferUsageFlagBits::eIndexBuffer |
- vk::BufferUsageFlagBits::eTransferDst,
- vk::MemoryPropertyFlagBits::eDeviceLocal);
+ buffer_factory_.NewBuffer(index_buffer_size,
+ vk::BufferUsageFlagBits::eIndexBuffer |
+ vk::BufferUsageFlagBits::eTransferDst,
+ vk::MemoryPropertyFlagBits::eDeviceLocal);
auto writer = batch_gpu_uploader->AcquireWriter(index_buffer_size);
GenerateRoundedRectIndices(spec, mesh_spec, writer->host_ptr(),
diff --git a/public/lib/escher/shape/rounded_rect_factory.h b/public/lib/escher/shape/rounded_rect_factory.h
index 751ce7b..f80f4f2 100644
--- a/public/lib/escher/shape/rounded_rect_factory.h
+++ b/public/lib/escher/shape/rounded_rect_factory.h
@@ -7,11 +7,11 @@
#include "lib/escher/resources/resource_recycler.h"
#include "lib/escher/shape/rounded_rect.h"
+#include "lib/escher/vk/buffer_factory.h"
namespace escher {
class BatchGpuUploader;
-class BufferFactory;
class RoundedRectFactory : private ResourceRecycler {
public:
@@ -26,8 +26,7 @@
const MeshSpec& mesh_spec,
BatchGpuUploader* gpu_uploader);
- std::unique_ptr<BufferFactory> buffer_factory_;
-
+ BufferFactoryAdapter buffer_factory_;
BufferPtr index_buffer_;
};
diff --git a/public/lib/escher/test/gpu_mem_unittest.cc b/public/lib/escher/test/gpu_mem_unittest.cc
index 44ff107..3907a42 100644
--- a/public/lib/escher/test/gpu_mem_unittest.cc
+++ b/public/lib/escher/test/gpu_mem_unittest.cc
@@ -3,11 +3,13 @@
// found in the LICENSE file.
#include "lib/escher/vk/gpu_mem.h"
+#include "gtest/gtest.h"
#include "lib/escher/impl/gpu_mem_slab.h"
+#include "lib/escher/test/gtest_vulkan.h"
#include "lib/escher/vk/gpu_allocator.h"
#include "lib/escher/vk/naive_gpu_allocator.h"
-
-#include "gtest/gtest.h"
+#include "lib/escher/vk/vulkan_context.h"
+#include "lib/escher/vk/vulkan_device_queues.h"
#include <iostream>
@@ -18,10 +20,10 @@
// different ways.
const vk::DeviceSize kDeviceSize = 1000;
void TestSubAllocation(GpuMemPtr mem) {
- auto sub_alloc1 = mem->Allocate(kDeviceSize, 0);
- auto sub_alloc2 = mem->Allocate(kDeviceSize + 1, 0);
- auto sub_alloc3 = mem->Allocate(kDeviceSize, 1);
- auto sub_alloc4 = mem->Allocate(kDeviceSize, 0);
+ auto sub_alloc1 = mem->Suballocate(kDeviceSize, 0);
+ auto sub_alloc2 = mem->Suballocate(kDeviceSize + 1, 0);
+ auto sub_alloc3 = mem->Suballocate(kDeviceSize, 1);
+ auto sub_alloc4 = mem->Suballocate(kDeviceSize, 0);
// Valid sub-allocation.
EXPECT_NE(nullptr, sub_alloc1.get());
// Invalid sub-allocation due to increased size.
@@ -32,14 +34,14 @@
EXPECT_NE(nullptr, sub_alloc4.get());
// Can sub-allocate from a sub-allocation...
- auto sub_alloc5 = sub_alloc1->Allocate(kDeviceSize / 2, kDeviceSize / 2);
+ auto sub_alloc5 = sub_alloc1->Suballocate(kDeviceSize / 2, kDeviceSize / 2);
EXPECT_NE(nullptr, sub_alloc5.get());
// ... and sub-allocate again from that sub-allocation. As before, the size
// and offset of the sub-allocation must fit within the parent.
- auto sub_alloc6 = sub_alloc5->Allocate(kDeviceSize / 2, 0);
- auto sub_alloc7 = sub_alloc5->Allocate(kDeviceSize / 2 + 1, 0);
- auto sub_alloc8 = sub_alloc5->Allocate(kDeviceSize / 2, 1);
- auto sub_alloc9 = sub_alloc5->Allocate(kDeviceSize / 2, 0);
+ auto sub_alloc6 = sub_alloc5->Suballocate(kDeviceSize / 2, 0);
+ auto sub_alloc7 = sub_alloc5->Suballocate(kDeviceSize / 2 + 1, 0);
+ auto sub_alloc8 = sub_alloc5->Suballocate(kDeviceSize / 2, 1);
+ auto sub_alloc9 = sub_alloc5->Suballocate(kDeviceSize / 2, 0);
// Valid sub-allocation.
EXPECT_NE(nullptr, sub_alloc6.get());
// Invalid sub-allocation due to increased size.
@@ -52,126 +54,56 @@
// This test should be updated to include all hashed types used by Escher.
TEST(GpuMem, WrapExisting) {
- const uint32_t kMemoryTypeIndex = 0;
- auto mem = GpuMem::New(vk::Device(), vk::DeviceMemory(), kDeviceSize,
- false /* needs_mapped_ptr */, kMemoryTypeIndex);
+ auto mem = GpuMem::AdoptVkMemory(vk::Device(), vk::DeviceMemory(),
+ kDeviceSize, false /* needs_mapped_ptr */);
TestSubAllocation(mem);
}
-TEST(GpuMem, NaiveAllocator) {
- VulkanContext context(vk::Instance(), vk::PhysicalDevice(), vk::Device(),
- vk::Queue(), 0, vk::Queue(), 0);
- NaiveGpuAllocator allocator(context);
+VK_TEST(GpuMem, NaiveAllocator) {
+ escher::VulkanInstance::Params instance_params(
+ {{"VK_LAYER_LUNARG_standard_validation"},
+ {VK_EXT_DEBUG_REPORT_EXTENSION_NAME},
+ false});
+
+ auto vulkan_instance =
+ escher::VulkanInstance::New(std::move(instance_params));
+ auto vulkan_device = escher::VulkanDeviceQueues::New(vulkan_instance, {});
+ NaiveGpuAllocator allocator(vulkan_device->GetVulkanContext());
// Standard sub-allocation tests.
- auto alloc =
- allocator.Allocate({kDeviceSize, 0, 0}, vk::MemoryPropertyFlags());
- EXPECT_EQ(kDeviceSize, allocator.total_slab_bytes());
+ auto alloc = allocator.AllocateMemory(
+ {kDeviceSize, 0, 0xffffffff}, vk::MemoryPropertyFlagBits::eDeviceLocal);
+ EXPECT_EQ(kDeviceSize, allocator.GetTotalBytesAllocated());
TestSubAllocation(alloc);
// Adding sub-allocations doesn't increase slab-count.
- EXPECT_EQ(1U, allocator.slab_count());
- auto sub_alloc1 = alloc->Allocate(kDeviceSize, 0);
- auto sub_alloc1a = sub_alloc1->Allocate(kDeviceSize, 0);
- auto sub_alloc1b = sub_alloc1->Allocate(kDeviceSize, 0);
- auto sub_alloc2 = alloc->Allocate(kDeviceSize, 0);
- auto sub_alloc2a = sub_alloc2->Allocate(kDeviceSize, 0);
- auto sub_alloc2b = sub_alloc2->Allocate(kDeviceSize, 0);
- EXPECT_EQ(1U, allocator.slab_count());
+ EXPECT_EQ(kDeviceSize, allocator.GetTotalBytesAllocated());
+ auto sub_alloc1 = alloc->Suballocate(kDeviceSize, 0);
+ auto sub_alloc1a = sub_alloc1->Suballocate(kDeviceSize, 0);
+ auto sub_alloc1b = sub_alloc1->Suballocate(kDeviceSize, 0);
+ auto sub_alloc2 = alloc->Suballocate(kDeviceSize, 0);
+ auto sub_alloc2a = sub_alloc2->Suballocate(kDeviceSize, 0);
+ auto sub_alloc2b = sub_alloc2->Suballocate(kDeviceSize, 0);
+ EXPECT_EQ(kDeviceSize, allocator.GetTotalBytesAllocated());
// Allocating then freeing increases/decreases the slab-count.
- auto alloc2 =
- allocator.Allocate({kDeviceSize, 0, 0}, vk::MemoryPropertyFlags());
- EXPECT_EQ(2U * kDeviceSize, allocator.total_slab_bytes());
- EXPECT_EQ(2U, allocator.slab_count());
+ auto alloc2 = allocator.AllocateMemory(
+ {kDeviceSize, 0, 0xffffffff}, vk::MemoryPropertyFlagBits::eHostVisible);
+ EXPECT_EQ(2U * kDeviceSize, allocator.GetTotalBytesAllocated());
alloc2 = nullptr;
- EXPECT_EQ(1U, allocator.slab_count());
+ EXPECT_EQ(kDeviceSize, allocator.GetTotalBytesAllocated());
// Sub-allocations keep parent allocations alive.
alloc = nullptr;
- EXPECT_EQ(1U, allocator.slab_count());
+ EXPECT_EQ(kDeviceSize, allocator.GetTotalBytesAllocated());
sub_alloc1 = nullptr;
sub_alloc1a = nullptr;
sub_alloc1b = nullptr;
sub_alloc2 = nullptr;
sub_alloc2a = nullptr;
- EXPECT_EQ(1U, allocator.slab_count());
- EXPECT_EQ(kDeviceSize, allocator.total_slab_bytes());
+ EXPECT_EQ(kDeviceSize, allocator.GetTotalBytesAllocated());
sub_alloc2b = nullptr;
- EXPECT_EQ(0U, allocator.slab_count());
- EXPECT_EQ(0U, allocator.total_slab_bytes());
-}
-
-// Used to test GpuAllocator sub-allocation callbacks.
-class NaiveGpuAllocatorForCallbackTest : public NaiveGpuAllocator {
- public:
- explicit NaiveGpuAllocatorForCallbackTest(GpuMem** last_slab,
- vk::DeviceSize* last_size,
- vk::DeviceSize* last_offset)
- : NaiveGpuAllocator(VulkanContext()),
- last_slab_(last_slab),
- last_size_(last_size),
- last_offset_(last_offset) {}
-
- void OnSuballocationDestroyed(GpuMem* slab, vk::DeviceSize size,
- vk::DeviceSize offset) override {
- *last_slab_ = slab;
- *last_size_ = size;
- *last_offset_ = offset;
- }
-
- private:
- GpuMem** const last_slab_ = nullptr;
- vk::DeviceSize* const last_size_ = nullptr;
- vk::DeviceSize* const last_offset_ = nullptr;
-};
-
-// Note: this test relies on an allocator that returns raw GpuMemSlabs, not
-// sub-allocations.
-TEST(GpuMem, AllocatorCallbacks) {
- GpuMem* last_slab = nullptr;
- vk::DeviceSize last_size = 0;
- vk::DeviceSize last_offset = 0;
- NaiveGpuAllocatorForCallbackTest allocator(&last_slab, &last_size,
- &last_offset);
-
- auto alloc1 =
- allocator.Allocate({kDeviceSize, 0, 0}, vk::MemoryPropertyFlags());
- auto alloc2 =
- allocator.Allocate({kDeviceSize, 0, 0}, vk::MemoryPropertyFlags());
- EXPECT_EQ(nullptr, last_slab);
-
- auto sub_alloc1a = alloc1->Allocate(10, 11);
- auto sub_alloc1b = alloc1->Allocate(20, 12);
- auto sub_alloc2a = alloc2->Allocate(30, 13);
- auto sub_alloc2b = alloc2->Allocate(40, 14);
- // Still no sub-allocations destroyed.
- EXPECT_EQ(nullptr, last_slab);
-
- auto sub_sub_alloc = sub_alloc1a->Allocate(1, 1);
- sub_alloc1a = nullptr;
- // sub_alloc1a is kept alive by sub_sub_alloc.
- EXPECT_EQ(nullptr, last_slab);
-
- // Trigger the first notification.
- sub_sub_alloc = nullptr;
- EXPECT_EQ(alloc1.get(), last_slab);
- EXPECT_EQ(10U, last_size);
- EXPECT_EQ(11U, last_offset);
-
- // Finish the rest in different order than initial allocations.
- sub_alloc2b = nullptr;
- EXPECT_EQ(alloc2.get(), last_slab);
- EXPECT_EQ(40U, last_size);
- EXPECT_EQ(14U, last_offset);
- sub_alloc2a = nullptr;
- EXPECT_EQ(alloc2.get(), last_slab);
- EXPECT_EQ(30U, last_size);
- EXPECT_EQ(13U, last_offset);
- sub_alloc1b = nullptr;
- EXPECT_EQ(alloc1.get(), last_slab);
- EXPECT_EQ(20U, last_size);
- EXPECT_EQ(12U, last_offset);
+ EXPECT_EQ(0U, allocator.GetTotalBytesAllocated());
}
namespace {
@@ -197,9 +129,9 @@
GpuMemPtr mem =
fxl::MakeRefCounted<FakeGpuMem>(kVkMem, kSize0, kOffset0, nullptr);
- auto sub = mem->Allocate(kSize1, kOffset1);
- auto subsub = sub->Allocate(kSize2, kOffset2);
- auto subsubsub = subsub->Allocate(kSize3, kOffset3);
+ auto sub = mem->Suballocate(kSize1, kOffset1);
+ auto subsub = sub->Suballocate(kSize2, kOffset2);
+ auto subsubsub = subsub->Suballocate(kSize3, kOffset3);
EXPECT_NE(vk::DeviceMemory(), mem->base());
EXPECT_EQ(mem->base(), sub->base());
@@ -225,16 +157,16 @@
GpuMemPtr mem = fxl::MakeRefCounted<FakeGpuMem>(vk::DeviceMemory(), kSize1,
kOffset1, kNullPtr);
- GpuMemPtr sub = mem->Allocate(kSize2, kOffset2);
- GpuMemPtr subsub = sub->Allocate(kSize3, kOffset3);
+ GpuMemPtr sub = mem->Suballocate(kSize2, kOffset2);
+ GpuMemPtr subsub = sub->Suballocate(kSize3, kOffset3);
EXPECT_EQ(nullptr, mem->mapped_ptr());
EXPECT_EQ(nullptr, sub->mapped_ptr());
EXPECT_EQ(nullptr, subsub->mapped_ptr());
mem = fxl::MakeRefCounted<FakeGpuMem>(vk::DeviceMemory(), kSize1, kOffset1,
kFakePtr);
- sub = mem->Allocate(kSize2, kOffset2);
- subsub = sub->Allocate(kSize3, kOffset3);
+ sub = mem->Suballocate(kSize2, kOffset2);
+ subsub = sub->Suballocate(kSize3, kOffset3);
EXPECT_EQ(kFakePtr, mem->mapped_ptr());
EXPECT_EQ(static_cast<ptrdiff_t>(kOffset2),
sub->mapped_ptr() - mem->mapped_ptr());
diff --git a/public/lib/escher/test/pose_buffer_latching_test.cc b/public/lib/escher/test/pose_buffer_latching_test.cc
index 13b2265..bd9271a 100644
--- a/public/lib/escher/test/pose_buffer_latching_test.cc
+++ b/public/lib/escher/test/pose_buffer_latching_test.cc
@@ -3,15 +3,16 @@
// found in the LICENSE file.
#include "garnet/public/lib/escher/escher.h"
+#include "garnet/public/lib/escher/hmd/pose_buffer.h"
#include "garnet/public/lib/escher/hmd/pose_buffer_latching_shader.h"
#include "garnet/public/lib/escher/renderer/frame.h"
#include "garnet/public/lib/escher/resources/resource_recycler.h"
#include "garnet/public/lib/escher/scene/camera.h"
#include "garnet/public/lib/escher/test/gtest_vulkan.h"
+#include "garnet/public/lib/escher/util/epsilon_compare.h"
#include "garnet/public/lib/escher/vk/buffer.h"
+#include "garnet/public/lib/escher/vk/gpu_allocator.h"
#include "gtest/gtest.h"
-#include "lib/escher/hmd/pose_buffer.h"
-#include "lib/escher/util/epsilon_compare.h"
#include <glm/gtc/type_ptr.hpp>
@@ -79,11 +80,10 @@
vk::BufferUsageFlagBits::eStorageBuffer;
// Create the shader.
- hmd::PoseBuffer pose_buffer(
- escher::Buffer::New(escher->resource_recycler(), frame->gpu_allocator(),
- pose_buffer_size, buffer_usage_flags,
- memory_property_flags),
- num_entries, base_time, time_interval);
+ hmd::PoseBuffer pose_buffer(escher->gpu_allocator()->AllocateBuffer(
+ escher->resource_recycler(), pose_buffer_size,
+ buffer_usage_flags, memory_property_flags),
+ num_entries, base_time, time_interval);
hmd::PoseBufferLatchingShader test_shader(escher->GetWeakPtr());
diff --git a/public/lib/escher/test/renderer/batch_gpu_uploader_unittest.cc b/public/lib/escher/test/renderer/batch_gpu_uploader_unittest.cc
index 08c58bc..bf9e744 100644
--- a/public/lib/escher/test/renderer/batch_gpu_uploader_unittest.cc
+++ b/public/lib/escher/test/renderer/batch_gpu_uploader_unittest.cc
@@ -122,7 +122,8 @@
const size_t buffer_size = 3 * sizeof(vec3);
auto writer = uploader->AcquireWriter(buffer_size);
// Create buffer to write to.
- BufferFactory buffer_factory(escher);
+ BufferFactoryAdapter buffer_factory(escher->gpu_allocator(),
+ escher->resource_recycler());
BufferPtr vertex_buffer =
buffer_factory.NewBuffer(buffer_size,
vk::BufferUsageFlagBits::eVertexBuffer |
@@ -189,7 +190,7 @@
region.imageExtent.width = image->width();
region.imageExtent.height = image->height();
region.imageExtent.depth = 1;
- region.bufferOffset = image->memory_offset();
+ region.bufferOffset = image->memory()->offset();
BatchGpuUploaderPtr uploader = BatchGpuUploader::New(escher, 0);
auto reader = uploader->AcquireReader(image->memory()->size());
@@ -210,7 +211,8 @@
auto escher = test::GetEscher()->GetWeakPtr();
// Create buffer to read from.
const size_t buffer_size = 3 * sizeof(vec3);
- BufferFactory buffer_factory(escher);
+ BufferFactoryAdapter buffer_factory(escher->gpu_allocator(),
+ escher->resource_recycler());
BufferPtr vertex_buffer =
buffer_factory.NewBuffer(buffer_size,
vk::BufferUsageFlagBits::eVertexBuffer |
diff --git a/public/lib/escher/test/vk/buffer_unittest.cc b/public/lib/escher/test/vk/buffer_unittest.cc
index c1386a6..f24440a 100644
--- a/public/lib/escher/test/vk/buffer_unittest.cc
+++ b/public/lib/escher/test/vk/buffer_unittest.cc
@@ -23,19 +23,19 @@
// This is silly, but without creating a buffer, I don't understand how to
// populate vk::MemoryRequirements::memoryTypeBits.
- auto dummy_buffer = Buffer::New(recycler, allocator, kDummyBufferSize,
- kBufferUsageFlags, kMemoryPropertyFlags);
+ auto dummy_buffer = allocator->AllocateBuffer(
+ recycler, kDummyBufferSize, kBufferUsageFlags, kMemoryPropertyFlags);
vk::MemoryRequirements reqs =
escher->vk_device().getBufferMemoryRequirements(dummy_buffer->vk());
// Now that we have the memory requirements, we can allocate some memory, so
// that we can test creating a buffer with pre-existing memory.
- auto mem1 = allocator->Allocate(reqs, kMemoryPropertyFlags);
+ auto mem1 = allocator->AllocateMemory(reqs, kMemoryPropertyFlags);
// Suballocate some memory.
constexpr vk::DeviceSize kBufferSize = 1000;
constexpr vk::DeviceSize kOffset = 512;
- auto mem2 = mem1->Allocate(kBufferSize, kOffset);
+ auto mem2 = mem1->Suballocate(kBufferSize, kOffset);
EXPECT_EQ(mem1->mapped_ptr() + kOffset, mem2->mapped_ptr());
// Allocate 2 buffers, one from the original allocation, and one from the
diff --git a/public/lib/escher/vk/buffer.cc b/public/lib/escher/vk/buffer.cc
index 4fb2461..3dceae8 100644
--- a/public/lib/escher/vk/buffer.cc
+++ b/public/lib/escher/vk/buffer.cc
@@ -15,50 +15,9 @@
ResourceType::kWaitableResource,
ResourceType::kBuffer);
-BufferPtr Buffer::New(ResourceManager* manager, GpuAllocator* allocator,
- vk::DeviceSize size, vk::BufferUsageFlags usage_flags,
- vk::MemoryPropertyFlags memory_property_flags,
- GpuMemPtr* out_ptr) {
- TRACE_DURATION("gfx", "escher::Buffer::New[allocator]");
- FXL_DCHECK(manager);
-
- auto device = manager->vulkan_context().device;
- FXL_DCHECK(device);
-
- // Create buffer.
- vk::BufferCreateInfo buffer_create_info;
- buffer_create_info.size = size;
- buffer_create_info.usage = usage_flags;
- buffer_create_info.sharingMode = vk::SharingMode::eExclusive;
- auto vk_buffer =
- ESCHER_CHECKED_VK_RESULT(device.createBuffer(buffer_create_info));
-
- auto memory_requirements = device.getBufferMemoryRequirements(vk_buffer);
-
- // Allocate memory for the buffer.
- //
- // Note that while code could use the other factory function to construct an
- // escher::Buffer object while holding onto the GpuMemPtr, it would result in
- // duplicate work, as the memory requirements are only known after parsing the
- // vkBufferCreateInfo struct and producing a valid vkHandle.
- GpuMemPtr mem;
- if (allocator) {
- mem = allocator->Allocate(memory_requirements, memory_property_flags);
- } else {
- mem = GpuMem::New(device, manager->vulkan_context().physical_device,
- memory_requirements, memory_property_flags);
- }
-
- if (out_ptr) {
- *out_ptr = mem;
- }
-
- return fxl::MakeRefCounted<Buffer>(manager, std::move(mem), vk_buffer);
-}
-
BufferPtr Buffer::New(ResourceManager* manager, GpuMemPtr mem,
vk::BufferUsageFlags usage_flags) {
- TRACE_DURATION("gfx", "escher::Buffer::New[mem]");
+ TRACE_DURATION("gfx", "escher::Buffer::New");
auto device = manager->vulkan_context().device;
// Create buffer.
diff --git a/public/lib/escher/vk/buffer.h b/public/lib/escher/vk/buffer.h
index 916503a..d8ded06 100644
--- a/public/lib/escher/vk/buffer.h
+++ b/public/lib/escher/vk/buffer.h
@@ -20,11 +20,6 @@
static const ResourceTypeInfo kTypeInfo;
const ResourceTypeInfo& type_info() const override { return kTypeInfo; }
- static BufferPtr New(ResourceManager* manager, GpuAllocator* allocator,
- vk::DeviceSize size, vk::BufferUsageFlags usage_flags,
- vk::MemoryPropertyFlags memory_property_flags,
- GpuMemPtr* out_ptr = nullptr);
-
static BufferPtr New(ResourceManager* manager, GpuMemPtr mem,
vk::BufferUsageFlags usage_flags);
diff --git a/public/lib/escher/vk/buffer_factory.cc b/public/lib/escher/vk/buffer_factory.cc
deleted file mode 100644
index e71de81..0000000
--- a/public/lib/escher/vk/buffer_factory.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2017 The Fuchsia 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 "lib/escher/vk/buffer_factory.h"
-#include "lib/escher/vk/gpu_mem.h"
-
-#include "lib/escher/escher.h"
-
-namespace escher {
-
-BufferFactory::BufferFactory(EscherWeakPtr escher)
- : ResourceRecycler(std::move(escher)) {}
-
-BufferPtr BufferFactory::NewBuffer(
- vk::DeviceSize size, vk::BufferUsageFlags usage_flags,
- vk::MemoryPropertyFlags memory_property_flags) {
- return Buffer::New(this, escher()->gpu_allocator(), size, usage_flags,
- memory_property_flags);
-}
-
-BufferPtr BufferFactory::NewBuffer(GpuMemPtr mem,
- vk::BufferUsageFlags usage_flags) {
- return Buffer::New(this, mem, usage_flags);
-}
-
-} // namespace escher
diff --git a/public/lib/escher/vk/buffer_factory.h b/public/lib/escher/vk/buffer_factory.h
index e87d303..30f2de8 100644
--- a/public/lib/escher/vk/buffer_factory.h
+++ b/public/lib/escher/vk/buffer_factory.h
@@ -5,30 +5,53 @@
#ifndef LIB_ESCHER_VK_BUFFER_FACTORY_H_
#define LIB_ESCHER_VK_BUFFER_FACTORY_H_
-#include "lib/escher/resources/resource_recycler.h"
+#include "lib/escher/resources/resource_manager.h"
#include "lib/escher/vk/buffer.h"
+#include "lib/escher/vk/gpu_allocator.h"
namespace escher {
-// BufferFactory allows clients to obtain unused Buffers with the desired
-// properties. The default implementation allocates memory and creates a new
-// Buffer, but subclasses may override this behavior, e.g. to support efficient
-// recycling of fixed-size Buffers.
-class BufferFactory : private ResourceRecycler {
+// BufferFactory allows clients to obtain new Buffers with the desired
+// properties. Subclasses are free to implement custom caching/recycling
+// behaviors. All buffers obtained from a BufferFactory must be released before
+// the BufferFactory is destroyed.
+class BufferFactory {
public:
- explicit BufferFactory(EscherWeakPtr escher);
+ virtual ~BufferFactory() = default;
- // Creates a buffer, along with a new memory.
+ // Creates a buffer, backed by a block of memory. If |out_ptr| is non-null,
+ // the buffer will be bound to a dedicated piece of memory (i.e.,
+ // VkMemoryDedicatedRequirements.requiresDedicatedAllocation
+ // == true). That memory must be accessable through the GpuMem returned in
+ // |out_ptr|.
virtual BufferPtr NewBuffer(vk::DeviceSize size,
vk::BufferUsageFlags usage_flags,
- vk::MemoryPropertyFlags memory_property_flags);
+ vk::MemoryPropertyFlags memory_property_flags,
+ GpuMemPtr* out_ptr = nullptr) = 0;
+};
- // Creates a buffer for the given memory.
- virtual BufferPtr NewBuffer(GpuMemPtr mem, vk::BufferUsageFlags usage_flags);
+// This default implementation allocates memory and creates a new
+// Buffer using the provided allocator and manager. The intent is for this class
+// to adapt existing GpuAllocators to the BufferFactory interface (i.e.
+// equivalent to a partial bind). Classes that wish to implement their own
+// caching logic should subclass BufferFactory directly, instead of injecting
+// tricky subclasses of GpuAllocator and ResourceManager into this object.
+class BufferFactoryAdapter final : public BufferFactory {
+ public:
+ BufferFactoryAdapter(GpuAllocator* allocator, ResourceManager* manager)
+ : allocator_(allocator->GetWeakPtr()), manager_(manager) {}
- // Expose escher()... this is one aspect of ResourceRecycler that we want to
- // inherit publicly.
- using ResourceRecycler::escher;
+ BufferPtr NewBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage_flags,
+ vk::MemoryPropertyFlags memory_property_flags,
+ GpuMemPtr* out_ptr = nullptr) final {
+ FXL_DCHECK(allocator_);
+ return allocator_->AllocateBuffer(manager_, size, usage_flags,
+ memory_property_flags, out_ptr);
+ }
+
+ private:
+ const GpuAllocatorWeakPtr allocator_;
+ ResourceManager* const manager_;
};
} // namespace escher
diff --git a/public/lib/escher/vk/gpu_allocator.cc b/public/lib/escher/vk/gpu_allocator.cc
deleted file mode 100644
index b10580b..0000000
--- a/public/lib/escher/vk/gpu_allocator.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2016 The Fuchsia 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 "lib/escher/vk/gpu_allocator.h"
-
-#include "lib/escher/impl/vulkan_utils.h"
-
-namespace escher {
-
-GpuAllocator::GpuAllocator(const VulkanContext& context)
- : physical_device_(context.physical_device),
- device_(context.device),
- weak_factory_(this) {}
-
-GpuAllocator::~GpuAllocator() {
- FXL_CHECK(total_slab_bytes_ == 0);
- FXL_CHECK(slab_count_ == 0);
-}
-
-GpuMemPtr GpuAllocator::AllocateSlab(vk::MemoryRequirements reqs,
- vk::MemoryPropertyFlags flags) {
- return impl::GpuMemSlab::New(device(), physical_device(), reqs, flags, this);
-}
-
-void GpuAllocator::OnSlabCreated(vk::DeviceSize slab_size) {
- ++slab_count_;
- total_slab_bytes_ += slab_size;
-}
-
-void GpuAllocator::OnSlabDestroyed(vk::DeviceSize slab_size) {
- --slab_count_;
- total_slab_bytes_ -= slab_size;
-}
-
-} // namespace escher
diff --git a/public/lib/escher/vk/gpu_allocator.h b/public/lib/escher/vk/gpu_allocator.h
index 6db931c..d5c976d 100644
--- a/public/lib/escher/vk/gpu_allocator.h
+++ b/public/lib/escher/vk/gpu_allocator.h
@@ -7,88 +7,57 @@
#include <vulkan/vulkan.hpp>
-#include "lib/escher/impl/gpu_mem_slab.h"
-#include "lib/escher/vk/vulkan_context.h"
+#include "lib/escher/vk/buffer.h"
+#include "lib/escher/vk/gpu_mem.h"
+#include "lib/escher/vk/image.h"
#include "lib/fxl/memory/weak_ptr.h"
namespace escher {
-// GpuAllocator provides a framework for malloc()-like sub-allocation of Vulkan
-// memory. Vulkan does not require implementations to support large numbers of
+// GpuAllocator is an interface for allocating vulkan-aware blocks of memory,
+// and objects that are backed by said memory (i.e., buffers and images).
+//
+// Vulkan implementations are not required to support large numbers of raw
// memory allocations. Instead, applications are expected to allocate larger
// chunks of memory, and sub-allocate from within these chunks.
//
-// GpuAllocator defines the interface that clients use to obtain sub-allocated
-// memory; the specific sub-allocation strategy employed is the responsibility
-// of concrete subclasses of GpuAllocator.
-//
-// Implementation notes:
-// The following is only of interest to implementors of GpuAllocator subclasses.
-//
-// Unbeknownst to clients, GpuMem::Allocate() and GpuAllocator::Allocate() do
-// not return an instance of GpuMem, but rather an instance of a concrete
-// subclass. There are two concrete subclasses of GpuMem (with no plans to
-// create more):
-// - impl::GpuMemSuballocation
-// - impl::GpuMemSlab
-//
-// GpuMemSuballocation represents a subset of a parent GpuMem; the object
-// returned from GpuMem::Allocate() is always a GpuMemSuballocation. This is
-// also the type returned by GpuAllocator::Allocate() when a subclass performs
-// a sub-allocation of an existing GpuMem (in fact, the subclass implementation
-// uses GpuMem::Allocate() to perform this sub-allocation).
-//
-// However, sometimes a GpuAllocator has insufficient free space to sub-allocate
-// from, and must allocate more memory directly from Vulkan. This is done by
-// calling the protected method GpuAllocator::AllocateSlab(). The returned
-// GpuMem object is actually a GpuMemSlab, but the subclass neither knows nor
-// cares (except indirectly: GpuMemSlab overrides OnAllocationDestroyed() to
-// call GpuAllocator::OnSuballocationDestroyed()).
+// GpuAllocator defines the interface that clients use to obtain
+// sub-allocated memory; the specific sub-allocation strategy employed is
+// the responsibility of concrete subclasses of GpuAllocator.
class GpuAllocator {
public:
- GpuAllocator(const VulkanContext& context);
- virtual ~GpuAllocator();
+ GpuAllocator() : weak_factory_(this) {}
+ virtual ~GpuAllocator() = default;
fxl::WeakPtr<GpuAllocator> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
- virtual GpuMemPtr Allocate(vk::MemoryRequirements reqs,
- vk::MemoryPropertyFlags flags) = 0;
+ virtual GpuMemPtr AllocateMemory(
+ vk::MemoryRequirements reqs,
+ vk::MemoryPropertyFlags memory_property_flags) = 0;
- vk::PhysicalDevice physical_device() const { return physical_device_; }
- vk::Device device() const { return device_; }
+ // If |out_ptr| is non-null, this buffer must be backed by a dedicated
+ // piece of memory (i.e.,
+ // VkMemoryDedicatedRequirements.requiresDedicatedAllocation
+ // == true). That memory must be accessible through the GpuMem returned in
+ // |out_ptr|.
+ virtual BufferPtr AllocateBuffer(
+ ResourceManager* manager, vk::DeviceSize size,
+ vk::BufferUsageFlags usage_flags,
+ vk::MemoryPropertyFlags memory_property_flags,
+ GpuMemPtr* out_ptr = nullptr) = 0;
- // Current number of bytes allocated (i.e. unfreed) by this allocator.
- // This is the sum of all slabs allocated by AllocateSlab(), even if the
- // no sub-allocations have been made from these slabs.
- uint64_t total_slab_bytes() { return total_slab_bytes_; }
- uint32_t slab_count() const { return slab_count_; }
+ virtual ImagePtr AllocateImage(ResourceManager* manager,
+ const escher::ImageInfo& info) = 0;
- protected:
- // Concrete subclasses use this to allocate a slab of memory directly from
- // Vulkan. Sub-allocation can then be performed via GpuMem::Allocate().
- GpuMemPtr AllocateSlab(vk::MemoryRequirements reqs,
- vk::MemoryPropertyFlags flags);
-
- private:
- // Callbacks to allow a GpuMemSlab to notify its GpuAllocator of changes.
- friend class impl::GpuMemSlab;
- void OnSlabCreated(vk::DeviceSize slab_size);
- void OnSlabDestroyed(vk::DeviceSize slab_size);
- // Notify the GpuAllocator that a sub-allocated range of memory is no longer
- // used within the specified slab.
- virtual void OnSuballocationDestroyed(GpuMem* slab, vk::DeviceSize size,
- vk::DeviceSize offset) = 0;
-
- vk::PhysicalDevice physical_device_;
- vk::Device device_;
- vk::DeviceSize total_slab_bytes_ = 0;
- size_t slab_count_ = 0;
+ virtual uint32_t GetTotalBytesAllocated() const = 0;
fxl::WeakPtrFactory<GpuAllocator> weak_factory_; // must be last
FXL_DISALLOW_COPY_AND_ASSIGN(GpuAllocator);
};
+typedef fxl::WeakPtr<GpuAllocator> GpuAllocatorWeakPtr;
+
} // namespace escher
#endif // LIB_ESCHER_VK_GPU_ALLOCATOR_H_
diff --git a/public/lib/escher/vk/gpu_mem.cc b/public/lib/escher/vk/gpu_mem.cc
index 722f031..7521787 100644
--- a/public/lib/escher/vk/gpu_mem.cc
+++ b/public/lib/escher/vk/gpu_mem.cc
@@ -15,20 +15,13 @@
GpuMem::~GpuMem() {}
-GpuMemPtr GpuMem::New(vk::Device device, vk::PhysicalDevice physical_device,
- vk::MemoryRequirements reqs,
- vk::MemoryPropertyFlags flags) {
- return impl::GpuMemSlab::New(device, physical_device, reqs, flags, nullptr);
+GpuMemPtr GpuMem::AdoptVkMemory(vk::Device device, vk::DeviceMemory mem,
+ vk::DeviceSize size, bool needs_mapped_ptr) {
+ return fxl::AdoptRef(
+ new impl::GpuMemSlab(device, mem, size, needs_mapped_ptr, nullptr));
}
-GpuMemPtr GpuMem::New(vk::Device device, vk::DeviceMemory mem,
- vk::DeviceSize size, bool needs_mapped_ptr,
- uint32_t memory_type_index) {
- return fxl::AdoptRef(new impl::GpuMemSlab(device, mem, size, needs_mapped_ptr,
- memory_type_index, nullptr));
-}
-
-GpuMemPtr GpuMem::Allocate(vk::DeviceSize size, vk::DeviceSize offset) {
+GpuMemPtr GpuMem::Suballocate(vk::DeviceSize size, vk::DeviceSize offset) {
if (offset + size > size_) {
return GpuMemPtr();
}
diff --git a/public/lib/escher/vk/gpu_mem.h b/public/lib/escher/vk/gpu_mem.h
index 42df467..883b228 100644
--- a/public/lib/escher/vk/gpu_mem.h
+++ b/public/lib/escher/vk/gpu_mem.h
@@ -21,17 +21,10 @@
// Ref-counted wrapper around a vk::DeviceMemory. Supports sub-allocation.
class GpuMem : public fxl::RefCountedThreadSafe<GpuMem> {
public:
- // Create a GpuMem that wraps a newly-allocated vk::DeviceMemory, which will
- // be destroyed when the GpuMem dies.
- static GpuMemPtr New(vk::Device device, vk::PhysicalDevice physical_device,
- vk::MemoryRequirements reqs,
- vk::MemoryPropertyFlags flags);
-
- // Create a GpuMem that takes ownership of |mem|, which will be destroyed hen
- // the GpuMem dies. Guaranteed to return non-null result.
- static GpuMemPtr New(vk::Device device, vk::DeviceMemory mem,
- vk::DeviceSize size, bool needs_mapped_ptr,
- uint32_t memory_type_index);
+ // Create a GpuMem that takes ownership of |mem|, which will be destroyed when
+ // the GpuMem dies. Guaranteed to return a non-null result.
+ static GpuMemPtr AdoptVkMemory(vk::Device device, vk::DeviceMemory mem,
+ vk::DeviceSize size, bool needs_mapped_ptr);
// Sub-allocate a GpuMem that represents a sub-range of the memory in this
// GpuMem. Since these sub-allocations reference the parent GpuMem, the
@@ -39,7 +32,7 @@
// Returns nullptr if the requested offset/size do not fit within the current
// GpuMem.
// Note: no bookkeeping ensures that sub-allocations do not overlap!
- GpuMemPtr Allocate(vk::DeviceSize size, vk::DeviceSize offset);
+ GpuMemPtr Suballocate(vk::DeviceSize size, vk::DeviceSize offset);
vk::DeviceMemory base() const { return base_; }
vk::DeviceSize size() const { return size_; }
@@ -47,8 +40,8 @@
uint8_t* mapped_ptr() const { return mapped_ptr_; }
protected:
- // |offset| + |size| must be <= the size of |base|. Takes ownership of
- // |base|.
+ // |offset| + |size| must be <= the size of |base|. This class does not
+ // takes ownership of |base| by default.
GpuMem(vk::DeviceMemory base, vk::DeviceSize size, vk::DeviceSize offset,
uint8_t* mapped_ptr);
@@ -56,13 +49,6 @@
virtual ~GpuMem();
private:
- // Allow subclasses to take action when a sub-allocation is destroyed. For
- // example, this can be used by subclasses of GpuAllocator for bookkeeping of
- // available memory withing a GpuMemSlab.
- friend class impl::GpuMemSuballocation;
- virtual void OnAllocationDestroyed(vk::DeviceSize size,
- vk::DeviceSize offset) {}
-
vk::DeviceMemory base_;
vk::DeviceSize size_;
vk::DeviceSize offset_;
diff --git a/public/lib/escher/vk/image.cc b/public/lib/escher/vk/image.cc
index 9c30304..e171869 100644
--- a/public/lib/escher/vk/image.cc
+++ b/public/lib/escher/vk/image.cc
@@ -17,40 +17,33 @@
ResourceType::kWaitableResource,
ResourceType::kImage);
-ImagePtr Image::New(ResourceManager* image_owner, ImageInfo info,
- vk::Image vk_image, GpuMemPtr mem,
- vk::DeviceSize mem_offset, bool bind_image_memory) {
- TRACE_DURATION("gfx", "escher::Image::New (from VkImage)");
- if (mem && bind_image_memory) {
- auto bind_result = image_owner->vk_device().bindImageMemory(
- vk_image, mem->base(), mem->offset() + mem_offset);
- if (bind_result != vk::Result::eSuccess) {
- FXL_DLOG(ERROR) << "vkBindImageMemory failed: "
- << vk::to_string(bind_result);
- return nullptr;
- }
+ImagePtr Image::AdoptVkImage(ResourceManager* image_owner, ImageInfo info,
+ vk::Image vk_image, GpuMemPtr mem) {
+ TRACE_DURATION("gfx", "escher::Image::AdoptImage (from VkImage)");
+ FXL_CHECK(vk_image);
+ FXL_CHECK(mem);
+ auto bind_result = image_owner->vk_device().bindImageMemory(
+ vk_image, mem->base(), mem->offset());
+ if (bind_result != vk::Result::eSuccess) {
+ FXL_DLOG(ERROR) << "vkBindImageMemory failed: "
+ << vk::to_string(bind_result);
+ return nullptr;
}
- return fxl::AdoptRef(new Image(image_owner, info, vk_image, mem, mem_offset));
+
+ return fxl::AdoptRef(new Image(image_owner, info, vk_image, mem));
}
-ImagePtr Image::New(ResourceManager* image_owner, const ImageInfo& info,
- GpuAllocator* allocator) {
- TRACE_DURATION("gfx", "escher::Image::New (from ImageInfo)");
-
- auto vk_device = image_owner->vk_device();
- vk::Image image = image_utils::CreateVkImage(vk_device, info);
- vk::MemoryRequirements reqs = vk_device.getImageMemoryRequirements(image);
- return Image::New(image_owner, info, image,
- allocator->Allocate(reqs, info.memory_flags));
+ImagePtr Image::WrapVkImage(ResourceManager* image_owner, ImageInfo info,
+ vk::Image vk_image) {
+ return fxl::AdoptRef(new Image(image_owner, info, vk_image, nullptr));
}
-Image::Image(ResourceManager* image_owner, ImageInfo info, vk::Image vk_image,
- GpuMemPtr mem, vk::DeviceSize mem_offset)
+Image::Image(ResourceManager* image_owner, ImageInfo info, vk::Image image,
+ GpuMemPtr mem)
: WaitableResource(image_owner),
info_(info),
- image_(vk_image),
- mem_(std::move(mem)),
- mem_offset_(mem_offset) {
+ image_(image),
+ mem_(std::move(mem)) {
auto is_depth_stencil = image_utils::IsDepthStencilFormat(info.format);
has_depth_ = is_depth_stencil.first;
has_stencil_ = is_depth_stencil.second;
diff --git a/public/lib/escher/vk/image.h b/public/lib/escher/vk/image.h
index 40094be..a330237 100644
--- a/public/lib/escher/vk/image.h
+++ b/public/lib/escher/vk/image.h
@@ -48,19 +48,16 @@
static const ResourceTypeInfo kTypeInfo;
const ResourceTypeInfo& type_info() const override { return kTypeInfo; }
- // Constructor. In some cases it is necessary to wrap an un-owned vk::Image,
- // which should not be destroyed when this Image is destroyed (e.g. when
- // working with images associated with a vk::SwapchainKHR); this is done by
- // passing nullptr as the |mem| argument.
- // If |mem| is passed and |bind_image_memory| is true, this method also binds
- // the memory to the image. |mem_offset| is the offset of the image's memory
- // within |mem|.
- static ImagePtr New(ResourceManager* image_owner, ImageInfo info, vk::Image,
- GpuMemPtr mem, vk::DeviceSize mem_offset = 0,
- bool bind_image_memory = true);
+ // Constructor. Claims ownership of the vk::Image, and binds it to the
+ // provided GpuMemPtr.
+ static ImagePtr AdoptVkImage(ResourceManager* image_owner, ImageInfo info,
+ vk::Image image, GpuMemPtr mem);
- static ImagePtr New(ResourceManager* image_owner, const ImageInfo& info,
- GpuAllocator* allocator);
+ // Constructor. Wraps an existing image without claiming ownership. Useful
+ // when the image is owned/maintained by another system (e.g.,
+ // vk::SwapchainKHR).
+ static ImagePtr WrapVkImage(ResourceManager* image_owner, ImageInfo info,
+ vk::Image image);
// Returns image_ and mem_ to the owner.
~Image() override;
@@ -76,8 +73,6 @@
bool has_stencil() const { return has_stencil_; }
bool is_transient() const { return info_.is_transient(); }
const GpuMemPtr& memory() const { return mem_; }
- // Offset of the Image within its GpuMem.
- vk::DeviceSize memory_offset() const { return mem_offset_; }
// TODO(ES-83): how does this interact with swapchain_layout_?
// Should this be automatically set when various transitions are made, e.g.
@@ -101,15 +96,13 @@
// which should not be destroyed when this Image is destroyed (e.g. when
// working with images associated with a vk::SwapchainKHR); this is done by
// passing nullptr as the |mem| argument.
- // |mem_offset| is the offset of the image's memory within |mem|.
- Image(ResourceManager* image_owner, ImageInfo info, vk::Image, GpuMemPtr mem,
- vk::DeviceSize mem_offset);
+ Image(ResourceManager* image_owner, ImageInfo info, vk::Image image,
+ GpuMemPtr mem);
private:
const ImageInfo info_;
const vk::Image image_;
GpuMemPtr mem_;
- const vk::DeviceSize mem_offset_ = 0;
bool has_depth_;
bool has_stencil_;
diff --git a/public/lib/escher/vk/image_factory.h b/public/lib/escher/vk/image_factory.h
index f726c03..ac31378 100644
--- a/public/lib/escher/vk/image_factory.h
+++ b/public/lib/escher/vk/image_factory.h
@@ -5,20 +5,43 @@
#ifndef LIB_ESCHER_VK_IMAGE_FACTORY_H_
#define LIB_ESCHER_VK_IMAGE_FACTORY_H_
+#include "lib/escher/resources/resource_manager.h"
+#include "lib/escher/vk/gpu_allocator.h"
#include "lib/escher/vk/image.h"
-#include "lib/fxl/memory/ref_counted.h"
namespace escher {
-// ImageFactory creates Images, which may or may not have been recycled. All
-// Images obtained from an ImageFactory must be destroyed before the
-// ImageFactory is destroyed.
+// ImageFactory allows clients to obtain new Images with the desired
+// properties. Subclasses are free to implement custom caching/recycling
+// behaviors. All images obtained from an ImageFactory must be released before
+// the ImageFactory is destroyed.
class ImageFactory {
public:
- virtual ~ImageFactory() {}
+ virtual ~ImageFactory() = default;
virtual ImagePtr NewImage(const ImageInfo& info) = 0;
};
+// This default implementation allocates memory and creates a new
+// Image using the provided allocator and manager. The intent is for this class
+// to adapt existing GpuAllocators to the ImageFactory interface (i.e.
+// equivalent to a partial bind). Classes that wish to implement their own
+// caching logic should subclass ImageFactory directly, instead of injecting
+// tricky subclasses of GpuAllocator and ResourceManager into this object.
+class ImageFactoryAdapter final : public ImageFactory {
+ public:
+ ImageFactoryAdapter(GpuAllocator* allocator, ResourceManager* manager)
+ : allocator_(allocator->GetWeakPtr()), manager_(manager) {}
+
+ ImagePtr NewImage(const ImageInfo& info) final {
+ FXL_DCHECK(allocator_);
+ return allocator_->AllocateImage(manager_, info);
+ }
+
+ private:
+ const GpuAllocatorWeakPtr allocator_;
+ ResourceManager* const manager_;
+};
+
} // namespace escher
#endif // LIB_ESCHER_VK_IMAGE_FACTORY_H_
diff --git a/public/lib/escher/vk/naive_gpu_allocator.cc b/public/lib/escher/vk/naive_gpu_allocator.cc
index 16c8690..b1a98a9 100644
--- a/public/lib/escher/vk/naive_gpu_allocator.cc
+++ b/public/lib/escher/vk/naive_gpu_allocator.cc
@@ -3,28 +3,110 @@
// found in the LICENSE file.
#include "lib/escher/vk/naive_gpu_allocator.h"
+#include "lib/escher/impl/gpu_mem_slab.h"
+#include "lib/escher/impl/vulkan_utils.h"
+#include "lib/escher/util/image_utils.h"
+#include "lib/escher/util/trace_macros.h"
+#include "lib/escher/vk/image.h"
namespace escher {
NaiveGpuAllocator::NaiveGpuAllocator(const VulkanContext& context)
- : GpuAllocator(context) {}
-
-GpuMemPtr NaiveGpuAllocator::Allocate(vk::MemoryRequirements reqs,
- vk::MemoryPropertyFlags flags) {
- // TODO: need to manually overallocate and adjust offset to ensure alignment,
- // based on the content of reqs.alignment? Probably not, but should verify.
-
- // More sophisticated subclasses of GpuAllocator will perform multiple
- // suballocations within a single GpuMemSlab; these will retain the unique_ptr
- // to the slab, along with additional metadata to track which regions within
- // it are available. However, since we know that there is a 1-1 mapping, we
- // release our unique_ptr to the slab, since it is guaranteed to be returned
- // to us by FreeMem.
- return AllocateSlab(reqs, flags);
+ : physical_device_(context.physical_device), device_(context.device) {
+ FXL_DCHECK(device_);
}
-void NaiveGpuAllocator::OnSuballocationDestroyed(GpuMem* slab,
- vk::DeviceSize size,
- vk::DeviceSize offset) {}
+NaiveGpuAllocator::~NaiveGpuAllocator() {
+ FXL_CHECK(total_slab_bytes_ == 0);
+ FXL_CHECK(slab_count_ == 0);
+}
+
+GpuMemPtr NaiveGpuAllocator::AllocateMemory(vk::MemoryRequirements reqs,
+ vk::MemoryPropertyFlags flags) {
+ TRACE_DURATION("gfx", "escher::NaiveGpuAllocator::AllocateMemory");
+
+ // TODO (SCN-730): need to manually overallocate and adjust offset to ensure
+ // alignment, based on the content of reqs.alignment? Probably not, but
+ // should verify.
+ vk::DeviceMemory vk_mem;
+ uint32_t memory_type_index = 0;
+ bool needs_mapped_ptr = false;
+ // Determine whether we will need to map the memory.
+ if (flags & vk::MemoryPropertyFlagBits::eHostVisible) {
+ // We don't currently provide an interface for flushing mapped data, so
+ // ensure that the allocated memory is cache-coherent. This is more
+ // convenient anyway.
+ flags |= vk::MemoryPropertyFlagBits::eHostCoherent;
+ needs_mapped_ptr = true;
+ }
+
+ // TODO (SCN-1161): cache flags for efficiency? Or perhaps change signature of
+ // this method to directly take the memory-type index.
+ memory_type_index =
+ impl::GetMemoryTypeIndex(physical_device_, reqs.memoryTypeBits, flags);
+
+ {
+ TRACE_DURATION("gfx", "vk::Device::allocateMemory");
+ vk::MemoryAllocateInfo info;
+ info.allocationSize = reqs.size;
+ info.memoryTypeIndex = memory_type_index;
+ vk_mem = ESCHER_CHECKED_VK_RESULT(device_.allocateMemory(info));
+ }
+
+ return fxl::AdoptRef(
+ new impl::GpuMemSlab(device_, vk_mem, reqs.size, needs_mapped_ptr, this));
+}
+
+BufferPtr NaiveGpuAllocator::AllocateBuffer(
+ ResourceManager* manager, vk::DeviceSize size,
+ vk::BufferUsageFlags usage_flags,
+ vk::MemoryPropertyFlags memory_property_flags, GpuMemPtr* out_ptr) {
+ TRACE_DURATION("gfx", "escher::NaiveGpuAllocator::AllocateBuffer");
+ FXL_DCHECK(manager);
+
+ // Create buffer.
+ vk::BufferCreateInfo buffer_create_info;
+ buffer_create_info.size = size;
+ buffer_create_info.usage = usage_flags;
+ buffer_create_info.sharingMode = vk::SharingMode::eExclusive;
+ auto vk_buffer =
+ ESCHER_CHECKED_VK_RESULT(device_.createBuffer(buffer_create_info));
+
+ auto memory_requirements = device_.getBufferMemoryRequirements(vk_buffer);
+
+ // Allocate memory for the buffer.
+ GpuMemPtr mem = AllocateMemory(memory_requirements, memory_property_flags);
+ if (out_ptr) {
+ *out_ptr = mem;
+ }
+ return fxl::AdoptRef(new Buffer(manager, std::move(mem), vk_buffer));
+}
+
+ImagePtr NaiveGpuAllocator::AllocateImage(ResourceManager* manager,
+ const ImageInfo& info) {
+ vk::Image image = image_utils::CreateVkImage(device_, info);
+
+ // Allocate memory and bind it to the image.
+ vk::MemoryRequirements reqs = device_.getImageMemoryRequirements(image);
+ escher::GpuMemPtr memory = AllocateMemory(reqs, info.memory_flags);
+ ImagePtr escher_image =
+ Image::AdoptVkImage(manager, info, image, std::move(memory));
+ FXL_CHECK(escher_image);
+ return escher_image;
+}
+
+uint32_t NaiveGpuAllocator::GetTotalBytesAllocated() const {
+ return total_slab_bytes_;
+}
+
+void NaiveGpuAllocator::OnSlabCreated(vk::DeviceSize slab_size) {
+ ++slab_count_;
+ total_slab_bytes_ += slab_size;
+}
+
+void NaiveGpuAllocator::OnSlabDestroyed(vk::DeviceSize slab_size) {
+ --slab_count_;
+ total_slab_bytes_ -= slab_size;
+}
} // namespace escher
diff --git a/public/lib/escher/vk/naive_gpu_allocator.h b/public/lib/escher/vk/naive_gpu_allocator.h
index d7463fc..40f3fdb 100644
--- a/public/lib/escher/vk/naive_gpu_allocator.h
+++ b/public/lib/escher/vk/naive_gpu_allocator.h
@@ -7,8 +7,8 @@
#include <vulkan/vulkan.hpp>
+#include "lib/escher/impl/gpu_mem_slab.h"
#include "lib/escher/vk/gpu_allocator.h"
-#include "lib/escher/vk/gpu_mem.h"
#include "lib/escher/vk/vulkan_context.h"
namespace escher {
@@ -19,15 +19,35 @@
class NaiveGpuAllocator : public GpuAllocator {
public:
NaiveGpuAllocator(const VulkanContext& context);
+ ~NaiveGpuAllocator();
- GpuMemPtr Allocate(vk::MemoryRequirements reqs,
- vk::MemoryPropertyFlags flags) override;
+ // |GpuAllocator|
+ GpuMemPtr AllocateMemory(vk::MemoryRequirements reqs,
+ vk::MemoryPropertyFlags flags) override;
+
+ // |GpuAllocator|
+ BufferPtr AllocateBuffer(ResourceManager* manager, vk::DeviceSize size,
+ vk::BufferUsageFlags usage_flags,
+ vk::MemoryPropertyFlags memory_property_flags,
+ GpuMemPtr* out_ptr) override;
+
+ // |GpuAllocator|
+ ImagePtr AllocateImage(ResourceManager* manager,
+ const escher::ImageInfo& info) override;
+
+ // |GpuAllocator|
+ uint32_t GetTotalBytesAllocated() const override;
private:
- // No-op, because NaiveGpuAllocator does not perform sub-allocation. This
- // can only be called if a client manually sub-allocates from the allocation.
- void OnSuballocationDestroyed(GpuMem* slab, vk::DeviceSize size,
- vk::DeviceSize offset) override;
+ // Callbacks to allow a GpuMemSlab to notify its GpuAllocator of changes.
+ friend class impl::GpuMemSlab;
+ void OnSlabCreated(vk::DeviceSize slab_size);
+ void OnSlabDestroyed(vk::DeviceSize slab_size);
+
+ vk::PhysicalDevice physical_device_;
+ vk::Device device_;
+ vk::DeviceSize total_slab_bytes_ = 0;
+ size_t slab_count_ = 0;
};
} // namespace escher
diff --git a/public/lib/escher/vk/simple_image_factory.cc b/public/lib/escher/vk/simple_image_factory.cc
deleted file mode 100644
index 043931c..0000000
--- a/public/lib/escher/vk/simple_image_factory.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2017 The Fuchsia 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 "lib/escher/vk/simple_image_factory.h"
-
-#include "lib/escher/resources/resource_manager.h"
-#include "lib/escher/util/image_utils.h"
-#include "lib/escher/vk/gpu_allocator.h"
-
-namespace escher {
-
-SimpleImageFactory::SimpleImageFactory(ResourceManager* resource_manager,
- escher::GpuAllocator* allocator)
- : resource_manager_(resource_manager), allocator_(allocator) {}
-
-SimpleImageFactory::~SimpleImageFactory() {}
-
-ImagePtr SimpleImageFactory::NewImage(const ImageInfo& info) {
- vk::Image image =
- image_utils::CreateVkImage(resource_manager_->vk_device(), info);
-
- // Allocate memory and bind it to the image.
- vk::MemoryRequirements reqs =
- resource_manager_->vk_device().getImageMemoryRequirements(image);
- escher::GpuMemPtr memory = allocator_->Allocate(reqs, info.memory_flags);
- ImagePtr escher_image =
- Image::New(resource_manager_, info, image, std::move(memory));
- FXL_CHECK(escher_image);
- return escher_image;
-}
-
-} // namespace escher
diff --git a/public/lib/escher/vk/simple_image_factory.h b/public/lib/escher/vk/simple_image_factory.h
deleted file mode 100644
index f37eedc..0000000
--- a/public/lib/escher/vk/simple_image_factory.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef LIB_ESCHER_VK_SIMPLE_IMAGE_FACTORY_H_
-#define LIB_ESCHER_VK_SIMPLE_IMAGE_FACTORY_H_
-
-#include <vulkan/vulkan.hpp>
-
-#include "lib/escher/impl/gpu_uploader.h"
-#include "lib/escher/vk/image.h"
-#include "lib/escher/vk/image_factory.h"
-#include "lib/fxl/memory/ref_counted.h"
-
-namespace escher {
-
-// Creates images by allocating a new chunk of memory directly from the
-// passed allocator. Does not cache images.
-class SimpleImageFactory : public escher::ImageFactory {
- public:
- SimpleImageFactory(ResourceManager* resource_manager,
- escher::GpuAllocator* allocator);
- ~SimpleImageFactory() override;
-
- ImagePtr NewImage(const escher::ImageInfo& info) override;
-
- private:
- ResourceManager* resource_manager_;
- escher::GpuAllocator* allocator_;
-};
-
-} // namespace escher
-
-#endif // LIB_ESCHER_VK_SIMPLE_IMAGE_FACTORY_H_