Bug 1444432 - Create a Compositor abstraction called AsyncReadbackBuffer and implement it for CompositorOGL. r=jrmuizel

MozReview-Commit-ID: Jx1RFFoKypz

--HG--
extra : rebase_source : f7851e97ebc5d1cbc50896d3d02c028d26343f59
This commit is contained in:
Markus Stange 2018-03-28 15:46:38 -04:00
Родитель 7981f6dc01
Коммит 0e1a4b9b8c
3 изменённых файлов: 153 добавлений и 0 удалений

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

@ -135,6 +135,7 @@ class CompositorD3D11;
class BasicCompositor;
class TextureReadLock;
struct GPUStats;
class AsyncReadbackBuffer;
enum SurfaceInitMode
{
@ -262,6 +263,23 @@ public:
const CompositingRenderTarget* aSource,
const gfx::IntPoint& aSourcePoint) = 0;
/**
* Grab a snapshot of aSource and store it in aDest, so that the pixels can
* be read on the CPU by mapping aDest at some point in the future.
* aSource and aDest must have the same size.
* If this is a GPU compositor, this call must not block on the GPU.
* Returns whether the operation was successful.
*/
virtual bool
ReadbackRenderTarget(CompositingRenderTarget* aSource,
AsyncReadbackBuffer* aDest) { return false; }
/**
* Create an AsyncReadbackBuffer of the specified size. Can return null.
*/
virtual already_AddRefed<AsyncReadbackBuffer>
CreateAsyncReadbackBuffer(const gfx::IntSize& aSize) { return nullptr; }
/**
* Sets the given surface as the target for subsequent calls to DrawQuad.
* Passing null as aSurface sets the screen as the target.
@ -625,6 +643,22 @@ BlendOpIsMixBlendMode(gfx::CompositionOp aOp)
}
}
class AsyncReadbackBuffer
{
public:
NS_INLINE_DECL_REFCOUNTING(AsyncReadbackBuffer)
gfx::IntSize GetSize() const { return mSize; }
virtual bool MapAndCopyInto(gfx::DataSourceSurface* aSurface,
const gfx::IntSize& aReadSize) const=0;
protected:
explicit AsyncReadbackBuffer(const gfx::IntSize& aSize) : mSize(aSize) {}
virtual ~AsyncReadbackBuffer() {}
gfx::IntSize mSize;
};
struct TexturedVertex
{
float position[2];

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

@ -44,6 +44,7 @@
#include "GLReadTexImageHelper.h"
#include "GLBlitTextureImageHelper.h"
#include "HeapCopyOfStackArray.h"
#include "mozilla/gfx/Swizzle.h"
#if MOZ_WIDGET_ANDROID
#include "GeneratedJNIWrappers.h"
@ -63,6 +64,87 @@ using namespace mozilla::gl;
static const GLuint kCoordinateAttributeIndex = 0;
static const GLuint kTexCoordinateAttributeIndex = 1;
class AsyncReadbackBufferOGL final : public AsyncReadbackBuffer
{
public:
AsyncReadbackBufferOGL(GLContext* aGL, const IntSize& aSize);
bool MapAndCopyInto(DataSourceSurface* aSurface,
const IntSize& aReadSize) const override;
void Bind() const
{
mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, mBufferHandle);
mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 1);
}
protected:
~AsyncReadbackBufferOGL() override;
private:
GLContext* mGL;
GLuint mBufferHandle;
};
AsyncReadbackBufferOGL::AsyncReadbackBufferOGL(GLContext* aGL,
const IntSize& aSize)
: AsyncReadbackBuffer(aSize)
, mGL(aGL)
{
size_t bufferByteCount = mSize.width * mSize.height * 4;
mGL->fGenBuffers(1, &mBufferHandle);
ScopedPackState scopedPackState(mGL);
Bind();
mGL->fBufferData(LOCAL_GL_PIXEL_PACK_BUFFER, bufferByteCount, nullptr,
LOCAL_GL_STREAM_READ);
}
AsyncReadbackBufferOGL::~AsyncReadbackBufferOGL()
{
if (mGL && mGL->MakeCurrent()) {
mGL->fDeleteBuffers(1, &mBufferHandle);
}
}
bool
AsyncReadbackBufferOGL::MapAndCopyInto(DataSourceSurface* aSurface,
const IntSize& aReadSize) const
{
MOZ_RELEASE_ASSERT(aReadSize <= aSurface->GetSize());
if (!mGL || !mGL->MakeCurrent()) {
return false;
}
ScopedPackState scopedPackState(mGL);
Bind();
uint8_t* srcData = static_cast<uint8_t*>(
mGL->fMapBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, LOCAL_GL_READ_ONLY));
if (!srcData) {
return false;
}
int32_t srcStride = mSize.width * 4; // Bind() sets an alignment of 1
DataSourceSurface::ScopedMap map(aSurface, DataSourceSurface::WRITE);
uint8_t* destData = map.GetData();
int32_t destStride = map.GetStride();
SurfaceFormat destFormat = aSurface->GetFormat();
for (int32_t destRow = 0; destRow < aReadSize.height; destRow++) {
// Turn srcData upside down during the copy.
int32_t srcRow = aReadSize.height - 1 - destRow;
uint8_t* src = &srcData[srcRow * srcStride];
uint8_t* dest = &destData[destRow * destStride];
SwizzleData(src, srcStride, SurfaceFormat::R8G8B8A8,
dest, destStride, destFormat, IntSize(aReadSize.width, 1));
}
mGL->fUnmapBuffer(LOCAL_GL_PIXEL_PACK_BUFFER);
return true;
}
static void
BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask,
GLenum aTexUnit, const gfx::Matrix4x4& aTransform)
@ -599,6 +681,36 @@ CompositorOGL::GetCurrentRenderTarget() const
return mCurrentRenderTarget;
}
already_AddRefed<AsyncReadbackBuffer>
CompositorOGL::CreateAsyncReadbackBuffer(const IntSize& aSize)
{
return MakeAndAddRef<AsyncReadbackBufferOGL>(mGLContext, aSize);
}
bool
CompositorOGL::ReadbackRenderTarget(CompositingRenderTarget* aSource,
AsyncReadbackBuffer* aDest)
{
IntSize size = aSource->GetSize();
MOZ_RELEASE_ASSERT(aDest->GetSize() == size);
RefPtr<CompositingRenderTarget> previousTarget = GetCurrentRenderTarget();
if (previousTarget != aSource) {
SetRenderTarget(aSource);
}
ScopedPackState scopedPackState(mGLContext);
static_cast<AsyncReadbackBufferOGL*>(aDest)->Bind();
mGLContext->fReadPixels(0, 0, size.width, size.height,
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, 0);
if (previousTarget != aSource) {
SetRenderTarget(previousTarget);
}
return true;
}
static GLenum
GetFrameBufferInternalFormat(GLContext* gl,
GLuint aFrameBuffer,

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

@ -158,6 +158,13 @@ public:
virtual void SetRenderTarget(CompositingRenderTarget *aSurface) override;
virtual CompositingRenderTarget* GetCurrentRenderTarget() const override;
virtual bool
ReadbackRenderTarget(CompositingRenderTarget* aSource,
AsyncReadbackBuffer* aDest) override;
virtual already_AddRefed<AsyncReadbackBuffer>
CreateAsyncReadbackBuffer(const gfx::IntSize& aSize) override;
virtual void DrawQuad(const gfx::Rect& aRect,
const gfx::IntRect& aClipRect,
const EffectChain &aEffectChain,