bool
BufferTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
{
  if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) {
    return false;
  }
  const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();

  uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
  RefPtr<gfx::DataSourceSurface> surface =
    gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(), stride,
                                                  rgb.size(), rgb.format());

  if (!surface) {
    gfxCriticalError() << "Failed to get serializer as surface!";
    return false;
  }

  RefPtr<gfx::DataSourceSurface> srcSurf = aSurface->GetDataSurface();

  if (!srcSurf) {
    gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (BT).";
    return false;
  }

  if (surface->GetSize() != srcSurf->GetSize() || surface->GetFormat() != srcSurf->GetFormat()) {
    gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format (BT)! This: " << surface->GetSize() << " " << surface->GetFormat() << " Other: " << aSurface->GetSize() << " " << aSurface->GetFormat();
    return false;
  }

  gfx::DataSourceSurface::MappedSurface sourceMap;
  gfx::DataSourceSurface::MappedSurface destMap;
  if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) {
    gfxCriticalError() << "Failed to map source surface for UpdateFromSurface (BT).";
    return false;
  }

  if (!surface->Map(gfx::DataSourceSurface::WRITE, &destMap)) {
    srcSurf->Unmap();
    gfxCriticalError() << "Failed to map destination surface for UpdateFromSurface.";
    return false;
  }


  for (int y = 0; y < srcSurf->GetSize().height; y++) {
    memcpy(destMap.mData + destMap.mStride * y,
           sourceMap.mData + sourceMap.mStride * y,
           srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
  }

  srcSurf->Unmap();
  surface->Unmap();

  return true;
}
Example #2
0
static already_AddRefed<layers::Image>
CreateImageFromRawData(const gfx::IntSize& aSize,
                       uint32_t aStride,
                       gfx::SurfaceFormat aFormat,
                       uint8_t* aBuffer,
                       uint32_t aBufferLength,
                       const Maybe<IntRect>& aCropRect)
{
  MOZ_ASSERT(NS_IsMainThread());

  // Copy and crop the source buffer into a SourceSurface.
  RefPtr<SourceSurface> rgbaSurface =
    CreateSurfaceFromRawData(aSize, aStride, aFormat,
                             aBuffer, aBufferLength,
                             aCropRect);

  if (NS_WARN_IF(!rgbaSurface)) {
    return nullptr;
  }

  // Convert RGBA to BGRA
  RefPtr<DataSourceSurface> rgbaDataSurface = rgbaSurface->GetDataSurface();
  RefPtr<DataSourceSurface> bgraDataSurface =
    Factory::CreateDataSourceSurfaceWithStride(rgbaDataSurface->GetSize(),
                                               SurfaceFormat::B8G8R8A8,
                                               rgbaDataSurface->Stride());

  DataSourceSurface::MappedSurface rgbaMap;
  DataSourceSurface::MappedSurface bgraMap;

  if (NS_WARN_IF(!rgbaDataSurface->Map(DataSourceSurface::MapType::READ, &rgbaMap)) ||
      NS_WARN_IF(!bgraDataSurface->Map(DataSourceSurface::MapType::WRITE, &bgraMap))) {
    return nullptr;
  }

  libyuv::ABGRToARGB(rgbaMap.mData, rgbaMap.mStride,
                     bgraMap.mData, bgraMap.mStride,
                     bgraDataSurface->GetSize().width,
                     bgraDataSurface->GetSize().height);

  rgbaDataSurface->Unmap();
  bgraDataSurface->Unmap();

  // Create an Image from the BGRA SourceSurface.
  RefPtr<layers::Image> image = CreateImageFromSurface(bgraDataSurface);

  if (NS_WARN_IF(!image)) {
    return nullptr;
  }

  return image.forget();
}
Example #3
0
static already_AddRefed<SharedMemory>
ReadSegment(const IPC::Message& aDescriptor, Shmem::id_t* aId, size_t* aNBytes, size_t aExtraSize)
{
  if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) {
    NS_ERROR("expected 'shmem created' message");
    return nullptr;
  }
  SharedMemory::SharedMemoryType type;
  PickleIterator iter(aDescriptor);
  if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, aNBytes, &type)) {
    return nullptr;
  }
  RefPtr<SharedMemory> segment = NewSegment(type);
  if (!segment) {
    return nullptr;
  }
  if (!segment->ReadHandle(&aDescriptor, &iter)) {
    NS_ERROR("trying to open invalid handle");
    return nullptr;
  }
  aDescriptor.EndRead(iter);
  size_t size = SharedMemory::PageAlignedSize(*aNBytes + aExtraSize);
  if (!segment->Map(size)) {
    return nullptr;
  }
  // close the handle to the segment after it is mapped
  segment->CloseHandle();
  return segment.forget();
}
Example #4
0
bool
MemoryDIBTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
{
  RefPtr<gfxImageSurface> imgSurf = mSurface->GetAsImageSurface();

  RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();

  if (!srcSurf) {
    gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (DIB).";
    return false;
  }

  DataSourceSurface::MappedSurface sourceMap;
  if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) {
    gfxCriticalError() << "Failed to map source surface for UpdateFromSurface.";
    return false;
  }

  for (int y = 0; y < srcSurf->GetSize().height; y++) {
    memcpy(imgSurf->Data() + imgSurf->Stride() * y,
           sourceMap.mData + sourceMap.mStride * y,
           srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
  }

  srcSurf->Unmap();
  return true;
}
TemporaryRef<gfx::SourceSurface>
MacIOSurfaceImage::GetAsSourceSurface()
{
  mSurface->Lock();
  size_t bytesPerRow = mSurface->GetBytesPerRow();
  size_t ioWidth = mSurface->GetDevicePixelWidth();
  size_t ioHeight = mSurface->GetDevicePixelHeight();

  unsigned char* ioData = (unsigned char*)mSurface->GetBaseAddress();

  RefPtr<gfx::DataSourceSurface> dataSurface
    = gfx::Factory::CreateDataSourceSurface(gfx::IntSize(ioWidth, ioHeight), gfx::SurfaceFormat::B8G8R8A8);
  if (NS_WARN_IF(!dataSurface)) {
    return nullptr;
  }

  gfx::DataSourceSurface::MappedSurface mappedSurface;
  if (!dataSurface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface))
    return nullptr;

  for (size_t i = 0; i < ioHeight; ++i) {
    memcpy(mappedSurface.mData + i * mappedSurface.mStride,
           ioData + i * bytesPerRow,
           ioWidth * 4);
  }

  dataSurface->Unmap();
  mSurface->Unlock();

  return dataSurface;
}
Example #6
0
TemporaryRef<SourceSurface>
DrawTargetSkia::OptimizeSourceSurface(SourceSurface *aSurface) const
{
  if (aSurface->GetType() == SurfaceType::SKIA) {
    return aSurface;
  }

  if (!UsingSkiaGPU()) {
    // If we're not using skia-gl then drawing doesn't require any
    // uploading, so any data surface is fine. Call GetDataSurface
    // to trigger any required readback so that it only happens
    // once.
    return aSurface->GetDataSurface();
  }

  // If we are using skia-gl then we want to copy into a surface that
  // will cache the uploaded gl texture.
  RefPtr<DataSourceSurface> dataSurf = aSurface->GetDataSurface();
  DataSourceSurface::MappedSurface map;
  if (!dataSurf->Map(DataSourceSurface::READ, &map)) {
    return nullptr;
  }

  RefPtr<SourceSurface> result = CreateSourceSurfaceFromData(map.mData,
                                                             dataSurf->GetSize(),
                                                             map.mStride,
                                                             dataSurf->GetFormat());
  dataSurf->Unmap();
  return result.forget();
}
Example #7
0
TemporaryRef<SourceSurface>
DrawTargetD2D1::OptimizeSourceSurface(SourceSurface* aSurface) const
{
  if (aSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
    return aSurface;
  }

  RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();

  DataSourceSurface::MappedSurface map;
  if (!data->Map(DataSourceSurface::MapType::READ, &map)) {
    return nullptr;
  }

  RefPtr<ID2D1Bitmap1> bitmap;
  HRESULT hr = mDC->CreateBitmap(D2DIntSize(data->GetSize()), map.mData, map.mStride,
                                 D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(data->GetFormat())),
                                 byRef(bitmap));

  data->Unmap();

  if (!bitmap) {
    return data;
  }

  return new SourceSurfaceD2D1(bitmap.get(), mDC, data->GetFormat(), data->GetSize());
}
Example #8
0
NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer,
                                          const nsACString& aMimeType,
                                          int32_t aScaledWidth,
                                          int32_t aScaledHeight,
                                          const nsAString& aOutputOptions,
                                          nsIInputStream **aStream)
{
  NS_ENSURE_ARG(aScaledWidth >= 0 && aScaledHeight >= 0);

  // If no scaled size is specified, we'll just encode the image at its
  // original size (no scaling).
  if (aScaledWidth == 0 && aScaledHeight == 0) {
    return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
  }

  // Use frame 0 from the image container.
  RefPtr<SourceSurface> frame =
    aContainer->GetFrame(imgIContainer::FRAME_FIRST,
                         imgIContainer::FLAG_SYNC_DECODE);
  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);

  int32_t frameWidth = frame->GetSize().width;
  int32_t frameHeight = frame->GetSize().height;

  // If the given width or height is zero we'll replace it with the image's
  // original dimensions.
  if (aScaledWidth == 0) {
    aScaledWidth = frameWidth;
  } else if (aScaledHeight == 0) {
    aScaledHeight = frameHeight;
  }

  RefPtr<DataSourceSurface> dataSurface =
    Factory::CreateDataSourceSurface(IntSize(aScaledWidth, aScaledHeight),
                                     SurfaceFormat::B8G8R8A8);
  if (NS_WARN_IF(!dataSurface)) {
    return NS_ERROR_FAILURE;
  }

  DataSourceSurface::MappedSurface map;
  if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
    return NS_ERROR_FAILURE;
  }

  RefPtr<DrawTarget> dt =
    Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                     map.mData,
                                     dataSurface->GetSize(),
                                     map.mStride,
                                     SurfaceFormat::B8G8R8A8);
  dt->DrawSurface(frame,
                  Rect(0, 0, aScaledWidth, aScaledHeight),
                  Rect(0, 0, frameWidth, frameHeight),
                  DrawSurfaceOptions(),
                  DrawOptions(1.0f, CompositionOp::OP_SOURCE));

  dataSurface->Unmap();

  return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
}
Example #9
0
TemporaryRef<DataSourceSurface>
gfxUtils::UnpremultiplyDataSurface(DataSourceSurface* aSurface)
{
    // Only premultiply ARGB32
    if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) {
        return aSurface;
    }

    DataSourceSurface::MappedSurface map;
    if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
        return nullptr;
    }

    RefPtr<DataSourceSurface> dest = Factory::CreateDataSourceSurfaceWithStride(aSurface->GetSize(),
                                                                                aSurface->GetFormat(),
                                                                                map.mStride);

    DataSourceSurface::MappedSurface destMap;
    if (!dest->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
        aSurface->Unmap();
        return nullptr;
    }

    uint8_t *src = map.mData;
    uint8_t *dst = destMap.mData;

    for (int32_t i = 0; i < aSurface->GetSize().height; ++i) {
        uint8_t *srcRow = src + (i * map.mStride);
        uint8_t *dstRow = dst + (i * destMap.mStride);

        for (int32_t j = 0; j < aSurface->GetSize().width; ++j) {
#ifdef IS_LITTLE_ENDIAN
          uint8_t b = *srcRow++;
          uint8_t g = *srcRow++;
          uint8_t r = *srcRow++;
          uint8_t a = *srcRow++;

          *dstRow++ = UnpremultiplyValue(a, b);
          *dstRow++ = UnpremultiplyValue(a, g);
          *dstRow++ = UnpremultiplyValue(a, r);
          *dstRow++ = a;
#else
          uint8_t a = *srcRow++;
          uint8_t r = *srcRow++;
          uint8_t g = *srcRow++;
          uint8_t b = *srcRow++;

          *dstRow++ = a;
          *dstRow++ = UnpremultiplyValue(a, r);
          *dstRow++ = UnpremultiplyValue(a, g);
          *dstRow++ = UnpremultiplyValue(a, b);
#endif
        }
    }

    aSurface->Unmap();
    dest->Unmap();
    return dest;
}
Example #10
0
GdkPixbuf*
nsImageToPixbuf::SourceSurfaceToPixbuf(SourceSurface* aSurface,
                                       int32_t aWidth,
                                       int32_t aHeight)
{
    MOZ_ASSERT(aWidth <= aSurface->GetSize().width &&
               aHeight <= aSurface->GetSize().height,
               "Requested rect is bigger than the supplied surface");

    GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
                                       aWidth, aHeight);
    if (!pixbuf)
        return nullptr;

    uint32_t destStride = gdk_pixbuf_get_rowstride (pixbuf);
    guchar* destPixels = gdk_pixbuf_get_pixels (pixbuf);

    RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
    DataSourceSurface::MappedSurface map;
    if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map))
        return nullptr;

    uint8_t* srcData = map.mData;
    int32_t srcStride = map.mStride;

    SurfaceFormat format = dataSurface->GetFormat();

    for (int32_t row = 0; row < aHeight; ++row) {
        for (int32_t col = 0; col < aWidth; ++col) {
            guchar* destPixel = destPixels + row * destStride + 4 * col;

            uint32_t* srcPixel =
                reinterpret_cast<uint32_t*>((srcData + row * srcStride + 4 * col));

            if (format == SurfaceFormat::B8G8R8A8) {
                const uint8_t a = (*srcPixel >> 24) & 0xFF;
                const uint8_t r = unpremultiply((*srcPixel >> 16) & 0xFF, a);
                const uint8_t g = unpremultiply((*srcPixel >>  8) & 0xFF, a);
                const uint8_t b = unpremultiply((*srcPixel >>  0) & 0xFF, a);

                *destPixel++ = r;
                *destPixel++ = g;
                *destPixel++ = b;
                *destPixel++ = a;
            } else {
                MOZ_ASSERT(format == SurfaceFormat::B8G8R8X8);

                const uint8_t r = (*srcPixel >> 16) & 0xFF;
                const uint8_t g = (*srcPixel >>  8) & 0xFF;
                const uint8_t b = (*srcPixel >>  0) & 0xFF;

                *destPixel++ = r;
                *destPixel++ = g;
                *destPixel++ = b;
                *destPixel++ = 0xFF; // A
            }
        }
    }
Example #11
0
void
TextureClientD3D11::UpdateFromSurface(gfx::SourceSurface* aSurface)
{
  RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();

  if (!srcSurf) {
    gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface.";
    return;
  }

  if (mDrawTarget) {
    // Ensure unflushed work from our outstanding drawtarget won't override this
    // update later.
    mDrawTarget->Flush();
  }

  if (mSize != srcSurf->GetSize() || mFormat != srcSurf->GetFormat()) {
    gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format!";
    return;
  }

  DataSourceSurface::MappedSurface sourceMap;
  if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) {
    gfxCriticalError() << "Failed to map source surface for UpdateFromSurface.";
    return;
  }

  if (mTexture) {
    RefPtr<ID3D11Device> device;
    mTexture->GetDevice(getter_AddRefs(device));
    RefPtr<ID3D11DeviceContext> ctx;
    device->GetImmediateContext(getter_AddRefs(ctx));

    D3D11_BOX box;
    box.front = 0;
    box.back = 1;
    box.top = box.left = 0;
    box.right = aSurface->GetSize().width;
    box.bottom = aSurface->GetSize().height;

    ctx->UpdateSubresource(mTexture, 0, &box, sourceMap.mData, sourceMap.mStride, 0);
  } else {
    RefPtr<ID3D10Device> device;
    mTexture10->GetDevice(getter_AddRefs(device));

    D3D10_BOX box;
    box.front = 0;
    box.back = 1;
    box.top = box.left = 0;
    box.right = aSurface->GetSize().width;
    box.bottom = aSurface->GetSize().height;

    device->UpdateSubresource(mTexture10, 0, &box, sourceMap.mData, sourceMap.mStride, 0);
  }
  srcSurf->Unmap();
}
Example #12
0
static already_AddRefed<SharedMemory>
CreateSegment(SharedMemory::SharedMemoryType aType, size_t aNBytes, size_t aExtraSize)
{
  RefPtr<SharedMemory> segment = NewSegment(aType);
  if (!segment) {
    return nullptr;
  }
  size_t size = SharedMemory::PageAlignedSize(aNBytes + aExtraSize);
  if (!segment->Create(size) || !segment->Map(size)) {
    return nullptr;
  }
  return segment.forget();
}
already_AddRefed<DataSourceSurface>
DataSourceSurfaceFromYCbCrDescriptor(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor, gfx::DataSourceSurface* aSurface)
{
  gfx::IntSize ySize = aDescriptor.ySize();
  gfx::IntSize cbCrSize = aDescriptor.cbCrSize();
  int32_t yStride = ySize.width;
  int32_t cbCrStride = cbCrSize.width;

  RefPtr<DataSourceSurface> result;
  if (aSurface) {
    MOZ_ASSERT(aSurface->GetSize() == ySize);
    MOZ_ASSERT(aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8);
    if (aSurface->GetSize() == ySize &&
        aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8) {
      result = aSurface;
    }
  }

  if (!result) {
    result =
      Factory::CreateDataSourceSurface(ySize, gfx::SurfaceFormat::B8G8R8X8);
  }
  if (NS_WARN_IF(!result)) {
    return nullptr;
  }

  DataSourceSurface::MappedSurface map;
  if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
    return nullptr;
  }

  layers::PlanarYCbCrData ycbcrData;
  ycbcrData.mYChannel     = GetYChannel(aBuffer, aDescriptor);
  ycbcrData.mYStride      = yStride;
  ycbcrData.mYSize        = ySize;
  ycbcrData.mCbChannel    = GetCbChannel(aBuffer, aDescriptor);
  ycbcrData.mCrChannel    = GetCrChannel(aBuffer, aDescriptor);
  ycbcrData.mCbCrStride   = cbCrStride;
  ycbcrData.mCbCrSize     = cbCrSize;
  ycbcrData.mPicSize      = ySize;
  ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();

  gfx::ConvertYCbCrToRGB(ycbcrData,
                         gfx::SurfaceFormat::B8G8R8X8,
                         ySize,
                         map.mData,
                         map.mStride);

  result->Unmap();
  return result.forget();
}
Example #14
0
HRESULT
D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
                               const nsIntRect& aRegion,
                               ImageContainer* aContainer,
                               Image** aOutImage)
{
  NS_ENSURE_TRUE(aVideoSample, E_POINTER);
  NS_ENSURE_TRUE(aContainer, E_POINTER);
  NS_ENSURE_TRUE(aOutImage, E_POINTER);

  // Our video frame is stored in a non-sharable ID3D11Texture2D. We need
  // to create a copy of that frame as a sharable resource, save its share
  // handle, and put that handle into the rendering pipeline.

  RefPtr<D3D11ShareHandleImage> image =
    new D3D11ShareHandleImage(gfx::IntSize(mWidth, mHeight), aRegion);
  bool ok = image->AllocateTexture(mTextureClientAllocator);
  NS_ENSURE_TRUE(ok, E_FAIL);

  HRESULT hr = mTransform->Input(aVideoSample);
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  RefPtr<IMFSample> sample;
  RefPtr<ID3D11Texture2D> texture = image->GetTexture();
  hr = CreateOutputSample(sample, texture);
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  hr = mTransform->Output(&sample);

  RefPtr<ID3D11DeviceContext> ctx;
  mDevice->GetImmediateContext(getter_AddRefs(ctx));

  // Copy a small rect into our sync surface, and then map it
  // to block until decoding/color conversion completes.
  D3D11_BOX rect = { 0, 0, 0, kSyncSurfaceSize, kSyncSurfaceSize, 1 };
  ctx->CopySubresourceRegion(mSyncSurface, 0, 0, 0, 0, texture, 0, &rect);

  D3D11_MAPPED_SUBRESOURCE mapped;
  hr = ctx->Map(mSyncSurface, 0, D3D11_MAP_READ, 0, &mapped);
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  ctx->Unmap(mSyncSurface, 0);

  image.forget(aOutImage);

  return S_OK;
}
Example #15
0
TemporaryRef<gfx::SourceSurface>
GrallocImage::GetAsSourceSurface()
{
  if (!mTextureClient) {
    return nullptr;
  }

  android::sp<GraphicBuffer> graphicBuffer =
    mTextureClient->GetGraphicBuffer();

  RefPtr<gfx::DataSourceSurface> surface =
    gfx::Factory::CreateDataSourceSurface(GetSize(), gfx::SurfaceFormat::R5G6B5);
  if (NS_WARN_IF(!surface)) {
    return nullptr;
  }

  gfx::DataSourceSurface::MappedSurface mappedSurface;
  if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
    NS_WARNING("Could not map DataSourceSurface");
    return nullptr;
  }

  int32_t rv;
  uint32_t omxFormat = 0;

  omxFormat = GrallocImage::GetOmxFormat(graphicBuffer->getPixelFormat());
  if (!omxFormat) {
    rv = ConvertVendorYUVFormatToRGB565(graphicBuffer, surface, &mappedSurface);
    surface->Unmap();

    if (rv != OK) {
      NS_WARNING("Unknown color format");
      return nullptr;
    }

    return surface;
  }

  rv = ConvertOmxYUVFormatToRGB565(graphicBuffer, surface, &mappedSurface, mData, omxFormat);
  surface->Unmap();

  if (rv != OK) {
    return nullptr;
  }

  return surface;
}
Example #16
0
void
WebGLContext::GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat)
{
    *aImageBuffer = nullptr;
    *aFormat = 0;

    // Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied
    bool premult;
    RefPtr<SourceSurface> snapshot =
      GetSurfaceSnapshot(mOptions.premultipliedAlpha ? nullptr : &premult);
    if (!snapshot) {
        return;
    }
    MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!");

    RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();

    DataSourceSurface::MappedSurface map;
    if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
        return;
    }

    static const fallible_t fallible = fallible_t();
    uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
    if (!imageBuffer) {
        dataSurface->Unmap();
        return;
    }
    memcpy(imageBuffer, map.mData, mWidth * mHeight * 4);

    dataSurface->Unmap();

    int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
    if (!mOptions.premultipliedAlpha) {
        // We need to convert to INPUT_FORMAT_RGBA, otherwise
        // we are automatically considered premult, and unpremult'd.
        // Yes, it is THAT silly.
        // Except for different lossy conversions by color,
        // we could probably just change the label, and not change the data.
        gfxUtils::ConvertBGRAtoRGBA(imageBuffer, mWidth * mHeight * 4);
        format = imgIEncoder::INPUT_FORMAT_RGBA;
    }

    *aImageBuffer = imageBuffer;
    *aFormat = format;
}
TemporaryRef<DataSourceSurface>
YCbCrImageDataDeserializer::ToDataSourceSurface()
{
  RefPtr<DataSourceSurface> result =
    Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8);

  DataSourceSurface::MappedSurface map;
  result->Map(DataSourceSurface::MapType::WRITE, &map);

  gfx::ConvertYCbCrToRGB32(GetYData(), GetCbData(), GetCrData(),
                           map.mData,
                           0, 0, //pic x and y
                           GetYSize().width, GetYSize().height,
                           GetYStride(), GetCbCrStride(),
                           map.mStride,
                           gfx::YV12);
  result->Unmap();
  return result.forget();
}
Example #18
0
static already_AddRefed<IDirect3DTexture9>
SurfaceToTexture(IDirect3DDevice9 *aDevice,
                 SourceSurface *aSurface,
                 const IntSize &aSize)
{
  RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
  if (!dataSurface) {
    return nullptr;
  }
  DataSourceSurface::MappedSurface map;
  if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
    return nullptr;
  }
  nsRefPtr<IDirect3DTexture9> texture =
    DataToTexture(aDevice, map.mData, map.mStride, aSize,
                  D3dFormatForSurfaceFormat(dataSurface->GetFormat()));
  dataSurface->Unmap();
  return texture.forget();
}
bool
GrallocTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
{
  MOZ_ASSERT(mMappedBuffer, "Calling TextureClient::BorrowDrawTarget without locking :(");

  if (!mMappedBuffer) {
    return false;
  }

  RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();

  if (!srcSurf) {
    gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (GTC).";
    return false;
  }

  gfx::SurfaceFormat format = SurfaceFormatForPixelFormat(mGraphicBuffer->getPixelFormat());
  if (mSize != srcSurf->GetSize() || mFormat != srcSurf->GetFormat()) {
    gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << mSize << " " << format << " Other: " << srcSurf->GetSize() << " " << srcSurf->GetFormat();
    return false;
  }

  long pixelStride = mGraphicBuffer->getStride();
  long byteStride = pixelStride * BytesPerPixel(format);

  DataSourceSurface::MappedSurface sourceMap;

  if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) {
    gfxCriticalError() << "Failed to map source surface for UpdateFromSurface (GTC).";
    return false;
  }

  for (int y = 0; y < srcSurf->GetSize().height; y++) {
    memcpy(mMappedBuffer + byteStride * y,
           sourceMap.mData + sourceMap.mStride * y,
           srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
  }

  srcSurf->Unmap();

  return true;
}
Example #20
0
static bool
MapSrcAndCreateMappedDest(DataSourceSurface* srcSurf,
                          RefPtr<DataSourceSurface>* out_destSurf,
                          DataSourceSurface::MappedSurface* out_srcMap,
                          DataSourceSurface::MappedSurface* out_destMap)
{
    MOZ_ASSERT(srcSurf);
    MOZ_ASSERT(out_destSurf && out_srcMap && out_destMap);

    if (srcSurf->GetFormat() != SurfaceFormat::B8G8R8A8) {
        MOZ_ASSERT(false, "Only operate on BGRA8.");
        return false;
    }

    // Ok, map source for reading.
    DataSourceSurface::MappedSurface srcMap;
    if (!srcSurf->Map(DataSourceSurface::MapType::READ, &srcMap)) {
        MOZ_ASSERT(false, "Couldn't Map srcSurf.");
        return false;
    }

    // Make our dest surface based on the src.
    RefPtr<DataSourceSurface> destSurf =
        Factory::CreateDataSourceSurfaceWithStride(srcSurf->GetSize(),
                                                   srcSurf->GetFormat(),
                                                   srcMap.mStride);
    if (NS_WARN_IF(!destSurf)) {
        return false;
    }

    DataSourceSurface::MappedSurface destMap;
    if (!destSurf->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
        MOZ_ASSERT(false, "Couldn't Map destSurf.");
        srcSurf->Unmap();
        return false;
    }

    *out_destSurf = destSurf;
    *out_srcMap = srcMap;
    *out_destMap = destMap;
    return true;
}
Example #21
0
bool
ShmemDIBTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
{

  RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();

  if (!srcSurf) {
    gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (DTD).";
    return false;
  }

  DataSourceSurface::MappedSurface sourceMap;
  if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) {
    gfxCriticalError() << "Failed to map source surface for UpdateFromSurface.";
    return false;
  }

  GdiFlush();

  uint32_t stride = mSize.width * BytesPerPixel(mFormat);
  uint8_t* data = (uint8_t*)::MapViewOfFile(mFileMapping, FILE_MAP_WRITE, 0, 0, stride * mSize.height);

  if (!data) {
    gfxCriticalError() << "Failed to map view of file for UpdateFromSurface.";
    srcSurf->Unmap();
    return false;
  }

  for (int y = 0; y < srcSurf->GetSize().height; y++) {
    memcpy(data + stride * y,
           sourceMap.mData + sourceMap.mStride * y,
           srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()));
  }

  ::UnmapViewOfFile(data);

  srcSurf->Unmap();
  return true;
}
already_AddRefed<DataSourceSurface>
YCbCrImageDataDeserializer::ToDataSourceSurface()
{
    RefPtr<DataSourceSurface> result =
        Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8);
    if (NS_WARN_IF(!result)) {
        return nullptr;
    }

    DataSourceSurface::MappedSurface map;
    if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
        return nullptr;
    }

    gfx::ConvertYCbCrToRGB32(GetYData(), GetCbData(), GetCrData(),
                             map.mData,
                             0, 0, //pic x and y
                             GetYSize().width, GetYSize().height,
                             GetYStride(), GetCbCrStride(),
                             map.mStride,
                             gfx::YV12);
    result->Unmap();
    return result.forget();
}
Example #23
0
/* static */
nsresult
ImageEncoder::ExtractDataInternal(const nsAString& aType,
                                  const nsAString& aOptions,
                                  uint8_t* aImageBuffer,
                                  int32_t aFormat,
                                  const nsIntSize aSize,
                                  layers::Image* aImage,
                                  nsICanvasRenderingContextInternal* aContext,
                                  nsIInputStream** aStream,
                                  imgIEncoder* aEncoder)
{
  if (aSize.IsEmpty()) {
    return NS_ERROR_INVALID_ARG;
  }

  nsCOMPtr<nsIInputStream> imgStream;

  // get image bytes
  nsresult rv;
  if (aImageBuffer) {
    rv = ImageEncoder::GetInputStream(
      aSize.width,
      aSize.height,
      aImageBuffer,
      aFormat,
      aEncoder,
      nsPromiseFlatString(aOptions).get(),
      getter_AddRefs(imgStream));
  } else if (aContext) {
    NS_ConvertUTF16toUTF8 encoderType(aType);
    rv = aContext->GetInputStream(encoderType.get(),
                                  nsPromiseFlatString(aOptions).get(),
                                  getter_AddRefs(imgStream));
  } else if (aImage) {
    // It is safe to convert PlanarYCbCr format from YUV to RGB off-main-thread.
    // Other image formats could have problem to convert format off-main-thread.
    // So here it uses a help function GetBRGADataSourceSurfaceSync() to convert
    // format on main thread.
    if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
      nsTArray<uint8_t> data;
      layers::PlanarYCbCrImage* ycbcrImage = static_cast<layers::PlanarYCbCrImage*> (aImage);
      gfxImageFormat format = gfxImageFormat::ARGB32;
      uint32_t stride = GetAlignedStride<16>(aSize.width * 4);
      size_t length = BufferSizeFromStrideAndHeight(stride, aSize.height);
      data.SetCapacity(length);

      gfxUtils::ConvertYCbCrToRGB(*ycbcrImage->GetData(),
                                  format,
                                  aSize,
                                  data.Elements(),
                                  stride);

      rv = aEncoder->InitFromData(data.Elements(),
                                  aSize.width * aSize.height * 4,
                                  aSize.width,
                                  aSize.height,
                                  aSize.width * 4,
                                  imgIEncoder::INPUT_FORMAT_HOSTARGB,
                                  aOptions);
    } else {
      RefPtr<gfx::DataSourceSurface> dataSurface;
      dataSurface = GetBRGADataSourceSurfaceSync(aImage);

      DataSourceSurface::MappedSurface map;
      if (!dataSurface->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
        return NS_ERROR_INVALID_ARG;
      }
      rv = aEncoder->InitFromData(map.mData,
                                  aSize.width * aSize.height * 4,
                                  aSize.width,
                                  aSize.height,
                                  aSize.width * 4,
                                  imgIEncoder::INPUT_FORMAT_HOSTARGB,
                                  aOptions);
      dataSurface->Unmap();
    }

    if (NS_SUCCEEDED(rv)) {
      imgStream = do_QueryInterface(aEncoder);
    }
  } else {
    // no context, so we have to encode an empty image
    // note that if we didn't have a current context, the spec says we're
    // supposed to just return transparent black pixels of the canvas
    // dimensions.
    RefPtr<DataSourceSurface> emptyCanvas =
      Factory::CreateDataSourceSurfaceWithStride(IntSize(aSize.width, aSize.height),
                                                 SurfaceFormat::B8G8R8A8,
                                                 4 * aSize.width, true);
    if (NS_WARN_IF(!emptyCanvas)) {
      return NS_ERROR_INVALID_ARG;
    }

    DataSourceSurface::MappedSurface map;
    if (!emptyCanvas->Map(DataSourceSurface::MapType::WRITE, &map)) {
      return NS_ERROR_INVALID_ARG;
    }
    rv = aEncoder->InitFromData(map.mData,
                                aSize.width * aSize.height * 4,
                                aSize.width,
                                aSize.height,
                                aSize.width * 4,
                                imgIEncoder::INPUT_FORMAT_HOSTARGB,
                                aOptions);
    emptyCanvas->Unmap();
    if (NS_SUCCEEDED(rv)) {
      imgStream = do_QueryInterface(aEncoder);
    }
  }
  NS_ENSURE_SUCCESS(rv, rv);

  imgStream.forget(aStream);
  return rv;
}
Example #24
0
TemporaryRef<gfx::SourceSurface>
GrallocImage::GetAsSourceSurface()
{
  if (!mTextureClient) {
    return nullptr;
  }
  android::sp<GraphicBuffer> graphicBuffer =
    mTextureClient->GetGraphicBuffer();

  void *buffer;
  int32_t rv =
    graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_OFTEN, &buffer);

  if (rv) {
    NS_WARNING("Couldn't lock graphic buffer");
    return nullptr;
  }

  GraphicBufferAutoUnlock unlock(graphicBuffer);

  uint32_t format = graphicBuffer->getPixelFormat();
  uint32_t omxFormat = 0;

  for (int i = 0; sColorIdMap[i]; i += 2) {
    if (sColorIdMap[i] == format) {
      omxFormat = sColorIdMap[i + 1];
      break;
    }
  }

  if (!omxFormat) {
    NS_WARNING("Unknown color format");
    return nullptr;
  }

  RefPtr<gfx::DataSourceSurface> surface
    = gfx::Factory::CreateDataSourceSurface(GetSize(), gfx::SurfaceFormat::R5G6B5);
  if (!surface) {
    NS_WARNING("Failed to create SourceSurface.");
    return nullptr;
  }

  uint32_t width = GetSize().width;
  uint32_t height = GetSize().height;

  gfx::DataSourceSurface::MappedSurface mappedSurface;
  if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
    NS_WARNING("Could not map DataSourceSurface");
    return nullptr;
  }

  if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO) {
    // The Adreno hardware decoder aligns image dimensions to a multiple of 32,
    // so we have to account for that here
    uint32_t alignedWidth = ALIGN(width, 32);
    uint32_t alignedHeight = ALIGN(height, 32);
    uint32_t uvOffset = ALIGN(alignedHeight * alignedWidth, 4096);
    uint32_t uvStride = 2 * ALIGN(width / 2, 32);
    uint8_t* buffer_as_bytes = static_cast<uint8_t*>(buffer);
    ConvertYVU420SPToRGB565(buffer, alignedWidth,
                            buffer_as_bytes + uvOffset, uvStride,
                            mappedSurface.mData,
                            width, height);

    surface->Unmap();
    return surface;
  }

  if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
    uint32_t uvOffset = height * width;
    ConvertYVU420SPToRGB565(buffer, width,
                            buffer + uvOffset, width,
                            mappedSurface.mData,
                            width, height);

    surface->Unmap();
    return surface;
  }

  if (format == HAL_PIXEL_FORMAT_YV12) {
    gfx::ConvertYCbCrToRGB(mData,
                           surface->GetFormat(),
                           mSize,
                           surface->GetData(),
                           surface->Stride());
    surface->Unmap();
    return surface;
  }

  android::ColorConverter colorConverter((OMX_COLOR_FORMATTYPE)omxFormat,
                                         OMX_COLOR_Format16bitRGB565);

  if (!colorConverter.isValid()) {
    NS_WARNING("Invalid color conversion");
    surface->Unmap();
    return nullptr;
  }

  rv = colorConverter.convert(buffer, width, height,
                              0, 0, width - 1, height - 1 /* source crop */,
                              mappedSurface.mData, width, height,
                              0, 0, width - 1, height - 1 /* dest crop */);

  surface->Unmap();

  if (rv) {
    NS_WARNING("OMX color conversion failed");
    return nullptr;
  }

  return surface;
}
Example #25
0
NS_IMETHODIMP
imgTools::EncodeCroppedImage(imgIContainer* aContainer,
                             const nsACString& aMimeType,
                             int32_t aOffsetX,
                             int32_t aOffsetY,
                             int32_t aWidth,
                             int32_t aHeight,
                             const nsAString& aOutputOptions,
                             nsIInputStream** aStream)
{
  NS_ENSURE_ARG(aOffsetX >= 0 && aOffsetY >= 0 && aWidth >= 0 && aHeight >= 0);

  // Offsets must be zero when no width and height are given or else we're out
  // of bounds.
  NS_ENSURE_ARG(aWidth + aHeight > 0 || aOffsetX + aOffsetY == 0);

  // If no size is specified then we'll preserve the image's original dimensions
  // and don't need to crop.
  if (aWidth == 0 && aHeight == 0) {
    return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
  }

  // Use frame 0 from the image container.
  RefPtr<SourceSurface> frame =
    aContainer->GetFrame(imgIContainer::FRAME_FIRST,
                         imgIContainer::FLAG_SYNC_DECODE);
  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);

  int32_t frameWidth = frame->GetSize().width;
  int32_t frameHeight = frame->GetSize().height;

  // If the given width or height is zero we'll replace it with the image's
  // original dimensions.
  if (aWidth == 0) {
    aWidth = frameWidth;
  } else if (aHeight == 0) {
    aHeight = frameHeight;
  }

  // Check that the given crop rectangle is within image bounds.
  NS_ENSURE_ARG(frameWidth >= aOffsetX + aWidth &&
                frameHeight >= aOffsetY + aHeight);

  RefPtr<DataSourceSurface> dataSurface =
    Factory::CreateDataSourceSurface(IntSize(aWidth, aHeight),
                                     SurfaceFormat::B8G8R8A8,
                                     /* aZero = */ true);
  if (NS_WARN_IF(!dataSurface)) {
    return NS_ERROR_FAILURE;
  }

  DataSourceSurface::MappedSurface map;
  if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
    return NS_ERROR_FAILURE;
  }

  RefPtr<DrawTarget> dt =
    Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                     map.mData,
                                     dataSurface->GetSize(),
                                     map.mStride,
                                     SurfaceFormat::B8G8R8A8);
  if (!dt) {
    gfxWarning() <<
      "imgTools::EncodeCroppedImage failed in CreateDrawTargetForData";
    return NS_ERROR_OUT_OF_MEMORY;
  }
  dt->CopySurface(frame,
                  IntRect(aOffsetX, aOffsetY, aWidth, aHeight),
                  IntPoint(0, 0));

  dataSurface->Unmap();

  return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
}
Example #26
0
bool
nsDragService::CreateDragImage(nsIDOMNode *aDOMNode,
                               nsIScriptableRegion *aRegion,
                               SHDRAGIMAGE *psdi)
{
  if (!psdi)
    return false;

  memset(psdi, 0, sizeof(SHDRAGIMAGE));
  if (!aDOMNode)
    return false;

  // Prepare the drag image
  nsIntRect dragRect;
  RefPtr<SourceSurface> surface;
  nsPresContext* pc;
  DrawDrag(aDOMNode, aRegion,
           mScreenX, mScreenY,
           &dragRect, &surface, &pc);
  if (!surface)
    return false;

  uint32_t bmWidth = dragRect.width, bmHeight = dragRect.height;

  if (bmWidth == 0 || bmHeight == 0)
    return false;

  psdi->crColorKey = CLR_NONE;

  RefPtr<DataSourceSurface> dataSurface =
    Factory::CreateDataSourceSurface(IntSize(bmWidth, bmHeight),
                                     SurfaceFormat::B8G8R8A8);
  NS_ENSURE_TRUE(dataSurface, false);

  DataSourceSurface::MappedSurface map;
  if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
    return false;
  }

  RefPtr<DrawTarget> dt =
    Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                     map.mData,
                                     dataSurface->GetSize(),
                                     map.mStride,
                                     dataSurface->GetFormat());
  if (!dt) {
    dataSurface->Unmap();
    return false;
  }

  dt->DrawSurface(surface,
                  Rect(0, 0, dataSurface->GetSize().width, dataSurface->GetSize().height),
                  Rect(0, 0, surface->GetSize().width, surface->GetSize().height),
                  DrawSurfaceOptions(),
                  DrawOptions(1.0f, CompositionOp::OP_SOURCE));
  dt->Flush();

  BITMAPV5HEADER bmih;
  memset((void*)&bmih, 0, sizeof(BITMAPV5HEADER));
  bmih.bV5Size        = sizeof(BITMAPV5HEADER);
  bmih.bV5Width       = bmWidth;
  bmih.bV5Height      = -(int32_t)bmHeight; // flip vertical
  bmih.bV5Planes      = 1;
  bmih.bV5BitCount    = 32;
  bmih.bV5Compression = BI_BITFIELDS;
  bmih.bV5RedMask     = 0x00FF0000;
  bmih.bV5GreenMask   = 0x0000FF00;
  bmih.bV5BlueMask    = 0x000000FF;
  bmih.bV5AlphaMask   = 0xFF000000;

  HDC hdcSrc = CreateCompatibleDC(nullptr);
  void *lpBits = nullptr;
  if (hdcSrc) {
    psdi->hbmpDragImage =
    ::CreateDIBSection(hdcSrc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS,
                       (void**)&lpBits, nullptr, 0);
    if (psdi->hbmpDragImage && lpBits) {
      CopySurfaceDataToPackedArray(map.mData, static_cast<uint8_t*>(lpBits),
                                   dataSurface->GetSize(), map.mStride,
                                   BytesPerPixel(dataSurface->GetFormat()));
    }

    psdi->sizeDragImage.cx = bmWidth;
    psdi->sizeDragImage.cy = bmHeight;

    // Mouse position in center
    if (mScreenX == -1 || mScreenY == -1) {
      psdi->ptOffset.x = (uint32_t)((float)bmWidth/2.0f);
      psdi->ptOffset.y = (uint32_t)((float)bmHeight/2.0f);
    } else {
      int32_t sx = mScreenX, sy = mScreenY;
      ConvertToUnscaledDevPixels(pc, &sx, &sy);
      psdi->ptOffset.x = sx - dragRect.x;
      psdi->ptOffset.y = sy - dragRect.y;
    }

    DeleteDC(hdcSrc);
  }

  dataSurface->Unmap();

  return psdi->hbmpDragImage != nullptr;
}
already_AddRefed<gfx::SourceSurface>
D3D11ShareHandleImage::GetAsSourceSurface()
{
  RefPtr<ID3D11Texture2D> texture = GetTexture();
  if (!texture) {
    gfxWarning() << "Cannot readback from shared texture because no texture is available.";
    return nullptr;
  }

  RefPtr<ID3D11Device> device;
  texture->GetDevice(getter_AddRefs(device));

  D3D11_TEXTURE2D_DESC desc;
  texture->GetDesc(&desc);

  HRESULT hr;

  if (desc.Format == DXGI_FORMAT_NV12) {
    nsAutoCString error;
    std::unique_ptr<DXVA2Manager> manager(DXVA2Manager::CreateD3D11DXVA(nullptr, error, device));

    if (!manager) {
      gfxWarning() << "Failed to create DXVA2 manager!";
      return nullptr;
    }

    RefPtr<ID3D11Texture2D> outTexture;

    hr = manager->CopyToBGRATexture(texture, getter_AddRefs(outTexture));

    if (FAILED(hr)) {
      gfxWarning() << "Failed to copy NV12 to BGRA texture.";
      return nullptr;
    }

    texture = outTexture;
    texture->GetDesc(&desc);
  }

  CD3D11_TEXTURE2D_DESC softDesc(desc.Format, desc.Width, desc.Height);
  softDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
  softDesc.BindFlags = 0;
  softDesc.MiscFlags = 0;
  softDesc.MipLevels = 1;
  softDesc.Usage = D3D11_USAGE_STAGING;

  RefPtr<ID3D11Texture2D> softTexture;
  hr = device->CreateTexture2D(&softDesc,
                                       NULL,
                                       static_cast<ID3D11Texture2D**>(getter_AddRefs(softTexture)));

  if (FAILED(hr)) {
    NS_WARNING("Failed to create 2D staging texture.");
    return nullptr;
  }

  RefPtr<ID3D11DeviceContext> context;
  device->GetImmediateContext(getter_AddRefs(context));
  if (!context) {
    return nullptr;
  }

  RefPtr<IDXGIKeyedMutex> mutex;
  hr = texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));

  if (SUCCEEDED(hr) && mutex) {
    hr = mutex->AcquireSync(0, 2000);
    if (hr != S_OK) {
      NS_WARNING("Acquire sync didn't manage to return within 2 seconds.");
    }
  }
  context->CopyResource(softTexture, texture);
  if (SUCCEEDED(hr) && mutex) {
    mutex->ReleaseSync(0);
  }

  RefPtr<gfx::DataSourceSurface> surface =
    gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8A8);
  if (NS_WARN_IF(!surface)) {
    return nullptr;
  }

  gfx::DataSourceSurface::MappedSurface mappedSurface;
  if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
    return nullptr;
  }

  D3D11_MAPPED_SUBRESOURCE map;
  hr = context->Map(softTexture, 0, D3D11_MAP_READ, 0, &map);
  if (!SUCCEEDED(hr)) {
    surface->Unmap();
    return nullptr;
  }

  for (int y = 0; y < mSize.height; y++) {
    memcpy(mappedSurface.mData + mappedSurface.mStride * y,
           (unsigned char*)(map.pData) + map.RowPitch * y,
           mSize.width * 4);
  }

  context->Unmap(softTexture, 0);
  surface->Unmap();

  return surface.forget();
}
Example #28
0
void
TextRenderer::RenderText(const string& aText, const IntPoint& aOrigin,
                         const Matrix4x4& aTransform, uint32_t aTextSize,
                         uint32_t aTargetPixelWidth)
{
  EnsureInitialized();

  // For now we only have a bitmap font with a 16px cell size, so we just
  // scale it up if the user wants larger text.
  Float scaleFactor = Float(aTextSize) / Float(sCellHeight);

  aTargetPixelWidth /= scaleFactor;

  uint32_t numLines = 1;
  uint32_t maxWidth = 0;
  uint32_t lineWidth = 0;
  // Calculate the size of the surface needed to draw all the glyphs.
  for (uint32_t i = 0; i < aText.length(); i++) {
    // Insert a line break if we go past the TargetPixelWidth.
    // XXX - this has the downside of overrunning the intended width, causing
    // things at the edge of a window to be cut off.
    if (aText[i] == '\n' || (aText[i] == ' ' && lineWidth > aTargetPixelWidth)) {
      numLines++;
      lineWidth = 0;
      continue;
    }

    lineWidth += sGlyphWidths[uint32_t(aText[i])];
    maxWidth = std::max(lineWidth, maxWidth);
  }

  // Create a surface to draw our glyphs to.
  RefPtr<DataSourceSurface> textSurf =
    Factory::CreateDataSourceSurface(IntSize(maxWidth, numLines * sCellHeight), sTextureFormat);
  if (NS_WARN_IF(!textSurf)) {
    return;
  }

  DataSourceSurface::MappedSurface map;
  if (NS_WARN_IF(!textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map))) {
    return;
  }

  // Initialize the surface to transparent white.
  memset(map.mData, uint8_t(sBackgroundOpacity * 255.0f),
         numLines * sCellHeight * map.mStride);

  uint32_t currentXPos = 0;
  uint32_t currentYPos = 0;

  // Copy our glyphs onto the surface.
  for (uint32_t i = 0; i < aText.length(); i++) {
    if (aText[i] == '\n' || (aText[i] == ' ' && currentXPos > aTargetPixelWidth)) {
      currentYPos += sCellHeight;
      currentXPos = 0;
      continue;
    }

    uint32_t glyphXOffset = aText[i] % (sTextureWidth / sCellWidth) * sCellWidth * BytesPerPixel(sTextureFormat);
    uint32_t truncatedLine = aText[i] / (sTextureWidth / sCellWidth);
    uint32_t glyphYOffset =  truncatedLine * sCellHeight * mMap.mStride;

    for (int y = 0; y < 16; y++) {
      memcpy(map.mData + (y + currentYPos) * map.mStride + currentXPos * BytesPerPixel(sTextureFormat),
             mMap.mData + glyphYOffset + y * mMap.mStride + glyphXOffset,
             sGlyphWidths[uint32_t(aText[i])] * BytesPerPixel(sTextureFormat));
    }

    currentXPos += sGlyphWidths[uint32_t(aText[i])];
  }

  textSurf->Unmap();

  RefPtr<DataTextureSource> src = mCompositor->CreateDataTextureSource();

  if (!src->Update(textSurf)) {
    // Upload failed.
    return;
  }

  RefPtr<EffectRGB> effect = new EffectRGB(src, true, SamplingFilter::LINEAR);
  EffectChain chain;
  chain.mPrimaryEffect = effect;

  Matrix4x4 transform = aTransform;
  transform.PreScale(scaleFactor, scaleFactor, 1.0f);
  mCompositor->DrawQuad(Rect(aOrigin.x, aOrigin.y, maxWidth, numLines * 16),
                        IntRect(-10000, -10000, 20000, 20000), chain, 1.0f, transform);
}
Example #29
0
NS_IMETHODIMP
nsClipboard::SetNativeClipboardData( nsITransferable *aTransferable,
                                     QClipboard::Mode clipboardMode )
{
    if (nullptr == aTransferable)
    {
        NS_WARNING("nsClipboard::SetNativeClipboardData(): no transferable!");
        return NS_ERROR_FAILURE;
    }

    // get flavor list that includes all flavors that can be written (including
    // ones obtained through conversion)
    nsCOMPtr<nsISupportsArray> flavorList;
    nsresult rv = aTransferable->FlavorsTransferableCanExport( getter_AddRefs(flavorList) );

    if (NS_FAILED(rv))
    {
        NS_WARNING("nsClipboard::SetNativeClipboardData(): no FlavorsTransferable !");
        return NS_ERROR_FAILURE;
    }

    QClipboard *cb = QGuiApplication::clipboard();
    QMimeData *mimeData = new QMimeData;

    uint32_t flavorCount = 0;
    flavorList->Count(&flavorCount);
    bool imageAdded = false;

    for (uint32_t i = 0; i < flavorCount; ++i)
    {
        nsCOMPtr<nsISupports> genericFlavor;
        flavorList->GetElementAt(i,getter_AddRefs(genericFlavor));
        nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
        
        if (currentFlavor)
        {
            // flavorStr is the mime type
            nsXPIDLCString flavorStr;
            currentFlavor->ToString(getter_Copies(flavorStr));

            // Clip is the data which will be sent to the clipboard
            nsCOMPtr<nsISupports> clip;
            // len is the length of the data
            uint32_t len;

            // Unicode text?
            if (!strcmp(flavorStr.get(), kUnicodeMime))
            {
                rv = aTransferable->GetTransferData(flavorStr,getter_AddRefs(clip),&len);
                nsCOMPtr<nsISupportsString> wideString;
                wideString = do_QueryInterface(clip);
                if (!wideString || NS_FAILED(rv))
                    continue;

                nsAutoString utf16string;
                wideString->GetData(utf16string);
                QString str = QString::fromUtf16((const ushort*)utf16string.get());

                // Add text to the mimeData
                mimeData->setText(str);
            }

            // html?
            else if (!strcmp(flavorStr.get(), kHTMLMime))
            {
                rv = aTransferable->GetTransferData(flavorStr,getter_AddRefs(clip),&len);
                nsCOMPtr<nsISupportsString> wideString;
                wideString = do_QueryInterface(clip);
                if (!wideString || NS_FAILED(rv))
                    continue;

                nsAutoString utf16string;
                wideString->GetData(utf16string);
                QString str = QString::fromUtf16((const ushort*)utf16string.get());

                // Add html to the mimeData
                mimeData->setHtml(str);
            }

            // image?
            else if (!imageAdded // image is added only once to the clipboard
                     && (!strcmp(flavorStr.get(), kNativeImageMime)
                     ||  !strcmp(flavorStr.get(), kPNGImageMime)
                     ||  !strcmp(flavorStr.get(), kJPEGImageMime)
                     ||  !strcmp(flavorStr.get(), kJPGImageMime)
                     ||  !strcmp(flavorStr.get(), kGIFImageMime))
                    )
            {
                // Look through our transfer data for the image
                static const char* const imageMimeTypes[] = {
                    kNativeImageMime, kPNGImageMime, kJPEGImageMime, kJPGImageMime, kGIFImageMime };
                nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive;
                for (uint32_t i = 0; !ptrPrimitive && i < ArrayLength(imageMimeTypes); i++)
                {
                    aTransferable->GetTransferData(imageMimeTypes[i], getter_AddRefs(clip), &len);
                    ptrPrimitive = do_QueryInterface(clip);
                }

                if (!ptrPrimitive)
                    continue;

                nsCOMPtr<nsISupports> primitiveData;
                ptrPrimitive->GetData(getter_AddRefs(primitiveData));
                nsCOMPtr<imgIContainer> image(do_QueryInterface(primitiveData));
                if (!image)  // Not getting an image for an image mime type!?
                   continue;

                RefPtr<SourceSurface> surface =
                  image->GetFrame(imgIContainer::FRAME_CURRENT,
                                  imgIContainer::FLAG_SYNC_DECODE);
                if (!surface)
                  continue;

                RefPtr<DataSourceSurface> dataSurface =
                  surface->GetDataSurface();
                if (!dataSurface)
                  continue;

                DataSourceSurface::MappedSurface map;
                if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map))
                  continue;

                QImage qImage(map.mData,
                              dataSurface->GetSize().width,
                              dataSurface->GetSize().height,
                              map.mStride,
                              _moz2dformat_to_qformat(dataSurface->GetFormat()));

                dataSurface->Unmap();

                // Add image to the mimeData
                mimeData->setImageData(qImage);
                imageAdded = true;
            }

            // Other flavors, adding data to clipboard "as is"
            else
            {
                rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(clip), &len);
                // nothing found?
                if (!clip || NS_FAILED(rv))
                    continue;

                void *primitive_data = nullptr;
                nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr.get(), clip,
                                                            &primitive_data, len);

                if (primitive_data)
                {
                    QByteArray data ((const char *)primitive_data, len);
                    // Add data to the mimeData
                    mimeData->setData(flavorStr.get(), data);
                    nsMemory::Free(primitive_data);
                }
            }
        }
    }

    // If we have some mime data, add it to the clipboard
    if(!mimeData->formats().isEmpty())
        cb->setMimeData(mimeData, clipboardMode);
    else
        delete mimeData;

    return NS_OK;
}
Example #30
0
// See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
// with E_OUTOFMEMORY.
static bool
DoesTextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT format, UINT bindflags)
{
  // CreateTexture2D is known to crash on lower feature levels, see bugs
  // 1170211 and 1089413.
  if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) {
    return false;
  }

  if (gfxPrefs::Direct2DForceEnabled() ||
      gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING))
  {
    return true;
  }

  if (GetModuleHandleW(L"atidxx32.dll")) {
    nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
    if (gfxInfo) {
      nsString vendorID, vendorID2;
      gfxInfo->GetAdapterVendorID(vendorID);
      gfxInfo->GetAdapterVendorID2(vendorID2);
      if (vendorID.EqualsLiteral("0x8086") && vendorID2.IsEmpty()) {
        if (!gfxPrefs::LayersAMDSwitchableGfxEnabled()) {
          return false;
        }
        gfxCriticalError(CriticalLog::DefaultOptions(false)) << "PossiblyBrokenSurfaceSharing_UnexpectedAMDGPU";
      }
    }
  }

  RefPtr<ID3D11Texture2D> texture;
  D3D11_TEXTURE2D_DESC desc;
  const int texture_size = 32;
  desc.Width = texture_size;
  desc.Height = texture_size;
  desc.MipLevels = 1;
  desc.ArraySize = 1;
  desc.Format = format;
  desc.SampleDesc.Count = 1;
  desc.SampleDesc.Quality = 0;
  desc.Usage = D3D11_USAGE_DEFAULT;
  desc.CPUAccessFlags = 0;
  desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
  desc.BindFlags = bindflags;

  uint32_t color[texture_size * texture_size];
  for (size_t i = 0; i < sizeof(color)/sizeof(color[0]); i++) {
    color[i] = 0xff00ffff;
  }
  // XXX If we pass the data directly at texture creation time we
  //     get a crash on Intel 8.5.10.[18xx-1994] drivers.
  //     We can work around this issue by doing UpdateSubresource.
  if (!TryCreateTexture2D(device, &desc, nullptr, texture)) {
    gfxCriticalNote << "DoesD3D11TextureSharingWork_TryCreateTextureFailure";
    return false;
  }

  RefPtr<IDXGIKeyedMutex> sourceSharedMutex;
  texture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sourceSharedMutex));
  if (FAILED(sourceSharedMutex->AcquireSync(0, 30*1000))) {
    gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceMutexTimeout";
    // only wait for 30 seconds
    return false;
  }

  RefPtr<ID3D11DeviceContext> deviceContext;
  device->GetImmediateContext(getter_AddRefs(deviceContext));

  int stride = texture_size * 4;
  deviceContext->UpdateSubresource(texture, 0, nullptr, color, stride, stride * texture_size);

  if (FAILED(sourceSharedMutex->ReleaseSync(0))) {
    gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceReleaseSyncTimeout";
    return false;
  }

  HANDLE shareHandle;
  RefPtr<IDXGIResource> otherResource;
  if (FAILED(texture->QueryInterface(__uuidof(IDXGIResource),
                                     getter_AddRefs(otherResource))))
  {
    gfxCriticalError() << "DoesD3D11TextureSharingWork_GetResourceFailure";
    return false;
  }

  if (FAILED(otherResource->GetSharedHandle(&shareHandle))) {
    gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
    return false;
  }

  RefPtr<ID3D11Resource> sharedResource;
  RefPtr<ID3D11Texture2D> sharedTexture;
  if (FAILED(device->OpenSharedResource(shareHandle, __uuidof(ID3D11Resource),
                                        getter_AddRefs(sharedResource))))
  {
    gfxCriticalError(CriticalLog::DefaultOptions(false)) << "OpenSharedResource failed for format " << format;
    return false;
  }

  if (FAILED(sharedResource->QueryInterface(__uuidof(ID3D11Texture2D),
                                            getter_AddRefs(sharedTexture))))
  {
    gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure";
    return false;
  }

  // create a staging texture for readback
  RefPtr<ID3D11Texture2D> cpuTexture;
  desc.Usage = D3D11_USAGE_STAGING;
  desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
  desc.MiscFlags = 0;
  desc.BindFlags = 0;
  if (FAILED(device->CreateTexture2D(&desc, nullptr, getter_AddRefs(cpuTexture)))) {
    gfxCriticalError() << "DoesD3D11TextureSharingWork_CreateTextureFailure";
    return false;
  }

  RefPtr<IDXGIKeyedMutex> sharedMutex;
  sharedResource->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sharedMutex));
  {
    HRESULT hr;
    AutoTextureLock lock(sharedMutex, hr, 30*1000);
    if (FAILED(hr)) {
      gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout";
      // only wait for 30 seconds
      return false;
    }

    // Copy to the cpu texture so that we can readback
    deviceContext->CopyResource(cpuTexture, sharedTexture);

    // We only need to hold on to the mutex during the copy.
    sharedMutex->ReleaseSync(0);
  }

  D3D11_MAPPED_SUBRESOURCE mapped;
  uint32_t resultColor = 0;
  if (SUCCEEDED(deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped))) {
    // read the texture
    resultColor = *(uint32_t*)mapped.pData;
    deviceContext->Unmap(cpuTexture, 0);
  } else {
    gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed";
    return false;
  }

  // check that the color we put in is the color we get out
  if (resultColor != color[0]) {
    // Shared surfaces seem to be broken on dual AMD & Intel HW when using the
    // AMD GPU
    gfxCriticalNote << "DoesD3D11TextureSharingWork_ColorMismatch";
    return false;
  }

  RefPtr<ID3D11ShaderResourceView> sharedView;

  // This if(FAILED()) is the one that actually fails on systems affected by bug 1083071.
  if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL, getter_AddRefs(sharedView)))) {
    gfxCriticalNote << "CreateShaderResourceView failed for format" << format;
    return false;
  }

  return true;
}