aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShahbaz Youssefi <syoussefi@chromium.org>2024-05-10 00:15:31 -0400
committerAngle LUCI CQ <angle-scoped@luci-project-accounts.iam.gserviceaccount.com>2024-05-14 03:59:10 +0000
commita1665d2fc335ef1481c76d4066cb2e22bab83ba7 (patch)
tree47d614a76bfd09b316f0570bf9fa5e7508bc4979
parentdf2e7bd7c99e27868947f887355ad11979f6d492 (diff)
downloadangle-a1665d2fc335ef1481c76d4066cb2e22bab83ba7.tar.gz
Reland "Document thread-unsafe iterator access to resource maps"
This is a reland of commit d1bb6ed8399dd12e79484f30f9e9ded95c25625a The crash was due to another issue (disabling EGL validation in Chrome) Original change's description: > Document thread-unsafe iterator access to resource maps > > By using a proxy type, everywhere resource maps are iterated are clearly > marked as not being thread safe. In most cases, only destruction and > capture/replay iterate over these maps, which means thread safety is not > an issue (or is externally enforced). > > The only case where iterators are used in the presence of other contexts > is with ANGLE_request_extension, which is changed to explicitly require > the application to ensure thread safety. In practice, the user is > Chrome which already guarantees this. > > Bug: angleproject:8667 > Change-Id: I7af13c6433b6955d9c36f9088b3aa4c065e1cfc1 > Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5526428 > Reviewed-by: Charlie Lao <cclao@google.com> > Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> > Reviewed-by: Geoff Lang <geofflang@chromium.org> Bug: angleproject:8667 Change-Id: Id539cabac01df5f242150f6684222577003eef3f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5531278 Reviewed-by: Charlie Lao <cclao@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org>
-rw-r--r--extensions/ANGLE_request_extension.txt4
-rw-r--r--src/libANGLE/Context.cpp14
-rw-r--r--src/libANGLE/ResourceManager.cpp60
-rw-r--r--src/libANGLE/ResourceManager.h6
-rw-r--r--src/libANGLE/ResourceMap.h42
-rw-r--r--src/libANGLE/ResourceMap_unittest.cpp10
-rw-r--r--src/libANGLE/capture/FrameCapture.cpp33
-rw-r--r--src/libANGLE/capture/serialize.cpp20
8 files changed, 124 insertions, 65 deletions
diff --git a/extensions/ANGLE_request_extension.txt b/extensions/ANGLE_request_extension.txt
index 88d3422e3b..56317e6d6a 100644
--- a/extensions/ANGLE_request_extension.txt
+++ b/extensions/ANGLE_request_extension.txt
@@ -85,7 +85,9 @@ Additions to the OpenGL ES 3.0 Specification
enable or disable the requestable OpenGL ES extension named <name>. If the
requested extension was not requestable or disablable, INVALID_OPERATION is
generated. Not all requestable extensions can be disabled. There is
- currently no query for disablable extensions.
+ currently no query for disablable extensions. This operation is not thread
+ safe, and the application is responsible for ensuring no other context in
+ the share group is accessed by another thread during this operation.
New State
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 1b23bd94a8..5eda734ca6 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -850,7 +850,7 @@ egl::Error Context::onDestroy(const egl::Display *display)
mDefaultFramebuffer->onDestroy(this);
mDefaultFramebuffer.reset();
- for (auto fence : mFenceNVMap)
+ for (auto fence : UnsafeResourceMapIter(mFenceNVMap))
{
if (fence.second)
{
@@ -860,7 +860,7 @@ egl::Error Context::onDestroy(const egl::Display *display)
}
mFenceNVMap.clear();
- for (auto query : mQueryMap)
+ for (auto query : UnsafeResourceMapIter(mQueryMap))
{
if (query.second != nullptr)
{
@@ -869,7 +869,7 @@ egl::Error Context::onDestroy(const egl::Display *display)
}
mQueryMap.clear();
- for (auto vertexArray : mVertexArrayMap)
+ for (auto vertexArray : UnsafeResourceMapIter(mVertexArrayMap))
{
if (vertexArray.second)
{
@@ -878,7 +878,7 @@ egl::Error Context::onDestroy(const egl::Display *display)
}
mVertexArrayMap.clear();
- for (auto transformFeedback : mTransformFeedbackMap)
+ for (auto transformFeedback : UnsafeResourceMapIter(mTransformFeedbackMap))
{
if (transformFeedback.second != nullptr)
{
@@ -3618,7 +3618,8 @@ void Context::beginTransformFeedback(PrimitiveMode primitiveMode)
bool Context::hasActiveTransformFeedback(ShaderProgramID program) const
{
- for (auto pair : mTransformFeedbackMap)
+ // Note: transform feedback objects are private to context and so the map doesn't need locking
+ for (auto pair : UnsafeResourceMapIter(mTransformFeedbackMap))
{
if (pair.second != nullptr && pair.second->hasBoundProgram(program))
{
@@ -4498,7 +4499,8 @@ void Context::updateCaps()
(mState.isWebGL() || mState.hasRobustAccess()));
// Cache this in the VertexArrays. They need to check it in state change notifications.
- for (auto vaoIter : mVertexArrayMap)
+ // Note: vertex array objects are private to context and so the map doesn't need locking
+ for (auto vaoIter : UnsafeResourceMapIter(mVertexArrayMap))
{
VertexArray *vao = vaoIter.second;
vao->setBufferAccessValidationEnabled(mBufferAccessValidationEnabled);
diff --git a/src/libANGLE/ResourceManager.cpp b/src/libANGLE/ResourceManager.cpp
index 8c63342b12..bf0c93d59e 100644
--- a/src/libANGLE/ResourceManager.cpp
+++ b/src/libANGLE/ResourceManager.cpp
@@ -61,14 +61,16 @@ void ResourceManagerBase::release(const Context *context)
template <typename ResourceType, typename ImplT, typename IDType>
TypedResourceManager<ResourceType, ImplT, IDType>::~TypedResourceManager()
{
- ASSERT(mObjectMap.empty());
+ ASSERT(UnsafeResourceMapIter(mObjectMap).empty());
}
template <typename ResourceType, typename ImplT, typename IDType>
void TypedResourceManager<ResourceType, ImplT, IDType>::reset(const Context *context)
{
+ // Note: this function is called when the last context in the share group is destroyed. Thus
+ // there are no thread safety concerns.
this->mHandleAllocator.reset();
- for (const auto &resource : mObjectMap)
+ for (const auto &resource : UnsafeResourceMapIter(mObjectMap))
{
if (resource.second)
{
@@ -138,21 +140,30 @@ ShaderProgramManager::ShaderProgramManager() {}
ShaderProgramManager::~ShaderProgramManager()
{
- ASSERT(mPrograms.empty());
- ASSERT(mShaders.empty());
+ ASSERT(UnsafeResourceMapIter(mPrograms).empty());
+ ASSERT(UnsafeResourceMapIter(mShaders).empty());
}
void ShaderProgramManager::reset(const Context *context)
{
- while (!mPrograms.empty())
+ // Note: this function is called when the last context in the share group is destroyed. Thus
+ // there are no thread safety concerns.
+ mHandleAllocator.reset();
+ for (const auto &program : UnsafeResourceMapIter(mPrograms))
{
- deleteProgram(context, {mPrograms.begin()->first});
+ if (program.second)
+ {
+ program.second->onDestroy(context);
+ }
}
- mPrograms.clear();
- while (!mShaders.empty())
+ for (const auto &shader : UnsafeResourceMapIter(mShaders))
{
- deleteShader(context, {mShaders.begin()->first});
+ if (shader.second)
+ {
+ shader.second->onDestroy(context);
+ }
}
+ mPrograms.clear();
mShaders.clear();
}
@@ -238,7 +249,9 @@ TextureID TextureManager::createTexture()
void TextureManager::signalAllTexturesDirty() const
{
- for (const auto &texture : mObjectMap)
+ // Note: this function is called with glRequestExtensionANGLE and glDisableExtensionANGLE. The
+ // GL_ANGLE_request_extension explicitly requires the application to ensure thread safety.
+ for (const auto &texture : UnsafeResourceMapIter(mObjectMap))
{
if (texture.second)
{
@@ -384,7 +397,8 @@ Framebuffer *FramebufferManager::getDefaultFramebuffer() const
void FramebufferManager::invalidateFramebufferCompletenessCache() const
{
- for (const auto &framebuffer : mObjectMap)
+ // Note: framebuffer objects are private to context and so the map doesn't need locking
+ for (const auto &framebuffer : UnsafeResourceMapIter(mObjectMap))
{
if (framebuffer.second)
{
@@ -428,14 +442,20 @@ MemoryObjectManager::MemoryObjectManager() {}
MemoryObjectManager::~MemoryObjectManager()
{
- ASSERT(mMemoryObjects.empty());
+ ASSERT(UnsafeResourceMapIter(mMemoryObjects).empty());
}
void MemoryObjectManager::reset(const Context *context)
{
- while (!mMemoryObjects.empty())
+ // Note: this function is called when the last context in the share group is destroyed. Thus
+ // there are no thread safety concerns.
+ mHandleAllocator.reset();
+ for (const auto &memoryObject : UnsafeResourceMapIter(mMemoryObjects))
{
- deleteMemoryObject(context, {mMemoryObjects.begin()->first});
+ if (memoryObject.second)
+ {
+ memoryObject.second->release(context);
+ }
}
mMemoryObjects.clear();
}
@@ -477,14 +497,20 @@ SemaphoreManager::SemaphoreManager() {}
SemaphoreManager::~SemaphoreManager()
{
- ASSERT(mSemaphores.empty());
+ ASSERT(UnsafeResourceMapIter(mSemaphores).empty());
}
void SemaphoreManager::reset(const Context *context)
{
- while (!mSemaphores.empty())
+ // Note: this function is called when the last context in the share group is destroyed. Thus
+ // there are no thread safety concerns.
+ mHandleAllocator.reset();
+ for (const auto &semaphore : UnsafeResourceMapIter(mSemaphores))
{
- deleteSemaphore(context, {mSemaphores.begin()->first});
+ if (semaphore.second)
+ {
+ semaphore.second->release(context);
+ }
}
mSemaphores.clear();
}
diff --git a/src/libANGLE/ResourceManager.h b/src/libANGLE/ResourceManager.h
index 710a88dd44..372b76b4b5 100644
--- a/src/libANGLE/ResourceManager.h
+++ b/src/libANGLE/ResourceManager.h
@@ -75,11 +75,7 @@ class TypedResourceManager : public ResourceManagerBase
return GetIDValue(handle) == 0 || mObjectMap.contains(handle);
}
- typename ResourceMap<ResourceType, IDType>::Iterator begin() const
- {
- return mObjectMap.begin();
- }
- typename ResourceMap<ResourceType, IDType>::Iterator end() const { return mObjectMap.end(); }
+ const ResourceMap<ResourceType, IDType> &getResourcesForCapture() const { return mObjectMap; }
protected:
~TypedResourceManager() override;
diff --git a/src/libANGLE/ResourceMap.h b/src/libANGLE/ResourceMap.h
index b454e261a2..92d6b6251d 100644
--- a/src/libANGLE/ResourceMap.h
+++ b/src/libANGLE/ResourceMap.h
@@ -73,6 +73,11 @@ class ResourceMap final : angle::NonCopyable
bool mSkipNulls;
};
+ private:
+ friend class Iterator;
+ template <typename SameResourceType, typename SameIDType>
+ friend class UnsafeResourceMapIter;
+
// null values represent reserved handles.
Iterator begin() const;
Iterator end() const;
@@ -80,12 +85,7 @@ class ResourceMap final : angle::NonCopyable
Iterator beginWithNull() const;
Iterator endWithNull() const;
- // Not a constant-time operation, should only be used for verification.
- bool empty() const;
-
- private:
- friend class Iterator;
-
+ // Used by iterators and related functions only (due to lack of thread safety).
GLuint nextResource(size_t flatIndex, bool skipNulls) const;
// constexpr methods cannot contain reinterpret_cast, so we need a static method.
@@ -108,6 +108,30 @@ class ResourceMap final : angle::NonCopyable
HashMap mHashedResources;
};
+// A helper to retrieve the resource map iterators while being explicit that this is not thread
+// safe. Usage of iterators are limited to clean up on destruction and capture/replay, neither of
+// which can race with other threads in their access to the resource map.
+template <typename ResourceType, typename IDType>
+class UnsafeResourceMapIter
+{
+ public:
+ using ResMap = ResourceMap<ResourceType, IDType>;
+
+ UnsafeResourceMapIter(const ResMap &resourceMap) : mResourceMap(resourceMap) {}
+
+ typename ResMap::Iterator begin() const { return mResourceMap.begin(); }
+ typename ResMap::Iterator end() const { return mResourceMap.end(); }
+
+ typename ResMap::Iterator beginWithNull() const { return mResourceMap.beginWithNull(); }
+ typename ResMap::Iterator endWithNull() const { return mResourceMap.endWithNull(); }
+
+ // Not a constant-time operation, should only be used for verification.
+ bool empty() const;
+
+ private:
+ const ResMap &mResourceMap;
+};
+
template <typename ResourceType, typename IDType>
ResourceMap<ResourceType, IDType>::ResourceMap()
: mFlatResourcesSize(kInitialFlatResourcesSize),
@@ -119,7 +143,7 @@ ResourceMap<ResourceType, IDType>::ResourceMap()
template <typename ResourceType, typename IDType>
ResourceMap<ResourceType, IDType>::~ResourceMap()
{
- ASSERT(empty());
+ ASSERT(UnsafeResourceMapIter(*this).empty());
delete[] mFlatResources;
}
@@ -222,9 +246,9 @@ ResourceMap<ResourceType, IDType>::endWithNull() const
}
template <typename ResourceType, typename IDType>
-bool ResourceMap<ResourceType, IDType>::empty() const
+bool UnsafeResourceMapIter<ResourceType, IDType>::empty() const
{
- return (begin() == end());
+ return begin() == end();
}
template <typename ResourceType, typename IDType>
diff --git a/src/libANGLE/ResourceMap_unittest.cpp b/src/libANGLE/ResourceMap_unittest.cpp
index 056dde518a..01d2d706ba 100644
--- a/src/libANGLE/ResourceMap_unittest.cpp
+++ b/src/libANGLE/ResourceMap_unittest.cpp
@@ -33,7 +33,7 @@ TEST(ResourceMapTest, AssignAndErase)
ASSERT_EQ(&objects[index], found);
}
- ASSERT_TRUE(resourceMap.empty());
+ ASSERT_TRUE(UnsafeResourceMapIter(resourceMap).empty());
}
// Tests assigning slots in the map and then using clear() to free it.
@@ -48,7 +48,7 @@ TEST(ResourceMapTest, AssignAndClear)
}
resourceMap.clear();
- ASSERT_TRUE(resourceMap.empty());
+ ASSERT_TRUE(UnsafeResourceMapIter(resourceMap).empty());
}
// Tests growing a map more than double the size.
@@ -80,7 +80,7 @@ TEST(ResourceMapTest, BigGrowth)
ASSERT_EQ(object, *found);
}
- ASSERT_TRUE(resourceMap.empty());
+ ASSERT_TRUE(UnsafeResourceMapIter(resourceMap).empty());
}
// Tests querying unassigned or erased values.
@@ -106,7 +106,7 @@ TEST(ResourceMapTest, QueryUnassigned)
resourceMap.assign(object, &object);
}
- ASSERT_FALSE(resourceMap.empty());
+ ASSERT_FALSE(UnsafeResourceMapIter(resourceMap).empty());
for (size_t &object : objects)
{
@@ -126,7 +126,7 @@ TEST(ResourceMapTest, QueryUnassigned)
ASSERT_EQ(object, *found);
}
- ASSERT_TRUE(resourceMap.empty());
+ ASSERT_TRUE(UnsafeResourceMapIter(resourceMap).empty());
ASSERT_FALSE(resourceMap.contains(0));
ASSERT_EQ(nullptr, resourceMap.query(0));
diff --git a/src/libANGLE/capture/FrameCapture.cpp b/src/libANGLE/capture/FrameCapture.cpp
index 22daf186f7..3d9680aa94 100644
--- a/src/libANGLE/capture/FrameCapture.cpp
+++ b/src/libANGLE/capture/FrameCapture.cpp
@@ -4125,7 +4125,7 @@ void CaptureShareGroupMidExecutionSetup(
// Capture Buffer data.
const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
- for (const auto &bufferIter : buffers)
+ for (const auto &bufferIter : gl::UnsafeResourceMapIter(buffers.getResourcesForCapture()))
{
gl::BufferID id = {bufferIter.first};
gl::Buffer *buffer = bufferIter.second;
@@ -4267,7 +4267,7 @@ void CaptureShareGroupMidExecutionSetup(
// Capture Texture setup and data.
const gl::TextureManager &textures = apiState.getTextureManagerForCapture();
- for (const auto &textureIter : textures)
+ for (const auto &textureIter : gl::UnsafeResourceMapIter(textures.getResourcesForCapture()))
{
gl::TextureID id = {textureIter.first};
gl::Texture *texture = textureIter.second;
@@ -4593,7 +4593,8 @@ void CaptureShareGroupMidExecutionSetup(
const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
FramebufferCaptureFuncs framebufferFuncs(context->isGLES1());
- for (const auto &renderbufIter : renderbuffers)
+ for (const auto &renderbufIter :
+ gl::UnsafeResourceMapIter(renderbuffers.getResourcesForCapture()))
{
gl::RenderbufferID id = {renderbufIter.first};
const gl::Renderbuffer *renderbuffer = renderbufIter.second;
@@ -4657,7 +4658,7 @@ void CaptureShareGroupMidExecutionSetup(
// Capture Program binary state.
gl::ShaderProgramID tempShaderStartID = {resourceTracker->getMaxShaderPrograms()};
std::map<gl::ShaderProgramID, std::vector<gl::ShaderProgramID>> deferredAttachCalls;
- for (const auto &programIter : programs)
+ for (const auto &programIter : gl::UnsafeResourceMapIter(programs))
{
gl::ShaderProgramID id = {programIter.first};
gl::Program *program = programIter.second;
@@ -4738,7 +4739,7 @@ void CaptureShareGroupMidExecutionSetup(
}
// Handle shaders.
- for (const auto &shaderIter : shaders)
+ for (const auto &shaderIter : gl::UnsafeResourceMapIter(shaders))
{
gl::ShaderProgramID id = {shaderIter.first};
gl::Shader *shader = shaderIter.second;
@@ -4827,7 +4828,7 @@ void CaptureShareGroupMidExecutionSetup(
// Capture Sampler Objects
const gl::SamplerManager &samplers = apiState.getSamplerManagerForCapture();
- for (const auto &samplerIter : samplers)
+ for (const auto &samplerIter : gl::UnsafeResourceMapIter(samplers.getResourcesForCapture()))
{
gl::SamplerID samplerID = {samplerIter.first};
@@ -4892,7 +4893,7 @@ void CaptureShareGroupMidExecutionSetup(
// Capture Sync Objects
const gl::SyncManager &syncs = apiState.getSyncManagerForCapture();
- for (const auto &syncIter : syncs)
+ for (const auto &syncIter : gl::UnsafeResourceMapIter(syncs.getResourcesForCapture()))
{
gl::SyncID syncID = {syncIter.first};
const gl::Sync *sync = syncIter.second;
@@ -4967,7 +4968,7 @@ void CaptureMidExecutionSetup(const gl::Context *context,
const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
gl::VertexArrayID boundVertexArrayID = {0};
- for (const auto &vertexArrayIter : vertexArrayMap)
+ for (const auto &vertexArrayIter : gl::UnsafeResourceMapIter(vertexArrayMap))
{
TrackedResource &trackedVertexArrays =
resourceTracker->getTrackedResource(context->id(), ResourceIDType::VertexArray);
@@ -5145,7 +5146,8 @@ void CaptureMidExecutionSetup(const gl::Context *context,
const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
gl::RenderbufferID currentRenderbuffer = {0};
- for (const auto &renderbufIter : renderbuffers)
+ for (const auto &renderbufIter :
+ gl::UnsafeResourceMapIter(renderbuffers.getResourcesForCapture()))
{
currentRenderbuffer = renderbufIter.second->id();
}
@@ -5162,7 +5164,8 @@ void CaptureMidExecutionSetup(const gl::Context *context,
gl::FramebufferID currentDrawFramebuffer = {0};
gl::FramebufferID currentReadFramebuffer = {0};
- for (const auto &framebufferIter : framebuffers)
+ for (const auto &framebufferIter :
+ gl::UnsafeResourceMapIter(framebuffers.getResourcesForCapture()))
{
gl::FramebufferID id = {framebufferIter.first};
const gl::Framebuffer *framebuffer = framebufferIter.second;
@@ -5297,7 +5300,8 @@ void CaptureMidExecutionSetup(const gl::Context *context,
const gl::ProgramPipelineManager *programPipelineManager =
apiState.getProgramPipelineManagerForCapture();
- for (const auto &ppoIterator : *programPipelineManager)
+ for (const auto &ppoIterator :
+ gl::UnsafeResourceMapIter(programPipelineManager->getResourcesForCapture()))
{
gl::ProgramPipeline *pipeline = ppoIterator.second;
gl::ProgramPipelineID id = {ppoIterator.first};
@@ -5380,8 +5384,9 @@ void CaptureMidExecutionSetup(const gl::Context *context,
// Create existing queries. Note that queries may be genned and not yet started. In that
// case the queries will exist in the query map as nullptr entries.
const gl::QueryMap &queryMap = context->getQueriesForCapture();
- for (gl::QueryMap::Iterator queryIter = queryMap.beginWithNull();
- queryIter != queryMap.endWithNull(); ++queryIter)
+ for (gl::QueryMap::Iterator queryIter = gl::UnsafeResourceMapIter(queryMap).beginWithNull(),
+ endIter = gl::UnsafeResourceMapIter(queryMap).endWithNull();
+ queryIter != endIter; ++queryIter)
{
ASSERT(queryIter->first);
gl::QueryID queryID = {queryIter->first};
@@ -5407,7 +5412,7 @@ void CaptureMidExecutionSetup(const gl::Context *context,
// Transform Feedback
const gl::TransformFeedbackMap &xfbMap = context->getTransformFeedbacksForCapture();
- for (const auto &xfbIter : xfbMap)
+ for (const auto &xfbIter : gl::UnsafeResourceMapIter(xfbMap))
{
gl::TransformFeedbackID xfbID = {xfbIter.first};
diff --git a/src/libANGLE/capture/serialize.cpp b/src/libANGLE/capture/serialize.cpp
index c1138a7f34..61655020a6 100644
--- a/src/libANGLE/capture/serialize.cpp
+++ b/src/libANGLE/capture/serialize.cpp
@@ -1404,7 +1404,8 @@ Result SerializeContextToString(const gl::Context *context, std::string *stringO
const gl::FramebufferManager &framebufferManager =
context->getState().getFramebufferManagerForCapture();
GroupScope framebufferGroup(&json, "FramebufferManager");
- for (const auto &framebuffer : framebufferManager)
+ for (const auto &framebuffer :
+ gl::UnsafeResourceMapIter(framebufferManager.getResourcesForCapture()))
{
gl::Framebuffer *framebufferPtr = framebuffer.second;
ANGLE_TRY(SerializeFramebuffer(context, &json, &scratchBuffer, framebufferPtr));
@@ -1413,7 +1414,7 @@ Result SerializeContextToString(const gl::Context *context, std::string *stringO
{
const gl::BufferManager &bufferManager = context->getState().getBufferManagerForCapture();
GroupScope framebufferGroup(&json, "BufferManager");
- for (const auto &buffer : bufferManager)
+ for (const auto &buffer : gl::UnsafeResourceMapIter(bufferManager.getResourcesForCapture()))
{
gl::Buffer *bufferPtr = buffer.second;
ANGLE_TRY(SerializeBuffer(context, &json, &scratchBuffer, bufferPtr));
@@ -1423,7 +1424,8 @@ Result SerializeContextToString(const gl::Context *context, std::string *stringO
const gl::SamplerManager &samplerManager =
context->getState().getSamplerManagerForCapture();
GroupScope samplerGroup(&json, "SamplerManager");
- for (const auto &sampler : samplerManager)
+ for (const auto &sampler :
+ gl::UnsafeResourceMapIter(samplerManager.getResourcesForCapture()))
{
gl::Sampler *samplerPtr = sampler.second;
SerializeSampler(&json, samplerPtr);
@@ -1433,7 +1435,8 @@ Result SerializeContextToString(const gl::Context *context, std::string *stringO
const gl::RenderbufferManager &renderbufferManager =
context->getState().getRenderbufferManagerForCapture();
GroupScope renderbufferGroup(&json, "RenderbufferManager");
- for (const auto &renderbuffer : renderbufferManager)
+ for (const auto &renderbuffer :
+ gl::UnsafeResourceMapIter(renderbufferManager.getResourcesForCapture()))
{
gl::Renderbuffer *renderbufferPtr = renderbuffer.second;
ANGLE_TRY(SerializeRenderbuffer(context, &json, &scratchBuffer, renderbufferPtr));
@@ -1445,7 +1448,7 @@ Result SerializeContextToString(const gl::Context *context, std::string *stringO
const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaderManager =
shaderProgramManager.getShadersForCapture();
GroupScope shaderGroup(&json, "ShaderManager");
- for (const auto &shader : shaderManager)
+ for (const auto &shader : gl::UnsafeResourceMapIter(shaderManager))
{
GLuint id = shader.first;
gl::Shader *shaderPtr = shader.second;
@@ -1456,7 +1459,7 @@ Result SerializeContextToString(const gl::Context *context, std::string *stringO
const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programManager =
shaderProgramManager.getProgramsForCaptureAndPerf();
GroupScope shaderGroup(&json, "ProgramManager");
- for (const auto &program : programManager)
+ for (const auto &program : gl::UnsafeResourceMapIter(programManager))
{
GLuint id = program.first;
gl::Program *programPtr = program.second;
@@ -1467,7 +1470,8 @@ Result SerializeContextToString(const gl::Context *context, std::string *stringO
const gl::TextureManager &textureManager =
context->getState().getTextureManagerForCapture();
GroupScope shaderGroup(&json, "TextureManager");
- for (const auto &texture : textureManager)
+ for (const auto &texture :
+ gl::UnsafeResourceMapIter(textureManager.getResourcesForCapture()))
{
gl::Texture *texturePtr = texture.second;
ANGLE_TRY(SerializeTexture(context, &json, &scratchBuffer, texturePtr));
@@ -1476,7 +1480,7 @@ Result SerializeContextToString(const gl::Context *context, std::string *stringO
{
const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
GroupScope shaderGroup(&json, "VertexArrayMap");
- for (const auto &vertexArray : vertexArrayMap)
+ for (const auto &vertexArray : gl::UnsafeResourceMapIter(vertexArrayMap))
{
gl::VertexArray *vertexArrayPtr = vertexArray.second;
SerializeVertexArray(&json, vertexArrayPtr);