зеркало из 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"
|
// "pointer mode"
|
||||||
aGl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
aGl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
// NB: quadVertices and texCoords vertices must match
|
// Given what we know about these textures and coordinates, we can
|
||||||
GLfloat quadVertices[] = {
|
// compute fmod(t, 1.0f) to get the same texture coordinate out. If
|
||||||
0.0f, 0.0f, // bottom left
|
// the texCoordRect dimension is < 0 or > width/height, then we have
|
||||||
1.0f, 0.0f, // bottom right
|
// wraparound that we need to deal with by drawing multiple quads,
|
||||||
0.0f, 1.0f, // top left
|
// because we can't rely on full non-power-of-two texture support
|
||||||
1.0f, 1.0f // top right
|
// (which is required for the REPEAT wrap mode).
|
||||||
};
|
|
||||||
|
GLContext::RectTriangles rects;
|
||||||
|
GLContext::DecomposeIntoNoRepeatTriangles(aTexCoordRect, aTexSize, rects);
|
||||||
|
|
||||||
aGl->fVertexAttribPointer(vertAttribIndex, 2,
|
aGl->fVertexAttribPointer(vertAttribIndex, 2,
|
||||||
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
|
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
|
||||||
quadVertices);
|
rects.vertexCoords);
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
aGl->fVertexAttribPointer(texCoordAttribIndex, 2,
|
aGl->fVertexAttribPointer(texCoordAttribIndex, 2,
|
||||||
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
|
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
|
||||||
texCoords);
|
rects.texCoords);
|
||||||
|
|
||||||
DEBUG_GL_ERROR_CHECK(aGl);
|
DEBUG_GL_ERROR_CHECK(aGl);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -106,7 +98,7 @@ BindAndDrawQuadWithTextureRect(LayerProgram *aProg,
|
||||||
{
|
{
|
||||||
aGl->fEnableVertexAttribArray(vertAttribIndex);
|
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);
|
DEBUG_GL_ERROR_CHECK(aGl);
|
||||||
|
|
||||||
aGl->fDisableVertexAttribArray(vertAttribIndex);
|
aGl->fDisableVertexAttribArray(vertAttribIndex);
|
||||||
|
@ -230,7 +222,7 @@ public:
|
||||||
{
|
{
|
||||||
NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color");
|
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;
|
return mTexImage ? mTexImage->GetBackingSurface() : nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,7 +353,7 @@ BasicBufferOGL::BeginPaint(ContentType aContentType)
|
||||||
// So allocate a new buffer for the destination.
|
// So allocate a new buffer for the destination.
|
||||||
destBufferRect = visibleBounds;
|
destBufferRect = visibleBounds;
|
||||||
destBuffer = gl()->CreateTextureImage(visibleBounds.Size(), aContentType,
|
destBuffer = gl()->CreateTextureImage(visibleBounds.Size(), aContentType,
|
||||||
LOCAL_GL_REPEAT);
|
LOCAL_GL_CLAMP_TO_EDGE);
|
||||||
DEBUG_GL_ERROR_CHECK(gl());
|
DEBUG_GL_ERROR_CHECK(gl());
|
||||||
if (!destBuffer)
|
if (!destBuffer)
|
||||||
return result;
|
return result;
|
||||||
|
@ -380,7 +372,7 @@ BasicBufferOGL::BeginPaint(ContentType aContentType)
|
||||||
// The buffer's not big enough, so allocate a new one
|
// The buffer's not big enough, so allocate a new one
|
||||||
destBufferRect = visibleBounds;
|
destBufferRect = visibleBounds;
|
||||||
destBuffer = gl()->CreateTextureImage(visibleBounds.Size(), aContentType,
|
destBuffer = gl()->CreateTextureImage(visibleBounds.Size(), aContentType,
|
||||||
LOCAL_GL_REPEAT);
|
LOCAL_GL_CLAMP_TO_EDGE);
|
||||||
DEBUG_GL_ERROR_CHECK(gl());
|
DEBUG_GL_ERROR_CHECK(gl());
|
||||||
if (!destBuffer)
|
if (!destBuffer)
|
||||||
return result;
|
return result;
|
||||||
|
@ -410,7 +402,7 @@ BasicBufferOGL::BeginPaint(ContentType aContentType)
|
||||||
// can't blit, just draw everything
|
// can't blit, just draw everything
|
||||||
destBufferRect = visibleBounds;
|
destBufferRect = visibleBounds;
|
||||||
destBuffer = gl()->CreateTextureImage(visibleBounds.Size(), aContentType,
|
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");
|
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,
|
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));
|
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 dx0 = 2.0 * float(aDstRect.x) / float(dstSize.width) - 1.0;
|
||||||
float dy0 = 2.0 * float(aDstRect.y) / float(dstSize.height) - 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 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 dy1 = 2.0 * float(aDstRect.y + aDstRect.height) / float(dstSize.height) - 1.0;
|
||||||
|
|
||||||
float quadTriangleCoords[] = {
|
RectTriangles rects;
|
||||||
dx0, dy1,
|
DecomposeIntoNoRepeatTriangles(aSrcRect, srcSize,
|
||||||
dx0, dy0,
|
rects);
|
||||||
dx1, dy1,
|
|
||||||
dx1, dy0
|
|
||||||
};
|
|
||||||
|
|
||||||
float texCoords[] = {
|
GLfloat *quadTriangleCoords = rects.vertexCoords;
|
||||||
sx0, sy1,
|
GLfloat *texCoords = rects.texCoords;
|
||||||
sx0, sy0,
|
|
||||||
sx1, sy1,
|
// now put the coords into the d[xy]0 .. d[xy]1 coordinate space
|
||||||
sx1, sy0
|
// 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);
|
fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||||
fBindTexture(LOCAL_GL_TEXTURE_2D, aSrc->Texture());
|
fBindTexture(LOCAL_GL_TEXTURE_2D, aSrc->Texture());
|
||||||
|
@ -1194,7 +1189,7 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
|
||||||
|
|
||||||
DEBUG_GL_ERROR_CHECK(this);
|
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);
|
DEBUG_GL_ERROR_CHECK(this);
|
||||||
|
|
||||||
|
@ -1223,6 +1218,161 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
|
||||||
PopViewportRect();
|
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
|
void
|
||||||
GLContext::UseBlitProgram()
|
GLContext::UseBlitProgram()
|
||||||
{
|
{
|
||||||
|
|
|
@ -697,6 +697,37 @@ public:
|
||||||
void BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
|
void BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
|
||||||
TextureImage *aDst, const nsIntRect& aDstRect);
|
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
|
* Known GL extensions that can be queried by
|
||||||
* IsExtensionSupported. The results of this are cached, and as
|
* IsExtensionSupported. The results of this are cached, and as
|
||||||
|
|
Загрузка…
Ссылка в новой задаче