Render script's bad performance slows time

Hi, guys!
I made a render script that renders 3 textures to a simple shader with a mix method.
It runs smoothly on my PC and Android device, but the multilayer thing makes the HTML build have a poor performance.
I have a simple test scene with moving objects, and not only it’s heavy, but also slow, although i’m using go.animate. So it’s not frame rate independent.
Is there a way for the render script not to interfere with the game’s execution time?
Also, is there something I can do to improve my render script’s performance?
Here’s the update section:

function update(self)
	render.set_depth_mask(true)
	render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0})

	local original_width = 720
	local original_height = 1280
	local current_width = render.get_window_width()
	local current_height = render.get_window_height()
	render.set_viewport(0, 0, current_width, current_height)
	render.set_view(self.view)
	
	render.set_depth_mask(false)
	render.disable_state(render.STATE_DEPTH_TEST)
	render.disable_state(render.STATE_STENCIL_TEST)
	render.enable_state(render.STATE_BLEND)
	render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
	render.disable_state(render.STATE_CULL_FACE)

	local ratio = math.min(math.min(current_width / original_width, current_height / original_height), 1)
	local projected_width = current_width / ratio
	local projected_height = current_height / ratio
	render.set_projection(vmath.matrix4_orthographic(-(projected_width/2), projected_width/2, -(projected_height/2), projected_height/2, -1, 1))

    --Render layers and draw to texture
    render.enable_render_target(self.proj_black)
        render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0})
        render.draw(self.proj_black_pred)
    render.disable_render_target(self.proj_black)

    render.enable_render_target(self.proj_blank)
        render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0})
        render.draw(self.proj_blank_pred)
    render.disable_render_target(self.proj_blank)

    render.enable_render_target(self.fill)
        render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0})
        render.draw(self.fill_pred)
    render.disable_render_target(self.fill)

    --Pass textures to shader and draw to render buffer
    render.enable_material("mat")
        render.enable_texture(0, self.proj_black, render.BUFFER_COLOR_BIT)
        render.enable_texture(1, self.proj_blank, render.BUFFER_COLOR_BIT)
        render.enable_texture(2, self.fill, render.BUFFER_COLOR_BIT)
            render.draw(self.quad_pred)
        render.disable_texture(0, self.proj_black)
        render.disable_texture(1, self.proj_blank)
        render.disable_texture(2, self.fill)
    render.disable_material("mat")
	render.draw(self.particle_pred)
	render.draw_debug3d()
	
	render.set_view(vmath.matrix4())
	render.set_projection(vmath.matrix4_orthographic(0, render.get_window_width(), 0, render.get_window_height(), -1, 1))
	
	render.enable_state(render.STATE_STENCIL_TEST)
	render.draw(self.gui_pred)
	render.draw(self.text_pred)
	render.disable_state(render.STATE_STENCIL_TEST)
	
	render.set_depth_mask(false)
	render.draw_debug2d()
end

Update: I added some redundanct methods to the script and it happens to slow down time on the PC build as well

I just found out about the variable_dt option in the .project file. It should be enabled to measure frame time step against actual time. I feel dumb now. :sweat_smile:
But the other question remains, since my render script is still heavy on the browser and, probably, some poor mobile devices.

Can you verify with multiple browsers and mention browser versions tested?

The frame step problem was solved, as I said above.
The question that remains is: is there something I can do to improve my render script’s performance? Do you have any sugestions? Maybe a good practice that I did not apply?

Some things you can try:

  • Find out precisely where the time is spent. If you already know it’s in the mix shader, can you rewrite it? More work in vertex shader, less in fragment shader? Do you have too high precisions on your varyings? Do you do dependent texture reads? (All this shader optimization is really not specific to Defold, it’s all OpenGL and generic GPU problems. You can google a lot on it.)
  • Otherwise, find out by removing calls in the render script and see when the performance is as expected. One possibility is that the time is spent in the mix shader, another when drawing the three textures.
  • Can you avoid render.clear’ing the render targets? If you draw full screen, you don’t need to clear. Not sure how you use the render targets, but it seems like you only use the color buffer, so you probably don’t need to clear depth and stencil buffers anyway.
  • Can you try bundling the game for HTML5 and see if that changes anything, rather than running in the browser straight from the editor? (That would be a Defold issue, like running the render code in debug mode etc which could make it slower)

I really don’t think the render script is slow, more like the GPU work it creates is slow.

6 Likes
  • The extra time is spent in render script work, I tested it (also, the profiler points it out).
  • The most consuming part is the render target draw section.
  • I can’t, it’s not fullscreen, but I don’t need to clear depth and stencil buffers indeed. It had a small improvement by removing these.
  • The production HTML build is faster indeed.

Thank you very much, you helped a lot.

2 Likes

Perhaps you are using Chrome as a browser?
In our debug builds, we call glGetError and that is notoriously slow in Chrome. Other browsers perform better there with that function.

3 Likes

I have noticed that Firefox and Edge performed much faster than Chrome. Thank you for pointing that out.

1 Like

It’s a stencil masking post effect. I could use the stencil buffer, but I need alpha blending to achieve the desired effect. Alpha clipping (alphatest/cutout) would be an option, but I don’t know if it’s possible in Defold; it’s also heavy for mobile devices anyways.
The game is running 60 fps on a mid range phone and 32 fps on a cheap phone (that runs 60 fps with the default built-in render script). I guess changing the approach to achieve the same results with better performance is not worth the effort for now.
Thank you all for your help.

2 Likes