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,
mGLState.setObjectDirty(target);
}
// TODO(jiawei.shao@intel.com): implement framebufferTextureEXT
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)
......
......@@ -85,9 +85,26 @@ bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttach
if (attachment.type() == GL_TEXTURE)
{
if (attachment.layer() >= size.depth)
// [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())
{
return false;
if (attachment.layer() >= size.depth)
{
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.
......@@ -149,11 +166,7 @@ bool CheckAttachmentSampleCompleteness(const Context *context,
ASSERT(texture);
const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
// 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());
bool fixedSampleloc = texture->getAttachmentFixedSampleLocations(attachmentImageIndex);
if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
{
return false;
......@@ -1030,6 +1043,9 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
const FramebufferAttachment *firstAttachment = getFirstNonNullAttachment();
Optional<bool> isLayered;
Optional<TextureType> colorAttachmentsTextureType;
for (const FramebufferAttachment &colorAttachment : mState.mColorAttachments)
{
if (colorAttachment.isAttached())
......@@ -1074,7 +1090,37 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
}
hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
hasAttachments = true;
if (!hasAttachments)
{
isLayered = colorAttachment.isLayered();
if (isLayered.value())
{
colorAttachmentsTextureType = colorAttachment.getTextureImageIndex().getType();
}
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;
}
}
}
}
}
......@@ -1104,7 +1150,23 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
}
hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
hasAttachments = true;
if (!hasAttachments)
{
isLayered = depthAttachment.isLayered();
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;
......@@ -1133,7 +1195,23 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
}
hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
hasAttachments = true;
if (!hasAttachments)
{
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
......
......@@ -251,6 +251,11 @@ GLint FramebufferAttachment::layer() const
return (index.has3DLayer() ? index.getLayerIndex() : 0);
}
bool FramebufferAttachment::isLayered() const
{
return mTarget.textureIndex().isLayered();
}
GLsizei FramebufferAttachment::getNumViews() const
{
return mNumViews;
......
......@@ -12,9 +12,9 @@
#include "angle_gl.h"
#include "common/angleutils.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/Error.h"
#include "libANGLE/ImageIndex.h"
#include "libANGLE/formatutils.h"
namespace egl
{
......@@ -43,7 +43,6 @@ class Subject;
namespace gl
{
class FramebufferAttachmentObject;
struct Format;
class Renderbuffer;
class Texture;
......@@ -96,8 +95,14 @@ class FramebufferAttachment final
GLenum getComponentType() const;
GLenum getColorEncoding() const;
bool isTextureWithId(GLuint textureId) const { return mType == GL_TEXTURE && id() == textureId; }
bool isRenderbufferWithId(GLuint renderbufferId) const { return mType == GL_RENDERBUFFER && id() == renderbufferId; }
bool isTextureWithId(GLuint textureId) const
{
return mType == GL_TEXTURE && id() == textureId;
}
bool isRenderbufferWithId(GLuint renderbufferId) const
{
return mType == GL_RENDERBUFFER && id() == renderbufferId;
}
GLenum getBinding() const { return mTarget.binding(); }
GLuint id() const;
......@@ -107,6 +112,7 @@ class FramebufferAttachment final
TextureTarget cubeMapFace() const;
GLint mipLevel() const;
GLint layer() const;
bool isLayered() const;
GLsizei getNumViews() const;
GLenum getMultiviewLayout() const;
GLint getBaseViewIndex() const;
......@@ -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
// Renderbuffers, it will always be 1.
Extents getSize() const;
const Format &getFormat() const;
Format getFormat() const;
GLsizei getSamples() const;
GLenum type() const { return mType; }
bool isAttached() const { return mType != GL_NONE; }
......@@ -190,17 +196,16 @@ class FramebufferAttachmentObject
FramebufferAttachmentObject();
virtual ~FramebufferAttachmentObject();
virtual Extents getAttachmentSize(const ImageIndex &imageIndex) const = 0;
virtual const Format &getAttachmentFormat(GLenum binding,
const ImageIndex &imageIndex) const = 0;
virtual GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const = 0;
virtual Extents getAttachmentSize(const ImageIndex &imageIndex) const = 0;
virtual Format getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const = 0;
virtual GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const = 0;
virtual void onAttach(const Context *context) = 0;
virtual void onDetach(const Context *context) = 0;
virtual GLuint getId() const = 0;
virtual GLuint getId() const = 0;
// These are used for robust resource initialization.
virtual InitState initState(const ImageIndex &imageIndex) const = 0;
virtual InitState initState(const ImageIndex &imageIndex) const = 0;
virtual void setInitState(const ImageIndex &imageIndex, InitState initState) = 0;
Error getAttachmentRenderTarget(const Context *context,
......@@ -223,7 +228,7 @@ inline Extents FramebufferAttachment::getSize() const
return mResource->getAttachmentSize(mTarget.textureIndex());
}
inline const Format &FramebufferAttachment::getFormat() const
inline Format FramebufferAttachment::getFormat() const
{
ASSERT(mResource);
return mResource->getAttachmentFormat(mTarget.binding(), mTarget.textureIndex());
......@@ -244,6 +249,6 @@ inline gl::Error FramebufferAttachment::getRenderTargetImpl(
rtOut);
}
} // namespace gl
} // namespace gl
#endif // LIBANGLE_FRAMEBUFFERATTACHMENT_H_
#endif // LIBANGLE_FRAMEBUFFERATTACHMENT_H_
......@@ -187,7 +187,7 @@ gl::Error Image::orphanSibling(const gl::Context *context, ImageSibling *sibling
return gl::NoError();
}
const gl::Format &Image::getFormat() const
gl::Format Image::getFormat() const
{
return mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex);
}
......
......@@ -82,7 +82,7 @@ class Image final : public gl::RefCountObject
gl::Error onDestroy(const gl::Context *context) override;
~Image() override;
const gl::Format &getFormat() const;
gl::Format getFormat() const;
size_t getWidth() const;
size_t getHeight() const;
size_t getSamples() const;
......
......@@ -56,6 +56,9 @@ TextureTarget TextureTypeToTarget(TextureType type, GLint layerIndex)
{
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);
}
else
......@@ -79,6 +82,19 @@ bool ImageIndex::hasLayer() const
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
{
// It's quicker to check != CubeMap than calling usesTex3D, which checks multiple types. This
......@@ -109,6 +125,11 @@ bool ImageIndex::valid() const
return mType != TextureType::InvalidEnum;
}
bool ImageIndex::isEntireLevelCubeMap() const
{
return mType == TextureType::CubeMap && mLayerIndex == ImageIndex::kEntireLevel;
}
ImageIndex ImageIndex::Make2D(GLint levelIndex)
{
return ImageIndex(TextureType::_2D, levelIndex, kEntireLevel, 1);
......@@ -119,7 +140,7 @@ ImageIndex ImageIndex::MakeRectangle(GLint levelIndex)
return ImageIndex(TextureType::Rectangle, levelIndex, kEntireLevel, 1);
}
ImageIndex ImageIndex::MakeCube(TextureTarget target, GLint levelIndex)
ImageIndex ImageIndex::MakeCubeMapFace(TextureTarget target, GLint levelIndex)
{
ASSERT(IsCubeMapFaceTarget(target));
return ImageIndex(TextureType::CubeMap, levelIndex, TextureTargetToLayer(target), 1);
......
......@@ -36,12 +36,17 @@ class ImageIndex
bool usesTex3D() const;
GLint cubeMapFaceIndex() const;
bool valid() const;
// Note that you cannot use this function when the ImageIndex represents an entire level of cube
// map.
TextureTarget getTarget() const;
bool isLayered() const;
bool isEntireLevelCubeMap() const;
static ImageIndex Make2D(GLint levelIndex);
static ImageIndex MakeRectangle(GLint levelIndex);
static ImageIndex MakeCube(TextureTarget target, GLint levelIndex);
static ImageIndex Make2DArray(GLint levelIndex, GLint layerIndex);
static ImageIndex MakeCubeMapFace(TextureTarget target, GLint levelIndex);
static ImageIndex Make2DArray(GLint levelIndex, GLint layerIndex = kEntireLevel);
static ImageIndex Make2DArrayRange(GLint levelIndex, GLint layerIndex, GLint layerCount);
static ImageIndex Make3D(GLint levelIndex, GLint layerIndex = kEntireLevel);
static ImageIndex MakeFromTarget(TextureTarget target, GLint levelIndex);
......
......@@ -221,8 +221,8 @@ Extents Renderbuffer::getAttachmentSize(const gl::ImageIndex & /*imageIndex*/) c
return Extents(mState.mWidth, mState.mHeight, 1);
}
const Format &Renderbuffer::getAttachmentFormat(GLenum /*binding*/,
const ImageIndex & /*imageIndex*/) const
Format Renderbuffer::getAttachmentFormat(GLenum /*binding*/,
const ImageIndex & /*imageIndex*/) const
{
return getFormat();
}
......
......@@ -96,7 +96,7 @@ class Renderbuffer final : public egl::ImageSibling,
// FramebufferAttachmentObject Impl
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;
void onAttach(const Context *context) override;
......
......@@ -424,7 +424,7 @@ gl::Extents Surface::getAttachmentSize(const gl::ImageIndex & /*target*/) const
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);
}
......
......@@ -107,8 +107,7 @@ class Surface : public gl::FramebufferAttachmentObject
// FramebufferAttachmentObject implementation
gl::Extents getAttachmentSize(const gl::ImageIndex &imageIndex) const override;
const gl::Format &getAttachmentFormat(GLenum binding,
const gl::ImageIndex &imageIndex) const override;
gl::Format getAttachmentFormat(GLenum binding, const gl::ImageIndex &imageIndex) const override;
GLsizei getAttachmentSamples(const gl::ImageIndex &imageIndex) const override;
void onAttach(const gl::Context *context) override {}
......
......@@ -224,12 +224,12 @@ const ImageDesc &TextureState::getBaseLevelDesc() const
return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
}
void TextureState::setCrop(const gl::Rectangle& rect)
void TextureState::setCrop(const gl::Rectangle &rect)
{
mCropRect = rect;
}
const gl::Rectangle& TextureState::getCrop() const
const gl::Rectangle &TextureState::getCrop() const
{
return mCropRect;
}
......@@ -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
{
if (imageIndex.isEntireLevelCubeMap())
{
ASSERT(isCubeComplete());
const GLint levelIndex = imageIndex.getLevelIndex();
return getImageDesc(kCubeMapTextureTargetMin, levelIndex);
}
return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex());
}
......@@ -1386,25 +1396,72 @@ Error Texture::setEGLImageTarget(const Context *context, TextureType type, egl::
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;
}
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;
}
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);
}
const gl::Rectangle& Texture::getCrop() const
const gl::Rectangle &Texture::getCrop() const
{
return mState.getCrop();
}
......@@ -1510,6 +1567,21 @@ Error Texture::ensureInitialized(const Context *context)
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;
}
......@@ -1520,9 +1592,22 @@ InitState Texture::initState() const
void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
{
ImageDesc newDesc = mState.getImageDesc(imageIndex);
newDesc.initState = initState;
mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
// 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);
newDesc.initState = initState;
mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
}
}
Error Texture::ensureSubImageInitialized(const Context *context,
......@@ -1537,8 +1622,8 @@ Error Texture::ensureSubImageInitialized(const Context *context,
// Pre-initialize the texture contents if necessary.
// TODO(jmadill): Check if area overlaps the entire texture.
ImageIndex imageIndex = ImageIndex::MakeFromTarget(target, static_cast<GLint>(level));
const auto &desc = mState.getImageDesc(imageIndex);
ImageIndex imageIndex = ImageIndex::MakeFromTarget(target, static_cast<GLint>(level));
const auto &desc = mState.getImageDesc(imageIndex);
if (desc.initState == InitState::MayNeedInit)
{
ASSERT(mState.mInitState == InitState::MayNeedInit);
......
......@@ -375,9 +375,11 @@ class Texture final : public egl::ImageSibling, public LabeledObject
// FramebufferAttachmentObject implementation
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;
bool getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const;
// GLES1 emulation
void setCrop(const gl::Rectangle& rect);
const gl::Rectangle& getCrop() const;
......
......@@ -952,6 +952,10 @@ void QueryFramebufferAttachmentParameteriv(const Context *context,
}
break;
case GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT:
*params = attachmentObject->isLayered();
break;
default:
UNREACHABLE();
break;
......
......@@ -2191,7 +2191,7 @@ gl::Error TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context,
if (image->isDirty())
{
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);
ANGLE_TRY(commitRegion(context, index, region));
}
......@@ -2239,7 +2239,7 @@ gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
{
// 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
......
......@@ -2289,7 +2289,7 @@ gl::Error Renderer11::copyImageCube(const gl::Context *context,
TextureStorage11_Cube *storage11 = GetAs<TextureStorage11_Cube>(storage);
ASSERT(storage11);
gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
gl::ImageIndex index = gl::ImageIndex::MakeCubeMapFace(target, level);
RenderTargetD3D *destRenderTarget = nullptr;
ANGLE_TRY(storage11->getRenderTarget(context, index, &destRenderTarget));
ASSERT(destRenderTarget);
......
......@@ -57,6 +57,14 @@ void BindFramebufferAttachment(const FunctionsGL *functions,
ToGLenum(texture->getType()),
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)
{
functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint,
......
......@@ -4127,6 +4127,14 @@ bool ValidateGetFramebufferAttachmentParameterivBase(Context *context,
}
break;
case GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT:
if (!context->getExtensions().geometryShader)
{
ANGLE_VALIDATION_ERR(context, InvalidEnum(), GeometryShaderExtensionNotEnabled);
return false;
}
break;
default:
context->handleError(InvalidEnum());
return false;
......
......@@ -48,13 +48,6 @@
// 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
// 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
1729 D3D11 : dEQP-GLES31.functional.atomic_counter.* = SKIP
1951 D3D11 : dEQP-GLES31.functional.layout_binding.ssbo.* = SKIP
......@@ -1558,9 +1551,8 @@
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.varying.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.geometry_* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.invocation_output_* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.draw_* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.layered.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.* = 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.vertex_transform_feedback.* = FAIL
......
......@@ -745,6 +745,101 @@ TEST_P(GeometryShaderTest, NegativeFramebufferTextureEXT)
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(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