nvk/heap: Upload shaders on the CPU when we have a map
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26622>
This commit is contained in:
@@ -168,8 +168,10 @@ nvk_heap_alloc_locked(struct nvk_device *dev, struct nvk_heap *heap,
|
||||
|
||||
*addr_out = heap->bos[bo_idx].addr + bo_offset;
|
||||
if (map_out != NULL) {
|
||||
assert(heap->bos[bo_idx].map != NULL);
|
||||
*map_out = (char *)heap->bos[bo_idx].map + bo_offset;
|
||||
if (heap->bos[bo_idx].map != NULL)
|
||||
*map_out = (char *)heap->bos[bo_idx].map + bo_offset;
|
||||
else
|
||||
*map_out = NULL;
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
@@ -223,35 +225,42 @@ nvk_heap_upload(struct nvk_device *dev, struct nvk_heap *heap,
|
||||
uint64_t *addr_out)
|
||||
{
|
||||
simple_mtx_lock(&heap->mutex);
|
||||
void *map = NULL;
|
||||
VkResult result = nvk_heap_alloc_locked(dev, heap, size, alignment,
|
||||
addr_out, NULL /* map */);
|
||||
addr_out, &map);
|
||||
simple_mtx_unlock(&heap->mutex);
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
/* Now, kick off an upload of the shader data.
|
||||
*
|
||||
* This is a queued operation that the driver ensures happens before any
|
||||
* more client work via semaphores. Because this is asynchronous and heap
|
||||
* allocations are synchronous we have to be a bit careful here. The heap
|
||||
* only ever tracks the current known CPU state of everything while the
|
||||
* upload queue makes that state valid at some point in the future.
|
||||
*
|
||||
* This can be especially tricky for very fast upload/free cycles such as
|
||||
* if the client compiles a shader, throws it away without using it, and
|
||||
* then compiles another shader that ends up at the same address. What
|
||||
* makes this all correct is the fact that the everything on the upload
|
||||
* queue happens in a well-defined device-wide order. In this case the
|
||||
* first shader will get uploaded and then the second will get uploaded
|
||||
* over top of it. As long as we don't free the memory out from under the
|
||||
* upload queue, everything will end up in the correct state by the time
|
||||
* the client's shaders actually execute.
|
||||
*/
|
||||
result = nvk_upload_queue_upload(dev, &dev->upload, *addr_out, data, size);
|
||||
if (result != VK_SUCCESS) {
|
||||
nvk_heap_free(dev, heap, *addr_out, size);
|
||||
return result;
|
||||
if (map != NULL && (heap->map_flags & NOUVEAU_WS_BO_WR)) {
|
||||
/* If we have a map, copy directly with memcpy */
|
||||
memcpy(map, data, size);
|
||||
} else {
|
||||
/* Otherwise, kick off an upload with the upload queue.
|
||||
*
|
||||
* This is a queued operation that the driver ensures happens before any
|
||||
* more client work via semaphores. Because this is asynchronous and
|
||||
* heap allocations are synchronous we have to be a bit careful here.
|
||||
* The heap only ever tracks the current known CPU state of everything
|
||||
* while the upload queue makes that state valid at some point in the
|
||||
* future.
|
||||
*
|
||||
* This can be especially tricky for very fast upload/free cycles such
|
||||
* as if the client compiles a shader, throws it away without using it,
|
||||
* and then compiles another shader that ends up at the same address.
|
||||
* What makes this all correct is the fact that the everything on the
|
||||
* upload queue happens in a well-defined device-wide order. In this
|
||||
* case the first shader will get uploaded and then the second will get
|
||||
* uploaded over top of it. As long as we don't free the memory out
|
||||
* from under the upload queue, everything will end up in the correct
|
||||
* state by the time the client's shaders actually execute.
|
||||
*/
|
||||
result = nvk_upload_queue_upload(dev, &dev->upload, *addr_out, data, size);
|
||||
if (result != VK_SUCCESS) {
|
||||
nvk_heap_free(dev, heap, *addr_out, size);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
Reference in New Issue
Block a user