diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml
index 01f1598f851..d12d33364ac 100644
--- a/src/mapi/glapi/gen/gl_API.xml
+++ b/src/mapi/glapi/gen/gl_API.xml
@@ -2682,8 +2682,7 @@
-
+
diff --git a/src/mesa/main/glthread_pixels.c b/src/mesa/main/glthread_pixels.c
index c8fed4bb7db..bceef8081dd 100644
--- a/src/mesa/main/glthread_pixels.c
+++ b/src/mesa/main/glthread_pixels.c
@@ -9,6 +9,7 @@
#include "main/image.h"
#define MAX_BITMAP_BYTE_SIZE 4096
+#define MAX_DRAWPIX_BYTE_SIZE 4096
struct marshal_cmd_Bitmap
{
@@ -87,3 +88,75 @@ _mesa_marshal_Bitmap(GLsizei width, GLsizei height, GLfloat xorig,
CALL_Bitmap(ctx->Dispatch.Current,
(width, height, xorig, yorig, xmove, ymove, bitmap));
}
+
+struct marshal_cmd_DrawPixels
+{
+ struct marshal_cmd_base cmd_base;
+ uint16_t num_slots;
+ GLenum16 format;
+ GLenum16 type;
+ GLsizei width;
+ GLsizei height;
+ GLvoid *pixels;
+};
+
+uint32_t
+_mesa_unmarshal_DrawPixels(struct gl_context *ctx,
+ const struct marshal_cmd_DrawPixels *restrict cmd)
+{
+ CALL_DrawPixels(ctx->Dispatch.Current,
+ (cmd->width, cmd->height, cmd->format, cmd->type,
+ cmd->pixels));
+ return cmd->num_slots;
+}
+
+void GLAPIENTRY
+_mesa_marshal_DrawPixels(GLsizei width, GLsizei height, GLenum format,
+ GLenum type, const GLvoid *pixels)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ int cmd_size = sizeof(struct marshal_cmd_DrawPixels);
+
+ /* If not building a display list... */
+ if (!ctx->GLThread.ListMode) {
+ /* PBO */
+ if (!_mesa_glthread_has_no_unpack_buffer(ctx)) {
+ struct marshal_cmd_DrawPixels *cmd =
+ _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawPixels,
+ cmd_size);
+ cmd->num_slots = align(cmd_size, 8) / 8;
+ cmd->format = MIN2(format, 0xffff); /* clamped to 0xffff (invalid enum) */
+ cmd->type = MIN2(type, 0xffff); /* clamped to 0xffff (invalid enum) */
+ cmd->width = width;
+ cmd->height = height;
+ cmd->pixels = (void *)pixels;
+ return;
+ }
+
+ /* A negative stride is unimplemented (it inverts the offset). */
+ if (!ctx->Unpack.Invert) {
+ size_t image_size =
+ (size_t)_mesa_image_row_stride(&ctx->GLThread.Unpack,
+ width, format, type) * height;
+
+ /* If the image is small enough, copy it into the batch. */
+ if (image_size <= MAX_DRAWPIX_BYTE_SIZE) {
+ struct marshal_cmd_DrawPixels *cmd =
+ _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawPixels,
+ cmd_size + image_size);
+ cmd->num_slots = align(cmd_size + image_size, 8) / 8;
+ cmd->format = MIN2(format, 0xffff); /* clamped to 0xffff (invalid enum) */
+ cmd->type = MIN2(type, 0xffff); /* clamped to 0xffff (invalid enum) */
+ cmd->width = width;
+ cmd->height = height;
+ cmd->pixels = cmd + 1;
+ memcpy(cmd->pixels, pixels, image_size);
+ return;
+ }
+ }
+ }
+
+ _mesa_glthread_finish_before(ctx, "DrawPixels");
+ CALL_DrawPixels(ctx->Dispatch.Current,
+ (width, height, format, type, pixels));
+}