зеркало из https://github.com/mozilla/pjs.git
Bug 675908 - Fix TiledTextureImage updates. r=joe,romaxa
TiledTextureImage breaks BeginUpdate/EndUpdate in these cases: - The update is encompassed by more than one tile - The update is encompassed by a single tile that isn't the first tile - The update is a non-rectangular region that covers more than one tile Fixed by using signed instead of unsigned integers in tile loops, correcting an incorrect device offset and correcting the region returned by BeginUpdate.
This commit is contained in:
Родитель
677d76824c
Коммит
5f138b7af9
|
@ -575,20 +575,8 @@ BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
|
|||
NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
|
||||
|
||||
// determine the region the client will need to repaint
|
||||
ImageFormat format =
|
||||
(GetContentType() == gfxASurface::CONTENT_COLOR) ?
|
||||
gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
|
||||
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;
|
||||
}
|
||||
|
||||
aRegion = mUpdateRegion;
|
||||
GetUpdateRegion(aRegion);
|
||||
mUpdateRegion = aRegion;
|
||||
|
||||
nsIntRect rgnSize = mUpdateRegion.GetBounds();
|
||||
if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(rgnSize)) {
|
||||
|
@ -596,7 +584,10 @@ BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
mUpdateSurface =
|
||||
ImageFormat format =
|
||||
(GetContentType() == gfxASurface::CONTENT_COLOR) ?
|
||||
gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
|
||||
mUpdateSurface =
|
||||
GetSurfaceForUpdate(gfxIntSize(rgnSize.width, rgnSize.height), format);
|
||||
|
||||
if (!mUpdateSurface || mUpdateSurface->CairoStatus()) {
|
||||
|
@ -609,6 +600,16 @@ BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
|
|||
return mUpdateSurface;
|
||||
}
|
||||
|
||||
void
|
||||
BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
|
||||
{
|
||||
// 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
|
||||
if (mTextureState != Valid)
|
||||
aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
|
||||
}
|
||||
|
||||
void
|
||||
BasicTextureImage::EndUpdate()
|
||||
{
|
||||
|
@ -729,10 +730,9 @@ 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);
|
||||
nsIntRect bounds = nsIntRect(0, 0, mSize.width, mSize.height);
|
||||
region = nsIntRegion(bounds);
|
||||
} else {
|
||||
region = aRegion;
|
||||
|
@ -740,8 +740,8 @@ TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& 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;
|
||||
int xPos = (i % mColumns) * mTileSize;
|
||||
int yPos = (i / mColumns) * mTileSize;
|
||||
nsIntRegion tileRegion;
|
||||
tileRegion.And(region, nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize())); // intersect with tile
|
||||
if (tileRegion.IsEmpty())
|
||||
|
@ -757,25 +757,66 @@ TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion,
|
|||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
|
||||
{
|
||||
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
|
||||
aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRegion newRegion;
|
||||
|
||||
// We need to query each texture with the region it will be drawing and
|
||||
// set aForRegion to be the combination of all of these regions
|
||||
for (unsigned i = 0; i < mImages.Length(); i++) {
|
||||
int xPos = (i % mColumns) * mTileSize;
|
||||
int yPos = (i / mColumns) * mTileSize;
|
||||
nsIntRect imageRect = nsIntRect(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
|
||||
|
||||
if (aForRegion.Intersects(imageRect)) {
|
||||
// Make a copy of the region
|
||||
nsIntRegion subRegion;
|
||||
subRegion.And(aForRegion, imageRect);
|
||||
// Translate it into tile-space
|
||||
subRegion.MoveBy(-xPos, -yPos);
|
||||
// Query region
|
||||
mImages[i]->GetUpdateRegion(subRegion);
|
||||
// Translate back
|
||||
subRegion.MoveBy(xPos, yPos);
|
||||
// Add to the accumulated region
|
||||
newRegion.Or(newRegion, subRegion);
|
||||
}
|
||||
}
|
||||
|
||||
aForRegion = newRegion;
|
||||
}
|
||||
|
||||
gfxASurface*
|
||||
TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
|
||||
{
|
||||
NS_ASSERTION(!mInUpdate, "nested update");
|
||||
mInUpdate = PR_TRUE;
|
||||
|
||||
// Note, we don't call GetUpdateRegion here as if the updated region is
|
||||
// fully contained in a single tile, we get to avoid iterating through
|
||||
// the tiles again (and a little copying).
|
||||
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;
|
||||
aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
|
||||
}
|
||||
|
||||
nsIntRect bounds = aRegion.GetBounds();
|
||||
|
||||
for (unsigned i = 0; i < mImages.Length(); i++) {
|
||||
unsigned int xPos = (i % mColumns) * mTileSize;
|
||||
unsigned int yPos = (i / mColumns) * mTileSize;
|
||||
int xPos = (i % mColumns) * mTileSize;
|
||||
int yPos = (i / mColumns) * mTileSize;
|
||||
nsIntRegion imageRegion = nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
|
||||
|
||||
// a single Image can handle this update request
|
||||
|
@ -786,6 +827,10 @@ TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
|
|||
nsRefPtr<gfxASurface> surface = mImages[i]->BeginUpdate(aRegion);
|
||||
// caller expects container space
|
||||
aRegion.MoveBy(xPos, yPos);
|
||||
// Correct the device offset
|
||||
gfxPoint offset = surface->GetDeviceOffset();
|
||||
surface->SetDeviceOffset(gfxPoint(offset.x - xPos,
|
||||
offset.y - yPos));
|
||||
// we don't have a temp surface
|
||||
mUpdateSurface = nsnull;
|
||||
// remember which image to EndUpdate
|
||||
|
@ -793,15 +838,21 @@ TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
|
|||
return surface.get();
|
||||
}
|
||||
}
|
||||
|
||||
// Get the real updated region, taking into account the capabilities of
|
||||
// each TextureImage tile
|
||||
GetUpdateRegion(aRegion);
|
||||
mUpdateRegion = aRegion;
|
||||
bounds = aRegion.GetBounds();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -820,9 +871,10 @@ TiledTextureImage::EndUpdate()
|
|||
|
||||
// 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;
|
||||
int xPos = (i % mColumns) * mTileSize;
|
||||
int yPos = (i / mColumns) * mTileSize;
|
||||
nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize());
|
||||
|
||||
nsIntRegion subregion;
|
||||
subregion.And(mUpdateRegion, imageRect);
|
||||
if (subregion.IsEmpty())
|
||||
|
@ -842,6 +894,7 @@ TiledTextureImage::EndUpdate()
|
|||
mInUpdate = PR_FALSE;
|
||||
mShaderType = mImages[0]->GetShaderProgramType();
|
||||
mIsRGBFormat = mImages[0]->IsRGB();
|
||||
mTextureState = Valid;
|
||||
}
|
||||
|
||||
void TiledTextureImage::BeginTileIteration()
|
||||
|
|
|
@ -193,6 +193,15 @@ public:
|
|||
* followed by EndUpdate().
|
||||
*/
|
||||
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion) = 0;
|
||||
/**
|
||||
* Retrieves the region that will require updating, given a
|
||||
* region that needs to be updated. This can be used for
|
||||
* making decisions about updating before calling BeginUpdate().
|
||||
*
|
||||
* |aRegion| is an inout param.
|
||||
*/
|
||||
virtual void GetUpdateRegion(nsIntRegion& aForRegion) {
|
||||
};
|
||||
/**
|
||||
* Finish the active update and synchronize with the server, if
|
||||
* necessary.
|
||||
|
@ -353,6 +362,7 @@ public:
|
|||
virtual void BindTexture(GLenum aTextureUnit);
|
||||
|
||||
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
|
||||
virtual void GetUpdateRegion(nsIntRegion& aForRegion);
|
||||
virtual void EndUpdate();
|
||||
virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0));
|
||||
virtual GLuint GetTextureID() { return mTexture; };
|
||||
|
@ -397,6 +407,7 @@ public:
|
|||
~TiledTextureImage();
|
||||
void DumpDiv();
|
||||
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
|
||||
virtual void GetUpdateRegion(nsIntRegion& aForRegion);
|
||||
virtual void EndUpdate();
|
||||
virtual void Resize(const nsIntSize& aSize);
|
||||
virtual PRUint32 GetTileCount();
|
||||
|
|
|
@ -1221,27 +1221,28 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void GetUpdateRegion(nsIntRegion& aForRegion)
|
||||
{
|
||||
if (mTextureState != Valid) {
|
||||
// if the texture hasn't been initialized yet, force the
|
||||
// client to paint everything
|
||||
aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
|
||||
} else if (!mBackingSurface) {
|
||||
// We can only draw a rectangle, not subregions due to
|
||||
// the way that our texture upload functions work. If
|
||||
// needed, we /could/ do multiple texture uploads if we have
|
||||
// non-overlapping rects, but that's a tradeoff.
|
||||
aForRegion = nsIntRegion(aForRegion.GetBounds());
|
||||
}
|
||||
}
|
||||
|
||||
virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion)
|
||||
{
|
||||
NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
|
||||
|
||||
// determine the region the client will need to repaint
|
||||
if (mTextureState != Valid) {
|
||||
// if the texture hasn't been initialized yet, force the
|
||||
// client to paint everything
|
||||
mUpdateRect = nsIntRect(nsIntPoint(0, 0), mSize);
|
||||
//printf_stderr("v Forcing full paint\n");
|
||||
aRegion = nsIntRegion(mUpdateRect);
|
||||
} else {
|
||||
mUpdateRect = aRegion.GetBounds();
|
||||
if (!mBackingSurface) {
|
||||
// We can only draw a rectangle, not subregions due to
|
||||
// the way that our texture upload functions work. If
|
||||
// needed, we /could/ do multiple texture uploads if we have
|
||||
// non-overlapping rects, but that's a tradeoff.
|
||||
aRegion = nsIntRegion(mUpdateRect);
|
||||
}
|
||||
}
|
||||
GetUpdateRegion(aRegion);
|
||||
mUpdateRect = aRegion.GetBounds();
|
||||
|
||||
//printf_stderr("BeginUpdate with updateRect [%d %d %d %d]\n", mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height);
|
||||
if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(mUpdateRect)) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче