Bug 651192 - Part 5: Support remote access to ImageContainers. r=roc

This commit is contained in:
Bas Schouten 2012-02-16 04:26:19 +01:00
Родитель 048a0c15c9
Коммит b798e874b1
11 изменённых файлов: 548 добавлений и 122 удалений

Просмотреть файл

@ -212,9 +212,10 @@ nsPluginInstanceOwner::GetImageContainer()
mInstance->GetImageContainer(getter_AddRefs(container));
if (container) {
#ifdef XP_MACOSX
nsRefPtr<Image> image = container->GetCurrentImage();
AutoLockImage autoLock(container);
Image* image = autoLock.GetImage();
if (image && image->GetFormat() == Image::MAC_IO_SURFACE && mObjectFrame) {
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image.get());
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image);
NS_ADDREF_THIS();
oglImage->SetUpdateCallback(&DrawPlugin, this);
oglImage->SetDestroyCallback(&OnDestroyImage);
@ -3719,10 +3720,11 @@ void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
nsRefPtr<ImageContainer> container = mObjectFrame->GetImageContainer();
if (container) {
#ifdef XP_MACOSX
nsRefPtr<Image> image = container->GetCurrentImage();
AutoLockImage autoLock(container);
Image *image = autoLock.GetImage();
if (image && (image->GetFormat() == Image::MAC_IO_SURFACE) && mObjectFrame) {
// Undo what we did to the current image in SetCurrentImage().
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image.get());
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image);
oglImage->SetUpdateCallback(nsnull, nsnull);
oglImage->SetDestroyCallback(nsnull);
// If we have a current image here, its destructor hasn't yet been
@ -3730,6 +3732,9 @@ void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
// to do ourselves what OnDestroyImage() would have done.
NS_RELEASE_THIS();
}
// Important! Unlock here otherwise SetCurrentImage will deadlock with
// our lock if we have a RemoteImage.
autoLock.Unlock();
#endif
container->SetCurrentImage(nsnull);
}

Просмотреть файл

@ -367,7 +367,8 @@ PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginDrawingModel(
#endif
{
if (!GetImageContainer()) {
return false;
*result = NPERR_GENERIC_ERROR;
return true;
}
mDrawingModel = drawingModel;

Просмотреть файл

@ -36,6 +36,7 @@
* ***** END LICENSE BLOCK ***** */
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ipc/CrossProcessMutex.h"
#include "ImageLayers.h"
#include "gfxImageSurface.h"
#include "yuv_convert.h"
@ -119,15 +120,91 @@ ImageContainer::SetCurrentImage(Image *aImage)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
mRemoteDataMutex->Lock();
// This is important since it ensures we won't change the active image
// when we currently have a locked image that depends on mRemoteData.
}
mActiveImage = aImage;
CurrentImageChanged();
if (mRemoteData) {
mRemoteDataMutex->Unlock();
}
}
bool
ImageContainer::HasCurrentImage()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
EnsureActiveImage();
return !!mActiveImage.get();
}
return !!mActiveImage.get();
}
already_AddRefed<Image>
ImageContainer::LockCurrentImage()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
mRemoteDataMutex->Lock();
}
EnsureActiveImage();
nsRefPtr<Image> retval = mActiveImage;
return retval.forget();
}
already_AddRefed<gfxASurface>
ImageContainer::GetCurrentAsSurface(gfxIntSize *aSize)
ImageContainer::LockCurrentAsSurface(gfxIntSize *aSize, Image** aCurrentImage)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
mRemoteDataMutex->Lock();
EnsureActiveImage();
if (aCurrentImage) {
NS_IF_ADDREF(mActiveImage);
*aCurrentImage = mActiveImage.get();
}
if (!mActiveImage) {
return nsnull;
}
if (mActiveImage->GetFormat() == Image::REMOTE_IMAGE_BITMAP) {
nsRefPtr<gfxImageSurface> newSurf =
new gfxImageSurface(mRemoteData->mBitmap.mData, mRemoteData->mSize, mRemoteData->mBitmap.mStride,
mRemoteData->mFormat == RemoteImageData::BGRX32 ?
gfxASurface::ImageFormatARGB32 :
gfxASurface::ImageFormatRGB24);
*aSize = newSurf->GetSize();
return newSurf.forget();
}
}
if (aCurrentImage) {
NS_IF_ADDREF(mActiveImage);
*aCurrentImage = mActiveImage.get();
}
if (!mActiveImage) {
return nsnull;
}
@ -136,11 +213,45 @@ ImageContainer::GetCurrentAsSurface(gfxIntSize *aSize)
return mActiveImage->GetAsSurface();
}
void
ImageContainer::UnlockCurrentImage()
{
if (mRemoteData) {
NS_ASSERTION(mRemoteDataMutex, "Should have remote data mutex when having remote data!");
mRemoteDataMutex->Unlock();
}
}
already_AddRefed<gfxASurface>
ImageContainer::GetCurrentAsSurface(gfxIntSize *aSize)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
EnsureActiveImage();
*aSize = mRemoteData->mSize;
return mActiveImage ? mActiveImage->GetAsSurface() : nsnull;
}
*aSize = mActiveImage->GetSize();
return mActiveImage ? mActiveImage->GetAsSurface() : nsnull;
}
gfxIntSize
ImageContainer::GetCurrentSize()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mRemoteData) {
CrossProcessMutexAutoLock autoLock(*mRemoteDataMutex);
// We don't need to ensure we have an active image here, as we need to
// be in the mutex anyway, and this is easiest to return from there.
return mRemoteData->mSize;
}
if (!mActiveImage) {
return gfxIntSize(0,0);
}
@ -148,6 +259,47 @@ ImageContainer::GetCurrentSize()
return mActiveImage->GetSize();
}
void
ImageContainer::SetRemoteImageData(RemoteImageData *aData, CrossProcessMutex *aMutex)
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(!mActiveImage, "No active image expected when SetRemoteImageData is called.");
NS_ASSERTION(!mRemoteData, "No remote data expected when SetRemoteImageData is called.");
mRemoteData = aData;
if (aData) {
memset(aData, 0, sizeof(RemoteImageData));
} else {
mActiveImage = nsnull;
}
mRemoteDataMutex = aMutex;
}
void
ImageContainer::EnsureActiveImage()
{
if (mRemoteData) {
if (mRemoteData->mWasUpdated) {
mActiveImage = nsnull;
}
if (mRemoteData->mType == RemoteImageData::RAW_BITMAP &&
mRemoteData->mBitmap.mData && !mActiveImage) {
nsRefPtr<RemoteBitmapImage> newImg = new RemoteBitmapImage();
newImg->mFormat = mRemoteData->mFormat;
newImg->mData = mRemoteData->mBitmap.mData;
newImg->mSize = mRemoteData->mSize;
newImg->mStride = mRemoteData->mBitmap.mStride;
mRemoteData->mWasUpdated = false;
mActiveImage = newImg;
}
}
}
PlanarYCbCrImage::PlanarYCbCrImage(BufferRecycleBin *aRecycleBin)
: Image(nsnull, PLANAR_YCBCR)
, mBufferSize(0)
@ -270,6 +422,21 @@ MacIOSurfaceImage::Update(ImageContainer* aContainer)
}
}
#endif
already_AddRefed<gfxASurface>
RemoteBitmapImage::GetAsSurface()
{
nsRefPtr<gfxImageSurface> newSurf =
new gfxImageSurface(mSize,
mFormat == RemoteImageData::BGRX32 ? gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32);
for (int y = 0; y < mSize.height; y++) {
memcpy(newSurf->Data() + newSurf->Stride() * y,
mData + mStride * y,
mSize.width * 4);
}
return newSurf.forget();
}
}
}

Просмотреть файл

@ -54,6 +54,12 @@
#endif
namespace mozilla {
class CrossProcessMutex;
namespace ipc {
class Shmem;
}
namespace layers {
enum StereoMode {
@ -120,7 +126,12 @@ public:
*
* It wraps an IOSurface object and binds it directly to a GL texture.
*/
MAC_IO_SURFACE
MAC_IO_SURFACE,
/**
* An bitmap image that can be shared with a remote process.
*/
REMOTE_IMAGE_BITMAP
};
Format GetFormat() { return mFormat; }
@ -225,6 +236,46 @@ protected:
BufferRecycleBin *aRecycleBin);
};
/**
* This struct is used to store RemoteImages, it is meant to be able to live in
* shared memory. Therefor it should not contain a vtable pointer. Remote
* users can manipulate the data in this structure to specify what image is to
* be drawn by the container. When accessing this data users should make sure
* the mutex synchronizing access to the structure is held!
*/
struct RemoteImageData {
enum Type {
/**
* This is a format that uses raw bitmap data.
*/
RAW_BITMAP
};
/* These formats describe the format in the memory byte-order */
enum Format {
/* 8 bits per channel */
BGRA32,
/* 8 bits per channel, alpha channel is ignored */
BGRX32
};
// This should be set to true if a change was made so that the ImageContainer
// knows to throw out any cached RemoteImage objects.
bool mWasUpdated;
Type mType;
Format mFormat;
gfxIntSize mSize;
union {
struct {
/* This pointer is set by a remote process, however it will be set to
* the container process' address the memory of the raw bitmap resides
* at.
*/
unsigned char *mData;
int mStride;
} mBitmap;
};
};
/**
* A class that manages Images for an ImageLayer. The only reason
@ -242,7 +293,9 @@ public:
mPaintCount(0),
mPreviousImagePainted(false),
mImageFactory(new ImageFactory()),
mRecycleBin(new BufferRecycleBin())
mRecycleBin(new BufferRecycleBin()),
mRemoteData(nsnull),
mRemoteDataMutex(nsnull)
{}
~ImageContainer();
@ -266,26 +319,37 @@ public:
* aImage can be null. While it's null, nothing will be painted.
*
* The Image data must not be modified after this method is called!
*
* Implementations must call CurrentImageChanged() while holding
* mReentrantMonitor.
*/
void SetCurrentImage(Image* aImage);
/**
* Get the current Image.
* This has to add a reference since otherwise there are race conditions
* where the current image is destroyed before the caller can add
* a reference.
* Returns if the container currently has an image.
* Can be called on any thread. This method takes mReentrantMonitor
* when accessing thread-shared state.
* Implementations must call CurrentImageChanged() while holding
* mReentrantMonitor.
*/
already_AddRefed<Image> GetCurrentImage()
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
bool HasCurrentImage();
nsRefPtr<Image> retval = mActiveImage;
return retval.forget();
}
/**
* Lock the current Image.
* This has to add a reference since otherwise there are race conditions
* where the current image is destroyed before the caller can add
* a reference. This lock strictly guarantees the underlying image remains
* valid, it does not mean the current image cannot change.
* Can be called on any thread. This method will lock the cross-process
* mutex to ensure remote processes cannot alter underlying data. This call
* -must- be balanced by a call to UnlockCurrentImage and users should avoid
* holding the image locked for a long time.
*/
already_AddRefed<Image> LockCurrentImage();
/**
* This call unlocks the image. For remote images releasing the cross-process
* mutex.
*/
void UnlockCurrentImage();
/**
* Get the current image as a gfxASurface. This is useful for fallback
@ -301,9 +365,25 @@ public:
* modify it.
* Can be called on any thread. This method takes mReentrantMonitor
* when accessing thread-shared state.
* If the current image is a remote image, that is, if it is an image that
* may be shared accross processes, calling this function will make
* a copy of the image data while holding the mRemoteDataMutex. If possible,
* the lock methods should be used to avoid the copy, however this should be
* avoided if the surface is required for a long period of time.
*/
already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSizeResult);
/**
* This is similar to GetCurrentAsSurface, however this does not make a copy
* of the image data and requires the user to call UnlockCurrentImage when
* done with the image data. Once UnlockCurrentImage has been called the
* surface returned by this function is no longer valid! This works for any
* type of image. Optionally a pointer can be passed to receive the current
* image.
*/
already_AddRefed<gfxASurface> LockCurrentAsSurface(gfxIntSize* aSizeResult,
Image** aCurrentImage = nsnull);
/**
* Returns the size of the image in pixels.
* Can be called on any thread. This method takes mReentrantMonitor when accessing
@ -354,7 +434,8 @@ public:
*/
void NotifyPaintedImage(Image* aPainted) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
nsRefPtr<Image> current = GetCurrentImage();
nsRefPtr<Image> current = mActiveImage;
if (aPainted == current) {
if (mPaintTime.IsNull()) {
mPaintTime = TimeStamp::Now();
@ -369,9 +450,30 @@ public:
}
}
/**
* This function is called to tell the ImageContainer where the
* (cross-process) segment lives where the shared data about possible
* remote images are stored. In addition to this a CrossProcessMutex object
* is passed telling the container how to synchronize access to this data.
* NOTE: This should be called during setup of the container and not after
* usage has started.
*/
void SetRemoteImageData(RemoteImageData *aRemoteData,
CrossProcessMutex *aRemoteDataMutex);
/**
* This can be used to check if the container has RemoteData set.
*/
RemoteImageData *GetRemoteImageData() { return mRemoteData; }
protected:
typedef mozilla::ReentrantMonitor ReentrantMonitor;
// This is called to ensure we have an active image, this may not be true
// when we're storing image information in a RemoteImageData structure.
// NOTE: If we have remote data mRemoteDataMutex should be locked when
// calling this function!
void EnsureActiveImage();
// ReentrantMonitor to protect thread safe access to the "current
// image", and any other state which is shared between threads.
ReentrantMonitor mReentrantMonitor;
@ -407,6 +509,54 @@ protected:
gfxIntSize mScaleHint;
nsRefPtr<BufferRecycleBin> mRecycleBin;
// This contains the remote image data for this container, if this is NULL
// that means the container has no other process that may control its active
// image.
RemoteImageData *mRemoteData;
// This cross-process mutex is used to synchronise access to mRemoteData.
// When this mutex is held, we will always be inside the mReentrantMonitor
// however the same is not true vice versa.
CrossProcessMutex *mRemoteDataMutex;
};
class AutoLockImage
{
public:
AutoLockImage(ImageContainer *aContainer) : mContainer(aContainer) { mImage = mContainer->LockCurrentImage(); }
AutoLockImage(ImageContainer *aContainer, gfxASurface **aSurface) : mContainer(aContainer) {
*aSurface = mContainer->LockCurrentAsSurface(&mSize, getter_AddRefs(mImage)).get();
}
~AutoLockImage() { if (mContainer) { mContainer->UnlockCurrentImage(); } }
Image* GetImage() { return mImage; }
const gfxIntSize &GetSize() { return mSize; }
void Unlock() {
if (mContainer) {
mImage = nsnull;
mContainer->UnlockCurrentImage();
mContainer = nsnull;
}
}
/** Things get a little tricky here, because our underlying image can -still-
* change, and OS X requires a complicated callback mechanism to update this
* we need to support staying the lock and getting the new image in a proper
* way. This method makes any images retrieved with GetImage invalid!
*/
void Refresh() {
if (mContainer) {
mContainer->UnlockCurrentImage();
mImage = mContainer->LockCurrentImage();
}
}
private:
ImageContainer *mContainer;
nsRefPtr<Image> mImage;
gfxIntSize mSize;
};
/**
@ -676,6 +826,20 @@ private:
};
#endif
class RemoteBitmapImage : public Image {
public:
RemoteBitmapImage() : Image(NULL, REMOTE_IMAGE_BITMAP) {}
already_AddRefed<gfxASurface> GetAsSurface();
gfxIntSize GetSize() { return mSize; }
unsigned char *mData;
int mStride;
gfxIntSize mSize;
RemoteImageData::Format mFormat;
};
}
}

Просмотреть файл

@ -904,9 +904,11 @@ BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext,
mContainer->SetImageFactory(mManager->IsCompositingCheap() ? nsnull : BasicManager()->GetImageFactory());
nsRefPtr<Image> image = mContainer->GetCurrentImage();
nsRefPtr<gfxASurface> surface;
AutoLockImage autoLock(mContainer, getter_AddRefs(surface));
Image *image = autoLock.GetImage();
mSize = autoLock.GetSize();
nsRefPtr<gfxASurface> surface = mContainer->GetCurrentAsSurface(&mSize);
if (!surface || surface->CairoStatus()) {
return nsnull;
}
@ -2522,13 +2524,16 @@ BasicShadowableImageLayer::Paint(gfxContext* aContext)
return;
}
nsRefPtr<Image> image = mContainer->GetCurrentImage();
AutoLockImage autoLock(mContainer);
Image *image = autoLock.GetImage();
if (!image) {
return;
}
if (image->GetFormat() == Image::PLANAR_YCBCR && BasicManager()->IsCompositingCheap()) {
PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(image.get());
PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(image);
const PlanarYCbCrImage::Data *data = YCbCrImage->GetData();
NS_ASSERTION(data, "Must be able to retrieve yuv data from image!");

Просмотреть файл

@ -44,6 +44,34 @@
namespace mozilla {
namespace layers {
static already_AddRefed<ID3D10Texture2D>
DataToTexture(ID3D10Device *aDevice,
unsigned char *data,
int stride,
const gfxIntSize &aSize)
{
D3D10_SUBRESOURCE_DATA srdata;
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
aSize.width,
aSize.height,
1, 1);
desc.Usage = D3D10_USAGE_IMMUTABLE;
srdata.pSysMem = data;
srdata.SysMemPitch = stride;
nsRefPtr<ID3D10Texture2D> texture;
HRESULT hr = aDevice->CreateTexture2D(&desc, &srdata, getter_AddRefs(texture));
if (FAILED(hr)) {
LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("Failed to create texture for data"),
hr);
}
return texture.forget();
}
static already_AddRefed<ID3D10Texture2D>
SurfaceToTexture(ID3D10Device *aDevice,
@ -78,26 +106,7 @@ SurfaceToTexture(ID3D10Device *aDevice,
context->Paint();
}
D3D10_SUBRESOURCE_DATA data;
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
imageSurface->GetSize().width,
imageSurface->GetSize().height,
1, 1);
desc.Usage = D3D10_USAGE_IMMUTABLE;
data.pSysMem = imageSurface->Data();
data.SysMemPitch = imageSurface->Stride();
nsRefPtr<ID3D10Texture2D> texture;
HRESULT hr = aDevice->CreateTexture2D(&desc, &data, getter_AddRefs(texture));
if (FAILED(hr)) {
LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("Failed to create texture for image surface"),
hr);
}
return texture.forget();
return DataToTexture(aDevice, imageSurface->Data(), imageSurface->Stride(), aSize);
}
Layer*
@ -109,11 +118,14 @@ ImageLayerD3D10::GetLayer()
void
ImageLayerD3D10::RenderLayer()
{
if (!GetContainer()) {
ImageContainer *container = GetContainer();
if (!container) {
return;
}
nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
AutoLockImage autoLock(container);
Image *image = autoLock.GetImage();
if (!image) {
return;
}
@ -122,27 +134,51 @@ ImageLayerD3D10::RenderLayer()
ID3D10EffectTechnique *technique;
if (image->GetFormat() == Image::CAIRO_SURFACE)
if (image->GetFormat() == Image::CAIRO_SURFACE || image->GetFormat() == Image::REMOTE_IMAGE_BITMAP)
{
CairoImage *cairoImage =
static_cast<CairoImage*>(image.get());
bool hasAlpha = false;
gfxIntSize size;
if (!cairoImage->mSurface) {
return;
}
if (image->GetFormat() == Image::REMOTE_IMAGE_BITMAP) {
RemoteBitmapImage *remoteImage =
static_cast<RemoteBitmapImage*>(image);
if (!image->GetBackendData(LayerManager::LAYERS_D3D10)) {
nsAutoPtr<TextureD3D10BackendData> dat = new TextureD3D10BackendData();
dat->mTexture = DataToTexture(device(), remoteImage->mData, remoteImage->mStride, remoteImage->mSize);
if (!cairoImage->GetBackendData(LayerManager::LAYERS_D3D10)) {
nsAutoPtr<CairoD3D10BackendData> dat(new CairoD3D10BackendData());
dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
if (dat->mTexture) {
device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView));
cairoImage->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget());
if (dat->mTexture) {
device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView));
image->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget());
}
}
hasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32;
size = remoteImage->mSize;
} else {
CairoImage *cairoImage =
static_cast<CairoImage*>(image);
if (!cairoImage->mSurface) {
return;
}
if (!image->GetBackendData(LayerManager::LAYERS_D3D10)) {
nsAutoPtr<TextureD3D10BackendData> dat = new TextureD3D10BackendData();
dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
if (dat->mTexture) {
device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView));
image->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget());
}
}
hasAlpha = cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA;
size = cairoImage->mSize;
}
CairoD3D10BackendData *data =
static_cast<CairoD3D10BackendData*>(cairoImage->GetBackendData(LayerManager::LAYERS_D3D10));
TextureD3D10BackendData *data =
static_cast<TextureD3D10BackendData*>(image->GetBackendData(LayerManager::LAYERS_D3D10));
if (!data) {
return;
@ -154,7 +190,7 @@ ImageLayerD3D10::RenderLayer()
return;
}
if (cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
if (hasAlpha) {
if (mFilter == gfxPattern::FILTER_NEAREST) {
technique = effect()->GetTechniqueByName("RenderRGBALayerPremulPoint");
} else {
@ -174,12 +210,12 @@ ImageLayerD3D10::RenderLayer()
ShaderConstantRectD3D10(
(float)0,
(float)0,
(float)cairoImage->mSize.width,
(float)cairoImage->mSize.height)
(float)size.width,
(float)size.height)
);
} else if (image->GetFormat() == Image::PLANAR_YCBCR) {
PlanarYCbCrImage *yuvImage =
static_cast<PlanarYCbCrImage*>(image.get());
static_cast<PlanarYCbCrImage*>(image);
if (!yuvImage->mBufferSize) {
return;
@ -262,11 +298,15 @@ ImageLayerD3D10::RenderLayer()
(float)yuvImage->mData.mPicSize.height / yuvImage->mData.mYSize.height)
);
}
bool resetTexCoords = image->GetFormat() == Image::PLANAR_YCBCR;
image = nsnull;
autoLock.Unlock();
technique->GetPassByIndex(0)->Apply(0);
device()->Draw(4, 0);
if (image->GetFormat() == Image::PLANAR_YCBCR) {
if (resetTexCoords) {
effect()->GetVariableByName("vTextureCoords")->AsVector()->
SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
}

Просмотреть файл

@ -74,7 +74,7 @@ struct PlanarYCbCrD3D10BackendData : public ImageBackendData
nsRefPtr<ID3D10ShaderResourceView> mCrView;
};
struct CairoD3D10BackendData : public ImageBackendData
struct TextureD3D10BackendData : public ImageBackendData
{
nsRefPtr<ID3D10Texture2D> mTexture;
nsRefPtr<ID3D10ShaderResourceView> mSRView;

Просмотреть файл

@ -53,23 +53,11 @@ namespace mozilla {
namespace layers {
static already_AddRefed<IDirect3DTexture9>
SurfaceToTexture(IDirect3DDevice9 *aDevice,
gfxASurface *aSurface,
const gfxIntSize &aSize)
DataToTexture(IDirect3DDevice9 *aDevice,
unsigned char *aData,
int aStride,
const gfxIntSize &aSize)
{
nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
if (!imageSurface) {
imageSurface = new gfxImageSurface(aSize,
gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
context->SetSource(aSurface);
context->SetOperator(gfxContext::OPERATOR_SOURCE);
context->Paint();
}
nsRefPtr<IDirect3DTexture9> texture;
nsRefPtr<IDirect3DDevice9Ex> deviceEx;
aDevice->QueryInterface(IID_IDirect3DDevice9Ex,
@ -103,7 +91,7 @@ SurfaceToTexture(IDirect3DDevice9 *aDevice,
surface->LockRect(&lockedRect, NULL, 0);
for (int y = 0; y < aSize.height; y++) {
memcpy((char*)lockedRect.pBits + lockedRect.Pitch * y,
imageSurface->Data() + imageSurface->Stride() * y,
aData + aStride * y,
aSize.width * 4);
}
surface->UnlockRect();
@ -127,7 +115,7 @@ SurfaceToTexture(IDirect3DDevice9 *aDevice,
// use memcpy
for (int y = 0; y < aSize.height; y++) {
memcpy((char*)lockrect.pBits + lockrect.Pitch * y,
imageSurface->Data() + imageSurface->Stride() * y,
aData + aStride * y,
aSize.width * 4);
}
@ -137,6 +125,27 @@ SurfaceToTexture(IDirect3DDevice9 *aDevice,
return texture.forget();
}
static already_AddRefed<IDirect3DTexture9>
SurfaceToTexture(IDirect3DDevice9 *aDevice,
gfxASurface *aSurface,
const gfxIntSize &aSize)
{
nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
if (!imageSurface) {
imageSurface = new gfxImageSurface(aSize,
gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
context->SetSource(aSurface);
context->SetOperator(gfxContext::OPERATOR_SOURCE);
context->Paint();
}
return DataToTexture(aDevice, imageSurface->Data(), imageSurface->Stride(), aSize);
}
static void AllocateTexturesYCbCr(PlanarYCbCrImage *aImage,
IDirect3DDevice9 *aDevice,
LayerManagerD3D9 *aManager)
@ -302,37 +311,61 @@ ImageLayerD3D9::GetLayer()
void
ImageLayerD3D9::RenderLayer()
{
if (!GetContainer()) {
ImageContainer *container = GetContainer();
if (!container) {
return;
}
nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
AutoLockImage autoLock(container);
Image *image = autoLock.GetImage();
if (!image) {
return;
}
SetShaderTransformAndOpacity();
if (image->GetFormat() == Image::CAIRO_SURFACE)
if (image->GetFormat() == Image::CAIRO_SURFACE || image->GetFormat() == Image::REMOTE_IMAGE_BITMAP)
{
CairoImage *cairoImage =
static_cast<CairoImage*>(image.get());
bool hasAlpha = false;
gfxIntSize size;
if (!cairoImage->mSurface) {
return;
}
if (!cairoImage->GetBackendData(LayerManager::LAYERS_D3D9)) {
nsAutoPtr<CairoD3D9BackendData> dat(new CairoD3D9BackendData());
dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
if (dat->mTexture) {
cairoImage->SetBackendData(LayerManager::LAYERS_D3D9, dat.forget());
if (image->GetFormat() == Image::REMOTE_IMAGE_BITMAP) {
RemoteBitmapImage *remoteImage =
static_cast<RemoteBitmapImage*>(image);
if (!image->GetBackendData(LayerManager::LAYERS_D3D9)) {
nsAutoPtr<TextureD3D9BackendData> dat = new TextureD3D9BackendData();
dat->mTexture = DataToTexture(device(), remoteImage->mData, remoteImage->mStride, remoteImage->mSize);
if (dat->mTexture) {
image->SetBackendData(LayerManager::LAYERS_D3D9, dat.forget());
}
}
hasAlpha = remoteImage->mFormat == RemoteImageData::BGRA32;
size = remoteImage->mSize;
} else {
CairoImage *cairoImage =
static_cast<CairoImage*>(image);
if (!cairoImage->mSurface) {
return;
}
if (!image->GetBackendData(LayerManager::LAYERS_D3D9)) {
nsAutoPtr<TextureD3D9BackendData> dat = new TextureD3D9BackendData();
dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
if (dat->mTexture) {
image->SetBackendData(LayerManager::LAYERS_D3D9, dat.forget());
}
}
hasAlpha = cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA;
size = cairoImage->mSize;
}
CairoD3D9BackendData *data =
static_cast<CairoD3D9BackendData*>(cairoImage->GetBackendData(LayerManager::LAYERS_D3D9));
TextureD3D9BackendData *data =
static_cast<TextureD3D9BackendData*>(image->GetBackendData(LayerManager::LAYERS_D3D9));
if (!data) {
return;
@ -344,12 +377,6 @@ ImageLayerD3D9::RenderLayer()
return;
}
gfxIntSize size;
nsRefPtr<gfxASurface> surface =
GetContainer()->GetCurrentAsSurface(&size);
nsRefPtr<IDirect3DTexture9> texture =
SurfaceToTexture(device(), surface, size);
device()->SetVertexShaderConstantF(CBvLayerQuad,
ShaderConstantRect(0,
0,
@ -357,7 +384,7 @@ ImageLayerD3D9::RenderLayer()
size.height),
1);
if (surface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
if (hasAlpha) {
mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER);
} else {
mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER);
@ -367,7 +394,12 @@ ImageLayerD3D9::RenderLayer()
device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
}
device()->SetTexture(0, texture);
device()->SetTexture(0, data->mTexture);
image = nsnull;
data = nsnull;
autoLock.Unlock();
device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
if (mFilter == gfxPattern::FILTER_NEAREST) {
device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
@ -375,7 +407,7 @@ ImageLayerD3D9::RenderLayer()
}
} else {
PlanarYCbCrImage *yuvImage =
static_cast<PlanarYCbCrImage*>(image.get());
static_cast<PlanarYCbCrImage*>(image);
if (!yuvImage->mBufferSize) {
return;
@ -459,6 +491,10 @@ ImageLayerD3D9::RenderLayer()
device()->SetTexture(1, data->mCbTexture);
device()->SetTexture(2, data->mCrTexture);
image = nsnull;
data = nsnull;
autoLock.Unlock();
device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
device()->SetVertexShaderConstantF(CBvTextureCoords,

Просмотреть файл

@ -71,7 +71,7 @@ public:
};
struct CairoD3D9BackendData : public ImageBackendData
struct TextureD3D9BackendData : public ImageBackendData
{
nsRefPtr<IDirect3DTexture9> mTexture;
};

Просмотреть файл

@ -214,19 +214,26 @@ void
ImageLayerOGL::RenderLayer(int,
const nsIntPoint& aOffset)
{
if (!GetContainer())
nsRefPtr<ImageContainer> container = GetContainer();
if (!container)
return;
mOGLManager->MakeCurrent();
nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
AutoLockImage autoLock(container);
Image *image = autoLock.GetImage();
if (!image) {
return;
}
NS_ASSERTION(image->GetFormat() != Image::REMOTE_IMAGE_BITMAP,
"Remote images aren't handled yet in OGL layers!");
if (image->GetFormat() == Image::PLANAR_YCBCR) {
PlanarYCbCrImage *yuvImage =
static_cast<PlanarYCbCrImage*>(image.get());
static_cast<PlanarYCbCrImage*>(image);
if (!yuvImage->mBufferSize) {
return;
@ -276,7 +283,7 @@ ImageLayerOGL::RenderLayer(int,
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
} else if (image->GetFormat() == Image::CAIRO_SURFACE) {
CairoImage *cairoImage =
static_cast<CairoImage*>(image.get());
static_cast<CairoImage*>(image);
if (!cairoImage->mSurface) {
return;
@ -424,16 +431,18 @@ ImageLayerOGL::RenderLayer(int,
#ifdef XP_MACOSX
} else if (image->GetFormat() == Image::MAC_IO_SURFACE) {
MacIOSurfaceImage *ioImage =
static_cast<MacIOSurfaceImage*>(image.get());
static_cast<MacIOSurfaceImage*>(image);
if (!mOGLManager->GetThebesLayerCallback()) {
// If its an empty transaction we still need to update
// the plugin IO Surface and make sure we grab the
// new image
ioImage->Update(GetContainer());
image = GetContainer()->GetCurrentImage();
image = nsnull;
autoLock.Refresh();
image = autoLock.GetImage();
gl()->MakeCurrent();
ioImage = static_cast<MacIOSurfaceImage*>(image.get());
ioImage = static_cast<MacIOSurfaceImage*>(image);
}
if (!ioImage) {

Просмотреть файл

@ -1190,8 +1190,7 @@ nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
nsRefPtr<ImageContainer> container = GetImageContainer();
nsRefPtr<Image> currentImage = container ? container->GetCurrentImage() : nsnull;
if (!currentImage || !isVisible ||
if (container && container->HasCurrentImage() || !isVisible ||
container->GetCurrentSize() != gfxIntSize(window->width, window->height)) {
mInstanceOwner->NotifyPaintWaiter(aBuilder);
}