Don't expand displayports beyond the maximum texture size. (bug 1135907, r=kats)

--HG--
extra : rebase_source : 95178166bfb1aac79836808e4e5ebaa123145d9f
This commit is contained in:
dvander@alliedmods.net 2015-03-16 22:59:29 -07:00
parent df118d4a47
commit 9215e781e3

View File

@ -825,6 +825,33 @@ ApplyRectMultiplier(nsRect aRect, float aMultiplier)
return nsRect(ceil(newX), ceil(newY), floor(newWidth), floor(newHeight));
}
// Return the maximum displayport size, based on the LayerManager's maximum
// supported texture size. The result is in app units.
static nscoord
GetMaxDisplayPortSize(nsIContent* aContent)
{
MOZ_ASSERT(!gfxPrefs::LayersTilesEnabled(), "Do not clamp displayports if tiling is enabled");
nsIFrame* frame = aContent->GetPrimaryFrame();
if (!frame) {
return nscoord_MAX;
}
frame = nsLayoutUtils::GetDisplayRootFrame(frame);
nsIWidget* widget = frame->GetNearestWidget();
if (!widget) {
return nscoord_MAX;
}
LayerManager* lm = widget->GetLayerManager();
if (!lm) {
return nscoord_MAX;
}
nsPresContext* presContext = frame->PresContext();
uint32_t maxSizeInDevPixels = lm->GetMaxTextureSize();
return presContext->DevPixelsToAppUnits(maxSizeInDevPixels);
}
static nsRect
GetDisplayPortFromRectData(nsIContent* aContent,
DisplayPortPropertyData* aRectData,
@ -900,24 +927,23 @@ GetDisplayPortFromMarginsData(nsIContent* aContent,
ScreenRect screenRect = LayoutDeviceRect::FromAppUnits(base, auPerDevPixel)
* parentRes;
// Expand the rect by the margins
screenRect.Inflate(aMarginsData->mMargins);
if (gfxPrefs::LayersTilesEnabled()) {
// Note on the correctness of applying the alignment in Screen space:
// The correct space to apply the alignment in would be Layer space, but
// we don't necessarily know the scale to convert to Layer space at this
// point because Layout may not yet have chosen the resolution at which to
// render (it chooses that in FrameLayerBuilder, but this can be called
// during display list building). Therefore, we perform the alignment in
// Screen space, which basically assumes that Layout chose to render at
// screen resolution; since this is what Layout does most of the time,
// this is a good approximation. A proper solution would involve moving
// the choosing of the resolution to display-list building time.
int alignmentX = gfxPlatform::GetPlatform()->GetTileWidth();
int alignmentY = gfxPlatform::GetPlatform()->GetTileHeight();
int alignmentX = gfxPlatform::GetPlatform()->GetTileWidth();
int alignmentY = gfxPlatform::GetPlatform()->GetTileHeight();
// Expand the rect by the margins
screenRect.Inflate(aMarginsData->mMargins);
// And then align it to the requested alignment.
// Note on the correctness of applying the alignment in Screen space:
// The correct space to apply the alignment in would be Layer space, but
// we don't necessarily know the scale to convert to Layer space at this
// point because Layout may not yet have chosen the resolution at which to
// render (it chooses that in FrameLayerBuilder, but this can be called
// during display list building). Therefore, we perform the alignment in
// Screen space, which basically assumes that Layout chose to render at
// screen resolution; since this is what Layout does most of the time,
// this is a good approximation. A proper solution would involve moving the
// choosing of the resolution to display-list building time.
if (gfxPrefs::LayersTilesEnabled() && (alignmentX > 0 && alignmentY > 0)) {
// Inflate the rectangle by 1 so that we always push to the next tile
// boundary. This is desirable to stop from having a rectangle with a
// moving origin occasionally being smaller when it coincidentally lines
@ -942,9 +968,38 @@ GetDisplayPortFromMarginsData(nsIContent* aContent,
float h = alignmentY * ceil(screenRect.YMost() / alignmentY) - y;
screenRect = ScreenRect(x, y, w, h);
screenRect -= scrollPosScreen;
} else {
nscoord maxSizeInAppUnits = GetMaxDisplayPortSize(aContent);
if (maxSizeInAppUnits == nscoord_MAX) {
// Pick a safe maximum displayport size for sanity purposes. This is the
// lowest maximum texture size on tileless-platforms (Windows, D3D10).
maxSizeInAppUnits = presContext->DevPixelsToAppUnits(8192);
}
// Find the maximum size in screen pixels.
int32_t maxSizeInDevPixels = presContext->AppUnitsToDevPixels(maxSizeInAppUnits);
int32_t maxWidthInScreenPixels = floor(double(maxSizeInDevPixels) * res.xScale);
int32_t maxHeightInScreenPixels = floor(double(maxSizeInDevPixels) * res.yScale);
// For each axis, inflate the margins up to the maximum size.
const ScreenMargin& margins = aMarginsData->mMargins;
if (screenRect.height < maxHeightInScreenPixels) {
int32_t budget = maxHeightInScreenPixels - screenRect.height;
int32_t top = std::min(int32_t(margins.top), budget);
screenRect.y -= top;
screenRect.height += top + std::min(int32_t(margins.bottom), budget - top);
}
if (screenRect.width < maxWidthInScreenPixels) {
int32_t budget = maxWidthInScreenPixels - screenRect.width;
int32_t left = std::min(int32_t(margins.left), budget);
screenRect.x -= left;
screenRect.width += left + std::min(int32_t(margins.right), budget - left);
}
}
// Convert the aligned rect back into app units
// Convert the aligned rect back into app units.
nsRect result = LayoutDeviceRect::ToAppUnits(screenRect / res, auPerDevPixel);
// Expand it for the low-res buffer if needed
@ -988,11 +1043,25 @@ GetDisplayPortImpl(nsIContent* aContent, nsRect *aResult, float aMultiplier)
NS_ASSERTION((rectData == nullptr) != (marginsData == nullptr),
"Only one of rectData or marginsData should be set!");
nsRect result;
if (rectData) {
*aResult = GetDisplayPortFromRectData(aContent, rectData, aMultiplier);
result = GetDisplayPortFromRectData(aContent, rectData, aMultiplier);
} else {
*aResult = GetDisplayPortFromMarginsData(aContent, marginsData, aMultiplier);
result = GetDisplayPortFromMarginsData(aContent, marginsData, aMultiplier);
}
if (!gfxPrefs::LayersTilesEnabled()) {
// Either we should have gotten a valid rect directly from the displayport
// base, or we should have computed a valid rect from the margins.
NS_ASSERTION(GetMaxDisplayPortSize(aContent) <= 0 ||
result.width < GetMaxDisplayPortSize(aContent),
"Displayport must be a valid texture size");
NS_ASSERTION(GetMaxDisplayPortSize(aContent) <= 0 ||
result.height < GetMaxDisplayPortSize(aContent),
"Displayport must be a valid texture size");
}
*aResult = result;
return true;
}