Adding Texture3D support.
Bug 19126833
Added Texture3D argument verifications.
Added the basic API and functions. A few are still unimplemented:
- Image::loadCompressedData() (for depth other than 1)
- Texture3D::copyImage()
- Texture3D::generateMipmaps()
Added colour grading test for 3D texture
Change-Id: I9e52afa7213999f94c5916c2f301fc6fa4b42c0d
Reviewed-on: https://swiftshader-review.googlesource.com/1730
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index da05a8a..d228d29 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -131,6 +131,7 @@
// objects all of whose names are 0.
mTexture2DZero.set(new Texture2D(0));
+ mTexture3DZero.set(new Texture3D(0));
mTextureCubeMapZero.set(new TextureCubeMap(0));
mTextureExternalZero.set(new TextureExternal(0));
@@ -212,6 +213,7 @@
mState.renderbuffer.set(NULL);
mTexture2DZero.set(NULL);
+ mTexture3DZero.set(NULL);
mTextureCubeMapZero.set(NULL);
mTextureExternalZero.set(NULL);
@@ -951,6 +953,13 @@
mState.samplerTexture[TEXTURE_EXTERNAL][mState.activeSampler].set(getTexture(texture));
}
+void Context::bindTexture3D(GLuint texture)
+{
+ mResourceManager->checkTextureAllocation(texture, TEXTURE_3D);
+
+ mState.samplerTexture[TEXTURE_3D][mState.activeSampler].set(getTexture(texture));
+}
+
void Context::bindReadFramebuffer(GLuint framebuffer)
{
if(!getFramebuffer(framebuffer))
@@ -1162,7 +1171,12 @@
Texture2D *Context::getTexture2D()
{
- return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D));
+ return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D));
+}
+
+Texture3D *Context::getTexture3D()
+{
+ return static_cast<Texture3D*>(getSamplerTexture(mState.activeSampler, TEXTURE_3D));
}
TextureCubeMap *Context::getTextureCubeMap()
@@ -1184,6 +1198,7 @@
switch (type)
{
case TEXTURE_2D: return mTexture2DZero.get();
+ case TEXTURE_3D: return mTexture3DZero.get();
case TEXTURE_CUBE: return mTextureCubeMapZero.get();
case TEXTURE_EXTERNAL: return mTextureExternalZero.get();
default: UNREACHABLE();
@@ -1486,7 +1501,18 @@
*params = mState.samplerTexture[TEXTURE_EXTERNAL][mState.activeSampler].id();
}
break;
- default:
+ case GL_TEXTURE_BINDING_3D_OES:
+ {
+ if(mState.activeSampler < 0 || mState.activeSampler > MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
+ {
+ error(GL_INVALID_OPERATION);
+ return false;
+ }
+
+ *params = mState.samplerTexture[TEXTURE_3D][mState.activeSampler].id();
+ }
+ break;
+ default:
return false;
}
@@ -1576,6 +1602,7 @@
case GL_TEXTURE_BINDING_2D:
case GL_TEXTURE_BINDING_CUBE_MAP:
case GL_TEXTURE_BINDING_EXTERNAL_OES:
+ case GL_TEXTURE_BINDING_3D_OES:
{
*type = GL_INT;
*numParams = 1;
@@ -2028,12 +2055,14 @@
{
GLenum wrapS = texture->getWrapS();
GLenum wrapT = texture->getWrapT();
+ GLenum wrapR = texture->getWrapR();
GLenum texFilter = texture->getMinFilter();
GLenum magFilter = texture->getMagFilter();
GLfloat maxAnisotropy = texture->getMaxAnisotropy();
device->setAddressingModeU(samplerType, samplerIndex, es2sw::ConvertTextureWrap(wrapS));
- device->setAddressingModeV(samplerType, samplerIndex, es2sw::ConvertTextureWrap(wrapT));
+ device->setAddressingModeV(samplerType, samplerIndex, es2sw::ConvertTextureWrap(wrapT));
+ device->setAddressingModeW(samplerType, samplerIndex, es2sw::ConvertTextureWrap(wrapR));
sw::FilterType minFilter;
sw::MipmapType mipFilter;
@@ -2109,6 +2138,27 @@
device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_2D);
}
}
+ else if(baseTexture->getTarget() == GL_TEXTURE_3D_OES)
+ {
+ Texture3D *texture = static_cast<Texture3D*>(baseTexture);
+
+ for(int mipmapLevel = 0; mipmapLevel < MIPMAP_LEVELS; mipmapLevel++)
+ {
+ int surfaceLevel = mipmapLevel;
+
+ if(surfaceLevel < 0)
+ {
+ surfaceLevel = 0;
+ }
+ else if(surfaceLevel >= levelCount)
+ {
+ surfaceLevel = levelCount - 1;
+ }
+
+ egl::Image *surface = texture->getImage(surfaceLevel);
+ device->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_3D);
+ }
+ }
else if(baseTexture->getTarget() == GL_TEXTURE_CUBE_MAP)
{
for(int face = 0; face < 6; face++)
diff --git a/src/OpenGL/libGLESv2/Context.h b/src/OpenGL/libGLESv2/Context.h
index 42c8c19..5331af3 100644
--- a/src/OpenGL/libGLESv2/Context.h
+++ b/src/OpenGL/libGLESv2/Context.h
@@ -49,6 +49,7 @@
class Program;
class Texture;
class Texture2D;
+class Texture3D;
class TextureCubeMap;
class TextureExternal;
class Framebuffer;
@@ -370,6 +371,7 @@
void bindTexture2D(GLuint texture);
void bindTextureCubeMap(GLuint texture);
void bindTextureExternal(GLuint texture);
+ void bindTexture3D(GLuint texture);
void bindReadFramebuffer(GLuint framebuffer);
void bindDrawFramebuffer(GLuint framebuffer);
void bindRenderbuffer(GLuint renderbuffer);
@@ -397,7 +399,8 @@
Buffer *getElementArrayBuffer();
Program *getCurrentProgram();
Texture2D *getTexture2D();
- TextureCubeMap *getTextureCubeMap();
+ Texture3D *getTexture3D();
+ TextureCubeMap *getTextureCubeMap();
TextureExternal *getTextureExternal();
Texture *getSamplerTexture(unsigned int sampler, TextureType type);
Framebuffer *getReadFramebuffer();
@@ -460,8 +463,9 @@
State mState;
- gl::BindingPointer<Texture2D> mTexture2DZero;
- gl::BindingPointer<TextureCubeMap> mTextureCubeMapZero;
+ gl::BindingPointer<Texture2D> mTexture2DZero;
+ gl::BindingPointer<Texture3D> mTexture3DZero;
+ gl::BindingPointer<TextureCubeMap> mTextureCubeMapZero;
gl::BindingPointer<TextureExternal> mTextureExternalZero;
typedef std::map<GLint, Framebuffer*> FramebufferMap;
diff --git a/src/OpenGL/libGLESv2/Image.cpp b/src/OpenGL/libGLESv2/Image.cpp
index a78694c..6a36db5 100644
--- a/src/OpenGL/libGLESv2/Image.cpp
+++ b/src/OpenGL/libGLESv2/Image.cpp
@@ -22,28 +22,28 @@
{
enum DataType
{
- Alpha,
- AlphaFloat,
- AlphaHalfFloat,
- Luminance,
- LuminanceFloat,
- LuminanceHalfFloat,
- LuminanceAlpha,
- LuminanceAlphaFloat,
- LuminanceAlphaHalfFloat,
- RGBUByte,
- RGB565,
- RGBFloat,
- RGBHalfFloat,
- RGBAUByte,
- RGBA4444,
- RGBA5551,
- RGBAFloat,
- RGBAHalfFloat,
- BGRA,
- D16,
- D24,
- D32,
+ Alpha,
+ AlphaFloat,
+ AlphaHalfFloat,
+ Luminance,
+ LuminanceFloat,
+ LuminanceHalfFloat,
+ LuminanceAlpha,
+ LuminanceAlphaFloat,
+ LuminanceAlphaHalfFloat,
+ RGBUByte,
+ RGB565,
+ RGBFloat,
+ RGBHalfFloat,
+ RGBAUByte,
+ RGBA4444,
+ RGBA5551,
+ RGBAFloat,
+ RGBAHalfFloat,
+ BGRA,
+ D16,
+ D24,
+ D32,
S8,
};
@@ -53,13 +53,13 @@
UNIMPLEMENTED();
}
- template<>
+ template<>
void LoadImageRow<Alpha>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
memcpy(dest + xoffset, source, width);
}
- template<>
+ template<>
void LoadImageRow<AlphaFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const float *sourceF = reinterpret_cast<const float*>(source);
@@ -74,7 +74,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<AlphaHalfFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
@@ -89,13 +89,13 @@
}
}
- template<>
+ template<>
void LoadImageRow<Luminance>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
memcpy(dest + xoffset, source, width);
}
- template<>
+ template<>
void LoadImageRow<LuminanceFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const float *sourceF = reinterpret_cast<const float*>(source);
@@ -110,7 +110,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<LuminanceHalfFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
@@ -125,13 +125,13 @@
}
}
- template<>
+ template<>
void LoadImageRow<LuminanceAlpha>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
memcpy(dest + xoffset * 2, source, width * 2);
}
- template<>
+ template<>
void LoadImageRow<LuminanceAlphaFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const float *sourceF = reinterpret_cast<const float*>(source);
@@ -146,7 +146,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<LuminanceAlphaHalfFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
@@ -161,7 +161,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<RGBUByte>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
unsigned char *destB = dest + xoffset * 4;
@@ -175,7 +175,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<RGB565>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned short *source565 = reinterpret_cast<const unsigned short*>(source);
@@ -191,7 +191,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<RGBFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const float *sourceF = reinterpret_cast<const float*>(source);
@@ -206,7 +206,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<RGBHalfFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned short *sourceH = reinterpret_cast<const unsigned short*>(source);
@@ -221,7 +221,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<RGBAUByte>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
@@ -234,7 +234,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<RGBA4444>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned short *source4444 = reinterpret_cast<const unsigned short*>(source);
@@ -250,7 +250,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<RGBA5551>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned short *source5551 = reinterpret_cast<const unsigned short*>(source);
@@ -266,25 +266,25 @@
}
}
- template<>
+ template<>
void LoadImageRow<RGBAFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
memcpy(dest + xoffset * 16, source, width * 16);
}
- template<>
+ template<>
void LoadImageRow<RGBAHalfFloat>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
memcpy(dest + xoffset * 8, source, width * 8);
}
- template<>
+ template<>
void LoadImageRow<BGRA>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
memcpy(dest + xoffset * 4, source, width * 4);
}
- template<>
+ template<>
void LoadImageRow<D16>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned short *sourceD16 = reinterpret_cast<const unsigned short*>(source);
@@ -296,7 +296,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<D24>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned int *sourceD24 = reinterpret_cast<const unsigned int*>(source);
@@ -308,7 +308,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<D32>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned int *sourceD32 = reinterpret_cast<const unsigned int*>(source);
@@ -320,7 +320,7 @@
}
}
- template<>
+ template<>
void LoadImageRow<S8>(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width)
{
const unsigned int *sourceI = reinterpret_cast<const unsigned int*>(source);
@@ -339,7 +339,7 @@
{
const unsigned char *inputStart = static_cast<const unsigned char*>(input)+(z * inputPitch * height);
unsigned char *destStart = static_cast<unsigned char*>(buffer)+((zoffset + z) * destPitch * destHeight);
- for(int y = 0; y < height; y++)
+ for(int y = 0; y < height; ++y)
{
const unsigned char *source = inputStart + y * inputPitch;
unsigned char *dest = destStart + (y + yoffset) * destPitch;
@@ -364,7 +364,14 @@
Image::Image(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type)
: parentTexture(parentTexture)
- , egl::Image(getParentResource(parentTexture), width, height, format, type, selectInternalFormat(format, type))
+ , egl::Image(getParentResource(parentTexture), width, height, 1, format, type, selectInternalFormat(format, type))
+ {
+ referenceCount = 1;
+ }
+
+ Image::Image(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type)
+ : parentTexture(parentTexture)
+ , egl::Image(getParentResource(parentTexture), width, height, depth, format, type, selectInternalFormat(format, type))
{
referenceCount = 1;
}
@@ -508,13 +515,11 @@
return sw::FORMAT_A8R8G8B8;
}
- void Image::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *input)
+ void Image::loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *input)
{
GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment);
void *buffer = lock(0, 0, sw::LOCK_WRITEONLY);
- GLint zoffset = 0;
- GLsizei depth = 1;
-
+
if(buffer)
{
switch(type)
@@ -621,7 +626,7 @@
LoadImageData<D32>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, getPitch(), getHeight(), input, buffer);
break;
case GL_UNSIGNED_INT_24_8_OES:
- loadD24S8ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer);
+ loadD24S8ImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, input, buffer);
break;
default: UNREACHABLE();
}
@@ -630,22 +635,27 @@
unlock();
}
- void Image::loadD24S8ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer)
+ void Image::loadD24S8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, const void *input, void *buffer)
{
- LoadImageData<D24>(xoffset, yoffset, 0, width, height, 1, inputPitch, getPitch(), getHeight(), input, buffer);
+ LoadImageData<D24>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, getPitch(), getHeight(), input, buffer);
unsigned char *stencil = reinterpret_cast<unsigned char*>(lockStencil(0, sw::PUBLIC));
if(stencil)
{
- LoadImageData<S8>(xoffset, yoffset, 0, width, height, 1, inputPitch, getStencilPitchB(), getHeight(), input, stencil);
+ LoadImageData<S8>(xoffset, yoffset, zoffset, width, height, depth, inputPitch, getStencilPitchB(), getHeight(), input, stencil);
unlockStencil();
}
}
- void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
+ void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
{
+ if(zoffset != 0 || depth != 1)
+ {
+ UNIMPLEMENTED(); // FIXME
+ }
+
int inputPitch = ComputeCompressedPitch(width, format);
int rows = imageSize / inputPitch;
void *buffer = lock(xoffset, yoffset, sw::LOCK_WRITEONLY);
diff --git a/src/OpenGL/libGLESv2/Image.hpp b/src/OpenGL/libGLESv2/Image.hpp
index 4c1a1ac..3824a8f 100644
--- a/src/OpenGL/libGLESv2/Image.hpp
+++ b/src/OpenGL/libGLESv2/Image.hpp
@@ -26,10 +26,11 @@
{
public:
Image(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type);
+ Image(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type);
Image(Texture *parentTexture, GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable, bool renderTarget);
- void loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *input);
- void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
+ void loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *input);
+ void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
virtual void addRef();
virtual void release();
@@ -40,7 +41,7 @@
private:
virtual ~Image();
- void loadD24S8ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer);
+ void loadD24S8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, const void *input, void *buffer);
egl::Texture *parentTexture;
diff --git a/src/OpenGL/libGLESv2/Program.cpp b/src/OpenGL/libGLESv2/Program.cpp
index 3ffb06b..7599be5 100644
--- a/src/OpenGL/libGLESv2/Program.cpp
+++ b/src/OpenGL/libGLESv2/Program.cpp
@@ -591,7 +591,8 @@
if(targetUniform->type == GL_INT ||
targetUniform->type == GL_SAMPLER_2D ||
targetUniform->type == GL_SAMPLER_CUBE ||
- targetUniform->type == GL_SAMPLER_EXTERNAL_OES)
+ targetUniform->type == GL_SAMPLER_EXTERNAL_OES ||
+ targetUniform->type == GL_SAMPLER_3D_OES)
{
memcpy(targetUniform->data + uniformIndex[location].element * sizeof(GLint),
v, sizeof(GLint) * count);
@@ -924,7 +925,8 @@
case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, size, f); break;
case GL_SAMPLER_2D:
case GL_SAMPLER_CUBE:
- case GL_SAMPLER_EXTERNAL_OES:
+ case GL_SAMPLER_EXTERNAL_OES:
+ case GL_SAMPLER_3D_OES:
case GL_INT: applyUniform1iv(location, size, i); break;
case GL_INT_VEC2: applyUniform2iv(location, size, i); break;
case GL_INT_VEC3: applyUniform3iv(location, size, i); break;
@@ -1315,7 +1317,7 @@
bool Program::defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, int registerIndex)
{
- if(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES)
+ if(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES || type == GL_SAMPLER_3D_OES)
{
int index = registerIndex;
@@ -1326,7 +1328,17 @@
if(index < MAX_VERTEX_TEXTURE_IMAGE_UNITS)
{
samplersVS[index].active = true;
- samplersVS[index].textureType = (type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
+ switch(type) {
+ case GL_SAMPLER_CUBE:
+ samplersVS[index].textureType = TEXTURE_CUBE;
+ break;
+ case GL_SAMPLER_3D_OES:
+ samplersVS[index].textureType = TEXTURE_3D;
+ break;
+ default:
+ samplersVS[index].textureType = TEXTURE_2D;
+ break;
+ }
samplersVS[index].logicalTextureUnit = 0;
}
else
@@ -1340,7 +1352,17 @@
if(index < MAX_TEXTURE_IMAGE_UNITS)
{
samplersPS[index].active = true;
- samplersPS[index].textureType = (type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
+ switch(type) {
+ case GL_SAMPLER_CUBE:
+ samplersPS[index].textureType = TEXTURE_CUBE;
+ break;
+ case GL_SAMPLER_3D_OES:
+ samplersPS[index].textureType = TEXTURE_3D;
+ break;
+ default:
+ samplersPS[index].textureType = TEXTURE_2D;
+ break;
+ }
samplersPS[index].logicalTextureUnit = 0;
}
else
@@ -1737,7 +1759,8 @@
{
if(targetUniform->type == GL_SAMPLER_2D ||
targetUniform->type == GL_SAMPLER_CUBE ||
- targetUniform->type == GL_SAMPLER_EXTERNAL_OES)
+ targetUniform->type == GL_SAMPLER_EXTERNAL_OES ||
+ targetUniform->type == GL_SAMPLER_3D_OES)
{
for(int i = 0; i < count; i++)
{
@@ -1760,7 +1783,8 @@
{
if(targetUniform->type == GL_SAMPLER_2D ||
targetUniform->type == GL_SAMPLER_CUBE ||
- targetUniform->type == GL_SAMPLER_EXTERNAL_OES)
+ targetUniform->type == GL_SAMPLER_EXTERNAL_OES ||
+ targetUniform->type == GL_SAMPLER_3D_OES)
{
for(int i = 0; i < count; i++)
{
diff --git a/src/OpenGL/libGLESv2/Renderbuffer.cpp b/src/OpenGL/libGLESv2/Renderbuffer.cpp
index a88d222..58f5f57 100644
--- a/src/OpenGL/libGLESv2/Renderbuffer.cpp
+++ b/src/OpenGL/libGLESv2/Renderbuffer.cpp
@@ -82,12 +82,12 @@
// Renderbuffers acting as proxies. Here, we notify the texture of a reference.
void RenderbufferTexture2D::addProxyRef(const Renderbuffer *proxy)
{
- mTexture2D->addProxyRef(proxy);
+ mTexture2D->addProxyRef(proxy);
}
void RenderbufferTexture2D::releaseProxy(const Renderbuffer *proxy)
{
- mTexture2D->releaseProxy(proxy);
+ mTexture2D->releaseProxy(proxy);
}
// Increments refcount on image.
@@ -101,12 +101,12 @@
// caller must release() the returned image
egl::Image *RenderbufferTexture2D::createSharedImage()
{
- return mTexture2D->createSharedImage(GL_TEXTURE_2D, 0);
+ return mTexture2D->createSharedImage(GL_TEXTURE_2D, 0);
}
bool RenderbufferTexture2D::isShared() const
{
- return mTexture2D->isShared(GL_TEXTURE_2D, 0);
+ return mTexture2D->isShared(GL_TEXTURE_2D, 0);
}
GLsizei RenderbufferTexture2D::getWidth() const
@@ -134,6 +134,74 @@
return 0;
}
+///// RenderbufferTexture3D Implementation ////////
+
+RenderbufferTexture3D::RenderbufferTexture3D(Texture3D *texture)
+{
+ mTexture3D.set(texture);
+}
+
+RenderbufferTexture3D::~RenderbufferTexture3D()
+{
+ mTexture3D.set(NULL);
+}
+
+// Textures need to maintain their own reference count for references via
+// Renderbuffers acting as proxies. Here, we notify the texture of a reference.
+void RenderbufferTexture3D::addProxyRef(const Renderbuffer *proxy)
+{
+ mTexture3D->addProxyRef(proxy);
+}
+
+void RenderbufferTexture3D::releaseProxy(const Renderbuffer *proxy)
+{
+ mTexture3D->releaseProxy(proxy);
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+egl::Image *RenderbufferTexture3D::getRenderTarget()
+{
+ return mTexture3D->getRenderTarget(GL_TEXTURE_3D_OES, 0);
+}
+
+// Increments refcount on image.
+// caller must release() the returned image
+egl::Image *RenderbufferTexture3D::createSharedImage()
+{
+ return mTexture3D->createSharedImage(GL_TEXTURE_3D_OES, 0);
+}
+
+bool RenderbufferTexture3D::isShared() const
+{
+ return mTexture3D->isShared(GL_TEXTURE_3D_OES, 0);
+}
+
+GLsizei RenderbufferTexture3D::getWidth() const
+{
+ return mTexture3D->getWidth(GL_TEXTURE_3D_OES, 0);
+}
+
+GLsizei RenderbufferTexture3D::getHeight() const
+{
+ return mTexture3D->getHeight(GL_TEXTURE_3D_OES, 0);
+}
+
+GLenum RenderbufferTexture3D::getFormat() const
+{
+ return mTexture3D->getFormat(GL_TEXTURE_3D_OES, 0);
+}
+
+sw::Format RenderbufferTexture3D::getInternalFormat() const
+{
+ return mTexture3D->getInternalFormat(GL_TEXTURE_3D_OES, 0);
+}
+
+GLsizei RenderbufferTexture3D::getSamples() const
+{
+ return 0;
+}
+
///// RenderbufferTextureCubeMap Implementation ////////
RenderbufferTextureCubeMap::RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target) : mTarget(target)
@@ -361,7 +429,7 @@
mHeight = renderTarget->getHeight();
internalFormat = renderTarget->getInternalFormat();
format = sw2es::ConvertBackBufferFormat(internalFormat);
- mSamples = renderTarget->getMultiSampleDepth() & ~1;
+ mSamples = renderTarget->getDepth() & ~1;
}
}
@@ -438,7 +506,7 @@
mHeight = depthStencil->getHeight();
internalFormat = depthStencil->getInternalFormat();
format = sw2es::ConvertDepthStencilFormat(internalFormat);
- mSamples = depthStencil->getMultiSampleDepth() & ~1;
+ mSamples = depthStencil->getDepth() & ~1;
}
}
diff --git a/src/OpenGL/libGLESv2/Renderbuffer.h b/src/OpenGL/libGLESv2/Renderbuffer.h
index b8e9d0d..bd322e7 100644
--- a/src/OpenGL/libGLESv2/Renderbuffer.h
+++ b/src/OpenGL/libGLESv2/Renderbuffer.h
@@ -26,6 +26,7 @@
namespace es2
{
class Texture2D;
+class Texture3D;
class TextureCubeMap;
class Renderbuffer;
class Colorbuffer;
@@ -83,6 +84,30 @@
gl::BindingPointer<Texture2D> mTexture2D;
};
+class RenderbufferTexture3D : public RenderbufferInterface
+{
+public:
+ RenderbufferTexture3D(Texture3D *texture);
+
+ virtual ~RenderbufferTexture3D();
+
+ virtual void addProxyRef(const Renderbuffer *proxy);
+ virtual void releaseProxy(const Renderbuffer *proxy);
+
+ virtual egl::Image *getRenderTarget();
+ virtual egl::Image *createSharedImage();
+ virtual bool isShared() const;
+
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getFormat() const;
+ virtual sw::Format getInternalFormat() const;
+ virtual GLsizei getSamples() const;
+
+private:
+ gl::BindingPointer<Texture3D> mTexture3D;
+};
+
class RenderbufferTextureCubeMap : public RenderbufferInterface
{
public:
diff --git a/src/OpenGL/libGLESv2/ResourceManager.cpp b/src/OpenGL/libGLESv2/ResourceManager.cpp
index e3be9bc..2f6fd74 100644
--- a/src/OpenGL/libGLESv2/ResourceManager.cpp
+++ b/src/OpenGL/libGLESv2/ResourceManager.cpp
@@ -307,11 +307,15 @@
{
textureObject = new TextureCubeMap(texture);
}
- else if(type == TEXTURE_EXTERNAL)
- {
- textureObject = new TextureExternal(texture);
- }
- else
+ else if(type == TEXTURE_EXTERNAL)
+ {
+ textureObject = new TextureExternal(texture);
+ }
+ else if(type == TEXTURE_3D)
+ {
+ textureObject = new Texture3D(texture);
+ }
+ else
{
UNREACHABLE();
return;
diff --git a/src/OpenGL/libGLESv2/ResourceManager.h b/src/OpenGL/libGLESv2/ResourceManager.h
index 699944f..d7d626d 100644
--- a/src/OpenGL/libGLESv2/ResourceManager.h
+++ b/src/OpenGL/libGLESv2/ResourceManager.h
@@ -33,6 +33,7 @@
enum TextureType
{
TEXTURE_2D,
+ TEXTURE_3D,
TEXTURE_CUBE,
TEXTURE_EXTERNAL,
diff --git a/src/OpenGL/libGLESv2/Texture.cpp b/src/OpenGL/libGLESv2/Texture.cpp
index 4964bce..982c7c8 100644
--- a/src/OpenGL/libGLESv2/Texture.cpp
+++ b/src/OpenGL/libGLESv2/Texture.cpp
@@ -10,7 +10,7 @@
//
// Texture.cpp: Implements the Texture class and its derived classes
-// Texture2D and TextureCubeMap. Implements GL texture objects and related
+// Texture2D, TextureCubeMap and Texture3D. Implements GL texture objects and related
// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
#include "Texture.h"
@@ -34,6 +34,7 @@
mMagFilter = GL_LINEAR;
mWrapS = GL_REPEAT;
mWrapT = GL_REPEAT;
+ mWrapR = GL_REPEAT;
mMaxAnisotropy = 1.0f;
resource = new sw::Resource(0);
@@ -109,21 +110,41 @@
// Returns true on successful wrap state update (valid enum parameter)
bool Texture::setWrapT(GLenum wrap)
{
- switch(wrap)
- {
- case GL_REPEAT:
- case GL_MIRRORED_REPEAT:
- if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
- {
- return false;
- }
- // Fall through
- case GL_CLAMP_TO_EDGE:
- mWrapT = wrap;
- return true;
- default:
- return false;
- }
+ switch(wrap)
+ {
+ case GL_REPEAT:
+ case GL_MIRRORED_REPEAT:
+ if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
+ {
+ return false;
+ }
+ // Fall through
+ case GL_CLAMP_TO_EDGE:
+ mWrapT = wrap;
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful wrap state update (valid enum parameter)
+bool Texture::setWrapR(GLenum wrap)
+{
+ switch(wrap)
+ {
+ case GL_REPEAT:
+ case GL_MIRRORED_REPEAT:
+ if(getTarget() == GL_TEXTURE_EXTERNAL_OES)
+ {
+ return false;
+ }
+ // Fall through
+ case GL_CLAMP_TO_EDGE:
+ mWrapR = wrap;
+ return true;
+ default:
+ return false;
+ }
}
// Returns true on successful max anisotropy update (valid anisotropy value)
@@ -161,7 +182,12 @@
GLenum Texture::getWrapT() const
{
- return mWrapT;
+ return mWrapT;
+}
+
+GLenum Texture::getWrapR() const
+{
+ return mWrapR;
}
GLfloat Texture::getMaxAnisotropy() const
@@ -169,6 +195,11 @@
return mMaxAnisotropy;
}
+GLsizei Texture::getDepth(GLenum target, GLint level) const
+{
+ return 1;
+}
+
egl::Image *Texture::createSharedImage(GLenum target, unsigned int level)
{
egl::Image *image = getRenderTarget(target, level); // Increments reference count
@@ -185,7 +216,8 @@
{
if(pixels && image)
{
- image->loadImageData(0, 0, image->getWidth(), image->getHeight(), format, type, unpackAlignment, pixels);
+ GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES) ? image->getDepth() : 1;
+ image->loadImageData(0, 0, 0, image->getWidth(), image->getHeight(), depth, format, type, unpackAlignment, pixels);
}
}
@@ -193,18 +225,19 @@
{
if(pixels && image)
{
- image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), imageSize, pixels);
+ GLsizei depth = (getTarget() == GL_TEXTURE_3D_OES) ? image->getDepth() : 1;
+ image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), depth, imageSize, pixels);
}
}
-void Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
+void Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image)
{
if(!image)
{
return error(GL_INVALID_OPERATION);
}
- if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
+ if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth())
{
return error(GL_INVALID_VALUE);
}
@@ -221,18 +254,18 @@
if(pixels)
{
- image->loadImageData(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels);
+ image->loadImageData(xoffset, yoffset, zoffset, width, height, depth, format, type, unpackAlignment, pixels);
}
}
-void Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image)
+void Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image)
{
if(!image)
{
return error(GL_INVALID_OPERATION);
}
- if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight())
+ if(width + xoffset > image->getWidth() || height + yoffset > image->getHeight() || depth + zoffset > image->getDepth())
{
return error(GL_INVALID_VALUE);
}
@@ -244,7 +277,7 @@
if(pixels)
{
- image->loadCompressedData(xoffset, yoffset, width, height, imageSize, pixels);
+ image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, imageSize, pixels);
}
}
@@ -467,12 +500,12 @@
void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
{
- Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[level]);
+ Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackAlignment, pixels, image[level]);
}
void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
{
- Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[level]);
+ Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[level]);
}
void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
@@ -508,7 +541,7 @@
renderTarget->release();
}
-void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
{
if(!image[level])
{
@@ -847,12 +880,12 @@
void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
{
- Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, image[CubeFaceIndex(target)][level]);
+ Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpackAlignment, pixels, image[CubeFaceIndex(target)][level]);
}
void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
{
- Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
+ Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, image[CubeFaceIndex(target)][level]);
}
// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
@@ -1031,7 +1064,7 @@
return image[CubeFaceIndex(face)][level];
}
-void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
{
int face = CubeFaceIndex(target);
@@ -1140,12 +1173,402 @@
return image[face][level]->isShared();
}
+Texture3D::Texture3D(GLuint id) : Texture(id)
+{
+ for(int i = 0; i < MIPMAP_LEVELS; i++)
+ {
+ image[i] = 0;
+ }
+
+ mSurface = NULL;
+
+ mColorbufferProxy = NULL;
+ mProxyRefs = 0;
+}
+
+Texture3D::~Texture3D()
+{
+ resource->lock(sw::DESTRUCT);
+
+ for(int i = 0; i < MIPMAP_LEVELS; i++)
+ {
+ if(image[i])
+ {
+ image[i]->unbind(this);
+ image[i] = 0;
+ }
+ }
+
+ resource->unlock();
+
+ if(mSurface)
+ {
+ mSurface->setBoundTexture(NULL);
+ mSurface = NULL;
+ }
+
+ mColorbufferProxy = NULL;
+}
+
+// We need to maintain a count of references to renderbuffers acting as
+// proxies for this texture, so that we do not attempt to use a pointer
+// to a renderbuffer proxy which has been deleted.
+void Texture3D::addProxyRef(const Renderbuffer *proxy)
+{
+ mProxyRefs++;
+}
+
+void Texture3D::releaseProxy(const Renderbuffer *proxy)
+{
+ if(mProxyRefs > 0)
+ {
+ mProxyRefs--;
+ }
+
+ if(mProxyRefs == 0)
+ {
+ mColorbufferProxy = NULL;
+ }
+}
+
+GLenum Texture3D::getTarget() const
+{
+ return GL_TEXTURE_3D_OES;
+}
+
+GLsizei Texture3D::getWidth(GLenum target, GLint level) const
+{
+ ASSERT(target == GL_TEXTURE_3D_OES);
+ return image[level] ? image[level]->getWidth() : 0;
+}
+
+GLsizei Texture3D::getHeight(GLenum target, GLint level) const
+{
+ ASSERT(target == GL_TEXTURE_3D_OES);
+ return image[level] ? image[level]->getHeight() : 0;
+}
+
+GLsizei Texture3D::getDepth(GLenum target, GLint level) const
+{
+ ASSERT(target == GL_TEXTURE_3D_OES);
+ return image[level] ? image[level]->getDepth() : 0;
+}
+
+GLenum Texture3D::getFormat(GLenum target, GLint level) const
+{
+ ASSERT(target == GL_TEXTURE_3D_OES);
+ return image[level] ? image[level]->getFormat() : 0;
+}
+
+GLenum Texture3D::getType(GLenum target, GLint level) const
+{
+ ASSERT(target == GL_TEXTURE_3D_OES);
+ return image[level] ? image[level]->getType() : 0;
+}
+
+sw::Format Texture3D::getInternalFormat(GLenum target, GLint level) const
+{
+ ASSERT(target == GL_TEXTURE_3D_OES);
+ return image[level] ? image[level]->getInternalFormat() : sw::FORMAT_NULL;
+}
+
+int Texture3D::getLevelCount() const
+{
+ ASSERT(isSamplerComplete());
+ int levels = 0;
+
+ while(levels < MIPMAP_LEVELS && image[levels])
+ {
+ levels++;
+ }
+
+ return levels;
+}
+
+void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ if(image[level])
+ {
+ image[level]->unbind(this);
+ }
+
+ image[level] = new Image(this, width, height, depth, format, type);
+
+ if(!image[level])
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ Texture::setImage(format, type, unpackAlignment, pixels, image[level]);
+}
+
+void Texture3D::bindTexImage(egl::Surface *surface)
+{
+ GLenum format;
+
+ switch(surface->getInternalFormat())
+ {
+ case sw::FORMAT_A8R8G8B8:
+ format = GL_RGBA;
+ break;
+ case sw::FORMAT_X8R8G8B8:
+ format = GL_RGB;
+ break;
+ default:
+ UNIMPLEMENTED();
+ return;
+ }
+
+ for(int level = 0; level < MIPMAP_LEVELS; level++)
+ {
+ if(image[level])
+ {
+ image[level]->unbind(this);
+ image[level] = 0;
+ }
+ }
+
+ image[0] = surface->getRenderTarget();
+
+ mSurface = surface;
+ mSurface->setBoundTexture(this);
+}
+
+void Texture3D::releaseTexImage()
+{
+ for(int level = 0; level < MIPMAP_LEVELS; level++)
+ {
+ if(image[level])
+ {
+ image[level]->unbind(this);
+ image[level] = 0;
+ }
+ }
+}
+
+void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
+{
+ if(image[level])
+ {
+ image[level]->unbind(this);
+ }
+
+ image[level] = new Image(this, width, height, depth, format, GL_UNSIGNED_BYTE);
+
+ if(!image[level])
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ Texture::setCompressedImage(imageSize, pixels, image[level]);
+}
+
+void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ Texture::subImage(xoffset, yoffset, zoffset, width, height, format, depth, type, unpackAlignment, pixels, image[level]);
+}
+
+void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
+{
+ Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, image[level]);
+}
+
+void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source)
+{
+ UNIMPLEMENTED();
+}
+
+void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ if(zoffset != 0)
+ {
+ UNIMPLEMENTED(); // FIXME: add support for copying into a layer other than layer 0
+ }
+
+ if(!image[level])
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ egl::Image *renderTarget = source->getRenderTarget();
+
+ if(!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ sw::Rect sourceRect = { x, y, x + width, y + height };
+ sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());
+
+ copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, image[level]);
+
+ renderTarget->release();
+}
+
+void Texture3D::setImage(egl::Image *sharedImage)
+{
+ sharedImage->addRef();
+
+ if(image[0])
+ {
+ image[0]->unbind(this);
+ }
+
+ image[0] = sharedImage;
+}
+
+// Tests for 3D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
+bool Texture3D::isSamplerComplete() const
+{
+ if(!image[0])
+ {
+ return false;
+ }
+
+ GLsizei width = image[0]->getWidth();
+ GLsizei height = image[0]->getHeight();
+ GLsizei depth = image[0]->getDepth();
+
+ if(width <= 0 || height <= 0 || depth <= 0)
+ {
+ return false;
+ }
+
+ if(isMipmapFiltered())
+ {
+ if(!isMipmapComplete())
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Tests for 3D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
+bool Texture3D::isMipmapComplete() const
+{
+ GLsizei width = image[0]->getWidth();
+ GLsizei height = image[0]->getHeight();
+ GLsizei depth = image[0]->getDepth();
+
+ int q = log2(std::max(std::max(width, height), depth));
+
+ for(int level = 1; level <= q; level++)
+ {
+ if(!image[level])
+ {
+ return false;
+ }
+
+ if(image[level]->getFormat() != image[0]->getFormat())
+ {
+ return false;
+ }
+
+ if(image[level]->getType() != image[0]->getType())
+ {
+ return false;
+ }
+
+ if(image[level]->getWidth() != std::max(1, width >> level))
+ {
+ return false;
+ }
+
+ if(image[level]->getHeight() != std::max(1, height >> level))
+ {
+ return false;
+ }
+
+ if(image[level]->getDepth() != std::max(1, depth >> level))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool Texture3D::isCompressed(GLenum target, GLint level) const
+{
+ return IsCompressed(getFormat(target, level));
+}
+
+bool Texture3D::isDepth(GLenum target, GLint level) const
+{
+ return IsDepthTexture(getFormat(target, level));
+}
+
+void Texture3D::generateMipmaps()
+{
+ UNIMPLEMENTED();
+}
+
+egl::Image *Texture3D::getImage(unsigned int level)
+{
+ return image[level];
+}
+
+Renderbuffer *Texture3D::getRenderbuffer(GLenum target)
+{
+ if(target != GL_TEXTURE_3D_OES)
+ {
+ return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
+ }
+
+ if(mColorbufferProxy == NULL)
+ {
+ mColorbufferProxy = new Renderbuffer(id(), new RenderbufferTexture3D(this));
+ }
+
+ return mColorbufferProxy;
+}
+
+egl::Image *Texture3D::getRenderTarget(GLenum target, unsigned int level)
+{
+ ASSERT(target == GL_TEXTURE_3D_OES);
+ ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
+
+ if(image[level])
+ {
+ image[level]->addRef();
+ }
+
+ return image[level];
+}
+
+bool Texture3D::isShared(GLenum target, unsigned int level) const
+{
+ ASSERT(target == GL_TEXTURE_3D_OES);
+ ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
+
+ if(mSurface) // Bound to an EGLSurface
+ {
+ return true;
+ }
+
+ if(!image[level])
+ {
+ return false;
+ }
+
+ return image[level]->isShared();
+}
+
TextureExternal::TextureExternal(GLuint id) : Texture2D(id)
{
mMinFilter = GL_LINEAR;
mMagFilter = GL_LINEAR;
mWrapS = GL_CLAMP_TO_EDGE;
- mWrapT = GL_CLAMP_TO_EDGE;
+ mWrapT = GL_CLAMP_TO_EDGE;
+ mWrapR = GL_CLAMP_TO_EDGE;
}
TextureExternal::~TextureExternal()
diff --git a/src/OpenGL/libGLESv2/Texture.h b/src/OpenGL/libGLESv2/Texture.h
index 100cf01..ae0ec86 100644
--- a/src/OpenGL/libGLESv2/Texture.h
+++ b/src/OpenGL/libGLESv2/Texture.h
@@ -63,17 +63,20 @@
bool setMinFilter(GLenum filter);
bool setMagFilter(GLenum filter);
bool setWrapS(GLenum wrap);
- bool setWrapT(GLenum wrap);
+ bool setWrapT(GLenum wrap);
+ bool setWrapR(GLenum wrap);
bool setMaxAnisotropy(GLfloat textureMaxAnisotropy);
GLenum getMinFilter() const;
GLenum getMagFilter() const;
GLenum getWrapS() const;
- GLenum getWrapT() const;
+ GLenum getWrapT() const;
+ GLenum getWrapR() const;
GLfloat getMaxAnisotropy() const;
virtual GLsizei getWidth(GLenum target, GLint level) const = 0;
- virtual GLsizei getHeight(GLenum target, GLint level) const = 0;
+ virtual GLsizei getHeight(GLenum target, GLint level) const = 0;
+ virtual GLsizei getDepth(GLenum target, GLint level) const;
virtual GLenum getFormat(GLenum target, GLint level) const = 0;
virtual GLenum getType(GLenum target, GLint level) const = 0;
virtual sw::Format getInternalFormat(GLenum target, GLint level) const = 0;
@@ -89,13 +92,13 @@
virtual bool isShared(GLenum target, unsigned int level) const = 0;
virtual void generateMipmaps() = 0;
- virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0;
+ virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0;
protected:
void setImage(GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image);
- void subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image);
+ void subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, egl::Image *image);
void setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image);
- void subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image);
+ void subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image);
bool copy(egl::Image *source, const sw::Rect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, egl::Image *dest);
@@ -105,6 +108,7 @@
GLenum mMagFilter;
GLenum mWrapS;
GLenum mWrapT;
+ GLenum mWrapR;
GLfloat mMaxAnisotropy;
sw::Resource *resource;
@@ -134,7 +138,7 @@
void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
- void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+ void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
void setImage(egl::Image *image);
@@ -193,7 +197,7 @@
void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
- virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+ virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
virtual bool isSamplerComplete() const;
virtual bool isCompressed(GLenum target, GLint level) const;
@@ -226,6 +230,65 @@
unsigned int mFaceProxyRefs[6];
};
+class Texture3D : public Texture
+{
+public:
+ explicit Texture3D(GLuint id);
+
+ virtual ~Texture3D();
+
+ void addProxyRef(const Renderbuffer *proxy);
+ void releaseProxy(const Renderbuffer *proxy);
+
+ virtual GLenum getTarget() const;
+
+ virtual GLsizei getWidth(GLenum target, GLint level) const;
+ virtual GLsizei getHeight(GLenum target, GLint level) const;
+ virtual GLsizei getDepth(GLenum target, GLint level) const;
+ virtual GLenum getFormat(GLenum target, GLint level) const;
+ virtual GLenum getType(GLenum target, GLint level) const;
+ virtual sw::Format getInternalFormat(GLenum target, GLint level) const;
+ virtual int getLevelCount() const;
+
+ void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels);
+ void subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels);
+ void copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source);
+ void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+
+ void setImage(egl::Image *image);
+
+ virtual bool isSamplerComplete() const;
+ virtual bool isCompressed(GLenum target, GLint level) const;
+ virtual bool isDepth(GLenum target, GLint level) const;
+ virtual void bindTexImage(egl::Surface *surface);
+ virtual void releaseTexImage();
+
+ virtual void generateMipmaps();
+
+ virtual Renderbuffer *getRenderbuffer(GLenum target);
+ virtual egl::Image *getRenderTarget(GLenum target, unsigned int level);
+ virtual bool isShared(GLenum target, unsigned int level) const;
+
+ egl::Image *getImage(unsigned int level);
+
+protected:
+ bool isMipmapComplete() const;
+
+ egl::Image *image[IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+
+ egl::Surface *mSurface;
+
+ // A specific internal reference count is kept for colorbuffer proxy references,
+ // because, as the renderbuffer acting as proxy will maintain a binding pointer
+ // back to this texture, there would be a circular reference if we used a binding
+ // pointer here. This reference count will cause the pointer to be set to NULL if
+ // the count drops to zero, but will not cause deletion of the Renderbuffer.
+ Renderbuffer *mColorbufferProxy;
+ unsigned int mProxyRefs;
+};
+
class TextureExternal : public Texture2D
{
public:
diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index 7f289dc..f354579 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -33,6 +33,15 @@
#include <exception>
#include <limits>
+typedef std::pair<GLenum, GLenum> InternalFormatTypePair;
+typedef std::map<InternalFormatTypePair, GLenum> FormatMap;
+
+// A helper function to insert data into the format map with fewer characters.
+static void InsertFormatMapping(FormatMap& map, GLenum internalformat, GLenum format, GLenum type)
+{
+ map[InternalFormatTypePair(internalformat, type)] = format;
+}
+
static bool validImageSize(GLint level, GLsizei width, GLsizei height)
{
if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || width < 0 || height < 0)
@@ -63,14 +72,14 @@
if(compressed)
{
if((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
- (height % 4 != 0 && height != texture->getHeight(target, 0)))
+ (height % 4 != 0 && height != texture->getHeight(target, 0)))
{
return error(GL_INVALID_OPERATION, false);
}
}
if(xoffset + width > texture->getWidth(target, level) ||
- yoffset + height > texture->getHeight(target, level))
+ yoffset + height > texture->getHeight(target, level))
{
return error(GL_INVALID_VALUE, false);
}
@@ -78,6 +87,200 @@
return true;
}
+static bool validateSubImageParams(bool compressed, GLsizei width, GLsizei height, GLsizei depth, GLint xoffset, GLint yoffset, GLint zoffset, GLenum target, GLint level, GLenum format, es2::Texture *texture)
+{
+ if(!texture)
+ {
+ return error(GL_INVALID_OPERATION, false);
+ }
+
+ if(compressed != texture->isCompressed(target, level))
+ {
+ return error(GL_INVALID_OPERATION, false);
+ }
+
+ if(format != GL_NONE && format != texture->getFormat(target, level))
+ {
+ return error(GL_INVALID_OPERATION, false);
+ }
+
+ if(compressed)
+ {
+ if((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
+ (height % 4 != 0 && height != texture->getHeight(target, 0)) ||
+ (depth % 4 != 0 && depth != texture->getDepth(target, 0)))
+ {
+ return error(GL_INVALID_OPERATION, false);
+ }
+ }
+
+ if(xoffset + width > texture->getWidth(target, level) ||
+ yoffset + height > texture->getHeight(target, level) ||
+ zoffset + depth > texture->getDepth(target, level))
+ {
+ return error(GL_INVALID_VALUE, false);
+ }
+
+ return true;
+}
+
+static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFormat)
+{
+ // [OpenGL ES 2.0.24] table 3.9
+ switch(textureFormat)
+ {
+ case GL_ALPHA:
+ if(colorbufferFormat != GL_ALPHA &&
+ colorbufferFormat != GL_RGBA &&
+ colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return error(GL_INVALID_OPERATION, false);
+ }
+ break;
+ case GL_LUMINANCE:
+ case GL_RGB:
+ if(colorbufferFormat != GL_RGB &&
+ colorbufferFormat != GL_RGB565 &&
+ colorbufferFormat != GL_RGB8_OES &&
+ colorbufferFormat != GL_RGBA &&
+ colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return error(GL_INVALID_OPERATION, false);
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGBA:
+ if(colorbufferFormat != GL_RGBA &&
+ colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return error(GL_INVALID_OPERATION, false);
+ }
+ break;
+ case GL_ETC1_RGB8_OES:
+ return error(GL_INVALID_OPERATION, false);
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ if(S3TC_SUPPORT)
+ {
+ return error(GL_INVALID_OPERATION, false);
+ }
+ else
+ {
+ return error(GL_INVALID_ENUM, false);
+ }
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_STENCIL_OES:
+ return error(GL_INVALID_OPERATION, false);
+ default:
+ return error(GL_INVALID_ENUM, false);
+ }
+ return true;
+}
+
+static FormatMap BuildFormatMap3D()
+{
+ FormatMap map;
+
+ // Internal format | Format | Type
+ InsertFormatMapping(map, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
+ InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4);
+ InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
+ InsertFormatMapping(map, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_R8_EXT, GL_RED_EXT, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_R16F_EXT, GL_RED_EXT, GL_HALF_FLOAT_OES);
+ InsertFormatMapping(map, GL_R16F_EXT, GL_RED_EXT, GL_FLOAT);
+ InsertFormatMapping(map, GL_R32F_EXT, GL_RED_EXT, GL_FLOAT);
+ InsertFormatMapping(map, GL_RG8_EXT, GL_RG_EXT, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_R16F_EXT, GL_RED_EXT, GL_HALF_FLOAT_OES);
+ InsertFormatMapping(map, GL_R16F_EXT, GL_RED_EXT, GL_FLOAT);
+ InsertFormatMapping(map, GL_RG32F_EXT, GL_RG_EXT, GL_FLOAT);
+ InsertFormatMapping(map, GL_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_SRGB8_NV, GL_RGB, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
+ InsertFormatMapping(map, GL_RGB16F_EXT, GL_HALF_FLOAT_OES, GL_FLOAT);
+ InsertFormatMapping(map, GL_RGB32F_EXT, GL_RGB, GL_FLOAT);
+ InsertFormatMapping(map, GL_RGBA8_OES, GL_RGBA, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_SRGB8_ALPHA8_EXT, GL_RGBA, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
+ InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV_EXT);
+ InsertFormatMapping(map, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE);
+ InsertFormatMapping(map, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4);
+ InsertFormatMapping(map, GL_RGB10_A2_EXT, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV_EXT);
+ InsertFormatMapping(map, GL_RGBA16F_EXT, GL_RGBA, GL_HALF_FLOAT_OES);
+ InsertFormatMapping(map, GL_RGBA16F_EXT, GL_RGBA, GL_FLOAT);
+ InsertFormatMapping(map, GL_RGBA32F_EXT, GL_RGBA, GL_FLOAT);
+
+ return map;
+}
+
+static bool ValidateType3D(GLenum type)
+{
+ switch(type)
+ {
+ case GL_UNSIGNED_BYTE:
+ case GL_BYTE:
+ case GL_UNSIGNED_SHORT:
+ case GL_SHORT:
+ case GL_UNSIGNED_INT:
+ case GL_INT:
+ case GL_HALF_FLOAT_OES:
+ case GL_FLOAT:
+ case GL_UNSIGNED_SHORT_5_6_5:
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ case GL_UNSIGNED_INT_2_10_10_10_REV_EXT:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static bool ValidateFormat3D(GLenum format)
+{
+ switch(format)
+ {
+ case GL_RED_EXT:
+ case GL_RG_EXT:
+ case GL_RGB:
+ case GL_RGBA:
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_STENCIL_OES:
+ case GL_LUMINANCE_ALPHA:
+ case GL_LUMINANCE:
+ case GL_ALPHA:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static bool ValidateInternalFormat3D(GLenum internalformat, GLenum format, GLenum type)
+{
+ static const FormatMap formatMap = BuildFormatMap3D();
+ FormatMap::const_iterator iter = formatMap.find(InternalFormatTypePair(internalformat, type));
+ if(iter != formatMap.end())
+ {
+ return iter->second == format;
+ }
+ return false;
+}
+
extern "C"
{
@@ -301,6 +504,9 @@
case GL_TEXTURE_EXTERNAL_OES:
context->bindTextureExternal(texture);
return;
+ case GL_TEXTURE_3D_OES:
+ context->bindTexture3D(texture);
+ return;
default:
return error(GL_INVALID_ENUM);
}
@@ -730,7 +936,7 @@
if(context)
{
- if(level > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ if(level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
return error(GL_INVALID_VALUE);
}
@@ -850,7 +1056,7 @@
if(context)
{
- if(level > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ if(level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
return error(GL_INVALID_VALUE);
}
@@ -956,58 +1162,9 @@
es2::Renderbuffer *source = framebuffer->getColorbuffer();
GLenum colorbufferFormat = source->getFormat();
- // [OpenGL ES 2.0.24] table 3.9
- switch(internalformat)
+ if(!validateColorBufferFormat(internalformat, colorbufferFormat))
{
- case GL_ALPHA:
- if(colorbufferFormat != GL_ALPHA &&
- colorbufferFormat != GL_RGBA &&
- colorbufferFormat != GL_RGBA4 &&
- colorbufferFormat != GL_RGB5_A1 &&
- colorbufferFormat != GL_RGBA8_OES)
- {
- return error(GL_INVALID_OPERATION);
- }
- break;
- case GL_LUMINANCE:
- case GL_RGB:
- if(colorbufferFormat != GL_RGB &&
- colorbufferFormat != GL_RGB565 &&
- colorbufferFormat != GL_RGB8_OES &&
- colorbufferFormat != GL_RGBA &&
- colorbufferFormat != GL_RGBA4 &&
- colorbufferFormat != GL_RGB5_A1 &&
- colorbufferFormat != GL_RGBA8_OES)
- {
- return error(GL_INVALID_OPERATION);
- }
- break;
- case GL_LUMINANCE_ALPHA:
- case GL_RGBA:
- if(colorbufferFormat != GL_RGBA &&
- colorbufferFormat != GL_RGBA4 &&
- colorbufferFormat != GL_RGB5_A1 &&
- colorbufferFormat != GL_RGBA8_OES)
- {
- return error(GL_INVALID_OPERATION);
- }
- break;
- case GL_ETC1_RGB8_OES:
- return error(GL_INVALID_OPERATION);
- case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
- case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
- if(S3TC_SUPPORT)
- {
- return error(GL_INVALID_OPERATION);
- }
- else
- {
- return error(GL_INVALID_ENUM);
- }
- default:
- return error(GL_INVALID_ENUM);
+ return;
}
if(target == GL_TEXTURE_2D)
@@ -1066,7 +1223,7 @@
if(context)
{
- if(level > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ if(level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
return error(GL_INVALID_VALUE);
}
@@ -1104,64 +1261,12 @@
GLenum textureFormat = texture->getFormat(target, level);
- // [OpenGL ES 2.0.24] table 3.9
- switch(textureFormat)
+ if(!validateColorBufferFormat(textureFormat, colorbufferFormat))
{
- case GL_ALPHA:
- if(colorbufferFormat != GL_ALPHA &&
- colorbufferFormat != GL_RGBA &&
- colorbufferFormat != GL_RGBA4 &&
- colorbufferFormat != GL_RGB5_A1 &&
- colorbufferFormat != GL_RGBA8_OES)
- {
- return error(GL_INVALID_OPERATION);
- }
- break;
- case GL_LUMINANCE:
- case GL_RGB:
- if(colorbufferFormat != GL_RGB &&
- colorbufferFormat != GL_RGB565 &&
- colorbufferFormat != GL_RGB8_OES &&
- colorbufferFormat != GL_RGBA &&
- colorbufferFormat != GL_RGBA4 &&
- colorbufferFormat != GL_RGB5_A1 &&
- colorbufferFormat != GL_RGBA8_OES)
- {
- return error(GL_INVALID_OPERATION);
- }
- break;
- case GL_LUMINANCE_ALPHA:
- case GL_RGBA:
- if(colorbufferFormat != GL_RGBA &&
- colorbufferFormat != GL_RGBA4 &&
- colorbufferFormat != GL_RGB5_A1 &&
- colorbufferFormat != GL_RGBA8_OES)
- {
- return error(GL_INVALID_OPERATION);
- }
- break;
- case GL_ETC1_RGB8_OES:
- return error(GL_INVALID_OPERATION);
- case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
- case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
- if(S3TC_SUPPORT)
- {
- return error(GL_INVALID_OPERATION);
- }
- else
- {
- return error(GL_INVALID_ENUM);
- }
- case GL_DEPTH_COMPONENT:
- case GL_DEPTH_STENCIL_OES:
- return error(GL_INVALID_OPERATION);
- default:
- return error(GL_INVALID_ENUM);
+ return;
}
- texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, framebuffer);
+ texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer);
}
}
@@ -2861,6 +2966,7 @@
"GL_OES_texture_half_float "
"GL_OES_texture_half_float_linear "
"GL_OES_texture_npot "
+ "GL_OES_texture_3D "
"GL_EXT_blend_minmax "
"GL_EXT_occlusion_query_boolean "
"GL_EXT_read_format_bgra "
@@ -2920,6 +3026,9 @@
case GL_TEXTURE_WRAP_T:
*params = (GLfloat)texture->getWrapT();
break;
+ case GL_TEXTURE_WRAP_R_OES:
+ *params = (GLfloat)texture->getWrapR();
+ break;
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
*params = texture->getMaxAnisotropy();
break;
@@ -2971,6 +3080,9 @@
case GL_TEXTURE_WRAP_T:
*params = texture->getWrapT();
break;
+ case GL_TEXTURE_WRAP_R_OES:
+ *params = texture->getWrapR();
+ break;
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
*params = (GLint)texture->getMaxAnisotropy();
break;
@@ -4144,6 +4256,9 @@
case GL_TEXTURE_2D:
texture = context->getTexture2D();
break;
+ case GL_TEXTURE_3D_OES:
+ texture = context->getTexture3D();
+ break;
case GL_TEXTURE_CUBE_MAP:
texture = context->getTextureCubeMap();
break;
@@ -4168,6 +4283,12 @@
return error(GL_INVALID_ENUM);
}
break;
+ case GL_TEXTURE_WRAP_R_OES:
+ if(!texture->setWrapR((GLenum)param))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
case GL_TEXTURE_MIN_FILTER:
if(!texture->setMinFilter((GLenum)param))
{
@@ -4212,6 +4333,9 @@
case GL_TEXTURE_2D:
texture = context->getTexture2D();
break;
+ case GL_TEXTURE_3D_OES:
+ texture = context->getTexture3D();
+ break;
case GL_TEXTURE_CUBE_MAP:
texture = context->getTextureCubeMap();
break;
@@ -4236,6 +4360,12 @@
return error(GL_INVALID_ENUM);
}
break;
+ case GL_TEXTURE_WRAP_R_OES:
+ if(!texture->setWrapR((GLenum)param))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
case GL_TEXTURE_MIN_FILTER:
if(!texture->setMinFilter((GLenum)param))
{
@@ -4302,7 +4432,7 @@
if(context)
{
- if(level > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ if(level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
return error(GL_INVALID_VALUE);
}
@@ -5047,9 +5177,373 @@
"GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* pixels = 0x%0.8p)",
target, level, internalformat, width, height, depth, border, format, type, pixels);
- UNIMPLEMENTED(); // FIXME
+ switch(target)
+ {
+ case GL_TEXTURE_3D_OES:
+ switch(format)
+ {
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_STENCIL_OES:
+ return error(GL_INVALID_OPERATION);
+ default:
+ break;
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(!ValidateType3D(type) || !ValidateFormat3D(format))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ const GLsizei maxSize3D = es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level;
+ if((width < 0) || (height < 0) || (depth < 0) || (width > maxSize3D) || (height > maxSize3D) || (depth > maxSize3D))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(border != 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if(!ValidateInternalFormat3D(internalformat, format, type))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ es2::Context *context = es2::getContext();
+
+ if(context)
+ {
+ es2::Texture3D *texture = context->getTexture3D();
+
+ if(!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->setImage(level, width, height, depth, internalformat, type, context->getUnpackAlignment(), pixels);
+ }
}
+void GL_APIENTRY glTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels)
+{
+ TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, "
+ "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* pixels = 0x%0.8p)",
+ target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
+
+ switch(target)
+ {
+ case GL_TEXTURE_3D_OES:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(!ValidateType3D(type) || !ValidateFormat3D(format))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if((width < 0) || (height < 0) || (depth < 0))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ es2::Context *context = es2::getContext();
+
+ if(context)
+ {
+ es2::Texture3D *texture = context->getTexture3D();
+
+ if(validateSubImageParams(false, width, height, depth, xoffset, yoffset, zoffset, target, level, format, texture))
+ {
+ texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getUnpackAlignment(), pixels);
+ }
+ }
+}
+
+void GL_APIENTRY glCopyTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLint zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
+ target, level, xoffset, yoffset, zoffset, x, y, width, height);
+
+ switch(target)
+ {
+ case GL_TEXTURE_3D_OES:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ es2::Context *context = es2::getContext();
+
+ if(context)
+ {
+ es2::Framebuffer *framebuffer = context->getReadFramebuffer();
+
+ if(framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if(context->getReadFramebufferHandle() != 0 && framebuffer->getColorbuffer()->getSamples() > 1)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ es2::Renderbuffer *source = framebuffer->getColorbuffer();
+ GLenum colorbufferFormat = source->getFormat();
+ es2::Texture3D *texture = context->getTexture3D();
+
+ if(!validateSubImageParams(false, width, height, 1, xoffset, yoffset, zoffset, target, level, GL_NONE, texture))
+ {
+ return;
+ }
+
+ GLenum textureFormat = texture->getFormat(target, level);
+
+ if(!validateColorBufferFormat(textureFormat, colorbufferFormat))
+ {
+ return;
+ }
+
+ texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, framebuffer);
+ }
+}
+
+void GL_APIENTRY glCompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data)
+{
+ TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
+ "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
+ target, level, internalformat, width, height, depth, border, imageSize, data);
+
+ switch(target)
+ {
+ case GL_TEXTURE_3D_OES:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ const GLsizei maxSize3D = es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level;
+ if((width < 0) || (height < 0) || (depth < 0) || (width > maxSize3D) || (height > maxSize3D) || (depth > maxSize3D) ||(border != 0) || (imageSize < 0))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ switch(internalformat)
+ {
+ case GL_ETC1_RGB8_OES:
+ break;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ if(!S3TC_SUPPORT)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_COMPONENT16:
+ case GL_DEPTH_COMPONENT32_OES:
+ case GL_DEPTH_STENCIL_OES:
+ case GL_DEPTH24_STENCIL8_OES:
+ return error(GL_INVALID_OPERATION);
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(imageSize != es2::ComputeCompressedSize(width, height, internalformat) * depth)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ es2::Context *context = es2::getContext();
+
+ if(context)
+ {
+ es2::Texture3D *texture = context->getTexture3D();
+
+ if(!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data);
+ }
+}
+
+void GL_APIENTRY glCompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data)
+{
+ TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, "
+ "GLenum format = 0x%X, GLsizei imageSize = %d, const void *data = 0x%0.8p)",
+ target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
+
+ switch(target)
+ {
+ case GL_TEXTURE_3D_OES:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(xoffset < 0 || yoffset < 0 || zoffset < 0 || !validImageSize(level, width, height) || depth < 0 || imageSize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ switch(format)
+ {
+ case GL_ETC1_RGB8_OES:
+ break;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ if(!S3TC_SUPPORT)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(width == 0 || height == 0 || depth == 0 || data == NULL)
+ {
+ return;
+ }
+
+ es2::Context *context = es2::getContext();
+
+ if(context)
+ {
+ es2::Texture3D *texture = context->getTexture3D();
+
+ if(!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
+ }
+}
+
+void GL_APIENTRY glFramebufferTexture3DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
+{
+ TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, "
+ "GLuint texture = %d, GLint level = %d, GLint zoffset = %d)", target, attachment, textarget, texture, level, zoffset);
+
+ if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch(attachment)
+ {
+ case GL_COLOR_ATTACHMENT0:
+ case GL_DEPTH_ATTACHMENT:
+ case GL_STENCIL_ATTACHMENT:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ es2::Context *context = es2::getContext();
+
+ if(context)
+ {
+ if(texture == 0)
+ {
+ textarget = GL_NONE;
+ }
+ else
+ {
+ es2::Texture *tex = context->getTexture(texture);
+
+ if(tex == NULL)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if(tex->isCompressed(textarget, level))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch(textarget)
+ {
+ case GL_TEXTURE_3D_OES:
+ if(tex->getTarget() != GL_TEXTURE_3D_OES)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if(level != 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ es2::Framebuffer *framebuffer = NULL;
+ GLuint framebufferHandle = 0;
+ if(target == GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ framebuffer = context->getReadFramebuffer();
+ framebufferHandle = context->getReadFramebufferHandle();
+ }
+ else
+ {
+ framebuffer = context->getDrawFramebuffer();
+ framebufferHandle = context->getDrawFramebufferHandle();
+ }
+
+ if(framebufferHandle == 0 || !framebuffer)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch(attachment)
+ {
+ case GL_COLOR_ATTACHMENT0: framebuffer->setColorbuffer(textarget, texture); break;
+ case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture); break;
+ case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture); break;
+ }
+ }
+}
+
void GL_APIENTRY glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
{
if(egl::getClientVersion() == 1)
diff --git a/src/OpenGL/libGLESv2/utilities.cpp b/src/OpenGL/libGLESv2/utilities.cpp
index 8ebcb16..acfa903 100644
--- a/src/OpenGL/libGLESv2/utilities.cpp
+++ b/src/OpenGL/libGLESv2/utilities.cpp
@@ -32,6 +32,7 @@
case GL_SAMPLER_2D:
case GL_SAMPLER_CUBE:
case GL_SAMPLER_EXTERNAL_OES:
+ case GL_SAMPLER_3D_OES:
return 1;
case GL_BOOL_VEC2:
case GL_FLOAT_VEC2:
@@ -77,7 +78,8 @@
case GL_INT:
case GL_SAMPLER_2D:
case GL_SAMPLER_CUBE:
- case GL_SAMPLER_EXTERNAL_OES:
+ case GL_SAMPLER_EXTERNAL_OES:
+ case GL_SAMPLER_3D_OES:
case GL_INT_VEC2:
case GL_INT_VEC3:
case GL_INT_VEC4:
@@ -122,6 +124,7 @@
case GL_SAMPLER_2D:
case GL_SAMPLER_CUBE:
case GL_SAMPLER_EXTERNAL_OES:
+ case GL_SAMPLER_3D_OES:
return 1;
case GL_FLOAT_MAT2:
return 2;