{"action":"created","issue":{"url":"https://api.github.com/repos/gpuweb/gpuweb/issues/38","repository_url":"https://api.github.com/repos/gpuweb/gpuweb","labels_url":"https://api.github.com/repos/gpuweb/gpuweb/issues/38/labels{/name}","comments_url":"https://api.github.com/repos/gpuweb/gpuweb/issues/38/comments","events_url":"https://api.github.com/repos/gpuweb/gpuweb/issues/38/events","html_url":"https://github.com/gpuweb/gpuweb/issues/38","id":270772105,"node_id":"MDU6SXNzdWUyNzA3NzIxMDU=","number":38,"title":"Resource Round-Robining","user":{"login":"litherum","id":918903,"node_id":"MDQ6VXNlcjkxODkwMw==","avatar_url":"https://avatars0.githubusercontent.com/u/918903?v=4","gravatar_id":"","url":"https://api.github.com/users/litherum","html_url":"https://github.com/litherum","followers_url":"https://api.github.com/users/litherum/followers","following_url":"https://api.github.com/users/litherum/following{/other_user}","gists_url":"https://api.github.com/users/litherum/gists{/gist_id}","starred_url":"https://api.github.com/users/litherum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/litherum/subscriptions","organizations_url":"https://api.github.com/users/litherum/orgs","repos_url":"https://api.github.com/users/litherum/repos","events_url":"https://api.github.com/users/litherum/events{/privacy}","received_events_url":"https://api.github.com/users/litherum/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":11,"created_at":"2017-11-02T19:06:29Z","updated_at":"2018-11-14T18:07:15Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"## Background\r\n\r\nOn Nov. 1, there was consensus in the group about scheduling resource uploads & downloads at a particular point in the device's queue so that the CPU and GPU wouldn't be accessing the same resource at the same time. This is the best (only?) solution for resources which live across multiple frames.\r\n\r\nLet's consider the other side of the issue: when information on the CPU is only necessary on the GPU for a single frame. One example of this is the Model View Projection matrices, which are consistent throughout a single frame, but will change from frame to frame.\r\n\r\nThere are a few possible models for these kinds of resources:\r\n1. **Resource Churn** The application allocates and destroys a new resource each frame. Obviously (I think we can all agree) we don't want this.\r\n2. **Scheduled Uploads** The application uses a single resource, and schedules an upload at the start of each frame.\r\n3. **Explicit Recycling** Allocate `n` resources up front, and recycle them each frame. We can piggyback off the design of the swapchain here, because the swapchain includes `n` buffers, and it guarantees that, when you're recording commands to draw into a particular swapchain buffer, that buffer is not being accessed by the GPU. If we make an array of our own resources which parallels the `n` buffers in the swapchain, the parallel item in our own resource array is unused by the GPU at recording time, and therefore is free for the CPU to populate.\r\n4. **Implicit recycling** Just like above, a collection of resources will be created, but this array is owned by the implementation. All resources exist inside the implementation in a \"free pool\" or an \"in-use pool.\" When an application asks for a resource, one is pulled from the free pool, or if the pool doesn't contain anything compatible, a new one is created. The application then attaches this resource to their recording commands, and notifies the implementation when they're done recording with this resource. At this point, however, the resource isn't returned to the free pool; instead, the implementation only returns the resource to the free pool when the GPU is finished with the resource. This way, any resource granted to the application is free to be immediately written into by the CPU. (Indeed, the resource acquisition function may even accept an argument to specify the resource's initial contents.) In this option, the same number of resources will be created and recycled as in option 3, but the application doesn't own the array.\r\n\r\n## Recommendation\r\nOption 4 is most compatible with a Web API, and should be the model for WebGPU. This is for a few reasons.\r\n\r\nOption 2 is a good start, but we can do better. In this model, the CPU-side memcpy() will occur on the GPU's timeline, taking time away from the GPU's execution. The other models allow for issuing the memcpy() during command recording, before ownership of the resource has been given to the GPU.\r\n\r\nOption 3 improves upon 2, but has the drawback of making application logic dependent on the number of buffers in the swapchain, which is another potential source of non-portability. In particular, both Metal and Vulkan (and maybe Direct3D, I don't know) don't let the application specify exactly how many buffers the swapchain contains. Vulkan allows the application to request a certain number, but the actual implementation may return a [different](https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/html/vkspec.html#vkGetSwapchainImagesKHR) number than requested. Metal never tells you how many buffers are in the swapchain, but just gives you the \"[next one](https://developer.apple.com/documentation/quartzcore/cametallayer/1478172-nextdrawable).\" We'd like to avoid web authors hardcoding a constant number of resources in their application because that happened to be how many buffers their local machine was using.\r\n\r\nOption 4 has all the benefits of option 3, but has additional benefits:\r\n1. **Portability** Application logic is insensitive to the number of buffers in the platform's swapchain.\r\n2. **Performance** Letting the browser automatically recycle resources means that the browser can improve the performance of poorly-written applications. Recycling should be automatic; developers shouldn't have to opt-in to good performance.\r\n3. **Fingerprinting** The nature of the platform swapchains would provide more entropy for fingerprinting."},"comment":{"url":"https://api.github.com/repos/gpuweb/gpuweb/issues/comments/438760770","html_url":"https://github.com/gpuweb/gpuweb/issues/38#issuecomment-438760770","issue_url":"https://api.github.com/repos/gpuweb/gpuweb/issues/38","id":438760770,"node_id":"MDEyOklzc3VlQ29tbWVudDQzODc2MDc3MA==","user":{"login":"magcius","id":40890,"node_id":"MDQ6VXNlcjQwODkw","avatar_url":"https://avatars1.githubusercontent.com/u/40890?v=4","gravatar_id":"","url":"https://api.github.com/users/magcius","html_url":"https://github.com/magcius","followers_url":"https://api.github.com/users/magcius/followers","following_url":"https://api.github.com/users/magcius/following{/other_user}","gists_url":"https://api.github.com/users/magcius/gists{/gist_id}","starred_url":"https://api.github.com/users/magcius/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/magcius/subscriptions","organizations_url":"https://api.github.com/users/magcius/orgs","repos_url":"https://api.github.com/users/magcius/repos","events_url":"https://api.github.com/users/magcius/events{/privacy}","received_events_url":"https://api.github.com/users/magcius/received_events","type":"User","site_admin":false},"created_at":"2018-11-14T18:07:15Z","updated_at":"2018-11-14T18:07:15Z","author_association":"NONE","body":"Plenty of resources will change between frames besides modelviewprojection matrices (anything animating, e.g. texture or bone SRTs, color animations, blend shapes, visibility). Push constants aren't a general solution.\r\n\r\nI'm using option #2 in my prototype right now, but I would be OK with implementing #3 in my code. Adding more functionality to the WebGPU layer to buffer updates is bad. e.g. Often times, when building velocity buffers, you want to have a read-only copy of the animation or mvp matrices from last frame anyway, so users are going to be buffering them. Having it hidden behind implementation details is just going to have apps waste more memory."}}
{"actor":{"display_login":"magcius"}}