Allow glDelete* while PLS is active

Banning glDelete* is extremely dangerous. It will almost definitely
cause memory leaks in client code, and it makes JS garbage collection
needlessly complex.

Instead, specify that PLS is implicity deactivated if the client deletes
anything that is attached to the current draw framebuffer during a PLS
rendering pass.

Bug: chromium:1421437
Change-Id: I3a18ee6b5d5567431e6fa3eccea58cb049845502
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4521436
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Chris Dalton <chris@rive.app>
This commit is contained in:
Chris Dalton 2023-05-09 12:19:54 -06:00 коммит произвёл Angle LUCI CQ
Родитель b76166d027
Коммит 7d4c6d1d07
17 изменённых файлов: 442 добавлений и 216 удалений

Просмотреть файл

@ -451,6 +451,7 @@ Additions to the OpenGL ES Specification, Version 3.0.6
DebugMessageCallback*
DebugMessageControl*
DebugMessageInsert*
Delete*
DepthFunc
DepthMask
DepthRangef
@ -654,7 +655,24 @@ Additions to the OpenGL ES Specification, Version 3.0.6
Modify Section 4.4.2 "Attaching Images to Framebuffer Objects"
(Insert two new numbered section after 4.4.2.3 "Attaching Texture Images to a
(Add a new paragraph to 4.4.2.3 "Attaching Renderbuffer Images to a
Framebuffer".)
If a renderbuffer object is deleted while its image is attached to the
currently bound draw framebuffer, and pixel local storage is active, then it
is as if EndPixelLocalStorageANGLE() had been called with
<n>=PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE and <storeops> of
STORE_OP_STORE_ANGLE.
(Add a new paragraph to 4.4.2.4 "Attaching Texture Images to a Framebuffer".)
If a texture object is deleted while its image is attached to the currently
bound draw framebuffer, and pixel local storage is active, then it is as if
EndPixelLocalStorageANGLE() had been called with
<n>=PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE and <storeops> of
STORE_OP_STORE_ANGLE.
(Insert two new numbered section after 4.4.2.4 "Attaching Texture Images to a
Framebuffer".)
Section 4.4.2.X "Configuring Pixel Local Storage on a Framebuffer"
@ -810,6 +828,12 @@ Additions to the OpenGL ES Specification, Version 3.0.6
When a texture object is deleted, any pixel local storage plane to which it
is bound is automatically deinitialized.
If a texture object is deleted while its image is bound to a pixel local
storage plane on the currently bound draw framebuffer, and pixel local
storage is active, then it is as if EndPixelLocalStorageANGLE() had been
called with <n>=PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE and <storeops> of
STORE_OP_STORE_ANGLE.
Section 4.4.2.Y "Pixel Local Clear State"
Each pixel local storage plane on a framebuffer has state for three separate
@ -1269,7 +1293,7 @@ Issues
spec.
(3) Should we support the ability to enable/disable pixel local storage
planes on an individual basis? (e.g., "GL_LOAD_OP_DISABLE_ANGLE.)
planes on an individual basis? (e.g., "LOAD_OP_DISABLE_ANGLE".)
RESOLVED: No. Some implementations need to reserve color attachments for
internal use. Allowing any combination of planes to be enabled or disabled

Просмотреть файл

@ -6,7 +6,7 @@
"scripts/entry_point_packed_gl_enums.json":
"1c6b036918aabb9822a638fbf33f87f4",
"scripts/generate_entry_points.py":
"25a27ff7c9c450a62c98eee8cb5c7a85",
"af2e7b9911842300f7cbdd3230e279cb",
"scripts/gl_angle_ext.xml":
"758f78e8bf6447f118643421110728b7",
"scripts/registry_xml.py":
@ -132,7 +132,7 @@
"src/libGLESv2/entry_points_egl_ext_autogen.h":
"5a212372e378e0890d2d3ac96c1a3765",
"src/libGLESv2/entry_points_gl_1_autogen.cpp":
"f64ecfbe03214f2a658efe5c2b15e03b",
"19032ff73d0152f7db98f1330dc01781",
"src/libGLESv2/entry_points_gl_1_autogen.h":
"fc92166806eac5dc285f6a3f06e89d2b",
"src/libGLESv2/entry_points_gl_2_autogen.cpp":
@ -152,15 +152,15 @@
"src/libGLESv2/entry_points_gles_1_0_autogen.h":
"1d3aef77845a416497070985a8e9cb31",
"src/libGLESv2/entry_points_gles_2_0_autogen.cpp":
"2051b56158c541d5db8e3d91947cae6d",
"0a4061235c23281170a779ab89d5ea94",
"src/libGLESv2/entry_points_gles_2_0_autogen.h":
"691c60c2dfed9beca68aa1f32aa2c71b",
"src/libGLESv2/entry_points_gles_3_0_autogen.cpp":
"d39253a1e6ced7bb846911deb79157ad",
"dba836d09dcfacfceb03acbed55117a7",
"src/libGLESv2/entry_points_gles_3_0_autogen.h":
"4ac2582759cdc6a30f78f83ab684d555",
"src/libGLESv2/entry_points_gles_3_1_autogen.cpp":
"bdcbc67e3a08d5b60eccfd5ba22a037f",
"eab6c2e40e05a0f87f5fa7e73e95a31b",
"src/libGLESv2/entry_points_gles_3_1_autogen.h":
"a7327c330a91665fc31accbb78793b42",
"src/libGLESv2/entry_points_gles_3_2_autogen.cpp":
@ -168,7 +168,7 @@
"src/libGLESv2/entry_points_gles_3_2_autogen.h":
"647f932a299cdb4726b60bbba059f0d2",
"src/libGLESv2/entry_points_gles_ext_autogen.cpp":
"6ce59775f5eb6e67688b01ceb415c748",
"e6695455270bbda7da7e4f30838905d2",
"src/libGLESv2/entry_points_gles_ext_autogen.h":
"a410e5f079226a62a48222243c91231b",
"src/libGLESv2/libGLESv2_autogen.cpp":

Просмотреть файл

@ -105,6 +105,7 @@ PLS_ALLOW_WILDCARDS = [
"DebugMessageCallback*",
"DebugMessageControl*",
"DebugMessageInsert*",
"Delete*",
"Disablei*",
"DrawArrays*",
"DrawElements*",

Просмотреть файл

@ -1096,6 +1096,28 @@ void Context::deleteProgram(ShaderProgramID program)
void Context::deleteTexture(TextureID textureID)
{
// If a texture object is deleted while its image is bound to a pixel local storage plane on the
// currently bound draw framebuffer, and pixel local storage is active, then it is as if
// EndPixelLocalStorageANGLE() had been called with <n>=PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE
// and <storeops> of STORE_OP_STORE_ANGLE.
if (mState.getPixelLocalStorageActivePlanes() != 0)
{
PixelLocalStorage *pls = mState.getDrawFramebuffer()->peekPixelLocalStorage();
// Even though there is a nonzero number of active PLS planes, peekPixelLocalStorage() may
// still return null if we are in the middle of deleting the active framebuffer.
if (pls != nullptr)
{
for (GLuint i = 0; i < mState.mCaps.maxPixelLocalStoragePlanes; ++i)
{
if (pls->getPlane(i).getTextureID() == textureID)
{
endPixelLocalStorageWithStoreOpsStore();
break;
}
}
}
}
Texture *texture = mState.mTextureManager->getTexture(textureID);
if (texture != nullptr)
{
@ -9409,6 +9431,15 @@ void Context::endPixelLocalStorage(GLsizei n, const GLenum storeops[])
mState.setPixelLocalStorageActivePlanes(0);
}
void Context::endPixelLocalStorageWithStoreOpsStore()
{
GLsizei n = mState.getPixelLocalStorageActivePlanes();
ASSERT(n >= 1);
angle::FixedVector<GLenum, IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES> storeops(
n, GL_STORE_OP_STORE_ANGLE);
endPixelLocalStorage(n, storeops.data());
}
void Context::pixelLocalStorageBarrier()
{
if (getExtensions().shaderPixelLocalStorageCoherentANGLE)

Просмотреть файл

@ -690,6 +690,9 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
// The implementation's ShPixelLocalStorageType must be "PixelLocalStorageEXT".
void drawPixelLocalStorageEXTDisable(const PixelLocalStoragePlane[], const GLenum storeops[]);
// Ends the currently active pixel local storage session with GL_STORE_OP_STORE on all planes.
void endPixelLocalStorageWithStoreOpsStore();
private:
void initializeDefaultResources();

Просмотреть файл

@ -996,17 +996,17 @@ const std::string &Framebuffer::getLabel() const
return mState.mLabel;
}
bool Framebuffer::detachTexture(const Context *context, TextureID textureId)
bool Framebuffer::detachTexture(Context *context, TextureID textureId)
{
return detachResourceById(context, GL_TEXTURE, textureId.value);
}
bool Framebuffer::detachRenderbuffer(const Context *context, RenderbufferID renderbufferId)
bool Framebuffer::detachRenderbuffer(Context *context, RenderbufferID renderbufferId)
{
return detachResourceById(context, GL_RENDERBUFFER, renderbufferId.value);
}
bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId)
bool Framebuffer::detachResourceById(Context *context, GLenum resourceType, GLuint resourceId)
{
bool found = false;
@ -1047,13 +1047,23 @@ bool Framebuffer::detachResourceById(const Context *context, GLenum resourceType
return found;
}
bool Framebuffer::detachMatchingAttachment(const Context *context,
bool Framebuffer::detachMatchingAttachment(Context *context,
FramebufferAttachment *attachment,
GLenum matchType,
GLuint matchId)
{
if (attachment->isAttached() && attachment->type() == matchType && attachment->id() == matchId)
{
const State &contextState = context->getState();
if (contextState.getPixelLocalStorageActivePlanes() != 0 &&
this == contextState.getDrawFramebuffer())
{
// If a (renderbuffer, texture) object is deleted while its image is attached to the
// currently bound draw framebuffer object, and pixel local storage is active, then it
// is as if EndPixelLocalStorageANGLE() had been called with
// <n>=PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE and <storeops> of STORE_OP_STORE_ANGLE.
context->endPixelLocalStorageWithStoreOpsStore();
}
// We go through resetAttachment to make sure that all the required bookkeeping will be done
// such as updating enabled draw buffer state.
resetAttachment(context, attachment->getBinding());

Просмотреть файл

@ -237,8 +237,8 @@ class Framebuffer final : public angle::ObserverInterface,
GLint baseViewIndex);
void resetAttachment(const Context *context, GLenum binding);
bool detachTexture(const Context *context, TextureID texture);
bool detachRenderbuffer(const Context *context, RenderbufferID renderbuffer);
bool detachTexture(Context *context, TextureID texture);
bool detachRenderbuffer(Context *context, RenderbufferID renderbuffer);
const FramebufferAttachment *getColorAttachment(size_t colorAttachment) const;
const FramebufferAttachment *getDepthAttachment() const;
@ -442,15 +442,15 @@ class Framebuffer final : public angle::ObserverInterface,
// Lazily creates a PixelLocalStorage object for this Framebuffer.
PixelLocalStorage &getPixelLocalStorage(const Context *);
// Returns nullptr if the pixel local storage object has not been created yet.
const PixelLocalStorage *peekPixelLocalStorage() const { return mPixelLocalStorage.get(); }
PixelLocalStorage *peekPixelLocalStorage() const { return mPixelLocalStorage.get(); }
// Detaches the the pixel local storage object so the Context can call deleteContextObjects().
std::unique_ptr<PixelLocalStorage> detachPixelLocalStorage();
static const FramebufferID kDefaultDrawFramebufferHandle;
private:
bool detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId);
bool detachMatchingAttachment(const Context *context,
bool detachResourceById(Context *context, GLenum resourceType, GLuint resourceId);
bool detachMatchingAttachment(Context *context,
FramebufferAttachment *attachment,
GLenum matchType,
GLuint matchId);

Просмотреть файл

@ -441,8 +441,8 @@ const Texture *PixelLocalStoragePlane::getBackingTexture(const Context *context)
return tex;
}
PixelLocalStorage::PixelLocalStorage(const ShPixelLocalStorageOptions &plsOptions)
: mPLSOptions(plsOptions)
PixelLocalStorage::PixelLocalStorage(const ShPixelLocalStorageOptions &plsOptions, const Caps &caps)
: mPLSOptions(plsOptions), mPlanes(caps.maxPixelLocalStoragePlanes)
{}
PixelLocalStorage::~PixelLocalStorage() {}
@ -450,7 +450,8 @@ PixelLocalStorage::~PixelLocalStorage() {}
namespace
{
bool AllPlanesDeinitialized(
const std::array<PixelLocalStoragePlane, IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES> &planes,
const angle::FixedVector<PixelLocalStoragePlane, IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES>
&planes,
const Context *context)
{
for (const PixelLocalStoragePlane &plane : planes)
@ -551,9 +552,7 @@ void PixelLocalStorage::interrupt(Context *context)
mActivePlanesAtInterrupt <= IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES);
if (mActivePlanesAtInterrupt >= 1)
{
angle::FixedVector<GLenum, IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES> storeops(
mActivePlanesAtInterrupt, GL_STORE_OP_STORE_ANGLE);
context->endPixelLocalStorage(mActivePlanesAtInterrupt, storeops.data());
context->endPixelLocalStorageWithStoreOpsStore();
}
}
++mInterruptCount;
@ -584,8 +583,8 @@ namespace
class PixelLocalStorageImageLoadStore : public PixelLocalStorage
{
public:
PixelLocalStorageImageLoadStore(const ShPixelLocalStorageOptions &plsOptions)
: PixelLocalStorage(plsOptions)
PixelLocalStorageImageLoadStore(const ShPixelLocalStorageOptions &plsOptions, const Caps &caps)
: PixelLocalStorage(plsOptions, caps)
{
ASSERT(mPLSOptions.type == ShPixelLocalStorageType::ImageLoadStore);
}
@ -808,8 +807,9 @@ class PixelLocalStorageImageLoadStore : public PixelLocalStorage
class PixelLocalStorageFramebufferFetch : public PixelLocalStorage
{
public:
PixelLocalStorageFramebufferFetch(const ShPixelLocalStorageOptions &plsOptions)
: PixelLocalStorage(plsOptions)
PixelLocalStorageFramebufferFetch(const ShPixelLocalStorageOptions &plsOptions,
const Caps &caps)
: PixelLocalStorage(plsOptions, caps)
{
ASSERT(mPLSOptions.type == ShPixelLocalStorageType::FramebufferFetch);
}
@ -1021,8 +1021,8 @@ class PixelLocalStorageFramebufferFetch : public PixelLocalStorage
class PixelLocalStorageEXT : public PixelLocalStorage
{
public:
PixelLocalStorageEXT(const ShPixelLocalStorageOptions &plsOptions)
: PixelLocalStorage(plsOptions)
PixelLocalStorageEXT(const ShPixelLocalStorageOptions &plsOptions, const Caps &caps)
: PixelLocalStorage(plsOptions, caps)
{
ASSERT(mPLSOptions.type == ShPixelLocalStorageType::PixelLocalStorageEXT);
}
@ -1092,14 +1092,15 @@ std::unique_ptr<PixelLocalStorage> PixelLocalStorage::Make(const Context *contex
{
const ShPixelLocalStorageOptions &plsOptions =
context->getImplementation()->getNativePixelLocalStorageOptions();
const Caps &caps = context->getState().getCaps();
switch (plsOptions.type)
{
case ShPixelLocalStorageType::ImageLoadStore:
return std::make_unique<PixelLocalStorageImageLoadStore>(plsOptions);
return std::make_unique<PixelLocalStorageImageLoadStore>(plsOptions, caps);
case ShPixelLocalStorageType::FramebufferFetch:
return std::make_unique<PixelLocalStorageFramebufferFetch>(plsOptions);
return std::make_unique<PixelLocalStorageFramebufferFetch>(plsOptions, caps);
case ShPixelLocalStorageType::PixelLocalStorageEXT:
return std::make_unique<PixelLocalStorageEXT>(plsOptions);
return std::make_unique<PixelLocalStorageEXT>(plsOptions, caps);
default:
UNREACHABLE();
return nullptr;

Просмотреть файл

@ -19,6 +19,7 @@
namespace gl
{
struct Caps;
class Context;
class Texture;
@ -43,22 +44,13 @@ class PixelLocalStoragePlane : angle::NonCopyable, public angle::ObserverInterfa
void setTextureBacked(Context *, Texture *, int level, int layer);
void onSubjectStateChange(angle::SubjectIndex, angle::SubjectMessage) override;
bool isMemoryless() const
{
// isMemoryless() should be false if the plane is deinitialized.
ASSERT(!mMemoryless || mInternalformat != GL_NONE);
return mMemoryless;
}
// Returns true if the plane is deinitialized, either explicitly or implicitly via deleting the
// texture that was attached to it.
bool isDeinitialized() const;
// Ensures we have an internal backing texture for memoryless planes. In some implementations we
// need a backing texture even if the plane is memoryless.
void ensureBackingTextureIfMemoryless(Context *, Extents plsSize);
GLenum getInternalformat() const { return mInternalformat; }
bool isMemoryless() const { return mMemoryless; }
TextureID getTextureID() const { return mTextureID; }
// Implements glGetIntegeri_v() for GL_PIXEL_LOCAL_FORMAT_ANGLE,
// GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE, GL_PIXEL_LOCAL_TEXTURE_LEVEL_ANGLE, and
@ -70,6 +62,10 @@ class PixelLocalStoragePlane : angle::NonCopyable, public angle::ObserverInterfa
// or memoryless.
bool getTextureImageExtents(const Context *, Extents *extents) const;
// Ensures we have an internal backing texture for memoryless planes. In some implementations we
// need a backing texture even if the plane is memoryless.
void ensureBackingTextureIfMemoryless(Context *, Extents plsSize);
// Attaches this plane to the specified color attachment point on the current draw framebuffer.
void attachToDrawFramebuffer(Context *, GLenum colorAttachment) const;
@ -172,7 +168,7 @@ class PixelLocalStorage
void restore(Context *);
protected:
PixelLocalStorage(const ShPixelLocalStorageOptions &);
PixelLocalStorage(const ShPixelLocalStorageOptions &, const Caps &);
// Called when the context is lost or destroyed. Causes the subclass to clear its GL object
// handles.
@ -190,7 +186,8 @@ class PixelLocalStorage
const ShPixelLocalStorageOptions mPLSOptions;
private:
std::array<PixelLocalStoragePlane, IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES> mPlanes;
angle::FixedVector<PixelLocalStoragePlane, IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES>
mPlanes;
size_t mInterruptCount = 0;
GLsizei mActivePlanesAtInterrupt = 0;
};

Просмотреть файл

@ -1745,7 +1745,7 @@ TextureID State::getSamplerTextureId(unsigned int sampler, TextureType type) con
return mSamplerTextures[type][sampler].id();
}
void State::detachTexture(const Context *context, const TextureMap &zeroTextures, TextureID texture)
void State::detachTexture(Context *context, const TextureMap &zeroTextures, TextureID texture)
{
// Textures have a detach method on State rather than a simple
// removeBinding, because the zero/null texture objects are managed
@ -1857,7 +1857,7 @@ void State::setRenderbufferBinding(const Context *context, Renderbuffer *renderb
mDirtyBits.set(DIRTY_BIT_RENDERBUFFER_BINDING);
}
void State::detachRenderbuffer(const Context *context, RenderbufferID renderbuffer)
void State::detachRenderbuffer(Context *context, RenderbufferID renderbuffer)
{
// [OpenGL ES 2.0.24] section 4.4 page 109:
// If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though

Просмотреть файл

@ -330,7 +330,7 @@ class State : angle::NonCopyable
}
TextureID getSamplerTextureId(unsigned int sampler, TextureType type) const;
void detachTexture(const Context *context, const TextureMap &zeroTextures, TextureID texture);
void detachTexture(Context *context, const TextureMap &zeroTextures, TextureID texture);
void initializeZeroTextures(const Context *context, const TextureMap &zeroTextures);
void invalidateTextureBindings(TextureType type);
@ -353,7 +353,7 @@ class State : angle::NonCopyable
void setRenderbufferBinding(const Context *context, Renderbuffer *renderbuffer);
RenderbufferID getRenderbufferId() const { return mRenderbuffer.id(); }
Renderbuffer *getCurrentRenderbuffer() const { return mRenderbuffer.get(); }
void detachRenderbuffer(const Context *context, RenderbufferID renderbuffer);
void detachRenderbuffer(Context *context, RenderbufferID renderbuffer);
// Framebuffer binding manipulation
void setReadFramebufferBinding(Framebuffer *framebuffer);

Просмотреть файл

@ -1101,8 +1101,7 @@ void GL_APIENTRY GL_DeleteLists(GLuint list, GLsizei range)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteLists) &&
ValidateDeleteLists(context, angle::EntryPoint::GLDeleteLists, list, range)));
ValidateDeleteLists(context, angle::EntryPoint::GLDeleteLists, list, range));
if (isCallValid)
{
context->deleteLists(list, range);

Просмотреть файл

@ -876,9 +876,7 @@ void GL_APIENTRY GL_DeleteBuffers(GLsizei n, const GLuint *buffers)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteBuffers) &&
ValidateDeleteBuffers(context, angle::EntryPoint::GLDeleteBuffers, n,
buffersPacked)));
ValidateDeleteBuffers(context, angle::EntryPoint::GLDeleteBuffers, n, buffersPacked));
if (isCallValid)
{
context->deleteBuffers(n, buffersPacked);
@ -904,9 +902,8 @@ void GL_APIENTRY GL_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteFramebuffers) &&
ValidateDeleteFramebuffers(context, angle::EntryPoint::GLDeleteFramebuffers, n,
framebuffersPacked)));
ValidateDeleteFramebuffers(context, angle::EntryPoint::GLDeleteFramebuffers, n,
framebuffersPacked));
if (isCallValid)
{
context->deleteFramebuffers(n, framebuffersPacked);
@ -931,8 +928,7 @@ void GL_APIENTRY GL_DeleteProgram(GLuint program)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteProgram) &&
ValidateDeleteProgram(context, angle::EntryPoint::GLDeleteProgram, programPacked)));
ValidateDeleteProgram(context, angle::EntryPoint::GLDeleteProgram, programPacked));
if (isCallValid)
{
context->deleteProgram(programPacked);
@ -959,10 +955,8 @@ void GL_APIENTRY GL_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context,
angle::EntryPoint::GLDeleteRenderbuffers) &&
ValidateDeleteRenderbuffers(context, angle::EntryPoint::GLDeleteRenderbuffers, n,
renderbuffersPacked)));
ValidateDeleteRenderbuffers(context, angle::EntryPoint::GLDeleteRenderbuffers, n,
renderbuffersPacked));
if (isCallValid)
{
context->deleteRenderbuffers(n, renderbuffersPacked);
@ -987,8 +981,7 @@ void GL_APIENTRY GL_DeleteShader(GLuint shader)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteShader) &&
ValidateDeleteShader(context, angle::EntryPoint::GLDeleteShader, shaderPacked)));
ValidateDeleteShader(context, angle::EntryPoint::GLDeleteShader, shaderPacked));
if (isCallValid)
{
context->deleteShader(shaderPacked);
@ -1012,11 +1005,9 @@ void GL_APIENTRY GL_DeleteTextures(GLsizei n, const GLuint *textures)
{
const TextureID *texturesPacked = PackParam<const TextureID *>(textures);
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteTextures) &&
ValidateDeleteTextures(context, angle::EntryPoint::GLDeleteTextures, n,
texturesPacked)));
bool isCallValid = (context->skipValidation() ||
ValidateDeleteTextures(context, angle::EntryPoint::GLDeleteTextures, n,
texturesPacked));
if (isCallValid)
{
context->deleteTextures(n, texturesPacked);

Просмотреть файл

@ -588,8 +588,7 @@ void GL_APIENTRY GL_DeleteQueries(GLsizei n, const GLuint *ids)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteQueries) &&
ValidateDeleteQueries(context, angle::EntryPoint::GLDeleteQueries, n, idsPacked)));
ValidateDeleteQueries(context, angle::EntryPoint::GLDeleteQueries, n, idsPacked));
if (isCallValid)
{
context->deleteQueries(n, idsPacked);
@ -613,11 +612,9 @@ void GL_APIENTRY GL_DeleteSamplers(GLsizei count, const GLuint *samplers)
{
const SamplerID *samplersPacked = PackParam<const SamplerID *>(samplers);
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteSamplers) &&
ValidateDeleteSamplers(context, angle::EntryPoint::GLDeleteSamplers, count,
samplersPacked)));
bool isCallValid = (context->skipValidation() ||
ValidateDeleteSamplers(context, angle::EntryPoint::GLDeleteSamplers,
count, samplersPacked));
if (isCallValid)
{
context->deleteSamplers(count, samplersPacked);
@ -643,8 +640,7 @@ void GL_APIENTRY GL_DeleteSync(GLsync sync)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteSync) &&
ValidateDeleteSync(context, angle::EntryPoint::GLDeleteSync, syncPacked)));
ValidateDeleteSync(context, angle::EntryPoint::GLDeleteSync, syncPacked));
if (isCallValid)
{
context->deleteSync(syncPacked);
@ -670,10 +666,8 @@ void GL_APIENTRY GL_DeleteTransformFeedbacks(GLsizei n, const GLuint *ids)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context,
angle::EntryPoint::GLDeleteTransformFeedbacks) &&
ValidateDeleteTransformFeedbacks(
context, angle::EntryPoint::GLDeleteTransformFeedbacks, n, idsPacked)));
ValidateDeleteTransformFeedbacks(
context, angle::EntryPoint::GLDeleteTransformFeedbacks, n, idsPacked));
if (isCallValid)
{
context->deleteTransformFeedbacks(n, idsPacked);
@ -697,11 +691,9 @@ void GL_APIENTRY GL_DeleteVertexArrays(GLsizei n, const GLuint *arrays)
{
const VertexArrayID *arraysPacked = PackParam<const VertexArrayID *>(arrays);
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteVertexArrays) &&
ValidateDeleteVertexArrays(context, angle::EntryPoint::GLDeleteVertexArrays, n,
arraysPacked)));
bool isCallValid = (context->skipValidation() ||
ValidateDeleteVertexArrays(
context, angle::EntryPoint::GLDeleteVertexArrays, n, arraysPacked));
if (isCallValid)
{
context->deleteVertexArrays(n, arraysPacked);

Просмотреть файл

@ -203,10 +203,8 @@ void GL_APIENTRY GL_DeleteProgramPipelines(GLsizei n, const GLuint *pipelines)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context,
angle::EntryPoint::GLDeleteProgramPipelines) &&
ValidateDeleteProgramPipelines(context, angle::EntryPoint::GLDeleteProgramPipelines,
n, pipelinesPacked)));
ValidateDeleteProgramPipelines(context, angle::EntryPoint::GLDeleteProgramPipelines, n,
pipelinesPacked));
if (isCallValid)
{
context->deleteProgramPipelines(n, pipelinesPacked);

Просмотреть файл

@ -72,12 +72,9 @@ void GL_APIENTRY GL_DeletePerfMonitorsAMD(GLsizei n, GLuint *monitors)
if (context)
{
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context,
angle::EntryPoint::GLDeletePerfMonitorsAMD) &&
ValidateDeletePerfMonitorsAMD(context, angle::EntryPoint::GLDeletePerfMonitorsAMD, n,
monitors)));
bool isCallValid = (context->skipValidation() ||
ValidateDeletePerfMonitorsAMD(
context, angle::EntryPoint::GLDeletePerfMonitorsAMD, n, monitors));
if (isCallValid)
{
context->deletePerfMonitors(n, monitors);
@ -5565,11 +5562,9 @@ void GL_APIENTRY GL_DeleteQueriesEXT(GLsizei n, const GLuint *ids)
{
const QueryID *idsPacked = PackParam<const QueryID *>(ids);
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteQueriesEXT) &&
ValidateDeleteQueriesEXT(context, angle::EntryPoint::GLDeleteQueriesEXT, n,
idsPacked)));
bool isCallValid = (context->skipValidation() ||
ValidateDeleteQueriesEXT(context, angle::EntryPoint::GLDeleteQueriesEXT,
n, idsPacked));
if (isCallValid)
{
context->deleteQueries(n, idsPacked);
@ -6629,10 +6624,8 @@ void GL_APIENTRY GL_DeleteMemoryObjectsEXT(GLsizei n, const GLuint *memoryObject
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context,
angle::EntryPoint::GLDeleteMemoryObjectsEXT) &&
ValidateDeleteMemoryObjectsEXT(context, angle::EntryPoint::GLDeleteMemoryObjectsEXT,
n, memoryObjectsPacked)));
ValidateDeleteMemoryObjectsEXT(context, angle::EntryPoint::GLDeleteMemoryObjectsEXT, n,
memoryObjectsPacked));
if (isCallValid)
{
context->deleteMemoryObjects(n, memoryObjectsPacked);
@ -7402,10 +7395,8 @@ void GL_APIENTRY GL_DeleteSemaphoresEXT(GLsizei n, const GLuint *semaphores)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context,
angle::EntryPoint::GLDeleteSemaphoresEXT) &&
ValidateDeleteSemaphoresEXT(context, angle::EntryPoint::GLDeleteSemaphoresEXT, n,
semaphoresPacked)));
ValidateDeleteSemaphoresEXT(context, angle::EntryPoint::GLDeleteSemaphoresEXT, n,
semaphoresPacked));
if (isCallValid)
{
context->deleteSemaphores(n, semaphoresPacked);
@ -7770,10 +7761,8 @@ void GL_APIENTRY GL_DeleteProgramPipelinesEXT(GLsizei n, const GLuint *pipelines
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context,
angle::EntryPoint::GLDeleteProgramPipelinesEXT) &&
ValidateDeleteProgramPipelinesEXT(
context, angle::EntryPoint::GLDeleteProgramPipelinesEXT, n, pipelinesPacked)));
ValidateDeleteProgramPipelinesEXT(
context, angle::EntryPoint::GLDeleteProgramPipelinesEXT, n, pipelinesPacked));
if (isCallValid)
{
context->deleteProgramPipelines(n, pipelinesPacked);
@ -10151,9 +10140,7 @@ void GL_APIENTRY GL_DeleteFencesNV(GLsizei n, const GLuint *fences)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context, angle::EntryPoint::GLDeleteFencesNV) &&
ValidateDeleteFencesNV(context, angle::EntryPoint::GLDeleteFencesNV, n,
fencesPacked)));
ValidateDeleteFencesNV(context, angle::EntryPoint::GLDeleteFencesNV, n, fencesPacked));
if (isCallValid)
{
context->deleteFencesNV(n, fencesPacked);
@ -11220,10 +11207,8 @@ void GL_APIENTRY GL_DeleteFramebuffersOES(GLsizei n, const GLuint *framebuffers)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context,
angle::EntryPoint::GLDeleteFramebuffersOES) &&
ValidateDeleteFramebuffersOES(context, angle::EntryPoint::GLDeleteFramebuffersOES, n,
framebuffersPacked)));
ValidateDeleteFramebuffersOES(context, angle::EntryPoint::GLDeleteFramebuffersOES, n,
framebuffersPacked));
if (isCallValid)
{
context->deleteFramebuffers(n, framebuffersPacked);
@ -11251,10 +11236,8 @@ void GL_APIENTRY GL_DeleteRenderbuffersOES(GLsizei n, const GLuint *renderbuffer
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context,
angle::EntryPoint::GLDeleteRenderbuffersOES) &&
ValidateDeleteRenderbuffersOES(context, angle::EntryPoint::GLDeleteRenderbuffersOES,
n, renderbuffersPacked)));
ValidateDeleteRenderbuffersOES(context, angle::EntryPoint::GLDeleteRenderbuffersOES, n,
renderbuffersPacked));
if (isCallValid)
{
context->deleteRenderbuffers(n, renderbuffersPacked);
@ -12974,10 +12957,8 @@ void GL_APIENTRY GL_DeleteVertexArraysOES(GLsizei n, const GLuint *arrays)
SCOPED_SHARE_CONTEXT_LOCK(context);
bool isCallValid =
(context->skipValidation() ||
(ValidatePixelLocalStorageInactive(context,
angle::EntryPoint::GLDeleteVertexArraysOES) &&
ValidateDeleteVertexArraysOES(context, angle::EntryPoint::GLDeleteVertexArraysOES, n,
arraysPacked)));
ValidateDeleteVertexArraysOES(context, angle::EntryPoint::GLDeleteVertexArraysOES, n,
arraysPacked));
if (isCallValid)
{
context->deleteVertexArrays(n, arraysPacked);

Просмотреть файл

@ -12,6 +12,90 @@
using namespace angle;
#define ASSERT_GL_INTEGER(pname, expected) \
{ \
GLint value; \
glGetIntegerv(pname, &value); \
ASSERT_EQ(value, GLint(expected)); \
}
#define EXPECT_GL_INTEGER(pname, expected) \
{ \
GLint value; \
glGetIntegerv(pname, &value); \
EXPECT_EQ(value, GLint(expected)); \
}
#define EXPECT_PLS_INTEGER(plane, pname, expected) \
{ \
GLint value = 0xbaadc0de; \
glGetFramebufferPixelLocalStorageParameterivRobustANGLE(plane, pname, 1, nullptr, &value); \
EXPECT_EQ(value, GLint(expected)); \
value = 0xbaadc0de; \
glGetFramebufferPixelLocalStorageParameterivANGLE(plane, pname, &value); \
EXPECT_EQ(value, GLint(expected)); \
}
#define EXPECT_GL_SINGLE_ERROR(err) \
EXPECT_GL_ERROR(err); \
while (GLenum nextError = glGetError()) \
{ \
EXPECT_EQ(nextError, GLenum(GL_NO_ERROR)); \
}
#define EXPECT_PIXEL_LOCAL_CLEAR_VALUE_FLOAT(plane, rgba) \
{ \
std::array<GLfloat, 4> expected rgba; \
std::array<GLfloat, 4> value; \
value.fill(std::numeric_limits<GLfloat>::quiet_NaN()); \
glGetFramebufferPixelLocalStorageParameterfvANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_FLOAT_ANGLE, value.data()); \
EXPECT_EQ(value, expected); \
value.fill(std::numeric_limits<GLfloat>::quiet_NaN()); \
glGetFramebufferPixelLocalStorageParameterfvRobustANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_FLOAT_ANGLE, 4, nullptr, value.data()); \
EXPECT_EQ(value, expected); \
}
#define EXPECT_PIXEL_LOCAL_CLEAR_VALUE_INT(plane, rgba) \
{ \
std::array<GLint, 4> expected rgba; \
std::array<GLint, 4> value; \
value.fill(0xbaadc0de); \
glGetFramebufferPixelLocalStorageParameterivANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_INT_ANGLE, value.data()); \
EXPECT_EQ(value, expected); \
value.fill(0xbaadc0de); \
glGetFramebufferPixelLocalStorageParameterivRobustANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_INT_ANGLE, 4, nullptr, value.data()); \
EXPECT_EQ(value, expected); \
}
#define EXPECT_PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT(plane, rgba) \
{ \
std::array<GLuint, 4> expected rgba; \
std::array<GLuint, 4> value; \
std::array<GLint, 4> valuei; \
valuei.fill(0xbaadc0de); \
glGetFramebufferPixelLocalStorageParameterivANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_ANGLE, valuei.data()); \
memcpy(value.data(), valuei.data(), sizeof(value)); \
EXPECT_EQ(value, expected); \
valuei.fill(0xbaadc0de); \
glGetFramebufferPixelLocalStorageParameterivRobustANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_ANGLE, 4, nullptr, valuei.data()); \
memcpy(value.data(), valuei.data(), sizeof(value)); \
EXPECT_EQ(value, expected); \
}
#define EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(framebuffer, attachment, value) \
{ \
GLint attachmentName = 0xbaadc0de; \
glGetFramebufferAttachmentParameteriv( \
framebuffer, attachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &attachmentName); \
EXPECT_EQ(attachmentName, static_cast<GLint>(value)); \
}
constexpr static int W = 128, H = 128;
constexpr static std::array<float, 4> FULLSCREEN = {0, 0, W, H};
@ -56,6 +140,11 @@ class PLSTestTexture
PLSTestTexture(GLenum internalformat) { reset(internalformat); }
PLSTestTexture(GLenum internalformat, int w, int h) { reset(internalformat, w, h); }
PLSTestTexture(PLSTestTexture &&that) : mID(std::exchange(that.mID, 0)) {}
void reset()
{
glDeleteTextures(1, &mID);
mID = 0;
}
void reset(GLenum internalformat) { reset(internalformat, W, H); }
void reset(GLenum internalformat, int w, int h)
{
@ -610,51 +699,6 @@ TEST_P(PixelLocalStorageTest, R32)
ASSERT_GL_NO_ERROR();
}
#define EXPECT_PIXEL_LOCAL_CLEAR_VALUE_FLOAT(plane, rgba) \
{ \
std::array<GLfloat, 4> expected rgba; \
std::array<GLfloat, 4> value; \
value.fill(std::numeric_limits<GLfloat>::quiet_NaN()); \
glGetFramebufferPixelLocalStorageParameterfvANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_FLOAT_ANGLE, value.data()); \
EXPECT_EQ(value, expected); \
value.fill(std::numeric_limits<GLfloat>::quiet_NaN()); \
glGetFramebufferPixelLocalStorageParameterfvRobustANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_FLOAT_ANGLE, 4, nullptr, value.data()); \
EXPECT_EQ(value, expected); \
}
#define EXPECT_PIXEL_LOCAL_CLEAR_VALUE_INT(plane, rgba) \
{ \
std::array<GLint, 4> expected rgba; \
std::array<GLint, 4> value; \
value.fill(0xbaadc0de); \
glGetFramebufferPixelLocalStorageParameterivANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_INT_ANGLE, value.data()); \
EXPECT_EQ(value, expected); \
value.fill(0xbaadc0de); \
glGetFramebufferPixelLocalStorageParameterivRobustANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_INT_ANGLE, 4, nullptr, value.data()); \
EXPECT_EQ(value, expected); \
}
#define EXPECT_PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT(plane, rgba) \
{ \
std::array<GLuint, 4> expected rgba; \
std::array<GLuint, 4> value; \
std::array<GLint, 4> valuei; \
valuei.fill(0xbaadc0de); \
glGetFramebufferPixelLocalStorageParameterivANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_ANGLE, valuei.data()); \
memcpy(value.data(), valuei.data(), sizeof(value)); \
EXPECT_EQ(value, expected); \
valuei.fill(0xbaadc0de); \
glGetFramebufferPixelLocalStorageParameterivRobustANGLE( \
plane, GL_PIXEL_LOCAL_CLEAR_VALUE_UNSIGNED_INT_ANGLE, 4, nullptr, valuei.data()); \
memcpy(value.data(), valuei.data(), sizeof(value)); \
EXPECT_EQ(value, expected); \
}
// Check proper functioning of the clear value state.
TEST_P(PixelLocalStorageTest, ClearValues_rgba8)
{
@ -2666,6 +2710,192 @@ TEST_P(PixelLocalStorageTest, Interrupt)
ASSERT_GL_NO_ERROR();
}
// Check that deleting attachments and PLS bindings on the current draw framebuffer implicitly
// deactivates pixel local storage.
TEST_P(PixelLocalStorageTest, DeleteAttachments_draw_framebuffer)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_shader_pixel_local_storage"));
GLFramebuffer fbo;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
GLuint depthStencil;
glGenRenderbuffers(1, &depthStencil);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, W, H);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencil);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthStencil);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthStencil);
PLSTestTexture colorTex(GL_RGBA8);
if (MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE > 0)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTex);
}
GLuint colorRenderbuffer;
if (MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE > 1)
{
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, W, H);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER,
colorRenderbuffer);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, colorRenderbuffer);
}
PLSTestTexture pls0(GL_RGBA8);
glFramebufferTexturePixelLocalStorageANGLE(0, pls0, 0, 0);
EXPECT_PLS_INTEGER(0, GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE, pls0);
PLSTestTexture pls1(GL_RGBA8);
glFramebufferTexturePixelLocalStorageANGLE(1, pls1, 0, 0);
EXPECT_PLS_INTEGER(1, GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE, pls1);
glBeginPixelLocalStorageANGLE(1, GLenumArray({GL_DONT_CARE}));
EXPECT_GL_INTEGER(GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE, 1);
ASSERT_GL_NO_ERROR();
// Deleting the depth/stencil will implicitly end pixel local storage.
glDeleteRenderbuffers(1, &depthStencil);
EXPECT_GL_NO_ERROR();
EXPECT_GL_INTEGER(GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE, 0);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 0);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, 0);
if (MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE > 0)
{
// Deleting the color texture will implicitly end pixel local storage.
glBeginPixelLocalStorageANGLE(1, GLenumArray({GL_DONT_CARE}));
colorTex.reset();
EXPECT_GL_NO_ERROR();
EXPECT_GL_INTEGER(GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE, 0);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0);
}
if (MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE > 1)
{
// Deleting the color renderbuffer will implicitly end pixel local storage.
glBeginPixelLocalStorageANGLE(1, GLenumArray({GL_DONT_CARE}));
glDeleteRenderbuffers(1, &colorRenderbuffer);
EXPECT_GL_NO_ERROR();
EXPECT_GL_INTEGER(GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE, 0);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, 0);
}
// Pixel local storage can't be ended because it's already deactivated.
glEndPixelLocalStorageANGLE(1, GLenumArray({GL_DONT_CARE}));
EXPECT_GL_SINGLE_ERROR(GL_INVALID_OPERATION);
// Deleting an inactive PLS plane will implicitly end pixel local storage.
glBeginPixelLocalStorageANGLE(1, GLenumArray({GL_DONT_CARE}));
pls1.reset();
EXPECT_GL_NO_ERROR();
EXPECT_GL_INTEGER(GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE, 0);
EXPECT_PLS_INTEGER(1, GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE, 0);
// Deleting an active PLS plane will implicitly end pixel local storage.
glBeginPixelLocalStorageANGLE(1, GLenumArray({GL_DONT_CARE}));
pls0.reset();
EXPECT_GL_NO_ERROR();
EXPECT_GL_INTEGER(GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE, 0);
EXPECT_PLS_INTEGER(0, GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE, 0);
// Deleting the textures deinitialized the planes.
glBeginPixelLocalStorageANGLE(1, GLenumArray({GL_DONT_CARE}));
EXPECT_GL_SINGLE_ERROR(GL_INVALID_OPERATION);
EXPECT_GL_INTEGER(GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE, 0);
}
// Check that deleting attachments and PLS bindings on the current read framebuffer does *not*
// deactivate pixel local storage.
TEST_P(PixelLocalStorageTest, DeleteAttachments_read_framebuffer)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_shader_pixel_local_storage"));
// Deleting attachments on the read framebuffer does not turn off PLS.
GLFramebuffer readFBO;
glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
GLuint depthStencil;
glGenRenderbuffers(1, &depthStencil);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, W, H);
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencil);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthStencil);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthStencil);
PLSTestTexture colorTex(GL_RGBA8);
if (MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE > 0)
{
colorTex.reset(GL_RGBA8);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex,
0);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTex);
}
GLuint colorRenderbuffer;
if (MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE > 1)
{
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, W, H);
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER,
colorRenderbuffer);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
colorRenderbuffer);
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, readFBO);
PLSTestTexture inactivePLS0(GL_RGBA8);
glFramebufferTexturePixelLocalStorageANGLE(0, inactivePLS0, 0, 0);
EXPECT_PLS_INTEGER(0, GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE, inactivePLS0);
PLSTestTexture inactivePLS1(GL_RGBA8);
glFramebufferTexturePixelLocalStorageANGLE(1, inactivePLS1, 0, 0);
EXPECT_PLS_INTEGER(1, GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE, inactivePLS1);
GLFramebuffer fbo;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
PLSTestTexture activePLS(GL_RGBA8);
glFramebufferTexturePixelLocalStorageANGLE(0, activePLS, 0, 0);
glBeginPixelLocalStorageANGLE(1, GLenumArray({GL_DONT_CARE}));
EXPECT_GL_NO_ERROR();
EXPECT_GL_INTEGER(GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE, 1);
glDeleteRenderbuffers(1, &depthStencil);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 0);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, 0);
if (MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE > 0)
{
colorTex.reset();
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0);
}
if (MAX_COLOR_ATTACHMENTS_WITH_ACTIVE_PIXEL_LOCAL_STORAGE > 1)
{
glDeleteRenderbuffers(1, &colorRenderbuffer);
EXPECT_FRAMEBUFFER_ATTACHMENT_NAME(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, 0);
}
inactivePLS0.reset();
inactivePLS1.reset();
EXPECT_GL_NO_ERROR();
EXPECT_GL_INTEGER(GL_PIXEL_LOCAL_STORAGE_ACTIVE_PLANES_ANGLE, 1);
glEndPixelLocalStorageANGLE(1, GLenumArray({GL_DONT_CARE}));
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, readFBO);
EXPECT_PLS_INTEGER(0, GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE, 0);
EXPECT_PLS_INTEGER(1, GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE, 0);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PixelLocalStorageTest);
#define PLATFORM(API, BACKEND) API##_##BACKEND()
#define PLS_INSTANTIATE_RENDERING_TEST_AND(TEST, API, ...) \
@ -3117,37 +3347,6 @@ class ScopedEnable
GLenum mFeature;
};
#define ASSERT_GL_INTEGER(pname, expected) \
{ \
GLint value; \
glGetIntegerv(pname, &value); \
ASSERT_EQ(value, GLint(expected)); \
}
#define EXPECT_GL_INTEGER(pname, expected) \
{ \
GLint value; \
glGetIntegerv(pname, &value); \
EXPECT_EQ(value, GLint(expected)); \
}
#define EXPECT_PLS_INTEGER(plane, pname, expected) \
{ \
GLint value = 0xbaadc0de; \
glGetFramebufferPixelLocalStorageParameterivRobustANGLE(plane, pname, 1, nullptr, &value); \
EXPECT_EQ(value, GLint(expected)); \
value = 0xbaadc0de; \
glGetFramebufferPixelLocalStorageParameterivANGLE(plane, pname, &value); \
EXPECT_EQ(value, GLint(expected)); \
}
#define EXPECT_GL_SINGLE_ERROR(err) \
EXPECT_GL_ERROR(err); \
while (GLenum nextError = glGetError()) \
{ \
EXPECT_EQ(nextError, GLenum(GL_NO_ERROR)); \
}
#define EXPECT_GL_SINGLE_ERROR_MSG(msg) \
if (mHasDebugKHR) \
{ \
@ -3313,7 +3512,7 @@ TEST_P(PixelLocalStorageValidationTest, FramebufferTexturePixelLocalStorageANGLE
{
// When a texture object is deleted, any pixel local storage plane to which it was bound is
// automatically deinitialized.
GLFramebuffer keepalive; // Keep the underlying texture alive after deleting uts ID by
GLFramebuffer keepalive; // Keep the underlying texture alive after deleting its ID by
// binding it to a framebuffer.
glBindFramebuffer(GL_FRAMEBUFFER, keepalive);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
@ -3339,7 +3538,7 @@ TEST_P(PixelLocalStorageValidationTest, FramebufferTexturePixelLocalStorageANGLE
EXPECT_PLS_INTEGER(1, GL_PIXEL_LOCAL_TEXTURE_LAYER_ANGLE, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
{
GLFramebuffer keepalive; // Keep the underlying texture alive after deleting uts ID by
GLFramebuffer keepalive; // Keep the underlying texture alive after deleting its ID by
// binding it to a framebuffer.
glBindFramebuffer(GL_FRAMEBUFFER, keepalive);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
@ -3488,7 +3687,7 @@ TEST_P(PixelLocalStorageValidationTest, FramebufferTexturePixelLocalStorageANGLE
// When a texture object is deleted, any pixel local storage plane to which it was bound is
// automatically deinitialized.
{
GLFramebuffer keepalive; // Keep the underlying texture alive after deleting uts ID by
GLFramebuffer keepalive; // Keep the underlying texture alive after deleting its ID by
// binding it to a framebuffer.
glBindFramebuffer(GL_FRAMEBUFFER, keepalive);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0);
@ -3521,7 +3720,7 @@ TEST_P(PixelLocalStorageValidationTest, FramebufferTexturePixelLocalStorageANGLE
// When a texture object is deleted, any pixel local storage plane to which it was bound is
// automatically deinitialized.
{
GLFramebuffer keepalive; // Keep the underlying texture alive after deleting uts ID by
GLFramebuffer keepalive; // Keep the underlying texture alive after deleting its ID by
// binding it to a framebuffer.
glBindFramebuffer(GL_FRAMEBUFFER, keepalive);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex3D, 0, 0);
@ -3770,7 +3969,7 @@ TEST_P(PixelLocalStorageValidationTest, BeginPixelLocalStorageANGLE_context_stat
}
// Check that transform feedback is banned when PLS is active.
TEST_P(PixelLocalStorageValidationTest, BeginPixelLocalStorageANGLE_transform_feedback)
TEST_P(PixelLocalStorageValidationTest, PLSActive_bans_transform_feedback)
{
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
@ -3823,7 +4022,7 @@ TEST_P(PixelLocalStorageValidationTest, BeginPixelLocalStorageANGLE_transform_fe
}
// Check that EXT_blend_func_extended is banned when PLS is active.
TEST_P(PixelLocalStorageValidationTest, BeginPixelLocalStorageANGLE_blend_extended)
TEST_P(PixelLocalStorageValidationTest, PLSActive_bans_blend_func_extended)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_blend_func_extended"));
@ -3943,7 +4142,7 @@ TEST_P(PixelLocalStorageValidationTest, BeginPixelLocalStorageANGLE_blend_extend
}
// Check that KHR_blend_equation_advanced is banned when PLS is active.
TEST_P(PixelLocalStorageValidationTest, BeginPixelLocalStorageANGLE_blend_advanced)
TEST_P(PixelLocalStorageValidationTest, PLSActive_bans_blend_equation_advanced)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_KHR_blend_equation_advanced"));
@ -4870,7 +5069,6 @@ TEST_P(PixelLocalStorageValidationTest, BannedCommands)
EXPECT_BANNED_DEFAULT_MSG(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 0, 0));
EXPECT_BANNED_DEFAULT_MSG(glBlitFramebuffer(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
EXPECT_BANNED_DEFAULT_MSG(glBindFramebuffer(GL_FRAMEBUFFER, 0));
EXPECT_BANNED_DEFAULT_MSG(glDeleteFramebuffers(1, nullptr));
EXPECT_BANNED_DEFAULT_MSG(glDrawBuffers(0, nullptr));
// INVALID_OPERATION is generated by Enable(), Disable() if <cap> is not one of: CULL_FACE,
@ -5858,7 +6056,7 @@ TEST_P(PixelLocalStorageCompilerTest, FragmentTestVariables)
// Check that the "blend_support" layout qualifiers defined in KHR_blend_equation_advanced are
// illegal when PLS is declared.
TEST_P(PixelLocalStorageCompilerTest, BlendFuncExtended)
TEST_P(PixelLocalStorageCompilerTest, BlendFuncExtended_illegal_with_PLS)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_blend_func_extended"));
@ -5916,7 +6114,7 @@ TEST_P(PixelLocalStorageCompilerTest, BlendFuncExtended)
// Check that the "blend_support" layout qualifiers defined in KHR_blend_equation_advanced are
// illegal when PLS is declared.
TEST_P(PixelLocalStorageCompilerTest, BlendEquationAdvanced)
TEST_P(PixelLocalStorageCompilerTest, BlendEquationAdvanced_illegal_with_PLS)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_KHR_blend_equation_advanced"));