Просмотр исходного кода

libobs/graphics: Improve sprite drawing perf

Sprites were unnecessarily updating a dynamic vertex buffer every single
draw call. This creates static vertex buffers for common vertex buffer
dimensions/uvs and only uses a dynamic vertex buffer when the texture
coordinates actually change.

Porbably not a significant perf change considering the very few number
of traingles we draw per frame but still nice to do.
Lain 7 месяцев назад
Родитель
Сommit
7b8b51b29f
2 измененных файлов с 64 добавлено и 21 удалено
  1. 2 0
      libobs/graphics/graphics-internal.h
  2. 62 21
      libobs/graphics/graphics.c

+ 2 - 0
libobs/graphics/graphics-internal.h

@@ -311,6 +311,8 @@ struct graphics_subsystem {
 	struct gs_effect *cur_effect;
 
 	gs_vertbuffer_t *sprite_buffer;
+	gs_vertbuffer_t *flipped_sprite_buffer;
+	gs_vertbuffer_t *subregion_buffer;
 
 	bool using_immediate;
 	struct gs_vb_data *vbd;

+ 62 - 21
libobs/graphics/graphics.c

@@ -114,25 +114,46 @@ static bool graphics_init_immediate_vb(struct graphics_subsystem *graphics)
 	return true;
 }
 
-static bool graphics_init_sprite_vb(struct graphics_subsystem *graphics)
+static bool graphics_init_sprite_vbs(struct graphics_subsystem *graphics)
 {
 	struct gs_vb_data *vbd;
 
 	vbd = gs_vbdata_create();
 	vbd->num = 4;
-	vbd->points = bmalloc(sizeof(struct vec3) * 4);
+	vbd->points = bzalloc(sizeof(struct vec3) * 4);
 	vbd->num_tex = 1;
-	vbd->tvarray = bmalloc(sizeof(struct gs_tvertarray));
+	vbd->tvarray = bzalloc(sizeof(struct gs_tvertarray));
 	vbd->tvarray[0].width = 2;
-	vbd->tvarray[0].array = bmalloc(sizeof(struct vec2) * 4);
+	vbd->tvarray[0].array = bzalloc(sizeof(struct vec2) * 4);
+
+	vbd->points[1].x = 1.0f;
+	vbd->points[2].y = 1.0f;
+	vbd->points[3].x = 1.0f;
+	vbd->points[3].y = 1.0f;
 
-	memset(vbd->points, 0, sizeof(struct vec3) * 4);
-	memset(vbd->tvarray[0].array, 0, sizeof(struct vec2) * 4);
+	struct vec2 *uvs = vbd->tvarray[0].array;
+	uvs[1].x = 1.0f;
+	uvs[2].y = 1.0f;
+	uvs[3].x = 1.0f;
+	uvs[3].y = 1.0f;
 
-	graphics->sprite_buffer = graphics->exports.device_vertexbuffer_create(graphics->device, vbd, GS_DYNAMIC);
+	graphics->sprite_buffer = gs_vertexbuffer_create(vbd, GS_DUP_BUFFER);
 	if (!graphics->sprite_buffer)
 		return false;
 
+	graphics->subregion_buffer = gs_vertexbuffer_create(vbd, GS_DUP_BUFFER | GS_DYNAMIC);
+	if (!graphics->subregion_buffer)
+		return false;
+
+	uvs[0].y = 1.0f;
+	uvs[1].y = 1.0f;
+	uvs[2].y = 0.0f;
+	uvs[3].y = 0.0f;
+
+	graphics->flipped_sprite_buffer = gs_vertexbuffer_create(vbd, 0);
+	if (!graphics->flipped_sprite_buffer)
+		return false;
+
 	return true;
 }
 
@@ -145,9 +166,11 @@ static bool graphics_init(struct graphics_subsystem *graphics)
 
 	graphics->exports.device_enter_context(graphics->device);
 
+	thread_graphics = graphics;
+
 	if (!graphics_init_immediate_vb(graphics))
 		return false;
-	if (!graphics_init_sprite_vb(graphics))
+	if (!graphics_init_sprite_vbs(graphics))
 		return false;
 	if (pthread_mutex_init(&graphics->mutex, NULL) != 0)
 		return false;
@@ -168,6 +191,7 @@ static bool graphics_init(struct graphics_subsystem *graphics)
 	graphics->exports.device_leave_context(graphics->device);
 
 	gs_init_image_deps();
+	thread_graphics = NULL;
 	return true;
 }
 
@@ -227,6 +251,8 @@ void gs_destroy(graphics_t *graphics)
 			effect = next;
 		}
 
+		graphics->exports.gs_vertexbuffer_destroy(graphics->subregion_buffer);
+		graphics->exports.gs_vertexbuffer_destroy(graphics->flipped_sprite_buffer);
 		graphics->exports.gs_vertexbuffer_destroy(graphics->sprite_buffer);
 		graphics->exports.gs_vertexbuffer_destroy(graphics->immediate_vertbuffer);
 		graphics->exports.device_destroy(graphics->device);
@@ -1000,23 +1026,30 @@ void gs_draw_sprite(gs_texture_t *tex, uint32_t flip, uint32_t width, uint32_t h
 	fcx = width ? (float)width : (float)gs_texture_get_width(tex);
 	fcy = height ? (float)height : (float)gs_texture_get_height(tex);
 
-	data = gs_vertexbuffer_get_data(graphics->sprite_buffer);
-	if (tex && gs_texture_is_rect(tex))
-		build_sprite_rect(data, tex, fcx, fcy, flip);
-	else
-		build_sprite_norm(data, fcx, fcy, flip);
+	gs_matrix_push();
+	gs_matrix_scale3f(fcx, fcy, 1.0f);
 
-	gs_vertexbuffer_flush(graphics->sprite_buffer);
-	gs_load_vertexbuffer(graphics->sprite_buffer);
 	gs_load_indexbuffer(NULL);
 
-	gs_draw(GS_TRISTRIP, 0, 0);
+	if (tex && gs_texture_is_rect(tex)) {
+		data = gs_vertexbuffer_get_data(graphics->subregion_buffer);
+		build_sprite_rect(data, tex, 1.0f, 1.0f, flip);
+		gs_vertexbuffer_flush(graphics->subregion_buffer);
+		gs_load_vertexbuffer(graphics->subregion_buffer);
+		gs_draw(GS_TRISTRIP, 0, 0);
+	} else {
+		gs_load_vertexbuffer(flip ? graphics->flipped_sprite_buffer : graphics->sprite_buffer);
+		gs_draw(GS_TRISTRIP, 0, 0);
+	}
+
+	gs_matrix_pop();
 }
 
 void gs_draw_sprite_subregion(gs_texture_t *tex, uint32_t flip, uint32_t sub_x, uint32_t sub_y, uint32_t sub_cx,
 			      uint32_t sub_cy)
 {
 	graphics_t *graphics = thread_graphics;
+	uint32_t cx, cy;
 	float fcx, fcy;
 	struct gs_vb_data *data;
 
@@ -1027,14 +1060,22 @@ void gs_draw_sprite_subregion(gs_texture_t *tex, uint32_t flip, uint32_t sub_x,
 		}
 	}
 
-	fcx = (float)gs_texture_get_width(tex);
-	fcy = (float)gs_texture_get_height(tex);
+	cx = gs_texture_get_width(tex);
+	cy = gs_texture_get_height(tex);
+
+	if (sub_x == 0 && sub_y == 0 && sub_cx == cx && sub_cy == cy) {
+		gs_draw_sprite(tex, flip, 0, 0);
+		return;
+	}
+
+	fcx = (float)cx;
+	fcy = (float)cy;
 
-	data = gs_vertexbuffer_get_data(graphics->sprite_buffer);
+	data = gs_vertexbuffer_get_data(graphics->subregion_buffer);
 	build_subsprite_norm(data, (float)sub_x, (float)sub_y, (float)sub_cx, (float)sub_cy, fcx, fcy, flip);
 
-	gs_vertexbuffer_flush(graphics->sprite_buffer);
-	gs_load_vertexbuffer(graphics->sprite_buffer);
+	gs_vertexbuffer_flush(graphics->subregion_buffer);
+	gs_load_vertexbuffer(graphics->subregion_buffer);
 	gs_load_indexbuffer(NULL);
 
 	gs_draw(GS_TRISTRIP, 0, 0);