Created
August 5, 2019 22:04
-
-
Save clayjohn/80d9b1e52e1b9a23445504e85a8d7890 to your computer and use it in GitHub Desktop.
Uses custom viewports to generate textures before the first frame is drawn
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
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.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@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.