shithub: cstory

Download patch

ref: a77cc0a559d9cc35e00f3d17c4d8056e1ddc5e82
parent: 8513a1d7d859217a245baf31813cd850d062afb5
author: Clownacy <Clownacy@users.noreply.github.com>
date: Mon Oct 12 13:30:10 EDT 2020

Optimise the 3DS port (now runs okay on Old3DSs)

This commit customises the software renderer specifically for the
3DS, taking into account its rotated framebuffer and BGR format.

With this, the game appears to run full-speed on Old3DSs. Of course,
the level transition effect still makes the console chug, but that
thing was always a bit of a bottleneck.

--- a/src/Backends/Platform/3DS.cpp
+++ b/src/Backends/Platform/3DS.cpp
@@ -22,7 +22,7 @@
 
 	if (R_SUCCEEDED(romfsInit()))
 	{
-		osSetSpeedupEnable(true); // Enable New3DS speedup, since this doesn't run very well on Old3DSs yet
+//		osSetSpeedupEnable(true); // Enable New3DS speedup, since this doesn't run very well on Old3DSs yet
 
 		return true;
 	}
--- a/src/Backends/Rendering/Software.cpp
+++ b/src/Backends/Rendering/Software.cpp
@@ -37,8 +37,13 @@
 	if (WindowBackend_Software_CreateWindow(window_title, screen_width, screen_height, fullscreen))
 	{
 		framebuffer.pixels = WindowBackend_Software_GetFramebuffer(&framebuffer.pitch);
+	#ifdef _3DS
+		framebuffer.width = screen_height;
+		framebuffer.height = screen_width;
+	#else
 		framebuffer.width = screen_width;
 		framebuffer.height = screen_height;
+	#endif
 
 		return &framebuffer;
 	}
@@ -80,9 +85,15 @@
 		return NULL;
 	}
 
+#ifdef _3DS
+	surface->width = height;
+	surface->height = width;
+	surface->pitch = height * 3;
+#else
 	surface->width = width;
 	surface->height = height;
 	surface->pitch = width * 3;
+#endif
 
 	return surface;
 }
@@ -107,8 +118,25 @@
 
 void RenderBackend_UploadSurface(RenderBackend_Surface *surface, const unsigned char *pixels, size_t width, size_t height)
 {
+#ifdef _3DS
+	// Rotate 90 degrees clockwise, and convert from RGB to BGR
+	const unsigned char *source_pointer = pixels;
+
 	for (size_t y = 0; y < height; ++y)
+	{
+		for (size_t x = 0; x < width; ++x)
+		{
+			unsigned char *destination_pixel = &surface->pixels[x * surface->pitch + (surface->width - y - 1) * 3];
+
+			destination_pixel[2] = *source_pointer++;
+			destination_pixel[1] = *source_pointer++;
+			destination_pixel[0] = *source_pointer++;
+		}
+	}
+#else
+	for (size_t y = 0; y < height; ++y)
 		memcpy(&surface->pixels[y * surface->pitch], &pixels[y * width * 3], width * 3);
+#endif
 }
 
 ATTRIBUTE_HOT void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBackend_Rect *rect, RenderBackend_Surface *destination_surface, long x, long y, bool colour_key)
@@ -115,10 +143,23 @@
 {
 	RenderBackend_Rect rect_clamped;
 
+#ifdef _3DS
+	// Rotate
+	rect_clamped.left = source_surface->width - rect->bottom;
+	rect_clamped.top = rect->left;
+	rect_clamped.right = source_surface->width - rect->top;
+	rect_clamped.bottom = rect->right;
+
+	const long new_x = (destination_surface->width - y) - (rect_clamped.right - rect_clamped.left);
+	const long new_y = x;
+	x = new_x;
+	y = new_y;
+#else
 	rect_clamped.left = rect->left;
 	rect_clamped.top = rect->top;
 	rect_clamped.right = rect->right;
 	rect_clamped.bottom = rect->bottom;
+#endif
 
 	// Clamp the rect and coordinates so we don't write outside the pixel buffer
 	long overflow;
@@ -194,10 +235,18 @@
 {
 	RenderBackend_Rect rect_clamped;
 
+#ifdef _3DS
+	// Rotate
+	rect_clamped.left = surface->width - rect->bottom;
+	rect_clamped.top = rect->left;
+	rect_clamped.right = surface->width - rect->top;
+	rect_clamped.bottom = rect->right;
+#else
 	rect_clamped.left = rect->left;
 	rect_clamped.top = rect->top;
 	rect_clamped.right = rect->right;
 	rect_clamped.bottom = rect->bottom;
+#endif
 
 	// Clamp the rect so it doesn't write outside the pixel buffer
 	long overflow;
@@ -230,9 +279,15 @@
 
 		for (long i = 0; i < rect_clamped.right - rect_clamped.left; ++i)
 		{
+		#ifdef _3DS
+			*destination_pointer++ = blue;
+			*destination_pointer++ = green;
 			*destination_pointer++ = red;
+		#else
+			*destination_pointer++ = red;
 			*destination_pointer++ = green;
 			*destination_pointer++ = blue;
+		#endif
 		}
 	}
 }
@@ -247,8 +302,13 @@
 
 		if (atlas->pixels != NULL)
 		{
+		#ifdef _3DS
+			atlas->width = height;
+			atlas->height = width;
+		#else
 			atlas->width = width;
 			atlas->height = height;
+		#endif
 
 			return atlas;
 		}
@@ -267,8 +327,19 @@
 
 void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height, size_t pitch)
 {
+#ifdef _3DS
+	// Rotate
+	for (size_t h = 0; h < height; ++h)
+	{
+		const unsigned char *source_pointer = &pixels[h * pitch];
+
+		for (size_t w = 0; w < width; ++w)
+			atlas->pixels[(x + w) * atlas->width + (atlas->width - (y + h) - 1)] = *source_pointer++;
+	}
+#else
 	for (size_t i = 0; i < height; ++i)
 		memcpy(&atlas->pixels[(y + i) * atlas->width + x], &pixels[i * pitch], width);
+#endif
 }
 
 void RenderBackend_PrepareToDrawGlyphs(RenderBackend_GlyphAtlas *atlas, RenderBackend_Surface *destination_surface, unsigned char red, unsigned char green, unsigned char blue)
@@ -276,13 +347,37 @@
 	glyph_atlas = atlas;
 	glyph_destination_surface = destination_surface;
 
+#ifdef _3DS
+	glyph_colour_channels[0] = blue;
+	glyph_colour_channels[1] = green;
+	glyph_colour_channels[2] = red;
+#else
 	glyph_colour_channels[0] = red;
 	glyph_colour_channels[1] = green;
 	glyph_colour_channels[2] = blue;
+#endif
 }
 
 void RenderBackend_DrawGlyph(long x, long y, size_t glyph_x, size_t glyph_y, size_t glyph_width, size_t glyph_height)
 {
+#ifdef _3DS
+	// Rotate
+	const size_t new_glyph_width = glyph_height;
+	const size_t new_glyph_height = glyph_width;
+	glyph_width = new_glyph_width;
+	glyph_height = new_glyph_height;
+
+	const long new_x = (glyph_destination_surface->width - y) - glyph_width;
+	const long new_y = x;
+	x = new_x;
+	y = new_y;
+
+	const long new_glyph_x = (glyph_atlas->width - glyph_y) - glyph_width;
+	const long new_glyph_y = glyph_x;
+	glyph_x = new_glyph_x;
+	glyph_y = new_glyph_y;
+#endif
+
 	size_t surface_x;
 	size_t surface_y;
 
--- a/src/Backends/Rendering/Window/Software/3DS.cpp
+++ b/src/Backends/Rendering/Window/Software/3DS.cpp
@@ -2,6 +2,7 @@
 
 #include <stddef.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <3ds.h>
 
@@ -23,9 +24,9 @@
 
 	if (framebuffer != NULL)
 	{
-		framebuffer_pitch = screen_width * 3;
-		framebuffer_width = screen_width;
-		framebuffer_height = screen_height;
+		framebuffer_pitch = screen_height * 3;
+		framebuffer_width = screen_height;
+		framebuffer_height = screen_width;
 
 		return true;
 	}
@@ -47,22 +48,7 @@
 
 void WindowBackend_Software_Display(void)
 {
-	// Absolutely disgusting
-	unsigned char *actual_framebuffer = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL);
-
-	unsigned char *framebuffer_pointer = framebuffer;
-
-	const size_t offset = ((400 - framebuffer_width) / 2) * 240;
-
-	for (unsigned int h = framebuffer_height - 1; h-- != 0;)
-	{
-		for (unsigned int w = 0; w < framebuffer_width * 240; w += 240)
-		{
-			actual_framebuffer[(offset + w + h) * 3 + 2] = *framebuffer_pointer++;
-			actual_framebuffer[(offset + w + h) * 3 + 1] = *framebuffer_pointer++;
-			actual_framebuffer[(offset + w + h) * 3 + 0] = *framebuffer_pointer++;
-		}		
-	}
+	memcpy(gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL) + (400 - framebuffer_height) * 240 * 3 / 2, framebuffer, framebuffer_pitch * framebuffer_height);
 
 	gfxFlushBuffers();
 	gfxScreenSwapBuffers(GFX_TOP, false);