зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
7981f6dc01
Коммит
0e1a4b9b8c
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче