blob: 34e8338c711f488149e6ace2a74978e891648258 [file] [log] [blame]
// Copyright 2020 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 "src/ui/scenic/lib/flatland/renderer/null_renderer.h"
#include <lib/syslog/cpp/macros.h>
#include <zircon/pixelformat.h>
namespace flatland {
bool NullRenderer::RegisterRenderTargetCollection(
sysmem_util::GlobalBufferCollectionId collection_id,
fuchsia::sysmem::Allocator_Sync* sysmem_allocator,
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token) {
return ImportBufferCollection(collection_id, sysmem_allocator, std::move(token));
}
void NullRenderer::DeregisterRenderTargetCollection(
sysmem_util::GlobalBufferCollectionId collection_id) {
ReleaseBufferCollection(collection_id);
}
bool NullRenderer::ImportBufferCollection(
sysmem_util::GlobalBufferCollectionId collection_id,
fuchsia::sysmem::Allocator_Sync* sysmem_allocator,
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token) {
FX_DCHECK(collection_id != sysmem_util::kInvalidId);
// Check for a null token here before we try to duplicate it to get the
// vulkan token.
if (!token.is_valid()) {
FX_LOGS(ERROR) << "Token is invalid.";
return false;
}
if (collection_map_.find(collection_id) != collection_map_.end()) {
FX_LOGS(ERROR) << "Duplicate GlobalBufferCollectionID: " << collection_id;
return false;
}
auto result = BufferCollectionInfo::New(sysmem_allocator, std::move(token));
if (result.is_error()) {
FX_LOGS(ERROR) << "Unable to register collection.";
return false;
}
// Multiple threads may be attempting to read/write from |collection_map_| so we
// lock this function here.
// TODO(fxbug.dev/44335): Convert this to a lock-free structure.
std::unique_lock<std::mutex> lock(lock_);
collection_map_[collection_id] = std::move(result.value());
return true;
}
void NullRenderer::ReleaseBufferCollection(sysmem_util::GlobalBufferCollectionId collection_id) {
// Multiple threads may be attempting to read/write from the various maps,
// lock this function here.
// TODO(fxbug.dev/44335): Convert this to a lock-free structure.
std::unique_lock<std::mutex> lock(lock_);
auto collection_itr = collection_map_.find(collection_id);
// If the collection is not in the map, then there's nothing to do.
if (collection_itr == collection_map_.end()) {
return;
}
// Erase the sysmem collection from the map.
collection_map_.erase(collection_id);
// Erase the metadata. There may not actually be any metadata if the collection was
// never validated, but there's no need to check as erasing a non-existent key is valid.
collection_metadata_map_.erase(collection_id);
}
bool NullRenderer::ImportImage(const ImageMetadata& meta_data) {
auto buffer_metadata = Validate(meta_data.collection_id);
if (!buffer_metadata.has_value()) {
FX_LOGS(ERROR) << "CreateImage failed, collection_id " << meta_data.collection_id
<< " has not been allocated yet";
return false;
}
if (meta_data.vmo_idx >= buffer_metadata->vmo_count) {
FX_LOGS(ERROR) << "CreateImage failed, vmo_index " << meta_data.vmo_idx
<< " must be less than vmo_count " << buffer_metadata->vmo_count;
return false;
}
const auto& image_constraints = buffer_metadata->image_constraints;
if (meta_data.width < image_constraints.min_coded_width ||
meta_data.width > image_constraints.max_coded_width) {
FX_LOGS(ERROR) << "CreateImage failed, width " << meta_data.width
<< " is not within valid range [" << image_constraints.min_coded_width << ","
<< image_constraints.max_coded_width << "]";
return false;
}
if (meta_data.height < image_constraints.min_coded_height ||
meta_data.height > image_constraints.max_coded_height) {
FX_LOGS(ERROR) << "CreateImage failed, height " << meta_data.height
<< " is not within valid range [" << image_constraints.min_coded_height << ","
<< image_constraints.max_coded_height << "]";
return false;
}
return true;
}
void NullRenderer::ReleaseImage(GlobalImageId image_id) {}
std::optional<BufferCollectionMetadata> NullRenderer::Validate(
sysmem_util::GlobalBufferCollectionId collection_id) {
// TODO(fxbug.dev/44335): Convert this to a lock-free structure. This is trickier than in the
// other two cases for this class since we are mutating the buffer collection in this call. So we
// can only convert this to a lock free structure if the elements in the map are changed to be
// values only, or if we can guarantee that mutations on the elements only occur in a single
// thread.
std::unique_lock<std::mutex> lock(lock_);
auto collection_itr = collection_map_.find(collection_id);
// If the collection is not in the map, then it can't be validated.
if (collection_itr == collection_map_.end()) {
return std::nullopt;
}
// If there is already metadata, we can just return it instead of checking the allocation
// status again. Once a buffer is allocated it won't be stop being allocated.
auto metadata_itr = collection_metadata_map_.find(collection_id);
if (metadata_itr != collection_metadata_map_.end()) {
return metadata_itr->second;
}
// The collection should be allocated (i.e. all constraints set).
auto& collection = collection_itr->second;
if (!collection.BuffersAreAllocated()) {
return std::nullopt;
}
// If the collection is in the map, and it's allocated, then we can return meta-data regarding
// vmos and image constraints to the client.
const auto& sysmem_info = collection.GetSysmemInfo();
BufferCollectionMetadata result;
result.vmo_count = sysmem_info.buffer_count;
result.image_constraints = sysmem_info.settings.image_format_constraints;
collection_metadata_map_[collection_id] = result;
return result;
}
// Check that the buffer collections for each of the images passed in have been validated.
// DCHECK if they have not.
void NullRenderer::Render(const ImageMetadata& render_target,
const std::vector<Rectangle2D>& rectangles,
const std::vector<ImageMetadata>& images,
const std::vector<zx::event>& release_fences) {
for (const auto& image : images) {
auto collection_id = image.collection_id;
FX_DCHECK(collection_id != sysmem_util::kInvalidId);
// TODO(fxbug.dev/44335): Convert this to a lock-free structure.
std::unique_lock<std::mutex> lock(lock_);
auto metadata_itr = collection_metadata_map_.find(collection_id);
FX_DCHECK(metadata_itr != collection_metadata_map_.end());
auto metadata = metadata_itr->second;
lock.release();
// Make sure the image conforms to the constraints of the collection.
FX_DCHECK(image.vmo_idx < metadata.vmo_count);
FX_DCHECK(image.width <= metadata.image_constraints.max_coded_width);
FX_DCHECK(image.height <= metadata.image_constraints.max_coded_height);
}
// Fire all of the release fences.
for (auto& fence : release_fences) {
fence.signal(0, ZX_EVENT_SIGNALED);
}
}
} // namespace flatland