mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
2caf0bb798
When rendering progressively, make sure that any previously visible area that is still visible is updated at the same time. This helps maintain visual coherency on pages that invalidate previously visible areas while scrolling, and when losing layers between updates. This supersedes the previous method of only doing progressive updates while scrolling.
291 lines
11 KiB
C++
291 lines
11 KiB
C++
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/layers/PLayersChild.h"
|
|
#include "TiledThebesLayerOGL.h"
|
|
#include "ReusableTileStoreOGL.h"
|
|
#include "BasicTiledThebesLayer.h"
|
|
#include "gfxImageSurface.h"
|
|
|
|
namespace mozilla {
|
|
namespace layers {
|
|
|
|
using mozilla::gl::GLContext;
|
|
|
|
TiledLayerBufferOGL::~TiledLayerBufferOGL()
|
|
{
|
|
if (mRetainedTiles.Length() == 0)
|
|
return;
|
|
|
|
mContext->MakeCurrent();
|
|
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
|
if (mRetainedTiles[i] == GetPlaceholderTile())
|
|
continue;
|
|
mContext->fDeleteTextures(1, &mRetainedTiles[i].mTextureHandle);
|
|
}
|
|
}
|
|
|
|
void
|
|
TiledLayerBufferOGL::ReleaseTile(TiledTexture aTile)
|
|
{
|
|
// We've made current prior to calling TiledLayerBufferOGL::Update
|
|
if (aTile == GetPlaceholderTile())
|
|
return;
|
|
mContext->fDeleteTextures(1, &aTile.mTextureHandle);
|
|
}
|
|
|
|
void
|
|
TiledLayerBufferOGL::Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
|
|
const nsIntRegion& aNewValidRegion,
|
|
const nsIntRegion& aInvalidateRegion,
|
|
const gfxSize& aResolution)
|
|
{
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
printf_stderr("Upload %i, %i, %i, %i\n", aInvalidateRegion.GetBounds().x, aInvalidateRegion.GetBounds().y, aInvalidateRegion.GetBounds().width, aInvalidateRegion.GetBounds().height);
|
|
long start = PR_IntervalNow();
|
|
#endif
|
|
|
|
mResolution = aResolution;
|
|
mMainMemoryTiledBuffer = aMainMemoryTiledBuffer;
|
|
mContext->MakeCurrent();
|
|
Update(aNewValidRegion, aInvalidateRegion);
|
|
mMainMemoryTiledBuffer = nullptr;
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
if (PR_IntervalNow() - start > 10) {
|
|
printf_stderr("Time to upload %i\n", PR_IntervalNow() - start);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
TiledLayerBufferOGL::GetFormatAndTileForImageFormat(gfxASurface::gfxImageFormat aFormat,
|
|
GLenum& aOutFormat,
|
|
GLenum& aOutType)
|
|
{
|
|
if (aFormat == gfxASurface::ImageFormatRGB16_565) {
|
|
aOutFormat = LOCAL_GL_RGB;
|
|
aOutType = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
|
|
} else {
|
|
aOutFormat = LOCAL_GL_RGBA;
|
|
aOutType = LOCAL_GL_UNSIGNED_BYTE;
|
|
}
|
|
}
|
|
|
|
TiledTexture
|
|
TiledLayerBufferOGL::ValidateTile(TiledTexture aTile,
|
|
const nsIntPoint& aTileOrigin,
|
|
const nsIntRegion& aDirtyRect)
|
|
{
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
printf_stderr("Upload tile %i, %i\n", aTileOrigin.x, aTileOrigin.y);
|
|
long start = PR_IntervalNow();
|
|
#endif
|
|
if (aTile == GetPlaceholderTile()) {
|
|
mContext->fGenTextures(1, &aTile.mTextureHandle);
|
|
mContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aTile.mTextureHandle);
|
|
mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
|
|
mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
|
|
mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
|
|
mContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
|
|
} else {
|
|
mContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aTile.mTextureHandle);
|
|
}
|
|
|
|
nsRefPtr<gfxReusableSurfaceWrapper> reusableSurface = mMainMemoryTiledBuffer->GetTile(aTileOrigin).mSurface.get();
|
|
GLenum format, type;
|
|
GetFormatAndTileForImageFormat(reusableSurface->Format(), format, type);
|
|
|
|
const unsigned char* buf = reusableSurface->GetReadOnlyData();
|
|
mContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format,
|
|
GetTileLength(), GetTileLength(), 0,
|
|
format, type, buf);
|
|
|
|
aTile.mFormat = format;
|
|
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
if (PR_IntervalNow() - start > 1) {
|
|
printf_stderr("Tile Time to upload %i\n", PR_IntervalNow() - start);
|
|
}
|
|
#endif
|
|
return aTile;
|
|
}
|
|
|
|
TiledThebesLayerOGL::TiledThebesLayerOGL(LayerManagerOGL *aManager)
|
|
: ShadowThebesLayer(aManager, nullptr)
|
|
, LayerOGL(aManager)
|
|
, mVideoMemoryTiledBuffer(aManager->gl())
|
|
, mReusableTileStore(nullptr)
|
|
{
|
|
mImplData = static_cast<LayerOGL*>(this);
|
|
}
|
|
|
|
TiledThebesLayerOGL::~TiledThebesLayerOGL()
|
|
{
|
|
mMainMemoryTiledBuffer.ReadUnlock();
|
|
if (mReusableTileStore)
|
|
delete mReusableTileStore;
|
|
}
|
|
|
|
void
|
|
TiledThebesLayerOGL::PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* mTiledBuffer)
|
|
{
|
|
mMainMemoryTiledBuffer.ReadUnlock();
|
|
mMainMemoryTiledBuffer = *mTiledBuffer;
|
|
// TODO: Remove me once Bug 747811 lands.
|
|
delete mTiledBuffer;
|
|
mRegionToUpload.Or(mRegionToUpload, mMainMemoryTiledBuffer.GetPaintedRegion());
|
|
mMainMemoryTiledBuffer.ClearPaintedRegion();
|
|
}
|
|
|
|
void
|
|
TiledThebesLayerOGL::ProcessUploadQueue()
|
|
{
|
|
if (mRegionToUpload.IsEmpty())
|
|
return;
|
|
|
|
// We should only be retaining old tiles if we're not fixed position.
|
|
// Fixed position layers don't/shouldn't move on the screen, so retaining
|
|
// tiles is not useful and often results in rendering artifacts.
|
|
if (mReusableTileStore && mIsFixedPosition) {
|
|
delete mReusableTileStore;
|
|
mReusableTileStore = nullptr;
|
|
} else if (!mReusableTileStore && !mIsFixedPosition) {
|
|
// XXX Add a pref for reusable tile store size
|
|
mReusableTileStore = new ReusableTileStoreOGL(gl(), 1);
|
|
}
|
|
|
|
gfxSize resolution(1, 1);
|
|
if (mReusableTileStore) {
|
|
// Work out render resolution by multiplying the resolution of our ancestors.
|
|
// Only container layers can have frame metrics, so we start off with a
|
|
// resolution of 1, 1.
|
|
// XXX For large layer trees, it would be faster to do this once from the
|
|
// root node upwards and store the value on each layer.
|
|
for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
|
|
const FrameMetrics& metrics = parent->GetFrameMetrics();
|
|
resolution.width *= metrics.mResolution.width;
|
|
resolution.height *= metrics.mResolution.height;
|
|
}
|
|
|
|
mReusableTileStore->HarvestTiles(this,
|
|
&mVideoMemoryTiledBuffer,
|
|
mVideoMemoryTiledBuffer.GetValidRegion(),
|
|
mMainMemoryTiledBuffer.GetValidRegion(),
|
|
mVideoMemoryTiledBuffer.GetResolution(),
|
|
resolution);
|
|
}
|
|
|
|
// If we coalesce uploads while the layers' valid region is changing we will
|
|
// end up trying to upload area outside of the valid region. (bug 756555)
|
|
mRegionToUpload.And(mRegionToUpload, mMainMemoryTiledBuffer.GetValidRegion());
|
|
|
|
mVideoMemoryTiledBuffer.Upload(&mMainMemoryTiledBuffer,
|
|
mMainMemoryTiledBuffer.GetValidRegion(),
|
|
mRegionToUpload, resolution);
|
|
mValidRegion = mVideoMemoryTiledBuffer.GetValidRegion();
|
|
|
|
mMainMemoryTiledBuffer.ReadUnlock();
|
|
// Release all the tiles by replacing the tile buffer with an empty
|
|
// tiled buffer. This will prevent us from doing a double unlock when
|
|
// calling ~TiledThebesLayerOGL.
|
|
// FIXME: This wont be needed when we do progressive upload and lock
|
|
// tile by tile.
|
|
mMainMemoryTiledBuffer = BasicTiledLayerBuffer();
|
|
mRegionToUpload = nsIntRegion();
|
|
|
|
}
|
|
|
|
void
|
|
TiledThebesLayerOGL::RenderTile(TiledTexture aTile,
|
|
const gfx3DMatrix& aTransform,
|
|
const nsIntPoint& aOffset,
|
|
nsIntRegion aScreenRegion,
|
|
nsIntPoint aTextureOffset,
|
|
nsIntSize aTextureBounds,
|
|
Layer* aMaskLayer)
|
|
{
|
|
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, aTile.mTextureHandle);
|
|
ShaderProgramOGL *program;
|
|
if (aTile.mFormat == LOCAL_GL_RGB) {
|
|
program = mOGLManager->GetProgram(gl::RGBXLayerProgramType, aMaskLayer);
|
|
} else {
|
|
program = mOGLManager->GetProgram(gl::BGRALayerProgramType, aMaskLayer);
|
|
}
|
|
program->Activate();
|
|
program->SetTextureUnit(0);
|
|
program->SetLayerOpacity(GetEffectiveOpacity());
|
|
program->SetLayerTransform(aTransform);
|
|
program->SetRenderOffset(aOffset);
|
|
program->LoadMask(GetMaskLayer());
|
|
|
|
nsIntRegionRectIterator it(aScreenRegion);
|
|
for (const nsIntRect* rect = it.Next(); rect != nullptr; rect = it.Next()) {
|
|
nsIntRect textureRect(rect->x - aTextureOffset.x, rect->y - aTextureOffset.y,
|
|
rect->width, rect->height);
|
|
program->SetLayerQuadRect(*rect);
|
|
mOGLManager->BindAndDrawQuadWithTextureRect(program,
|
|
textureRect,
|
|
aTextureBounds);
|
|
}
|
|
}
|
|
|
|
void
|
|
TiledThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset)
|
|
{
|
|
gl()->MakeCurrent();
|
|
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
|
ProcessUploadQueue();
|
|
|
|
Layer* maskLayer = GetMaskLayer();
|
|
|
|
// Render old tiles to fill in gaps we haven't had the time to render yet.
|
|
if (mReusableTileStore) {
|
|
mReusableTileStore->DrawTiles(this,
|
|
mVideoMemoryTiledBuffer.GetValidRegion(),
|
|
mVideoMemoryTiledBuffer.GetResolution(),
|
|
GetEffectiveTransform(), aOffset, maskLayer);
|
|
}
|
|
|
|
// Render valid tiles.
|
|
const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
|
|
const nsIntRect visibleRect = visibleRegion.GetBounds();
|
|
|
|
uint32_t rowCount = 0;
|
|
uint32_t tileX = 0;
|
|
for (int32_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) {
|
|
rowCount++;
|
|
int32_t tileStartX = mVideoMemoryTiledBuffer.GetTileStart(x);
|
|
int16_t w = mVideoMemoryTiledBuffer.GetTileLength() - tileStartX;
|
|
if (x + w > visibleRect.x + visibleRect.width)
|
|
w = visibleRect.x + visibleRect.width - x;
|
|
int tileY = 0;
|
|
for (int32_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
|
|
int32_t tileStartY = mVideoMemoryTiledBuffer.GetTileStart(y);
|
|
int16_t h = mVideoMemoryTiledBuffer.GetTileLength() - tileStartY;
|
|
if (y + h > visibleRect.y + visibleRect.height)
|
|
h = visibleRect.y + visibleRect.height - y;
|
|
|
|
TiledTexture tileTexture = mVideoMemoryTiledBuffer.
|
|
GetTile(nsIntPoint(mVideoMemoryTiledBuffer.RoundDownToTileEdge(x),
|
|
mVideoMemoryTiledBuffer.RoundDownToTileEdge(y)));
|
|
if (tileTexture != mVideoMemoryTiledBuffer.GetPlaceholderTile()) {
|
|
nsIntRegion tileDrawRegion = nsIntRegion(nsIntRect(x, y, w, h));
|
|
tileDrawRegion.And(tileDrawRegion, mValidRegion);
|
|
|
|
nsIntPoint tileOffset(x - tileStartX, y - tileStartY);
|
|
uint16_t tileSize = mVideoMemoryTiledBuffer.GetTileLength();
|
|
RenderTile(tileTexture, GetEffectiveTransform(), aOffset, tileDrawRegion,
|
|
tileOffset, nsIntSize(tileSize, tileSize), maskLayer);
|
|
}
|
|
tileY++;
|
|
y += h;
|
|
}
|
|
tileX++;
|
|
x += w;
|
|
}
|
|
}
|
|
|
|
} // mozilla
|
|
} // layers
|