• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

3D Problem with MRT, surfaces crashing the game when setting twice

Status
Not open for further replies.

BlueHarrier

Member
Hi again, community.

Today I'm having issues with surfaces and Multi Render Targets, in this case, the game just crashes when trying to set the second target slot twice (reseting the target in between, obviously), and I don't know why. For some reason (and it's not the first time this happens to me), the game doesn't crash when using the debugger, but the application surface becomes completely white.

This is the fragment where it crashes (Draw End):
Code:
var
mat=matrix_build(x, y, z, 0, 0, 0, 2, 2, 2);
matrix_set(matrix_world, mat)
gpu_set_cullmode(cull_clockwise)

shader_set(sh3d_lightsource)

var
rel_uv=shader_get_uniform(sh3d_lightsource, "u_RelTexCoords"),
z_vals=shader_get_uniform(sh3d_lightsource, "u_ZVals"),
ul_color=shader_get_uniform(sh3d_lightsource, "u_LightColor"),
brightness=shader_get_uniform(sh3d_lightsource, "u_LightBrightness");

shader_set_uniform_f_array(rel_uv, sprite_get_uvs(tex_lamp, 0))
shader_set_uniform_f(z_vals, camera.z_near, camera.z_far)
shader_set_uniform_f(ul_color, color_get_red(l_color)/255, color_get_green(l_color)/255, color_get_blue(l_color)/255)
shader_set_uniform_f(brightness, 0.5)

surface_set_target_ext(0, application_surface)
surface_set_target_ext(1, global.light_surf)

camera_reload()

model_draw("lamp.dat", tex_lamp, 0)

surface_reset_target()

shader_reset()

gpu_set_cullmode(cull_noculling)

matrix_set(matrix_world, matrix_build_identity())
And the error given is:
Code:
############################################################################################
ERROR in
action number 1
of Create Event
for object obj_light:

Cannot free this surface - call surface_reset_target before calling surface_free
############################################################################################
This problem only occurs when there are TWO or more instances of this object in the room, when there's only one, there is no problem. Any ideas of what could it be?
 
Last edited:

Ido-f

Member
Try adding another surface_reset_target in there.
According to this blog post, you need a matching surface_reset_target call for each surface_set_target call, rather than only one at the end.
 

BlueHarrier

Member
Try adding another surface_reset_target in there.
According to this blog post, you need a matching surface_reset_target call for each surface_set_target call, rather than only one at the end.
It makes a stack error, I'm only setting one stack of surfaces.

Code:
___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Draw Event
for object obj_light:

Unbalanced surface stack. you are trying to pop a surface that has not been set.
 at gml_Object_obj_light_Draw_0 (line 29) - surface_reset_target()
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_light_Draw_0 (line 29)
If I had set the targets twice, it'd work, but it's not the case...
 

Binsk

Member
@Ido-f For future reference, since he's using surface_set_target_ext it only needs to be called once. It's just how MRTs work.

Is that the full error on the first post? I don't see a line number or anything. Is it possible a function you are calling, such as camera_reload or model_draw, is doing anything with the surfaces in their scripts?

By itself I'm not seeing anything wrong with that create event code.
 

BlueHarrier

Member
@Ido-f For future reference, since he's using surface_set_target_ext it only needs to be called once. It's just how MRTs work.

Is that the full error on the first post? I don't see a line number or anything. Is it possible a function you are calling, such as camera_reload or model_draw, is doing anything with the surfaces in their scripts?

By itself I'm not seeing anything wrong with that create event code.
Good news, I fixed it, I know how, but it doesn't seem logic to me.

By removing the first surface_set_target_ext, which sets up the application surface, the error changes, now, it returns a surface stack error (the same as my last reply), and removing that line solves the error. It seems that Game Maker only pushes surfaces that are set on the first slot, by reseting the target, it will reset slots 1, 2 and 3 to -1, and the slot 0 will become the application surface. What doesn't make sense is why does it crashes when everything was correct, because with other objects that doesn't requiere 2 surfaces I need to reset the target.
 

Binsk

Member
Can you humor me and try something? I'm wondering if the application surface hasn't been created yet since you are calling this in the create event instead of the draw event.

Try putting all this code in alarm 0 or something similar instead of the create event and set the alarm to 1 in the create event so that it has an offset of a step.

EDIT: Reading through the manual it states that the application_surface is created on the first draw event call in each room. This may be the issue, then.
 

BlueHarrier

Member
Can you humor me and try something? I'm wondering if the application surface hasn't been created yet since you are calling this in the create event instead of the draw event.

Try putting all this code in alarm 0 or something similar instead of the create event and set the alarm to 1 in the create event so that it has an offset of a step.

EDIT: Reading through the manual it states that the application_surface is created on the first draw event call in each room. This may be the issue, then.
Yeah, I forgot about mentioning that, even if GM error says that the event failing is the Create Event, I'm operating in the Draw End Event, and that's the code I'm showing. The create event hasn't got any surface function as they are controled by managers. I've seen errors like this one before, and they are shown as the create event, even if they're not.

Sorry, I should have said it before.
 
Last edited:

BlueHarrier

Member
Mind showing us the create code just in case?
Roger roger

Create Event:
Code:
///@desc Setup

var
format;

vertex_format_begin()
vertex_format_add_position_3d()
vertex_format_add_texcoord()
vertex_format_add_color()
vertex_format_add_normal()
format=vertex_format_end()

model_call_ext("lamp.dat", format)      //This function calls the model manager to avoid loading a model twice (uses saved model buffer files)
sprite_call(sprite_index)                //This one fetches a sprite to the graphic memory

z=-21
l_att=[0.5, 0.0005, 0.00000001]
l_color=make_color_rgb(255, 100, 100)
 

Binsk

Member
I'm at a loss. I honestly can't think of anything other than throwing out some highly unlikely possibilities. My remaining thoughts are:

1) Are you sure that your game is using the application_surface? Did you disable it at some point?
2) If you switch the application_surface out for your own surface does the error go away?
3) Do surfaces, application or otherwise, ever get recreated / modified in any way by any other objects?
4) On the same idea as (3), have you checked creation order? Are you sure it isn't just happenstance that it is 2+ objects? If placed in the room via editor, what happens if you remove them all and add them in again so the order changes?

Those are all the remaining things I can think of. Not much but it's what I've got. Maybe someone else has some ideas. -.-'
 

BlueHarrier

Member
I'm at a loss. I honestly can't think of anything other than throwing out some highly unlikely possibilities. My remaining thoughts are:

1) Are you sure that your game is using the application_surface? Did you disable it at some point?
2) If you switch the application_surface out for your own surface does the error go away?
3) Do surfaces, application or otherwise, ever get recreated / modified in any way by any other objects?
4) On the same idea as (3), have you checked creation order? Are you sure it isn't just happenstance that it is 2+ objects? If placed in the room via editor, what happens if you remove them all and add them in again so the order changes?

Those are all the remaining things I can think of. Not much but it's what I've got. Maybe someone else has some ideas. -.-'
As I said early, I fixed the problem, and I was only looking for an explanation of why did that happen, and I have a theory:

Basically, that "light_surf" is a bloom post-proccessed surface, that is created and secured on a Pre-Draw event in an object that acts as a graphic manager (it's literally called like that). That object makes the maintenance of all surface used in the game to work, from cleaning them each frame to making sure that they exist. It also clears the application surface and draws it manually on the screen buffer (Draw GUI, I have disabled the automatic drawing of the surface because of the post-proccess effects that are added to final render).

The error came when I used a double render target for drawing a lamp with an HLSL shader using 2 output targets: one for the common render, and the other one for the bloom surface. When setting the two targets, drawing and then reseting the target once work perfectly well, but when the code is executed two or more times, it returns an error that doesn't even make sense (because the error we got is one that should be given when you use surface_free(surf) with a non existing surface), happening the same with the event and the line.

THEORY:
I think this is just an engine error that can be solved manually. For some reason, surface_reset_target() does not reset the surfaces stored in another target index than 0, so the way I reseted the surface is manually, by doing surface_set_target_ext(1, -1). -1 is the void value, and the engine takes it perfectly well, with no memory increase and no performance impact, so everything seems correct.

These are the two summarized codes, the one that failed, and the other that worked:
Code:
/* CRASH */
[...]
surface_set_target_ext(0, surf1)
surface_set_target_ext(1, surf2)

//Draw stuff

surface_reset_target()

/* WORKS */
[...]
//Here we assume that the first target is already set, if not, I don't know how to fix this, in my case it is.
surface_set_target_ext(1, surf2)

//Draw stuff

surface_set_target_ext(1, -1)
P.S.: Should I edit the thread and say this and even report this to the technical support?
 
Status
Not open for further replies.
Top