From de4075b8595c6db370001727425f854b6631a692 Mon Sep 17 00:00:00 2001 From: Florian Haenel Date: Wed, 6 Jul 2011 11:00:47 -0700 Subject: [PATCH] Bug 607687 - Fennec should take care about Texture MAX size HW limitation r=jmuizelaar --- gfx/layers/opengl/CanvasLayerOGL.cpp | 10 +- gfx/layers/opengl/ImageLayerOGL.cpp | 38 ++- gfx/layers/opengl/ThebesLayerOGL.cpp | 47 +++- gfx/thebes/GLContext.cpp | 341 +++++++++++++++++++++++---- gfx/thebes/GLContext.h | 123 ++++++++-- gfx/thebes/GLContextProviderEGL.cpp | 40 +++- gfx/thebes/GLContextProviderGLX.cpp | 15 +- widget/src/cocoa/nsChildView.mm | 3 +- 8 files changed, 491 insertions(+), 126 deletions(-) diff --git a/gfx/layers/opengl/CanvasLayerOGL.cpp b/gfx/layers/opengl/CanvasLayerOGL.cpp index abb332a9d87..ad77d763f91 100644 --- a/gfx/layers/opengl/CanvasLayerOGL.cpp +++ b/gfx/layers/opengl/CanvasLayerOGL.cpp @@ -366,19 +366,21 @@ ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer, { mOGLManager->MakeCurrent(); - gl()->fActiveTexture(LOCAL_GL_TEXTURE0); - gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture()); ColorTextureLayerProgram *program = mOGLManager->GetColorTextureLayerProgram(mTexImage->GetShaderProgramType()); ApplyFilter(mFilter); program->Activate(); - program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize())); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetTextureUnit(0); - mOGLManager->BindAndDrawQuad(program, mNeedsYFlip ? true : false); + mTexImage->BeginTileIteration(); + do { + TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0); + program->SetLayerQuadRect(mTexImage->GetTileRect()); + mOGLManager->BindAndDrawQuad(program, mNeedsYFlip); // FIXME flip order of tiles? + } while (mTexImage->NextTile()); } diff --git a/gfx/layers/opengl/ImageLayerOGL.cpp b/gfx/layers/opengl/ImageLayerOGL.cpp index 4a55f9e4f8f..e89ddd25009 100644 --- a/gfx/layers/opengl/ImageLayerOGL.cpp +++ b/gfx/layers/opengl/ImageLayerOGL.cpp @@ -938,20 +938,20 @@ ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer, { mOGLManager->MakeCurrent(); - LayerProgram* program; - if (mTexImage) { - gl()->fActiveTexture(LOCAL_GL_TEXTURE0); - gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture()); ColorTextureLayerProgram *colorProgram = mOGLManager->GetColorTextureLayerProgram(mTexImage->GetShaderProgramType()); - ApplyFilter(mFilter); - colorProgram->Activate(); colorProgram->SetTextureUnit(0); - colorProgram->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize())); - program = colorProgram; + + mTexImage->BeginTileIteration(); + do { + TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0); + ApplyFilter(mFilter); + colorProgram->SetLayerQuadRect(mTexImage->GetTileRect()); + mOGLManager->BindAndDrawQuad(colorProgram); + } while (mTexImage->NextTile()); } else { gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mYUVTexture[0].GetTextureID()); @@ -962,7 +962,7 @@ ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer, gl()->fActiveTexture(LOCAL_GL_TEXTURE2); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mYUVTexture[2].GetTextureID()); ApplyFilter(mFilter); - + YCbCrTextureLayerProgram *yuvProgram = mOGLManager->GetYCbCrLayerProgram(); yuvProgram->Activate(); @@ -970,24 +970,14 @@ ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer, mPictureRect.width, mPictureRect.height)); yuvProgram->SetYCbCrTextureUnits(0, 1, 2); + yuvProgram->SetLayerTransform(GetEffectiveTransform()); + yuvProgram->SetLayerOpacity(GetEffectiveOpacity()); + yuvProgram->SetRenderOffset(aOffset); - program = yuvProgram; - program->SetLayerTransform(GetEffectiveTransform()); - program->SetLayerOpacity(GetEffectiveOpacity()); - program->SetRenderOffset(aOffset); - - mOGLManager->BindAndDrawQuadWithTextureRect(program, + mOGLManager->BindAndDrawQuadWithTextureRect(yuvProgram, mPictureRect, nsIntSize(mSize.width, mSize.height)); - - return; - } - - program->SetLayerTransform(GetEffectiveTransform()); - program->SetLayerOpacity(GetEffectiveOpacity()); - program->SetRenderOffset(aOffset); - - mOGLManager->BindAndDrawQuad(program); + } } diff --git a/gfx/layers/opengl/ThebesLayerOGL.cpp b/gfx/layers/opengl/ThebesLayerOGL.cpp index 919d5fd9a27..443585616a8 100644 --- a/gfx/layers/opengl/ThebesLayerOGL.cpp +++ b/gfx/layers/opengl/ThebesLayerOGL.cpp @@ -141,10 +141,6 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset, mTexImageOnWhite->EndUpdate(); } - // Bind textures. - TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0); - TextureImage::ScopedBindTexture texOnWhiteBind(mTexImageOnWhite, LOCAL_GL_TEXTURE1); - PRInt32 passes = mTexImageOnWhite ? 2 : 1; for (PRInt32 pass = 1; pass <= passes; ++pass) { LayerProgram *program; @@ -194,17 +190,42 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset, } else { renderRegion = &visibleRegion; } - nsIntRegionRectIterator iter(*renderRegion); - while (const nsIntRect *iterRect = iter.Next()) { - nsIntRect quadRect = *iterRect; - program->SetLayerQuadRect(quadRect); - quadRect.MoveBy(-GetOriginOffset()); - - aManager->BindAndDrawQuadWithTextureRect(program, quadRect, - mTexImage->GetSize(), - mTexImage->GetWrapMode()); + mTexImage->BeginTileIteration(); + if (mTexImageOnWhite) { + mTexImageOnWhite->BeginTileIteration(); + NS_ASSERTION(mTexImageOnWhite->GetTileRect() == mTexImage->GetTileRect(), "component alpha textures should be the same size."); } + nsIntRegion region(*renderRegion); + nsIntPoint origin = GetOriginOffset(); + region.MoveBy(-origin); // translate into TexImage space, buffer origin might not be at texture (0,0) + + do { + nsIntRect textureRect = mTexImage->GetTileRect(); + textureRect.MoveBy(region.GetBounds().x, region.GetBounds().y); + nsIntRegion subregion(region); + subregion.And(region, textureRect); // region this texture is visible in + if (subregion.IsEmpty()) { + continue; + } + // Bind textures. + TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0); + TextureImage::ScopedBindTexture texOnWhiteBind(mTexImageOnWhite, LOCAL_GL_TEXTURE1); + + nsIntRegionRectIterator iter(subregion); + while (const nsIntRect *iterRect = iter.Next()) { + nsIntRect regionRect = *iterRect; // one rectangle of this texture's region + // translate into the correct place for this texture sub-region + nsIntRect screenRect = regionRect; + screenRect.MoveBy(origin); + program->SetLayerQuadRect(screenRect); + + regionRect.MoveBy(-mTexImage->GetTileRect().TopLeft()); // get region of tile + aManager->BindAndDrawQuadWithTextureRect(program, regionRect, + textureRect.Size(), + mTexImage->GetWrapMode()); + } + } while (mTexImage->NextTile()); } if (mTexImageOnWhite) { diff --git a/gfx/thebes/GLContext.cpp b/gfx/thebes/GLContext.cpp index 6b85d1ab60a..e3a4bb48735 100644 --- a/gfx/thebes/GLContext.cpp +++ b/gfx/thebes/GLContext.cpp @@ -52,6 +52,7 @@ #include "GLContextProvider.h" #include "gfxCrashReporterUtils.h" +#include "gfxUtils.h" #include "mozilla/Util.h" // for DebugOnly @@ -636,7 +637,7 @@ void BasicTextureImage::BindTexture(GLenum aTextureUnit) { mGLContext->fActiveTexture(aTextureUnit); - mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, Texture()); + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); } @@ -659,7 +660,7 @@ BasicTextureImage::FinishedSurfaceUpload() } bool -BasicTextureImage::DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion) +BasicTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */) { nsIntRect bounds = aRegion.GetBounds(); nsIntRegion region; @@ -675,7 +676,7 @@ BasicTextureImage::DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion) region, mTexture, mTextureState == Created, - bounds.TopLeft(), + bounds.TopLeft() + aFrom, PR_FALSE); mTextureState = Valid; return true; @@ -702,6 +703,202 @@ BasicTextureImage::Resize(const nsIntSize& aSize) mSize = aSize; } +TiledTextureImage::TiledTextureImage(GLContext* aGL, + nsIntSize aSize, + TextureImage::ContentType aContentType, + PRBool aUseNearestFilter) + : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aUseNearestFilter) + , mCurrentImage(0) + , mInUpdate(PR_FALSE) + , mGL(aGL) + , mUseNearestFilter(aUseNearestFilter) + , mTextureState(Created) +{ + mTileSize = mGL->GetMaxTextureSize(); + if (aSize != nsIntSize(0,0)) { + Resize(aSize); + } +} + +TiledTextureImage::~TiledTextureImage() +{ +} + +bool +TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */) +{ + nsIntRect bounds = aRegion.GetBounds(); + nsIntRegion region; + if (mTextureState != Valid) { + bounds = nsIntRect(0, 0, mSize.width, mSize.height); + region = nsIntRegion(bounds); + } else { + region = aRegion; + } + + PRBool result = PR_TRUE; + for (unsigned i = 0; i < mImages.Length(); i++) { + unsigned int xPos = (i % mColumns) * mTileSize; + unsigned int yPos = (i / mColumns) * mTileSize; + nsIntRegion tileRegion; + tileRegion.And(region, nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize())); // intersect with tile + if (tileRegion.IsEmpty()) + continue; + tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space + result &= mImages[i]->DirectUpdate(aSurf, + tileRegion, + aFrom + nsIntPoint(xPos, yPos)); + } + mShaderType = mImages[0]->GetShaderProgramType(); + mIsRGBFormat = mImages[0]->IsRGB(); + mTextureState = Valid; + return result; +} + +gfxASurface* +TiledTextureImage::BeginUpdate(nsIntRegion& aRegion) +{ + NS_ASSERTION(!mInUpdate, "nested update"); + mInUpdate = PR_TRUE; + + if (mTextureState != Valid) + { + // if the texture hasn't been initialized yet, or something important + // changed, we need to recreate our backing surface and force the + // client to paint everything + mUpdateRegion = nsIntRect(nsIntPoint(0, 0), mSize); + } else { + mUpdateRegion = aRegion; + } + + for (unsigned i = 0; i < mImages.Length(); i++) { + unsigned int xPos = (i % mColumns) * mTileSize; + unsigned int yPos = (i / mColumns) * mTileSize; + nsIntRegion imageRegion = nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize())); + + // a single Image can handle this update request + if (imageRegion.Contains(aRegion)) { + // adjust for tile offset + aRegion.MoveBy(-xPos, -yPos); + // forward the actual call + nsRefPtr surface = mImages[i]->BeginUpdate(aRegion); + // caller expects container space + aRegion.MoveBy(xPos, yPos); + // we don't have a temp surface + mUpdateSurface = nsnull; + // remember which image to EndUpdate + mCurrentImage = i; + return surface.get(); + } + } + // update covers multiple Images - create a temp surface to paint in + gfxASurface::gfxImageFormat format = + (GetContentType() == gfxASurface::CONTENT_COLOR) ? + gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32; + + nsIntRect bounds = aRegion.GetBounds(); + mUpdateSurface = gfxPlatform::GetPlatform()-> + CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), gfxASurface::ContentFromFormat(format)); + mUpdateSurface->SetDeviceOffset(gfxPoint(-bounds.x, -bounds.y)); + return mUpdateSurface; +} + +void +TiledTextureImage::EndUpdate() +{ + NS_ASSERTION(mInUpdate, "EndUpdate not in update"); + if (!mUpdateSurface) { // update was to a single TextureImage + mImages[mCurrentImage]->EndUpdate(); + mInUpdate = PR_FALSE; + mTextureState = Valid; + mShaderType = mImages[mCurrentImage]->GetShaderProgramType(); + mIsRGBFormat = mImages[mCurrentImage]->IsRGB(); + return; + } + + // upload tiles from temp surface + for (unsigned i = 0; i < mImages.Length(); i++) { + unsigned int xPos = (i % mColumns) * mTileSize; + unsigned int yPos = (i / mColumns) * mTileSize; + nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()); + nsIntRegion subregion; + subregion.And(mUpdateRegion, imageRect); + if (subregion.IsEmpty()) + continue; + subregion.MoveBy(-xPos, -yPos); // Tile-local space + // copy tile from temp surface + gfxASurface* surf = mImages[i]->BeginUpdate(subregion); + nsRefPtr ctx = new gfxContext(surf); + gfxUtils::ClipToRegion(ctx, subregion); + ctx->SetOperator(gfxContext::OPERATOR_SOURCE); + ctx->SetSource(mUpdateSurface, gfxPoint(-xPos, -yPos)); + ctx->Paint(); + mImages[i]->EndUpdate(); + } + + mUpdateSurface = nsnull; + mInUpdate = PR_FALSE; + mShaderType = mImages[0]->GetShaderProgramType(); + mIsRGBFormat = mImages[0]->IsRGB(); +} + +void TiledTextureImage::BeginTileIteration() +{ + mCurrentImage = 0; +} + +PRBool TiledTextureImage::NextTile() +{ + if (mCurrentImage + 1 < mImages.Length()) { + mCurrentImage++; + return PR_TRUE; + } + return PR_FALSE; +} + +nsIntRect TiledTextureImage::GetTileRect() +{ + nsIntRect rect = mImages[mCurrentImage]->GetTileRect(); + unsigned int xPos = (mCurrentImage % mColumns) * mTileSize; + unsigned int yPos = (mCurrentImage / mColumns) * mTileSize; + rect.MoveTo(xPos, yPos); + return rect; +} + +void +TiledTextureImage::BindTexture(GLenum aTextureUnit) +{ + mImages[mCurrentImage]->BindTexture(aTextureUnit); +} + +/* + * simple resize, just discards everything. we can be more clever just + * adding or discarding tiles, but do we want this? + */ +void TiledTextureImage::Resize(const nsIntSize& aSize) +{ + if (mSize == aSize && mTextureState != Created) { + return; + } + mSize = aSize; + mImages.Clear(); + // calculate rows and columns, rounding up + mColumns = (aSize.width + mTileSize - 1) / mTileSize; + mRows = (aSize.height + mTileSize - 1) / mTileSize; + + for (unsigned int row = 0; row < mRows; row++) { + for (unsigned int col = 0; col < mColumns; col++) { + nsIntSize size( // use tilesize first, then the remainder + (col+1) * mTileSize > (unsigned int)aSize.width ? aSize.width % mTileSize : mTileSize, + (row+1) * mTileSize > (unsigned int)aSize.height ? aSize.height % mTileSize : mTileSize); + nsRefPtr teximg = + mGL->TileGenFunc(size, mContentType, mUseNearestFilter); + mImages.AppendElement(teximg.forget()); + } + } + mTextureState = Allocated; +} + PRBool GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize) { @@ -1245,6 +1442,9 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect, NS_ASSERTION(!aSrc->InUpdate(), "Source texture is in update!"); NS_ASSERTION(!aDst->InUpdate(), "Destination texture is in update!"); + if (aSrcRect.IsEmpty() || aDstRect.IsEmpty()) + return; + // only save/restore this stuff on Qualcomm Adreno, to work // around an apparent bug int savedFb = 0; @@ -1255,57 +1455,114 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect, fDisable(LOCAL_GL_SCISSOR_TEST); fDisable(LOCAL_GL_BLEND); - SetBlitFramebufferForDestTexture(aDst->Texture()); + // 2.0 means scale up by two + float blitScaleX = float(aDstRect.width) / float(aSrcRect.width); + float blitScaleY = float(aDstRect.height) / float(aSrcRect.height); - UseBlitProgram(); + // We start iterating over all destination tiles + aDst->BeginTileIteration(); + do { + // calculate portion of the tile that is going to be painted to + nsIntRect dstSubRect; + nsIntRect dstTextureRect = aDst->GetTileRect(); + dstSubRect.IntersectRect(aDstRect, dstTextureRect); - nsIntSize srcSize = aSrc->GetSize(); - nsIntSize dstSize = aDst->GetSize(); + // this tile is not part of the destination rectangle aDstRect + if (dstSubRect.IsEmpty()) + continue; - PushViewportRect(nsIntRect(0, 0, dstSize.width, dstSize.height)); + // (*) transform the rect of this tile into the rectangle defined by aSrcRect... + nsIntRect dstInSrcRect(dstSubRect); + dstInSrcRect.MoveBy(-aDstRect.TopLeft()); + // ...which might be of different size, hence scale accordingly + dstInSrcRect.ScaleRoundOut(1.0f / blitScaleX, 1.0f / blitScaleY); + dstInSrcRect.MoveBy(aSrcRect.TopLeft()); - float dx0 = 2.0 * float(aDstRect.x) / float(dstSize.width) - 1.0; - float dy0 = 2.0 * float(aDstRect.y) / float(dstSize.height) - 1.0; - float dx1 = 2.0 * float(aDstRect.x + aDstRect.width) / float(dstSize.width) - 1.0; - float dy1 = 2.0 * float(aDstRect.y + aDstRect.height) / float(dstSize.height) - 1.0; + SetBlitFramebufferForDestTexture(aDst->GetTextureID()); + UseBlitProgram(); - RectTriangles rects; - if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) { - rects.addRect(/* dest rectangle */ - dx0, dy0, dx1, dy1, - /* tex coords */ - aSrcRect.x / float(srcSize.width), - aSrcRect.y / float(srcSize.height), - aSrcRect.XMost() / float(srcSize.width), - aSrcRect.YMost() / float(srcSize.height)); - } else { - DecomposeIntoNoRepeatTriangles(aSrcRect, srcSize, rects); + aSrc->BeginTileIteration(); + // now iterate over all tiles in the source Image... + do { + // calculate portion of the source tile that is in the source rect + nsIntRect srcSubRect; + nsIntRect srcTextureRect = aSrc->GetTileRect(); + srcSubRect.IntersectRect(aSrcRect, srcTextureRect); - // now put the coords into the d[xy]0 .. d[xy]1 coordinate space - // from the 0..1 that it comes out of decompose - RectTriangles::vert_coord* v = (RectTriangles::vert_coord*)rects.vertexPointer(); - for (int i = 0; i < rects.elements(); ++i) { - v[i].x = (v[i].x * (dx1 - dx0)) + dx0; - v[i].y = (v[i].y * (dy1 - dy0)) + dy0; - } - } + // this tile is not part of the source rect + if (srcSubRect.IsEmpty()) { + continue; + } + // calculate intersection of source rect with destination rect + srcSubRect.IntersectRect(srcSubRect, dstInSrcRect); + // this tile does not overlap the current destination tile + if (srcSubRect.IsEmpty()) { + continue; + } + // We now have the intersection of + // the current source tile + // and the desired source rectangle + // and the destination tile + // and the desired destination rectange + // in destination space. + // We need to transform this back into destination space, inverting the transform from (*) + nsIntRect srcSubInDstRect(srcSubRect); + srcSubInDstRect.MoveBy(-aSrcRect.TopLeft()); + srcSubInDstRect.ScaleRoundOut(blitScaleX, blitScaleY); + srcSubInDstRect.MoveBy(aDstRect.TopLeft()); + // we transform these rectangles to be relative to the current src and dst tiles, respectively + nsIntSize srcSize = srcTextureRect.Size(); + nsIntSize dstSize = dstTextureRect.Size(); + srcSubRect.MoveBy(-srcTextureRect.x, -srcTextureRect.y); + srcSubInDstRect.MoveBy(-dstTextureRect.x, -dstTextureRect.y); - fActiveTexture(LOCAL_GL_TEXTURE0); - fBindTexture(LOCAL_GL_TEXTURE_2D, aSrc->Texture()); + float dx0 = 2.0 * float(srcSubInDstRect.x) / float(dstSize.width) - 1.0; + float dy0 = 2.0 * float(srcSubInDstRect.y) / float(dstSize.height) - 1.0; + float dx1 = 2.0 * float(srcSubInDstRect.x + srcSubInDstRect.width) / float(dstSize.width) - 1.0; + float dy1 = 2.0 * float(srcSubInDstRect.y + srcSubInDstRect.height) / float(dstSize.height) - 1.0; + PushViewportRect(nsIntRect(0, 0, dstSize.width, dstSize.height)); - fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); + RectTriangles rects; + if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) { + rects.addRect(/* dest rectangle */ + dx0, dy0, dx1, dy1, + /* tex coords */ + srcSubRect.x / float(srcSize.width), + srcSubRect.y / float(srcSize.height), + srcSubRect.XMost() / float(srcSize.width), + srcSubRect.YMost() / float(srcSize.height)); + } else { + DecomposeIntoNoRepeatTriangles(srcSubRect, srcSize, rects); - fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertexPointer()); - fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoordPointer()); + // now put the coords into the d[xy]0 .. d[xy]1 coordinate space + // from the 0..1 that it comes out of decompose + RectTriangles::vert_coord* v = (RectTriangles::vert_coord*)rects.vertexPointer(); - fEnableVertexAttribArray(0); - fEnableVertexAttribArray(1); + for (unsigned int i = 0; i < rects.elements(); ++i) { + v[i].x = (v[i].x * (dx1 - dx0)) + dx0; + v[i].y = (v[i].y * (dy1 - dy0)) + dy0; + } + } - fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements()); + TextureImage::ScopedBindTexture texBind(aSrc, LOCAL_GL_TEXTURE0); - fDisableVertexAttribArray(0); - fDisableVertexAttribArray(1); + fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); + + fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertexPointer()); + fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoordPointer()); + + fEnableVertexAttribArray(0); + fEnableVertexAttribArray(1); + + fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements()); + + fDisableVertexAttribArray(0); + fDisableVertexAttribArray(1); + + PopViewportRect(); + } while (aSrc->NextTile()); + } while (aDst->NextTile()); fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, NULL); fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, NULL); @@ -1325,8 +1582,6 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect, fEnable(LOCAL_GL_SCISSOR_TEST); fEnable(LOCAL_GL_BLEND); - - PopViewportRect(); } static unsigned int diff --git a/gfx/thebes/GLContext.h b/gfx/thebes/GLContext.h index 7838c55d456..2f088003cf3 100644 --- a/gfx/thebes/GLContext.h +++ b/gfx/thebes/GLContext.h @@ -75,8 +75,12 @@ typedef char realGLboolean; #include "GLContextSymbols.h" namespace mozilla { -namespace gl { + namespace layers { + class LayerManagerOGL; + class ColorTextureLayerProgram; + }; +namespace gl { class GLContext; class LibrarySymbolLoader @@ -156,6 +160,13 @@ class TextureImage { NS_INLINE_DECL_REFCOUNTING(TextureImage) public: + enum TextureState + { + Created, // Texture created, but has not had glTexImage called to initialize it. + Allocated, // Texture memory exists, but contents are invalid. + Valid // Texture fully ready to use. + }; + typedef gfxASurface::gfxContentType ContentType; virtual ~TextureImage() {} @@ -191,6 +202,22 @@ public: */ virtual void EndUpdate() = 0; + /** + * The Image may contain several textures for different regions (tiles). + * These functions iterate over each sub texture image tile. + */ + virtual void BeginTileIteration() { + }; + + virtual PRBool NextTile() { + return PR_FALSE; + }; + + virtual nsIntRect GetTileRect() { + return nsIntRect(nsIntPoint(0,0), mSize); + }; + + virtual GLuint GetTextureID() = 0; /** * Set this TextureImage's size, and ensure a texture has been * allocated. Must not be called between BeginUpdate and EndUpdate. @@ -206,7 +233,12 @@ public: EndUpdate(); } - virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion) =0; + /** + * aSurf - the source surface to update from + * aRegion - the region in this image to update + * aFrom - offset in the source to update from + */ + virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0)) = 0; virtual void BindTexture(GLenum aTextureUnit) = 0; virtual void ReleaseTexture() {}; @@ -233,16 +265,6 @@ public: TextureImage *mTexture; }; - /** - * Return this TextureImage's texture ID for use with GL APIs. - * Callers are responsible for properly binding the texture etc. - * - * The texture is only texture complete after either Resize - * or a matching pair of BeginUpdate/EndUpdate have been called. - * Otherwise, a texture ID may be returned, but the texture - * may not be texture complete. - */ - GLuint Texture() { return mTexture; } /** * Returns the shader program type that should be used to render @@ -279,17 +301,15 @@ protected: * TextureImage from GLContext::CreateTextureImage(). That is, * clients must not be given partially-constructed TextureImages. */ - TextureImage(GLuint aTexture, const nsIntSize& aSize, + TextureImage(const nsIntSize& aSize, GLenum aWrapMode, ContentType aContentType, PRBool aIsRGB = PR_FALSE) - : mTexture(aTexture) - , mSize(aSize) + : mSize(aSize) , mWrapMode(aWrapMode) , mContentType(aContentType) , mIsRGBFormat(aIsRGB) {} - GLuint mTexture; nsIntSize mSize; GLenum mWrapMode; ContentType mContentType; @@ -318,25 +338,19 @@ public: GLenum aWrapMode, ContentType aContentType, GLContext* aContext) - : TextureImage(aTexture, aSize, aWrapMode, aContentType) + : TextureImage(aSize, aWrapMode, aContentType) + , mTexture(aTexture) , mTextureState(Created) , mGLContext(aContext) , mUpdateOffset(0, 0) {} - enum TextureState - { - Created, // Texture created, but has not had glTexImage called to initialize it. - Allocated, // Texture memory exists, but contents are invalid. - Valid // Texture fully ready to use. - }; - virtual void BindTexture(GLenum aTextureUnit); virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion); virtual void EndUpdate(); - virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion); - + virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0)); + virtual GLuint GetTextureID() { return mTexture; }; // Returns a surface to draw into virtual already_AddRefed GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt); @@ -354,6 +368,7 @@ public: virtual void Resize(const nsIntSize& aSize); protected: + GLuint mTexture; TextureState mTextureState; GLContext* mGLContext; nsRefPtr mUpdateSurface; @@ -363,6 +378,47 @@ protected: nsIntPoint mUpdateOffset; }; +/** + * A container class that complements many sub TextureImages into a big TextureImage. + * Aims to behave just like the real thing. + */ + +class TiledTextureImage + : public TextureImage +{ +public: + TiledTextureImage(GLContext* aGL, nsIntSize aSize, + TextureImage::ContentType aContentType, PRBool aUseNearestFilter = PR_FALSE); + ~TiledTextureImage(); + void DumpDiv(); + virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion); + virtual void EndUpdate(); + virtual void Resize(const nsIntSize& aSize); + virtual void BeginTileIteration(); + virtual PRBool NextTile(); + virtual nsIntRect GetTileRect(); + virtual GLuint GetTextureID() { + return mImages[mCurrentImage]->GetTextureID(); + }; + virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0)); + virtual PRBool InUpdate() const { return mInUpdate; }; + virtual void BindTexture(GLenum); +protected: + unsigned int mCurrentImage; + nsTArray< nsRefPtr > mImages; + bool mInUpdate; + nsIntSize mSize; + unsigned int mTileSize; + unsigned int mRows, mColumns; + GLContext* mGL; + PRBool mUseNearestFilter; + // A temporary surface to faciliate cross-tile updates. + nsRefPtr mUpdateSurface; + // The region of update requested + nsIntRegion mUpdateRegion; + TextureState mTextureState; +}; + struct THEBES_API ContextFormat { static const ContextFormat BasicRGBA32Format; @@ -706,6 +762,21 @@ public: GLenum aWrapMode, PRBool aUseNearestFilter=PR_FALSE); + /** + * In EGL we want to use Tiled Texture Images, which we return + * from CreateTextureImage above. + * Inside TiledTextureImage we need to create actual images and to + * prevent infinite recursion we need to differentiate the two + * functions. + **/ + virtual already_AddRefed + TileGenFunc(const nsIntSize& aSize, + TextureImage::ContentType aContentType, + PRBool aUseNearestFilter = PR_FALSE) + { + return nsnull; + }; + /** * Read the image data contained in aTexture, and return it as an ImageSurface. * If GL_RGBA is given as the format, a ImageFormatARGB32 surface is returned. diff --git a/gfx/thebes/GLContextProviderEGL.cpp b/gfx/thebes/GLContextProviderEGL.cpp index 5445ff95eb0..c40323637b9 100644 --- a/gfx/thebes/GLContextProviderEGL.cpp +++ b/gfx/thebes/GLContextProviderEGL.cpp @@ -821,13 +821,18 @@ public: { return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface); } - + // GLContext interface - returns Tiled Texture Image in our case virtual already_AddRefed CreateTextureImage(const nsIntSize& aSize, TextureImage::ContentType aContentType, GLenum aWrapMode, PRBool aUseNearestFilter=PR_FALSE); + // a function to generate Tiles for Tiled Texture Image + virtual already_AddRefed + TileGenFunc(const nsIntSize& aSize, + TextureImage::ContentType aContentType, + PRBool aUseNearestFilter = PR_FALSE); // hold a reference to the given surface // for the lifetime of this context. void HoldSurface(gfxASurface *aSurf) { @@ -1108,7 +1113,8 @@ public: GLenum aWrapMode, ContentType aContentType, GLContext* aContext) - : TextureImage(aTexture, aSize, aWrapMode, aContentType) + : TextureImage(aSize, aWrapMode, aContentType) + , mTexture(aTexture) , mGLContext(aContext) , mUpdateFormat(gfxASurface::ImageFormatUnknown) , mSurface(nsnull) @@ -1302,10 +1308,10 @@ public: return; // mTexture is bound } - virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion) + virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */) { nsIntRect bounds = aRegion.GetBounds(); - + nsIntRegion region; if (!mCreated) { bounds = nsIntRect(0, 0, mSize.width, mSize.height); @@ -1319,7 +1325,7 @@ public: if (mUpdateSurface) { nsRefPtr ctx = new gfxContext(mUpdateSurface); gfxUtils::ClipToRegion(ctx, aRegion); - ctx->SetSource(aSurf); + ctx->SetSource(aSurf, gfxPoint(-aFrom.x, -aFrom.y)); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->Paint(); mUpdateSurface = nsnull; @@ -1331,7 +1337,7 @@ public: region, mTexture, !mCreated, - bounds.TopLeft(), + bounds.TopLeft() + aFrom, PR_FALSE); } @@ -1342,10 +1348,14 @@ public: virtual void BindTexture(GLenum aTextureUnit) { mGLContext->fActiveTexture(aTextureUnit); - mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, Texture()); + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); } + virtual GLuint GetTextureID() { + return mTexture; + }; + virtual PRBool InUpdate() const { return !!mUpdateSurface; } virtual void Resize(const nsIntSize& aSize) @@ -1576,6 +1586,7 @@ protected: nsRefPtr mUpdateSurface; EGLSurface mSurface; EGLConfig mConfig; + GLuint mTexture; EGLImageKHR mImageKHR; PRPackedBool mCreated; @@ -1588,6 +1599,15 @@ GLContextEGL::CreateTextureImage(const nsIntSize& aSize, TextureImage::ContentType aContentType, GLenum aWrapMode, PRBool aUseNearestFilter) +{ + nsRefPtr t = new gl::TiledTextureImage(this, aSize, aContentType); + return t.forget(); +}; + +already_AddRefed +GLContextEGL::TileGenFunc(const nsIntSize& aSize, + TextureImage::ContentType aContentType, + PRBool aUseNearestFilter) { MakeCurrent(); @@ -1598,13 +1618,13 @@ GLContextEGL::CreateTextureImage(const nsIntSize& aSize, fBindTexture(LOCAL_GL_TEXTURE_2D, texture); nsRefPtr teximage = - new TextureImageEGL(texture, aSize, aWrapMode, aContentType, this); + new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, this); GLint texfilter = aUseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR; fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter); fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode); - fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode); + fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); + fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); return teximage.forget(); } diff --git a/gfx/thebes/GLContextProviderGLX.cpp b/gfx/thebes/GLContextProviderGLX.cpp index e35b7382253..b976d100400 100644 --- a/gfx/thebes/GLContextProviderGLX.cpp +++ b/gfx/thebes/GLContextProviderGLX.cpp @@ -552,11 +552,12 @@ public: mInUpdate = PR_FALSE; } - virtual bool DirectUpdate(gfxASurface* aSurface, const nsIntRegion& aRegion) + + virtual bool DirectUpdate(gfxASurface* aSurface, const nsIntRegion& aRegion, const nsIntPoint& aFrom) { nsRefPtr ctx = new gfxContext(mUpdateSurface); gfxUtils::ClipToRegion(ctx, aRegion); - ctx->SetSource(aSurface); + ctx->SetSource(aSurface, aFrom); ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->Paint(); return true; @@ -565,7 +566,7 @@ public: virtual void BindTexture(GLenum aTextureUnit) { mGLContext->fActiveTexture(aTextureUnit); - mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, Texture()); + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); sGLXLibrary.BindTexImage(mPixmap); mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); } @@ -583,6 +584,10 @@ public: virtual PRBool InUpdate() const { return mInUpdate; } + virtual GLuint GetTextureID() { + return mTexture; + }; + private: TextureImageGLX(GLuint aTexture, const nsIntSize& aSize, @@ -591,11 +596,12 @@ private: GLContext* aContext, gfxASurface* aSurface, GLXPixmap aPixmap) - : TextureImage(aTexture, aSize, aWrapMode, aContentType) + : TextureImage(aSize, aWrapMode, aContentType) , mGLContext(aContext) , mUpdateSurface(aSurface) , mPixmap(aPixmap) , mInUpdate(PR_FALSE) + , mTexture(aTexture) { if (aSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) { mShaderType = gl::RGBALayerProgramType; @@ -608,6 +614,7 @@ private: nsRefPtr mUpdateSurface; GLXPixmap mPixmap; PRPackedBool mInUpdate; + GLuint mTexture; }; already_AddRefed diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index 833fcd47d9b..a788ca52543 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -2073,8 +2073,7 @@ nsChildView::DrawOver(LayerManager* aManager, nsIntRect aRect) float bottomX = aRect.x + aRect.width; float bottomY = aRect.y + aRect.height; - manager->gl()->fActiveTexture(LOCAL_GL_TEXTURE0); - manager->gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mResizerImage->Texture()); + TextureImage::ScopedBindTexture texBind(mResizerImage, LOCAL_GL_TEXTURE0); ColorTextureLayerProgram *program = manager->GetColorTextureLayerProgram(mResizerImage->GetShaderProgramType());