gecko-dev/gfx/layers/CanvasTranslator.cpp

254 строки
8.3 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "CanvasTranslator.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
#include "RecordedCanvasEventImpl.h"
#if defined(XP_WIN)
# include "mozilla/gfx/DeviceManagerDx.h"
# include "mozilla/layers/TextureD3D11.h"
#endif
namespace mozilla {
namespace layers {
// When in a transaction we wait for a short time because we're expecting more
// events from the content process. We don't want to wait for too long in case
// other content processes are waiting for events to process.
static const TimeDuration kReadEventTimeout = TimeDuration::FromMilliseconds(5);
static TextureData* CreateTextureData(TextureType aTextureType,
const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat) {
TextureData* textureData = nullptr;
switch (aTextureType) {
#ifdef XP_WIN
case TextureType::D3D11: {
RefPtr<ID3D11Device> device =
gfx::DeviceManagerDx::Get()->GetCanvasDevice();
MOZ_RELEASE_ASSERT(device, "Failed to get a device for canvas drawing.");
textureData =
D3D11TextureData::Create(aSize, aFormat, ALLOC_CLEAR_BUFFER, device);
break;
}
#endif
default:
MOZ_CRASH("Unsupported TextureType for CanvasTranslator.");
}
if (!textureData) {
MOZ_CRASH("Failed to create TextureData.");
}
return textureData;
}
/* static */
UniquePtr<CanvasTranslator> CanvasTranslator::Create() {
return UniquePtr<CanvasTranslator>(new CanvasTranslator());
}
CanvasTranslator::CanvasTranslator() : gfx::InlineTranslator() {}
CanvasTranslator::~CanvasTranslator() {
if (mReferenceTextureData) {
mReferenceTextureData->Unlock();
}
}
bool CanvasTranslator::Init(
const TextureType& aTextureType,
const ipc::SharedMemoryBasic::Handle& aReadHandle,
const CrossProcessSemaphoreHandle& aReaderSem,
const CrossProcessSemaphoreHandle& aWriterSem,
UniquePtr<CanvasEventRingBuffer::ReaderServices> aReaderServices) {
mTextureType = aTextureType;
mReferenceTextureData.reset(CreateTextureData(
aTextureType, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8));
mReferenceTextureData->Lock(OpenMode::OPEN_READ_WRITE);
mBaseDT = mReferenceTextureData->BorrowDrawTarget();
return mStream.InitReader(aReadHandle, aReaderSem, aWriterSem,
std::move(aReaderServices));
}
bool CanvasTranslator::TranslateRecording() {
int32_t eventType = mStream.ReadNextEvent();
while (mStream.good()) {
bool success = RecordedEvent::DoWithEventFromStream(
mStream, static_cast<RecordedEvent::EventType>(eventType),
[&](RecordedEvent* recordedEvent) -> bool {
// Make sure that the whole event was read from the stream.
if (!mStream.good()) {
return false;
}
return recordedEvent->PlayEvent(this);
});
if (!success && !HandleExtensionEvent(eventType)) {
gfxDevCrash(gfx::LogReason::PlayEventFailed)
<< "Failed to play canvas event type: " << eventType;
mIsValid = false;
return true;
}
if (!mIsInTransaction) {
return mStream.StopIfEmpty();
}
if (!mStream.HasDataToRead()) {
// We're going to wait for the next event, so take the opportunity to
// flush the rendering.
Flush();
if (!mStream.WaitForDataToRead(kReadEventTimeout, 0)) {
return true;
}
}
eventType = mStream.ReadNextEvent();
}
mIsValid = false;
return true;
}
#define READ_AND_PLAY_CANVAS_EVENT_TYPE(_typeenum, _class) \
case _typeenum: { \
auto e = _class(mStream); \
if (!mStream.good()) { \
return false; \
} \
return e.PlayCanvasEvent(this); \
}
bool CanvasTranslator::HandleExtensionEvent(int32_t aType) {
// This is where we handle extensions to the Moz2D Recording events to handle
// canvas specific things.
switch (aType) {
FOR_EACH_CANVAS_EVENT(READ_AND_PLAY_CANVAS_EVENT_TYPE)
default:
return false;
}
}
void CanvasTranslator::BeginTransaction() { mIsInTransaction = true; }
void CanvasTranslator::Flush() {
#if defined(XP_WIN)
gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
GetReferenceDrawTarget()->GetBackendType());
RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetCanvasDevice();
RefPtr<ID3D11DeviceContext> deviceContext;
device->GetImmediateContext(getter_AddRefs(deviceContext));
deviceContext->Flush();
#endif
}
void CanvasTranslator::EndTransaction() {
Flush();
mIsInTransaction = false;
}
void CanvasTranslator::AddSurfaceDescriptor(gfx::ReferencePtr aRefPtr,
TextureData* aTextureData) {
UniquePtr<SurfaceDescriptor> descriptor = MakeUnique<SurfaceDescriptor>();
if (!aTextureData->Serialize(*descriptor)) {
MOZ_CRASH("Failed to serialize");
}
MonitorAutoLock lock(mSurfaceDescriptorsMonitor);
mSurfaceDescriptors[aRefPtr] = std::move(descriptor);
mSurfaceDescriptorsMonitor.Notify();
}
already_AddRefed<gfx::DrawTarget> CanvasTranslator::CreateDrawTarget(
gfx::ReferencePtr aRefPtr, const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat) {
gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
GetReferenceDrawTarget()->GetBackendType());
TextureData* textureData = CreateTextureData(mTextureType, aSize, aFormat);
textureData->Lock(OpenMode::OPEN_READ_WRITE);
mTextureDatas[aRefPtr] = UniquePtr<TextureData>(textureData);
AddSurfaceDescriptor(aRefPtr, textureData);
RefPtr<gfx::DrawTarget> dt = textureData->BorrowDrawTarget();
AddDrawTarget(aRefPtr, dt);
return dt.forget();
}
void CanvasTranslator::RemoveDrawTarget(gfx::ReferencePtr aDrawTarget) {
InlineTranslator::RemoveDrawTarget(aDrawTarget);
gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
GetReferenceDrawTarget()->GetBackendType());
mTextureDatas.erase(aDrawTarget);
// It is possible that the texture from the content process has never been
// forwarded to the GPU process, so we have to make sure it is removed here
// otherwise if the same pointer gets used for a DrawTarget again in the
// content process then it could pick up the old (now invalid) descriptor.
MonitorAutoLock lock(mSurfaceDescriptorsMonitor);
mSurfaceDescriptors.erase(aDrawTarget);
}
TextureData* CanvasTranslator::LookupTextureData(
gfx::ReferencePtr aDrawTarget) {
TextureMap::const_iterator result = mTextureDatas.find(aDrawTarget);
if (result == mTextureDatas.end()) {
return nullptr;
}
return result->second.get();
}
UniquePtr<SurfaceDescriptor> CanvasTranslator::WaitForSurfaceDescriptor(
gfx::ReferencePtr aDrawTarget) {
MonitorAutoLock lock(mSurfaceDescriptorsMonitor);
DescriptorMap::iterator result;
while ((result = mSurfaceDescriptors.find(aDrawTarget)) ==
mSurfaceDescriptors.end()) {
mSurfaceDescriptorsMonitor.Wait();
}
UniquePtr<SurfaceDescriptor> descriptor = std::move(result->second);
mSurfaceDescriptors.erase(aDrawTarget);
return descriptor;
}
gfx::DataSourceSurface* CanvasTranslator::LookupDataSurface(
gfx::ReferencePtr aRefPtr) {
return mDataSurfaces.GetWeak(aRefPtr);
}
void CanvasTranslator::AddDataSurface(
gfx::ReferencePtr aRefPtr, RefPtr<gfx::DataSourceSurface>&& aSurface) {
mDataSurfaces.Put(aRefPtr, aSurface);
}
void CanvasTranslator::RemoveDataSurface(gfx::ReferencePtr aRefPtr) {
mDataSurfaces.Remove(aRefPtr);
}
void CanvasTranslator::SetPreparedMap(
gfx::ReferencePtr aSurface,
UniquePtr<gfx::DataSourceSurface::ScopedMap> aMap) {
mMappedSurface = aSurface;
mPreparedMap = std::move(aMap);
}
UniquePtr<gfx::DataSourceSurface::ScopedMap> CanvasTranslator::GetPreparedMap(
gfx::ReferencePtr aSurface) {
MOZ_RELEASE_ASSERT(mMappedSurface == aSurface,
"aSurface must match previously stored surface.");
mMappedSurface = nullptr;
return std::move(mPreparedMap);
}
} // namespace layers
} // namespace mozilla