|
|
|
|
| 47 |
#include "gfxTeeSurface.h" |
47 |
#include "gfxTeeSurface.h" |
| 48 |
|
48 |
|
| 49 |
namespace mozilla { |
49 |
namespace mozilla { |
| 50 |
namespace layers { |
50 |
namespace layers { |
| 51 |
|
51 |
|
| 52 |
using gl::GLContext; |
52 |
using gl::GLContext; |
| 53 |
using gl::TextureImage; |
53 |
using gl::TextureImage; |
| 54 |
|
54 |
|
|
|
55 |
static const int ALLOW_REPEAT = 0x01; |
| 56 |
|
| 55 |
// BindAndDrawQuadWithTextureRect can work with either GL_REPEAT (preferred) |
57 |
// BindAndDrawQuadWithTextureRect can work with either GL_REPEAT (preferred) |
| 56 |
// or GL_CLAMP_TO_EDGE textures. We select based on whether REPEAT is |
58 |
// or GL_CLAMP_TO_EDGE textures. We select based on whether REPEAT is |
| 57 |
// valid for non-power-of-two textures -- if we have NPOT support we use it, |
59 |
// valid for non-power-of-two textures -- if we have NPOT support we use it, |
| 58 |
// otherwise we stick with CLAMP_TO_EDGE and decompose. |
60 |
// otherwise we stick with CLAMP_TO_EDGE and decompose. |
| 59 |
static already_AddRefed<TextureImage> |
61 |
static already_AddRefed<TextureImage> |
| 60 |
CreateClampOrRepeatTextureImage(GLContext *aGl, |
62 |
CreateClampOrRepeatTextureImage(GLContext *aGl, |
| 61 |
const nsIntSize& aSize, |
63 |
const nsIntSize& aSize, |
| 62 |
TextureImage::ContentType aContentType) |
64 |
TextureImage::ContentType aContentType, |
|
|
65 |
PRUint32 aFlags) |
| 63 |
{ |
66 |
{ |
| 64 |
GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE; |
67 |
GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE; |
| 65 |
if (aGl->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) || |
68 |
if ((aFlags & ALLOW_REPEAT) && |
| 66 |
aGl->IsExtensionSupported(GLContext::OES_texture_npot)) |
69 |
(aGl->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) || |
|
|
70 |
aGl->IsExtensionSupported(GLContext::OES_texture_npot))) |
| 67 |
{ |
71 |
{ |
| 68 |
wrapMode = LOCAL_GL_REPEAT; |
72 |
wrapMode = LOCAL_GL_REPEAT; |
| 69 |
} |
73 |
} |
| 70 |
|
74 |
|
| 71 |
return aGl->CreateTextureImage(aSize, aContentType, wrapMode); |
75 |
return aGl->CreateTextureImage(aSize, aContentType, wrapMode); |
| 72 |
} |
76 |
} |
| 73 |
|
77 |
|
| 74 |
// |aTexCoordRect| is the rectangle from the texture that we want to |
78 |
// |aTexCoordRect| is the rectangle from the texture that we want to |
|
|
| 151 |
typedef ThebesLayerBuffer::PaintState PaintState; |
155 |
typedef ThebesLayerBuffer::PaintState PaintState; |
| 152 |
|
156 |
|
| 153 |
ThebesLayerBufferOGL(ThebesLayer* aLayer, LayerOGL* aOGLLayer) |
157 |
ThebesLayerBufferOGL(ThebesLayer* aLayer, LayerOGL* aOGLLayer) |
| 154 |
: mLayer(aLayer) |
158 |
: mLayer(aLayer) |
| 155 |
, mOGLLayer(aOGLLayer) |
159 |
, mOGLLayer(aOGLLayer) |
| 156 |
{} |
160 |
{} |
| 157 |
virtual ~ThebesLayerBufferOGL() {} |
161 |
virtual ~ThebesLayerBufferOGL() {} |
| 158 |
|
162 |
|
|
|
163 |
virtual void SetEnableRotationOptimization(PRBool aEnable) = 0; |
| 164 |
|
| 159 |
virtual PaintState BeginPaint(ContentType aContentType, |
165 |
virtual PaintState BeginPaint(ContentType aContentType, |
|
|
166 |
const nsIntRegion& aNeededRegion, |
| 160 |
float aXResolution, |
167 |
float aXResolution, |
| 161 |
float aYResolution) = 0; |
168 |
float aYResolution) = 0; |
| 162 |
|
169 |
|
| 163 |
void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager); |
170 |
void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager); |
| 164 |
|
171 |
|
| 165 |
nsIntSize GetSize() { |
172 |
nsIntSize GetSize() { |
| 166 |
if (mTexImage) |
173 |
if (mTexImage) |
| 167 |
return mTexImage->GetSize(); |
174 |
return mTexImage->GetSize(); |
|
Lines 228-244
ThebesLayerBufferOGL::RenderTo(const nsI
|
Link Here
|
|---|
|
| 228 |
DEBUG_GL_ERROR_CHECK(gl()); |
235 |
DEBUG_GL_ERROR_CHECK(gl()); |
| 229 |
alphaProgram->SetBlackTextureUnit(0); |
236 |
alphaProgram->SetBlackTextureUnit(0); |
| 230 |
alphaProgram->SetWhiteTextureUnit(1); |
237 |
alphaProgram->SetWhiteTextureUnit(1); |
| 231 |
program = alphaProgram; |
238 |
program = alphaProgram; |
| 232 |
} else { |
239 |
} else { |
| 233 |
// Note BGR: Cairo's image surfaces are always in what |
240 |
// Note BGR: Cairo's image surfaces are always in what |
| 234 |
// OpenGL and our shaders consider BGR format. |
241 |
// OpenGL and our shaders consider BGR format. |
| 235 |
ColorTextureLayerProgram *basicProgram = |
242 |
ColorTextureLayerProgram *basicProgram = |
| 236 |
aManager->GetBasicLayerProgram(mLayer->CanUseOpaqueSurface(), |
243 |
aManager->GetBasicLayerProgram(mTexImage->GetContentType() == gfxASurface::CONTENT_COLOR, |
| 237 |
mTexImage->IsRGB()); |
244 |
mTexImage->IsRGB()); |
| 238 |
|
245 |
|
| 239 |
basicProgram->Activate(); |
246 |
basicProgram->Activate(); |
| 240 |
DEBUG_GL_ERROR_CHECK(gl()); |
247 |
DEBUG_GL_ERROR_CHECK(gl()); |
| 241 |
basicProgram->SetTextureUnit(0); |
248 |
basicProgram->SetTextureUnit(0); |
| 242 |
program = basicProgram; |
249 |
program = basicProgram; |
| 243 |
} |
250 |
} |
| 244 |
|
251 |
|
|
|
| 286 |
|
293 |
|
| 287 |
SurfaceBufferOGL(ThebesLayerOGL* aLayer) |
294 |
SurfaceBufferOGL(ThebesLayerOGL* aLayer) |
| 288 |
: ThebesLayerBufferOGL(aLayer, aLayer) |
295 |
: ThebesLayerBufferOGL(aLayer, aLayer) |
| 289 |
, ThebesLayerBuffer(SizedToVisibleBounds) |
296 |
, ThebesLayerBuffer(SizedToVisibleBounds) |
| 290 |
{ |
297 |
{ |
| 291 |
} |
298 |
} |
| 292 |
virtual ~SurfaceBufferOGL() {} |
299 |
virtual ~SurfaceBufferOGL() {} |
| 293 |
|
300 |
|
|
|
301 |
virtual void SetEnableRotationOptimization(PRBool aEnable) |
| 302 |
{ |
| 303 |
ThebesLayerBuffer::SetEnableRotationOptimization(aEnable); |
| 304 |
} |
| 305 |
|
| 294 |
// ThebesLayerBufferOGL interface |
306 |
// ThebesLayerBufferOGL interface |
| 295 |
virtual PaintState BeginPaint(ContentType aContentType, |
307 |
virtual PaintState BeginPaint(ContentType aContentType, |
| 296 |
float aXResolution, |
308 |
const nsIntRegion& aNeededRegion, |
|
|
309 |
float aXResolution, |
| 297 |
float aYResolution) |
310 |
float aYResolution) |
| 298 |
{ |
311 |
{ |
| 299 |
// Let ThebesLayerBuffer do all the hard work for us! :D |
312 |
// Let ThebesLayerBuffer do all the hard work for us! :D |
| 300 |
return ThebesLayerBuffer::BeginPaint(mLayer, |
313 |
return ThebesLayerBuffer::BeginPaint(mLayer, |
| 301 |
aContentType, |
314 |
aContentType, |
|
|
315 |
aNeededRegion, |
| 302 |
aXResolution, |
316 |
aXResolution, |
| 303 |
aYResolution); |
317 |
aYResolution); |
| 304 |
} |
318 |
} |
| 305 |
|
319 |
|
| 306 |
// ThebesLayerBuffer interface |
320 |
// ThebesLayerBuffer interface |
| 307 |
virtual already_AddRefed<gfxASurface> |
321 |
virtual already_AddRefed<gfxASurface> |
| 308 |
CreateBuffer(ContentType aType, const nsIntSize& aSize) |
322 |
CreateBuffer(ContentType aType, const nsIntSize& aSize) |
| 309 |
{ |
323 |
{ |
| 310 |
NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color"); |
324 |
NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color"); |
| 311 |
|
325 |
|
| 312 |
mTexImage = CreateClampOrRepeatTextureImage(gl(), aSize, aType); |
326 |
mTexImage = CreateClampOrRepeatTextureImage(gl(), aSize, aType, |
|
|
327 |
mEnableRotationOptimization ? ALLOW_REPEAT : 0); |
| 313 |
return mTexImage ? mTexImage->GetBackingSurface() : nsnull; |
328 |
return mTexImage ? mTexImage->GetBackingSurface() : nsnull; |
| 314 |
} |
329 |
} |
| 315 |
|
330 |
|
| 316 |
protected: |
331 |
protected: |
| 317 |
virtual nsIntPoint GetOriginOffset() { |
332 |
virtual nsIntPoint GetOriginOffset() { |
| 318 |
return BufferRect().TopLeft() - BufferRotation(); |
333 |
return BufferRect().TopLeft() - BufferRotation(); |
| 319 |
} |
334 |
} |
| 320 |
}; |
335 |
}; |
|
|
| 326 |
// and implementing them here using GL hacketry. |
341 |
// and implementing them here using GL hacketry. |
| 327 |
class BasicBufferOGL : public ThebesLayerBufferOGL |
342 |
class BasicBufferOGL : public ThebesLayerBufferOGL |
| 328 |
{ |
343 |
{ |
| 329 |
public: |
344 |
public: |
| 330 |
BasicBufferOGL(ThebesLayerOGL* aLayer) |
345 |
BasicBufferOGL(ThebesLayerOGL* aLayer) |
| 331 |
: ThebesLayerBufferOGL(aLayer, aLayer) |
346 |
: ThebesLayerBufferOGL(aLayer, aLayer) |
| 332 |
, mBufferRect(0,0,0,0) |
347 |
, mBufferRect(0,0,0,0) |
| 333 |
, mBufferRotation(0,0) |
348 |
, mBufferRotation(0,0) |
|
|
349 |
, mEnableRotationOptimization(PR_FALSE) |
| 334 |
{} |
350 |
{} |
| 335 |
virtual ~BasicBufferOGL() {} |
351 |
virtual ~BasicBufferOGL() {} |
| 336 |
|
352 |
|
|
|
353 |
virtual void SetEnableRotationOptimization(PRBool aEnable) |
| 354 |
{ |
| 355 |
mEnableRotationOptimization = aEnable; |
| 356 |
} |
| 337 |
virtual PaintState BeginPaint(ContentType aContentType, |
357 |
virtual PaintState BeginPaint(ContentType aContentType, |
|
|
358 |
const nsIntRegion& aNeededRegion, |
| 338 |
float aXResolution, |
359 |
float aXResolution, |
| 339 |
float aYResolution); |
360 |
float aYResolution); |
| 340 |
|
361 |
|
| 341 |
protected: |
362 |
protected: |
| 342 |
enum XSide { |
363 |
enum XSide { |
| 343 |
LEFT, RIGHT |
364 |
LEFT, RIGHT |
| 344 |
}; |
365 |
}; |
| 345 |
enum YSide { |
366 |
enum YSide { |
|
|
| 349 |
|
370 |
|
| 350 |
virtual nsIntPoint GetOriginOffset() { |
371 |
virtual nsIntPoint GetOriginOffset() { |
| 351 |
return mBufferRect.TopLeft() - mBufferRotation; |
372 |
return mBufferRect.TopLeft() - mBufferRotation; |
| 352 |
} |
373 |
} |
| 353 |
|
374 |
|
| 354 |
private: |
375 |
private: |
| 355 |
nsIntRect mBufferRect; |
376 |
nsIntRect mBufferRect; |
| 356 |
nsIntPoint mBufferRotation; |
377 |
nsIntPoint mBufferRotation; |
|
|
378 |
PRPackedBool mEnableRotationOptimization; |
| 357 |
}; |
379 |
}; |
| 358 |
|
380 |
|
| 359 |
static void |
381 |
static void |
| 360 |
WrapRotationAxis(PRInt32* aRotationPoint, PRInt32 aSize) |
382 |
WrapRotationAxis(PRInt32* aRotationPoint, PRInt32 aSize) |
| 361 |
{ |
383 |
{ |
| 362 |
if (*aRotationPoint < 0) { |
384 |
if (*aRotationPoint < 0) { |
| 363 |
*aRotationPoint += aSize; |
385 |
*aRotationPoint += aSize; |
| 364 |
} else if (*aRotationPoint >= aSize) { |
386 |
} else if (*aRotationPoint >= aSize) { |
|
Lines 397-513
ScaledSize(const nsIntSize& aSize, float
|
Link Here
|
|---|
|
| 397 |
|
419 |
|
| 398 |
nsIntRect rect(0, 0, aSize.width, aSize.height); |
420 |
nsIntRect rect(0, 0, aSize.width, aSize.height); |
| 399 |
rect.ScaleRoundOut(aXScale, aYScale); |
421 |
rect.ScaleRoundOut(aXScale, aYScale); |
| 400 |
return rect.Size(); |
422 |
return rect.Size(); |
| 401 |
} |
423 |
} |
| 402 |
|
424 |
|
| 403 |
BasicBufferOGL::PaintState |
425 |
BasicBufferOGL::PaintState |
| 404 |
BasicBufferOGL::BeginPaint(ContentType aContentType, |
426 |
BasicBufferOGL::BeginPaint(ContentType aContentType, |
|
|
427 |
const nsIntRegion& aNeededRegion, |
| 405 |
float aXResolution, |
428 |
float aXResolution, |
| 406 |
float aYResolution) |
429 |
float aYResolution) |
| 407 |
{ |
430 |
{ |
| 408 |
PaintState result; |
431 |
PaintState result; |
| 409 |
|
432 |
|
| 410 |
result.mRegionToDraw.Sub(mLayer->GetVisibleRegion(), mLayer->GetValidRegion()); |
433 |
result.mRegionToDraw.Sub(aNeededRegion, mLayer->GetValidRegion()); |
| 411 |
|
434 |
|
| 412 |
float curXRes = mLayer->GetXResolution(); |
435 |
float curXRes = mLayer->GetXResolution(); |
| 413 |
float curYRes = mLayer->GetYResolution(); |
436 |
float curYRes = mLayer->GetYResolution(); |
| 414 |
Layer::SurfaceMode mode = mLayer->GetSurfaceMode(); |
437 |
Layer::SurfaceMode mode = mLayer->GetSurfaceMode(); |
| 415 |
|
438 |
|
| 416 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
439 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
| 417 |
#ifdef MOZ_GFX_OPTIMIZE_MOBILE |
440 |
#ifdef MOZ_GFX_OPTIMIZE_MOBILE |
| 418 |
mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA; |
441 |
mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA; |
| 419 |
#else |
442 |
#else |
| 420 |
if (!mLayer->GetParent() || !mLayer->GetParent()->SupportsComponentAlphaChildren()) { |
443 |
if (!mLayer->GetParent() || !mLayer->GetParent()->SupportsComponentAlphaChildren()) { |
| 421 |
mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA; |
444 |
mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA; |
| 422 |
} else { |
445 |
} else { |
| 423 |
aContentType = gfxASurface::CONTENT_COLOR; |
446 |
aContentType = gfxASurface::CONTENT_COLOR; |
| 424 |
} |
447 |
} |
| 425 |
#endif |
448 |
#endif |
| 426 |
} |
449 |
} |
|
|
450 |
if (mode == Layer::SURFACE_OPAQUE && aContentType == gfxASurface::CONTENT_COLOR_ALPHA) { |
| 451 |
// The caller may be forcing us to use an RGBA texture |
| 452 |
mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA; |
| 453 |
} |
| 427 |
|
454 |
|
| 428 |
if (!mTexImage || mTexImage->GetContentType() != aContentType || |
455 |
if (!mTexImage || mTexImage->GetContentType() != aContentType || |
| 429 |
aXResolution != curXRes || aYResolution != curYRes || |
456 |
aXResolution != curXRes || aYResolution != curYRes || |
| 430 |
(mode == Layer::SURFACE_COMPONENT_ALPHA) != (mTexImageOnWhite != nsnull)) { |
457 |
(mode == Layer::SURFACE_COMPONENT_ALPHA) != (mTexImageOnWhite != nsnull)) { |
| 431 |
// We're effectively clearing the valid region, so we need to draw |
458 |
// We're effectively clearing the valid region, so we need to draw |
| 432 |
// the entire visible region now. |
459 |
// the entire needed region now. |
| 433 |
// |
460 |
// |
| 434 |
// XXX/cjones: a possibly worthwhile optimization to keep in mind |
461 |
// XXX/cjones: a possibly worthwhile optimization to keep in mind |
| 435 |
// is to re-use buffers when the resolution and visible region |
462 |
// is to re-use buffers when the resolution and visible region |
| 436 |
// have changed in such a way that the buffer size stays the same. |
463 |
// have changed in such a way that the buffer size stays the same. |
| 437 |
// It might make even more sense to allocate buffers from a |
464 |
// It might make even more sense to allocate buffers from a |
| 438 |
// recyclable pool, so that we could keep this logic simple and |
465 |
// recyclable pool, so that we could keep this logic simple and |
| 439 |
// still get back the same buffer. |
466 |
// still get back the same buffer. |
| 440 |
result.mRegionToDraw = mLayer->GetVisibleRegion(); |
467 |
result.mRegionToDraw = aNeededRegion; |
| 441 |
result.mRegionToInvalidate = mLayer->GetValidRegion(); |
468 |
result.mRegionToInvalidate = mLayer->GetValidRegion(); |
| 442 |
mTexImage = nsnull; |
469 |
mTexImage = nsnull; |
| 443 |
mTexImageOnWhite = nsnull; |
470 |
mTexImageOnWhite = nsnull; |
| 444 |
mBufferRect.SetRect(0, 0, 0, 0); |
471 |
mBufferRect.SetRect(0, 0, 0, 0); |
| 445 |
mBufferRotation.MoveTo(0, 0); |
472 |
mBufferRotation.MoveTo(0, 0); |
| 446 |
} |
473 |
} |
| 447 |
|
474 |
|
| 448 |
if (result.mRegionToDraw.IsEmpty()) |
475 |
if (result.mRegionToDraw.IsEmpty()) |
| 449 |
return result; |
476 |
return result; |
| 450 |
|
477 |
|
| 451 |
nsIntRect visibleBounds = mLayer->GetVisibleRegion().GetBounds(); |
478 |
nsIntRect neededBounds = aNeededRegion.GetBounds(); |
| 452 |
nsIntRect drawBounds = result.mRegionToDraw.GetBounds(); |
479 |
nsIntRect drawBounds = result.mRegionToDraw.GetBounds(); |
| 453 |
nsIntSize destBufferDims = ScaledSize(visibleBounds.Size(), |
480 |
nsIntSize destBufferDims = ScaledSize(neededBounds.Size(), |
| 454 |
aXResolution, aYResolution); |
481 |
aXResolution, aYResolution); |
| 455 |
|
482 |
|
| 456 |
if (destBufferDims.width > gl()->GetMaxTextureSize() || |
483 |
if (destBufferDims.width > gl()->GetMaxTextureSize() || |
| 457 |
destBufferDims.height > gl()->GetMaxTextureSize()) { |
484 |
destBufferDims.height > gl()->GetMaxTextureSize()) { |
| 458 |
return result; |
485 |
return result; |
| 459 |
} |
486 |
} |
| 460 |
|
487 |
|
| 461 |
nsRefPtr<TextureImage> destBuffer; |
488 |
nsRefPtr<TextureImage> destBuffer; |
| 462 |
nsRefPtr<TextureImage> destBufferOnWhite; |
489 |
nsRefPtr<TextureImage> destBufferOnWhite; |
| 463 |
nsIntRect destBufferRect; |
490 |
nsIntRect destBufferRect; |
|
|
491 |
PRUint32 textureFlags = mEnableRotationOptimization ? ALLOW_REPEAT : 0; |
| 464 |
|
492 |
|
| 465 |
if (visibleBounds.Size() <= mBufferRect.Size()) { |
493 |
if (neededBounds.Size() <= mBufferRect.Size() && |
|
|
494 |
mTexImage && |
| 495 |
(mTexImage->GetWrapMode() == LOCAL_GL_CLAMP_TO_EDGE || mEnableRotationOptimization)) { |
| 466 |
NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution, |
496 |
NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution, |
| 467 |
"resolution changes must clear the buffer!"); |
497 |
"resolution changes must clear the buffer!"); |
| 468 |
// The current buffer is big enough to hold the visible area. |
498 |
// The current buffer is big enough to hold the visible area. |
| 469 |
if (mBufferRect.Contains(visibleBounds)) { |
499 |
if (mBufferRect.Contains(neededBounds)) { |
| 470 |
// We don't need to adjust mBufferRect. |
500 |
// We don't need to adjust mBufferRect. |
| 471 |
destBufferRect = mBufferRect; |
501 |
destBufferRect = mBufferRect; |
| 472 |
} else { |
502 |
} else { |
| 473 |
// The buffer's big enough but doesn't contain everything that's |
503 |
// The buffer's big enough but doesn't contain everything that's |
| 474 |
// going to be visible. We'll move it. |
504 |
// going to be visible. We'll move it. |
| 475 |
destBufferRect = nsIntRect(visibleBounds.TopLeft(), mBufferRect.Size()); |
505 |
destBufferRect = nsIntRect(neededBounds.TopLeft(), mBufferRect.Size()); |
| 476 |
} |
506 |
} |
| 477 |
nsIntRect keepArea; |
507 |
nsIntRect keepArea; |
| 478 |
if (keepArea.IntersectRect(destBufferRect, mBufferRect)) { |
508 |
if (keepArea.IntersectRect(destBufferRect, mBufferRect)) { |
| 479 |
// Set mBufferRotation so that the pixels currently in mBuffer |
509 |
// Set mBufferRotation so that the pixels currently in mBuffer |
| 480 |
// will still be rendered in the right place when mBufferRect |
510 |
// will still be rendered in the right place when mBufferRect |
| 481 |
// changes to destBufferRect. |
511 |
// changes to destBufferRect. |
| 482 |
nsIntPoint newRotation = mBufferRotation + |
512 |
nsIntPoint newRotation = mBufferRotation + |
| 483 |
(destBufferRect.TopLeft() - mBufferRect.TopLeft()); |
513 |
(destBufferRect.TopLeft() - mBufferRect.TopLeft()); |
| 484 |
WrapRotationAxis(&newRotation.x, mBufferRect.width); |
514 |
WrapRotationAxis(&newRotation.x, mBufferRect.width); |
| 485 |
WrapRotationAxis(&newRotation.y, mBufferRect.height); |
515 |
WrapRotationAxis(&newRotation.y, mBufferRect.height); |
| 486 |
NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation), |
516 |
NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation), |
| 487 |
"newRotation out of bounds"); |
517 |
"newRotation out of bounds"); |
| 488 |
PRInt32 xBoundary = destBufferRect.XMost() - newRotation.x; |
518 |
PRInt32 xBoundary = destBufferRect.XMost() - newRotation.x; |
| 489 |
PRInt32 yBoundary = destBufferRect.YMost() - newRotation.y; |
519 |
PRInt32 yBoundary = destBufferRect.YMost() - newRotation.y; |
| 490 |
if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) || |
520 |
if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) || |
| 491 |
(drawBounds.y < yBoundary && yBoundary < drawBounds.YMost())) { |
521 |
(drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) || |
|
|
522 |
(!mEnableRotationOptimization && newRotation != nsIntPoint(0,0))) { |
| 492 |
// The stuff we need to redraw will wrap around an edge of the |
523 |
// The stuff we need to redraw will wrap around an edge of the |
| 493 |
// buffer, so we will need to do a self-copy |
524 |
// buffer, so we will need to do a self-copy |
| 494 |
// If mBufferRotation == nsIntPoint(0,0) we could do a real |
525 |
// If mBufferRotation == nsIntPoint(0,0) we could do a real |
| 495 |
// self-copy but we're not going to do that in GL yet. |
526 |
// self-copy but we're not going to do that in GL yet. |
| 496 |
// We can't do a real self-copy because the buffer is rotated. |
527 |
// We can't do a real self-copy because the buffer is rotated. |
| 497 |
// So allocate a new buffer for the destination. |
528 |
// So allocate a new buffer for the destination. |
| 498 |
destBufferRect = visibleBounds; |
529 |
destBufferRect = neededBounds; |
| 499 |
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); |
530 |
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); |
| 500 |
DEBUG_GL_ERROR_CHECK(gl()); |
531 |
DEBUG_GL_ERROR_CHECK(gl()); |
| 501 |
if (!destBuffer) |
532 |
if (!destBuffer) |
| 502 |
return result; |
533 |
return result; |
| 503 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
534 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
| 504 |
destBufferOnWhite = |
535 |
destBufferOnWhite = |
| 505 |
CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); |
536 |
CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); |
| 506 |
DEBUG_GL_ERROR_CHECK(gl()); |
537 |
DEBUG_GL_ERROR_CHECK(gl()); |
| 507 |
if (!destBufferOnWhite) |
538 |
if (!destBufferOnWhite) |
| 508 |
return result; |
539 |
return result; |
| 509 |
} |
540 |
} |
| 510 |
} else { |
541 |
} else { |
| 511 |
mBufferRect = destBufferRect; |
542 |
mBufferRect = destBufferRect; |
| 512 |
mBufferRotation = newRotation; |
543 |
mBufferRotation = newRotation; |
| 513 |
} |
544 |
} |
|
Lines 515-539
BasicBufferOGL::BeginPaint(ContentType a
|
Link Here
|
|---|
|
| 515 |
// No pixels are going to be kept. The whole visible region |
546 |
// No pixels are going to be kept. The whole visible region |
| 516 |
// will be redrawn, so we don't need to copy anything, so we don't |
547 |
// will be redrawn, so we don't need to copy anything, so we don't |
| 517 |
// set destBuffer. |
548 |
// set destBuffer. |
| 518 |
mBufferRect = destBufferRect; |
549 |
mBufferRect = destBufferRect; |
| 519 |
mBufferRotation = nsIntPoint(0,0); |
550 |
mBufferRotation = nsIntPoint(0,0); |
| 520 |
} |
551 |
} |
| 521 |
} else { |
552 |
} else { |
| 522 |
// The buffer's not big enough, so allocate a new one |
553 |
// The buffer's not big enough, so allocate a new one |
| 523 |
destBufferRect = visibleBounds; |
554 |
destBufferRect = neededBounds; |
| 524 |
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); |
555 |
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); |
| 525 |
DEBUG_GL_ERROR_CHECK(gl()); |
556 |
DEBUG_GL_ERROR_CHECK(gl()); |
| 526 |
if (!destBuffer) |
557 |
if (!destBuffer) |
| 527 |
return result; |
558 |
return result; |
| 528 |
|
559 |
|
| 529 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
560 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
| 530 |
destBufferOnWhite = |
561 |
destBufferOnWhite = |
| 531 |
CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); |
562 |
CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); |
| 532 |
DEBUG_GL_ERROR_CHECK(gl()); |
563 |
DEBUG_GL_ERROR_CHECK(gl()); |
| 533 |
if (!destBufferOnWhite) |
564 |
if (!destBufferOnWhite) |
| 534 |
return result; |
565 |
return result; |
| 535 |
} |
566 |
} |
| 536 |
} |
567 |
} |
| 537 |
|
568 |
|
| 538 |
if (!destBuffer && !mTexImage) { |
569 |
if (!destBuffer && !mTexImage) { |
| 539 |
return result; |
570 |
return result; |
|
Lines 560-591
BasicBufferOGL::BeginPaint(ContentType a
|
Link Here
|
|---|
|
| 560 |
destBuffer, dstRect); |
591 |
destBuffer, dstRect); |
| 561 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
592 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
| 562 |
destBufferOnWhite->Resize(size); |
593 |
destBufferOnWhite->Resize(size); |
| 563 |
gl()->BlitTextureImage(mTexImageOnWhite, srcRect, |
594 |
gl()->BlitTextureImage(mTexImageOnWhite, srcRect, |
| 564 |
destBufferOnWhite, dstRect); |
595 |
destBufferOnWhite, dstRect); |
| 565 |
} |
596 |
} |
| 566 |
} else { |
597 |
} else { |
| 567 |
// can't blit, just draw everything |
598 |
// can't blit, just draw everything |
| 568 |
destBufferRect = visibleBounds; |
599 |
destBufferRect = neededBounds; |
| 569 |
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); |
600 |
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); |
| 570 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
601 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
| 571 |
destBufferOnWhite = |
602 |
destBufferOnWhite = |
| 572 |
CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType); |
603 |
CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType, textureFlags); |
| 573 |
} |
604 |
} |
| 574 |
} |
605 |
} |
| 575 |
} |
606 |
} |
| 576 |
|
607 |
|
| 577 |
mTexImage = destBuffer.forget(); |
608 |
mTexImage = destBuffer.forget(); |
| 578 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
609 |
if (mode == Layer::SURFACE_COMPONENT_ALPHA) { |
| 579 |
mTexImageOnWhite = destBufferOnWhite.forget(); |
610 |
mTexImageOnWhite = destBufferOnWhite.forget(); |
| 580 |
} |
611 |
} |
| 581 |
mBufferRect = destBufferRect; |
612 |
mBufferRect = destBufferRect; |
| 582 |
mBufferRotation = nsIntPoint(0,0); |
613 |
mBufferRotation = nsIntPoint(0,0); |
| 583 |
} |
614 |
} |
|
|
615 |
NS_ASSERTION(mEnableRotationOptimization || mBufferRotation == nsIntPoint(0,0), |
| 616 |
"Rotation disabled, but we have nonzero rotation?"); |
| 584 |
|
617 |
|
| 585 |
nsIntRegion invalidate; |
618 |
nsIntRegion invalidate; |
| 586 |
invalidate.Sub(mLayer->GetValidRegion(), destBufferRect); |
619 |
invalidate.Sub(mLayer->GetValidRegion(), destBufferRect); |
| 587 |
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate); |
620 |
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate); |
| 588 |
|
621 |
|
| 589 |
// Figure out which quadrant to draw in |
622 |
// Figure out which quadrant to draw in |
| 590 |
PRInt32 xBoundary = mBufferRect.XMost() - mBufferRotation.x; |
623 |
PRInt32 xBoundary = mBufferRect.XMost() - mBufferRotation.x; |
| 591 |
PRInt32 yBoundary = mBufferRect.YMost() - mBufferRotation.y; |
624 |
PRInt32 yBoundary = mBufferRect.YMost() - mBufferRotation.y; |
|
Lines 625-641
BasicBufferOGL::BeginPaint(ContentType a
|
Link Here
|
|---|
|
| 625 |
// be incorrect. |
658 |
// be incorrect. |
| 626 |
surf->SetAllowUseAsSource(PR_FALSE); |
659 |
surf->SetAllowUseAsSource(PR_FALSE); |
| 627 |
result.mContext = new gfxContext(surf); |
660 |
result.mContext = new gfxContext(surf); |
| 628 |
} else { |
661 |
} else { |
| 629 |
result.mContext = new gfxContext(mTexImage->BeginUpdate(result.mRegionToDraw)); |
662 |
result.mContext = new gfxContext(mTexImage->BeginUpdate(result.mRegionToDraw)); |
| 630 |
if (mTexImage->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) { |
663 |
if (mTexImage->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) { |
| 631 |
gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw); |
664 |
gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw); |
| 632 |
result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR); |
665 |
result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR); |
| 633 |
result.mContext->Fill(); |
666 |
result.mContext->Paint(); |
| 634 |
result.mContext->SetOperator(gfxContext::OPERATOR_OVER); |
667 |
result.mContext->SetOperator(gfxContext::OPERATOR_OVER); |
| 635 |
} |
668 |
} |
| 636 |
} |
669 |
} |
| 637 |
if (!result.mContext) { |
670 |
if (!result.mContext) { |
| 638 |
NS_WARNING("unable to get context for update"); |
671 |
NS_WARNING("unable to get context for update"); |
| 639 |
return result; |
672 |
return result; |
| 640 |
} |
673 |
} |
| 641 |
result.mContext->Scale(aXResolution, aYResolution); |
674 |
result.mContext->Scale(aXResolution, aYResolution); |
|
Lines 719-763
ThebesLayerOGL::RenderLayer(int aPreviou
|
Link Here
|
|---|
|
| 719 |
mOGLManager->MakeCurrent(); |
752 |
mOGLManager->MakeCurrent(); |
| 720 |
gl()->fActiveTexture(LOCAL_GL_TEXTURE0); |
753 |
gl()->fActiveTexture(LOCAL_GL_TEXTURE0); |
| 721 |
|
754 |
|
| 722 |
TextureImage::ContentType contentType = |
755 |
TextureImage::ContentType contentType = |
| 723 |
CanUseOpaqueSurface() ? gfxASurface::CONTENT_COLOR : |
756 |
CanUseOpaqueSurface() ? gfxASurface::CONTENT_COLOR : |
| 724 |
gfxASurface::CONTENT_COLOR_ALPHA; |
757 |
gfxASurface::CONTENT_COLOR_ALPHA; |
| 725 |
|
758 |
|
| 726 |
const gfx3DMatrix& transform = GetEffectiveTransform(); |
759 |
const gfx3DMatrix& transform = GetEffectiveTransform(); |
|
|
760 |
nsIntRegion neededRegion = mVisibleRegion; |
| 727 |
gfxMatrix transform2d; |
761 |
gfxMatrix transform2d; |
| 728 |
gfxSize scale(1.0, 1.0); |
762 |
gfxSize scale(1.0, 1.0); |
|
|
763 |
float paintXRes = 1.0; |
| 764 |
float paintYRes = 1.0; |
| 765 |
bool willResample; |
| 729 |
if (transform.Is2D(&transform2d)) { |
766 |
if (transform.Is2D(&transform2d)) { |
| 730 |
scale = transform2d.ScaleFactors(PR_TRUE); |
767 |
scale = transform2d.ScaleFactors(PR_TRUE); |
|
|
768 |
paintXRes = gfxUtils::ClampToScaleFactor(scale.width); |
| 769 |
paintYRes = gfxUtils::ClampToScaleFactor(scale.height); |
| 770 |
transform2d.Scale(1.0/paintXRes, 1.0/paintYRes); |
| 771 |
willResample = transform2d.HasNonIntegerTranslation(); |
| 772 |
} else { |
| 773 |
willResample = true; |
| 731 |
} |
774 |
} |
| 732 |
float paintXRes = gfxUtils::ClampToScaleFactor(scale.width); |
775 |
if (willResample && neededRegion.GetNumRects() > 1) { |
| 733 |
float paintYRes = gfxUtils::ClampToScaleFactor(scale.height); |
776 |
neededRegion = mVisibleRegion.GetBounds(); |
|
|
777 |
contentType = gfxASurface::CONTENT_COLOR_ALPHA; |
| 778 |
} |
| 734 |
|
779 |
|
| 735 |
Buffer::PaintState state = mBuffer->BeginPaint(contentType, paintXRes, paintYRes); |
780 |
mBuffer->SetEnableRotationOptimization(!willResample); |
|
|
781 |
Buffer::PaintState state = |
| 782 |
mBuffer->BeginPaint(contentType, neededRegion, paintXRes, paintYRes); |
| 736 |
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); |
783 |
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); |
| 737 |
|
784 |
|
| 738 |
if (state.mContext) { |
785 |
if (state.mContext) { |
| 739 |
state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion); |
786 |
state.mRegionToInvalidate.And(state.mRegionToInvalidate, neededRegion); |
| 740 |
mXResolution = paintXRes; |
787 |
mXResolution = paintXRes; |
| 741 |
mYResolution = paintYRes; |
788 |
mYResolution = paintYRes; |
| 742 |
|
789 |
|
| 743 |
LayerManager::DrawThebesLayerCallback callback = |
790 |
LayerManager::DrawThebesLayerCallback callback = |
| 744 |
mOGLManager->GetThebesLayerCallback(); |
791 |
mOGLManager->GetThebesLayerCallback(); |
| 745 |
if (!callback) { |
792 |
if (!callback) { |
| 746 |
NS_ERROR("GL should never need to update ThebesLayers in an empty transaction"); |
793 |
NS_ERROR("GL should never need to update ThebesLayers in an empty transaction"); |
| 747 |
} else { |
794 |
} else { |
| 748 |
void* callbackData = mOGLManager->GetThebesLayerCallbackData(); |
795 |
void* callbackData = mOGLManager->GetThebesLayerCallbackData(); |
| 749 |
callback(this, state.mContext, state.mRegionToDraw, |
796 |
callback(this, state.mContext, state.mRegionToDraw, |
| 750 |
state.mRegionToInvalidate, callbackData); |
797 |
state.mRegionToInvalidate, callbackData); |
| 751 |
// Everything that's visible has been validated. Do this instead of |
798 |
// Everything that's visible has been validated. Do this instead of |
| 752 |
// OR-ing with aRegionToDraw, since that can lead to a very complex region |
799 |
// OR-ing with aRegionToDraw, since that can lead to a very complex region |
| 753 |
// here (OR doesn't automatically simplify to the simplest possible |
800 |
// here (OR doesn't automatically simplify to the simplest possible |
| 754 |
// representation of a region.) |
801 |
// representation of a region.) |
| 755 |
mValidRegion.Or(mValidRegion, mVisibleRegion); |
802 |
mValidRegion.Or(mValidRegion, neededRegion); |
| 756 |
} |
803 |
} |
| 757 |
} |
804 |
} |
| 758 |
|
805 |
|
| 759 |
DEBUG_GL_ERROR_CHECK(gl()); |
806 |
DEBUG_GL_ERROR_CHECK(gl()); |
| 760 |
|
807 |
|
| 761 |
gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer); |
808 |
gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer); |
| 762 |
mBuffer->RenderTo(aOffset, mOGLManager); |
809 |
mBuffer->RenderTo(aOffset, mOGLManager); |
| 763 |
DEBUG_GL_ERROR_CHECK(gl()); |
810 |
DEBUG_GL_ERROR_CHECK(gl()); |
|
Lines 780-808
ThebesLayerOGL::IsEmpty()
|
Link Here
|
|---|
|
| 780 |
|
827 |
|
| 781 |
class ShadowBufferOGL : public ThebesLayerBufferOGL |
828 |
class ShadowBufferOGL : public ThebesLayerBufferOGL |
| 782 |
{ |
829 |
{ |
| 783 |
public: |
830 |
public: |
| 784 |
ShadowBufferOGL(ShadowThebesLayerOGL* aLayer) |
831 |
ShadowBufferOGL(ShadowThebesLayerOGL* aLayer) |
| 785 |
: ThebesLayerBufferOGL(aLayer, aLayer) |
832 |
: ThebesLayerBufferOGL(aLayer, aLayer) |
| 786 |
{} |
833 |
{} |
| 787 |
|
834 |
|
| 788 |
virtual PaintState BeginPaint(ContentType aContentType, float, float) { |
835 |
virtual void SetEnableRotationOptimization(PRBool aEnable) {} |
|
|
836 |
virtual PaintState BeginPaint(ContentType aContentType, |
| 837 |
const nsIntRegion&, float, float) { |
| 789 |
NS_RUNTIMEABORT("can't BeginPaint for a shadow layer"); |
838 |
NS_RUNTIMEABORT("can't BeginPaint for a shadow layer"); |
| 790 |
return PaintState(); |
839 |
return PaintState(); |
| 791 |
} |
840 |
} |
| 792 |
|
841 |
|
| 793 |
void |
|
|
| 794 |
CreateTexture(ContentType aType, const nsIntSize& aSize) |
| 795 |
{ |
| 796 |
NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color"); |
| 797 |
|
| 798 |
mTexImage = CreateClampOrRepeatTextureImage(gl(), aSize, aType); |
| 799 |
} |
| 800 |
|
| 801 |
void Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated, |
842 |
void Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated, |
| 802 |
const nsIntRect& aRect, const nsIntPoint& aRotation); |
843 |
const nsIntRect& aRect, const nsIntPoint& aRotation); |
| 803 |
|
844 |
|
| 804 |
protected: |
845 |
protected: |
| 805 |
virtual nsIntPoint GetOriginOffset() { |
846 |
virtual nsIntPoint GetOriginOffset() { |
| 806 |
return mBufferRect.TopLeft() - mBufferRotation; |
847 |
return mBufferRect.TopLeft() - mBufferRotation; |
| 807 |
} |
848 |
} |
| 808 |
|
849 |
|
|
|
| 812 |
}; |
853 |
}; |
| 813 |
|
854 |
|
| 814 |
void |
855 |
void |
| 815 |
ShadowBufferOGL::Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated, |
856 |
ShadowBufferOGL::Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated, |
| 816 |
const nsIntRect& aRect, const nsIntPoint& aRotation) |
857 |
const nsIntRect& aRect, const nsIntPoint& aRotation) |
| 817 |
{ |
858 |
{ |
| 818 |
gfxIntSize size = aUpdate->GetSize(); |
859 |
gfxIntSize size = aUpdate->GetSize(); |
| 819 |
if (GetSize() != nsIntSize(size.width, size.height)) { |
860 |
if (GetSize() != nsIntSize(size.width, size.height)) { |
| 820 |
CreateTexture(aUpdate->GetContentType(), |
861 |
// XXX we should do something here to decide whether to use REPEAT or not, |
| 821 |
nsIntSize(size.width, size.height)); |
862 |
// but I'm not sure what |
|
|
863 |
mTexImage = CreateClampOrRepeatTextureImage(gl(), |
| 864 |
nsIntSize(size.width, size.height), aUpdate->GetContentType(), ALLOW_REPEAT); |
| 822 |
} |
865 |
} |
| 823 |
|
866 |
|
| 824 |
nsIntRegion destRegion(aUpdated); |
867 |
nsIntRegion destRegion(aUpdated); |
| 825 |
// aUpdated is in screen coordinates. Move it so that the layer's |
868 |
// aUpdated is in screen coordinates. Move it so that the layer's |
| 826 |
// top-left is 0,0 |
869 |
// top-left is 0,0 |
| 827 |
nsIntPoint visTopLeft = mLayer->GetVisibleRegion().GetBounds().TopLeft(); |
870 |
nsIntPoint visTopLeft = mLayer->GetVisibleRegion().GetBounds().TopLeft(); |
| 828 |
destRegion.MoveBy(-visTopLeft); |
871 |
destRegion.MoveBy(-visTopLeft); |
| 829 |
|
872 |
|