summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2007-03-02 13:44:57 -0800
committerEric Anholt <eric@anholt.net>2007-03-02 13:44:57 -0800
commitfd52d635603b7093c5a2b7fa9c987cf59f9be27c (patch)
treefa25a303689b73a88b6798e7fe7e9c3bf46fa5a4
parentca0fa875e8bb5cb778d4db7d8053ec0a5ae34ef4 (diff)
Add a WIP UploadToScreen implementation. This almost displays right.
-rw-r--r--src/common.h37
-rw-r--r--src/i810_reg.h2
-rw-r--r--src/i830_exa.c91
3 files changed, 130 insertions, 0 deletions
diff --git a/src/common.h b/src/common.h
index 8f42bde8..6e8ddbda 100644
--- a/src/common.h
+++ b/src/common.h
@@ -131,6 +131,43 @@ extern void I830DPRINTF_stub(const char *filename, int line,
outring &= ringmask; \
} while (0)
+static inline void memset_volatile(volatile void *b, int c, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ ((volatile char *)b)[i] = c;
+}
+
+static inline void memcpy_volatile(volatile void *dst, const void *src,
+ size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ ((volatile char *)dst)[i] = ((volatile char *)src)[i];
+}
+
+/** Copies a given number of bytes to the ring */
+#define OUT_RING_COPY(n, ptr) do { \
+ if (I810_DEBUG & DEBUG_VERBOSE_RING) \
+ ErrorF("OUT_RING_DATA %d bytes\n", n); \
+ memcpy_volatile(virt + outring, ptr, n); \
+ outring += n; \
+ ringused += n; \
+ outring &= ringmask; \
+} while (0)
+
+/** Pads the ring with a given number of zero bytes */
+#define OUT_RING_PAD(n) do { \
+ if (I810_DEBUG & DEBUG_VERBOSE_RING) \
+ ErrorF("OUT_RING_PAD %d bytes\n", n); \
+ memset_volatile(virt + outring, 0, n); \
+ outring += n; \
+ ringused += n; \
+ outring &= ringmask; \
+} while (0)
+
union intfloat {
float f;
unsigned int ui;
diff --git a/src/i810_reg.h b/src/i810_reg.h
index 6a9c11e4..d63be025 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -1906,6 +1906,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SRC_COPY_BLT_WRITE_ALPHA (1<<21)
#define SRC_COPY_BLT_WRITE_RGB (1<<20)
+#define XY_PAT_BLT_IMMEDIATE ((2<<29)|(0x72<<22))
+
#define XY_MONO_PAT_BLT_CMD ((0x2<<29)|(0x52<<22)|0x7)
#define XY_MONO_PAT_VERT_SEED ((1<<10)|(1<<9)|(1<<8))
#define XY_MONO_PAT_HORT_SEED ((1<<14)|(1<<13)|(1<<12))
diff --git a/src/i830_exa.c b/src/i830_exa.c
index 37fd2842..bef8faef 100644
--- a/src/i830_exa.c
+++ b/src/i830_exa.c
@@ -297,6 +297,93 @@ i830_get_transformed_coordinates(int x, int y, PictTransformPtr transform,
}
}
+/**
+ * Uploads data from system memory to the framebuffer using a series of
+ * 8x8 pattern blits.
+ */
+static Bool
+i830_upload_to_screen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
+ int src_pitch)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
+ I830Ptr pI830 = I830PTR(pScrn);
+ const int uts_width_max = 16, uts_height_max = 16;
+ int cpp = pDst->drawable.bitsPerPixel / 8;
+ int sub_x, sub_y;
+ CARD32 br13;
+ CARD32 offset;
+
+ if (w > uts_width_max || h > uts_height_max)
+ I830FALLBACK("too large for upload to screen (%d,%d)", w, h);
+
+ offset = exaGetPixmapOffset(pDst);
+
+ br13 = exaGetPixmapPitch(pDst);
+ br13 |= ((I830PatternROP[GXcopy] & 0xff) << 16);
+ switch (pDst->drawable.bitsPerPixel) {
+ case 16:
+ br13 |= 1 << 24;
+ break;
+ case 32:
+ br13 |= 3 << 24;
+ break;
+ }
+
+ for (sub_y = 0; sub_y < uts_height_max && sub_y < h; sub_y += 8) {
+ int sub_height;
+
+ if (sub_y + 8 > h)
+ sub_height = h - sub_y;
+ else
+ sub_height = 8;
+
+ for (sub_x = 0; sub_x < uts_width_max && sub_x < w; sub_x += 8) {
+ int sub_width, line;
+ char *src_line = src + sub_y * src_pitch + sub_x * cpp;
+
+ if (sub_x + 8 > w)
+ sub_width = w - sub_x;
+ else
+ sub_width = 8;
+
+ BEGIN_LP_RING(6 + (cpp * 8 * 8 / 4));
+
+ /* XXX We may need a pattern offset here for {x,y} % 8 != 0*/
+ OUT_RING(XY_PAT_BLT_IMMEDIATE |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB |
+ (3 + cpp * 8 * 8 / 4));
+ OUT_RING(br13);
+ OUT_RING(((y + sub_y) << 16) | (x + sub_x));
+ OUT_RING(((y + sub_y + sub_height) << 16) |
+ (x + sub_x + sub_width));
+ OUT_RING(offset);
+
+ /* Write out the lines with valid data, followed by any needed
+ * padding
+ */
+ for (line = 0; line < sub_height; line++) {
+ OUT_RING_COPY(sub_width * cpp, src_line);
+ src_line += src_pitch;
+ if (sub_width != 8)
+ OUT_RING_PAD((8 - sub_width) * cpp);
+ }
+ /* Write out any full padding lines to follow */
+ if (sub_height != 8)
+ OUT_RING_PAD(8 * cpp * (8 - sub_height));
+
+ OUT_RING(MI_NOOP);
+ ADVANCE_LP_RING();
+ }
+ }
+
+ exaMarkSync(pDst->drawable.pScreen);
+ /* exaWaitSync(pDst->drawable.pScreen); */
+
+ return TRUE;
+}
+
+
/*
* TODO:
* - Dual head?
@@ -421,6 +508,10 @@ I830EXAInit(ScreenPtr pScreen)
pI830->EXADriverPtr->DoneComposite = i830_done_composite;
}
+ /* UploadToScreen/DownloadFromScreen */
+ if (0)
+ pI830->EXADriverPtr->UploadToScreen = i830_upload_to_screen;
+
if(!exaDriverInit(pScreen, pI830->EXADriverPtr)) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"EXA initialization failed; trying older version\n");