зеркало из https://github.com/mozilla/gecko-dev.git
b=609195; don't use GL_REPEAT for non-power-of-two textures; r=jrmuizel
This commit is contained in:
Родитель
8ac71d97a0
Коммит
c2d23145ca
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче