Comments (15)
Addressed internally. This one took nearly a whole week to complete ..
Will post the latest version early next week.
from anvil.
Good point. Unique pointers it shall be then!
from anvil.
This is one of the (many) topics that would earn their well deserved place in a documentation, had we had one.
The reason Anvil ultimately ended up with the reversed Instance<-PhysicalDevice<-Device dependency organization was because of the following reasons:
1a. If the app destroys a Vulkan Instance, all Vulkan handles created from that instance become obsolete, and so do their wrapper instances.
1b. It wouldn't take a tremendous effort to modify Anvil so that it would release all living Vulkan object handles while handling app's request to destroy a Vulkan Instance handle. However, that would imply all wrapper instances which are still alive at this point effectively become useless. Can we guarantee all app developers will understand the implications? Don't forget Anvil is about prototyping Vulkan apps after all.
2. An orthogonal aspect is that in Vulkan, an Instance owns all Physical Devices. A Device instance created from a Physical Device, but with the parent Instance handle already destroyed, means bad stuff coming to your app very shortly. Since Anvil is about prototyping, not assuming the developers care about all this dependency stuff, the lowest-hanging fruit was to use the design we currently have.
3. Finally, it proved much more easier to go with the current design, than the way you're suggesting (which I agree would have been much cleaner but perhaps a tad more bitter on the required longer-term maintenance effort). I hadn't spent much time on fleshing it out, but fixing all the cyclic references turned out to be a non-trivial task.
If you feel strong about the current model being misleading, let me know. If the reasons are convincing enough, I'm happy to reconsider my view.
from anvil.
Based on your points above though, it actually sounds like you're arguing exactly for why my suggestion is actually more inline with what you want!
Examples may help:
Usage With Current Implementation
std::weak_ptr<Anvil::SGPUDevice> createAnvilDevice()
{
std::shared_ptr<Anvil::Instance> pInstance = Anvil::Instance::create(...);
std::weak_ptr<Anvil::PhysicalDevice> pPhysicalDevice = Anvil::PhysicalDevice::create(pInstance, ...);
std::weak_ptr<Anvil::SGPUDevice> pDevice = Anvil::SGPUDevice::create(pPhysicalDevice, ...);
return pDevice;
}
int main(int argc, char** argv)
{
std::weak_ptr<Anvil::SGPUDevice> pDevice = createAnvilDevice();
pDevice->something(); // This is invalid!!! The device was already destroyed because I let the
// shared_ptr to the Instance expire at the end of the function, and it cleaned up everything
// it owned
return 0;
}
Now let's look at the same idea using a model where Device
has shared ownership of PhysicalDevice
, and that has shared ownership of Instance
Usage With Purposed Change
std::shared_ptr<Anvil::SGPUDevice> createAnvilDevice()
{
std::shared_ptr<Anvil::Instance> pInstance = Anvil::Instance::create(...);
std::shared_ptr<Anvil::PhysicalDevice> pPhysicalDevice = Anvil::PhysicalDevice::create(pInstance, ...);
std::shared_ptr<Anvil::SGPUDevice> pDevice = Anvil::SGPUDevice::create(pPhysicalDevice, ...);
return pDevice;
}
int main(int argc, char** argv)
{
std::shared_ptr<Anvil::SGPUDevice> pDevice = createAnvilDevice();
pDevice->something(); // This is good - We have a strong pointer to the Device keeping the PhysicalDevice alive,
// the PhysicalDevice has a strong pointer to the Instance keeping that alive
// When we return from this function, the shared_ptr will hit '0', which will free the VkDevice and lower the
// ref count on the PhysicalDevice, which will then hit '0'. That will free the VkPhysicalDevice and lower the
// ref count on the Instance, which will finally free the VkInstance.
// All of this happens automatically without me, the user, having to do anything.
return 0;
}
from anvil.
I think your current implementation exists to allow the user to destroy the Anvil::Instance
and have Anvil automatically clean up everything downstream of it, but I have to ask - Is that really something that you actually want? Based on your answers above, it sounds like 'no'.
With the behavior the way it is now - allowing the user to delete Anvil::Instance
directly and having it clean up everything - then that means that now the user potentially has a ton of weak_ptr<Anvil::xxx>
lying all over their code pointing to destroyed objects. Is that really what the user would want or expect?
I tend to think that you probably don't want to ever allow the user to directly delete an Anvil::Instance
. It should probably only be deleted automatically when it's not needed anymore, which is when everything that references it is destroyed.
Going back to my example above to also illustrate:
std::shared_ptr<Anvil::Instance> pInstance = Anvil::Instance::create(...);
std::weak_ptr<Anvil::PhysicalDevice> pPhysicalDevice = Anvil::PhysicalDevice::create(pInstance, ...);
std::weak_ptr<Anvil::SGPUDevice> pDevice = Anvil::SGPUDevice::create(pPhysicalDevice, ...);
pInstance.reset();
// User now has to know that pPhysicalDevice and pDevice are both invalid pointers now
from anvil.
Also, think in terms of multiples - If you have 10 Device
on a single PhysicalDevice
, don't you want the PhysicalDevice
to have a refcount of 10
? And then if the user frees one of the devices, you don't want PhysicalDevice
to be destroyed - you just want its refcount to drop to 9
.
from anvil.
Not sure if anything should be changed at this point due to backward compatibility, but if you asked me for my preferred model, I'd say no implicit ownership rules at all (apart from the relationships as in the original Vulkan API, e.g a physical device already exists in an instance, you only enumerate it).
I would be perfectly happy with simply adding RAII to Vulkan objects (think unique_ptr). Then the user can model whatever ownership rules that they need with usual language features. If an instance goes out of scope before a device, then oops you have a bug, deal with it.
Full disclosure: my view may be skewed by how Vulkan CTS framework handles this problem.
from anvil.
@MaciejJesionowskiAMD I would say that pushing ownership management to the end-user is a much lower abstraction then what Anvil seems to aim to provide. Yes, it's efficient in-that you're not using any CPU cycles for reference counting things that may only ever have a 1-to-1 mapping, but I would say that if a user is using Anvil then they've decided they're okay for trading off raw performance for a little bit of luxury. Users who care about nothing-but-performance are always free to just use the Vulkan API directly.
I'm not sure at this point that "backward compatibility" is an argument that should really be made about Anvil - I don't think it's being used very much in the wild right now, and I think that it's understood that it's kind of "in-development" software at this point, and that breaking changes may be made to it.
from anvil.
After thinking about the lifetime model a bit more, I realize one of the things that would easily improve it in Anvil is just to think about what you would need to do to remove all the Destroy()
methods from Instance
, PhysicalDevice
, and Device
.
Basically, you'd have to do these things, which are all good ideas(TM):
- Remove all the code that does the whole "recursive destroy" from
Instance
all the way toDevice
. - Move the logic to "deregister" the object to the dtor, which is good because RAII
- Change the register/deregister calls to store
weak_ptr<T>
instead of the currentshared_ptr<T>
. If you don't do this, the dtor will never be called becauseDevice
andPhysicalDevice
would keep each other alive by mutualshared_ptr
- Have the
create
functions return ashared_ptr
to the user. If you don't do that, the object will delete itself immediately, since it will no longer be kept alive by its parent (which is actually how it should work)
from anvil.
Anvil is going to make a move to raw pointers in a coming update. Apps can still use automated memory management by wrapping the returned ptrs in unique/shared ptrs, but I agree it was a bad design move to rely on automated ptrs on the library level.
from anvil.
@DominikWitczakAMD But then why wouldn't you at-least return a std::unique_ptr<T>
? Bjarne Stroustrup would have a fit if he knew you were returning raw pointers from an API in 2018 😛
from anvil.
FWIW don't even take my word for it:
C++ Core Guildelines - I.11: Never transfer ownership by a raw pointer (T*) or reference (T&)
from anvil.
I'm a bit on a fence when it comes to exposing unique pointers. They are a good idea BUT if they were to be used to wrap all objects instantiated by the library, we'd be introducing an implicit requirement of apps using exactly the same implementation of STL as Anvil. This is not a problem in general case, but in situations where someone needs to use the lib built using a different compiler, things can get quickly out of control.
Of course, it's still OK for Anvil to use STL internally and I'm not paranoid enough to start reimplementing all containers and algorithms used by the library just to avoid the dependency ;-) It's really the client<->library interfaces that are my biggest worry here.
from anvil.
In general you can’t design a c++ API around that use case anyway - c++ has no defined ABI, so many implementation details can and do change between compiler versions. If a user were to do that, unique_ptr would be the least of their troubles.
Hell - if they even link to a different runtime lib than you do, they’re screwed. Msvcrt.lib and msvcrtxx.dll are mutually incompatible.
So already your choices are to provide a different lib for msvc 2013, 2015, 2017 and static/dll versions of each, or make them compile it themselves.
from anvil.
The latest version addresses this issue. Thanks for reporting.
from anvil.
Related Issues (20)
- Why can't the user recreate swapchains?
- Suggestion: Add CMake option to use SDK location for glslang library HOT 2
- BaseDevice::is_extension_enabled does not work with instance extensions?
- VK_ERROR_EXTENSION_NOT_PRESENT error if device group extension is not supported by GPU HOT 2
- Not building on ubuntu 18.10 HOT 3
- Unhandled VK_ERROR_OUT_OF_DATE_KHR when Anvil-based program with window is minimized with Nvidia drivers HOT 3
- Queue::submit with blocking-flag set does not guarantee command buffer completion? HOT 1
- Assertion failure when using specialization constants HOT 1
- Assertion failure in BaseDevice::init with a Radeon R9 Fury HOT 1
- GCC 8+ does not compile successfully. (-Werror=class-memaccess) HOT 5
- Crash when submitting queue on Nvidia GPUs HOT 2
- Why is HLSL support turned off if ANVIL_LINK_WITH_GLSLANG flag is set? HOT 1
- record_bind_pipeline(..., PipelineID) is a O(logn) function, n count of pipelines. A faster alternative might should be added.
- QueryPool::get_query_pool_results calculates query size incorrectly
- Concerning wstring-to-string conversion in WIN32 implementation HOT 1
- Unusable with NVidia HOT 1
- get_image_format_properties uses stencil usage flags of 0, which is not allowed
- Error compiling with GCC 9 on Linux HOT 1
- Error Compiling with VS CMake HOT 2
- Is there any future roadmap? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from anvil.