Commit 07edd448 by Jamie Madill Committed by Shannon Woods

Change the checks for texture completeness in Texture*::copySubImage to only…

Change the checks for texture completeness in Texture*::copySubImage to only check if the specified level is complete. This removes the dependency between copySubImage and isSamplerComplete, which makes operation with sampler objects simpler. TRAC #23453 Signed-off-by: Nicolas Capens Signed-off-by: Shannon Woods Authored-by: Jamie Madill
parent eb3665c2
...@@ -599,7 +599,11 @@ void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo ...@@ -599,7 +599,11 @@ void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo
return gl::error(GL_INVALID_VALUE); return gl::error(GL_INVALID_VALUE);
} }
if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
// the current level we're copying to is defined (with appropriate format, width & height)
bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
{ {
mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source); mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
mDirtyImages = true; mDirtyImages = true;
...@@ -611,10 +615,10 @@ void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo ...@@ -611,10 +615,10 @@ void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo
convertToRenderTarget(); convertToRenderTarget();
} }
updateTexture();
if (level < levelCount()) if (level < levelCount())
{ {
updateTextureLevel(level);
GLuint clientVersion = mRenderer->getCurrentClientVersion(); GLuint clientVersion = mRenderer->getCurrentClientVersion();
gl::Rectangle sourceRect; gl::Rectangle sourceRect;
...@@ -731,37 +735,60 @@ bool Texture2D::isSamplerComplete() const ...@@ -731,37 +735,60 @@ bool Texture2D::isSamplerComplete() const
// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
bool Texture2D::isMipmapComplete() const bool Texture2D::isMipmapComplete() const
{ {
GLsizei width = mImageArray[0]->getWidth();
GLsizei height = mImageArray[0]->getHeight();
int q = log2(std::max(width, height));
for (int level = 0; level <= q; level++)
{
if (!isLevelComplete(level))
{
return false;
}
}
return true;
}
bool Texture2D::isLevelComplete(int level) const
{
if (isImmutable()) if (isImmutable())
{ {
return true; return true;
} }
GLsizei width = mImageArray[0]->getWidth(); const rx::Image *baseImage = mImageArray[0];
GLsizei height = mImageArray[0]->getHeight(); GLsizei width = baseImage->getWidth();
GLsizei height = baseImage->getHeight();
if (width <= 0 || height <= 0) if (width <= 0 || height <= 0)
{ {
return false; return false;
} }
int q = log2(std::max(width, height)); // The base image level is complete if the width and height are positive
if (level == 0)
{
return true;
}
for (int level = 1; level <= q; level++) ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
rx::Image *image = mImageArray[level];
if (image->getInternalFormat() != baseImage->getInternalFormat())
{ {
if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat()) return false;
{ }
return false;
}
if (mImageArray[level]->getWidth() != std::max(1, width >> level)) if (image->getWidth() != std::max(1, width >> level))
{ {
return false; return false;
} }
if (mImageArray[level]->getHeight() != std::max(1, height >> level)) if (image->getHeight() != std::max(1, height >> level))
{ {
return false; return false;
}
} }
return true; return true;
...@@ -811,12 +838,18 @@ void Texture2D::updateTexture() ...@@ -811,12 +838,18 @@ void Texture2D::updateTexture()
for (int level = 0; level < levels; level++) for (int level = 0; level < levels; level++)
{ {
rx::Image *image = mImageArray[level]; updateTextureLevel(level);
}
}
if (image->isDirty()) void Texture2D::updateTextureLevel(int level)
{ {
commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight()); ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
} rx::Image *image = mImageArray[level];
if (image->isDirty())
{
commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
} }
} }
...@@ -1201,19 +1234,13 @@ bool TextureCubeMap::isMipmapCubeComplete() const ...@@ -1201,19 +1234,13 @@ bool TextureCubeMap::isMipmapCubeComplete() const
} }
GLsizei size = mImageArray[0][0]->getWidth(); GLsizei size = mImageArray[0][0]->getWidth();
int q = log2(size); int q = log2(size);
for (int face = 0; face < 6; face++) for (int face = 0; face < 6; face++)
{ {
for (int level = 1; level <= q; level++) for (int level = 1; level <= q; level++)
{ {
if (mImageArray[face][level]->getInternalFormat() != mImageArray[0][0]->getInternalFormat()) if (!isFaceLevelComplete(face, level))
{
return false;
}
if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
{ {
return false; return false;
} }
...@@ -1223,6 +1250,44 @@ bool TextureCubeMap::isMipmapCubeComplete() const ...@@ -1223,6 +1250,44 @@ bool TextureCubeMap::isMipmapCubeComplete() const
return true; return true;
} }
bool TextureCubeMap::isFaceLevelComplete(int face, int level) const
{
ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
if (isImmutable())
{
return true;
}
const rx::Image *baseImage = mImageArray[face][0];
GLsizei size = baseImage->getWidth();
if (size <= 0)
{
return false;
}
// The base image level is complete if the width and height are positive
if (level == 0)
{
return true;
}
rx::Image *image = mImageArray[face][level];
if (image->getInternalFormat() != baseImage->getInternalFormat())
{
return false;
}
if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
{
return false;
}
return true;
}
bool TextureCubeMap::isCompressed(GLenum target, GLint level) const bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
{ {
return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()); return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
...@@ -1266,16 +1331,22 @@ void TextureCubeMap::updateTexture() ...@@ -1266,16 +1331,22 @@ void TextureCubeMap::updateTexture()
{ {
for (int level = 0; level < levels; level++) for (int level = 0; level < levels; level++)
{ {
rx::Image *image = mImageArray[face][level]; updateTextureFaceLevel(face, level);
if (image->isDirty())
{
commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
}
} }
} }
} }
void TextureCubeMap::updateTextureFaceLevel(int face, int level)
{
ASSERT(level >= 0 && face < 6 && level < (int)ArraySize(mImageArray[face]) && mImageArray[face][level] != NULL);
rx::Image *image = mImageArray[face][level];
if (image->isDirty())
{
commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
}
}
void TextureCubeMap::convertToRenderTarget() void TextureCubeMap::convertToRenderTarget()
{ {
rx::TextureStorageInterfaceCube *newTexStorage = NULL; rx::TextureStorageInterfaceCube *newTexStorage = NULL;
...@@ -1406,11 +1477,15 @@ void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLi ...@@ -1406,11 +1477,15 @@ void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLi
return gl::error(GL_INVALID_VALUE); return gl::error(GL_INVALID_VALUE);
} }
unsigned int faceindex = faceIndex(target); unsigned int face = faceIndex(target);
// can only make our texture storage to a render target if level 0 is defined (with a width & height) and
// the current level we're copying to is defined (with appropriate format, width & height)
bool canCreateRenderTarget = isFaceLevelComplete(face, level) && isFaceLevelComplete(face, 0);
if (!mImageArray[faceindex][level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) if (!mImageArray[face][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
{ {
mImageArray[faceindex][level]->copy(0, 0, 0, x, y, width, height, source); mImageArray[face][level]->copy(0, 0, 0, x, y, width, height, source);
mDirtyImages = true; mDirtyImages = true;
} }
else else
...@@ -1420,10 +1495,10 @@ void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLi ...@@ -1420,10 +1495,10 @@ void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLi
convertToRenderTarget(); convertToRenderTarget();
} }
updateTexture();
if (level < levelCount()) if (level < levelCount())
{ {
updateTextureFaceLevel(face, level);
GLuint clientVersion = mRenderer->getCurrentClientVersion(); GLuint clientVersion = mRenderer->getCurrentClientVersion();
gl::Rectangle sourceRect; gl::Rectangle sourceRect;
...@@ -1761,7 +1836,11 @@ void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo ...@@ -1761,7 +1836,11 @@ void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo
return gl::error(GL_INVALID_VALUE); return gl::error(GL_INVALID_VALUE);
} }
if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
// the current level we're copying to is defined (with appropriate format, width & height)
bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
{ {
mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source); mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
mDirtyImages = true; mDirtyImages = true;
...@@ -1773,10 +1852,10 @@ void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo ...@@ -1773,10 +1852,10 @@ void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yo
convertToRenderTarget(); convertToRenderTarget();
} }
updateTexture();
if (level < levelCount()) if (level < levelCount())
{ {
updateTextureLevel(level);
gl::Rectangle sourceRect; gl::Rectangle sourceRect;
sourceRect.x = x; sourceRect.x = x;
sourceRect.width = width; sourceRect.width = width;
...@@ -1824,43 +1903,68 @@ bool Texture3D::isSamplerComplete() const ...@@ -1824,43 +1903,68 @@ bool Texture3D::isSamplerComplete() const
bool Texture3D::isMipmapComplete() const bool Texture3D::isMipmapComplete() const
{ {
GLsizei width = mImageArray[0]->getWidth();
GLsizei height = mImageArray[0]->getHeight();
GLsizei depth = mImageArray[0]->getDepth();
int q = log2(std::max(std::max(width, height), depth));
for (int level = 0; level <= q; level++)
{
if (!isLevelComplete(level))
{
return false;
}
}
return true;
}
bool Texture3D::isLevelComplete(int level) const
{
ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
if (isImmutable()) if (isImmutable())
{ {
return true; return true;
} }
GLsizei width = mImageArray[0]->getWidth(); rx::Image *baseImage = mImageArray[0];
GLsizei height = mImageArray[0]->getHeight();
GLsizei depth = mImageArray[0]->getDepth(); GLsizei width = baseImage->getWidth();
GLsizei height = baseImage->getHeight();
GLsizei depth = baseImage->getDepth();
if (width <= 0 || height <= 0 || depth <= 0) if (width <= 0 || height <= 0 || depth <= 0)
{ {
return false; return false;
} }
int q = log2(std::max(std::max(width, height), depth)); if (level == 0)
{
return true;
}
for (int level = 1; level <= q; level++) rx::Image *levelImage = mImageArray[level];
if (levelImage->getInternalFormat() != baseImage->getInternalFormat())
{ {
if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat()) return false;
{ }
return false;
}
if (mImageArray[level]->getWidth() != std::max(1, width >> level)) if (levelImage->getWidth() != std::max(1, width >> level))
{ {
return false; return false;
} }
if (mImageArray[level]->getHeight() != std::max(1, height >> level)) if (levelImage->getHeight() != std::max(1, height >> level))
{ {
return false; return false;
} }
if (mImageArray[level]->getDepth() != std::max(1, depth >> level)) if (levelImage->getDepth() != std::max(1, depth >> level))
{ {
return false; return false;
}
} }
return true; return true;
...@@ -1911,12 +2015,19 @@ void Texture3D::updateTexture() ...@@ -1911,12 +2015,19 @@ void Texture3D::updateTexture()
for (int level = 0; level < levels; level++) for (int level = 0; level < levels; level++)
{ {
rx::Image *image = mImageArray[level]; updateTextureLevel(level);
}
}
if (image->isDirty()) void Texture3D::updateTextureLevel(int level)
{ {
commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth()); ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
}
rx::Image *image = mImageArray[level];
if (image->isDirty())
{
commitRect(level, 0, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight(), mImageArray[level]->getDepth());
} }
} }
...@@ -2255,7 +2366,11 @@ void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLi ...@@ -2255,7 +2366,11 @@ void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLi
return gl::error(GL_INVALID_VALUE); return gl::error(GL_INVALID_VALUE);
} }
if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
// the current level we're copying to is defined (with appropriate format, width & height)
bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
{ {
mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source); mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
mDirtyImages = true; mDirtyImages = true;
...@@ -2267,10 +2382,10 @@ void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLi ...@@ -2267,10 +2382,10 @@ void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLi
convertToRenderTarget(); convertToRenderTarget();
} }
updateTexture();
if (level < levelCount()) if (level < levelCount())
{ {
updateTextureLevel(level);
GLuint clientVersion = mRenderer->getCurrentClientVersion(); GLuint clientVersion = mRenderer->getCurrentClientVersion();
gl::Rectangle sourceRect; gl::Rectangle sourceRect;
...@@ -2317,6 +2432,26 @@ bool Texture2DArray::isSamplerComplete() const ...@@ -2317,6 +2432,26 @@ bool Texture2DArray::isSamplerComplete() const
bool Texture2DArray::isMipmapComplete() const bool Texture2DArray::isMipmapComplete() const
{ {
GLsizei width = getWidth(0);
GLsizei height = getHeight(0);
int q = log2(std::max(width, height));
for (int level = 1; level <= q; level++)
{
if (!isLevelComplete(level))
{
return false;
}
}
return true;
}
bool Texture2DArray::isLevelComplete(int level) const
{
ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
if (isImmutable()) if (isImmutable())
{ {
return true; return true;
...@@ -2331,29 +2466,29 @@ bool Texture2DArray::isMipmapComplete() const ...@@ -2331,29 +2466,29 @@ bool Texture2DArray::isMipmapComplete() const
return false; return false;
} }
int q = log2(std::max(width, height)); if (level == 0)
{
return true;
}
for (int level = 1; level <= q; level++) if (getInternalFormat(level) != getInternalFormat(0))
{ {
if (getInternalFormat(level) != getInternalFormat(0)) return false;
{ }
return false;
}
if (getWidth(level) != std::max(1, width >> level)) if (getWidth(level) != std::max(1, width >> level))
{ {
return false; return false;
} }
if (getHeight(level) != std::max(1, height >> level)) if (getHeight(level) != std::max(1, height >> level))
{ {
return false; return false;
} }
if (getDepth(level) != depth) if (getDepth(level) != depth)
{ {
return false; return false;
}
} }
return true; return true;
...@@ -2407,14 +2542,19 @@ void Texture2DArray::updateTexture() ...@@ -2407,14 +2542,19 @@ void Texture2DArray::updateTexture()
int levels = (isMipmapComplete() ? levelCount() : 1); int levels = (isMipmapComplete() ? levelCount() : 1);
for (int level = 0; level < levels; level++) for (int level = 0; level < levels; level++)
{ {
for (int layer = 0; layer < mLayerCounts[level]; layer++) updateTextureLevel(level);
{ }
rx::Image *image = mImageArray[level][layer]; }
if (image->isDirty()) void Texture2DArray::updateTextureLevel(int level)
{ {
commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight()); for (int layer = 0; layer < mLayerCounts[level]; layer++)
} {
rx::Image *image = mImageArray[level][layer];
if (image->isDirty())
{
commitRect(level, 0, 0, layer, image->getWidth(), image->getHeight());
} }
} }
} }
......
...@@ -190,6 +190,8 @@ class Texture2D : public Texture ...@@ -190,6 +190,8 @@ class Texture2D : public Texture
virtual rx::TextureStorageInterface *getStorage(bool renderTarget); virtual rx::TextureStorageInterface *getStorage(bool renderTarget);
bool isMipmapComplete() const; bool isMipmapComplete() const;
bool isLevelComplete(int level) const;
void updateTextureLevel(int level);
void redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height); void redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height);
void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
...@@ -264,6 +266,8 @@ class TextureCubeMap : public Texture ...@@ -264,6 +266,8 @@ class TextureCubeMap : public Texture
bool isCubeComplete() const; bool isCubeComplete() const;
bool isMipmapCubeComplete() const; bool isMipmapCubeComplete() const;
bool isFaceLevelComplete(int face, int level) const;
void updateTextureFaceLevel(int face, int level);
void setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels); void setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLint internalFormat, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
void commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); void commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
...@@ -332,6 +336,9 @@ class Texture3D : public Texture ...@@ -332,6 +336,9 @@ class Texture3D : public Texture
void redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth); void redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth);
void commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); void commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
bool isLevelComplete(int level) const;
void updateTextureLevel(int level);
rx::Image *mImageArray[IMPLEMENTATION_MAX_TEXTURE_LEVELS]; rx::Image *mImageArray[IMPLEMENTATION_MAX_TEXTURE_LEVELS];
rx::TextureStorageInterface3D *mTexStorage; rx::TextureStorageInterface3D *mTexStorage;
...@@ -395,6 +402,9 @@ class Texture2DArray : public Texture ...@@ -395,6 +402,9 @@ class Texture2DArray : public Texture
void redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth); void redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth);
void commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height); void commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height);
bool isLevelComplete(int level) const;
void updateTextureLevel(int level);
// Storing images as an array of single depth textures since D3D11 treats each array level of a // Storing images as an array of single depth textures since D3D11 treats each array level of a
// Texture2D object as a separate subresource. Each layer would have to be looped over // Texture2D object as a separate subresource. Each layer would have to be looped over
// to update all the texture layers since they cannot all be updated at once and it makes the most // to update all the texture layers since they cannot all be updated at once and it makes the most
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment