[go: nahoru, domu]

blob: b5d32cd957bec4494870e7ba26e0804214194a37 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/viz/public/cpp/compositing/copy_output_result_mojom_traits.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "mojo/public/cpp/bindings/optional_as_pointer.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace {
// This class retains the ReleaseCallback of the CopyOutputResult that is being
// sent over mojo. A PendingRemote<TextureReleaser> that talks to this impl
// object will be sent over mojo instead of the release_callback_ (which is not
// serializable). Once the client calls Release, the release_callback_ will be
// called. An object of this class will remain alive until the MessagePipe
// attached to it goes away (i.e. SelfOwnedReceiver is used).
class TextureReleaserImpl : public viz::mojom::TextureReleaser {
public:
explicit TextureReleaserImpl(viz::ReleaseCallback release_callback)
: release_callback_(std::move(release_callback)) {}
// mojom::TextureReleaser implementation:
void Release(const gpu::SyncToken& sync_token, bool is_lost) override {
std::move(release_callback_).Run(sync_token, is_lost);
}
private:
viz::ReleaseCallback release_callback_;
};
void Release(mojo::PendingRemote<viz::mojom::TextureReleaser> pending_remote,
const gpu::SyncToken& sync_token,
bool is_lost) {
mojo::Remote<viz::mojom::TextureReleaser> remote(std::move(pending_remote));
remote->Release(sync_token, is_lost);
}
} // namespace
namespace mojo {
// static
viz::mojom::CopyOutputResultFormat
EnumTraits<viz::mojom::CopyOutputResultFormat, viz::CopyOutputResult::Format>::
ToMojom(viz::CopyOutputResult::Format format) {
switch (format) {
case viz::CopyOutputResult::Format::RGBA:
return viz::mojom::CopyOutputResultFormat::RGBA;
case viz::CopyOutputResult::Format::I420_PLANES:
case viz::CopyOutputResult::Format::NV12_PLANES:
break; // Not intended for transport across service boundaries.
}
NOTREACHED();
return viz::mojom::CopyOutputResultFormat::RGBA;
}
// static
bool EnumTraits<viz::mojom::CopyOutputResultFormat,
viz::CopyOutputResult::Format>::
FromMojom(viz::mojom::CopyOutputResultFormat input,
viz::CopyOutputResult::Format* out) {
switch (input) {
case viz::mojom::CopyOutputResultFormat::RGBA:
*out = viz::CopyOutputResult::Format::RGBA;
return true;
}
return false;
}
// static
viz::mojom::CopyOutputResultDestination
EnumTraits<viz::mojom::CopyOutputResultDestination,
viz::CopyOutputResult::Destination>::
ToMojom(viz::CopyOutputResult::Destination destination) {
switch (destination) {
case viz::CopyOutputResult::Destination::kSystemMemory:
return viz::mojom::CopyOutputResultDestination::kSystemMemory;
case viz::CopyOutputResult::Destination::kNativeTextures:
return viz::mojom::CopyOutputResultDestination::kNativeTextures;
}
}
// static
bool EnumTraits<viz::mojom::CopyOutputResultDestination,
viz::CopyOutputResult::Destination>::
FromMojom(viz::mojom::CopyOutputResultDestination input,
viz::CopyOutputResult::Destination* out) {
switch (input) {
case viz::mojom::CopyOutputResultDestination::kSystemMemory:
*out = viz::CopyOutputResult::Destination::kSystemMemory;
return true;
case viz::mojom::CopyOutputResultDestination::kNativeTextures:
*out = viz::CopyOutputResult::Destination::kNativeTextures;
return true;
}
return false;
}
// static
viz::CopyOutputResult::Format
StructTraits<viz::mojom::CopyOutputResultDataView,
std::unique_ptr<viz::CopyOutputResult>>::
format(const std::unique_ptr<viz::CopyOutputResult>& result) {
return result->format();
}
// static
viz::CopyOutputResult::Destination
StructTraits<viz::mojom::CopyOutputResultDataView,
std::unique_ptr<viz::CopyOutputResult>>::
destination(const std::unique_ptr<viz::CopyOutputResult>& result) {
return result->destination();
}
// static
const gfx::Rect& StructTraits<viz::mojom::CopyOutputResultDataView,
std::unique_ptr<viz::CopyOutputResult>>::
rect(const std::unique_ptr<viz::CopyOutputResult>& result) {
return result->rect();
}
// static
absl::optional<viz::CopyOutputResult::ScopedSkBitmap>
StructTraits<viz::mojom::CopyOutputResultDataView,
std::unique_ptr<viz::CopyOutputResult>>::
bitmap(const std::unique_ptr<viz::CopyOutputResult>& result) {
if (result->destination() !=
viz::CopyOutputResult::Destination::kSystemMemory)
return absl::nullopt;
auto scoped_bitmap = result->ScopedAccessSkBitmap();
if (!scoped_bitmap.bitmap().readyToDraw()) {
// During shutdown or switching to background on Android, Chrome will
// release GPU context, it will release mapped GPU memory which is used
// in SkBitmap, in that case, a null bitmap will be sent.
return absl::nullopt;
}
return scoped_bitmap;
}
// static
mojo::OptionalAsPointer<const gpu::Mailbox>
StructTraits<viz::mojom::CopyOutputResultDataView,
std::unique_ptr<viz::CopyOutputResult>>::
mailbox(const std::unique_ptr<viz::CopyOutputResult>& result) {
if (result->destination() !=
viz::CopyOutputResult::Destination::kNativeTextures ||
result->IsEmpty()) {
return nullptr;
}
// Only RGBA can travel across process boundaries, in which case there will be
// only one plane that is relevant in the |result|:
DCHECK_EQ(result->format(), viz::CopyOutputResult::Format::RGBA);
return mojo::MakeOptionalAsPointer(
&result->GetTextureResult()->planes[0].mailbox);
}
// static
mojo::OptionalAsPointer<const gpu::SyncToken>
StructTraits<viz::mojom::CopyOutputResultDataView,
std::unique_ptr<viz::CopyOutputResult>>::
sync_token(const std::unique_ptr<viz::CopyOutputResult>& result) {
if (result->destination() !=
viz::CopyOutputResult::Destination::kNativeTextures ||
result->IsEmpty()) {
return nullptr;
}
// Only RGBA can travel across process boundaries, in which case there will be
// only one plane that is relevant in the |result|:
DCHECK_EQ(result->format(), viz::CopyOutputResult::Format::RGBA);
return mojo::MakeOptionalAsPointer(
&result->GetTextureResult()->planes[0].sync_token);
}
// static
mojo::OptionalAsPointer<const gfx::ColorSpace>
StructTraits<viz::mojom::CopyOutputResultDataView,
std::unique_ptr<viz::CopyOutputResult>>::
color_space(const std::unique_ptr<viz::CopyOutputResult>& result) {
if (result->destination() !=
viz::CopyOutputResult::Destination::kNativeTextures ||
result->IsEmpty()) {
return nullptr;
}
return mojo::MakeOptionalAsPointer(&result->GetTextureResult()->color_space);
}
// static
mojo::PendingRemote<viz::mojom::TextureReleaser>
StructTraits<viz::mojom::CopyOutputResultDataView,
std::unique_ptr<viz::CopyOutputResult>>::
releaser(const std::unique_ptr<viz::CopyOutputResult>& result) {
if (result->destination() !=
viz::CopyOutputResult::Destination::kNativeTextures)
return mojo::NullRemote();
// Only RGBA can travel across process boundaries, in which case there will be
// at most one release callback set in the |result|:
DCHECK_EQ(result->format(), viz::CopyOutputResult::Format::RGBA);
viz::CopyOutputResult::ReleaseCallbacks release_callbacks =
result->TakeTextureOwnership();
// Callbacks can be empty (in case the result is empty), or have exactly 1
// element (because a result with RGBA format can carry 1 texture).
DCHECK(release_callbacks.empty() || release_callbacks.size() == 1);
mojo::PendingRemote<viz::mojom::TextureReleaser> releaser;
MakeSelfOwnedReceiver(
std::make_unique<TextureReleaserImpl>(
release_callbacks.empty() ? viz::ReleaseCallback{}
: std::move(release_callbacks[0])),
releaser.InitWithNewPipeAndPassReceiver());
return releaser;
}
// static
bool StructTraits<viz::mojom::CopyOutputResultDataView,
std::unique_ptr<viz::CopyOutputResult>>::
Read(viz::mojom::CopyOutputResultDataView data,
std::unique_ptr<viz::CopyOutputResult>* out_p) {
// First read into local variables, and then instantiate an appropriate
// implementation of viz::CopyOutputResult.
viz::CopyOutputResult::Format format;
viz::CopyOutputResult::Destination destination;
gfx::Rect rect;
if (!data.ReadFormat(&format) || !data.ReadDestination(&destination) ||
!data.ReadRect(&rect)) {
return false;
}
if (rect.IsEmpty()) {
// An empty rect implies an empty result.
*out_p = std::make_unique<viz::CopyOutputResult>(format, destination,
gfx::Rect(), false);
return true;
}
switch (format) {
case viz::CopyOutputResult::Format::RGBA:
switch (destination) {
case viz::CopyOutputResult::Destination::kSystemMemory: {
absl::optional<SkBitmap> bitmap_opt;
if (!data.ReadBitmap(&bitmap_opt))
return false;
if (!bitmap_opt) {
// During shutdown or switching to background on Android, Chrome
// will release GPU context, it will release mapped GPU memory which
// is used in SkBitmap, in that case, the sender will send a null
// bitmap. So we should consider the copy output result is empty.
*out_p = std::make_unique<viz::CopyOutputResult>(
format, destination, gfx::Rect(), false);
return true;
}
if (!bitmap_opt->readyToDraw())
return false;
*out_p = std::make_unique<viz::CopyOutputSkBitmapResult>(
rect, std::move(*bitmap_opt));
return true;
}
case viz::CopyOutputResult::Destination::kNativeTextures: {
absl::optional<gpu::Mailbox> mailbox;
if (!data.ReadMailbox(&mailbox) || !mailbox)
return false;
absl::optional<gpu::SyncToken> sync_token;
if (!data.ReadSyncToken(&sync_token) || !sync_token)
return false;
absl::optional<gfx::ColorSpace> color_space;
if (!data.ReadColorSpace(&color_space) || !color_space)
return false;
if (mailbox->IsZero()) {
// Returns an empty result.
*out_p = std::make_unique<viz::CopyOutputResult>(
format, destination, gfx::Rect(), false);
return true;
}
auto releaser = data.TakeReleaser<
mojo::PendingRemote<viz::mojom::TextureReleaser>>();
if (!releaser)
return false; // Illegal to provide texture without Releaser.
// Returns a result with a ReleaseCallback that will return here and
// proxy the callback over mojo to the CopyOutputResult's origin via a
// mojo::Remote<viz::mojom::TextureReleaser> remote.
viz::CopyOutputResult::ReleaseCallbacks release_callbacks;
release_callbacks.emplace_back(
base::BindOnce(&Release, std::move(releaser)));
*out_p = std::make_unique<viz::CopyOutputTextureResult>(
viz::CopyOutputResult::Format::RGBA, rect,
viz::CopyOutputResult::TextureResult(*mailbox, *sync_token,
*color_space),
std::move(release_callbacks));
return true;
}
}
case viz::CopyOutputResult::Format::I420_PLANES:
case viz::CopyOutputResult::Format::NV12_PLANES:
break; // Not intended for transport across service boundaries.
}
NOTREACHED();
return false;
}
} // namespace mojo