intel: Add support for ARB_copy_buffer.
authorEric Anholt <eric@anholt.net>
Thu, 27 Aug 2009 23:53:50 +0000 (16:53 -0700)
committerEric Anholt <eric@anholt.net>
Fri, 28 Aug 2009 00:51:29 +0000 (17:51 -0700)
Passes glean's bufferObject test for this extension.

src/mesa/drivers/dri/intel/intel_buffer_objects.c
src/mesa/drivers/dri/intel/intel_extensions.c

index 9600557f2cc5e63c44ad2248947ed257c8b92186..a740397943903b32f84e8e6b884d538e8450ac3f 100644 (file)
 
 #include "main/imports.h"
 #include "main/mtypes.h"
+#include "main/macros.h"
 #include "main/bufferobj.h"
 
 #include "intel_context.h"
+#include "intel_blit.h"
 #include "intel_buffer_objects.h"
 #include "intel_batchbuffer.h"
 #include "intel_regions.h"
@@ -243,8 +245,10 @@ intel_bufferobj_map(GLcontext * ctx,
       return obj->Pointer;
    }
 
-   if (!read_only)
-      intelFlush(ctx);
+   /* Flush any existing batchbuffer that might have written to this
+    * buffer.
+    */
+   intelFlush(ctx);
 
    if (intel_obj->region)
       intel_bufferobj_cow(intel, intel_obj);
@@ -325,6 +329,90 @@ intel_bufferobj_buffer(struct intel_context *intel,
    return intel_obj->buffer;
 }
 
+static void
+intel_bufferobj_copy_subdata(GLcontext *ctx,
+                            struct gl_buffer_object *src,
+                            struct gl_buffer_object *dst,
+                            GLintptr read_offset, GLintptr write_offset,
+                            GLsizeiptr size)
+{
+   struct intel_context *intel = intel_context(ctx);
+   struct intel_buffer_object *intel_src = intel_buffer_object(src);
+   struct intel_buffer_object *intel_dst = intel_buffer_object(dst);
+   drm_intel_bo *src_bo, *dst_bo;
+   GLuint pitch, height;
+
+   if (size == 0)
+      return;
+
+   /* If we're in system memory, just map and memcpy. */
+   if (intel_src->sys_buffer || intel_dst->sys_buffer) {
+      /* The same buffer may be used, but note that regions copied may
+       * not overlap.
+       */
+      if (src == dst) {
+        char *ptr = intel_bufferobj_map(ctx, GL_COPY_WRITE_BUFFER,
+                                        GL_READ_WRITE, dst);
+        memcpy(ptr + write_offset, ptr + read_offset, size);
+        intel_bufferobj_unmap(ctx, GL_COPY_WRITE_BUFFER, dst);
+      } else {
+        const char *src_ptr;
+        char *dst_ptr;
+
+        src_ptr =  intel_bufferobj_map(ctx, GL_COPY_READ_BUFFER,
+                                       GL_READ_ONLY, src);
+        dst_ptr =  intel_bufferobj_map(ctx, GL_COPY_WRITE_BUFFER,
+                                       GL_WRITE_ONLY, dst);
+
+        memcpy(dst_ptr + write_offset, src_ptr + read_offset, size);
+
+        intel_bufferobj_unmap(ctx, GL_COPY_READ_BUFFER, src);
+        intel_bufferobj_unmap(ctx, GL_COPY_WRITE_BUFFER, dst);
+      }
+   }
+
+   /* Otherwise, we have real BOs, so blit them.  We don't have a memmove-type
+    * blit like some other hardware, so we'll do a rectangular blit covering
+    * a large space, then emit a scanline blit at the end to cover the last
+    * if we need.
+    */
+
+   dst_bo = intel_bufferobj_buffer(intel, intel_dst, INTEL_WRITE_PART);
+   src_bo = intel_bufferobj_buffer(intel, intel_src, INTEL_READ);
+
+   /* The pitch is a signed value. */
+   pitch = MIN2(size, (1 << 15) - 1);
+   height = size / pitch;
+   intelEmitCopyBlit(intel, 1,
+                    pitch, src_bo, read_offset, I915_TILING_NONE,
+                    pitch, dst_bo, write_offset, I915_TILING_NONE,
+                    0, 0, /* src x/y */
+                    0, 0, /* dst x/y */
+                    pitch, height, /* w, h */
+                    GL_COPY);
+
+   read_offset += pitch * height;
+   write_offset += pitch * height;
+   size -= pitch * height;
+   assert (size < (1 << 15));
+   if (size != 0) {
+      intelEmitCopyBlit(intel, 1,
+                       size, src_bo, read_offset, I915_TILING_NONE,
+                       size, dst_bo, write_offset, I915_TILING_NONE,
+                       0, 0, /* src x/y */
+                       0, 0, /* dst x/y */
+                       size, 1, /* w, h */
+                       GL_COPY);
+   }
+
+   /* Since we've emitted some blits to buffers that will (likely) be used
+    * in rendering operations in other cache domains in this batch, emit a
+    * flush.  Once again, we wish for a domain tracker in libdrm to cover
+    * usage inside of a batchbuffer.
+    */
+   intel_batchbuffer_emit_mi_flush(intel->batch);
+}
+
 void
 intelInitBufferObjectFuncs(struct dd_function_table *functions)
 {
@@ -335,4 +423,5 @@ intelInitBufferObjectFuncs(struct dd_function_table *functions)
    functions->GetBufferSubData = intel_bufferobj_get_subdata;
    functions->MapBuffer = intel_bufferobj_map;
    functions->UnmapBuffer = intel_bufferobj_unmap;
+   functions->CopyBufferSubData = intel_bufferobj_copy_subdata;
 }
index 9f90ef0a6973ca399e75b4b3b871de652f0b7fee..ff9ad5acced679175ef0d263ac80525de7efd505 100644 (file)
@@ -30,6 +30,7 @@
 #include "intel_extensions.h"
 
 
+#define need_GL_ARB_copy_buffer
 #define need_GL_ARB_framebuffer_object
 #define need_GL_ARB_occlusion_query
 #define need_GL_ARB_point_parameters
@@ -69,6 +70,7 @@
  * i965_dri.
  */
 static const struct dri_extension card_extensions[] = {
+   { "GL_ARB_copy_buffer",                GL_ARB_copy_buffer_functions },
    { "GL_ARB_half_float_pixel",           NULL },
    { "GL_ARB_multitexture",               NULL },
    { "GL_ARB_point_parameters",           GL_ARB_point_parameters_functions },