static already_AddRefed<TextureClient> TexClientFromReadback(SharedSurface* src, ISurfaceAllocator* allocator, TextureFlags baseFlags, LayersBackend layersBackend) { auto backendType = gfx::BackendType::CAIRO; TexClientFactory factory(allocator, src->mHasAlpha, src->mSize, backendType, baseFlags, layersBackend); RefPtr<TextureClient> texClient; { gl::ScopedReadbackFB autoReadback(src); // We have a source FB, now we need a format. GLenum destFormat = LOCAL_GL_BGRA; GLenum destType = LOCAL_GL_UNSIGNED_BYTE; GLenum readFormat; GLenum readType; // We actually don't care if they match, since we can handle // any read{Format,Type} we get. auto gl = src->mGL; GetActualReadFormats(gl, destFormat, destType, &readFormat, &readType); MOZ_ASSERT(readFormat == LOCAL_GL_RGBA || readFormat == LOCAL_GL_BGRA); MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE); // With a format and type, we can create texClient. if (readFormat == LOCAL_GL_BGRA && readType == LOCAL_GL_UNSIGNED_BYTE) { // 0xAARRGGBB // In Lendian: [BB, GG, RR, AA] texClient = factory.CreateB8G8R8AX8(); } else if (readFormat == LOCAL_GL_RGBA && readType == LOCAL_GL_UNSIGNED_BYTE) { // [RR, GG, BB, AA] texClient = factory.CreateR8G8B8AX8(); } else { MOZ_CRASH("GFX: Bad `read{Format,Type}`."); } MOZ_ASSERT(texClient); if (!texClient) return nullptr; // With a texClient, we can lock for writing. TextureClientAutoLock autoLock(texClient, OpenMode::OPEN_WRITE); DebugOnly<bool> succeeded = autoLock.Succeeded(); MOZ_ASSERT(succeeded, "texture should have locked"); MappedTextureData mapped; texClient->BorrowMappedData(mapped); // ReadPixels from the current FB into mapped.data. auto width = src->mSize.width; auto height = src->mSize.height; { ScopedPackAlignment autoAlign(gl, 4); MOZ_ASSERT(mapped.stride/4 == mapped.size.width); gl->raw_fReadPixels(0, 0, width, height, readFormat, readType, mapped.data); } // RB_SWAPPED doesn't work with D3D11. (bug 1051010) // RB_SWAPPED doesn't work with Basic. (bug ???????) // RB_SWAPPED doesn't work with D3D9. (bug ???????) bool layersNeedsManualSwap = layersBackend == LayersBackend::LAYERS_BASIC || layersBackend == LayersBackend::LAYERS_D3D9 || layersBackend == LayersBackend::LAYERS_D3D11; if (texClient->HasFlags(TextureFlags::RB_SWAPPED) && layersNeedsManualSwap) { size_t pixels = width * height; uint8_t* itr = mapped.data; for (size_t i = 0; i < pixels; i++) { SwapRB_R8G8B8A8(itr); itr += 4; } texClient->RemoveFlags(TextureFlags::RB_SWAPPED); } } return texClient.forget(); }
bool ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst) { AutoLockBits lock(dst); uint8_t* dstBytes; gfx::IntSize dstSize; int32_t dstStride; gfx::SurfaceFormat dstFormat; if (!lock.Lock(&dstBytes, &dstSize, &dstStride, &dstFormat)) return false; const bool isDstRGBA = (dstFormat == gfx::SurfaceFormat::R8G8B8A8 || dstFormat == gfx::SurfaceFormat::R8G8B8X8); MOZ_ASSERT_IF(!isDstRGBA, dstFormat == gfx::SurfaceFormat::B8G8R8A8 || dstFormat == gfx::SurfaceFormat::B8G8R8X8); size_t width = src->mSize.width; size_t height = src->mSize.height; MOZ_ASSERT(width == (size_t)dstSize.width); MOZ_ASSERT(height == (size_t)dstSize.height); GLenum readGLFormat; GLenum readType; { ScopedReadbackFB autoReadback(src); // We have a source FB, now we need a format. GLenum dstGLFormat = isDstRGBA ? LOCAL_GL_BGRA : LOCAL_GL_RGBA; GLenum dstType = LOCAL_GL_UNSIGNED_BYTE; // We actually don't care if they match, since we can handle // any read{Format,Type} we get. GLContext* gl = src->mGL; GetActualReadFormats(gl, dstGLFormat, dstType, &readGLFormat, &readType); MOZ_ASSERT(readGLFormat == LOCAL_GL_RGBA || readGLFormat == LOCAL_GL_BGRA); MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE); // ReadPixels from the current FB into lockedBits. { size_t alignment = 8; if (dstStride % 4 == 0) alignment = 4; ScopedPackAlignment autoAlign(gl, alignment); gl->raw_fReadPixels(0, 0, width, height, readGLFormat, readType, dstBytes); } } const bool isReadRGBA = readGLFormat == LOCAL_GL_RGBA; if (isReadRGBA != isDstRGBA) { for (size_t j = 0; j < height; ++j) { uint8_t* rowItr = dstBytes + j*dstStride; uint8_t* rowEnd = rowItr + 4*width; while (rowItr != rowEnd) { Swap(rowItr[0], rowItr[2]); rowItr += 4; } } } return true; }