Functionality to update borders of cube textures. The cube texture borders will be used for linear interpolation, in order to produce seamless edges. Change-Id: Idd17c72c6aaf7dcc65188b065ac8ba179b58cc37 Reviewed-on: https://swiftshader-review.googlesource.com/8209 Tested-by: Nicolas Capens <nicolascapens@google.com> Tested-by: Alexis Hétu <sugoi@google.com> Reviewed-by: Alexis Hétu <sugoi@google.com> Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/libGLESv2/Texture.cpp b/src/OpenGL/libGLESv2/Texture.cpp index 784d3fd..273c7ad 100644 --- a/src/OpenGL/libGLESv2/Texture.cpp +++ b/src/OpenGL/libGLESv2/Texture.cpp
@@ -1246,6 +1246,52 @@ return true; } +void TextureCubeMap::updateBorders(int level) +{ + egl::Image *posX = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_POSITIVE_X)][level]; + egl::Image *negX = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_NEGATIVE_X)][level]; + egl::Image *posY = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_POSITIVE_Y)][level]; + egl::Image *negY = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y)][level]; + egl::Image *posZ = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_POSITIVE_Z)][level]; + egl::Image *negZ = image[CubeFaceIndex(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)][level]; + + if(!posX || !negX || !posY || !negY || !posZ || !negZ) + { + return; + } + + // Copy top / bottom first. + posX->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::RIGHT); + posY->copyCubeEdge(sw::Surface::BOTTOM, posZ, sw::Surface::TOP); + posZ->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::TOP); + negX->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::LEFT); + negY->copyCubeEdge(sw::Surface::BOTTOM, negZ, sw::Surface::BOTTOM); + negZ->copyCubeEdge(sw::Surface::BOTTOM, negY, sw::Surface::BOTTOM); + + posX->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::RIGHT); + posY->copyCubeEdge(sw::Surface::TOP, negZ, sw::Surface::TOP); + posZ->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::BOTTOM); + negX->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::LEFT); + negY->copyCubeEdge(sw::Surface::TOP, posZ, sw::Surface::BOTTOM); + negZ->copyCubeEdge(sw::Surface::TOP, posY, sw::Surface::TOP); + + // Copy left / right after top and bottom are done. + // The corner colors will be computed assuming top / bottom are already set. + posX->copyCubeEdge(sw::Surface::RIGHT, negZ, sw::Surface::LEFT); + posY->copyCubeEdge(sw::Surface::RIGHT, posX, sw::Surface::TOP); + posZ->copyCubeEdge(sw::Surface::RIGHT, posX, sw::Surface::LEFT); + negX->copyCubeEdge(sw::Surface::RIGHT, posZ, sw::Surface::LEFT); + negY->copyCubeEdge(sw::Surface::RIGHT, posX, sw::Surface::BOTTOM); + negZ->copyCubeEdge(sw::Surface::RIGHT, negX, sw::Surface::LEFT); + + posX->copyCubeEdge(sw::Surface::LEFT, posZ, sw::Surface::RIGHT); + posY->copyCubeEdge(sw::Surface::LEFT, negX, sw::Surface::TOP); + posZ->copyCubeEdge(sw::Surface::LEFT, negX, sw::Surface::RIGHT); + negX->copyCubeEdge(sw::Surface::LEFT, negZ, sw::Surface::RIGHT); + negY->copyCubeEdge(sw::Surface::LEFT, negX, sw::Surface::BOTTOM); + negZ->copyCubeEdge(sw::Surface::LEFT, posX, sw::Surface::RIGHT); +} + bool TextureCubeMap::isCompressed(GLenum target, GLint level) const { return IsCompressed(getFormat(target, level), egl::getClientVersion());
diff --git a/src/OpenGL/libGLESv2/Texture.h b/src/OpenGL/libGLESv2/Texture.h index 143c51e..d5e0c80 100644 --- a/src/OpenGL/libGLESv2/Texture.h +++ b/src/OpenGL/libGLESv2/Texture.h
@@ -237,6 +237,7 @@ void releaseTexImage() override; void generateMipmaps() override; + void updateBorders(int level); Renderbuffer *getRenderbuffer(GLenum target, GLint level, GLint layer) override; egl::Image *getRenderTarget(GLenum target, unsigned int level) override;
diff --git a/src/Renderer/Surface.cpp b/src/Renderer/Surface.cpp index 2ec5183..3533d25 100644 --- a/src/Renderer/Surface.cpp +++ b/src/Renderer/Surface.cpp
@@ -3554,6 +3554,81 @@ internal.write(x, y, z, color); } + void Surface::copyCubeEdge(Edge dstEdge, Surface *src, Edge srcEdge) + { + Surface *dst = this; + + // Figure out if the edges to be copied in reverse order respectively from one another + // The copy should be reversed whenever the same edges are contiguous or if we're + // copying top <-> right or bottom <-> left. This is explained by the layout, which is: + // + // | +y | + // | -x | +z | +x | -z | + // | -y | + + bool reverse = (srcEdge == dstEdge) || + ((srcEdge == TOP) && (dstEdge == RIGHT)) || + ((srcEdge == RIGHT) && (dstEdge == TOP)) || + ((srcEdge == BOTTOM) && (dstEdge == LEFT)) || + ((srcEdge == LEFT) && (dstEdge == BOTTOM)); + + int srcBytes = src->bytes(src->Surface::getInternalFormat()); + int srcPitch = src->getInternalPitchB(); + int dstBytes = dst->bytes(dst->Surface::getInternalFormat()); + int dstPitch = dst->getInternalPitchB(); + + int srcW = src->getWidth(); + int srcH = src->getHeight(); + int dstW = dst->getWidth(); + int dstH = dst->getHeight(); + + ASSERT(srcW == srcH && dstW == dstH && srcW == dstW && srcBytes == dstBytes); + + // Src is expressed in the regular [0, width-1], [0, height-1] space + int srcDelta = ((srcEdge == TOP) || (srcEdge == BOTTOM)) ? srcBytes : srcPitch; + int srcStart = ((srcEdge == BOTTOM) ? srcPitch * (srcH - 1) : ((srcEdge == RIGHT) ? srcBytes * (srcW - 1) : 0)); + + // Dst contains borders, so it is expressed in the [-1, width+1], [-1, height+1] space + int dstDelta = (((dstEdge == TOP) || (dstEdge == BOTTOM)) ? dstBytes : dstPitch) * (reverse ? -1 : 1); + int dstStart = ((dstEdge == BOTTOM) ? dstPitch * (dstH + 1) : ((dstEdge == RIGHT) ? dstBytes * (dstW + 1) : 0)) + (reverse ? dstW * -dstDelta : dstDelta); + + char *srcBuf = (char*)src->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PRIVATE) + srcStart; + char *dstBuf = (char*)dst->lockInternal(-1, -1, 0, sw::LOCK_READWRITE, sw::PRIVATE) + dstStart; + + for(int i = 0; i < srcW; ++i, dstBuf += dstDelta, srcBuf += srcDelta) + { + memcpy(dstBuf, srcBuf, srcBytes); + } + + if(dstEdge == LEFT || dstEdge == RIGHT) + { + // TOP and BOTTOM are already set, let's average out the corners + int x0 = (dstEdge == RIGHT) ? dstW : -1; + int y0 = -1; + int x1 = (dstEdge == RIGHT) ? dstW - 1 : 0; + int y1 = 0; + dst->computeCubeCorner(x0, y0, x1, y1); + y0 = dstH; + y1 = dstH - 1; + dst->computeCubeCorner(x0, y0, x1, y1); + } + + src->unlockInternal(); + dst->unlockInternal(); + } + + void Surface::computeCubeCorner(int x0, int y0, int x1, int y1) + { + ASSERT(internal.lock != LOCK_UNLOCKED); + + sw::Color<float> color = internal.read(x0, y1); + color += internal.read(x1, y0); + color += internal.read(x1, y1); + color *= (1.0f / 3.0f); + + internal.write(x0, y0, color); + } + bool Surface::hasStencil() const { return isStencil(external.format);
diff --git a/src/Renderer/Surface.hpp b/src/Renderer/Surface.hpp index 3a6e59e..4de2b33 100644 --- a/src/Renderer/Surface.hpp +++ b/src/Renderer/Surface.hpp
@@ -317,6 +317,10 @@ void copyInternal(const Surface* src, int x, int y, float srcX, float srcY, bool filter); void copyInternal(const Surface* src, int x, int y, int z, float srcX, float srcY, float srcZ, bool filter); + enum Edge { TOP, BOTTOM, RIGHT, LEFT }; + void copyCubeEdge(Edge dstEdge, Surface *src, Edge srcEdge); + void computeCubeCorner(int x0, int y0, int x1, int y1); + bool hasStencil() const; bool hasDepth() const; bool hasPalette() const;