Implement GL_OES_fbo_render_mipmap.
This enables binding any texture mipmap level as a framebuffer
attachment.
Bug swiftshader:104
Change-Id: I3d4ea637ddd38bb62ca1363fe2c69c569eea36e9
Reviewed-on: https://swiftshader-review.googlesource.com/18008
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Lingfeng Yang <lfy@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/libGLES_CM/Framebuffer.cpp b/src/OpenGL/libGLES_CM/Framebuffer.cpp
index 097c6a2..6fcb9df 100644
--- a/src/OpenGL/libGLES_CM/Framebuffer.cpp
+++ b/src/OpenGL/libGLES_CM/Framebuffer.cpp
@@ -39,7 +39,7 @@
mStencilbufferPointer = nullptr;
}
-Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
+Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle, GLint level) const
{
Context *context = getContext();
Renderbuffer *buffer = nullptr;
@@ -54,29 +54,29 @@
}
else if(IsTextureTarget(type))
{
- buffer = context->getTexture(handle)->getRenderbuffer(type);
+ buffer = context->getTexture(handle)->getRenderbuffer(type, level);
}
else UNREACHABLE(type);
return buffer;
}
-void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
+void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer, GLint level)
{
mColorbufferType = (colorbuffer != 0) ? type : GL_NONE_OES;
- mColorbufferPointer = lookupRenderbuffer(type, colorbuffer);
+ mColorbufferPointer = lookupRenderbuffer(type, colorbuffer, level);
}
-void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
+void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level)
{
mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE_OES;
- mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer);
+ mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer, level);
}
-void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
+void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level)
{
mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE_OES;
- mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer);
+ mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer, level);
}
void Framebuffer::detachTexture(GLuint texture)
diff --git a/src/OpenGL/libGLES_CM/Framebuffer.h b/src/OpenGL/libGLES_CM/Framebuffer.h
index 39f227c..9c44129 100644
--- a/src/OpenGL/libGLES_CM/Framebuffer.h
+++ b/src/OpenGL/libGLES_CM/Framebuffer.h
@@ -38,9 +38,9 @@
virtual ~Framebuffer();
- void setColorbuffer(GLenum type, GLuint colorbuffer);
- void setDepthbuffer(GLenum type, GLuint depthbuffer);
- void setStencilbuffer(GLenum type, GLuint stencilbuffer);
+ void setColorbuffer(GLenum type, GLuint colorbuffer, GLint level = 0);
+ void setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level = 0);
+ void setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level = 0);
void detachTexture(GLuint texture);
void detachRenderbuffer(GLuint renderbuffer);
@@ -80,7 +80,7 @@
gl::BindingPointer<Renderbuffer> mStencilbufferPointer;
private:
- Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle) const;
+ Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle, GLint level) const;
};
class DefaultFramebuffer : public Framebuffer
diff --git a/src/OpenGL/libGLES_CM/Renderbuffer.cpp b/src/OpenGL/libGLES_CM/Renderbuffer.cpp
index c832443..68094d8 100644
--- a/src/OpenGL/libGLES_CM/Renderbuffer.cpp
+++ b/src/OpenGL/libGLES_CM/Renderbuffer.cpp
@@ -71,7 +71,7 @@
///// RenderbufferTexture2D Implementation ////////
-RenderbufferTexture2D::RenderbufferTexture2D(Texture2D *texture)
+RenderbufferTexture2D::RenderbufferTexture2D(Texture2D *texture, GLint level) : mLevel(level)
{
mTexture2D = texture;
}
@@ -190,6 +190,11 @@
return mInstance->getHeight();
}
+GLint Renderbuffer::getLevel() const
+{
+ return mInstance->getLevel();
+}
+
GLenum Renderbuffer::getFormat() const
{
return mInstance->getFormat();
@@ -230,6 +235,11 @@
return mInstance->getSamples();
}
+void Renderbuffer::setLevel(GLint level)
+{
+ return mInstance->setLevel(level);
+}
+
void Renderbuffer::setStorage(RenderbufferStorage *newStorage)
{
ASSERT(newStorage);
diff --git a/src/OpenGL/libGLES_CM/Renderbuffer.h b/src/OpenGL/libGLES_CM/Renderbuffer.h
index 4405b93..09a7391 100644
--- a/src/OpenGL/libGLES_CM/Renderbuffer.h
+++ b/src/OpenGL/libGLES_CM/Renderbuffer.h
@@ -48,9 +48,12 @@
virtual GLsizei getWidth() const = 0;
virtual GLsizei getHeight() const = 0;
+ virtual GLint getLevel() const { return 0; }
virtual GLint getFormat() const = 0;
virtual GLsizei getSamples() const = 0;
+ virtual void setLevel(GLint) {}
+
GLuint getRedSize() const;
GLuint getGreenSize() const;
GLuint getBlueSize() const;
@@ -62,24 +65,28 @@
class RenderbufferTexture2D : public RenderbufferInterface
{
public:
- RenderbufferTexture2D(Texture2D *texture);
+ RenderbufferTexture2D(Texture2D *texture, GLint level);
- virtual ~RenderbufferTexture2D();
+ ~RenderbufferTexture2D() override;
- virtual void addProxyRef(const Renderbuffer *proxy);
- virtual void releaseProxy(const Renderbuffer *proxy);
+ void addProxyRef(const Renderbuffer *proxy) override;
+ void releaseProxy(const Renderbuffer *proxy) override;
- virtual egl::Image *getRenderTarget();
- virtual egl::Image *createSharedImage();
- virtual bool isShared() const;
+ egl::Image *getRenderTarget() override;
+ egl::Image *createSharedImage() override;
+ bool isShared() const override;
- virtual GLsizei getWidth() const;
- virtual GLsizei getHeight() const;
- virtual GLint getFormat() const;
- virtual GLsizei getSamples() const;
+ GLsizei getWidth() const override;
+ GLsizei getHeight() const override;
+ GLint getLevel() const override { return mLevel; }
+ GLint getFormat() const override;
+ GLsizei getSamples() const override;
+
+ void setLevel(GLint level) override { mLevel = level; }
private:
gl::BindingPointer<Texture2D> mTexture2D;
+ GLint mLevel;
};
// A class derived from RenderbufferStorage is created whenever glRenderbufferStorage
@@ -90,16 +97,16 @@
public:
RenderbufferStorage();
- virtual ~RenderbufferStorage() = 0;
+ ~RenderbufferStorage() override = 0;
- virtual egl::Image *getRenderTarget() = 0;
- virtual egl::Image *createSharedImage() = 0;
- virtual bool isShared() const = 0;
+ egl::Image *getRenderTarget() override = 0;
+ egl::Image *createSharedImage() override = 0;
+ bool isShared() const override = 0;
- virtual GLsizei getWidth() const;
- virtual GLsizei getHeight() const;
- virtual GLint getFormat() const;
- virtual GLsizei getSamples() const;
+ GLsizei getWidth() const override;
+ GLsizei getHeight() const override;
+ GLint getFormat() const override;
+ GLsizei getSamples() const override;
protected:
GLsizei mWidth;
@@ -131,6 +138,7 @@
GLsizei getWidth() const;
GLsizei getHeight() const;
+ GLint getLevel() const;
GLenum getFormat() const;
GLuint getRedSize() const;
GLuint getGreenSize() const;
@@ -140,6 +148,7 @@
GLuint getStencilSize() const;
GLsizei getSamples() const;
+ void setLevel(GLint level);
void setStorage(RenderbufferStorage *newStorage);
private:
@@ -152,11 +161,11 @@
explicit Colorbuffer(egl::Image *renderTarget);
Colorbuffer(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
- virtual ~Colorbuffer();
+ ~Colorbuffer() override;
- virtual egl::Image *getRenderTarget();
- virtual egl::Image *createSharedImage();
- virtual bool isShared() const;
+ egl::Image *getRenderTarget() override;
+ egl::Image *createSharedImage() override;
+ bool isShared() const override;
private:
egl::Image *mRenderTarget;
@@ -170,9 +179,9 @@
~DepthStencilbuffer();
- virtual egl::Image *getRenderTarget();
- virtual egl::Image *createSharedImage();
- virtual bool isShared() const;
+ egl::Image *getRenderTarget() override;
+ egl::Image *createSharedImage() override;
+ bool isShared() const override;
protected:
egl::Image *mDepthStencil;
@@ -184,7 +193,7 @@
explicit Depthbuffer(egl::Image *depthStencil);
Depthbuffer(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
- virtual ~Depthbuffer();
+ ~Depthbuffer() override;
};
class Stencilbuffer : public DepthStencilbuffer
@@ -193,7 +202,7 @@
explicit Stencilbuffer(egl::Image *depthStencil);
Stencilbuffer(GLsizei width, GLsizei height, GLsizei samples);
- virtual ~Stencilbuffer();
+ ~Stencilbuffer() override;
};
}
diff --git a/src/OpenGL/libGLES_CM/Texture.cpp b/src/OpenGL/libGLES_CM/Texture.cpp
index 1043918..4d8b75a 100644
--- a/src/OpenGL/libGLES_CM/Texture.cpp
+++ b/src/OpenGL/libGLES_CM/Texture.cpp
@@ -678,7 +678,7 @@
return image[level];
}
-Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
+Renderbuffer *Texture2D::getRenderbuffer(GLenum target, GLint level)
{
if(target != GL_TEXTURE_2D)
{
@@ -687,7 +687,11 @@
if(!mColorbufferProxy)
{
- mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this));
+ mColorbufferProxy = new Renderbuffer(name, new RenderbufferTexture2D(this, level));
+ }
+ else
+ {
+ mColorbufferProxy->setLevel(level);
}
return mColorbufferProxy;
diff --git a/src/OpenGL/libGLES_CM/Texture.h b/src/OpenGL/libGLES_CM/Texture.h
index 0439039..e287c15 100644
--- a/src/OpenGL/libGLES_CM/Texture.h
+++ b/src/OpenGL/libGLES_CM/Texture.h
@@ -83,7 +83,7 @@
virtual bool isCompressed(GLenum target, GLint level) const = 0;
virtual bool isDepth(GLenum target, GLint level) const = 0;
- virtual Renderbuffer *getRenderbuffer(GLenum target) = 0;
+ virtual Renderbuffer *getRenderbuffer(GLenum target, GLint level) = 0;
virtual egl::Image *getRenderTarget(GLenum target, unsigned int level) = 0;
egl::Image *createSharedImage(GLenum target, unsigned int level);
virtual bool isShared(GLenum target, unsigned int level) const = 0;
@@ -153,7 +153,7 @@
void generateMipmaps() override;
void autoGenerateMipmaps() override;
- Renderbuffer *getRenderbuffer(GLenum target) override;
+ Renderbuffer *getRenderbuffer(GLenum target, GLint level) override;
egl::Image *getRenderTarget(GLenum target, unsigned int level) override;
bool isShared(GLenum target, unsigned int level) const override;
diff --git a/src/OpenGL/libGLES_CM/libGLES_CM.cpp b/src/OpenGL/libGLES_CM/libGLES_CM.cpp
index b1f5e80..7e5247c 100644
--- a/src/OpenGL/libGLES_CM/libGLES_CM.cpp
+++ b/src/OpenGL/libGLES_CM/libGLES_CM.cpp
@@ -1507,7 +1507,7 @@
return error(GL_INVALID_ENUM);
}
- if(level != 0)
+ if((level < 0) || (level >= es1::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
{
return error(GL_INVALID_VALUE);
}
@@ -1528,9 +1528,9 @@
switch(attachment)
{
- case GL_COLOR_ATTACHMENT0_OES: framebuffer->setColorbuffer(textarget, texture); break;
- case GL_DEPTH_ATTACHMENT_OES: framebuffer->setDepthbuffer(textarget, texture); break;
- case GL_STENCIL_ATTACHMENT_OES: framebuffer->setStencilbuffer(textarget, texture); break;
+ case GL_COLOR_ATTACHMENT0_OES: framebuffer->setColorbuffer(textarget, texture, level); break;
+ case GL_DEPTH_ATTACHMENT_OES: framebuffer->setDepthbuffer(textarget, texture, level); break;
+ case GL_STENCIL_ATTACHMENT_OES: framebuffer->setStencilbuffer(textarget, texture, level); break;
}
}
}
@@ -2082,19 +2082,23 @@
GLenum attachmentType;
GLuint attachmentHandle;
+ Renderbuffer *renderbuffer = nullptr;
switch(attachment)
{
case GL_COLOR_ATTACHMENT0_OES:
attachmentType = framebuffer->getColorbufferType();
attachmentHandle = framebuffer->getColorbufferName();
+ renderbuffer = framebuffer->getColorbuffer();
break;
case GL_DEPTH_ATTACHMENT_OES:
attachmentType = framebuffer->getDepthbufferType();
attachmentHandle = framebuffer->getDepthbufferName();
+ renderbuffer = framebuffer->getDepthbuffer();
break;
case GL_STENCIL_ATTACHMENT_OES:
attachmentType = framebuffer->getStencilbufferType();
attachmentHandle = framebuffer->getStencilbufferName();
+ renderbuffer = framebuffer->getStencilbuffer();
break;
default:
return error(GL_INVALID_ENUM);
@@ -2129,7 +2133,7 @@
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES:
if(attachmentObjectType == GL_TEXTURE)
{
- *params = 0; // FramebufferTexture2D will not allow level to be set to anything else in GL ES 2.0
+ *params = renderbuffer->getLevel();
}
else
{
@@ -2268,6 +2272,7 @@
"GL_OES_EGL_image_external "
"GL_OES_EGL_sync "
"GL_OES_element_index_uint "
+ "GL_OES_fbo_render_mipmap "
"GL_OES_framebuffer_object "
"GL_OES_packed_depth_stencil "
"GL_OES_read_format "
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index 5a5a6b3..e257174 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -4405,6 +4405,7 @@
"GL_OES_EGL_image_external",
"GL_OES_EGL_sync",
"GL_OES_element_index_uint",
+ "GL_OES_fbo_render_mipmap",
"GL_OES_framebuffer_object",
"GL_OES_packed_depth_stencil",
"GL_OES_rgb8_rgba8",
diff --git a/src/OpenGL/libGLESv2/Renderbuffer.cpp b/src/OpenGL/libGLESv2/Renderbuffer.cpp
index a970dcf..fdbb617 100644
--- a/src/OpenGL/libGLESv2/Renderbuffer.cpp
+++ b/src/OpenGL/libGLESv2/Renderbuffer.cpp
@@ -78,7 +78,7 @@
RenderbufferTexture2D::~RenderbufferTexture2D()
{
- mTexture2D = NULL;
+ mTexture2D = nullptr;
}
// Textures need to maintain their own reference count for references via
@@ -441,7 +441,7 @@
void Renderbuffer::setStorage(RenderbufferStorage *newStorage)
{
- ASSERT(newStorage != NULL);
+ ASSERT(newStorage);
delete mInstance;
mInstance = newStorage;
diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index 1577569..4be1261 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -6006,11 +6006,6 @@
return error(GL_INVALID_OPERATION);
}
- if(tex->isCompressed(textarget, level))
- {
- return error(GL_INVALID_OPERATION);
- }
-
switch(textarget)
{
case GL_TEXTURE_3D:
@@ -6023,10 +6018,15 @@
return error(GL_INVALID_ENUM);
}
- if(level != 0)
+ if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
{
return error(GL_INVALID_VALUE);
}
+
+ if(tex->isCompressed(textarget, level))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
}
es2::Framebuffer *framebuffer = nullptr;
@@ -6049,14 +6049,14 @@
switch(attachment)
{
- case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture); break;
- case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture); break;
+ case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture, level); break;
+ case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture, level); break;
default:
if((attachment - GL_COLOR_ATTACHMENT0) >= MAX_COLOR_ATTACHMENTS)
{
return error(GL_INVALID_ENUM);
}
- framebuffer->setColorbuffer(textarget, texture, attachment - GL_COLOR_ATTACHMENT0);
+ framebuffer->setColorbuffer(textarget, texture, attachment - GL_COLOR_ATTACHMENT0, level);
break;
}
}