Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend RenderingDevice.buffer_get_data() to allow reading data back from the GPU into PackedByteArrays that already exist #8862

Open
BrofessorDoucette opened this issue Jan 11, 2024 · 1 comment

Comments

@BrofessorDoucette
Copy link

BrofessorDoucette commented Jan 11, 2024

Describe the project you are working on

I am working on a voxel terrain editing plugin which will comprehensively use compute shaders to generate noise.

Describe the problem or limitation you are having in your project

Using RenderingDevice.BufferGetData() to readback from a compute shader forces a new PackedByteArray to be created instead of optionally allowing an existing PackedByteArray to be passed in to copy the data to. This forces an unnecessary heap allocation every time a compute buffer is read from.

Compute shaders are mainly good for processing large amount of data at once. The way godot is currently set up limits the uses of compute shaders, because a large amount of performance is lost by forcing a memcpy to a newly allocated PackedByteArray.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

This feature would add another method to the RenderingDevice class to optionally allow an existing PackedByteArray to be utilized for reading data back from a buffer.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Something along the lines of the following would be added to the RenderingDevice class:

Vector<uint8_t> RenderingDevice::buffer_get_data_into_existing(RID p_buffer, uint32_t p_offset, uint32_t p_size, Vector<uint8_t> &p_output) {
	_THREAD_SAFE_METHOD_

	Buffer *buffer = _get_buffer_from_owner(p_buffer);
	if (!buffer) {
		ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving.");
	}

	// Size of buffer to retrieve.
	if (!p_size) {
		p_size = buffer->size;
	} else {
		ERR_FAIL_COND_V_MSG(p_size + p_offset > buffer->size, Vector<uint8_t>(),
				"Size is larger than the buffer.");
	}

	uint32_t p_output_size = (uint32_t) p_output.size();
	if(p_size > p_output_size) {
		ERR_FAIL_COND_V_MSG(p_size > p_output_size, Vector<uint8_t>(),
				"Size is larger than the output.");
	}


	RDD::BufferID tmp_buffer = driver->buffer_create(buffer->size, RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU);
	ERR_FAIL_COND_V(!tmp_buffer, Vector<uint8_t>());

	RDD::BufferCopyRegion region;
	region.src_offset = p_offset;
	region.size = p_size;

	draw_graph.add_buffer_get_data(buffer->driver_id, buffer->draw_tracker, tmp_buffer, region);

	// Flush everything so memory can be safely mapped.
	_flush(true);

	uint8_t *buffer_mem = driver->buffer_map(tmp_buffer);
	ERR_FAIL_COND_V(!buffer_mem, Vector<uint8_t>());

	{
		uint8_t *w = p_output.ptrw();
		memcpy(w, buffer_mem, p_size);
	}

	driver->buffer_unmap(tmp_buffer);

	driver->buffer_free(tmp_buffer);

	return p_output;
}

Instead of creating a new Vector<uint8_t>, resizing, and then copying the data to that; one should be able to pass in an existing PackedByteArray.

If this enhancement will not be used often, can it be worked around with a few lines of script?

I believe this enhancement will be used extensively by anyone who uses compute shaders in godot.

Is there a reason why this should be core and not an add-on in the asset library?

Yes, this is a feature that other engines provide. Unity has a similar method, albeit it has bugs.
AsyncGPUReadback.RequestIntoNativeArray

@BrofessorDoucette BrofessorDoucette changed the title BufferGetData should be extended to allow reading data back from the GPU into PackedByteArrays that already exist instead of copying. BufferGetData should be extended to allow reading data back from the GPU into PackedByteArrays that already exist instead of forcing a new allocation. Jan 11, 2024
@Calinou Calinou changed the title BufferGetData should be extended to allow reading data back from the GPU into PackedByteArrays that already exist instead of forcing a new allocation. Extend RenderingDevice.buffer_get_data() to allow reading data back from the GPU into PackedByteArrays that already exist Jan 11, 2024
@Calinou
Copy link
Member

Calinou commented Jan 11, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants