diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h
index 0e3e7750a..b18f3e84e 100644
--- a/include/wlr/types/wlr_scene.h
+++ b/include/wlr/types/wlr_scene.h
@@ -132,6 +132,12 @@ struct wlr_scene_surface {
 		struct wl_listener frame_done;
 		struct wl_listener surface_destroy;
 		struct wl_listener surface_commit;
+
+		// True if the underlying buffer is a wlr_single_pixel_buffer_v1
+		bool is_single_pixel_buffer;
+		// If is_single_pixel_buffer is set, contains the color of the buffer
+		// as {R, G, B, A} where the max value of each component is UINT32_MAX
+		uint32_t single_pixel_buffer_color[4];
 	} WLR_PRIVATE;
 };
 
diff --git a/types/scene/surface.c b/types/scene/surface.c
index 1f954373d..079b82946 100644
--- a/types/scene/surface.c
+++ b/types/scene/surface.c
@@ -7,6 +7,7 @@
 #include <wlr/types/wlr_linux_drm_syncobj_v1.h>
 #include <wlr/types/wlr_output.h>
 #include <wlr/types/wlr_presentation_time.h>
+#include <wlr/types/wlr_single_pixel_buffer_v1.h>
 #include <wlr/util/transform.h>
 #include "types/wlr_scene.h"
 
@@ -164,6 +165,24 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
 	scene_buffer_unmark_client_buffer(scene_buffer);
 
 	if (surface->buffer) {
+		// If this is a buffer change, check if it's a single pixel buffer.
+		// Cache that so we can still apply rendering optimisations even when
+		// the original buffer has been freed after texture upload.
+		if (&surface->buffer->base != scene_buffer->buffer) {
+			scene_surface->is_single_pixel_buffer = false;
+			if (surface->buffer->source != NULL) {
+				struct wlr_single_pixel_buffer_v1 *single_pixel_buffer =
+					wlr_single_pixel_buffer_v1_try_from_buffer(surface->buffer->source);
+				if (single_pixel_buffer != NULL) {
+					scene_surface->is_single_pixel_buffer = true;
+					scene_surface->single_pixel_buffer_color[0] = single_pixel_buffer->r;
+					scene_surface->single_pixel_buffer_color[1] = single_pixel_buffer->g;
+					scene_surface->single_pixel_buffer_color[2] = single_pixel_buffer->b;
+					scene_surface->single_pixel_buffer_color[3] = single_pixel_buffer->a;
+				}
+			}
+		}
+
 		client_buffer_mark_next_can_damage(surface->buffer);
 
 		struct wlr_linux_drm_syncobj_surface_v1_state *syncobj_surface_state =
diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c
index d64ee4ada..481b2404f 100644
--- a/types/scene/wlr_scene.c
+++ b/types/scene/wlr_scene.c
@@ -1386,6 +1386,24 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
 	case WLR_SCENE_NODE_BUFFER:;
 		struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
 
+		struct wlr_scene_surface *scene_surface =
+			wlr_scene_surface_try_from_buffer(scene_buffer);
+		if (scene_surface != NULL && scene_surface->is_single_pixel_buffer) {
+			// Render the buffer as a rect, this is likely to be more efficient
+			wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){
+				.box = dst_box,
+				.color = {
+					.r = (float)scene_surface->single_pixel_buffer_color[0] / (float)UINT32_MAX,
+					.g = (float)scene_surface->single_pixel_buffer_color[1] / (float)UINT32_MAX,
+					.b = (float)scene_surface->single_pixel_buffer_color[2] / (float)UINT32_MAX,
+					.a = (float)scene_surface->single_pixel_buffer_color[3] /
+						(float)UINT32_MAX * scene_buffer->opacity,
+				},
+				.clip = &render_region,
+			});
+			break;
+		}
+
 		struct wlr_texture *texture = scene_buffer_get_texture(scene_buffer,
 			data->output->output->renderer);
 		if (texture == NULL) {
@@ -1736,6 +1754,18 @@ struct render_list_constructor_data {
 	bool fractional_scale;
 };
 
+static bool scene_buffer_is_black_opaque(struct wlr_scene_buffer *scene_buffer) {
+	struct wlr_scene_surface *scene_surface =
+		wlr_scene_surface_try_from_buffer(scene_buffer);
+	return scene_surface != NULL &&
+		scene_surface->is_single_pixel_buffer &&
+		scene_surface->single_pixel_buffer_color[0] == 0 &&
+		scene_surface->single_pixel_buffer_color[1] == 0 &&
+		scene_surface->single_pixel_buffer_color[2] == 0 &&
+		scene_surface->single_pixel_buffer_color[3] == UINT32_MAX &&
+		scene_buffer->opacity == 1.0;
+}
+
 static bool construct_render_list_iterator(struct wlr_scene_node *node,
 		int lx, int ly, void *_data) {
 	struct render_list_constructor_data *data = _data;
@@ -1758,6 +1788,16 @@ static bool construct_render_list_iterator(struct wlr_scene_node *node,
 		}
 	}
 
+	// Apply the same special-case to black opaque single-pixel buffers
+	if (node->type == WLR_SCENE_NODE_BUFFER && data->calculate_visibility &&
+			(!data->fractional_scale || data->render_list->size == 0)) {
+		struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
+
+		if (scene_buffer_is_black_opaque(scene_buffer)) {
+			return false;
+		}
+	}
+
 	pixman_region32_t intersection;
 	pixman_region32_init(&intersection);
 	pixman_region32_intersect_rect(&intersection, &node->visible,