• Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Question - Code Surface outside draw event

NazGhuL

NazTaiL
Hi. Someone has this error running my asset on marketplace:

**********************************.
Entering main loop.
**********************************.
Texture #3 1024,2048
ERROR!!! :: Trying to set a surface target that does not exist.

GMS2 is running on OSX.
I suspect that the problem comes from places outside the draw event where I can get code like

Code:
//create event
surf0 = surface_create(100, 100);
scr_update_surface_menu(surf0);//in there: draw_set, draw and reset_target

//step event
if(click_on_menu)
{
scr_remove_item();
scr_update_surface_menu(surf0);//in there: draw_set, draw and reset_target
}

//draw event
if(surface_exists(surf0)
{
draw_surface(surf0, x, y);
}
It's hard to debug because on my side, everything works fine. (Windows 10)
Is it that bad to 'sketch' a surface outside the draw event.

The manual states:
you should only create surfaces in the draw event. If you create a surface in the Create Event of an instance, you could potentially get the same index as theapplication_surface. This then can cause lots of problems and confusion as you think your using your own surface, but you are actually using the current render target. You should also always try to limit drawing to a surface in the draw event too, since due to the optimised way in which GameMaker Studio 2 draws to the screen, it is recommended that you keep all draw functions within the draw event - this includes clearing a surface when it is first created, etc... Drawing to a surface outside of the draw event is possible and may even be necessary for some effects, but it's not how it should be done.
So you do??
Code:
//create event
mysurf = -1; ??? noone? 0?
keyboard_update = 0;

//step event
if(keyboard_check_pressed(vk_space))
{
keyboard_update = 1;
}

//draw event
if(!surface_exists(mysurf)
{
mysurf = surface_create(100, 100);
}
else
{
     if(keyboard_update == 1)
     {
     scr_update_surface_menu(mysurf);//in there: draw_set, draw and reset_target
     keyboard_update = 0;
     }

draw_surface(mysurf, x, y);
}
 

Mert

Member
//step event
if(click_on_menu)
{
scr_remove_item();
scr_update_surface_menu(surf0);//in there: draw_set, draw and reset_target
}
All Drawing operations including surfaces must be done in DRAW EVENTS.
Move the code to Draw Event and all will be solved.
 

Hyomoto

Member
The stuff in the manual falls into 'best practices' territory. It's meant to give an answer to someone asking, "Well, then what should I do?" When it comes to surfaces it is possible to create and maintain them at any time, the issue is that depending on what's going on with your device, it is possible for them to be flushed from VRAM. This is why it is suggested that you always check if they exist before using, and create them during the draw event. In my experience you can safely create surfaces during the step event and they should still exist during the draw event. However, that's the creating of surfaces, and all draw code must always be in a draw event or nothing will happen. The reason that error is popping up is because you are trying to set a surface during the step event that no longer exists. There's a number of issues with that code, but what it comes down to is your problem is you aren't checking if the surface exists before setting it, and you are trying to draw during the step event. A better approach looks something like this:
Code:
//create event
surf0 = -1;
update = false;

//step event
if(click_on_menu)
{
  scr_remove_item();
  update = true;
}

//draw event
if( !surface_exists(surf0) ) { 
  surf0 = surface_create( 100, 100 );
  update = true;
}
if update
{
  scr_update_surface_menu(surf0);//in there: draw_set, draw and reset_target
  update = false;
}
draw_surface(surf0, x, y);
What I've done here is separate out all the ideas of your code into their specific blocks. During the create_event we create the variables we need, one to hold our surface, the other to let us know it needs to be updated. During the step event you handle your inputs, and flag the surface to be updated. Lastly, during the draw step we check if our surface exists, if it doesn't then we create one and flag it for updating. Next we check if the surface needs to be updated, and if it does, update it. Lastly we draw the surface.

This fixes all issues: we move all draw code to the draw event, we always check if a surface exists before using it, and we get rid of redundant calls which makes the code more easily maintained.
 

NazGhuL

NazTaiL
it is possible for them to be flushed from VRAM
That's exactly what happens in my situation.

Since my very first year using GM(8.1), I create surfaces in the create event, manipulate them in the step event and draw them in the draw event. That was what I learned.
It's the first time I face a problem with that. I will change this habit. It's not complicated, just a lot of work for certain project.
 
Top