b=609195; don't use GL_REPEAT for non-power-of-two textures; r=jrmuizel

This commit is contained in:
Vladimir Vukicevic 2010-11-12 12:02:17 -08:00
Родитель 8ac71d97a0
Коммит c2d23145ca
3 изменённых файлов: 218 добавлений и 45 удалений

Просмотреть файл

@ -73,32 +73,24 @@ BindAndDrawQuadWithTextureRect(LayerProgram *aProg,
// "pointer mode"
aGl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
// NB: quadVertices and texCoords vertices must match
GLfloat quadVertices[] = {
0.0f, 0.0f, // bottom left
1.0f, 0.0f, // bottom right
0.0f, 1.0f, // top left
1.0f, 1.0f // top right
};
// Given what we know about these textures and coordinates, we can
// compute fmod(t, 1.0f) to get the same texture coordinate out. If
// the texCoordRect dimension is < 0 or > width/height, then we have
// wraparound that we need to deal with by drawing multiple quads,
// because we can't rely on full non-power-of-two texture support
// (which is required for the REPEAT wrap mode).
GLContext::RectTriangles rects;
GLContext::DecomposeIntoNoRepeatTriangles(aTexCoordRect, aTexSize, rects);
aGl->fVertexAttribPointer(vertAttribIndex, 2,
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
quadVertices);
DEBUG_GL_ERROR_CHECK(aGl);
GLfloat xleft = GLfloat(aTexCoordRect.x) / GLfloat(aTexSize.width);
GLfloat ytop = GLfloat(aTexCoordRect.y) / GLfloat(aTexSize.height);
GLfloat w = GLfloat(aTexCoordRect.width) / GLfloat(aTexSize.width);
GLfloat h = GLfloat(aTexCoordRect.height) / GLfloat(aTexSize.height);
GLfloat texCoords[] = {
xleft, ytop,
w + xleft, ytop,
xleft, h + ytop,
w + xleft, h + ytop,
};
rects.vertexCoords);
aGl->fVertexAttribPointer(texCoordAttribIndex, 2,
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
texCoords);
rects.texCoords);
DEBUG_GL_ERROR_CHECK(aGl);
{
@ -106,7 +98,7 @@ BindAndDrawQuadWithTextureRect(LayerProgram *aProg,
{
aGl->fEnableVertexAttribArray(vertAttribIndex);
aGl->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
aGl->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.numRects * 6);
DEBUG_GL_ERROR_CHECK(aGl);
aGl->fDisableVertexAttribArray(vertAttribIndex);
@ -230,7 +222,7 @@ public:
{
NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color");
mTexImage = gl()->CreateTextureImage(aSize, aType, LOCAL_GL_REPEAT);
mTexImage = gl()->CreateTextureImage(aSize, aType, LOCAL_GL_CLAMP_TO_EDGE);
return mTexImage ? mTexImage->GetBackingSurface() : nsnull;
}
@ -361,7 +353,7 @@ BasicBufferOGL::BeginPaint(ContentType aContentType)
// So allocate a new buffer for the destination.
destBufferRect = visibleBounds;
destBuffer = gl()->CreateTextureImage(visibleBounds.Size(), aContentType,
LOCAL_GL_REPEAT);
LOCAL_GL_CLAMP_TO_EDGE);
DEBUG_GL_ERROR_CHECK(gl());
if (!destBuffer)
return result;
@ -380,7 +372,7 @@ BasicBufferOGL::BeginPaint(ContentType aContentType)
// The buffer's not big enough, so allocate a new one
destBufferRect = visibleBounds;
destBuffer = gl()->CreateTextureImage(visibleBounds.Size(), aContentType,
LOCAL_GL_REPEAT);
LOCAL_GL_CLAMP_TO_EDGE);
DEBUG_GL_ERROR_CHECK(gl());
if (!destBuffer)
return result;
@ -410,7 +402,7 @@ BasicBufferOGL::BeginPaint(ContentType aContentType)
// can't blit, just draw everything
destBufferRect = visibleBounds;
destBuffer = gl()->CreateTextureImage(visibleBounds.Size(), aContentType,
LOCAL_GL_REPEAT);
LOCAL_GL_CLAMP_TO_EDGE);
}
}
@ -575,7 +567,7 @@ public:
{
NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color");
mTexImage = gl()->CreateTextureImage(aSize, aType, LOCAL_GL_REPEAT);
mTexImage = gl()->CreateTextureImage(aSize, aType, LOCAL_GL_CLAMP_TO_EDGE);
}
void Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated,

Просмотреть файл

@ -1157,29 +1157,24 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
PushViewportRect(nsIntRect(0, 0, dstSize.width, dstSize.height));
float sx0 = float(aSrcRect.x) / float(srcSize.width);
float sy0 = float(aSrcRect.y) / float(srcSize.height);
float sx1 = float(aSrcRect.x + aSrcRect.width) / float(srcSize.width);
float sy1 = float(aSrcRect.y + aSrcRect.height) / float(srcSize.height);
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;
float quadTriangleCoords[] = {
dx0, dy1,
dx0, dy0,
dx1, dy1,
dx1, dy0
};
RectTriangles rects;
DecomposeIntoNoRepeatTriangles(aSrcRect, srcSize,
rects);
float texCoords[] = {
sx0, sy1,
sx0, sy0,
sx1, sy1,
sx1, sy0
};
GLfloat *quadTriangleCoords = rects.vertexCoords;
GLfloat *texCoords = rects.texCoords;
// now put the coords into the d[xy]0 .. d[xy]1 coordinate space
// from the 0..1 that it comes out of decompose
for (int i = 0; i < rects.numRects * 6; ++i) {
quadTriangleCoords[i*2] = (quadTriangleCoords[i*2] * (dx1 - dx0)) + dx0;
quadTriangleCoords[i*2+1] = (quadTriangleCoords[i*2+1] * (dy1 - dy0)) + dy0;
}
fActiveTexture(LOCAL_GL_TEXTURE0);
fBindTexture(LOCAL_GL_TEXTURE_2D, aSrc->Texture());
@ -1194,7 +1189,7 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
DEBUG_GL_ERROR_CHECK(this);
fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.numRects * 6);
DEBUG_GL_ERROR_CHECK(this);
@ -1223,6 +1218,161 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
PopViewportRect();
}
void
GLContext::RectTriangles::addRect(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1)
{
NS_ASSERTION(numRects < 4, "Overflow in number of rectangles, max 4!");
GLfloat *v = &vertexCoords[numRects*6*2];
GLfloat *t = &texCoords[numRects*6*2];
*v++ = x0; *v++ = y0;
*v++ = x1; *v++ = y0;
*v++ = x0; *v++ = y1;
*v++ = x0; *v++ = y1;
*v++ = x1; *v++ = y0;
*v++ = x1; *v++ = y1;
*t++ = tx0; *t++ = ty0;
*t++ = tx1; *t++ = ty0;
*t++ = tx0; *t++ = ty1;
*t++ = tx0; *t++ = ty1;
*t++ = tx1; *t++ = ty0;
*t++ = tx1; *t++ = ty1;
numRects++;
}
static GLfloat
WrapTexCoord(GLfloat v)
{
// fmodf gives negative results for negative numbers;
// that is, fmodf(0.75, 1.0) == 0.75, but
// fmodf(-0.75, 1.0) == -0.75. For the negative case,
// the result we need is 0.25, so we add 1.0f.
if (v < 0.0f) {
return 1.0f + fmodf(v, 1.0f);
}
return fmodf(v, 1.0f);
}
void
GLContext::DecomposeIntoNoRepeatTriangles(const nsIntRect& aTexCoordRect,
const nsIntSize& aTexSize,
RectTriangles& aRects)
{
// normalize this
nsIntRect tcr(aTexCoordRect);
while (tcr.x > aTexSize.width)
tcr.x -= aTexSize.width;
while (tcr.y > aTexSize.height)
tcr.y -= aTexSize.height;
// Compute top left and bottom right tex coordinates
GLfloat tl[2] =
{ GLfloat(tcr.x) / GLfloat(aTexSize.width),
GLfloat(tcr.y) / GLfloat(aTexSize.height) };
GLfloat br[2] =
{ GLfloat(tcr.XMost()) / GLfloat(aTexSize.width),
GLfloat(tcr.YMost()) / GLfloat(aTexSize.height) };
// then check if we wrap in either the x or y axis; if we do,
// then also use fmod to figure out the "true" non-wrapping
// texture coordinates.
bool xwrap = false, ywrap = false;
if (tcr.x < 0 || tcr.x > aTexSize.width ||
tcr.XMost() < 0 || tcr.XMost() > aTexSize.width)
{
xwrap = true;
tl[0] = WrapTexCoord(tl[0]);
br[0] = WrapTexCoord(br[0]);
}
if (tcr.y < 0 || tcr.y > aTexSize.height ||
tcr.YMost() < 0 || tcr.YMost() > aTexSize.height)
{
ywrap = true;
tl[1] = WrapTexCoord(tl[1]);
br[1] = WrapTexCoord(br[1]);
}
NS_ASSERTION(tl[0] >= 0.0f && tl[0] <= 1.0f &&
tl[1] >= 0.0f && tl[1] <= 1.0f &&
br[0] >= 0.0f && br[0] <= 1.0f &&
br[1] >= 0.0f && br[1] <= 1.0f,
"Somehow generated invalid texture coordinates");
// If xwrap is false, the texture will be sampled from tl[0]
// .. br[0]. If xwrap is true, then it will be split into tl[0]
// .. 1.0, and 0.0 .. br[0]. Same for the Y axis. The
// destination rectangle is also split appropriately, according
// to the calculated xmid/ymid values.
// There isn't a 1:1 mapping between tex coords and destination coords;
// when computing midpoints, we have to take that into account. We
// need to map the texture coords, which are (in the wrap case):
// |tl->1| and |0->br| to the |0->1| range of the vertex coords. So
// we have the length (1-tl)+(br) that needs to map into 0->1.
// These are only valid if there is wrap involved, they won't be used
// otherwise.
GLfloat xlen = (1.0f - tl[0]) + br[0];
GLfloat ylen = (1.0f - tl[1]) + br[1];
NS_ASSERTION(!xwrap || xlen > 0.0f, "xlen isn't > 0, what's going on?");
NS_ASSERTION(!ywrap || ylen > 0.0f, "ylen isn't > 0, what's going on?");
NS_ASSERTION(aTexCoordRect.width <= aTexSize.width &&
aTexCoordRect.height <= aTexSize.height, "tex coord rect would cause tiling!");
if (!xwrap && !ywrap) {
aRects.addRect(0.0f, 0.0f, 1.0f, 1.0f,
tl[0], tl[1], br[0], br[1]);
} else if (!xwrap && ywrap) {
GLfloat ymid = (1.0f - tl[1]) / ylen;
aRects.addRect(0.0f, 0.0f,
1.0f, ymid,
tl[0], tl[1],
br[0], 1.0f);
aRects.addRect(0.0f, ymid,
1.0f, 1.0f,
tl[0], 0.0f,
br[0], br[1]);
} else if (xwrap && !ywrap) {
GLfloat xmid = (1.0f - tl[0]) / xlen;
aRects.addRect(0.0f, 0.0f,
xmid, 1.0f,
tl[0], tl[1],
1.0f, br[1]);
aRects.addRect(xmid, 0.0f,
1.0f, 1.0f,
0.0f, tl[1],
br[0], br[1]);
} else {
GLfloat xmid = (1.0f - tl[0]) / xlen;
GLfloat ymid = (1.0f - tl[1]) / ylen;
aRects.addRect(0.0f, 0.0f,
xmid, ymid,
tl[0], tl[1],
1.0f, 1.0f);
aRects.addRect(xmid, 0.0f,
1.0f, ymid,
0.0f, tl[1],
br[0], 1.0f);
aRects.addRect(0.0f, ymid,
xmid, 1.0f,
tl[0], 0.0f,
1.0f, br[1]);
aRects.addRect(xmid, ymid,
1.0f, 1.0f,
0.0f, 0.0f,
br[0], br[1]);
}
}
void
GLContext::UseBlitProgram()
{

Просмотреть файл

@ -697,6 +697,37 @@ public:
void BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
TextureImage *aDst, const nsIntRect& aDstRect);
/** Helper for DecomposeIntoNoRepeatTriangles
*/
struct RectTriangles {
RectTriangles() : numRects(0) { }
void addRect(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1);
int numRects;
/* max is 4 rectangles, each made up of 2 triangles (3 2-coord vertices each) */
GLfloat vertexCoords[4*3*2*2];
GLfloat texCoords[4*3*2*2];
};
/**
* Decompose drawing the possibly-wrapped aTexCoordRect rectangle
* of a texture of aTexSize into one or more rectangles (represented
* as 2 triangles) and associated tex coordinates, such that
* we don't have to use the REPEAT wrap mode.
*
* The resulting triangle vertex coordinates will be in the space of
* (0.0, 0.0) to (1.0, 1.0) -- transform the coordinates appropriately
* if you need a different space.
*
* The resulting vertex coordinates should be drawn using GL_TRIANGLES,
* and rects.numRects * 3 * 6
*/
static void DecomposeIntoNoRepeatTriangles(const nsIntRect& aTexCoordRect,
const nsIntSize& aTexSize,
RectTriangles& aRects);
/**
* Known GL extensions that can be queried by
* IsExtensionSupported. The results of this are cached, and as