-
-
Save clayjohn/80d9b1e52e1b9a23445504e85a8d7890 to your computer and use it in GitHub Desktop.
extends Node2D | |
var myViewport | |
var myCanvas | |
func _ready(): | |
## Stop main viewport from drawing when we force draw | |
## should loop through all other viewports as well | |
VisualServer.viewport_set_active(get_viewport().get_viewport_rid(), false) | |
# initialize Viewport, needs canvas | |
myViewport = VisualServer.viewport_create() | |
myCanvas = VisualServer.canvas_create() | |
VisualServer.viewport_attach_canvas(myViewport, myCanvas) | |
VisualServer.viewport_set_size(myViewport, 64, 64) | |
## "active" instructs it to be drawn | |
VisualServer.viewport_set_active(myViewport, true) | |
## create CanvasItem and add to canvas just as in servers tutorial | |
var ci_rid = VisualServer.canvas_item_create() | |
VisualServer.viewport_set_canvas_transform(myViewport, myCanvas, Transform()) | |
VisualServer.canvas_item_set_parent(ci_rid, myCanvas) | |
var sprite = load("res://icon.png") | |
VisualServer.canvas_item_add_texture_rect(ci_rid, Rect2(Vector2(0, 0), sprite.get_size()), sprite) | |
## draw it once, this should be bundled into a function | |
VisualServer.viewport_set_update_mode(myViewport, VisualServer.VIEWPORT_UPDATE_ONCE) | |
VisualServer.viewport_set_vflip(myViewport, true) | |
VisualServer.force_draw(false) | |
var image = VisualServer.texture_get_data(VisualServer.viewport_get_texture(myViewport)) | |
var texture = ImageTexture.new() | |
texture.create_from_image(image) | |
$Sprite2.texture = texture | |
#exact same as above | |
VisualServer.viewport_set_update_mode(myViewport, VisualServer.VIEWPORT_UPDATE_ONCE) | |
VisualServer.viewport_set_vflip(myViewport, false) | |
VisualServer.force_draw(false) | |
var image2 = VisualServer.texture_get_data(VisualServer.viewport_get_texture(myViewport)) | |
var texture2 = ImageTexture.new() | |
texture2.create_from_image(image2) | |
$Sprite3.texture = texture2 | |
#prints 0 as no frames have actually drawn | |
print(Engine.get_frames_drawn()) | |
#reset the main viewport so everything actually draws to screen | |
VisualServer.viewport_set_active(get_viewport().get_viewport_rid(), true) |
@Flarkk force_draw
does not guarantee that all viewports have been drawn. It just submits the draw commands to the GPU immediately instead of at the end of the frame.
Unfortunately, I don't think force_sync()
is going to help you much :(
https://github.com/godotengine/godot/blob/5fe89e8ccda8f46c811e6f3fd601ca09ae138e17/servers/visual/visual_server_raster.cpp#L130-L131
Again, I didn't write this code assuming it would be run from another thread, so I can't do much troubleshooting for you. You can try running the code with different thread models to see if that helps. I understand that Godot, by default, tries to run all VisualServer commands on the main thread so you could be getting a bit out of sync, maybe running in a different thread model will help. Otherwise, you are just going to have to figure out a way to wait until the draw commands have finished executing before requesting the data from the GPU.
Ok got it, many thanks.
For now I’ll stick in waiting a bit the draw command complete (as the work is done on a thread, it doesn’t freeze the entire game).
I’ll rewrite the whole thing with compute shaders when Godot 4.0 is out, as it should allow to completely separate textures rendering from the draw process.
@clayjohn thanks for the hint. But something still sounds wrong from my understanding: If force_draw guarantees that all viewports have been drawn afterwards, when called on the main thread (whatever the underlying mechanism : semaphore, condition_variable, etc ... to sync with the visual server thread), what’s different to call from another thread ?
I’ve also spotted the force_sync method, but the doc is really light on it. I wonder whether it can help or not.
Note that I’m developing in c++ NativeScript, so I’m a bit reluctant to use godot style signals or callbacks (preferring good old c++ style :-)