-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
Add custom texture create function #79288
Conversation
CC @joemarshall |
560bf26
to
1e7d110
Compare
texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, p_rd_texture); | ||
} | ||
|
||
// TODO figure out what to do with slices |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no idea if we need to populate this data...
1e7d110
to
5ae0da8
Compare
5ae0da8
to
55c6bd1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just the comments noted (also check comment about freeing the RD RID above).
Does this play nice when RenderingServer is in multi-threaded mode?
It's my understanding that when RenderingServer is in multi-threaded mode, RenderingServer commands are queued and then executed at a later point on another thread. How do you make sure that RenderingServer commands in step 1) execute before step 2)? Basically, what I'm worried about is that when you turn multi-threaded mode on, code that worked perfectly fine in single-threaded mode suddenly stops working. |
@sakrel Ultimately the RenderingServer is calling into the RenderingDevice to handle the texture. As all the RenderingServer deals with is the RID. Since the RenderingDevice is thread safe, everything should just work shouldn't it? I should say "since the RenderingDevice is thread safe, in theory" Since we have a bit of work to do to make it more thread safe and efficient. Right now we just throw mutexes at the beginning of every method we want to be thread safe |
Yes, the RenderingDevice itself should be fine. It's just that when the RenderingServer is multi-threaded, it's possible for function calls to be reordered. Take this code for example:
So, first we use With thread model
As expected, the texture color is black.
I think this happens because the engine doesn't execute |
Like this pr, made a few comments. About threading, nothing quite works right now - I've got a work in progress to threadify renderingdevice - there's a few API changes needed which is annoying - most obviously draw_list_end which doesn't take a draw list ID, along with the various message things which underlying are using a draw list but without taking an id. |
@sakrel I think that use case would always result in something unexpected, at some point we need draw a line whether users are doing something logical or are just trying to trip up the system. My only "fear" in this is that documentation may not be clear and people take an overcomplicated approach because they are looking at two completely unrelated examples and trying to merge them. The whole premise is that you will only work with So it will always be through Having a scenario where both RD and RS are writing to the texture and doing things that contradict each other, you get into trouble. For instance for your example The docs must be clear on this, you can't interchange |
@BastiaanOlij I think the issue @sakrel raises is an important one for us to consider. There is also one extra complication. While the godot/servers/rendering/rendering_server_default.h Lines 135 to 144 in b8ed596
This means that creating a texture from the RenderingServer and accessing it from the RenderingDevice will appear to work fine, while updating it will break. I think we need to explore whether we can make the If that isn't possible, then we need to have clear warnings in the docs pages for any functions in either API that may suffer from this issue |
@clayjohn don't they all work the same? The only thing But I was partly wrong in what I said, you can populate and rd texture with |
@BastiaanOlij Take a look at the code block I posted above. |
55c6bd1
to
0adb0df
Compare
Ah because of the Hmm, so if I understand correctly, the problem is that if you're not on the main thread, and you call I think we have that problem in many places, basically an object should be marked |
Currently when you call texture_get_data, there's a call to flush, which flushes all draw calls, so in theory it should get everything that is drawn on whatever thread. Although it is a total pipeline stall which means that anything using texture_get_data is a bad idea anyway; that needs deprecating and replacing with async texture fetchers some point soon, or to return some kind of future-like object or something. The problem being observed above isn't anything to do with renderingdevice though, it is to do with the renderingserver proxying stuff to the rendering thread using command queue. Which whilst it makes sense for the GL renderer, needs some consideration for vulkan as to whether it is still appropriate. My instinct on this is that: b) renderingdevice should support writing draw buffers, updating textures etc. and everything on multiple threads. c) Consistency within threads should exist, i.e. if you call something to draw into a texture on a thread, then call something to read that texture on the same thread, you should get the right answer. d) The order of GPU operations between threads should not necessarily be guaranteed - that way we only have to flush everything at the end of frame, rather than introducing dependencies between threads. e) We should really really strongly discourage combination of renderingserver and renderingdevice calls like the above, except where absolutely required during the process of transferring resources from one to the other. It is totally asking for trouble... What this basically means from a vulkan point of view is that there is a separate vulkan command list for each thread. All command lists are transferred on frame end as they are currently. As we primarily use one queue for drawing, texture uploads etc, within thread consistency should be fine. texture_get_data etc. should firstly be discouraged, but secondly should push all pending commands (or maybe just the ones pending on that thread?) including the commands to copy data back, protected by appropriate barriers, then wait on a fence, as opposed to the current situation which is that it waits until everything pending is processed and the GPU is idle. Which as I mention above is BAD. |
I'm not sure about this btw, I know this is so in Godot 3, but in Godot 4 we're using threading in a very different way. I've never been very confident about the way we're handling this in Godot 3 but I also have to admit I never investigated it thoroughly. The only reason you'd want rendering to run on another thread is that you want to start processing the next frame, but you really can't do that until after you've made a snapshot of current instance data, which is something we do while looping through our viewports. Our current approach of using threading in the rendering server itself controlled from the main thread seems a much better approach, where we efficiently handle the current frame, build the command buffers, and then sent them off to the GPU, the GPU can then do its work in parallel with us processing the next frame (which now also makes use of multi threading to paralyze a lot of the work). Having a separate rendering thread seems like little win while complicating matter and requiring some serious synching anyway. |
I've moved this out of draft and added an example project so people can start playing with it. I do not know what I did that caused the CI to fail on documentation on texture classes this PR doesn't touch. edit owh I forgot to push in my rebase and latest fixes, maybe that clears it up 🤞 |
0adb0df
to
1b8c61d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing work! I think this is nearly ready to go. I left a few comments and suggestions. The biggest missing work item is to add support for Cubemaps and Cubemap Arrays on the RS side. Other than that I think this is ready to go.
I tested it locally with your attached demo and it works great. We should get your demo uploaded to the demos repo as soon as we merge this
dc94e04
to
d4c940e
Compare
Demo has now been added to the demo projects: godotengine/godot-demo-projects#938 |
b94c15a
to
6e4c47c
Compare
6e4c47c
to
de150b3
Compare
de150b3
to
63d6e9c
Compare
Thanks! |
hi! I tried following the example and ran into this error:
|
Can hint_screen_texture or a viewport be used as a Texture2drd? Viewport texture rid is seen as invalid by rd: using Godot;
using System.Diagnostics;
public partial class minimum : SubViewport
{
private RenderingDevice rd;
public override void _Ready()
{
rd = RenderingServer.GetRenderingDevice();
Debug.Assert(rd.TextureIsValid(this.GetTexture().GetRid()));
}
} and I'm not sure how to get hint_screen_texture's Rid (assuming there is one) Thanks! |
The screen texture definitely cannot be used as a Texture2DRD. I don't think we allow using a Viewport's texture either. Texture2DRD is a texture resource, it fills a very different purpose from Viewports |
This PR adds a method to
RenderingServer
,texture_rd_create
that allows you to create a texture object using a RID relating to a texture created directly with theRenderingDevice
. This in turn allows you to use that texture object to use the texture for materials and such.For those who want to test, a little example project I wipped together:
TestCustomTextures.zip
Looks way better animated but it implements an old fashion ripple effect as a compute shader: