Bug 604101 - Part 5 - Use Pixel Buffer Objects in TextureImageCGL. r=joe,jrmuizel a=blocking2.0

This commit is contained in:
Matt Woodrow 2010-12-16 23:49:42 -08:00
Родитель 63935bac8b
Коммит 41f7a4eadc
7 изменённых файлов: 149 добавлений и 184 удалений

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

@ -47,7 +47,7 @@
#include "nsThreadUtils.h"
#include "gfxImageSurface.h"
#include "gfxPlatform.h"
#include "GLContext.h"
#include "GLContextProvider.h"
@ -312,6 +312,11 @@ GLContext::InitWithPrefix(const char *prefix, PRBool trygl)
{ mIsGLES2 ? (PRFuncPtr*) NULL : (PRFuncPtr*) &mSymbols.fReadBuffer,
{ mIsGLES2 ? NULL : "ReadBuffer", NULL } },
{ mIsGLES2 ? (PRFuncPtr*) NULL : (PRFuncPtr*) &mSymbols.fMapBuffer,
{ mIsGLES2 ? NULL : "MapBuffer", NULL } },
{ mIsGLES2 ? (PRFuncPtr*) NULL : (PRFuncPtr*) &mSymbols.fUnmapBuffer,
{ mIsGLES2 ? NULL : "UnmapBuffer", NULL } },
{ NULL, { NULL } },
};
@ -321,6 +326,10 @@ GLContext::InitWithPrefix(const char *prefix, PRBool trygl)
if (mInitialized) {
InitExtensions();
NS_ASSERTION(!IsExtensionSupported(GLContext::ARB_pixel_buffer_object) ||
(mSymbols.fMapBuffer && mSymbols.fUnmapBuffer),
"ARB_pixel_buffer_object supported without glMapBuffer/UnmapBuffer being available!");
GLint v[4];
fGetIntegerv(LOCAL_GL_SCISSOR_BOX, v);
@ -404,6 +413,7 @@ static const char *sExtensionNames[] = {
"GL_EXT_read_format_bgra",
"GL_APPLE_client_storage",
"GL_ARB_texture_non_power_of_two",
"GL_ARB_pixel_buffer_object",
NULL
};
@ -566,15 +576,22 @@ BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
return NULL;
}
nsRefPtr<gfxASurface> updateSurface =
CreateUpdateSurface(gfxIntSize(rgnSize.width, rgnSize.height),
format);
nsRefPtr<gfxASurface> updateSurface =
GetSurfaceForUpdate(gfxIntSize(rgnSize.width, rgnSize.height), format);
if (!updateSurface)
return NULL;
updateSurface->SetDeviceOffset(gfxPoint(-mUpdateRect.x, -mUpdateRect.y));
mUpdateContext = new gfxContext(updateSurface);
// Clear the returned surface because it might have been re-used.
if (format == gfxASurface::ImageFormatARGB32) {
mUpdateContext->SetOperator(gfxContext::OPERATOR_CLEAR);
mUpdateContext->Paint();
mUpdateContext->SetOperator(gfxContext::OPERATOR_OVER);
}
return mUpdateContext;
}
@ -590,25 +607,44 @@ BasicTextureImage::EndUpdate()
// but important if we ever do anything directly with the surface.
originalSurface->SetDeviceOffset(gfxPoint(0, 0));
bool relative = FinishedSurfaceUpdate();
// The rect to upload from the surface is mUpdateRect sized and located at mUpdateOffset.
nsIntRect surfaceRect(mUpdateOffset.x, mUpdateOffset.y, mUpdateRect.width, mUpdateRect.height);
if (!mTextureInited) {
surfaceRect.x = 0;
surfaceRect.y = 0;
}
mShaderType =
mGLContext->UploadSurfaceToTexture(originalSurface,
surfaceRect,
mTexture,
!mTextureInited,
mUpdateRect.TopLeft());
mUpdateRect.TopLeft(),
relative);
FinishedSurfaceUpload();
mUpdateContext = nsnull;
mTextureInited = PR_TRUE;
return PR_TRUE; // mTexture is bound
}
already_AddRefed<gfxASurface>
BasicTextureImage::GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt)
{
return gfxPlatform::GetPlatform()->
CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
}
bool
BasicTextureImage::FinishedSurfaceUpdate()
{
return false;
}
void
BasicTextureImage::FinishedSurfaceUpload()
{
}
void
BasicTextureImage::Resize(const nsIntSize& aSize)
{
@ -1208,7 +1244,8 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
const nsIntRect& aSrcRect,
GLuint& aTexture,
bool aOverwrite,
const nsIntPoint& aDstPoint)
const nsIntPoint& aDstPoint,
bool aPixelBuffer)
{
bool textureInited = aOverwrite ? false : true;
MakeCurrent();
@ -1235,7 +1272,9 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
}
nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
unsigned char* data;
// If a pixel buffer is bound the data pointer parameter is relative
// to the start of the data block.
unsigned char* data = aPixelBuffer ? NULL : imageSurface->Data();
if (!imageSurface ||
(imageSurface->Format() != gfxASurface::ImageFormatARGB32 &&
@ -1251,9 +1290,7 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
context->Translate(-gfxPoint(aSrcRect.x, aSrcRect.y));
context->SetSource(aSurface);
context->Paint();
data = imageSurface->Data();
} else {
data = imageSurface->Data();
data += aSrcRect.y * imageSurface->Stride();
data += aSrcRect.x * 4;
}

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

@ -279,16 +279,8 @@ class BasicTextureImage
: public TextureImage
{
public:
virtual ~BasicTextureImage();
virtual gfxContext* BeginUpdate(nsIntRegion& aRegion);
virtual PRBool EndUpdate();
virtual PRBool InUpdate() const { return !!mUpdateContext; }
virtual void Resize(const nsIntSize& aSize);
protected:
typedef gfxASurface::gfxImageFormat ImageFormat;
virtual ~BasicTextureImage();
BasicTextureImage(GLuint aTexture,
const nsIntSize& aSize,
@ -301,8 +293,25 @@ protected:
, mUpdateOffset(0, 0)
{}
virtual gfxContext* BeginUpdate(nsIntRegion& aRegion);
virtual PRBool EndUpdate();
// Returns a surface to draw into
virtual already_AddRefed<gfxASurface>
CreateUpdateSurface(const gfxIntSize& aSize, ImageFormat aFmt) = 0;
GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt);
// Call when drawing into the update surface is complete.
// Returns true if textures should be upload with a relative
// offset - See UploadSurfaceToTexture.
virtual bool FinishedSurfaceUpdate();
// Call after surface data has been uploaded to a texture.
virtual void FinishedSurfaceUpload();
virtual PRBool InUpdate() const { return !!mUpdateContext; }
virtual void Resize(const nsIntSize& aSize);
protected:
PRBool mTextureInited;
GLContext* mGLContext;
@ -746,13 +755,17 @@ public:
* \param aTexture Texture to use, or 0 to have one created for you.
* \param aOverwrite Over an existing texture with a new one.
* \param aDstPoint Offset into existing texture to upload contents.
* \param aPixelBuffer Pass true to upload texture data with an
* offset from the base data (generally for pixel buffer objects),
* otherwise textures are upload with an absolute pointer to the data.
* \return Shader program needed to render this texture.
*/
ShaderProgramType UploadSurfaceToTexture(gfxASurface *aSurface,
const nsIntRect& aSrcRect,
GLuint& aTexture,
bool aOverwrite = false,
const nsIntPoint& aDstPoint = nsIntPoint(0, 0));
const nsIntPoint& aDstPoint = nsIntPoint(0, 0),
bool aPixelBuffer = PR_FALSE);
/** Helper for DecomposeIntoNoRepeatTriangles
*/
@ -808,6 +821,7 @@ public:
EXT_read_format_bgra,
APPLE_client_storage,
ARB_texture_non_power_of_two,
ARB_pixel_buffer_object,
Extensions_Max
};
@ -912,7 +926,11 @@ protected:
GLenum aWrapMode,
TextureImage::ContentType aContentType,
GLContext* aContext)
{ return NULL; }
{
nsRefPtr<BasicTextureImage> teximage(
new BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext));
return teximage.forget();
}
protected:
nsTArray<nsIntRect> mViewportStack;
@ -1842,6 +1860,20 @@ public:
AFTER_GL_CALL;
}
void* fMapBuffer(GLenum target, GLenum access) {
BEFORE_GL_CALL;
void *ret = mSymbols.fMapBuffer(target, access);
AFTER_GL_CALL;
return ret;
}
realGLboolean fUnmapBuffer(GLenum target) {
BEFORE_GL_CALL;
realGLboolean ret = mSymbols.fUnmapBuffer(target);
AFTER_GL_CALL;
return ret;
}
#ifndef DEBUG
GLuint GLAPIENTRY fCreateProgram() {

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

@ -294,72 +294,62 @@ class TextureImageCGL : public BasicTextureImage
GLenum,
TextureImage::ContentType,
GLContext*);
public:
~TextureImageCGL()
{
if (mPixelBuffer) {
mGLContext->fDeleteBuffers(1, &mPixelBuffer);
}
}
protected:
virtual gfxContext*
BeginUpdate(nsIntRegion& aRegion)
already_AddRefed<gfxASurface>
GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt)
{
ImageFormat format;
if (GetContentType() == gfxASurface::CONTENT_COLOR)
format = gfxASurface::ImageFormatRGB24;
else
format = gfxASurface::ImageFormatARGB32;
if (!mTextureInited || !mUpdateSurface ||
mUpdateSurface->GetContentType() != GetContentType())
{
mUpdateSurface = nsnull;
mUpdateOffset = nsIntPoint(0, 0);
// We need to (re)create our backing store. Let the base class to that.
return BasicTextureImage::BeginUpdate(aRegion);
if (!mGLContext->IsExtensionSupported(GLContext::ARB_pixel_buffer_object)) {
return gfxPlatform::GetPlatform()->
CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
}
nsRefPtr<gfxImageSurface> imageSurface = mUpdateSurface->GetAsImageSurface();
if (!imageSurface ||
nsIntSize(imageSurface->Width(), imageSurface->Height()) < mSize) {
mUpdateSurface = nsnull;
mUpdateOffset = nsIntPoint(0, 0);
// We need to (re)create our backing store. Let the base class to that.
return BasicTextureImage::BeginUpdate(aRegion);
if (!mPixelBuffer) {
mGLContext->fGenBuffers(1, &mPixelBuffer);
}
mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPixelBuffer);
PRInt32 size = aSize.width * 4 * aSize.height;
if (size > mPixelBufferSize) {
mGLContext->fBufferData(LOCAL_GL_PIXEL_UNPACK_BUFFER, size,
NULL, LOCAL_GL_STREAM_DRAW);
mPixelBufferSize = size;
}
unsigned char* data =
(unsigned char*)mGLContext->fMapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, LOCAL_GL_WRITE_ONLY);
if (!data) {
return nsnull;
}
// the basic impl can only upload updates to rectangles
mUpdateRect = aRegion.GetBounds();
aRegion = nsIntRegion(mUpdateRect);
nsRefPtr<gfxQuartzSurface> surf =
new gfxQuartzSurface(data, aSize,
aSize.width * 4, aFmt);
if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(mUpdateRect)) {
NS_ERROR("update outside of image");
return NULL;
return surf.forget();
}
bool FinishedSurfaceUpdate()
{
if (mPixelBuffer) {
mGLContext->fUnmapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER);
return true;
}
mUpdateContext = new gfxContext(mUpdateSurface);
mUpdateContext->Clip(gfxRect(mUpdateRect.x, mUpdateRect.y,
mUpdateRect.width, mUpdateRect.height));
if (GetContentType() != gfxASurface::CONTENT_COLOR)
{
mUpdateContext->SetOperator(gfxContext::OPERATOR_CLEAR);
mUpdateContext->Paint();
mUpdateContext->SetOperator(gfxContext::OPERATOR_OVER);
}
mUpdateOffset = mUpdateRect.TopLeft();
return mUpdateContext;
return false;
}
virtual PRBool
EndUpdate()
void FinishedSurfaceUpload()
{
if (!mUpdateSurface)
mUpdateSurface = mUpdateContext->OriginalSurface();
return BasicTextureImage::EndUpdate();
}
virtual already_AddRefed<gfxASurface>
CreateUpdateSurface(const gfxIntSize& aSize, ImageFormat aFmt)
{
mUpdateFormat = aFmt;
return gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
if (mPixelBuffer) {
mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
}
}
private:
@ -369,10 +359,12 @@ private:
ContentType aContentType,
GLContext* aContext)
: BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext)
, mPixelBuffer(0)
, mPixelBufferSize(0)
{}
ImageFormat mUpdateFormat;
nsRefPtr<gfxASurface> mUpdateSurface;
GLuint mPixelBuffer;
PRInt32 mPixelBufferSize;
};
already_AddRefed<TextureImage>

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

@ -370,13 +370,6 @@ TRY_AGAIN_NO_SHARING:
return PR_TRUE;
}
virtual already_AddRefed<TextureImage>
CreateBasicTextureImage(GLuint aTexture,
const nsIntSize& aSize,
GLenum aWrapMode,
TextureImage::ContentType aContentType,
GLContext* aContext);
private:
friend class GLContextProviderGLX;
@ -406,50 +399,6 @@ private:
nsRefPtr<gfxXlibSurface> mPixmap;
};
// FIXME/bug 575505: this is a (very slow!) placeholder
// implementation. Much better would be to create a Pixmap, wrap that
// in a GLXPixmap, and then glXBindTexImage() to our texture.
class TextureImageGLX : public BasicTextureImage
{
friend already_AddRefed<TextureImage>
GLContextGLX::CreateBasicTextureImage(GLuint,
const nsIntSize&,
GLenum,
TextureImage::ContentType,
GLContext*);
protected:
virtual already_AddRefed<gfxASurface>
CreateUpdateSurface(const gfxIntSize& aSize, ImageFormat aFmt)
{
mUpdateFormat = aFmt;
return gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
}
private:
TextureImageGLX(GLuint aTexture,
const nsIntSize& aSize,
GLenum aWrapMode,
ContentType aContentType,
GLContext* aContext)
: BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext)
{}
ImageFormat mUpdateFormat;
};
already_AddRefed<TextureImage>
GLContextGLX::CreateBasicTextureImage(GLuint aTexture,
const nsIntSize& aSize,
GLenum aWrapMode,
TextureImage::ContentType aContentType,
GLContext* aContext)
{
nsRefPtr<TextureImageGLX> teximage(
new TextureImageGLX(aTexture, aSize, aWrapMode, aContentType, aContext));
return teximage.forget();
}
static GLContextGLX *
GetGlobalContextGLX()
{

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

@ -327,13 +327,6 @@ public:
HGLRC Context() { return mContext; }
virtual already_AddRefed<TextureImage>
CreateBasicTextureImage(GLuint aTexture,
const nsIntSize& aSize,
GLenum aWrapMode,
TextureImage::ContentType aContentType,
GLContext* aContext);
protected:
friend class GLContextProviderWGL;
@ -445,50 +438,6 @@ GetGlobalContextWGL()
return static_cast<GLContextWGL*>(GLContextProviderWGL::GetGlobalContext());
}
class TextureImageWGL : public BasicTextureImage
{
friend already_AddRefed<TextureImage>
GLContextWGL::CreateBasicTextureImage(GLuint,
const nsIntSize&,
GLenum,
TextureImage::ContentType,
GLContext*);
protected:
virtual already_AddRefed<gfxASurface>
CreateUpdateSurface(const gfxIntSize& aSize, ImageFormat aFmt)
{
mUpdateSize = aSize;
mUpdateFormat = aFmt;
return gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
}
private:
TextureImageWGL(GLuint aTexture,
const nsIntSize& aSize,
GLenum aWrapMode,
ContentType aContentType,
GLContext* aContext)
: BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext)
{}
gfxIntSize mUpdateSize;
ImageFormat mUpdateFormat;
};
already_AddRefed<TextureImage>
GLContextWGL::CreateBasicTextureImage(GLuint aTexture,
const nsIntSize& aSize,
GLenum aWrapMode,
TextureImage::ContentType aContentType,
GLContext* aContext)
{
nsRefPtr<TextureImageWGL> teximage
(new TextureImageWGL(aTexture, aSize, aWrapMode, aContentType, aContext));
return teximage.forget();
}
already_AddRefed<GLContext>
GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget)
{

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

@ -363,6 +363,11 @@ struct GLContextSymbols
typedef void (GLAPIENTRY * PFNGLDELETERENDERBUFFERS) (GLsizei n, const GLuint* ids);
PFNGLDELETERENDERBUFFERS fDeleteRenderbuffers;
typedef void* (GLAPIENTRY * PFNGLMAPBUFFER) (GLenum target, GLenum access);
PFNGLMAPBUFFER fMapBuffer;
typedef realGLboolean (GLAPIENTRY * PFNGLUNMAPBUFFER) (GLenum target);
PFNGLUNMAPBUFFER fUnmapBuffer;
};
}

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

@ -844,6 +844,7 @@ typedef ptrdiff_t GLintptr;
#define LOCAL_GL_DYNAMIC_DRAW 0x88E8
#define LOCAL_GL_DYNAMIC_READ 0x88E9
#define LOCAL_GL_DYNAMIC_COPY 0x88EA
#define LOCAL_GL_PIXEL_UNPACK_BUFFER 0x88EC
#define LOCAL_GL_SAMPLES_PASSED 0x8914
#define LOCAL_GL_VERSION_2_0 1
#define LOCAL_GL_BLEND_EQUATION_RGB 0x8009