TemporaryRef<DataSourceSurface>
ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, SurfaceFormat aFormat)
{
    gl->MakeCurrent();
    gl->GuaranteeResolve();
    gl->fActiveTexture(LOCAL_GL_TEXTURE0);
    gl->fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);

    IntSize size;
    gl->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_WIDTH, &size.width);
    gl->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_HEIGHT, &size.height);

    RefPtr<DataSourceSurface> surf =
      Factory::CreateDataSourceSurfaceWithStride(size, SurfaceFormat::B8G8R8A8,
                                                 GetAlignedStride<4>(size.width * BytesPerPixel(SurfaceFormat::B8G8R8A8)));

    if (!surf) {
        return nullptr;
    }

    uint32_t currentPackAlignment = 0;
    gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*)&currentPackAlignment);
    if (currentPackAlignment != 4) {
        gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
    }
    gl->fGetTexImage(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, surf->GetData());
    if (currentPackAlignment != 4) {
        gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
    }

    if (aFormat == SurfaceFormat::R8G8B8A8 || aFormat == SurfaceFormat::R8G8B8X8) {
      SwapRAndBComponents(surf);
    }

    if (aYInvert) {
      surf = YInvertImageSurface(surf);
    }

    return surf.forget();
}
bool
SharedSurface_ANGLEShareHandle::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
{
    MOZ_ASSERT(out_surface);

    RefPtr<ID3D11Device> device =
      gfx::DeviceManagerDx::Get()->GetContentDevice();
    if (!device) {
        return false;
    }

    RefPtr<ID3D11Texture2D> tex;
    HRESULT hr = device->OpenSharedResource(mShareHandle,
                                            __uuidof(ID3D11Texture2D),
                                            (void**)(ID3D11Texture2D**)getter_AddRefs(tex));

    if (FAILED(hr)) {
        return false;
    }

    bool succeeded = false;
    ScopedLockTexture scopedLock(tex, &succeeded);
    if (!succeeded) {
        return false;
    }

    const uint8_t* data = reinterpret_cast<uint8_t*>(scopedLock.mSubresource.pData);
    uint32_t srcStride = scopedLock.mSubresource.RowPitch;

    gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE);
    if (!map.IsMapped()) {
        return false;
    }

    if (map.GetStride() == srcStride) {
        memcpy(map.GetData(), data, out_surface->GetSize().height * map.GetStride());
    } else {
        const uint8_t bytesPerPixel = BytesPerPixel(out_surface->GetFormat());
        for (int32_t i = 0; i < out_surface->GetSize().height; i++) {
            memcpy(map.GetData() + i * map.GetStride(),
                   data + i * srcStride,
                   bytesPerPixel * out_surface->GetSize().width);
        }
    }

    DXGI_FORMAT srcFormat = scopedLock.mDesc.Format;
    MOZ_ASSERT(srcFormat == DXGI_FORMAT_B8G8R8A8_UNORM ||
               srcFormat == DXGI_FORMAT_B8G8R8X8_UNORM ||
               srcFormat == DXGI_FORMAT_R8G8B8A8_UNORM);
    bool isSrcRGB = srcFormat == DXGI_FORMAT_R8G8B8A8_UNORM;

    gfx::SurfaceFormat destFormat = out_surface->GetFormat();
    MOZ_ASSERT(destFormat == gfx::SurfaceFormat::R8G8B8X8 ||
               destFormat == gfx::SurfaceFormat::R8G8B8A8 ||
               destFormat == gfx::SurfaceFormat::B8G8R8X8 ||
               destFormat == gfx::SurfaceFormat::B8G8R8A8);
    bool isDestRGB = destFormat == gfx::SurfaceFormat::R8G8B8X8 ||
                     destFormat == gfx::SurfaceFormat::R8G8B8A8;

    if (isSrcRGB != isDestRGB) {
        SwapRAndBComponents(out_surface);
    }

    return true;
}
void
ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
    gl->MakeCurrent();
    MOZ_ASSERT(dest->GetSize() != gfxIntSize(0, 0));

    /* gfxImageFormat::ARGB32:
     * RGBA+UByte: be[RGBA], le[ABGR]
     * RGBA+UInt: le[RGBA]
     * BGRA+UInt: le[BGRA]
     * BGRA+UIntRev: le[ARGB]
     *
     * gfxImageFormat::RGB16_565:
     * RGB+UShort: le[rrrrrggg,gggbbbbb]
     */
    bool hasAlpha = dest->Format() == gfxImageFormat::ARGB32;

    int destPixelSize;
    GLenum destFormat;
    GLenum destType;

    switch (dest->Format()) {
        case gfxImageFormat::RGB24: // XRGB
        case gfxImageFormat::ARGB32:
            destPixelSize = 4;
            // Needs host (little) endian ARGB.
            destFormat = LOCAL_GL_BGRA;
            destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
            break;

        case gfxImageFormat::RGB16_565:
            destPixelSize = 2;
            destFormat = LOCAL_GL_RGB;
            destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV;
            break;

        default:
            MOZ_CRASH("Bad format.");
    }
    MOZ_ASSERT(dest->Stride() == dest->Width() * destPixelSize);

    GLenum readFormat = destFormat;
    GLenum readType = destType;
    bool needsTempSurf = !GetActualReadFormats(gl,
                                               destFormat, destType,
                                               readFormat, readType);

    nsAutoPtr<gfxImageSurface> tempSurf;
    gfxImageSurface* readSurf = nullptr;
    int readPixelSize = 0;
    if (needsTempSurf) {
        if (gl->DebugMode()) {
            NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
        }
        SurfaceFormat readFormatGFX;

        switch (readFormat) {
            case LOCAL_GL_RGBA:
            case LOCAL_GL_BGRA: {
                readFormatGFX = hasAlpha ? SurfaceFormat::B8G8R8A8
                                         : SurfaceFormat::B8G8R8X8;
                break;
            }
            case LOCAL_GL_RGB: {
                MOZ_ASSERT(readPixelSize == 2);
                MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV);
                readFormatGFX = SurfaceFormat::R5G6B5;
                break;
            }
            default: {
                MOZ_CRASH("Bad read format.");
            }
        }

        switch (readType) {
            case LOCAL_GL_UNSIGNED_BYTE: {
                MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
                readPixelSize = 4;
                break;
            }
            case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV: {
                MOZ_ASSERT(readFormat == LOCAL_GL_BGRA);
                readPixelSize = 4;
                break;
            }
            case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV: {
                MOZ_ASSERT(readFormat == LOCAL_GL_RGB);
                readPixelSize = 2;
                break;
            }
            default: {
                MOZ_CRASH("Bad read type.");
            }
        }

        tempSurf = new gfxImageSurface(dest->GetSize(),
                                       SurfaceFormatToImageFormat(readFormatGFX),
                                       false);
        readSurf = tempSurf;
    } else {
        readPixelSize = destPixelSize;
        readSurf = dest;
    }
    MOZ_ASSERT(readPixelSize);

    GLint currentPackAlignment = 0;
    gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &currentPackAlignment);

    if (currentPackAlignment != readPixelSize)
        gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readPixelSize);

    GLsizei width = dest->Width();
    GLsizei height = dest->Height();

    readSurf->Flush();
    gl->fReadPixels(0, 0,
                    width, height,
                    readFormat, readType,
                    readSurf->Data());
    readSurf->MarkDirty();

    if (currentPackAlignment != readPixelSize)
        gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);

    if (readSurf != dest) {
        MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
        MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
        // So we just copied in RGBA in big endian, or le: 0xAABBGGRR.
        // We want 0xAARRGGBB, so swap R and B:
        dest->Flush();
        RefPtr<DataSourceSurface> readDSurf =
            Factory::CreateWrappingDataSourceSurface(readSurf->Data(),
                                                     readSurf->Stride(),
                                                     ToIntSize(readSurf->GetSize()),
                                                     ImageFormatToSurfaceFormat(readSurf->Format()));
        SwapRAndBComponents(readDSurf);
        dest->MarkDirty();

        gfxContext ctx(dest);
        ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
        ctx.SetSource(readSurf);
        ctx.Paint();
    }

    // Check if GL is giving back 1.0 alpha for
    // RGBA reads to RGBA images from no-alpha buffers.
#ifdef XP_MACOSX
    if (gl->WorkAroundDriverBugs() &&
        gl->Vendor() == gl::GLVendor::NVIDIA &&
        dest->Format() == gfxImageFormat::ARGB32 &&
        width && height)
    {
        GLint alphaBits = 0;
        gl->fGetIntegerv(LOCAL_GL_ALPHA_BITS, &alphaBits);
        if (!alphaBits) {
            const uint32_t alphaMask = gfxPackedPixelNoPreMultiply(0xff,0,0,0);

            dest->Flush();
            uint32_t* itr = (uint32_t*)dest->Data();
            uint32_t testPixel = *itr;
            if ((testPixel & alphaMask) != alphaMask) {
                // We need to set the alpha channel to 1.0 manually.
                uint32_t* itrEnd = itr + width*height;  // Stride is guaranteed to be width*4.

                for (; itr != itrEnd; itr++) {
                    *itr |= alphaMask;
                }
            }
            dest->MarkDirty();
        }
    }
#endif
}