Bug 1200595 - DIB TextureData implementation. r=Bas

This commit is contained in:
Nicolas Silva 2015-11-20 14:24:58 +01:00
parent 4b05b5d988
commit e6a5af34e7
3 changed files with 209 additions and 241 deletions

View File

@ -14,64 +14,117 @@ using namespace gfx;
namespace layers {
bool
TextureClientDIB::Lock(OpenMode)
/**
* Can only be drawn into through Cairo.
* The coresponding TextureHost depends on the compositor
*/
class MemoryDIBTextureData : public DIBTextureData
{
MOZ_ASSERT(!mIsLocked);
if (!IsValid()) {
return false;
}
mIsLocked = true;
return true;
}
public:
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
void
TextureClientDIB::Unlock()
virtual TextureData*
CreateSimilar(ISurfaceAllocator* aAllocator,
TextureFlags aFlags = TextureFlags::DEFAULT,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
static
DIBTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat);
virtual void Deallocate(ISurfaceAllocator* aAllocator) override
{
mSurface = nullptr;
}
MemoryDIBTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
gfxWindowsSurface* aSurface)
: DIBTextureData(aSize, aFormat, aSurface)
{
MOZ_COUNT_CTOR(MemoryDIBTextureData);
}
virtual ~MemoryDIBTextureData()
{
MOZ_COUNT_DTOR(MemoryDIBTextureData);
}
};
/**
* Can only be drawn into through Cairo.
* The coresponding TextureHost depends on the compositor
*/
class ShmemDIBTextureData : public DIBTextureData
{
MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!");
if (mDrawTarget) {
if (mReadbackSink) {
RefPtr<SourceSurface> snapshot = mDrawTarget->Snapshot();
RefPtr<DataSourceSurface> dataSurf = snapshot->GetDataSurface();
mReadbackSink->ProcessReadback(dataSurf);
public:
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
virtual TextureData*
CreateSimilar(ISurfaceAllocator* aAllocator,
TextureFlags aFlags = TextureFlags::DEFAULT,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
static
DIBTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
ISurfaceAllocator* aAllocator);
void DeallocateData()
{
if (mSurface) {
::DeleteObject(mBitmap);
::DeleteDC(mDC);
::CloseHandle(mFileMapping);
mBitmap = NULL;
mDC = NULL;
mFileMapping = NULL;
mSurface = nullptr;
}
mDrawTarget->Flush();
mDrawTarget = nullptr;
}
mIsLocked = false;
virtual void Deallocate(ISurfaceAllocator* aAllocator) override
{
DeallocateData();
}
ShmemDIBTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
gfxWindowsSurface* aSurface,
HANDLE aFileMapping, HANDLE aHostHandle,
HDC aDC, HBITMAP aBitmap)
: DIBTextureData(aSize, aFormat, aSurface)
, mFileMapping(aFileMapping)
, mHostHandle(aHostHandle)
, mDC(aDC)
, mBitmap(aBitmap)
{
MOZ_COUNT_CTOR(ShmemDIBTextureData);
}
virtual ~ShmemDIBTextureData()
{
MOZ_COUNT_DTOR(ShmemDIBTextureData);
}
HANDLE mFileMapping;
HANDLE mHostHandle;
HDC mDC;
HBITMAP mBitmap;
};
already_AddRefed<gfx::DrawTarget>
DIBTextureData::BorrowDrawTarget()
{
return gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mSurface, mSize);
}
gfx::DrawTarget*
TextureClientDIB::BorrowDrawTarget()
bool
DIBTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
{
MOZ_ASSERT(mIsLocked && IsAllocated());
if (!mDrawTarget) {
mDrawTarget =
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mSurface, mSize);
}
if (!mDrawTarget) {
gfxCriticalNote << "DIB failed draw target surface " << mSize << ", " << (int)mIsLocked << ", " << IsAllocated();
}
return mDrawTarget;
}
void
TextureClientDIB::UpdateFromSurface(gfx::SourceSurface* aSurface)
{
MOZ_ASSERT(mIsLocked && IsAllocated());
RefPtr<gfxImageSurface> imgSurf = mSurface->GetAsImageSurface();
RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
if (!srcSurf) {
gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface.";
return;
return false;
}
DataSourceSurface::MappedSurface sourceMap;
@ -84,43 +137,40 @@ TextureClientDIB::UpdateFromSurface(gfx::SourceSurface* aSurface)
}
srcSurf->Unmap();
return true;
}
TextureClientMemoryDIB::TextureClientMemoryDIB(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags)
: TextureClientDIB(aAllocator, aFormat, aFlags)
DIBTextureData*
DIBTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
ISurfaceAllocator* aAllocator)
{
MOZ_COUNT_CTOR(TextureClientMemoryDIB);
}
TextureClientMemoryDIB::~TextureClientMemoryDIB()
{
MOZ_COUNT_DTOR(TextureClientMemoryDIB);
}
already_AddRefed<TextureClient>
TextureClientMemoryDIB::CreateSimilar(TextureFlags aFlags,
TextureAllocationFlags aAllocFlags) const
{
RefPtr<TextureClient> tex = new TextureClientMemoryDIB(mAllocator, mFormat,
mFlags | aFlags);
if (!tex->AllocateForSurface(mSize, aAllocFlags)) {
if (!aAllocator) {
return nullptr;
}
if (aFormat == gfx::SurfaceFormat::UNKNOWN) {
return nullptr;
}
if (aAllocator->IsSameProcess()) {
return MemoryDIBTextureData::Create(aSize, aFormat);
} else {
return ShmemDIBTextureData::Create(aSize, aFormat, aAllocator);
}
}
return tex.forget();
TextureData*
MemoryDIBTextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
TextureFlags aFlags,
TextureAllocationFlags aAllocFlags) const
{
if (!aAllocator) {
return nullptr;
}
return MemoryDIBTextureData::Create(mSize, mFormat);
}
bool
TextureClientMemoryDIB::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
MemoryDIBTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
{
MOZ_ASSERT(IsValid());
if (!IsAllocated()) {
return false;
}
MOZ_ASSERT(mSurface);
// The host will release this ref when it receives the surface descriptor.
// We AddRef in case we die before the host receives the pointer.
@ -129,64 +179,34 @@ TextureClientMemoryDIB::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
return true;
}
bool
TextureClientMemoryDIB::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
DIBTextureData*
MemoryDIBTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat)
{
MOZ_ASSERT(!IsAllocated());
mSize = aSize;
mSurface = new gfxWindowsSurface(aSize, SurfaceFormatToImageFormat(mFormat));
if (!mSurface || mSurface->CairoStatus())
{
NS_WARNING("Could not create surface");
mSurface = nullptr;
return false;
}
return true;
}
TextureClientShmemDIB::TextureClientShmemDIB(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags)
: TextureClientDIB(aAllocator, aFormat, aFlags)
, mFileMapping(NULL)
, mHostHandle(NULL)
, mDC(NULL)
, mBitmap(NULL)
{
MOZ_COUNT_CTOR(TextureClientShmemDIB);
}
TextureClientShmemDIB::~TextureClientShmemDIB()
{
MOZ_COUNT_DTOR(TextureClientShmemDIB);
::DeleteObject(mBitmap);
::DeleteDC(mDC);
::CloseHandle(mFileMapping);
}
already_AddRefed<TextureClient>
TextureClientShmemDIB::CreateSimilar(TextureFlags aFlags,
TextureAllocationFlags aAllocFlags) const
{
RefPtr<TextureClient> tex = new TextureClientShmemDIB(mAllocator, mFormat,
mFlags | aFlags);
if (!tex->AllocateForSurface(mSize, aAllocFlags)) {
RefPtr<gfxWindowsSurface> surface
= new gfxWindowsSurface(aSize, SurfaceFormatToImageFormat(aFormat));
if (!surface || surface->CairoStatus()) {
NS_WARNING("Could not create DIB surface");
return nullptr;
}
return tex.forget();
return new MemoryDIBTextureData(aSize, aFormat, surface);
}
TextureData*
ShmemDIBTextureData::CreateSimilar(ISurfaceAllocator* aAllocator,
TextureFlags aFlags,
TextureAllocationFlags aAllocFlags) const
{
if (!aAllocator) {
return nullptr;
}
return ShmemDIBTextureData::Create(mSize, mFormat, aAllocator);
}
bool
TextureClientShmemDIB::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
ShmemDIBTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
{
MOZ_ASSERT(IsValid());
MOZ_ASSERT(mAllocator->ParentPid() != base::ProcessId());
if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
return false;
}
@ -195,33 +215,33 @@ TextureClientShmemDIB::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
return true;
}
bool
TextureClientShmemDIB::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
DIBTextureData*
ShmemDIBTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
ISurfaceAllocator* aAllocator)
{
MOZ_ASSERT(!IsAllocated());
MOZ_ASSERT(mAllocator->ParentPid() != base::ProcessId());
MOZ_ASSERT(aAllocator->ParentPid() != base::ProcessId());
mSize = aSize;
DWORD mapSize = aSize.width * aSize.height * BytesPerPixel(aFormat);
HANDLE fileMapping = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, mapSize, NULL);
DWORD mapSize = mSize.width * mSize.height * BytesPerPixel(mFormat);
mFileMapping = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, mapSize, NULL);
if (!mFileMapping) {
if (!fileMapping) {
gfxCriticalError() << "Failed to create memory file mapping for " << mapSize << " bytes.";
return false;
return nullptr;
}
uint8_t* data = (uint8_t*)::MapViewOfFile(mFileMapping, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, mSize.width * mSize.height * BytesPerPixel(mFormat));
uint8_t* data = (uint8_t*)::MapViewOfFile(fileMapping, FILE_MAP_WRITE | FILE_MAP_READ,
0, 0, aSize.width * aSize.height
* BytesPerPixel(aFormat));
memset(data, 0x80, mSize.width * mSize.height * BytesPerPixel(mFormat));
memset(data, 0x80, aSize.width * aSize.height * BytesPerPixel(aFormat));
::UnmapViewOfFile(mFileMapping);
::UnmapViewOfFile(fileMapping);
BITMAPV4HEADER header;
memset(&header, 0, sizeof(BITMAPV4HEADER));
header.bV4Size = sizeof(BITMAPV4HEADER);
header.bV4Width = mSize.width;
header.bV4Height = -LONG(mSize.height); // top-to-buttom DIB
header.bV4Width = aSize.width;
header.bV4Height = -LONG(aSize.height); // top-to-buttom DIB
header.bV4Planes = 1;
header.bV4BitCount = 32;
header.bV4V4Compression = BI_BITFIELDS;
@ -229,46 +249,54 @@ TextureClientShmemDIB::AllocateForSurface(gfx::IntSize aSize, TextureAllocationF
header.bV4GreenMask = 0x0000FF00;
header.bV4BlueMask = 0x000000FF;
mDC = ::CreateCompatibleDC(::GetDC(NULL));
HDC dc = ::CreateCompatibleDC(::GetDC(NULL));
if (!mDC) {
::CloseHandle(mFileMapping);
if (!dc) {
::CloseHandle(fileMapping);
gfxCriticalError() << "Failed to create DC for bitmap.";
return false;
return nullptr;
}
void* bits;
mBitmap = ::CreateDIBSection(mDC, (BITMAPINFO*)&header, DIB_RGB_COLORS, &bits, mFileMapping, 0);
HBITMAP bitmap = ::CreateDIBSection(dc, (BITMAPINFO*)&header,
DIB_RGB_COLORS, &bits,
fileMapping, 0);
if (!mBitmap) {
gfxCriticalError() << "Failed to create DIB section for a bitmap of size " << mSize;
::CloseHandle(mFileMapping);
::DeleteDC(mDC);
return false;
if (!bitmap) {
gfxCriticalError() << "Failed to create DIB section for a bitmap of size "
<< aSize;
::CloseHandle(fileMapping);
::DeleteDC(dc);
return nullptr;
}
::SelectObject(mDC, mBitmap);
::SelectObject(dc, bitmap);
mSurface = new gfxWindowsSurface(mDC, 0);
if (mSurface->CairoStatus())
RefPtr<gfxWindowsSurface> surface = new gfxWindowsSurface(dc, 0);
if (surface->CairoStatus())
{
::DeleteObject(mBitmap);
::DeleteDC(mDC);
::CloseHandle(mFileMapping);
gfxCriticalError() << "Could not create surface, status: " << mSurface->CairoStatus();
mSurface = nullptr;
return false;
::DeleteObject(bitmap);
::DeleteDC(dc);
::CloseHandle(fileMapping);
gfxCriticalError() << "Could not create surface, status: "
<< surface->CairoStatus();
return nullptr;
}
if (!ipc::DuplicateHandle(mFileMapping, mAllocator->ParentPid(), &mHostHandle, 0, DUPLICATE_SAME_ACCESS)) {
HANDLE hostHandle = NULL;
if (!ipc::DuplicateHandle(fileMapping, aAllocator->ParentPid(),
&hostHandle, 0, DUPLICATE_SAME_ACCESS)) {
gfxCriticalError() << "Failed to duplicate handle to parent process for surface.";
::DeleteObject(mBitmap);
::DeleteDC(mDC);
::CloseHandle(mFileMapping);
return false;
::DeleteObject(bitmap);
::DeleteDC(dc);
::CloseHandle(fileMapping);
return nullptr;
}
return true;
return new ShmemDIBTextureData(aSize, aFormat, surface,
fileMapping, hostHandle,
dc, bitmap);
}

View File

@ -15,101 +15,42 @@
namespace mozilla {
namespace layers {
class TextureClientDIB : public TextureClient
class DIBTextureData : public TextureData
{
public:
virtual bool IsAllocated() const override { return !!mSurface; }
virtual bool Lock(OpenMode, FenceHandle*) override { return true; }
virtual bool Lock(OpenMode aOpenMode) override;
virtual void Unlock() override;
virtual bool IsLocked() const override{ return mIsLocked; }
virtual void Unlock() override {}
virtual gfx::IntSize GetSize() const override { return mSize; }
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
virtual bool CanExposeDrawTarget() const override { return true; }
virtual bool SupportsMoz2D() const override { return true; }
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::SourceSurface* aSurface) override;
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
virtual bool HasInternalBuffer() const override { return true; }
static
DIBTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
ISurfaceAllocator* aAllocator);
protected:
TextureClientDIB(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat, TextureFlags aFlags)
: TextureClient(aAllocator, aFlags)
, mFormat(aFormat)
, mIsLocked(false)
{ }
DIBTextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
gfxWindowsSurface* aSurface)
: mSurface(aSurface)
, mSize(aSize)
, mFormat(aFormat)
{
MOZ_ASSERT(aSurface);
}
RefPtr<gfxWindowsSurface> mSurface;
RefPtr<gfx::DrawTarget> mDrawTarget;
gfx::IntSize mSize;
gfx::SurfaceFormat mFormat;
bool mIsLocked;
};
/**
* Can only be drawn into through Cairo.
* Prefer CairoTextureClient when possible.
* The coresponding TextureHost depends on the compositor
*/
class TextureClientMemoryDIB : public TextureClientDIB
{
public:
TextureClientMemoryDIB(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags);
virtual ~TextureClientMemoryDIB();
// TextureClient
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;
virtual already_AddRefed<TextureClient>
CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
};
/**
* Can only be drawn into through Cairo.
* Prefer CairoTextureClient when possible.
* The coresponding TextureHost depends on the compositor
*/
class TextureClientShmemDIB : public TextureClientDIB
{
public:
TextureClientShmemDIB(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags);
virtual ~TextureClientShmemDIB();
// TextureClient
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;
virtual already_AddRefed<TextureClient>
CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
protected:
HANDLE mFileMapping;
HANDLE mHostHandle;
HDC mDC;
HBITMAP mBitmap;
};
/**

View File

@ -593,10 +593,9 @@ TextureClient::CreateForDrawing(CompositableForwarder* aAllocator,
aAllocator->IsSameProcess() &&
moz2DBackend == gfx::BackendType::CAIRO &&
NS_IsMainThread()) {
if (aAllocator->IsSameProcess()) {
texture = new TextureClientMemoryDIB(aAllocator, aFormat, aTextureFlags);
} else {
texture = new TextureClientShmemDIB(aAllocator, aFormat, aTextureFlags);
TextureData* data = DIBTextureData::Create(aSize, aFormat, aAllocator);
if (data) {
return MakeAndAddRef<ClientTexture>(data, aTextureFlags, aAllocator);
}
}
#endif