Kha icon indicating copy to clipboard operation
Kha copied to clipboard

Improve 'end before you begin' throws

Open luboslenco opened this issue 6 years ago • 9 comments
trafficstars

The "end before you begin" throw is great - but if there is any other exception in between g.begin()/g.end() calls, the console will get bombed with "end before you begin" throws every frame, obscuring the original exception.

https://github.com/Kode/Kha/blob/master/Sources/kha/graphics4/Graphics2.hx#L1073

luboslenco avatar Mar 12 '19 09:03 luboslenco

Also maybe move that code between some #if kha_debug or something? Or would that not be worth it?

Disar avatar Mar 16 '19 19:03 Disar

It's an if for every begin/end call, i don't think it's worth it to wrap that tbh.

sh-dave avatar Mar 18 '19 07:03 sh-dave

I know this is a pretty old thread but.. Continuing along Disar's thread of thought, I think something like the following would be pretty nice to have (assuming here that kha debug compile is compatible with the debug haxe compilation flag).

index 7390d666..388792be 100644
--- a/Sources/kha/graphics4/Graphics2.hx
+++ b/Sources/kha/graphics4/Graphics2.hx
@@ -1024,13 +1024,17 @@ class Graphics2 extends kha.graphics2.Graphics {
 	}
 
 	override public function begin(clear: Bool = true, clearColor: Color = null): Void {
-		if (current == null) {
-			current = this;
-		}
-		else {
+		#if debug
+		if (current != this) {
 			throw "End before you begin";
 		}
-
+		#end
+		
+		if (current != null) {
+			current.flush();
+			current.g.end();
+		}
+		current = this;
 		g.begin();
 		if (clear) this.clear(clearColor);
 		setProjection();
@@ -1048,15 +1052,15 @@ class Graphics2 extends kha.graphics2.Graphics {
 	}
 
 	public override function end(): Void {
-		flush();
-		g.end();
-
-		if (current == this) {
-			current = null;
-		}
-		else {
+		#if debug
+		if (current != this) {
 			throw "Begin before you end";
 		}
+		#end
+		
+		current.flush();
+		current.g.end();
+		current = null;
 	}
 
 	private function drawVideoInternal(video: kha.Video, x: Float, y: Float, width: Float, height: Float): Void {

We could even have this bit:

if (current != null) {
	current.flush();
	current.g.end();
}

inside an #else block for just a little bit less overhead on debug builds.

lunabunn avatar Nov 24 '19 17:11 lunabunn

You don't need "I know it's an old thread" excuses for open issues, absolutely feel free to help fixing all of them 😅

RobDangerous avatar Nov 24 '19 17:11 RobDangerous

With Macro it is possible to ensure begin and end are always called.

khage have this thing (with more abstraction too) : https://github.com/wighawag/kha3d_examples/blob/master/tutorial08/Sources/Empty.hx#L110

Not sure if khage works with Haxe 4 but Haxe 4 might even have better way to do it.

wighawag avatar Nov 24 '19 18:11 wighawag

But that's too restrictive me thinks, things might involve some conditionals.

RobDangerous avatar Nov 24 '19 18:11 RobDangerous

With Macro it is possible to ensure begin and end are always called.

You don't even really need a macro for this, can do something like

frame.usingG4(g -> {
    g.clear(...);
    g.draw(...);
});

The anon function there is nicely inlined because it's an immediately-invoked function (see my post from 2017 ^^).

nadako avatar Nov 24 '19 18:11 nadako

IMHO, that's pretty redundant. If all draw calls were happening at one place anyway,

frame.usingG4(g -> {
    g.clear(...);
    g.draw(...);
});

this takes exactly the same amount of effort to write as:

var g = frame.g4;
g.begin()
g.clear(...);
g.draw(...);
g.end();

I still stand firmly by my fix, which keeps everything mostly the same while addressing both the original issue, while also a) getting rid of "end before you begin" & "begin before you end throws" in release builds and b) automatically calls begin/end, just in case something goes wrong.

IMHO, it is also important to note here that automatically calling before/end should be a fallback in case something unexpected and bad happens, not something to rely on...

lunabunn avatar Nov 24 '19 18:11 lunabunn

Although, that kind of inline-ability does have some of the nice vibes something like cascaded function calls or chaining have... I still don't think it should be part of the core Graphics2 class. Maybe part of GraphicsExtensions?

lunabunn avatar Nov 24 '19 18:11 lunabunn