bool ImageContainerChild::CopyDataIntoSharedImage(Image* src, SharedImage* dest) { if ((src->GetFormat() == PLANAR_YCBCR) && (dest->type() == SharedImage::TYCbCrImage)) { PlanarYCbCrImage *planarYCbCrImage = static_cast<PlanarYCbCrImage*>(src); const PlanarYCbCrImage::Data *data =planarYCbCrImage->GetData(); NS_ASSERTION(data, "Must be able to retrieve yuv data from image!"); YCbCrImage& yuv = dest->get_YCbCrImage(); ShmemYCbCrImage shmemImage(yuv.data(), yuv.offset()); for (int i = 0; i < data->mYSize.height; i++) { memcpy(shmemImage.GetYData() + i * shmemImage.GetYStride(), data->mYChannel + i * data->mYStride, data->mYSize.width); } for (int i = 0; i < data->mCbCrSize.height; i++) { memcpy(shmemImage.GetCbData() + i * shmemImage.GetCbCrStride(), data->mCbChannel + i * data->mCbCrStride, data->mCbCrSize.width); memcpy(shmemImage.GetCrData() + i * shmemImage.GetCbCrStride(), data->mCrChannel + i * data->mCbCrStride, data->mCbCrSize.width); } return true; } return false; // TODO: support more image formats }
SharedImage* ImageContainerChild::CreateSharedImageFromData(Image* image) { NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); ++mActiveImageCount; // TODO: I don't test for BasicManager()->IsCompositingCheap() here, // is this a problem? (the equvivalent code in PCompositor does that) if (image->GetFormat() == Image::PLANAR_YCBCR ) { PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrImage::Data *data = YCbCrImage->GetData(); NS_ASSERTION(data, "Must be able to retrieve yuv data from image!"); nsRefPtr<gfxSharedImageSurface> tempBufferY; nsRefPtr<gfxSharedImageSurface> tempBufferU; nsRefPtr<gfxSharedImageSurface> tempBufferV; if (!this->AllocBuffer(data->mYSize, gfxASurface::CONTENT_ALPHA, getter_AddRefs(tempBufferY)) || !this->AllocBuffer(data->mCbCrSize, gfxASurface::CONTENT_ALPHA, getter_AddRefs(tempBufferU)) || !this->AllocBuffer(data->mCbCrSize, gfxASurface::CONTENT_ALPHA, getter_AddRefs(tempBufferV))) { NS_RUNTIMEABORT("creating SharedImage failed!"); } for (int i = 0; i < data->mYSize.height; i++) { memcpy(tempBufferY->Data() + i * tempBufferY->Stride(), data->mYChannel + i * data->mYStride, data->mYSize.width); } for (int i = 0; i < data->mCbCrSize.height; i++) { memcpy(tempBufferU->Data() + i * tempBufferU->Stride(), data->mCbChannel + i * data->mCbCrStride, data->mCbCrSize.width); memcpy(tempBufferV->Data() + i * tempBufferV->Stride(), data->mCrChannel + i * data->mCbCrStride, data->mCbCrSize.width); } SharedImage* result = new SharedImage( *(new YUVImage(tempBufferY->GetShmem(), tempBufferU->GetShmem(), tempBufferV->GetShmem(), data->GetPictureRect()))); NS_ABORT_IF_FALSE(result->type() == SharedImage::TYUVImage, "SharedImage type not set correctly"); return result; } else if (image->GetFormat() == Image::GONK_IO_SURFACE) { GonkIOSurfaceImage* gonkImage = static_cast<GonkIOSurfaceImage*>(image); SharedImage* result = new SharedImage(gonkImage->GetSurfaceDescriptor()); return result; } else { NS_RUNTIMEABORT("TODO: Only YUVImage is supported here right now."); } return nsnull; }
SharedImage* ImageContainerChild::AllocateSharedImageFor(Image* image) { NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); if (!image) { return nullptr; } if (image->GetFormat() == PLANAR_YCBCR ) { PlanarYCbCrImage *planarYCbCrImage = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrImage::Data *data = planarYCbCrImage->GetData(); NS_ASSERTION(data, "Must be able to retrieve yuv data from image!"); if (!data) { return nullptr; } SharedMemory::SharedMemoryType shmType = OptimalShmemType(); size_t size = ShmemYCbCrImage::ComputeMinBufferSize(data->mYSize, data->mCbCrSize); Shmem shmem; if (!AllocUnsafeShmem(size, shmType, &shmem)) { return nullptr; } ShmemYCbCrImage::InitializeBufferInfo(shmem.get<uint8_t>(), data->mYSize, data->mCbCrSize); ShmemYCbCrImage shmemImage(shmem); if (!shmemImage.IsValid()) { NS_WARNING("Failed to properly allocate image data!"); DeallocShmem(shmem); return nullptr; } ++mActiveImageCount; return new SharedImage(YCbCrImage(shmem, 0, data->GetPictureRect())); } else { NS_RUNTIMEABORT("TODO: Only YCbCrImage is supported here right now."); } return nullptr; }
bool ImageContainerChild::CopyDataIntoSharedImage(Image* src, SharedImage* dest) { if ((src->GetFormat() == PLANAR_YCBCR) && (dest->type() == SharedImage::TYCbCrImage)) { PlanarYCbCrImage *planarYCbCrImage = static_cast<PlanarYCbCrImage*>(src); const PlanarYCbCrImage::Data *data = planarYCbCrImage->GetData(); NS_ASSERTION(data, "Must be able to retrieve yuv data from image!"); YCbCrImage& yuv = dest->get_YCbCrImage(); ShmemYCbCrImage shmemImage(yuv.data(), yuv.offset()); if (!shmemImage.CopyData(data->mYChannel, data->mCbChannel, data->mCrChannel, data->mYSize, data->mYStride, data->mCbCrSize, data->mCbCrStride)) { NS_WARNING("Failed to copy image data!"); return false; } return true; } return false; // TODO: support more image formats }
bool ImageContainerChild::CopyDataIntoSharedImage(Image* src, SharedImage* dest) { if ((src->GetFormat() == Image::PLANAR_YCBCR) && (dest->type() == SharedImage::TYUVImage)) { PlanarYCbCrImage *YCbCrImage = static_cast<PlanarYCbCrImage*>(src); const PlanarYCbCrImage::Data *data = YCbCrImage->GetData(); NS_ASSERTION(data, "Must be able to retrieve yuv data from image!"); YUVImage& yuv = dest->get_YUVImage(); nsRefPtr<gfxSharedImageSurface> surfY = gfxSharedImageSurface::Open(yuv.Ydata()); nsRefPtr<gfxSharedImageSurface> surfU = gfxSharedImageSurface::Open(yuv.Udata()); nsRefPtr<gfxSharedImageSurface> surfV = gfxSharedImageSurface::Open(yuv.Vdata()); gfxIntSize size = surfY->GetSize(); //gfxIntSize CbCrSize = surfU->GetSize(); NS_ABORT_IF_FALSE(size == mSize, "Sizes must match to copy image data."); for (int i = 0; i < data->mYSize.height; i++) { memcpy(surfY->Data() + i * surfY->Stride(), data->mYChannel + i * data->mYStride, data->mYSize.width); } for (int i = 0; i < data->mCbCrSize.height; i++) { memcpy(surfU->Data() + i * surfU->Stride(), data->mCbChannel + i * data->mCbCrStride, data->mCbCrSize.width); memcpy(surfV->Data() + i * surfV->Stride(), data->mCrChannel + i * data->mCbCrStride, data->mCbCrSize.width); } return true; } return false; // TODO: support more image formats }
void ImageLayerOGL::RenderLayer(int, const nsIntPoint& aOffset) { nsRefPtr<ImageContainer> container = GetContainer(); if (!container || mOGLManager->CompositingDisabled()) return; mOGLManager->MakeCurrent(); AutoLockImage autoLock(container); Image *image = autoLock.GetImage(); if (!image) { return; } NS_ASSERTION(image->GetFormat() != REMOTE_IMAGE_BITMAP, "Remote images aren't handled yet in OGL layers!"); if (image->GetFormat() == PLANAR_YCBCR) { PlanarYCbCrImage *yuvImage = static_cast<PlanarYCbCrImage*>(image); if (!yuvImage->IsValid()) { return; } PlanarYCbCrOGLBackendData *data = static_cast<PlanarYCbCrOGLBackendData*>(yuvImage->GetBackendData(LAYERS_OPENGL)); if (data && data->mTextures->GetGLContext() != gl()) { // If these textures were allocated by another layer manager, // clear them out and re-allocate below. data = nullptr; yuvImage->SetBackendData(LAYERS_OPENGL, nullptr); } if (!data) { AllocateTexturesYCbCr(yuvImage); data = static_cast<PlanarYCbCrOGLBackendData*>(yuvImage->GetBackendData(LAYERS_OPENGL)); } if (!data || data->mTextures->GetGLContext() != gl()) { // XXX - Can this ever happen? If so I need to fix this! return; } gl()->MakeCurrent(); gl()->fActiveTexture(LOCAL_GL_TEXTURE2); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[2].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); gl()->fActiveTexture(LOCAL_GL_TEXTURE1); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[1].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[0].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); ShaderProgramOGL *program = mOGLManager->GetProgram(YCbCrLayerProgramType, GetMaskLayer()); program->Activate(); program->SetLayerQuadRect(nsIntRect(0, 0, yuvImage->GetSize().width, yuvImage->GetSize().height)); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetYCbCrTextureUnits(0, 1, 2); program->LoadMask(GetMaskLayer()); mOGLManager->BindAndDrawQuadWithTextureRect(program, yuvImage->GetData()->GetPictureRect(), nsIntSize(yuvImage->GetData()->mYSize.width, yuvImage->GetData()->mYSize.height)); // We shouldn't need to do this, but do it anyway just in case // someone else forgets. gl()->fActiveTexture(LOCAL_GL_TEXTURE0); } else if (image->GetFormat() == CAIRO_SURFACE) { CairoImage *cairoImage = static_cast<CairoImage*>(image); if (!cairoImage->mSurface) { return; } NS_ASSERTION(cairoImage->mSurface->GetContentType() != gfxASurface::CONTENT_ALPHA, "Image layer has alpha image"); CairoOGLBackendData *data = static_cast<CairoOGLBackendData*>(cairoImage->GetBackendData(LAYERS_OPENGL)); if (data && data->mTexture.GetGLContext() != gl()) { // If this texture was allocated by another layer manager, clear // it out and re-allocate below. data = nullptr; cairoImage->SetBackendData(LAYERS_OPENGL, nullptr); } if (!data) { AllocateTexturesCairo(cairoImage); data = static_cast<CairoOGLBackendData*>(cairoImage->GetBackendData(LAYERS_OPENGL)); } if (!data || data->mTexture.GetGLContext() != gl()) { // XXX - Can this ever happen? If so I need to fix this! return; } gl()->MakeCurrent(); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTexture.GetTextureID()); ShaderProgramOGL *program = mOGLManager->GetProgram(data->mLayerProgram, GetMaskLayer()); gl()->ApplyFilterToBoundTexture(mFilter); program->Activate(); program->SetLayerQuadRect(nsIntRect(0, 0, cairoImage->GetSize().width, cairoImage->GetSize().height)); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetTextureUnit(0); program->LoadMask(GetMaskLayer()); mOGLManager->BindAndDrawQuad(program); #ifdef XP_MACOSX } else if (image->GetFormat() == MAC_IO_SURFACE) { MacIOSurfaceImage *ioImage = 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 = nullptr; autoLock.Refresh(); image = autoLock.GetImage(); gl()->MakeCurrent(); ioImage = static_cast<MacIOSurfaceImage*>(image); } if (!ioImage) { return; } gl()->fActiveTexture(LOCAL_GL_TEXTURE0); if (!ioImage->GetBackendData(LAYERS_OPENGL)) { AllocateTextureIOSurface(ioImage, gl()); } MacIOSurfaceImageOGLBackendData *data = static_cast<MacIOSurfaceImageOGLBackendData*>(ioImage->GetBackendData(LAYERS_OPENGL)); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, data->mTexture.GetTextureID()); ShaderProgramOGL *program = mOGLManager->GetProgram(gl::RGBARectLayerProgramType, GetMaskLayer()); program->Activate(); if (program->GetTexCoordMultiplierUniformLocation() != -1) { // 2DRect case, get the multiplier right for a sampler2DRect program->SetTexCoordMultiplier(ioImage->GetSize().width, ioImage->GetSize().height); } else { NS_ASSERTION(0, "no rects?"); } program->SetLayerQuadRect(nsIntRect(0, 0, ioImage->GetSize().width, ioImage->GetSize().height)); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetTextureUnit(0); program->LoadMask(GetMaskLayer()); mOGLManager->BindAndDrawQuad(program); gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); #endif #ifdef MOZ_WIDGET_GONK } else if (image->GetFormat() == GONK_IO_SURFACE) { GonkIOSurfaceImage *ioImage = static_cast<GonkIOSurfaceImage*>(image); if (!ioImage) { return; } gl()->MakeCurrent(); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); if (!ioImage->GetBackendData(LAYERS_OPENGL)) { AllocateTextureIOSurface(ioImage, gl()); } GonkIOSurfaceImageOGLBackendData *data = static_cast<GonkIOSurfaceImageOGLBackendData*>(ioImage->GetBackendData(LAYERS_OPENGL)); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->BindExternalBuffer(data->mTexture.GetTextureID(), ioImage->GetNativeBuffer()); ShaderProgramOGL *program = mOGLManager->GetProgram(RGBAExternalLayerProgramType, GetMaskLayer()); gl()->ApplyFilterToBoundTexture(mFilter); program->Activate(); program->SetLayerQuadRect(nsIntRect(0, 0, ioImage->GetSize().width, ioImage->GetSize().height)); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetTextureUnit(0); program->LoadMask(GetMaskLayer()); mOGLManager->BindAndDrawQuadWithTextureRect(program, GetVisibleRegion().GetBounds(), nsIntSize(ioImage->GetSize().width, ioImage->GetSize().height)); #endif } GetContainer()->NotifyPaintedImage(image); }
bool DeprecatedImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) { AutoLockImage autoLock(aContainer); Image *image = autoLock.GetImage(); if (!image) { return false; } if (mLastPaintedImageSerial == image->GetSerial()) { return true; } if (image->GetFormat() == PLANAR_YCBCR && EnsureDeprecatedTextureClient(TEXTURE_YCBCR)) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); if (ycbcr->AsDeprecatedSharedPlanarYCbCrImage()) { AutoLockDeprecatedTextureClient lock(mDeprecatedTextureClient); SurfaceDescriptor sd; if (!ycbcr->AsDeprecatedSharedPlanarYCbCrImage()->ToSurfaceDescriptor(sd)) { return false; } if (IsSurfaceDescriptorValid(*lock.GetSurfaceDescriptor())) { GetForwarder()->DestroySharedSurface(lock.GetSurfaceDescriptor()); } *lock.GetSurfaceDescriptor() = sd; } else { AutoLockYCbCrClient clientLock(mDeprecatedTextureClient); if (!clientLock.Update(ycbcr)) { NS_WARNING("failed to update DeprecatedTextureClient (YCbCr)"); return false; } } } else if (image->GetFormat() == SHARED_TEXTURE && EnsureDeprecatedTextureClient(TEXTURE_SHARED_GL_EXTERNAL)) { SharedTextureImage* sharedImage = static_cast<SharedTextureImage*>(image); const SharedTextureImage::Data *data = sharedImage->GetData(); SharedTextureDescriptor texture(data->mShareType, data->mHandle, data->mSize, data->mInverted); mDeprecatedTextureClient->SetDescriptor(SurfaceDescriptor(texture)); } else if (image->GetFormat() == SHARED_RGB && EnsureDeprecatedTextureClient(TEXTURE_SHMEM)) { nsIntRect rect(0, 0, image->GetSize().width, image->GetSize().height); UpdatePictureRect(rect); AutoLockDeprecatedTextureClient lock(mDeprecatedTextureClient); SurfaceDescriptor desc; if (!static_cast<DeprecatedSharedRGBImage*>(image)->ToSurfaceDescriptor(desc)) { return false; } mDeprecatedTextureClient->SetDescriptor(desc); #ifdef MOZ_WIDGET_GONK } else if (image->GetFormat() == GONK_IO_SURFACE && EnsureDeprecatedTextureClient(TEXTURE_SHARED_GL_EXTERNAL)) { nsIntRect rect(0, 0, image->GetSize().width, image->GetSize().height); UpdatePictureRect(rect); AutoLockDeprecatedTextureClient lock(mDeprecatedTextureClient); SurfaceDescriptor desc = static_cast<GonkIOSurfaceImage*>(image)->GetSurfaceDescriptor(); if (!IsSurfaceDescriptorValid(desc)) { return false; } mDeprecatedTextureClient->SetDescriptor(desc); } else if (image->GetFormat() == GRALLOC_PLANAR_YCBCR) { EnsureDeprecatedTextureClient(TEXTURE_SHARED_GL_EXTERNAL); nsIntRect rect(0, 0, image->GetSize().width, image->GetSize().height); UpdatePictureRect(rect); AutoLockDeprecatedTextureClient lock(mDeprecatedTextureClient); SurfaceDescriptor desc = static_cast<GrallocPlanarYCbCrImage*>(image)->GetSurfaceDescriptor(); if (!IsSurfaceDescriptorValid(desc)) { return false; } mDeprecatedTextureClient->SetDescriptor(desc); #endif } else { nsRefPtr<gfxASurface> surface = image->GetAsSurface(); MOZ_ASSERT(surface); EnsureDeprecatedTextureClient(TEXTURE_SHMEM); MOZ_ASSERT(mDeprecatedTextureClient, "Failed to create texture client"); AutoLockShmemClient clientLock(mDeprecatedTextureClient); if (!clientLock.Update(image, aContentFlags, surface)) { NS_WARNING("failed to update DeprecatedTextureClient"); return false; } } Updated(); if (image->GetFormat() == PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); UpdatePictureRect(ycbcr->GetData()->GetPictureRect()); } mLastPaintedImageSerial = image->GetSerial(); aContainer->NotifyPaintedImage(image); return true; }
nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk) { nsRefPtr<Image> img; if (aChunk.mFrame.GetForceBlack() || aChunk.IsNull()) { if (!mMuteFrame) { mMuteFrame = VideoFrame::CreateBlackImage(gfxIntSize(mFrameWidth, mFrameHeight)); MOZ_ASSERT(mMuteFrame); } img = mMuteFrame; } else { img = aChunk.mFrame.GetImage(); } ImageFormat format = img->GetFormat(); if (format != ImageFormat::PLANAR_YCBCR) { VP8LOG("Unsupported video format\n"); return NS_ERROR_FAILURE; } // Cast away constness b/c some of the accessors are non-const PlanarYCbCrImage* yuv = const_cast<PlanarYCbCrImage *>(static_cast<const PlanarYCbCrImage *>(img.get())); // Big-time assumption here that this is all contiguous data coming // from getUserMedia or other sources. MOZ_ASSERT(yuv); if (!yuv->IsValid()) { NS_WARNING("PlanarYCbCrImage is not valid"); return NS_ERROR_FAILURE; } const PlanarYCbCrImage::Data *data = yuv->GetData(); if (isYUV420(data) && !data->mCbSkip) { // 420 planar mVPXImageWrapper->planes[VPX_PLANE_Y] = data->mYChannel; mVPXImageWrapper->planes[VPX_PLANE_U] = data->mCbChannel; mVPXImageWrapper->planes[VPX_PLANE_V] = data->mCrChannel; mVPXImageWrapper->stride[VPX_PLANE_Y] = data->mYStride; mVPXImageWrapper->stride[VPX_PLANE_U] = data->mCbCrStride; mVPXImageWrapper->stride[VPX_PLANE_V] = data->mCbCrStride; } else { uint32_t yPlaneSize = mFrameWidth * mFrameHeight; uint32_t halfWidth = (mFrameWidth + 1) / 2; uint32_t halfHeight = (mFrameHeight + 1) / 2; uint32_t uvPlaneSize = halfWidth * halfHeight; if (mI420Frame.IsEmpty()) { mI420Frame.SetLength(yPlaneSize + uvPlaneSize * 2); } MOZ_ASSERT(mI420Frame.Length() >= (yPlaneSize + uvPlaneSize * 2)); uint8_t *y = mI420Frame.Elements(); uint8_t *cb = mI420Frame.Elements() + yPlaneSize; uint8_t *cr = mI420Frame.Elements() + yPlaneSize + uvPlaneSize; if (isYUV420(data) && data->mCbSkip) { // If mCbSkip is set, we assume it's nv12 or nv21. if (data->mCbChannel < data->mCrChannel) { // nv12 libyuv::NV12ToI420(data->mYChannel, data->mYStride, data->mCbChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); } else { // nv21 libyuv::NV21ToI420(data->mYChannel, data->mYStride, data->mCrChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); } } else if (isYUV444(data) && !data->mCbSkip) { libyuv::I444ToI420(data->mYChannel, data->mYStride, data->mCbChannel, data->mCbCrStride, data->mCrChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); } else if (isYUV422(data) && !data->mCbSkip) { libyuv::I422ToI420(data->mYChannel, data->mYStride, data->mCbChannel, data->mCbCrStride, data->mCrChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); } else { VP8LOG("Unsupported planar format\n"); return NS_ERROR_NOT_IMPLEMENTED; } mVPXImageWrapper->planes[VPX_PLANE_Y] = y; mVPXImageWrapper->planes[VPX_PLANE_U] = cb; mVPXImageWrapper->planes[VPX_PLANE_V] = cr; mVPXImageWrapper->stride[VPX_PLANE_Y] = mFrameWidth; mVPXImageWrapper->stride[VPX_PLANE_U] = halfWidth; mVPXImageWrapper->stride[VPX_PLANE_V] = halfWidth; } return NS_OK; }
SharedImage* ImageContainerChild::CreateSharedImageFromData(Image* image) { NS_ABORT_IF_FALSE(InImageBridgeChildThread(), "Should be in ImageBridgeChild thread."); if (!image) { return nullptr; } if (image->GetFormat() == PLANAR_YCBCR ) { PlanarYCbCrImage *planarYCbCrImage = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrImage::Data *data = planarYCbCrImage->GetData(); NS_ASSERTION(data, "Must be able to retrieve yuv data from image!"); if (!data) { return nullptr; } SharedMemory::SharedMemoryType shmType = OptimalShmemType(); size_t size = ShmemYCbCrImage::ComputeMinBufferSize(data->mYSize, data->mCbCrSize); Shmem shmem; if (!AllocUnsafeShmem(size, shmType, &shmem)) { return nullptr; } ShmemYCbCrImage::InitializeBufferInfo(shmem.get<uint8_t>(), data->mYSize, data->mCbCrSize); ShmemYCbCrImage shmemImage(shmem); if (!shmemImage.IsValid() || shmem.Size<uint8_t>() < size) { DeallocShmem(shmem); return nullptr; } for (int i = 0; i < data->mYSize.height; i++) { memcpy(shmemImage.GetYData() + i * shmemImage.GetYStride(), data->mYChannel + i * data->mYStride, data->mYSize.width); } for (int i = 0; i < data->mCbCrSize.height; i++) { memcpy(shmemImage.GetCbData() + i * shmemImage.GetCbCrStride(), data->mCbChannel + i * data->mCbCrStride, data->mCbCrSize.width); memcpy(shmemImage.GetCrData() + i * shmemImage.GetCbCrStride(), data->mCrChannel + i * data->mCbCrStride, data->mCbCrSize.width); } ++mActiveImageCount; SharedImage* result = new SharedImage(YCbCrImage(shmem, 0, data->GetPictureRect())); return result; #ifdef MOZ_WIDGET_GONK } else if (image->GetFormat() == GONK_IO_SURFACE) { GonkIOSurfaceImage* gonkImage = static_cast<GonkIOSurfaceImage*>(image); SharedImage* result = new SharedImage(gonkImage->GetSurfaceDescriptor()); return result; } else if (image->GetFormat() == GRALLOC_PLANAR_YCBCR) { GrallocPlanarYCbCrImage* GrallocImage = static_cast<GrallocPlanarYCbCrImage*>(image); SharedImage* result = new SharedImage(GrallocImage->GetSurfaceDescriptor()); return result; #endif } else { NS_RUNTIMEABORT("TODO: Only YCbCrImage is supported here right now."); } return nullptr; }
bool ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) { AutoTArray<ImageContainer::OwningImage,4> images; uint32_t generationCounter; aContainer->GetCurrentImages(&images, &generationCounter); if (mLastUpdateGenerationCounter == generationCounter) { return true; } mLastUpdateGenerationCounter = generationCounter; for (int32_t i = images.Length() - 1; i >= 0; --i) { if (!images[i].mImage->IsValid()) { // Don't try to update to an invalid image. images.RemoveElementAt(i); } } if (images.IsEmpty()) { // This can happen if a ClearAllImages raced with SetCurrentImages from // another thread and ClearImagesFromImageBridge ran after the // SetCurrentImages call but before UpdateImageClientNow. // This can also happen if all images in the list are invalid. // We return true because the caller would attempt to recreate the // ImageClient otherwise, and that isn't going to help. return true; } nsTArray<Buffer> newBuffers; AutoTArray<CompositableForwarder::TimedTextureClient,4> textures; for (auto& img : images) { Image* image = img.mImage; #ifdef MOZ_WIDGET_GONK if (image->GetFormat() == ImageFormat::OVERLAY_IMAGE) { OverlayImage* overlayImage = static_cast<OverlayImage*>(image); OverlaySource source; if (overlayImage->GetSidebandStream().IsValid()) { // Duplicate GonkNativeHandle::NhObj for ipc, // since ParamTraits<GonkNativeHandle>::Write() absorbs native_handle_t. RefPtr<GonkNativeHandle::NhObj> nhObj = overlayImage->GetSidebandStream().GetDupNhObj(); GonkNativeHandle handle(nhObj); if (!handle.IsValid()) { gfxWarning() << "ImageClientSingle::UpdateImage failed in GetDupNhObj"; return false; } source.handle() = OverlayHandle(handle); } else { source.handle() = OverlayHandle(overlayImage->GetOverlayId()); } source.size() = overlayImage->GetSize(); GetForwarder()->UseOverlaySource(this, source, image->GetPictureRect()); continue; } #endif RefPtr<TextureClient> texture = image->GetTextureClient(this); const bool hasTextureClient = !!texture; for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) { if (mBuffers[i].mImageSerial == image->GetSerial()) { if (hasTextureClient) { MOZ_ASSERT(image->GetTextureClient(this) == mBuffers[i].mTextureClient); } else { texture = mBuffers[i].mTextureClient; } // Remove this element from mBuffers so mBuffers only contains // images that aren't present in 'images' mBuffers.RemoveElementAt(i); } } if (!texture) { // Slow path, we should not be hitting it very often and if we do it means // we are using an Image class that is not backed by textureClient and we // should fix it. if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return false; } texture = TextureClient::CreateForYCbCr(GetForwarder(), data->mYSize, data->mCbCrSize, data->mStereoMode, TextureFlags::DEFAULT | mTextureFlags ); if (!texture) { return false; } TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY); if (!autoLock.Succeeded()) { return false; } bool status = UpdateYCbCrTextureClient(texture, *data); MOZ_ASSERT(status); if (!status) { return false; } } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE || image->GetFormat() == ImageFormat::EGLIMAGE) { gfx::IntSize size = image->GetSize(); if (image->GetFormat() == ImageFormat::EGLIMAGE) { EGLImageImage* typedImage = image->AsEGLImageImage(); texture = EGLImageTextureData::CreateTextureClient( typedImage, size, GetForwarder(), mTextureFlags); #ifdef MOZ_WIDGET_ANDROID } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { SurfaceTextureImage* typedImage = image->AsSurfaceTextureImage(); texture = AndroidSurfaceTextureData::CreateTextureClient( typedImage->GetSurfaceTexture(), size, typedImage->GetOriginPos(), GetForwarder(), mTextureFlags ); #endif } else { MOZ_ASSERT(false, "Bad ImageFormat."); } } else { RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface(); MOZ_ASSERT(surface); texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(), BackendSelector::Content, mTextureFlags); if (!texture) { return false; } MOZ_ASSERT(texture->CanExposeDrawTarget()); if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return false; } { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = texture->BorrowDrawTarget(); if (!dt) { gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; return false; } MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } texture->Unlock(); } } if (!texture || !AddTextureClient(texture)) { return false; } CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); t->mTextureClient = texture; t->mTimeStamp = img.mTimeStamp; t->mPictureRect = image->GetPictureRect(); t->mFrameID = img.mFrameID; t->mProducerID = img.mProducerID; Buffer* newBuf = newBuffers.AppendElement(); newBuf->mImageSerial = image->GetSerial(); newBuf->mTextureClient = texture; texture->SyncWithObject(GetForwarder()->GetSyncObject()); } GetForwarder()->UseTextures(this, textures); for (auto& b : mBuffers) { RemoveTexture(b.mTextureClient); } mBuffers.SwapElements(newBuffers); return true; }
bool ImageClientSingle::UpdateImageInternal(ImageContainer* aContainer, uint32_t aContentFlags, bool* aIsSwapped) { AutoLockImage autoLock(aContainer); *aIsSwapped = false; Image *image = autoLock.GetImage(); if (!image) { return false; } if (mLastPaintedImageSerial == image->GetSerial()) { return true; } if (image->AsSharedImage() && image->AsSharedImage()->GetTextureClient(this)) { // fast path: no need to allocate and/or copy image data RefPtr<TextureClient> texture = image->AsSharedImage()->GetTextureClient(this); if (mFrontBuffer) { GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); } mFrontBuffer = texture; if (!AddTextureClient(texture)) { mFrontBuffer = nullptr; return false; } GetForwarder()->UpdatedTexture(this, texture, nullptr); GetForwarder()->UseTexture(this, texture); } else if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return false; } if (mFrontBuffer && mFrontBuffer->IsImmutable()) { GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); mFrontBuffer = nullptr; } bool bufferCreated = false; if (!mFrontBuffer) { mFrontBuffer = CreateBufferTextureClient(gfx::SurfaceFormat::YUV, TEXTURE_FLAGS_DEFAULT); gfx::IntSize ySize(data->mYSize.width, data->mYSize.height); gfx::IntSize cbCrSize(data->mCbCrSize.width, data->mCbCrSize.height); if (!mFrontBuffer->AsTextureClientYCbCr()->AllocateForYCbCr(ySize, cbCrSize, data->mStereoMode)) { mFrontBuffer = nullptr; return false; } bufferCreated = true; } if (!mFrontBuffer->Lock(OPEN_WRITE_ONLY)) { return false; } bool status = mFrontBuffer->AsTextureClientYCbCr()->UpdateYCbCr(*data); mFrontBuffer->Unlock(); if (bufferCreated) { if (!AddTextureClient(mFrontBuffer)) { mFrontBuffer = nullptr; return false; } } if (status) { GetForwarder()->UpdatedTexture(this, mFrontBuffer, nullptr); GetForwarder()->UseTexture(this, mFrontBuffer); } else { MOZ_ASSERT(false); return false; } } else if (image->GetFormat() == ImageFormat::SHARED_TEXTURE) { SharedTextureImage* sharedImage = static_cast<SharedTextureImage*>(image); const SharedTextureImage::Data *data = sharedImage->GetData(); gfx::IntSize size = gfx::IntSize(image->GetSize().width, image->GetSize().height); if (mFrontBuffer) { GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); mFrontBuffer = nullptr; } RefPtr<SharedTextureClientOGL> buffer = new SharedTextureClientOGL(mTextureFlags); buffer->InitWith(data->mHandle, size, data->mShareType, data->mInverted); mFrontBuffer = buffer; if (!AddTextureClient(mFrontBuffer)) { mFrontBuffer = nullptr; return false; } GetForwarder()->UseTexture(this, mFrontBuffer); } else { RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface(); MOZ_ASSERT(surface); gfx::IntSize size = image->GetSize(); if (mFrontBuffer && (mFrontBuffer->IsImmutable() || mFrontBuffer->GetSize() != size)) { GetForwarder()->RemoveTextureFromCompositable(this, mFrontBuffer); mFrontBuffer = nullptr; } bool bufferCreated = false; if (!mFrontBuffer) { gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(gfx::ContentForFormat(surface->GetFormat())); mFrontBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format), mTextureFlags, gfx::BackendType::NONE, size); MOZ_ASSERT(mFrontBuffer->AsTextureClientDrawTarget()); if (!mFrontBuffer->AsTextureClientDrawTarget()->AllocateForSurface(size)) { mFrontBuffer = nullptr; return false; } bufferCreated = true; } if (!mFrontBuffer->Lock(OPEN_WRITE_ONLY)) { return false; } { // We must not keep a reference to the DrawTarget after it has been unlocked. RefPtr<DrawTarget> dt = mFrontBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget(); MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } mFrontBuffer->Unlock(); if (bufferCreated) { if (!AddTextureClient(mFrontBuffer)) { mFrontBuffer = nullptr; return false; } } GetForwarder()->UpdatedTexture(this, mFrontBuffer, nullptr); GetForwarder()->UseTexture(this, mFrontBuffer); } UpdatePictureRect(image->GetPictureRect()); mLastPaintedImageSerial = image->GetSerial(); aContainer->NotifyPaintedImage(image); *aIsSwapped = true; return true; }
bool ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) { AutoLockImage autoLock(aContainer); Image *image = autoLock.GetImage(); if (!image) { return false; } if (mLastPaintedImageSerial == image->GetSerial()) { return true; } if (image->GetFormat() == PLANAR_YCBCR) { EnsureTextureClient(TEXTURE_YCBCR); PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); if (ycbcr->AsSharedPlanarYCbCrImage()) { AutoLockTextureClient lock(mTextureClient); SurfaceDescriptor sd; if (!ycbcr->AsSharedPlanarYCbCrImage()->ToSurfaceDescriptor(sd)) { return false; } if (IsSurfaceDescriptorValid(*lock.GetSurfaceDescriptor())) { GetForwarder()->DestroySharedSurface(lock.GetSurfaceDescriptor()); } *lock.GetSurfaceDescriptor() = sd; } else { AutoLockYCbCrClient clientLock(mTextureClient); if (!clientLock.Update(ycbcr)) { NS_WARNING("failed to update TextureClient (YCbCr)"); return false; } } } else if (image->GetFormat() == SHARED_TEXTURE) { EnsureTextureClient(TEXTURE_SHARED_GL_EXTERNAL); SharedTextureImage* sharedImage = static_cast<SharedTextureImage*>(image); const SharedTextureImage::Data *data = sharedImage->GetData(); SharedTextureDescriptor texture(data->mShareType, data->mHandle, data->mSize, data->mInverted); mTextureClient->SetDescriptor(SurfaceDescriptor(texture)); } else if (image->GetFormat() == SHARED_RGB) { EnsureTextureClient(TEXTURE_SHMEM); nsIntRect rect(0, 0, image->GetSize().width, image->GetSize().height); UpdatePictureRect(rect); AutoLockTextureClient lock(mTextureClient); SurfaceDescriptor desc; if (!static_cast<SharedRGBImage*>(image)->ToSurfaceDescriptor(desc)) { return false; } mTextureClient->SetDescriptor(desc); } else { nsRefPtr<gfxASurface> surface = image->GetAsSurface(); MOZ_ASSERT(surface); EnsureTextureClient(TEXTURE_SHMEM); nsRefPtr<gfxPattern> pattern = new gfxPattern(surface); pattern->SetFilter(mFilter); AutoLockShmemClient clientLock(mTextureClient); if (!clientLock.Update(image, aContentFlags, pattern)) { NS_WARNING("failed to update TextureClient"); return false; } } Updated(); if (image->GetFormat() == PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); UpdatePictureRect(ycbcr->GetData()->GetPictureRect()); } mLastPaintedImageSerial = image->GetSerial(); aContainer->NotifyPaintedImage(image); return true; }
void ImageLayerOGL::RenderLayer(int, const nsIntPoint& aOffset) { nsRefPtr<ImageContainer> container = GetContainer(); if (!container || mOGLManager->CompositingDisabled()) return; mOGLManager->MakeCurrent(); AutoLockImage autoLock(container); Image *image = autoLock.GetImage(); if (!image) { return; } NS_ASSERTION(image->GetFormat() != REMOTE_IMAGE_BITMAP, "Remote images aren't handled yet in OGL layers!"); if (image->GetFormat() == PLANAR_YCBCR) { PlanarYCbCrImage *yuvImage = static_cast<PlanarYCbCrImage*>(image); if (!yuvImage->IsValid()) { return; } PlanarYCbCrOGLBackendData *data = static_cast<PlanarYCbCrOGLBackendData*>(yuvImage->GetBackendData(LAYERS_OPENGL)); if (data && data->mTextures->GetGLContext() != gl()) { // If these textures were allocated by another layer manager, // clear them out and re-allocate below. data = nullptr; yuvImage->SetBackendData(LAYERS_OPENGL, nullptr); } if (!data) { AllocateTexturesYCbCr(yuvImage); data = static_cast<PlanarYCbCrOGLBackendData*>(yuvImage->GetBackendData(LAYERS_OPENGL)); } if (!data || data->mTextures->GetGLContext() != gl()) { // XXX - Can this ever happen? If so I need to fix this! return; } gl()->MakeCurrent(); gl()->fActiveTexture(LOCAL_GL_TEXTURE2); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[2].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); gl()->fActiveTexture(LOCAL_GL_TEXTURE1); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[1].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[0].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); ShaderProgramOGL *program = mOGLManager->GetProgram(YCbCrLayerProgramType, GetMaskLayer()); program->Activate(); program->SetLayerQuadRect(nsIntRect(0, 0, yuvImage->GetSize().width, yuvImage->GetSize().height)); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetYCbCrTextureUnits(0, 1, 2); program->LoadMask(GetMaskLayer()); mOGLManager->BindAndDrawQuadWithTextureRect(program, yuvImage->GetData()->GetPictureRect(), nsIntSize(yuvImage->GetData()->mYSize.width, yuvImage->GetData()->mYSize.height)); // We shouldn't need to do this, but do it anyway just in case // someone else forgets. gl()->fActiveTexture(LOCAL_GL_TEXTURE0); } else if (image->GetFormat() == CAIRO_SURFACE) { CairoImage *cairoImage = static_cast<CairoImage*>(image); if (!cairoImage->mSurface) { return; } NS_ASSERTION(cairoImage->mSurface->GetContentType() != gfxASurface::CONTENT_ALPHA, "Image layer has alpha image"); CairoOGLBackendData *data = static_cast<CairoOGLBackendData*>(cairoImage->GetBackendData(LAYERS_OPENGL)); if (data && data->mTexture.GetGLContext() != gl()) { // If this texture was allocated by another layer manager, clear // it out and re-allocate below. data = nullptr; cairoImage->SetBackendData(LAYERS_OPENGL, nullptr); } if (!data) { AllocateTexturesCairo(cairoImage); data = static_cast<CairoOGLBackendData*>(cairoImage->GetBackendData(LAYERS_OPENGL)); } if (!data || data->mTexture.GetGLContext() != gl()) { // XXX - Can this ever happen? If so I need to fix this! return; } gl()->MakeCurrent(); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTexture.GetTextureID()); ShaderProgramOGL *program = mOGLManager->GetProgram(data->mLayerProgram, GetMaskLayer()); gl()->ApplyFilterToBoundTexture(mFilter); program->Activate(); program->SetLayerQuadRect(nsIntRect(0, 0, cairoImage->GetSize().width, cairoImage->GetSize().height)); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetTextureUnit(0); program->LoadMask(GetMaskLayer()); mOGLManager->BindAndDrawQuad(program); } else if (image->GetFormat() == SHARED_TEXTURE) { SharedTextureImage* texImage = static_cast<SharedTextureImage*>(image); const SharedTextureImage::Data* data = texImage->GetData(); GLContext::SharedHandleDetails handleDetails; if (!gl()->GetSharedHandleDetails(data->mShareType, data->mHandle, handleDetails)) { NS_ERROR("Failed to get shared handle details"); return; } ShaderProgramOGL* program = mOGLManager->GetProgram(handleDetails.mProgramType, GetMaskLayer()); program->Activate(); if (handleDetails.mProgramType == gl::RGBARectLayerProgramType) { // 2DRect case, get the multiplier right for a sampler2DRect program->SetTexCoordMultiplier(data->mSize.width, data->mSize.height); } program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetTextureUnit(0); program->SetTextureTransform(handleDetails.mTextureTransform); program->LoadMask(GetMaskLayer()); if (!texImage->GetBackendData(LAYERS_OPENGL)) { AllocateTextureSharedTexture(texImage, gl(), handleDetails.mTarget); } ImageOGLBackendData *backendData = static_cast<ImageOGLBackendData*>(texImage->GetBackendData(LAYERS_OPENGL)); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(handleDetails.mTarget, backendData->mTexture.GetTextureID()); if (!gl()->AttachSharedHandle(data->mShareType, data->mHandle)) { NS_ERROR("Failed to bind shared texture handle"); return; } gl()->ApplyFilterToBoundTexture(handleDetails.mTarget, mFilter); program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), data->mSize)); mOGLManager->BindAndDrawQuad(program, data->mInverted); gl()->fBindTexture(handleDetails.mTarget, 0); gl()->DetachSharedHandle(data->mShareType, data->mHandle); #ifdef MOZ_WIDGET_GONK } else if (image->GetFormat() == GONK_IO_SURFACE) { GonkIOSurfaceImage *ioImage = static_cast<GonkIOSurfaceImage*>(image); if (!ioImage) { return; } gl()->MakeCurrent(); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); if (!ioImage->GetBackendData(LAYERS_OPENGL)) { AllocateTextureIOSurface(ioImage, gl()); } GonkIOSurfaceImageOGLBackendData *data = static_cast<GonkIOSurfaceImageOGLBackendData*>(ioImage->GetBackendData(LAYERS_OPENGL)); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->BindExternalBuffer(data->mTexture.GetTextureID(), ioImage->GetNativeBuffer()); ShaderProgramOGL *program = mOGLManager->GetProgram(RGBAExternalLayerProgramType, GetMaskLayer()); gl()->ApplyFilterToBoundTexture(mFilter); program->Activate(); program->SetLayerQuadRect(nsIntRect(0, 0, ioImage->GetSize().width, ioImage->GetSize().height)); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetTextureUnit(0); program->LoadMask(GetMaskLayer()); mOGLManager->BindAndDrawQuadWithTextureRect(program, GetVisibleRegion().GetBounds(), nsIntSize(ioImage->GetSize().width, ioImage->GetSize().height)); #endif } GetContainer()->NotifyPaintedImage(image); }
bool ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) { AutoLockImage autoLock(aContainer); Image *image = autoLock.GetImage(); if (!image) { return false; } if (mLastPaintedImageSerial == image->GetSerial()) { return true; } if (image->AsSharedImage() && image->AsSharedImage()->GetTextureClient()) { // fast path: no need to allocate and/or copy image data RefPtr<TextureClient> texture = image->AsSharedImage()->GetTextureClient(); if (texture->IsSharedWithCompositor()) { // XXX - temporary fix for bug 911941 // This will be changed with bug 912907 return false; } if (mFrontBuffer) { RemoveTextureClient(mFrontBuffer); } mFrontBuffer = texture; AddTextureClient(texture); GetForwarder()->UpdatedTexture(this, texture, nullptr); GetForwarder()->UseTexture(this, texture); } else if (image->GetFormat() == PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return false; } if (mFrontBuffer && mFrontBuffer->IsImmutable()) { RemoveTextureClient(mFrontBuffer); mFrontBuffer = nullptr; } bool bufferCreated = false; if (!mFrontBuffer) { mFrontBuffer = CreateBufferTextureClient(gfx::FORMAT_YUV, TEXTURE_FLAGS_DEFAULT); gfx::IntSize ySize(data->mYSize.width, data->mYSize.height); gfx::IntSize cbCrSize(data->mCbCrSize.width, data->mCbCrSize.height); if (!mFrontBuffer->AsTextureClientYCbCr()->AllocateForYCbCr(ySize, cbCrSize, data->mStereoMode)) { mFrontBuffer = nullptr; return false; } bufferCreated = true; } if (!mFrontBuffer->Lock(OPEN_READ_WRITE)) { return false; } bool status = mFrontBuffer->AsTextureClientYCbCr()->UpdateYCbCr(*data); mFrontBuffer->Unlock(); if (bufferCreated) { AddTextureClient(mFrontBuffer); } if (status) { GetForwarder()->UpdatedTexture(this, mFrontBuffer, nullptr); GetForwarder()->UseTexture(this, mFrontBuffer); } else { MOZ_ASSERT(false); return false; } } else if (image->GetFormat() == SHARED_TEXTURE) { SharedTextureImage* sharedImage = static_cast<SharedTextureImage*>(image); const SharedTextureImage::Data *data = sharedImage->GetData(); gfx::IntSize size = gfx::IntSize(image->GetSize().width, image->GetSize().height); if (mFrontBuffer) { RemoveTextureClient(mFrontBuffer); mFrontBuffer = nullptr; } RefPtr<SharedTextureClientOGL> buffer = new SharedTextureClientOGL(mTextureFlags); buffer->InitWith(data->mHandle, size, data->mShareType, data->mInverted); mFrontBuffer = buffer; AddTextureClient(mFrontBuffer); GetForwarder()->UseTexture(this, mFrontBuffer); } else { nsRefPtr<gfxASurface> surface = image->GetAsSurface(); MOZ_ASSERT(surface); gfx::IntSize size = gfx::IntSize(image->GetSize().width, image->GetSize().height); if (mFrontBuffer && (mFrontBuffer->IsImmutable() || mFrontBuffer->GetSize() != size)) { RemoveTextureClient(mFrontBuffer); mFrontBuffer = nullptr; } bool bufferCreated = false; if (!mFrontBuffer) { gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(surface->GetContentType()); mFrontBuffer = CreateBufferTextureClient(gfx::ImageFormatToSurfaceFormat(format), TEXTURE_FLAGS_DEFAULT); MOZ_ASSERT(mFrontBuffer->AsTextureClientSurface()); mFrontBuffer->AsTextureClientSurface()->AllocateForSurface(size); bufferCreated = true; } if (!mFrontBuffer->Lock(OPEN_READ_WRITE)) { return false; } bool status = mFrontBuffer->AsTextureClientSurface()->UpdateSurface(surface); mFrontBuffer->Unlock(); if (bufferCreated) { AddTextureClient(mFrontBuffer); } if (status) { GetForwarder()->UpdatedTexture(this, mFrontBuffer, nullptr); GetForwarder()->UseTexture(this, mFrontBuffer); } else { return false; } } UpdatePictureRect(image->GetPictureRect()); mLastPaintedImageSerial = image->GetSerial(); aContainer->NotifyPaintedImage(image); return true; }
bool ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) { AutoLockImage autoLock(aContainer); Image *image = autoLock.GetImage(); if (!image) { return false; } // Don't try to update to an invalid image. We return true because the caller // would attempt to recreate the ImageClient otherwise, and that isn't going // to help. if (!image->IsValid()) { return true; } if (mLastPaintedImageSerial == image->GetSerial()) { return true; } RefPtr<TextureClient> texture = image->GetTextureClient(this); AutoRemoveTexture autoRemoveTexture(this); if (texture != mFrontBuffer) { autoRemoveTexture.mTexture = mFrontBuffer; mFrontBuffer = nullptr; } if (!texture) { // Slow path, we should not be hitting it very often and if we do it means // we are using an Image class that is not backed by textureClient and we // should fix it. if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return false; } texture = TextureClient::CreateForYCbCr(GetForwarder(), data->mYSize, data->mCbCrSize, data->mStereoMode, TextureFlags::DEFAULT | mTextureFlags ); if (!texture || !texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return false; } bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data); MOZ_ASSERT(status); texture->Unlock(); if (!status) { return false; } } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE || image->GetFormat() == ImageFormat::EGLIMAGE) { gfx::IntSize size = image->GetSize(); if (image->GetFormat() == ImageFormat::EGLIMAGE) { EGLImageImage* typedImage = static_cast<EGLImageImage*>(image); texture = new EGLImageTextureClient(GetForwarder(), mTextureFlags, typedImage, size); #ifdef MOZ_WIDGET_ANDROID } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { SurfaceTextureImage* typedImage = static_cast<SurfaceTextureImage*>(image); const SurfaceTextureImage::Data* data = typedImage->GetData(); texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags, data->mSurfTex, size, data->mOriginPos); #endif } else { MOZ_ASSERT(false, "Bad ImageFormat."); } } else { RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface(); MOZ_ASSERT(surface); texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(), gfx::BackendType::NONE, mTextureFlags); if (!texture) { return false; } MOZ_ASSERT(texture->CanExposeDrawTarget()); if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return false; } { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = texture->BorrowDrawTarget(); if (!dt) { gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; return false; } MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } texture->Unlock(); } } if (!texture || !AddTextureClient(texture)) { return false; } mFrontBuffer = texture; GetForwarder()->UseTexture(this, texture); UpdatePictureRect(image->GetPictureRect()); mLastPaintedImageSerial = image->GetSerial(); aContainer->NotifyPaintedImage(image); texture->SyncWithObject(GetForwarder()->GetSyncObject()); return true; }
/* static */ already_AddRefed<TextureClient> ImageClient::CreateTextureClientForImage(Image* aImage, KnowsCompositor* aForwarder) { RefPtr<TextureClient> texture; if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(aImage); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return nullptr; } texture = TextureClient::CreateForYCbCr(aForwarder, data->mYSize, data->mYStride, data->mCbCrSize, data->mCbCrStride, data->mStereoMode, data->mColorDepth, data->mYUVColorSpace, TextureFlags::DEFAULT); if (!texture) { return nullptr; } TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY); if (!autoLock.Succeeded()) { return nullptr; } bool status = UpdateYCbCrTextureClient(texture, *data); MOZ_ASSERT(status); if (!status) { return nullptr; } #ifdef MOZ_WIDGET_ANDROID } else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE) { gfx::IntSize size = aImage->GetSize(); SurfaceTextureImage* typedImage = aImage->AsSurfaceTextureImage(); texture = AndroidSurfaceTextureData::CreateTextureClient( typedImage->GetHandle(), size, typedImage->GetContinuous(), typedImage->GetOriginPos(), aForwarder->GetTextureForwarder(), TextureFlags::DEFAULT); #endif } else { RefPtr<gfx::SourceSurface> surface = aImage->GetAsSourceSurface(); MOZ_ASSERT(surface); texture = TextureClient::CreateForDrawing(aForwarder, surface->GetFormat(), aImage->GetSize(), BackendSelector::Content, TextureFlags::DEFAULT); if (!texture) { return nullptr; } MOZ_ASSERT(texture->CanExposeDrawTarget()); if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return nullptr; } { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = texture->BorrowDrawTarget(); if (!dt) { gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; return nullptr; } MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } texture->Unlock(); } return texture.forget(); }
nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk) { RefPtr<Image> img; if (aChunk.mFrame.GetForceBlack() || aChunk.IsNull()) { if (!mMuteFrame) { mMuteFrame = VideoFrame::CreateBlackImage(gfx::IntSize(mFrameWidth, mFrameHeight)); MOZ_ASSERT(mMuteFrame); } img = mMuteFrame; } else { img = aChunk.mFrame.GetImage(); } if (img->GetSize() != IntSize(mFrameWidth, mFrameHeight)) { VP8LOG("Dynamic resolution changes (was %dx%d, now %dx%d) are unsupported\n", mFrameWidth, mFrameHeight, img->GetSize().width, img->GetSize().height); return NS_ERROR_FAILURE; } ImageFormat format = img->GetFormat(); if (format == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* yuv = static_cast<PlanarYCbCrImage *>(img.get()); MOZ_RELEASE_ASSERT(yuv); if (!yuv->IsValid()) { NS_WARNING("PlanarYCbCrImage is not valid"); return NS_ERROR_FAILURE; } const PlanarYCbCrImage::Data *data = yuv->GetData(); if (isYUV420(data) && !data->mCbSkip) { // 420 planar, no need for conversions mVPXImageWrapper->planes[VPX_PLANE_Y] = data->mYChannel; mVPXImageWrapper->planes[VPX_PLANE_U] = data->mCbChannel; mVPXImageWrapper->planes[VPX_PLANE_V] = data->mCrChannel; mVPXImageWrapper->stride[VPX_PLANE_Y] = data->mYStride; mVPXImageWrapper->stride[VPX_PLANE_U] = data->mCbCrStride; mVPXImageWrapper->stride[VPX_PLANE_V] = data->mCbCrStride; return NS_OK; } } // Not 420 planar, have to convert uint32_t yPlaneSize = mFrameWidth * mFrameHeight; uint32_t halfWidth = (mFrameWidth + 1) / 2; uint32_t halfHeight = (mFrameHeight + 1) / 2; uint32_t uvPlaneSize = halfWidth * halfHeight; if (mI420Frame.IsEmpty()) { mI420Frame.SetLength(yPlaneSize + uvPlaneSize * 2); } uint8_t *y = mI420Frame.Elements(); uint8_t *cb = mI420Frame.Elements() + yPlaneSize; uint8_t *cr = mI420Frame.Elements() + yPlaneSize + uvPlaneSize; if (format == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* yuv = static_cast<PlanarYCbCrImage *>(img.get()); MOZ_RELEASE_ASSERT(yuv); if (!yuv->IsValid()) { NS_WARNING("PlanarYCbCrImage is not valid"); return NS_ERROR_FAILURE; } const PlanarYCbCrImage::Data *data = yuv->GetData(); int rv; std::string yuvFormat; if (isYUV420(data) && data->mCbSkip) { // If mCbSkip is set, we assume it's nv12 or nv21. if (data->mCbChannel < data->mCrChannel) { // nv12 rv = libyuv::NV12ToI420(data->mYChannel, data->mYStride, data->mCbChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); yuvFormat = "NV12"; } else { // nv21 rv = libyuv::NV21ToI420(data->mYChannel, data->mYStride, data->mCrChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); yuvFormat = "NV21"; } } else if (isYUV444(data) && !data->mCbSkip) { rv = libyuv::I444ToI420(data->mYChannel, data->mYStride, data->mCbChannel, data->mCbCrStride, data->mCrChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); yuvFormat = "I444"; } else if (isYUV422(data) && !data->mCbSkip) { rv = libyuv::I422ToI420(data->mYChannel, data->mYStride, data->mCbChannel, data->mCbCrStride, data->mCrChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); yuvFormat = "I422"; } else { VP8LOG("Unsupported planar format\n"); NS_ASSERTION(false, "Unsupported planar format"); return NS_ERROR_NOT_IMPLEMENTED; } if (rv != 0) { VP8LOG("Converting an %s frame to I420 failed\n", yuvFormat.c_str()); return NS_ERROR_FAILURE; } VP8LOG("Converted an %s frame to I420\n"); } else { // Not YCbCr at all. Try to get access to the raw data and convert. RefPtr<SourceSurface> surf = img->GetAsSourceSurface(); if (!surf) { VP8LOG("Getting surface from %s image failed\n", Stringify(format).c_str()); return NS_ERROR_FAILURE; } RefPtr<DataSourceSurface> data = surf->GetDataSurface(); if (!data) { VP8LOG("Getting data surface from %s image with %s (%s) surface failed\n", Stringify(format).c_str(), Stringify(surf->GetType()).c_str(), Stringify(surf->GetFormat()).c_str()); return NS_ERROR_FAILURE; } DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ); if (!map.IsMapped()) { VP8LOG("Reading DataSourceSurface from %s image with %s (%s) surface failed\n", Stringify(format).c_str(), Stringify(surf->GetType()).c_str(), Stringify(surf->GetFormat()).c_str()); return NS_ERROR_FAILURE; } int rv; switch (surf->GetFormat()) { case SurfaceFormat::B8G8R8A8: case SurfaceFormat::B8G8R8X8: rv = libyuv::ARGBToI420(static_cast<uint8*>(map.GetData()), map.GetStride(), y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); break; case SurfaceFormat::R5G6B5_UINT16: rv = libyuv::RGB565ToI420(static_cast<uint8*>(map.GetData()), map.GetStride(), y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); break; default: VP8LOG("Unsupported SourceSurface format %s\n", Stringify(surf->GetFormat()).c_str()); NS_ASSERTION(false, "Unsupported SourceSurface format"); return NS_ERROR_NOT_IMPLEMENTED; } if (rv != 0) { VP8LOG("%s to I420 conversion failed\n", Stringify(surf->GetFormat()).c_str()); return NS_ERROR_FAILURE; } VP8LOG("Converted a %s frame to I420\n", Stringify(surf->GetFormat()).c_str()); } mVPXImageWrapper->planes[VPX_PLANE_Y] = y; mVPXImageWrapper->planes[VPX_PLANE_U] = cb; mVPXImageWrapper->planes[VPX_PLANE_V] = cr; mVPXImageWrapper->stride[VPX_PLANE_Y] = mFrameWidth; mVPXImageWrapper->stride[VPX_PLANE_U] = halfWidth; mVPXImageWrapper->stride[VPX_PLANE_V] = halfWidth; return NS_OK; }
void ImageLayerD3D9::RenderLayer() { ImageContainer *container = GetContainer(); if (!container || mD3DManager->CompositingDisabled()) { return; } AutoLockImage autoLock(container); Image *image = autoLock.GetImage(); if (!image) { return; } SetShaderTransformAndOpacity(); gfx::IntSize size = image->GetSize(); if (image->GetFormat() == ImageFormat::CAIRO_SURFACE || image->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP || image->GetFormat() == ImageFormat::D3D9_RGB32_TEXTURE) { NS_ASSERTION(image->GetFormat() != ImageFormat::CAIRO_SURFACE || !static_cast<CairoImage*>(image)->mSourceSurface || static_cast<CairoImage*>(image)->mSourceSurface->GetFormat() != SurfaceFormat::A8, "Image layer has alpha image"); bool hasAlpha = false; nsRefPtr<IDirect3DTexture9> texture = GetTexture(image, hasAlpha); device()->SetVertexShaderConstantF(CBvLayerQuad, ShaderConstantRect(0, 0, size.width, size.height), 1); if (hasAlpha) { mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER, GetMaskLayer()); } else { mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER, GetMaskLayer()); } if (mFilter == GraphicsFilter::FILTER_NEAREST) { device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); } device()->SetTexture(0, texture); image = nullptr; autoLock.Unlock(); device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); if (mFilter == GraphicsFilter::FILTER_NEAREST) { device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); } } else { PlanarYCbCrImage *yuvImage = static_cast<PlanarYCbCrImage*>(image); if (!yuvImage->IsValid()) { return; } if (!yuvImage->GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D9)) { AllocateTexturesYCbCr(yuvImage, device(), mD3DManager); } PlanarYCbCrD3D9BackendData *data = static_cast<PlanarYCbCrD3D9BackendData*>(yuvImage->GetBackendData(mozilla::layers::LayersBackend::LAYERS_D3D9)); if (!data) { return; } nsRefPtr<IDirect3DDevice9> dev; data->mYTexture->GetDevice(getter_AddRefs(dev)); if (dev != device()) { return; } device()->SetVertexShaderConstantF(CBvLayerQuad, ShaderConstantRect(0, 0, size.width, size.height), 1); device()->SetVertexShaderConstantF(CBvTextureCoords, ShaderConstantRect( (float)yuvImage->GetData()->mPicX / yuvImage->GetData()->mYSize.width, (float)yuvImage->GetData()->mPicY / yuvImage->GetData()->mYSize.height, (float)yuvImage->GetData()->mPicSize.width / yuvImage->GetData()->mYSize.width, (float)yuvImage->GetData()->mPicSize.height / yuvImage->GetData()->mYSize.height ), 1); mD3DManager->SetShaderMode(DeviceManagerD3D9::YCBCRLAYER, GetMaskLayer()); /* * Send 3d control data and metadata */ if (mD3DManager->GetNv3DVUtils()) { Nv_Stereo_Mode mode; switch (yuvImage->GetData()->mStereoMode) { case StereoMode::LEFT_RIGHT: mode = NV_STEREO_MODE_LEFT_RIGHT; break; case StereoMode::RIGHT_LEFT: mode = NV_STEREO_MODE_RIGHT_LEFT; break; case StereoMode::BOTTOM_TOP: mode = NV_STEREO_MODE_BOTTOM_TOP; break; case StereoMode::TOP_BOTTOM: mode = NV_STEREO_MODE_TOP_BOTTOM; break; case StereoMode::MONO: mode = NV_STEREO_MODE_MONO; break; } // Send control data even in mono case so driver knows to leave stereo mode. mD3DManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE); if (yuvImage->GetData()->mStereoMode != StereoMode::MONO) { mD3DManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE); nsRefPtr<IDirect3DSurface9> renderTarget; device()->GetRenderTarget(0, getter_AddRefs(renderTarget)); mD3DManager->GetNv3DVUtils()->SendNv3DVMetaData((unsigned int)yuvImage->GetSize().width, (unsigned int)yuvImage->GetSize().height, (HANDLE)(data->mYTexture), (HANDLE)(renderTarget)); } } // Linear scaling is default here, adhering to mFilter is difficult since // presumably even with point filtering we'll still want chroma upsampling // to be linear. In the current approach we can't. device()->SetTexture(0, data->mYTexture); device()->SetTexture(1, data->mCbTexture); device()->SetTexture(2, data->mCrTexture); image = nullptr; data = nullptr; autoLock.Unlock(); device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); device()->SetVertexShaderConstantF(CBvTextureCoords, ShaderConstantRect(0, 0, 1.0f, 1.0f), 1); } GetContainer()->NotifyPaintedImage(image); }
void ImageLayerD3D10::RenderLayer() { ImageContainer *container = GetContainer(); if (!container) { return; } AutoLockImage autoLock(container); Image *image = autoLock.GetImage(); if (!image) { return; } gfxIntSize size = image->GetSize(); SetEffectTransformAndOpacity(); ID3D10EffectTechnique *technique; nsRefPtr<IDXGIKeyedMutex> keyedMutex; if (image->GetFormat() == ImageFormat::CAIRO_SURFACE || image->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP || image->GetFormat() == ImageFormat::REMOTE_IMAGE_DXGI_TEXTURE || image->GetFormat() == ImageFormat::D3D9_RGB32_TEXTURE) { NS_ASSERTION(image->GetFormat() != ImageFormat::CAIRO_SURFACE || !static_cast<CairoImage*>(image)->mSurface || static_cast<CairoImage*>(image)->mSurface->GetContentType() != gfxASurface::CONTENT_ALPHA, "Image layer has alpha image"); bool hasAlpha = false; nsRefPtr<ID3D10ShaderResourceView> srView = GetImageSRView(image, hasAlpha, getter_AddRefs(keyedMutex)); if (!srView) { return; } uint8_t shaderFlags = SHADER_PREMUL; shaderFlags |= LoadMaskTexture(); shaderFlags |= hasAlpha ? SHADER_RGBA : SHADER_RGB; shaderFlags |= mFilter == gfxPattern::FILTER_NEAREST ? SHADER_POINT : SHADER_LINEAR; technique = SelectShader(shaderFlags); effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(srView); effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( ShaderConstantRectD3D10( (float)0, (float)0, (float)size.width, (float)size.height) ); } else if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage *yuvImage = static_cast<PlanarYCbCrImage*>(image); if (!yuvImage->IsValid()) { return; } if (!yuvImage->GetBackendData(mozilla::layers::LAYERS_D3D10)) { AllocateTexturesYCbCr(yuvImage); } PlanarYCbCrD3D10BackendData *data = static_cast<PlanarYCbCrD3D10BackendData*>(yuvImage->GetBackendData(mozilla::layers::LAYERS_D3D10)); if (!data) { return; } nsRefPtr<ID3D10Device> dev; data->mYTexture->GetDevice(getter_AddRefs(dev)); if (dev != device()) { return; } // TODO: At some point we should try to deal with mFilter here, you don't // really want to use point filtering in the case of NEAREST, since that // would also use point filtering for Chroma upsampling. Where most likely // the user would only want point filtering for final RGB image upsampling. technique = SelectShader(SHADER_YCBCR | LoadMaskTexture()); effect()->GetVariableByName("tY")->AsShaderResource()->SetResource(data->mYView); effect()->GetVariableByName("tCb")->AsShaderResource()->SetResource(data->mCbView); effect()->GetVariableByName("tCr")->AsShaderResource()->SetResource(data->mCrView); effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector( ShaderConstantRectD3D10( (float)0, (float)0, (float)size.width, (float)size.height) ); effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector( ShaderConstantRectD3D10( (float)yuvImage->GetData()->mPicX / yuvImage->GetData()->mYSize.width, (float)yuvImage->GetData()->mPicY / yuvImage->GetData()->mYSize.height, (float)yuvImage->GetData()->mPicSize.width / yuvImage->GetData()->mYSize.width, (float)yuvImage->GetData()->mPicSize.height / yuvImage->GetData()->mYSize.height) ); } bool resetTexCoords = image->GetFormat() == ImageFormat::PLANAR_YCBCR; image = nullptr; autoLock.Unlock(); technique->GetPassByIndex(0)->Apply(0); device()->Draw(4, 0); if (keyedMutex) { keyedMutex->ReleaseSync(0); } if (resetTexCoords) { effect()->GetVariableByName("vTextureCoords")->AsVector()-> SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f)); } GetContainer()->NotifyPaintedImage(image); }