Bug 671428. cairo: Handle bad strides in acquire_source_surface. r=bas
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Tue, 16 Aug 2011 19:07:49 -0400
changeset 75416 be62b6c4392a9eb07d5a570ba9a1450c1aa8d805
parent 75415 0c4897315acce9bc8fc97cd1b9bb810cbd356f64
child 75417 8f315a50dcc9736e0efa47d8110fc14dc3d80415
push id21023
push usermak77@bonardo.net
push dateThu, 18 Aug 2011 09:39:20 +0000
treeherdermozilla-central@f69a10f23bf3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas
bugs671428
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 671428. cairo: Handle bad strides in acquire_source_surface. r=bas Cairo requires image surfaces to have a particular stride alignment. Sometimes the texture we get back from Direct3D doesn't meet these requirements. In that case, copy to a different buffer that meets these requirments.
gfx/cairo/cairo/src/cairo-d2d-surface.cpp
gfx/cairo/cairo/src/cairoint.h
--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
@@ -2505,21 +2505,38 @@ static cairo_status_t
     // We need to release the device after calling the constructor, since the
     // device destruction may release the D3D/D2D libraries.
     cairo_device_t *device = &d2dsurf->device->base;
     d2dsurf->~cairo_d2d_surface_t();
     cairo_release_device(device);
     return CAIRO_STATUS_SUCCESS;
 }
 
+/* The input types for src and dst don't match because in our particular use case, copying from a texture,
+ * those types don't match. */
+static void
+_copy_data_to_different_stride(unsigned char *dst, int dst_stride, void *src, UINT src_stride, int height)
+{
+
+    unsigned char *src_p = (unsigned char *)src;
+    int min_stride = MIN(dst_stride, src_stride);
+    while (height) {
+        memcpy(dst, src_p, min_stride);
+        height--;
+        dst += dst_stride;
+        src_p += src_stride;
+    }
+}
+
 static cairo_status_t
 _cairo_d2d_acquire_source_image(void                    *abstract_surface,
-				cairo_image_surface_t  **image_out,
+				cairo_image_surface_t  **image_out_ret,
 				void                   **image_extra)
 {
+    cairo_surface_t *image_out;
     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(abstract_surface);
     _cairo_d2d_flush(d2dsurf);
 
     HRESULT hr;
     D2D1_SIZE_U size = d2dsurf->rt->GetPixelSize();
 
     RefPtr<ID3D10Texture2D> softTexture;
 
@@ -2547,34 +2564,46 @@ static cairo_status_t
 
     d2dsurf->device->mD3D10Device->CopyResource(softTexture, d2dsurf->surface);
 
     D3D10_MAPPED_TEXTURE2D data;
     hr = softTexture->Map(0, D3D10_MAP_READ_WRITE, 0, &data);
     if (FAILED(hr)) {
 	return _cairo_error(CAIRO_STATUS_NO_DEVICE);
     }
-    *image_out = 
-	(cairo_image_surface_t*)cairo_image_surface_create_for_data((unsigned char*)data.pData,
-										  d2dsurf->format,
-										  size.width,
-										  size.height,
-										  data.RowPitch);
-
-    if (cairo_surface_status(&((*image_out)->base))) {
-	volatile cairo_status_t flambo[10];
-	for (int i=0; i<10; i++) {
-	    flambo[i] = cairo_surface_status(&((*image_out)->base));
-	}
-	volatile int p = 0;
-	p = 5/p;
+
+    if (_cairo_valid_stride_alignment(data.RowPitch)) {
+	image_out = cairo_image_surface_create_for_data((unsigned char*)data.pData,
+						  d2dsurf->format,
+						  size.width,
+						  size.height,
+						  data.RowPitch);
+    } else {
+	/* Slow path used when the stride doesn't match our requirements.
+	 * This is possible on at least the Intel driver 8.15.10.2302.
+	 *
+	 * Create a new image surface and copy our data into it */
+	image_out = cairo_image_surface_create(d2dsurf->format,
+					 size.width,
+					 size.height);
+	_copy_data_to_different_stride(cairo_image_surface_get_data(image_out),
+				       cairo_image_surface_get_stride(image_out),
+				       data.pData,
+				       data.RowPitch,
+				       size.height);
+
     }
+    /* these are the only surface statuses we expect */
+    assert(cairo_surface_status(image_out) == CAIRO_STATUS_SUCCESS ||
+	   cairo_surface_status(image_out) == CAIRO_STATUS_NO_MEMORY);
+
     *image_extra = softTexture.forget();
-
-    return CAIRO_STATUS_SUCCESS;
+    *image_out_ret = (cairo_image_surface_t*)image_out;
+
+    return cairo_surface_status(image_out);
 }
 
 static void
 _cairo_d2d_release_source_image(void                   *abstract_surface,
 				cairo_image_surface_t  *image,
 				void                   *image_extra)
 {
     if (((cairo_surface_t*)abstract_surface)->type != CAIRO_SURFACE_TYPE_D2D) {
--- a/gfx/cairo/cairo/src/cairoint.h
+++ b/gfx/cairo/cairo/src/cairoint.h
@@ -1903,16 +1903,22 @@ cairo_private void
    ((((bpp)*(w)+7)/8 + CAIRO_STRIDE_ALIGNMENT-1) & -CAIRO_STRIDE_ALIGNMENT)
 
 #define CAIRO_CONTENT_VALID(content) ((content) && 			         \
 				      (((content) & ~(CAIRO_CONTENT_COLOR |      \
 						      CAIRO_CONTENT_ALPHA |      \
 						      CAIRO_CONTENT_COLOR_ALPHA))\
 				       == 0))
 
+static inline cairo_bool_t
+_cairo_valid_stride_alignment(int stride)
+{
+    return !(stride & (CAIRO_STRIDE_ALIGNMENT-1));
+}
+
 cairo_private int
 _cairo_format_bits_per_pixel (cairo_format_t format) cairo_const;
 
 cairo_private cairo_format_t
 _cairo_format_from_content (cairo_content_t content) cairo_const;
 
 cairo_private cairo_format_t
 _cairo_format_from_pixman_format (pixman_format_code_t pixman_format);