mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
500 lines
16 KiB
C++
500 lines
16 KiB
C++
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* 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 http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/layers/TextureHost.h"
|
|
#include "LayersLogging.h" // for AppendToString
|
|
#include "gfx2DGlue.h" // for ToIntSize
|
|
#include "gfxImageSurface.h" // for gfxImageSurface
|
|
#include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
|
|
#include "mozilla/ipc/Shmem.h" // for Shmem
|
|
#include "mozilla/layers/Compositor.h" // for Compositor
|
|
#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
|
|
#include "mozilla/layers/ImageDataSerializer.h"
|
|
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
|
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
|
#include "nsAString.h"
|
|
#include "nsAutoPtr.h" // for nsRefPtr
|
|
#include "nsPrintfCString.h" // for nsPrintfCString
|
|
|
|
struct nsIntPoint;
|
|
|
|
namespace mozilla {
|
|
namespace layers {
|
|
|
|
// implemented in TextureOGL.cpp
|
|
TemporaryRef<DeprecatedTextureHost> CreateDeprecatedTextureHostOGL(SurfaceDescriptorType aDescriptorType,
|
|
uint32_t aDeprecatedTextureHostFlags,
|
|
uint32_t aTextureFlags);
|
|
// implemented in BasicCompositor.cpp
|
|
TemporaryRef<DeprecatedTextureHost> CreateBasicDeprecatedTextureHost(SurfaceDescriptorType aDescriptorType,
|
|
uint32_t aDeprecatedTextureHostFlags,
|
|
uint32_t aTextureFlags);
|
|
|
|
#ifdef XP_WIN
|
|
TemporaryRef<DeprecatedTextureHost> CreateDeprecatedTextureHostD3D9(SurfaceDescriptorType aDescriptorType,
|
|
uint32_t aDeprecatedTextureHostFlags,
|
|
uint32_t aTextureFlags);
|
|
|
|
TemporaryRef<DeprecatedTextureHost> CreateDeprecatedTextureHostD3D11(SurfaceDescriptorType aDescriptorType,
|
|
uint32_t aDeprecatedTextureHostFlags,
|
|
uint32_t aTextureFlags);
|
|
#endif
|
|
|
|
/* static */ TemporaryRef<DeprecatedTextureHost>
|
|
DeprecatedTextureHost::CreateDeprecatedTextureHost(SurfaceDescriptorType aDescriptorType,
|
|
uint32_t aDeprecatedTextureHostFlags,
|
|
uint32_t aTextureFlags)
|
|
{
|
|
switch (Compositor::GetBackend()) {
|
|
case LAYERS_OPENGL:
|
|
return CreateDeprecatedTextureHostOGL(aDescriptorType,
|
|
aDeprecatedTextureHostFlags,
|
|
aTextureFlags);
|
|
#ifdef XP_WIN
|
|
case LAYERS_D3D9:
|
|
return CreateDeprecatedTextureHostD3D9(aDescriptorType,
|
|
aDeprecatedTextureHostFlags,
|
|
aTextureFlags);
|
|
case LAYERS_D3D11:
|
|
return CreateDeprecatedTextureHostD3D11(aDescriptorType,
|
|
aDeprecatedTextureHostFlags,
|
|
aTextureFlags);
|
|
#endif
|
|
case LAYERS_BASIC:
|
|
return CreateBasicDeprecatedTextureHost(aDescriptorType,
|
|
aDeprecatedTextureHostFlags,
|
|
aTextureFlags);
|
|
default:
|
|
MOZ_CRASH("Couldn't create texture host");
|
|
}
|
|
}
|
|
|
|
// implemented in TextureOGL.cpp
|
|
TemporaryRef<TextureHost> CreateTextureHostOGL(uint64_t aID,
|
|
const SurfaceDescriptor& aDesc,
|
|
ISurfaceAllocator* aDeallocator,
|
|
TextureFlags aFlags);
|
|
|
|
// static
|
|
TemporaryRef<TextureHost>
|
|
TextureHost::Create(uint64_t aID,
|
|
const SurfaceDescriptor& aDesc,
|
|
ISurfaceAllocator* aDeallocator,
|
|
TextureFlags aFlags)
|
|
{
|
|
switch (Compositor::GetBackend()) {
|
|
case LAYERS_OPENGL:
|
|
return CreateTextureHostOGL(aID, aDesc, aDeallocator, aFlags);
|
|
case LAYERS_BASIC:
|
|
return CreateBackendIndependentTextureHost(aID,
|
|
aDesc,
|
|
aDeallocator,
|
|
aFlags);
|
|
#ifdef XP_WIN
|
|
case LAYERS_D3D11:
|
|
case LAYERS_D3D9:
|
|
// XXX - not implemented yet
|
|
#endif
|
|
default:
|
|
MOZ_CRASH("Couldn't create texture host");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
TemporaryRef<TextureHost>
|
|
CreateBackendIndependentTextureHost(uint64_t aID,
|
|
const SurfaceDescriptor& aDesc,
|
|
ISurfaceAllocator* aDeallocator,
|
|
TextureFlags aFlags)
|
|
{
|
|
RefPtr<TextureHost> result;
|
|
switch (aDesc.type()) {
|
|
case SurfaceDescriptor::TSurfaceDescriptorShmem: {
|
|
const SurfaceDescriptorShmem& descriptor = aDesc.get_SurfaceDescriptorShmem();
|
|
result = new ShmemTextureHost(aID,
|
|
descriptor.data(),
|
|
descriptor.format(),
|
|
aDeallocator,
|
|
aFlags);
|
|
break;
|
|
}
|
|
case SurfaceDescriptor::TSurfaceDescriptorMemory: {
|
|
const SurfaceDescriptorMemory& descriptor = aDesc.get_SurfaceDescriptorMemory();
|
|
result = new MemoryTextureHost(aID,
|
|
reinterpret_cast<uint8_t*>(descriptor.data()),
|
|
descriptor.format(),
|
|
aFlags);
|
|
break;
|
|
}
|
|
default: {
|
|
NS_WARNING("No backend independent TextureHost for this descriptor type");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DeprecatedTextureHost::DeprecatedTextureHost()
|
|
: mFlags(0)
|
|
, mBuffer(nullptr)
|
|
, mDeAllocator(nullptr)
|
|
, mFormat(gfx::FORMAT_UNKNOWN)
|
|
{
|
|
MOZ_COUNT_CTOR(DeprecatedTextureHost);
|
|
}
|
|
|
|
DeprecatedTextureHost::~DeprecatedTextureHost()
|
|
{
|
|
if (mBuffer) {
|
|
if (!(mFlags & TEXTURE_DEALLOCATE_CLIENT)) {
|
|
if (mDeAllocator) {
|
|
mDeAllocator->DestroySharedSurface(mBuffer);
|
|
} else {
|
|
MOZ_ASSERT(mBuffer->type() == SurfaceDescriptor::Tnull_t);
|
|
}
|
|
}
|
|
delete mBuffer;
|
|
}
|
|
MOZ_COUNT_DTOR(DeprecatedTextureHost);
|
|
}
|
|
|
|
void
|
|
DeprecatedTextureHost::Update(const SurfaceDescriptor& aImage,
|
|
nsIntRegion* aRegion,
|
|
nsIntPoint* aOffset)
|
|
{
|
|
UpdateImpl(aImage, aRegion, aOffset);
|
|
}
|
|
|
|
void
|
|
DeprecatedTextureHost::SwapTextures(const SurfaceDescriptor& aImage,
|
|
SurfaceDescriptor* aResult,
|
|
nsIntRegion* aRegion)
|
|
{
|
|
SwapTexturesImpl(aImage, aRegion);
|
|
|
|
MOZ_ASSERT(mBuffer, "trying to swap a non-buffered texture host?");
|
|
if (aResult) {
|
|
*aResult = *mBuffer;
|
|
}
|
|
*mBuffer = aImage;
|
|
// The following SetBuffer call was added in bug 912725 as a fix for the
|
|
// hacky fix introduced in gecko 23 for bug 862324.
|
|
// Note that it is a no-op in the generic case, but not for
|
|
// GrallocDeprecatedTextureHostOGL which overrides SetBuffer to make it
|
|
// register the TextureHost with the GrallocBufferActor.
|
|
// The reason why this SetBuffer calls is needed here is that just above we
|
|
// overwrote *mBuffer in place, so we need to tell the new mBuffer about this
|
|
// TextureHost.
|
|
SetBuffer(mBuffer, mDeAllocator);
|
|
}
|
|
|
|
#ifdef MOZ_LAYERS_HAVE_LOG
|
|
void
|
|
TextureSource::PrintInfo(nsACString& aTo, const char* aPrefix)
|
|
{
|
|
aTo += aPrefix;
|
|
aTo += nsPrintfCString("UnknownTextureSource (0x%p)", this);
|
|
}
|
|
|
|
void
|
|
DeprecatedTextureHost::PrintInfo(nsACString& aTo, const char* aPrefix)
|
|
{
|
|
aTo += aPrefix;
|
|
aTo += nsPrintfCString("%s (0x%p)", Name(), this);
|
|
AppendToString(aTo, GetSize(), " [size=", "]");
|
|
AppendToString(aTo, GetFormat(), " [format=", "]");
|
|
AppendToString(aTo, mFlags, " [flags=", "]");
|
|
}
|
|
#endif // MOZ_LAYERS_HAVE_LOG
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BufferTextureHost::BufferTextureHost(uint64_t aID,
|
|
gfx::SurfaceFormat aFormat,
|
|
TextureFlags aFlags)
|
|
: TextureHost(aID, aFlags)
|
|
, mCompositor(nullptr)
|
|
, mFormat(aFormat)
|
|
, mUpdateSerial(1)
|
|
, mLocked(false)
|
|
, mPartialUpdate(false)
|
|
{}
|
|
|
|
BufferTextureHost::~BufferTextureHost()
|
|
{}
|
|
|
|
void
|
|
BufferTextureHost::Updated(const nsIntRegion* aRegion)
|
|
{
|
|
++mUpdateSerial;
|
|
if (aRegion) {
|
|
mPartialUpdate = true;
|
|
mMaybeUpdatedRegion = *aRegion;
|
|
} else {
|
|
mPartialUpdate = false;
|
|
}
|
|
if (GetFlags() & TEXTURE_IMMEDIATE_UPLOAD) {
|
|
DebugOnly<bool> result = MaybeUpload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr);
|
|
MOZ_ASSERT(result);
|
|
}
|
|
}
|
|
|
|
void
|
|
BufferTextureHost::SetCompositor(Compositor* aCompositor)
|
|
{
|
|
if (mCompositor == aCompositor) {
|
|
return;
|
|
}
|
|
DeallocateDeviceData();
|
|
mCompositor = aCompositor;
|
|
}
|
|
|
|
void
|
|
BufferTextureHost::DeallocateDeviceData()
|
|
{
|
|
RefPtr<NewTextureSource> it = mFirstSource;
|
|
while (it) {
|
|
it->DeallocateDeviceData();
|
|
it = it->GetNextSibling();
|
|
}
|
|
}
|
|
|
|
bool
|
|
BufferTextureHost::Lock()
|
|
{
|
|
mLocked = true;
|
|
return true;
|
|
}
|
|
|
|
void
|
|
BufferTextureHost::Unlock()
|
|
{
|
|
mLocked = false;
|
|
}
|
|
|
|
NewTextureSource*
|
|
BufferTextureHost::GetTextureSources()
|
|
{
|
|
MOZ_ASSERT(mLocked, "should never be called while not locked");
|
|
if (!MaybeUpload(mPartialUpdate ? &mMaybeUpdatedRegion : nullptr)) {
|
|
return nullptr;
|
|
}
|
|
return mFirstSource;
|
|
}
|
|
|
|
gfx::SurfaceFormat
|
|
BufferTextureHost::GetFormat() const
|
|
{
|
|
// mFormat is the format of the data that we share with the content process.
|
|
// GetFormat, on the other hand, expects the format that we present to the
|
|
// Compositor (it is used to choose the effect type).
|
|
// if the compositor does not support YCbCr effects, we give it a RGBX texture
|
|
// instead (see BufferTextureHost::Upload)
|
|
if (mFormat == gfx::FORMAT_YUV &&
|
|
mCompositor &&
|
|
!mCompositor->SupportsEffect(EFFECT_YCBCR)) {
|
|
return gfx::FORMAT_R8G8B8X8;
|
|
}
|
|
return mFormat;
|
|
}
|
|
|
|
bool
|
|
BufferTextureHost::MaybeUpload(nsIntRegion *aRegion)
|
|
{
|
|
if (mFirstSource && mFirstSource->GetUpdateSerial() == mUpdateSerial) {
|
|
return true;
|
|
}
|
|
if (!Upload(aRegion)) {
|
|
return false;
|
|
}
|
|
mFirstSource->SetUpdateSerial(mUpdateSerial);
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
BufferTextureHost::Upload(nsIntRegion *aRegion)
|
|
{
|
|
if (mFormat == gfx::FORMAT_UNKNOWN) {
|
|
NS_WARNING("BufferTextureHost: unsupported format!");
|
|
return false;
|
|
} else if (mFormat == gfx::FORMAT_YUV) {
|
|
YCbCrImageDataDeserializer yuvDeserializer(GetBuffer());
|
|
MOZ_ASSERT(yuvDeserializer.IsValid());
|
|
|
|
if (!mCompositor->SupportsEffect(EFFECT_YCBCR)) {
|
|
RefPtr<gfx::DataSourceSurface> surf = yuvDeserializer.ToDataSourceSurface();
|
|
if (!mFirstSource) {
|
|
mFirstSource = mCompositor->CreateDataTextureSource(mFlags);
|
|
}
|
|
mFirstSource->Update(surf, mFlags, aRegion);
|
|
return true;
|
|
}
|
|
|
|
RefPtr<DataTextureSource> srcY;
|
|
RefPtr<DataTextureSource> srcU;
|
|
RefPtr<DataTextureSource> srcV;
|
|
if (!mFirstSource) {
|
|
// We don't support BigImages for YCbCr compositing.
|
|
srcY = mCompositor->CreateDataTextureSource(mFlags|TEXTURE_DISALLOW_BIGIMAGE);
|
|
srcU = mCompositor->CreateDataTextureSource(mFlags|TEXTURE_DISALLOW_BIGIMAGE);
|
|
srcV = mCompositor->CreateDataTextureSource(mFlags|TEXTURE_DISALLOW_BIGIMAGE);
|
|
mFirstSource = srcY;
|
|
srcY->SetNextSibling(srcU);
|
|
srcU->SetNextSibling(srcV);
|
|
} else {
|
|
// mFormat never changes so if this was created as a YCbCr host and already
|
|
// contains a source it should already have 3 sources.
|
|
// BufferTextureHost only uses DataTextureSources so it is safe to assume
|
|
// all 3 sources are DataTextureSource.
|
|
MOZ_ASSERT(mFirstSource->GetNextSibling());
|
|
MOZ_ASSERT(mFirstSource->GetNextSibling()->GetNextSibling());
|
|
srcY = mFirstSource;
|
|
srcU = mFirstSource->GetNextSibling()->AsDataTextureSource();
|
|
srcV = mFirstSource->GetNextSibling()->GetNextSibling()->AsDataTextureSource();
|
|
}
|
|
|
|
|
|
RefPtr<gfx::DataSourceSurface> tempY =
|
|
gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetYData(),
|
|
yuvDeserializer.GetYStride(),
|
|
gfx::ToIntSize(yuvDeserializer.GetYSize()),
|
|
gfx::FORMAT_A8);
|
|
RefPtr<gfx::DataSourceSurface> tempCb =
|
|
gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetCbData(),
|
|
yuvDeserializer.GetCbCrStride(),
|
|
gfx::ToIntSize(yuvDeserializer.GetCbCrSize()),
|
|
gfx::FORMAT_A8);
|
|
RefPtr<gfx::DataSourceSurface> tempCr =
|
|
gfx::Factory::CreateWrappingDataSourceSurface(yuvDeserializer.GetCrData(),
|
|
yuvDeserializer.GetCbCrStride(),
|
|
gfx::ToIntSize(yuvDeserializer.GetCbCrSize()),
|
|
gfx::FORMAT_A8);
|
|
// We don't support partial updates for Y U V textures
|
|
NS_ASSERTION(!aRegion, "Unsupported partial updates for YCbCr textures");
|
|
if (!srcY->Update(tempY, mFlags) ||
|
|
!srcU->Update(tempCb, mFlags) ||
|
|
!srcV->Update(tempCr, mFlags)) {
|
|
NS_WARNING("failed to update the DataTextureSource");
|
|
return false;
|
|
}
|
|
} else {
|
|
// non-YCbCr case
|
|
if (!mFirstSource) {
|
|
mFirstSource = mCompositor->CreateDataTextureSource();
|
|
}
|
|
ImageDataDeserializer deserializer(GetBuffer());
|
|
if (!deserializer.IsValid()) {
|
|
NS_WARNING("failed to open shmem surface");
|
|
return false;
|
|
}
|
|
|
|
RefPtr<gfx::DataSourceSurface> surf = deserializer.GetAsSurface();
|
|
if (!surf) {
|
|
return false;
|
|
}
|
|
|
|
if (!mFirstSource->Update(surf.get(), mFlags, aRegion)) {
|
|
NS_WARNING("failed to update the DataTextureSource");
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
already_AddRefed<gfxImageSurface>
|
|
BufferTextureHost::GetAsSurface()
|
|
{
|
|
nsRefPtr<gfxImageSurface> result;
|
|
if (mFormat == gfx::FORMAT_UNKNOWN) {
|
|
NS_WARNING("BufferTextureHost: unsupported format!");
|
|
return nullptr;
|
|
} else if (mFormat == gfx::FORMAT_YUV) {
|
|
YCbCrImageDataDeserializer yuvDeserializer(GetBuffer());
|
|
if (!yuvDeserializer.IsValid()) {
|
|
return nullptr;
|
|
}
|
|
result = new gfxImageSurface(yuvDeserializer.GetYData(),
|
|
yuvDeserializer.GetYSize(),
|
|
yuvDeserializer.GetYStride(),
|
|
gfxASurface::ImageFormatA8);
|
|
} else {
|
|
ImageDataDeserializer deserializer(GetBuffer());
|
|
if (!deserializer.IsValid()) {
|
|
return nullptr;
|
|
}
|
|
RefPtr<gfxImageSurface> surf = deserializer.GetAsThebesSurface();
|
|
result = surf.get();
|
|
}
|
|
return result.forget();
|
|
}
|
|
|
|
ShmemTextureHost::ShmemTextureHost(uint64_t aID,
|
|
const ipc::Shmem& aShmem,
|
|
gfx::SurfaceFormat aFormat,
|
|
ISurfaceAllocator* aDeallocator,
|
|
TextureFlags aFlags)
|
|
: BufferTextureHost(aID, aFormat, aFlags)
|
|
, mShmem(new ipc::Shmem(aShmem))
|
|
, mDeallocator(aDeallocator)
|
|
{
|
|
MOZ_COUNT_CTOR(ShmemTextureHost);
|
|
}
|
|
|
|
ShmemTextureHost::~ShmemTextureHost()
|
|
{
|
|
DeallocateDeviceData();
|
|
delete mShmem;
|
|
MOZ_COUNT_DTOR(ShmemTextureHost);
|
|
}
|
|
|
|
void
|
|
ShmemTextureHost::DeallocateSharedData()
|
|
{
|
|
if (mShmem) {
|
|
MOZ_ASSERT(mDeallocator,
|
|
"Shared memory would leak without a ISurfaceAllocator");
|
|
mDeallocator->DeallocShmem(*mShmem);
|
|
}
|
|
}
|
|
|
|
uint8_t* ShmemTextureHost::GetBuffer()
|
|
{
|
|
return mShmem ? mShmem->get<uint8_t>() : nullptr;
|
|
}
|
|
|
|
MemoryTextureHost::MemoryTextureHost(uint64_t aID,
|
|
uint8_t* aBuffer,
|
|
gfx::SurfaceFormat aFormat,
|
|
TextureFlags aFlags)
|
|
: BufferTextureHost(aID, aFormat, aFlags)
|
|
, mBuffer(aBuffer)
|
|
{
|
|
MOZ_COUNT_CTOR(MemoryTextureHost);
|
|
}
|
|
|
|
MemoryTextureHost::~MemoryTextureHost()
|
|
{
|
|
DeallocateDeviceData();
|
|
MOZ_COUNT_DTOR(MemoryTextureHost);
|
|
}
|
|
|
|
void
|
|
MemoryTextureHost::DeallocateSharedData()
|
|
{
|
|
delete[] mBuffer;
|
|
}
|
|
|
|
uint8_t* MemoryTextureHost::GetBuffer()
|
|
{
|
|
return mBuffer;
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace
|