Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Fix texture leak in TexturePoolHolder #5141

Merged
merged 2 commits into from
May 26, 2016
Merged

Conversation

brunoabinader
Copy link
Member

Fixes a misused operator bool() plus usage of an undefined pointer in {GL,TexturePool}Holder code.

👀 @kkaefer @jfirebaugh

Fixes #5136.

}
}
ids.fill(0);
std::for_each(ids.begin(), ids.end(), [&](GLuint& id) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the switch from range-based for to for_each?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, I can achieve the same thing capturing a non-const reference in a range-based for.

@brunoabinader brunoabinader force-pushed the brunoabinader-texture-leak branch from dc597ef to 0b7277b Compare May 25, 2016 21:45
@jfirebaugh
Copy link
Contributor

The intended invariant is that if {GLObjectStore,TexturePoolHolder} is owning a resource, its objectStore is not null. It shouldn't be necessary to check both the resource and objectStore.

I think the actual bug lies in the implementations of the move constructors and operator=s. They need to transfer objectStore along with the resource.

@jfirebaugh
Copy link
Contributor

jfirebaugh commented May 25, 2016

Here's how I would do if implementing this pattern from scratch:

struct ProgramDeleter {
    GLObjectStore* store = nullptr;
    void operator()(GLuint id) {
        assert(store);
        store->abandonedPrograms.push_back(id);
    }
};
UniqueProgram GLObjectStore::createProgram() {
    return std::make_unique_resource(MBGL_CHECK_ERROR(glCreateProgram()), ProgramDeleter(this));
}

@brunoabinader brunoabinader force-pushed the brunoabinader-texture-leak branch from 0b7277b to b9351dd Compare May 26, 2016 15:11
@brunoabinader
Copy link
Member Author

@jfirebaugh my previous implementation used std::unique_ptr but as suggested by @kkaefer in 02b3771#commitcomment-16093745 we ditched that to save on lesser redirections. I'm 👍 on revisiting this if we all agree on the implementation pros/cons.

ids.fill(0);
if (!created()) return;
for (GLuint& id : ids) {
if (id == 0) return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return needs to revert back to a conditional.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, meant continue there.

@brunoabinader brunoabinader force-pushed the brunoabinader-texture-leak branch from b9351dd to 78a26b7 Compare May 26, 2016 16:14
@@ -38,10 +38,10 @@ class GLHolder : private util::noncopyable {
public:
GLHolder() {}

GLHolder(GLHolder&& o) noexcept : id(o.id) { o.id = 0; }
GLHolder& operator=(GLHolder&& o) noexcept { id = o.id; o.id = 0; return *this; }
GLHolder(GLHolder&& o) noexcept : id(o.id), objectStore(o.objectStore) { id = 0; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you change o.id = 0 to id = 0? Isn't the former correct?

Fixes an issue where a moved {GL,TexturePool}Holder would use an invalid
pointer when accessing 'objectStore'.

Fixes #5136.
Prevents confusing usage of GL holder objects.
@brunoabinader brunoabinader force-pushed the brunoabinader-texture-leak branch from 78a26b7 to c111250 Compare May 26, 2016 16:37
@brunoabinader brunoabinader merged commit c111250 into master May 26, 2016
@brunoabinader brunoabinader deleted the brunoabinader-texture-leak branch May 26, 2016 17:02
@brunoabinader
Copy link
Member Author

We'll proceed with @jfirebaugh's suggestion from #5141 (comment) in a separate PR.

@1ec5 1ec5 added the performance Speed, stability, CPU usage, memory usage, or power usage label May 27, 2016
1ec5 added a commit that referenced this pull request May 27, 2016
brunoabinader added a commit that referenced this pull request May 31, 2016
Source: https://github.com/okdshin/unique_resource

These replace the complexity of manually handling moveable-RAII objects
with a type specific for that purpose.

As suggested in #5141 (comment).
brunoabinader added a commit that referenced this pull request May 31, 2016
Source: https://github.com/okdshin/unique_resource

These replace the complexity of manually handling moveable-RAII objects
with a type specific for that purpose.

As suggested in #5141 (comment).
brunoabinader added a commit that referenced this pull request May 31, 2016
Source: https://github.com/okdshin/unique_resource

These replace the complexity of manually handling moveable-RAII objects
with a type specific for that purpose.

As suggested in #5141 (comment).
brunoabinader added a commit that referenced this pull request Jun 1, 2016
Source: https://github.com/okdshin/unique_resource

These replace the complexity of manually handling moveable-RAII objects
with a type specific for that purpose.

As suggested in #5141 (comment).
1ec5 added a commit that referenced this pull request Jun 3, 2016
Added entries to the iOS SDK changelog for #5124, #2444, #5141, #5164. Removed entries for changes made since the last release; they go in the GitHub prerelease notes but not here in this document.
@haberbyte
Copy link

haberbyte commented Jan 12, 2020

Here's how I would do if implementing this pattern from scratch:

* Pull in a polyfill for C++XX `unique_resource` (https://github.com/okdshin/unique_resource)

* `using UniqueProgram = std::unique_resource<GLuint, ProgramDeleter>;`
struct ProgramDeleter {
    GLObjectStore* store = nullptr;
    void operator()(GLuint id) {
        assert(store);
        store->abandonedPrograms.push_back(id);
    }
};
UniqueProgram GLObjectStore::createProgram() {
    return std::make_unique_resource(MBGL_CHECK_ERROR(glCreateProgram()), ProgramDeleter(this));
}

Hey @jfirebaugh, i came across this recently and was wondering if you would still do it this way.
I am wondering if the same thing could be accomplished by simply using std::unique_ptr, either wrapping each type in its own class or even by passing a deleter to the unique_ptr, e.g.

struct TextureDeleter {
    Context* context;
    TextureDeleter(Context* c) : context(c) {}
    void operator()(TextureID*) const;
};

Why is the unique_resource.hpp needed? Would love to understand this, i am probably missing something!

@kkaefer
Copy link
Member

kkaefer commented Jan 13, 2020

@haberbyte unique_resource is similar, but not identical to unique_ptr: It manages resources that are represented as integers (e.g. as returned by OpenGL API calls) instead of pointers. You could create a wrapper class for every resource type that stores the integer handle, but that means that you'd have to dereference a pointer every time you want to access the resource (i.e. you essentially store a pointer to an integer). In reality though, the performance benefit of storing the integer directly is probably pretty small.

@haberbyte
Copy link

Ah, that makes sense, thank you! Unfortunate, that it is not even part of C++17 🤷‍♂

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
performance Speed, stability, CPU usage, memory usage, or power usage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Raster/TexturePoolHolder leaks textures
5 participants