2015-10-15 18:53:33 +03:00
/* -*- 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 "BufferTexture.h"
# include "mozilla/layers/ImageDataSerializer.h"
# include "mozilla/layers/ISurfaceAllocator.h"
# include "mozilla/gfx/Logging.h"
# include "mozilla/gfx/2D.h"
# include "mozilla/fallible.h"
namespace mozilla {
namespace layers {
class MemoryTextureData : public BufferTextureData
{
public :
static MemoryTextureData * Create ( gfx : : IntSize aSize , gfx : : SurfaceFormat aFormat ,
gfx : : BackendType aMoz2DBackend , TextureFlags aFlags ,
TextureAllocationFlags aAllocFlags ,
ISurfaceAllocator * aAllocator ) ;
virtual TextureData *
CreateSimilar ( ISurfaceAllocator * aAllocator ,
TextureFlags aFlags = TextureFlags : : DEFAULT ,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT ) const override ;
virtual bool Serialize ( SurfaceDescriptor & aOutDescriptor ) override ;
virtual void Deallocate ( ISurfaceAllocator * ) override ;
2015-12-16 21:50:58 +03:00
MemoryTextureData ( const BufferDescriptor & aDesc ,
2015-10-15 18:53:33 +03:00
gfx : : BackendType aMoz2DBackend ,
uint8_t * aBuffer , size_t aBufferSize )
2015-12-16 21:50:58 +03:00
: BufferTextureData ( aDesc , aMoz2DBackend )
2015-10-15 18:53:33 +03:00
, mBuffer ( aBuffer )
, mBufferSize ( aBufferSize )
{
MOZ_ASSERT ( aBuffer ) ;
MOZ_ASSERT ( aBufferSize ) ;
}
virtual uint8_t * GetBuffer ( ) override { return mBuffer ; }
virtual size_t GetBufferSize ( ) override { return mBufferSize ; }
protected :
uint8_t * mBuffer ;
size_t mBufferSize ;
} ;
class ShmemTextureData : public BufferTextureData
{
public :
static ShmemTextureData * Create ( gfx : : IntSize aSize , gfx : : SurfaceFormat aFormat ,
gfx : : BackendType aMoz2DBackend , TextureFlags aFlags ,
TextureAllocationFlags aAllocFlags ,
ISurfaceAllocator * aAllocator ) ;
virtual TextureData *
CreateSimilar ( ISurfaceAllocator * aAllocator ,
TextureFlags aFlags = TextureFlags : : DEFAULT ,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT ) const override ;
virtual bool Serialize ( SurfaceDescriptor & aOutDescriptor ) override ;
virtual void Deallocate ( ISurfaceAllocator * aAllocator ) override ;
2015-12-16 21:50:58 +03:00
ShmemTextureData ( const BufferDescriptor & aDesc ,
2015-10-15 18:53:33 +03:00
gfx : : BackendType aMoz2DBackend , mozilla : : ipc : : Shmem aShmem )
2015-12-16 21:50:58 +03:00
: BufferTextureData ( aDesc , aMoz2DBackend )
2015-10-15 18:53:33 +03:00
, mShmem ( aShmem )
{
MOZ_ASSERT ( mShmem . Size < uint8_t > ( ) ) ;
}
virtual uint8_t * GetBuffer ( ) override { return mShmem . get < uint8_t > ( ) ; }
virtual size_t GetBufferSize ( ) override { return mShmem . Size < uint8_t > ( ) ; }
protected :
mozilla : : ipc : : Shmem mShmem ;
} ;
BufferTextureData *
BufferTextureData : : Create ( gfx : : IntSize aSize , gfx : : SurfaceFormat aFormat ,
gfx : : BackendType aMoz2DBackend , TextureFlags aFlags ,
TextureAllocationFlags aAllocFlags ,
ISurfaceAllocator * aAllocator )
{
if ( ! aAllocator | | aAllocator - > IsSameProcess ( ) ) {
return MemoryTextureData : : Create ( aSize , aFormat , aMoz2DBackend , aFlags , aAllocFlags , aAllocator ) ;
} else {
return ShmemTextureData : : Create ( aSize , aFormat , aMoz2DBackend , aFlags , aAllocFlags , aAllocator ) ;
}
}
BufferTextureData *
2015-12-16 21:50:58 +03:00
BufferTextureData : : CreateInternal ( ISurfaceAllocator * aAllocator ,
const BufferDescriptor & aDesc ,
gfx : : BackendType aMoz2DBackend ,
int32_t aBufferSize ,
TextureFlags aTextureFlags )
2015-10-15 18:53:33 +03:00
{
if ( ! aAllocator | | aAllocator - > IsSameProcess ( ) ) {
2015-12-16 21:50:58 +03:00
uint8_t * buffer = new ( fallible ) uint8_t [ aBufferSize ] ;
2015-10-15 18:53:33 +03:00
if ( ! buffer ) {
return nullptr ;
}
2015-12-16 21:50:58 +03:00
return new MemoryTextureData ( aDesc , aMoz2DBackend , buffer , aBufferSize ) ;
2015-10-15 18:53:33 +03:00
} else {
ipc : : Shmem shm ;
2015-12-16 21:50:58 +03:00
if ( ! aAllocator - > AllocUnsafeShmem ( aBufferSize , OptimalShmemType ( ) , & shm ) ) {
2015-10-15 18:53:33 +03:00
return nullptr ;
}
2015-12-16 21:50:58 +03:00
return new ShmemTextureData ( aDesc , aMoz2DBackend , shm ) ;
}
}
BufferTextureData *
BufferTextureData : : CreateForYCbCrWithBufferSize ( ISurfaceAllocator * aAllocator ,
gfx : : SurfaceFormat aFormat ,
int32_t aBufferSize ,
TextureFlags aTextureFlags )
{
if ( aBufferSize = = 0 | | ! gfx : : Factory : : CheckBufferSize ( aBufferSize ) ) {
return nullptr ;
2015-10-15 18:53:33 +03:00
}
// Initialize the metadata with something, even if it will have to be rewritten
// afterwards since we don't know the dimensions of the texture at this point.
2015-12-16 21:50:58 +03:00
BufferDescriptor desc = YCbCrDescriptor ( gfx : : IntSize ( ) , gfx : : IntSize ( ) ,
0 , 0 , 0 , StereoMode : : MONO ) ;
2015-10-15 18:53:33 +03:00
2015-12-16 21:50:58 +03:00
return CreateInternal ( aAllocator , desc , gfx : : BackendType : : NONE , aBufferSize ,
aTextureFlags ) ;
2015-10-15 18:53:33 +03:00
}
BufferTextureData *
BufferTextureData : : CreateForYCbCr ( ISurfaceAllocator * aAllocator ,
gfx : : IntSize aYSize ,
gfx : : IntSize aCbCrSize ,
StereoMode aStereoMode ,
TextureFlags aTextureFlags )
{
2015-12-16 21:50:58 +03:00
uint32_t bufSize = ImageDataSerializer : : ComputeYCbCrBufferSize ( aYSize , aCbCrSize ) ;
if ( bufSize = = 0 ) {
2015-10-15 18:53:33 +03:00
return nullptr ;
}
2015-12-16 21:50:58 +03:00
uint32_t yOffset ;
uint32_t cbOffset ;
uint32_t crOffset ;
ImageDataSerializer : : ComputeYCbCrOffsets ( aYSize . width , aYSize . height ,
aCbCrSize . width , aCbCrSize . height ,
yOffset , cbOffset , crOffset ) ;
2015-10-15 18:53:33 +03:00
2015-12-16 21:50:58 +03:00
YCbCrDescriptor descriptor = YCbCrDescriptor ( aYSize , aCbCrSize , yOffset , cbOffset ,
crOffset , aStereoMode ) ;
return CreateInternal ( aAllocator , descriptor , gfx : : BackendType : : NONE , bufSize ,
aTextureFlags ) ;
}
gfx : : IntSize
BufferTextureData : : GetSize ( ) const
{
return ImageDataSerializer : : SizeFromBufferDescriptor ( mDescriptor ) ;
}
gfx : : SurfaceFormat
BufferTextureData : : GetFormat ( ) const
{
return ImageDataSerializer : : FormatFromBufferDescriptor ( mDescriptor ) ;
2015-10-15 18:53:33 +03:00
}
bool
BufferTextureData : : SupportsMoz2D ( ) const
{
2015-12-16 21:50:58 +03:00
switch ( GetFormat ( ) ) {
2015-10-15 18:53:33 +03:00
case gfx : : SurfaceFormat : : YUV :
case gfx : : SurfaceFormat : : NV12 :
case gfx : : SurfaceFormat : : UNKNOWN :
return false ;
default :
return true ;
}
}
already_AddRefed < gfx : : DrawTarget >
BufferTextureData : : BorrowDrawTarget ( )
{
if ( mDrawTarget ) {
mDrawTarget - > SetTransform ( gfx : : Matrix ( ) ) ;
RefPtr < gfx : : DrawTarget > dt = mDrawTarget ;
return dt . forget ( ) ;
}
2015-12-16 21:50:58 +03:00
if ( mDescriptor . type ( ) ! = BufferDescriptor : : TRGBDescriptor ) {
2015-10-15 18:53:33 +03:00
return nullptr ;
}
2015-12-16 21:50:58 +03:00
const RGBDescriptor & rgb = mDescriptor . get_RGBDescriptor ( ) ;
uint32_t stride = ImageDataSerializer : : GetRGBStride ( rgb ) ;
mDrawTarget = gfx : : Factory : : CreateDrawTargetForData ( mMoz2DBackend ,
GetBuffer ( ) , rgb . size ( ) ,
stride , rgb . format ( ) ) ;
2015-10-15 18:53:33 +03:00
if ( mDrawTarget ) {
RefPtr < gfx : : DrawTarget > dt = mDrawTarget ;
return dt . forget ( ) ;
}
// TODO - should we warn? should we really fallback to cairo? perhaps
// at least update mMoz2DBackend...
2015-12-16 21:50:58 +03:00
if ( mMoz2DBackend ! = gfx : : BackendType : : CAIRO ) {
mDrawTarget = gfx : : Factory : : CreateDrawTargetForData ( gfx : : BackendType : : CAIRO ,
GetBuffer ( ) , rgb . size ( ) ,
stride , rgb . format ( ) ) ;
}
2015-10-15 18:53:33 +03:00
if ( ! mDrawTarget ) {
gfxCriticalNote < < " BorrowDrawTarget failure, original backend " < < ( int ) mMoz2DBackend ;
}
RefPtr < gfx : : DrawTarget > dt = mDrawTarget ;
return dt . forget ( ) ;
}
bool
BufferTextureData : : BorrowMappedData ( MappedTextureData & aData )
{
2015-12-16 21:50:58 +03:00
if ( GetFormat ( ) = = gfx : : SurfaceFormat : : YUV ) {
2015-10-15 18:53:33 +03:00
return false ;
}
2015-12-16 21:50:58 +03:00
gfx : : IntSize size = GetSize ( ) ;
2015-10-15 18:53:33 +03:00
2015-12-16 21:50:58 +03:00
aData . data = GetBuffer ( ) ;
aData . size = size ;
aData . format = GetFormat ( ) ;
aData . stride = ImageDataSerializer : : ComputeRGBStride ( aData . format , size . width ) ;
2015-10-15 18:53:33 +03:00
return true ;
}
bool
BufferTextureData : : BorrowMappedYCbCrData ( MappedYCbCrTextureData & aMap )
{
2015-12-16 21:50:58 +03:00
if ( mDescriptor . type ( ) ! = BufferDescriptor : : TYCbCrDescriptor ) {
2015-10-15 18:53:33 +03:00
return false ;
}
2015-12-16 21:50:58 +03:00
const YCbCrDescriptor & desc = mDescriptor . get_YCbCrDescriptor ( ) ;
uint8_t * data = GetBuffer ( ) ;
auto ySize = desc . ySize ( ) ;
auto cbCrSize = desc . cbCrSize ( ) ;
2015-10-15 18:53:33 +03:00
2015-12-16 21:50:58 +03:00
aMap . stereoMode = desc . stereoMode ( ) ;
aMap . metadata = nullptr ;
2015-10-15 18:53:33 +03:00
2015-12-16 21:50:58 +03:00
aMap . y . data = data + desc . yOffset ( ) ;
aMap . y . size = ySize ;
aMap . y . stride = ySize . width ;
2015-10-15 18:53:33 +03:00
aMap . y . skip = 0 ;
2015-12-16 21:50:58 +03:00
aMap . cb . data = data + desc . cbOffset ( ) ;
aMap . cb . size = cbCrSize ;
aMap . cb . stride = cbCrSize . width ;
2015-10-15 18:53:33 +03:00
aMap . cb . skip = 0 ;
2015-12-16 21:50:58 +03:00
aMap . cr . data = data + desc . crOffset ( ) ;
aMap . cr . size = cbCrSize ;
aMap . cr . stride = cbCrSize . width ;
2015-10-15 18:53:33 +03:00
aMap . cr . skip = 0 ;
return true ;
}
bool
BufferTextureData : : UpdateFromSurface ( gfx : : SourceSurface * aSurface )
{
2015-12-16 21:50:58 +03:00
if ( mDescriptor . type ( ) ! = BufferDescriptor : : TRGBDescriptor ) {
return false ;
}
const RGBDescriptor & rgb = mDescriptor . get_RGBDescriptor ( ) ;
2015-10-15 18:53:33 +03:00
2015-12-16 21:50:58 +03:00
uint32_t stride = ImageDataSerializer : : GetRGBStride ( rgb ) ;
RefPtr < gfx : : DataSourceSurface > surface =
gfx : : Factory : : CreateWrappingDataSourceSurface ( GetBuffer ( ) , stride ,
rgb . size ( ) , rgb . format ( ) ) ;
2015-10-15 18:53:33 +03:00
if ( ! surface ) {
gfxCriticalError ( ) < < " Failed to get serializer as surface! " ;
return false ;
}
RefPtr < gfx : : DataSourceSurface > srcSurf = aSurface - > GetDataSurface ( ) ;
if ( ! srcSurf ) {
2015-12-29 22:03:58 +03:00
gfxCriticalError ( ) < < " Failed to GetDataSurface in UpdateFromSurface (BT). " ;
2015-10-15 18:53:33 +03:00
return false ;
}
if ( surface - > GetSize ( ) ! = srcSurf - > GetSize ( ) | | surface - > GetFormat ( ) ! = srcSurf - > GetFormat ( ) ) {
2015-12-29 22:03:58 +03:00
gfxCriticalError ( ) < < " Attempt to update texture client from a surface with a different size or format (BT)! This: " < < surface - > GetSize ( ) < < " " < < surface - > GetFormat ( ) < < " Other: " < < aSurface - > GetSize ( ) < < " " < < aSurface - > GetFormat ( ) ;
2015-10-15 18:53:33 +03:00
return false ;
}
gfx : : DataSourceSurface : : MappedSurface sourceMap ;
gfx : : DataSourceSurface : : MappedSurface destMap ;
if ( ! srcSurf - > Map ( gfx : : DataSourceSurface : : READ , & sourceMap ) ) {
2015-12-29 22:03:58 +03:00
gfxCriticalError ( ) < < " Failed to map source surface for UpdateFromSurface (BT). " ;
2015-10-15 18:53:33 +03:00
return false ;
}
if ( ! surface - > Map ( gfx : : DataSourceSurface : : WRITE , & destMap ) ) {
srcSurf - > Unmap ( ) ;
gfxCriticalError ( ) < < " Failed to map destination surface for UpdateFromSurface. " ;
return false ;
}
for ( int y = 0 ; y < srcSurf - > GetSize ( ) . height ; y + + ) {
memcpy ( destMap . mData + destMap . mStride * y ,
sourceMap . mData + sourceMap . mStride * y ,
srcSurf - > GetSize ( ) . width * BytesPerPixel ( srcSurf - > GetFormat ( ) ) ) ;
}
srcSurf - > Unmap ( ) ;
surface - > Unmap ( ) ;
return true ;
}
2015-12-16 21:50:58 +03:00
void
BufferTextureData : : SetDesciptor ( const BufferDescriptor & aDescriptor )
{
MOZ_ASSERT ( mDescriptor . type ( ) = = BufferDescriptor : : TYCbCrDescriptor ) ;
MOZ_ASSERT ( mDescriptor . get_YCbCrDescriptor ( ) . ySize ( ) = = gfx : : IntSize ( ) ) ;
mDescriptor = aDescriptor ;
}
2015-10-15 18:53:33 +03:00
bool
MemoryTextureData : : Serialize ( SurfaceDescriptor & aOutDescriptor )
{
MOZ_ASSERT ( GetFormat ( ) ! = gfx : : SurfaceFormat : : UNKNOWN ) ;
if ( GetFormat ( ) = = gfx : : SurfaceFormat : : UNKNOWN ) {
return false ;
}
2015-12-16 21:50:58 +03:00
uintptr_t ptr = reinterpret_cast < uintptr_t > ( mBuffer ) ;
aOutDescriptor = SurfaceDescriptorBuffer ( mDescriptor , MemoryOrShmem ( ptr ) ) ;
2015-10-15 18:53:33 +03:00
return true ;
}
2015-12-16 21:50:58 +03:00
static bool InitBuffer ( uint8_t * buf , size_t bufSize , TextureAllocationFlags aAllocFlags )
2015-10-15 18:53:33 +03:00
{
if ( ! buf ) {
gfxDebug ( ) < < " BufferTextureData: Failed to allocate " < < bufSize < < " bytes " ;
return false ;
}
if ( aAllocFlags & ALLOC_CLEAR_BUFFER ) {
memset ( buf , 0 , bufSize ) ;
}
if ( aAllocFlags & ALLOC_CLEAR_BUFFER_WHITE ) {
memset ( buf , 0xFF , bufSize ) ;
}
return true ;
}
MemoryTextureData *
MemoryTextureData : : Create ( gfx : : IntSize aSize , gfx : : SurfaceFormat aFormat ,
gfx : : BackendType aMoz2DBackend , TextureFlags aFlags ,
TextureAllocationFlags aAllocFlags ,
ISurfaceAllocator * )
{
2015-12-16 21:50:58 +03:00
// Should have used CreateForYCbCr.
MOZ_ASSERT ( aFormat ! = gfx : : SurfaceFormat : : YUV ) ;
2015-10-15 18:53:33 +03:00
if ( aSize . width < = 0 | | aSize . height < = 0 ) {
gfxDebug ( ) < < " Asking for buffer of invalid size " < < aSize . width < < " x " < < aSize . height ;
return nullptr ;
}
2015-12-16 21:50:58 +03:00
uint32_t bufSize = ImageDataSerializer : : ComputeRGBBufferSize ( aSize , aFormat ) ;
2015-10-15 18:53:33 +03:00
if ( ! bufSize ) {
return nullptr ;
}
uint8_t * buf = new ( fallible ) uint8_t [ bufSize ] ;
2015-12-16 21:50:58 +03:00
if ( ! InitBuffer ( buf , bufSize , aAllocFlags ) ) {
return nullptr ;
2015-10-15 18:53:33 +03:00
}
2015-12-16 21:50:58 +03:00
GfxMemoryImageReporter : : DidAlloc ( buf ) ;
BufferDescriptor descriptor = RGBDescriptor ( aSize , aFormat ) ;
return new MemoryTextureData ( descriptor , aMoz2DBackend , buf , bufSize ) ;
2015-10-15 18:53:33 +03:00
}
void
MemoryTextureData : : Deallocate ( ISurfaceAllocator * )
{
MOZ_ASSERT ( mBuffer ) ;
GfxMemoryImageReporter : : WillFree ( mBuffer ) ;
delete [ ] mBuffer ;
mBuffer = nullptr ;
}
TextureData *
MemoryTextureData : : CreateSimilar ( ISurfaceAllocator * aAllocator ,
TextureFlags aFlags ,
TextureAllocationFlags aAllocFlags ) const
{
2015-12-16 21:50:58 +03:00
return MemoryTextureData : : Create ( GetSize ( ) , GetFormat ( ) , mMoz2DBackend ,
2015-10-15 18:53:33 +03:00
aFlags , aAllocFlags , aAllocator ) ;
}
bool
ShmemTextureData : : Serialize ( SurfaceDescriptor & aOutDescriptor )
{
MOZ_ASSERT ( GetFormat ( ) ! = gfx : : SurfaceFormat : : UNKNOWN ) ;
if ( GetFormat ( ) = = gfx : : SurfaceFormat : : UNKNOWN ) {
return false ;
}
2015-12-16 21:50:58 +03:00
aOutDescriptor = SurfaceDescriptorBuffer ( mDescriptor , MemoryOrShmem ( mShmem ) ) ;
2015-10-15 18:53:33 +03:00
return true ;
}
ShmemTextureData *
ShmemTextureData : : Create ( gfx : : IntSize aSize , gfx : : SurfaceFormat aFormat ,
gfx : : BackendType aMoz2DBackend , TextureFlags aFlags ,
TextureAllocationFlags aAllocFlags ,
ISurfaceAllocator * aAllocator )
{
MOZ_ASSERT ( aAllocator ) ;
2015-12-16 21:50:58 +03:00
// Should have used CreateForYCbCr.
MOZ_ASSERT ( aFormat ! = gfx : : SurfaceFormat : : YUV ) ;
2015-10-15 18:53:33 +03:00
if ( ! aAllocator ) {
return nullptr ;
}
if ( aSize . width < = 0 | | aSize . height < = 0 ) {
gfxDebug ( ) < < " Asking for buffer of invalid size " < < aSize . width < < " x " < < aSize . height ;
return nullptr ;
}
2015-12-16 21:50:58 +03:00
uint32_t bufSize = ImageDataSerializer : : ComputeRGBBufferSize ( aSize , aFormat ) ;
2015-10-15 18:53:33 +03:00
if ( ! bufSize ) {
return nullptr ;
}
mozilla : : ipc : : Shmem shm ;
if ( ! aAllocator - > AllocUnsafeShmem ( bufSize , OptimalShmemType ( ) , & shm ) ) {
return nullptr ;
}
uint8_t * buf = shm . get < uint8_t > ( ) ;
2015-12-16 21:50:58 +03:00
if ( ! InitBuffer ( buf , bufSize , aAllocFlags ) ) {
return nullptr ;
2015-10-15 18:53:33 +03:00
}
2015-12-16 21:50:58 +03:00
BufferDescriptor descriptor = RGBDescriptor ( aSize , aFormat ) ;
return new ShmemTextureData ( descriptor , aMoz2DBackend , shm ) ;
2015-10-15 18:53:33 +03:00
return nullptr ;
}
TextureData *
ShmemTextureData : : CreateSimilar ( ISurfaceAllocator * aAllocator ,
TextureFlags aFlags ,
TextureAllocationFlags aAllocFlags ) const
{
2015-12-16 21:50:58 +03:00
return ShmemTextureData : : Create ( GetSize ( ) , GetFormat ( ) , mMoz2DBackend ,
2015-10-15 18:53:33 +03:00
aFlags , aAllocFlags , aAllocator ) ;
}
void
ShmemTextureData : : Deallocate ( ISurfaceAllocator * aAllocator )
{
aAllocator - > DeallocShmem ( mShmem ) ;
}
} // namespace
} // namespace