Commit a8802477 by Jiawei Shao Committed by Commit Bot

ES31: Implement FramebufferTextureEXT on OpenGL back-ends

This patch intends to implement FramebufferTextureEXT on OpenGL back-ends. 1. Support layered framebuffer attachments. 2. Add new framebuffer completeness rules on layered framebuffer attachments. 3. Support FRAMEBUFFER_ATTACHMENT_LAYERED_EXT as a valid <pname> parameter of GetFramebufferAttachmentParameteriv. Note that for an entire level of a cube map: 1. It has no TextureTarget because TEXTURE_CUBE is not a valid target for TexImage*D. 2. It corresponds to 6 ImageDescs (that represents its faces) in class Texture, so when the cube map is cube complete, we return the ImageDesc of its first face, meanwhile we do not allow querying ImageDesc if it is not cube complete. BUG=angleproject:1941 TEST=angle_end2end_tests dEQP-GLES31.functional.geometry_shading.query.framebuffer_attachment_layers dEQP-GLES31.functional.geometry_shading.query.framebuffer_incomplete_layer_targets dEQP-GLES31.functional.geometry_shading.layered.* dEQP-GLES31.functional.geometry_shading.instanced.invocation_per_layer_* dEQP-GLES31.functional.geometry_shading.instanced.multiple_layers_per_invocation_* Change-Id: I44393b513ec8f1a682fd1c47d3eaa6f3b3fae877 Reviewed-on: https://chromium-review.googlesource.com/1075811 Commit-Queue: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent d73a6111
...@@ -3690,10 +3690,25 @@ void Context::framebufferTextureMultiviewSideBySide(GLenum target, ...@@ -3690,10 +3690,25 @@ void Context::framebufferTextureMultiviewSideBySide(GLenum target,
mGLState.setObjectDirty(target); mGLState.setObjectDirty(target);
} }
// TODO(jiawei.shao@intel.com): implement framebufferTextureEXT
void Context::framebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level) void Context::framebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level)
{ {
UNIMPLEMENTED(); Framebuffer *framebuffer = mGLState.getTargetFramebuffer(target);
ASSERT(framebuffer);
if (texture != 0)
{
Texture *textureObj = getTexture(texture);
ImageIndex index = ImageIndex::MakeFromType(
textureObj->getType(), level, ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
framebuffer->setAttachment(this, GL_TEXTURE, attachment, index, textureObj);
}
else
{
framebuffer->resetAttachment(this, attachment);
}
mGLState.setObjectDirty(target);
} }
void Context::drawBuffers(GLsizei n, const GLenum *bufs) void Context::drawBuffers(GLsizei n, const GLenum *bufs)
......
...@@ -85,10 +85,27 @@ bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttach ...@@ -85,10 +85,27 @@ bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttach
if (attachment.type() == GL_TEXTURE) if (attachment.type() == GL_TEXTURE)
{ {
// [EXT_geometry_shader] Section 9.4.1, "Framebuffer Completeness"
// If <image> is a three-dimensional texture or a two-dimensional array texture and the
// attachment is not layered, the selected layer is less than the depth or layer count,
// respectively, of the texture.
if (!attachment.isLayered())
{
if (attachment.layer() >= size.depth) if (attachment.layer() >= size.depth)
{ {
return false; return false;
} }
}
// If <image> is a three-dimensional texture or a two-dimensional array texture and the
// attachment is layered, the depth or layer count, respectively, of the texture is less
// than or equal to the value of MAX_FRAMEBUFFER_LAYERS_EXT.
else
{
if (static_cast<GLuint>(size.depth) >= context->getCaps().maxFramebufferLayers)
{
return false;
}
}
// ES3 specifies that cube map texture attachments must be cube complete. // ES3 specifies that cube map texture attachments must be cube complete.
// This language is missing from the ES2 spec, but we enforce it here because some // This language is missing from the ES2 spec, but we enforce it here because some
...@@ -149,11 +166,7 @@ bool CheckAttachmentSampleCompleteness(const Context *context, ...@@ -149,11 +166,7 @@ bool CheckAttachmentSampleCompleteness(const Context *context,
ASSERT(texture); ASSERT(texture);
const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex(); const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
bool fixedSampleloc = texture->getAttachmentFixedSampleLocations(attachmentImageIndex);
// ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
// the same for all attached textures.
bool fixedSampleloc = texture->getFixedSampleLocations(
attachmentImageIndex.getTarget(), attachmentImageIndex.getLevelIndex());
if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value()) if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
{ {
return false; return false;
...@@ -1030,6 +1043,9 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) ...@@ -1030,6 +1043,9 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment(); const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
Optional<bool> isLayered;
Optional<TextureType> colorAttachmentsTextureType;
for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments) for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
{ {
if (colorAttachment.isAttached()) if (colorAttachment.isAttached())
...@@ -1074,8 +1090,38 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) ...@@ -1074,8 +1090,38 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
} }
hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER); hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
if (!hasAttachments)
{
isLayered = colorAttachment.isLayered();
if (isLayered.value())
{
colorAttachmentsTextureType = colorAttachment.getTextureImageIndex().getType();
}
hasAttachments = true; hasAttachments = true;
} }
else
{
// [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
// If any framebuffer attachment is layered, all populated attachments
// must be layered. Additionally, all populated color attachments must
// be from textures of the same target. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
ASSERT(isLayered.valid());
if (isLayered.value() != colorAttachment.isLayered())
{
return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
}
else if (isLayered.value())
{
ASSERT(colorAttachmentsTextureType.valid());
if (colorAttachmentsTextureType.value() !=
colorAttachment.getTextureImageIndex().getType())
{
return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
}
}
}
}
} }
const FramebufferAttachment &depthAttachment = mState.mDepthAttachment; const FramebufferAttachment &depthAttachment = mState.mDepthAttachment;
...@@ -1104,8 +1150,24 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) ...@@ -1104,8 +1150,24 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
} }
hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER); hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
if (!hasAttachments)
{
isLayered = depthAttachment.isLayered();
hasAttachments = true; hasAttachments = true;
} }
else
{
// [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
// If any framebuffer attachment is layered, all populated attachments
// must be layered. {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
ASSERT(isLayered.valid());
if (isLayered.value() != depthAttachment.isLayered())
{
return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
}
}
}
const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment; const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
if (stencilAttachment.isAttached()) if (stencilAttachment.isAttached())
...@@ -1133,8 +1195,24 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context) ...@@ -1133,8 +1195,24 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
} }
hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER); hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
if (!hasAttachments)
{
hasAttachments = true; hasAttachments = true;
} }
else
{
// [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
// If any framebuffer attachment is layered, all populated attachments
// must be layered.
// {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
ASSERT(isLayered.valid());
if (isLayered.value() != stencilAttachment.isLayered())
{
return GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT;
}
}
}
// Starting from ES 3.0 stencil and depth, if present, should be the same image // Starting from ES 3.0 stencil and depth, if present, should be the same image
if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() && if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
......
...@@ -251,6 +251,11 @@ GLint FramebufferAttachment::layer() const ...@@ -251,6 +251,11 @@ GLint FramebufferAttachment::layer() const
return (index.has3DLayer() ? index.getLayerIndex() : 0); return (index.has3DLayer() ? index.getLayerIndex() : 0);
} }
bool FramebufferAttachment::isLayered() const
{
return mTarget.textureIndex().isLayered();
}
GLsizei FramebufferAttachment::getNumViews() const GLsizei FramebufferAttachment::getNumViews() const
{ {
return mNumViews; return mNumViews;
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
#include "angle_gl.h" #include "angle_gl.h"
#include "common/angleutils.h" #include "common/angleutils.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
#include "libANGLE/ImageIndex.h" #include "libANGLE/ImageIndex.h"
#include "libANGLE/formatutils.h"
namespace egl namespace egl
{ {
...@@ -43,7 +43,6 @@ class Subject; ...@@ -43,7 +43,6 @@ class Subject;
namespace gl namespace gl
{ {
class FramebufferAttachmentObject; class FramebufferAttachmentObject;
struct Format;
class Renderbuffer; class Renderbuffer;
class Texture; class Texture;
...@@ -96,8 +95,14 @@ class FramebufferAttachment final ...@@ -96,8 +95,14 @@ class FramebufferAttachment final
GLenum getComponentType() const; GLenum getComponentType() const;
GLenum getColorEncoding() const; GLenum getColorEncoding() const;
bool isTextureWithId(GLuint textureId) const { return mType == GL_TEXTURE && id() == textureId; } bool isTextureWithId(GLuint textureId) const
bool isRenderbufferWithId(GLuint renderbufferId) const { return mType == GL_RENDERBUFFER && id() == renderbufferId; } {
return mType == GL_TEXTURE && id() == textureId;
}
bool isRenderbufferWithId(GLuint renderbufferId) const
{
return mType == GL_RENDERBUFFER && id() == renderbufferId;
}
GLenum getBinding() const { return mTarget.binding(); } GLenum getBinding() const { return mTarget.binding(); }
GLuint id() const; GLuint id() const;
...@@ -107,6 +112,7 @@ class FramebufferAttachment final ...@@ -107,6 +112,7 @@ class FramebufferAttachment final
TextureTarget cubeMapFace() const; TextureTarget cubeMapFace() const;
GLint mipLevel() const; GLint mipLevel() const;
GLint layer() const; GLint layer() const;
bool isLayered() const;
GLsizei getNumViews() const; GLsizei getNumViews() const;
GLenum getMultiviewLayout() const; GLenum getMultiviewLayout() const;
GLint getBaseViewIndex() const; GLint getBaseViewIndex() const;
...@@ -116,7 +122,7 @@ class FramebufferAttachment final ...@@ -116,7 +122,7 @@ class FramebufferAttachment final
// correspond to a 3D texture depth or the layer count of a 2D array texture. For Surfaces and // correspond to a 3D texture depth or the layer count of a 2D array texture. For Surfaces and
// Renderbuffers, it will always be 1. // Renderbuffers, it will always be 1.
Extents getSize() const; Extents getSize() const;
const Format &getFormat() const; Format getFormat() const;
GLsizei getSamples() const; GLsizei getSamples() const;
GLenum type() const { return mType; } GLenum type() const { return mType; }
bool isAttached() const { return mType != GL_NONE; } bool isAttached() const { return mType != GL_NONE; }
...@@ -191,8 +197,7 @@ class FramebufferAttachmentObject ...@@ -191,8 +197,7 @@ class FramebufferAttachmentObject
virtual ~FramebufferAttachmentObject(); virtual ~FramebufferAttachmentObject();
virtual Extents getAttachmentSize(const ImageIndex &imageIndex) const = 0; virtual Extents getAttachmentSize(const ImageIndex &imageIndex) const = 0;
virtual const Format &getAttachmentFormat(GLenum binding, virtual Format getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const = 0;
const ImageIndex &imageIndex) const = 0;
virtual GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const = 0; virtual GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const = 0;
virtual void onAttach(const Context *context) = 0; virtual void onAttach(const Context *context) = 0;
...@@ -223,7 +228,7 @@ inline Extents FramebufferAttachment::getSize() const ...@@ -223,7 +228,7 @@ inline Extents FramebufferAttachment::getSize() const
return mResource->getAttachmentSize(mTarget.textureIndex()); return mResource->getAttachmentSize(mTarget.textureIndex());
} }
inline const Format &FramebufferAttachment::getFormat() const inline Format FramebufferAttachment::getFormat() const
{ {
ASSERT(mResource); ASSERT(mResource);
return mResource->getAttachmentFormat(mTarget.binding(), mTarget.textureIndex()); return mResource->getAttachmentFormat(mTarget.binding(), mTarget.textureIndex());
......
...@@ -187,7 +187,7 @@ gl::Error Image::orphanSibling(const gl::Context *context, ImageSibling *sibling ...@@ -187,7 +187,7 @@ gl::Error Image::orphanSibling(const gl::Context *context, ImageSibling *sibling
return gl::NoError(); return gl::NoError();
} }
const gl::Format &Image::getFormat() const gl::Format Image::getFormat() const
{ {
return mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex); return mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
} }
......
...@@ -82,7 +82,7 @@ class Image final : public gl::RefCountObject ...@@ -82,7 +82,7 @@ class Image final : public gl::RefCountObject
gl::Error onDestroy(const gl::Context *context) override; gl::Error onDestroy(const gl::Context *context) override;
~Image() override; ~Image() override;
const gl::Format &getFormat() const; gl::Format getFormat() const;
size_t getWidth() const; size_t getWidth() const;
size_t getHeight() const; size_t getHeight() const;
size_t getSamples() const; size_t getSamples() const;
......
...@@ -56,6 +56,9 @@ TextureTarget TextureTypeToTarget(TextureType type, GLint layerIndex) ...@@ -56,6 +56,9 @@ TextureTarget TextureTypeToTarget(TextureType type, GLint layerIndex)
{ {
if (type == TextureType::CubeMap) if (type == TextureType::CubeMap)
{ {
// As GL_TEXTURE_CUBE_MAP cannot be a texture target in texImage*D APIs, so we don't allow
// an entire cube map to have a texture target.
ASSERT(layerIndex != ImageIndex::kEntireLevel);
return CubeFaceIndexToTextureTarget(layerIndex); return CubeFaceIndexToTextureTarget(layerIndex);
} }
else else
...@@ -79,6 +82,19 @@ bool ImageIndex::hasLayer() const ...@@ -79,6 +82,19 @@ bool ImageIndex::hasLayer() const
return mLayerIndex != kEntireLevel; return mLayerIndex != kEntireLevel;
} }
bool ImageIndex::isLayered() const
{
switch (mType)
{
case TextureType::_2DArray:
case TextureType::CubeMap:
case TextureType::_3D:
return mLayerIndex == kEntireLevel;
default:
return false;
}
}
bool ImageIndex::has3DLayer() const bool ImageIndex::has3DLayer() const
{ {
// It's quicker to check != CubeMap than calling usesTex3D, which checks multiple types. This // It's quicker to check != CubeMap than calling usesTex3D, which checks multiple types. This
...@@ -109,6 +125,11 @@ bool ImageIndex::valid() const ...@@ -109,6 +125,11 @@ bool ImageIndex::valid() const
return mType != TextureType::InvalidEnum; return mType != TextureType::InvalidEnum;
} }
bool ImageIndex::isEntireLevelCubeMap() const
{
return mType == TextureType::CubeMap && mLayerIndex == ImageIndex::kEntireLevel;
}
ImageIndex ImageIndex::Make2D(GLint levelIndex) ImageIndex ImageIndex::Make2D(GLint levelIndex)
{ {
return ImageIndex(TextureType::_2D, levelIndex, kEntireLevel, 1); return ImageIndex(TextureType::_2D, levelIndex, kEntireLevel, 1);
...@@ -119,7 +140,7 @@ ImageIndex ImageIndex::MakeRectangle(GLint levelIndex) ...@@ -119,7 +140,7 @@ ImageIndex ImageIndex::MakeRectangle(GLint levelIndex)
return ImageIndex(TextureType::Rectangle, levelIndex, kEntireLevel, 1); return ImageIndex(TextureType::Rectangle, levelIndex, kEntireLevel, 1);
} }
ImageIndex ImageIndex::MakeCube(TextureTarget target, GLint levelIndex) ImageIndex ImageIndex::MakeCubeMapFace(TextureTarget target, GLint levelIndex)
{ {
ASSERT(IsCubeMapFaceTarget(target)); ASSERT(IsCubeMapFaceTarget(target));
return ImageIndex(TextureType::CubeMap, levelIndex, TextureTargetToLayer(target), 1); return ImageIndex(TextureType::CubeMap, levelIndex, TextureTargetToLayer(target), 1);
......
...@@ -36,12 +36,17 @@ class ImageIndex ...@@ -36,12 +36,17 @@ class ImageIndex
bool usesTex3D() const; bool usesTex3D() const;
GLint cubeMapFaceIndex() const; GLint cubeMapFaceIndex() const;
bool valid() const; bool valid() const;
// Note that you cannot use this function when the ImageIndex represents an entire level of cube
// map.
TextureTarget getTarget() const; TextureTarget getTarget() const;
bool isLayered() const;
bool isEntireLevelCubeMap() const;
static ImageIndex Make2D(GLint levelIndex); static ImageIndex Make2D(GLint levelIndex);
static ImageIndex MakeRectangle(GLint levelIndex); static ImageIndex MakeRectangle(GLint levelIndex);
static ImageIndex MakeCube(TextureTarget target, GLint levelIndex); static ImageIndex MakeCubeMapFace(TextureTarget target, GLint levelIndex);
static ImageIndex Make2DArray(GLint levelIndex, GLint layerIndex); static ImageIndex Make2DArray(GLint levelIndex, GLint layerIndex = kEntireLevel);
static ImageIndex Make2DArrayRange(GLint levelIndex, GLint layerIndex, GLint layerCount); static ImageIndex Make2DArrayRange(GLint levelIndex, GLint layerIndex, GLint layerCount);
static ImageIndex Make3D(GLint levelIndex, GLint layerIndex = kEntireLevel); static ImageIndex Make3D(GLint levelIndex, GLint layerIndex = kEntireLevel);
static ImageIndex MakeFromTarget(TextureTarget target, GLint levelIndex); static ImageIndex MakeFromTarget(TextureTarget target, GLint levelIndex);
......
...@@ -221,7 +221,7 @@ Extents Renderbuffer::getAttachmentSize(const gl::ImageIndex & /*imageIndex*/) c ...@@ -221,7 +221,7 @@ Extents Renderbuffer::getAttachmentSize(const gl::ImageIndex & /*imageIndex*/) c
return Extents(mState.mWidth, mState.mHeight, 1); return Extents(mState.mWidth, mState.mHeight, 1);
} }
const Format &Renderbuffer::getAttachmentFormat(GLenum /*binding*/, Format Renderbuffer::getAttachmentFormat(GLenum /*binding*/,
const ImageIndex & /*imageIndex*/) const const ImageIndex & /*imageIndex*/) const
{ {
return getFormat(); return getFormat();
......
...@@ -96,7 +96,7 @@ class Renderbuffer final : public egl::ImageSibling, ...@@ -96,7 +96,7 @@ class Renderbuffer final : public egl::ImageSibling,
// FramebufferAttachmentObject Impl // FramebufferAttachmentObject Impl
Extents getAttachmentSize(const ImageIndex &imageIndex) const override; Extents getAttachmentSize(const ImageIndex &imageIndex) const override;
const Format &getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const override; Format getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const override;
GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const override; GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const override;
void onAttach(const Context *context) override; void onAttach(const Context *context) override;
......
...@@ -424,7 +424,7 @@ gl::Extents Surface::getAttachmentSize(const gl::ImageIndex & /*target*/) const ...@@ -424,7 +424,7 @@ gl::Extents Surface::getAttachmentSize(const gl::ImageIndex & /*target*/) const
return gl::Extents(getWidth(), getHeight(), 1); return gl::Extents(getWidth(), getHeight(), 1);
} }
const gl::Format &Surface::getAttachmentFormat(GLenum binding, const gl::ImageIndex &target) const gl::Format Surface::getAttachmentFormat(GLenum binding, const gl::ImageIndex &target) const
{ {
return (binding == GL_BACK ? mColorFormat : mDSFormat); return (binding == GL_BACK ? mColorFormat : mDSFormat);
} }
......
...@@ -107,8 +107,7 @@ class Surface : public gl::FramebufferAttachmentObject ...@@ -107,8 +107,7 @@ class Surface : public gl::FramebufferAttachmentObject
// FramebufferAttachmentObject implementation // FramebufferAttachmentObject implementation
gl::Extents getAttachmentSize(const gl::ImageIndex &imageIndex) const override; gl::Extents getAttachmentSize(const gl::ImageIndex &imageIndex) const override;
const gl::Format &getAttachmentFormat(GLenum binding, gl::Format getAttachmentFormat(GLenum binding, const gl::ImageIndex &imageIndex) const override;
const gl::ImageIndex &imageIndex) const override;
GLsizei getAttachmentSamples(const gl::ImageIndex &imageIndex) const override; GLsizei getAttachmentSamples(const gl::ImageIndex &imageIndex) const override;
void onAttach(const gl::Context *context) override {} void onAttach(const gl::Context *context) override {}
......
...@@ -224,12 +224,12 @@ const ImageDesc &TextureState::getBaseLevelDesc() const ...@@ -224,12 +224,12 @@ const ImageDesc &TextureState::getBaseLevelDesc() const
return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel()); return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
} }
void TextureState::setCrop(const gl::Rectangle& rect) void TextureState::setCrop(const gl::Rectangle &rect)
{ {
mCropRect = rect; mCropRect = rect;
} }
const gl::Rectangle& TextureState::getCrop() const const gl::Rectangle &TextureState::getCrop() const
{ {
return mCropRect; return mCropRect;
} }
...@@ -510,8 +510,18 @@ void TextureState::setImageDesc(TextureTarget target, size_t level, const ImageD ...@@ -510,8 +510,18 @@ void TextureState::setImageDesc(TextureTarget target, size_t level, const ImageD
} }
} }
// Note that an ImageIndex that represents an entire level of a cube map corresponds to 6
// ImageDescs, so if the cube map is cube complete, we return the ImageDesc of the first cube
// face, and we don't allow using this function when the cube map is not cube complete.
const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
{ {
if (imageIndex.isEntireLevelCubeMap())
{
ASSERT(isCubeComplete());
const GLint levelIndex = imageIndex.getLevelIndex();
return getImageDesc(kCubeMapTextureTargetMin, levelIndex);
}
return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex()); return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex());
} }
...@@ -1386,25 +1396,72 @@ Error Texture::setEGLImageTarget(const Context *context, TextureType type, egl:: ...@@ -1386,25 +1396,72 @@ Error Texture::setEGLImageTarget(const Context *context, TextureType type, egl::
Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
{ {
// As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
// we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
// one that belongs to the first face of the cube map.
if (imageIndex.isEntireLevelCubeMap())
{
// A cube map texture is cube complete if the following conditions all hold true:
// - The levelbase arrays of each of the six texture images making up the cube map have
// identical, positive, and square dimensions.
if (!mState.isCubeComplete())
{
return Extents();
}
}
return mState.getImageDesc(imageIndex).size; return mState.getImageDesc(imageIndex).size;
} }
const Format &Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const Format Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
{ {
// As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
// we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
// one that belongs to the first face of the cube map.
if (imageIndex.isEntireLevelCubeMap())
{
// A cube map texture is cube complete if the following conditions all hold true:
// - The levelbase arrays were each specified with the same effective internal format.
if (!mState.isCubeComplete())
{
return Format::Invalid();
}
}
return mState.getImageDesc(imageIndex).format; return mState.getImageDesc(imageIndex).format;
} }
GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
{ {
return getSamples(imageIndex.getTarget(), 0); // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
// cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
if (imageIndex.isEntireLevelCubeMap())
{
return 0;
}
return getSamples(imageIndex.getTarget(), imageIndex.getLevelIndex());
} }
void Texture::setCrop(const gl::Rectangle& rect) bool Texture::getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const
{
// We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
// cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
if (imageIndex.isEntireLevelCubeMap())
{
return true;
}
// ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
// the same for all attached textures.
return getFixedSampleLocations(imageIndex.getTarget(), imageIndex.getLevelIndex());
}
void Texture::setCrop(const gl::Rectangle &rect)
{ {
mState.setCrop(rect); mState.setCrop(rect);
} }
const gl::Rectangle& Texture::getCrop() const const gl::Rectangle &Texture::getCrop() const
{ {
return mState.getCrop(); return mState.getCrop();
} }
...@@ -1510,6 +1567,21 @@ Error Texture::ensureInitialized(const Context *context) ...@@ -1510,6 +1567,21 @@ Error Texture::ensureInitialized(const Context *context)
InitState Texture::initState(const ImageIndex &imageIndex) const InitState Texture::initState(const ImageIndex &imageIndex) const
{ {
// As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
// we need to check all the related ImageDescs.
if (imageIndex.isEntireLevelCubeMap())
{
const GLint levelIndex = imageIndex.getLevelIndex();
for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
{
if (mState.getImageDesc(cubeFaceTarget, levelIndex).initState == InitState::MayNeedInit)
{
return InitState::MayNeedInit;
}
}
return InitState::Initialized;
}
return mState.getImageDesc(imageIndex).initState; return mState.getImageDesc(imageIndex).initState;
} }
...@@ -1520,9 +1592,22 @@ InitState Texture::initState() const ...@@ -1520,9 +1592,22 @@ InitState Texture::initState() const
void Texture::setInitState(const ImageIndex &imageIndex, InitState initState) void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
{ {
// As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
// we need to update all the related ImageDescs.
if (imageIndex.isEntireLevelCubeMap())
{
const GLint levelIndex = imageIndex.getLevelIndex();
for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
{
setInitState(ImageIndex::MakeCubeMapFace(cubeFaceTarget, levelIndex), initState);
}
}
else
{
ImageDesc newDesc = mState.getImageDesc(imageIndex); ImageDesc newDesc = mState.getImageDesc(imageIndex);
newDesc.initState = initState; newDesc.initState = initState;
mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc); mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
}
} }
Error Texture::ensureSubImageInitialized(const Context *context, Error Texture::ensureSubImageInitialized(const Context *context,
......
...@@ -375,9 +375,11 @@ class Texture final : public egl::ImageSibling, public LabeledObject ...@@ -375,9 +375,11 @@ class Texture final : public egl::ImageSibling, public LabeledObject
// FramebufferAttachmentObject implementation // FramebufferAttachmentObject implementation
Extents getAttachmentSize(const ImageIndex &imageIndex) const override; Extents getAttachmentSize(const ImageIndex &imageIndex) const override;
const Format &getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const override; Format getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const override;
GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const override; GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const override;
bool getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const;
// GLES1 emulation // GLES1 emulation
void setCrop(const gl::Rectangle& rect); void setCrop(const gl::Rectangle& rect);
const gl::Rectangle& getCrop() const; const gl::Rectangle& getCrop() const;
......
...@@ -952,6 +952,10 @@ void QueryFramebufferAttachmentParameteriv(const Context *context, ...@@ -952,6 +952,10 @@ void QueryFramebufferAttachmentParameteriv(const Context *context,
} }
break; break;
case GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT:
*params = attachmentObject->isLayered();
break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
......
...@@ -2191,7 +2191,7 @@ gl::Error TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context, ...@@ -2191,7 +2191,7 @@ gl::Error TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context,
if (image->isDirty()) if (image->isDirty())
{ {
gl::TextureTarget faceTarget = gl::CubeFaceIndexToTextureTarget(faceIndex); gl::TextureTarget faceTarget = gl::CubeFaceIndexToTextureTarget(faceIndex);
gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level); gl::ImageIndex index = gl::ImageIndex::MakeCubeMapFace(faceTarget, level);
gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1); gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
ANGLE_TRY(commitRegion(context, index, region)); ANGLE_TRY(commitRegion(context, index, region));
} }
...@@ -2239,7 +2239,7 @@ gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const ...@@ -2239,7 +2239,7 @@ gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
{ {
// The "layer" of the image index corresponds to the cube face // The "layer" of the image index corresponds to the cube face
return gl::ImageIndex::MakeCube(gl::CubeFaceIndexToTextureTarget(layer), mip); return gl::ImageIndex::MakeCubeMapFace(gl::CubeFaceIndexToTextureTarget(layer), mip);
} }
bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
......
...@@ -2289,7 +2289,7 @@ gl::Error Renderer11::copyImageCube(const gl::Context *context, ...@@ -2289,7 +2289,7 @@ gl::Error Renderer11::copyImageCube(const gl::Context *context,
TextureStorage11_Cube *storage11 = GetAs<TextureStorage11_Cube>(storage); TextureStorage11_Cube *storage11 = GetAs<TextureStorage11_Cube>(storage);
ASSERT(storage11); ASSERT(storage11);
gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); gl::ImageIndex index = gl::ImageIndex::MakeCubeMapFace(target, level);
RenderTargetD3D *destRenderTarget = nullptr; RenderTargetD3D *destRenderTarget = nullptr;
ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget)); ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget));
ASSERT(destRenderTarget); ASSERT(destRenderTarget);
......
...@@ -57,6 +57,14 @@ void BindFramebufferAttachment(const FunctionsGL *functions, ...@@ -57,6 +57,14 @@ void BindFramebufferAttachment(const FunctionsGL *functions,
ToGLenum(texture->getType()), ToGLenum(texture->getType()),
textureGL->getTextureID(), attachment->mipLevel()); textureGL->getTextureID(), attachment->mipLevel());
} }
else if (attachment->isLayered())
{
TextureType textureType = texture->getType();
ASSERT(textureType == TextureType::_2DArray || textureType == TextureType::_3D ||
textureType == TextureType::CubeMap);
functions->framebufferTexture(GL_FRAMEBUFFER, attachmentPoint,
textureGL->getTextureID(), attachment->mipLevel());
}
else if (texture->getType() == TextureType::CubeMap) else if (texture->getType() == TextureType::CubeMap)
{ {
functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint, functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint,
......
...@@ -4127,6 +4127,14 @@ bool ValidateGetFramebufferAttachmentParameterivBase(Context *context, ...@@ -4127,6 +4127,14 @@ bool ValidateGetFramebufferAttachmentParameterivBase(Context *context,
} }
break; break;
case GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT:
if (!context->getExtensions().geometryShader)
{
ANGLE_VALIDATION_ERR(context, InvalidEnum(), GeometryShaderExtensionNotEnabled);
return false;
}
break;
default: default:
context->handleError(InvalidEnum()); context->handleError(InvalidEnum());
return false; return false;
......
...@@ -48,13 +48,6 @@ ...@@ -48,13 +48,6 @@
// test expectations parser doesn't support having FAIL for GL and SKIP for D3D with the same test filter. // test expectations parser doesn't support having FAIL for GL and SKIP for D3D with the same test filter.
1442 OPENGL D3D11 : dEQP-GLES31.functional.image_load_store.* = SKIP 1442 OPENGL D3D11 : dEQP-GLES31.functional.image_load_store.* = SKIP
// TODO(jiawei.shao@intel.com): Implement FramebufferTextureEXT entry point defined in OpenGL ES 3.1 extension GL_EXT_geometry_shader
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.query.framebuffer_attachment_layered = SKIP
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.query.framebuffer_incomplete_layer_targets = SKIP
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.layered.* = SKIP
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.invocation_per_layer_* = SKIP
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.multiple_layers_per_invocation_* = SKIP
1442 D3D11 : dEQP-GLES31.functional.compute* = SKIP 1442 D3D11 : dEQP-GLES31.functional.compute* = SKIP
1729 D3D11 : dEQP-GLES31.functional.atomic_counter.* = SKIP 1729 D3D11 : dEQP-GLES31.functional.atomic_counter.* = SKIP
1951 D3D11 : dEQP-GLES31.functional.layout_binding.ssbo.* = SKIP 1951 D3D11 : dEQP-GLES31.functional.layout_binding.ssbo.* = SKIP
...@@ -1558,9 +1551,8 @@ ...@@ -1558,9 +1551,8 @@
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.conversion.* = FAIL 1941 D3D11 : dEQP-GLES31.functional.geometry_shading.conversion.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.emit.* = FAIL 1941 D3D11 : dEQP-GLES31.functional.geometry_shading.emit.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.varying.* = FAIL 1941 D3D11 : dEQP-GLES31.functional.geometry_shading.varying.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.geometry_* = FAIL 1941 D3D11 : dEQP-GLES31.functional.geometry_shading.layered.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.invocation_output_* = FAIL 1941 D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.draw_* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.input.* = FAIL 1941 D3D11 : dEQP-GLES31.functional.geometry_shading.input.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.negative.* = FAIL 1941 D3D11 : dEQP-GLES31.functional.geometry_shading.negative.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.vertex_transform_feedback.* = FAIL 1941 D3D11 : dEQP-GLES31.functional.geometry_shading.vertex_transform_feedback.* = FAIL
......
...@@ -745,6 +745,101 @@ TEST_P(GeometryShaderTest, NegativeFramebufferTextureEXT) ...@@ -745,6 +745,101 @@ TEST_P(GeometryShaderTest, NegativeFramebufferTextureEXT)
EXPECT_GL_ERROR(GL_INVALID_VALUE); EXPECT_GL_ERROR(GL_INVALID_VALUE);
} }
// Verify CheckFramebufferStatus can work correctly on layered depth and stencil attachments.
TEST_P(GeometryShaderTest, LayeredFramebufferCompletenessWithDepthAttachment)
{
ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
GLint maxFramebufferLayers;
glGetIntegerv(GL_MAX_FRAMEBUFFER_LAYERS_EXT, &maxFramebufferLayers);
constexpr GLint kTexLayers = 2;
ASSERT_LT(kTexLayers, maxFramebufferLayers);
GLTexture layeredColorTex;
glBindTexture(GL_TEXTURE_3D, layeredColorTex);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, kTexLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
// [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
// If any framebuffer attachment is layered, all populated attachments must be layered.
// {FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT }
GLTexture layeredDepthStencilTex;
glBindTexture(GL_TEXTURE_2D_ARRAY, layeredDepthStencilTex);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH24_STENCIL8, 32, 32, kTexLayers, 0,
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
// 1. Color attachment is layered, while depth attachment is not layered.
GLFramebuffer fbo1;
glBindFramebuffer(GL_FRAMEBUFFER, fbo1);
glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, layeredColorTex, 0);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, layeredDepthStencilTex, 0, 0);
GLenum status1 = glCheckFramebufferStatus(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT, status1);
// 2. Color attachment is not layered, while depth attachment is layered.
GLFramebuffer fbo2;
glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, layeredColorTex, 0, 0);
glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, layeredDepthStencilTex, 0);
GLenum status2 = glCheckFramebufferStatus(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT, status2);
// 3. Color attachment is not layered, while stencil attachment is layered.
GLFramebuffer fbo3;
glBindFramebuffer(GL_FRAMEBUFFER, fbo3);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, layeredColorTex, 0, 0);
glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, layeredDepthStencilTex, 0);
GLenum status3 = glCheckFramebufferStatus(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT, status3);
// [EXT_geometry_shader] section 9.4.1, "Framebuffer Completeness"
// If <image> is a three-dimensional texture or a two-dimensional array texture and the
// attachment is layered, the depth or layer count, respectively, of the texture is less than or
// equal to the value of MAX_FRAMEBUFFER_LAYERS_EXT.
GLint maxArrayTextureLayers;
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxArrayTextureLayers);
GLint depthTexLayer4 = maxFramebufferLayers + 1;
ANGLE_SKIP_TEST_IF(maxArrayTextureLayers < depthTexLayer4);
// Use a depth attachment whose layer count exceeds MAX_FRAMEBUFFER_LAYERS
GLTexture depthTex4;
glBindTexture(GL_TEXTURE_2D_ARRAY, depthTex4);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH24_STENCIL8, 32, 32, depthTexLayer4, 0,
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
GLFramebuffer fbo4;
glBindFramebuffer(GL_FRAMEBUFFER, fbo4);
glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTex4, 0);
GLenum status4 = glCheckFramebufferStatus(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, status4);
}
// Verify correct errors can be reported when we use layered cube map attachments on a framebuffer.
TEST_P(GeometryShaderTest, NegativeLayeredFramebufferCompletenessWithCubeMapTextures)
{
ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
GLTexture tex;
glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, status);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
glFramebufferTextureEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0);
ASSERT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, status);
}
ANGLE_INSTANTIATE_TEST(GeometryShaderTestES3, ES3_OPENGL(), ES3_OPENGLES(), ES3_D3D11()); ANGLE_INSTANTIATE_TEST(GeometryShaderTestES3, ES3_OPENGL(), ES3_OPENGLES(), ES3_D3D11());
ANGLE_INSTANTIATE_TEST(GeometryShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11()); ANGLE_INSTANTIATE_TEST(GeometryShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment