summaryrefslogtreecommitdiff
path: root/src/mesa/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers')
-rw-r--r--src/mesa/drivers/dri/i915pipe/Makefile49
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_batchbuffer.c342
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_batchbuffer.h124
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_batchpool.c418
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_blit.c527
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_blit.h62
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_buffer_objects.c257
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_buffer_objects.h86
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_buffers.c792
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_buffers.h55
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_context.c768
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_context.h426
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_depthstencil.c282
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_depthstencil.h14
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_fbo.c623
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_fbo.h127
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_ioctl.c137
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_ioctl.h40
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_mipmap_tree.c358
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_mipmap_tree.h198
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_pixel.c45
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_pixel.h63
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_reg.h88
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_regions.c480
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_regions.h141
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_render.c244
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_rotate.c237
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_rotate.h39
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_screen.c708
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_screen.h129
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_span.c401
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_span.h38
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_state.c261
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_structs.h132
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_surface.c259
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_tex.c192
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_tex.h151
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_tex_copy.c293
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_tex_format.c172
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_tex_image.c691
l---------src/mesa/drivers/dri/i915pipe/intel_tex_layout.c1
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_tex_subimage.c182
-rw-r--r--src/mesa/drivers/dri/i915pipe/intel_tex_validate.c272
43 files changed, 10904 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i915pipe/Makefile b/src/mesa/drivers/dri/i915pipe/Makefile
new file mode 100644
index 0000000000..857d3fc985
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/Makefile
@@ -0,0 +1,49 @@
+
+TOP = ../../../../..
+include $(TOP)/configs/current
+
+LIBNAME = i915tex_dri.so
+
+MINIGLX_SOURCES = server/intel_dri.c
+
+DRIVER_SOURCES = \
+ intel_regions.c \
+ intel_buffer_objects.c \
+ intel_batchbuffer.c \
+ intel_mipmap_tree.c \
+ intel_tex_layout.c \
+ intel_tex_image.c \
+ intel_tex_subimage.c \
+ intel_tex_copy.c \
+ intel_tex_validate.c \
+ intel_tex_format.c \
+ intel_tex.c \
+ intel_pixel.c \
+ intel_buffers.c \
+ intel_blit.c \
+ intel_context.c \
+ intel_ioctl.c \
+ intel_rotate.c \
+ intel_screen.c \
+ intel_span.c \
+ intel_state.c \
+ intel_surface.c \
+ intel_fbo.c \
+ intel_depthstencil.c \
+ intel_batchpool.c
+
+C_SOURCES = \
+ $(COMMON_SOURCES) \
+ $(COMMON_BM_SOURCES) \
+ $(DRIVER_SOURCES)
+
+ASM_SOURCES =
+
+DRIVER_DEFINES = -I../intel $(shell pkg-config libdrm --atleast-version=2.3.1 \
+ && echo "-DDRM_VBLANK_FLIP=DRM_VBLANK_FLIP")
+
+include ../Makefile.template
+
+intel_tex_layout.o: ../intel/intel_tex_layout.c
+
+symlinks:
diff --git a/src/mesa/drivers/dri/i915pipe/intel_batchbuffer.c b/src/mesa/drivers/dri/i915pipe/intel_batchbuffer.c
new file mode 100644
index 0000000000..9259f2ac05
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_batchbuffer.c
@@ -0,0 +1,342 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "intel_batchbuffer.h"
+#include "intel_ioctl.h"
+
+/* Relocations in kernel space:
+ * - pass dma buffer seperately
+ * - memory manager knows how to patch
+ * - pass list of dependent buffers
+ * - pass relocation list
+ *
+ * Either:
+ * - get back an offset for buffer to fire
+ * - memory manager knows how to fire buffer
+ *
+ * Really want the buffer to be AGP and pinned.
+ *
+ */
+
+/* Cliprect fence: The highest fence protecting a dma buffer
+ * containing explicit cliprect information. Like the old drawable
+ * lock but irq-driven. X server must wait for this fence to expire
+ * before changing cliprects [and then doing sw rendering?]. For
+ * other dma buffers, the scheduler will grab current cliprect info
+ * and mix into buffer. X server must hold the lock while changing
+ * cliprects??? Make per-drawable. Need cliprects in shared memory
+ * -- beats storing them with every cmd buffer in the queue.
+ *
+ * ==> X server must wait for this fence to expire before touching the
+ * framebuffer with new cliprects.
+ *
+ * ==> Cliprect-dependent buffers associated with a
+ * cliprect-timestamp. All of the buffers associated with a timestamp
+ * must go to hardware before any buffer with a newer timestamp.
+ *
+ * ==> Dma should be queued per-drawable for correct X/GL
+ * synchronization. Or can fences be used for this?
+ *
+ * Applies to: Blit operations, metaops, X server operations -- X
+ * server automatically waits on its own dma to complete before
+ * modifying cliprects ???
+ */
+
+static void
+intel_dump_batchbuffer(GLuint offset, GLuint * ptr, GLuint count)
+{
+ int i;
+ fprintf(stderr, "\n\n\nSTART BATCH (%d dwords):\n", count / 4);
+ for (i = 0; i < count / 4; i += 4)
+ fprintf(stderr, "0x%x:\t0x%08x 0x%08x 0x%08x 0x%08x\n",
+ offset + i * 4, ptr[i], ptr[i + 1], ptr[i + 2], ptr[i + 3]);
+ fprintf(stderr, "END BATCH\n\n\n");
+}
+
+void
+intel_batchbuffer_reset(struct intel_batchbuffer *batch)
+{
+
+ int i;
+
+ /*
+ * Get a new, free batchbuffer.
+ */
+
+ batch->size = batch->intel->intelScreen->maxBatchSize;
+ driBOData(batch->buffer, batch->size, NULL, 0);
+
+ driBOResetList(&batch->list);
+
+ /*
+ * Unreference buffers previously on the relocation list.
+ */
+
+ for (i = 0; i < batch->nr_relocs; i++) {
+ struct buffer_reloc *r = &batch->reloc[i];
+ driBOUnReference(r->buf);
+ }
+
+ batch->list_count = 0;
+ batch->nr_relocs = 0;
+ batch->flags = 0;
+
+ /*
+ * We don't refcount the batchbuffer itself since we can't destroy it
+ * while it's on the list.
+ */
+
+
+ driBOAddListItem(&batch->list, batch->buffer,
+ DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_EXE,
+ DRM_BO_MASK_MEM | DRM_BO_FLAG_EXE);
+
+
+ batch->map = driBOMap(batch->buffer, DRM_BO_FLAG_WRITE, 0);
+ batch->ptr = batch->map;
+}
+
+/*======================================================================
+ * Public functions
+ */
+struct intel_batchbuffer *
+intel_batchbuffer_alloc(struct intel_context *intel)
+{
+ struct intel_batchbuffer *batch = calloc(sizeof(*batch), 1);
+
+ batch->intel = intel;
+
+ driGenBuffers(intel->intelScreen->batchPool, "batchbuffer", 1,
+ &batch->buffer, 4096,
+ DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_EXE, 0);
+ batch->last_fence = NULL;
+ driBOCreateList(20, &batch->list);
+ intel_batchbuffer_reset(batch);
+ return batch;
+}
+
+void
+intel_batchbuffer_free(struct intel_batchbuffer *batch)
+{
+ if (batch->last_fence) {
+ driFenceFinish(batch->last_fence,
+ DRM_FENCE_TYPE_EXE | DRM_I915_FENCE_TYPE_RW, GL_FALSE);
+ driFenceUnReference(batch->last_fence);
+ batch->last_fence = NULL;
+ }
+ if (batch->map) {
+ driBOUnmap(batch->buffer);
+ batch->map = NULL;
+ }
+ driBOUnReference(batch->buffer);
+ batch->buffer = NULL;
+ free(batch);
+}
+
+/* TODO: Push this whole function into bufmgr.
+ */
+static void
+do_flush_locked(struct intel_batchbuffer *batch,
+ GLuint used,
+ GLboolean ignore_cliprects, GLboolean allow_unlock)
+{
+ GLuint *ptr;
+ GLuint i;
+ struct intel_context *intel = batch->intel;
+ unsigned fenceFlags;
+ struct _DriFenceObject *fo;
+
+ driBOValidateList(batch->intel->driFd, &batch->list);
+
+ /* Apply the relocations. This nasty map indicates to me that the
+ * whole task should be done internally by the memory manager, and
+ * that dma buffers probably need to be pinned within agp space.
+ */
+ ptr = (GLuint *) driBOMap(batch->buffer, DRM_BO_FLAG_WRITE,
+ DRM_BO_HINT_ALLOW_UNFENCED_MAP);
+
+
+ for (i = 0; i < batch->nr_relocs; i++) {
+ struct buffer_reloc *r = &batch->reloc[i];
+
+ ptr[r->offset / 4] = driBOOffset(r->buf) + r->delta;
+ }
+
+ if (INTEL_DEBUG & DEBUG_BATCH)
+ intel_dump_batchbuffer(0, ptr, used);
+
+ driBOUnmap(batch->buffer);
+ batch->map = NULL;
+
+ /* Throw away non-effective packets. Won't work once we have
+ * hardware contexts which would preserve statechanges beyond a
+ * single buffer.
+ */
+
+ if (!(intel->numClipRects == 0 && !ignore_cliprects)) {
+ intel_batch_ioctl(batch->intel,
+ driBOOffset(batch->buffer),
+ used, ignore_cliprects, allow_unlock);
+ }
+
+
+ /*
+ * Kernel fencing. The flags tells the kernel that we've
+ * programmed an MI_FLUSH.
+ */
+
+ fenceFlags = DRM_I915_FENCE_FLAG_FLUSHED;
+ fo = driFenceBuffers(batch->intel->driFd,
+ "Batch fence", fenceFlags);
+
+ /*
+ * User space fencing.
+ */
+
+ driBOFence(batch->buffer, fo);
+
+ if (driFenceType(fo) == DRM_FENCE_TYPE_EXE) {
+
+ /*
+ * Oops. We only validated a batch buffer. This means we
+ * didn't do any proper rendering. Discard this fence object.
+ */
+
+ driFenceUnReference(fo);
+ } else {
+ driFenceUnReference(batch->last_fence);
+ batch->last_fence = fo;
+ for (i = 0; i < batch->nr_relocs; i++) {
+ struct buffer_reloc *r = &batch->reloc[i];
+ driBOFence(r->buf, fo);
+ }
+ }
+
+ if (intel->numClipRects == 0 && !ignore_cliprects) {
+ if (allow_unlock) {
+ UNLOCK_HARDWARE(intel);
+ sched_yield();
+ LOCK_HARDWARE(intel);
+ }
+// intel->vtbl.lost_hardware(intel);
+ }
+}
+
+
+struct _DriFenceObject *
+intel_batchbuffer_flush(struct intel_batchbuffer *batch)
+{
+ struct intel_context *intel = batch->intel;
+ GLuint used = batch->ptr - batch->map;
+ GLboolean was_locked = intel->locked;
+
+ if (used == 0)
+ return batch->last_fence;
+
+#define MI_FLUSH ((0<<29)|(4<<23))
+
+ /* Add the MI_BATCH_BUFFER_END. Always add an MI_FLUSH - this is a
+ * performance drain that we would like to avoid.
+ */
+ if (used & 4) {
+ ((int *) batch->ptr)[0] = MI_FLUSH;
+ ((int *) batch->ptr)[1] = 0;
+ ((int *) batch->ptr)[2] = MI_BATCH_BUFFER_END;
+ used += 12;
+ }
+ else {
+ ((int *) batch->ptr)[0] = MI_FLUSH;
+ ((int *) batch->ptr)[1] = MI_BATCH_BUFFER_END;
+ used += 8;
+ }
+
+ driBOUnmap(batch->buffer);
+ batch->ptr = NULL;
+ batch->map = NULL;
+
+ /* TODO: Just pass the relocation list and dma buffer up to the
+ * kernel.
+ */
+ if (!was_locked)
+ LOCK_HARDWARE(intel);
+
+ do_flush_locked(batch, used, !(batch->flags & INTEL_BATCH_CLIPRECTS),
+ GL_FALSE);
+
+ if (!was_locked)
+ UNLOCK_HARDWARE(intel);
+
+ /* Reset the buffer:
+ */
+ intel_batchbuffer_reset(batch);
+ return batch->last_fence;
+}
+
+void
+intel_batchbuffer_finish(struct intel_batchbuffer *batch)
+{
+ struct _DriFenceObject *fence = intel_batchbuffer_flush(batch);
+ driFenceReference(fence);
+ driFenceFinish(fence, 3, GL_FALSE);
+ driFenceUnReference(fence);
+}
+
+
+/* This is the only way buffers get added to the validate list.
+ */
+GLboolean
+intel_batchbuffer_emit_reloc(struct intel_batchbuffer *batch,
+ struct _DriBufferObject *buffer,
+ GLuint flags, GLuint mask, GLuint delta)
+{
+ assert(batch->nr_relocs < MAX_RELOCS);
+
+ driBOAddListItem(&batch->list, buffer, flags, mask);
+
+ {
+ struct buffer_reloc *r = &batch->reloc[batch->nr_relocs++];
+ driBOReference(buffer);
+ r->buf = buffer;
+ r->offset = batch->ptr - batch->map;
+ r->delta = delta;
+ }
+
+ batch->ptr += 4;
+ return GL_TRUE;
+}
+
+
+
+void
+intel_batchbuffer_data(struct intel_batchbuffer *batch,
+ const void *data, GLuint bytes, GLuint flags)
+{
+ assert((bytes & 3) == 0);
+ intel_batchbuffer_require_space(batch, bytes, flags);
+ __memcpy(batch->ptr, data, bytes);
+ batch->ptr += bytes;
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_batchbuffer.h b/src/mesa/drivers/dri/i915pipe/intel_batchbuffer.h
new file mode 100644
index 0000000000..212f130101
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_batchbuffer.h
@@ -0,0 +1,124 @@
+#ifndef INTEL_BATCHBUFFER_H
+#define INTEL_BATCHBUFFER_H
+
+#include "mtypes.h"
+#include "dri_bufmgr.h"
+
+struct intel_context;
+
+#define BATCH_SZ 16384
+#define BATCH_RESERVED 16
+
+#define MAX_RELOCS 4096
+
+#define INTEL_BATCH_NO_CLIPRECTS 0x1
+#define INTEL_BATCH_CLIPRECTS 0x2
+
+struct buffer_reloc
+{
+ struct _DriBufferObject *buf;
+ GLuint offset;
+ GLuint delta; /* not needed? */
+};
+
+struct intel_batchbuffer
+{
+ struct bufmgr *bm;
+ struct intel_context *intel;
+
+ struct _DriBufferObject *buffer;
+ struct _DriFenceObject *last_fence;
+ GLuint flags;
+
+ drmBOList list;
+ GLuint list_count;
+ GLubyte *map;
+ GLubyte *ptr;
+
+ struct buffer_reloc reloc[MAX_RELOCS];
+ GLuint nr_relocs;
+ GLuint size;
+};
+
+struct intel_batchbuffer *intel_batchbuffer_alloc(struct intel_context
+ *intel);
+
+void intel_batchbuffer_free(struct intel_batchbuffer *batch);
+
+
+void intel_batchbuffer_finish(struct intel_batchbuffer *batch);
+
+struct _DriFenceObject *intel_batchbuffer_flush(struct intel_batchbuffer
+ *batch);
+
+void intel_batchbuffer_reset(struct intel_batchbuffer *batch);
+
+
+/* Unlike bmBufferData, this currently requires the buffer be mapped.
+ * Consider it a convenience function wrapping multple
+ * intel_buffer_dword() calls.
+ */
+void intel_batchbuffer_data(struct intel_batchbuffer *batch,
+ const void *data, GLuint bytes, GLuint flags);
+
+void intel_batchbuffer_release_space(struct intel_batchbuffer *batch,
+ GLuint bytes);
+
+GLboolean intel_batchbuffer_emit_reloc(struct intel_batchbuffer *batch,
+ struct _DriBufferObject *buffer,
+ GLuint flags,
+ GLuint mask, GLuint offset);
+
+/* Inline functions - might actually be better off with these
+ * non-inlined. Certainly better off switching all command packets to
+ * be passed as structs rather than dwords, but that's a little bit of
+ * work...
+ */
+static INLINE GLuint
+intel_batchbuffer_space(struct intel_batchbuffer *batch)
+{
+ return (batch->size - BATCH_RESERVED) - (batch->ptr - batch->map);
+}
+
+
+static INLINE void
+intel_batchbuffer_emit_dword(struct intel_batchbuffer *batch, GLuint dword)
+{
+ assert(batch->map);
+ assert(intel_batchbuffer_space(batch) >= 4);
+ *(GLuint *) (batch->ptr) = dword;
+ batch->ptr += 4;
+}
+
+static INLINE void
+intel_batchbuffer_require_space(struct intel_batchbuffer *batch,
+ GLuint sz, GLuint flags)
+{
+ assert(sz < batch->size - 8);
+ if (intel_batchbuffer_space(batch) < sz ||
+ (batch->flags != 0 && flags != 0 && batch->flags != flags))
+ intel_batchbuffer_flush(batch);
+
+ batch->flags |= flags;
+}
+
+/* Here are the crusty old macros, to be removed:
+ */
+#define BATCH_LOCALS
+
+#define BEGIN_BATCH(n, flags) do { \
+ assert(!intel->prim.flush); \
+ intel_batchbuffer_require_space(intel->batch, (n)*4, flags); \
+} while (0)
+
+#define OUT_BATCH(d) intel_batchbuffer_emit_dword(intel->batch, d)
+
+#define OUT_RELOC(buf,flags,mask,delta) do { \
+ assert((delta) >= 0); \
+ intel_batchbuffer_emit_reloc(intel->batch, buf, flags, mask, delta); \
+} while (0)
+
+#define ADVANCE_BATCH() do { } while(0)
+
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_batchpool.c b/src/mesa/drivers/dri/i915pipe/intel_batchpool.c
new file mode 100644
index 0000000000..2503b8a62a
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_batchpool.c
@@ -0,0 +1,418 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include <xf86drm.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "imports.h"
+#include "glthread.h"
+#include "dri_bufpool.h"
+#include "dri_bufmgr.h"
+#include "intel_screen.h"
+
+typedef struct
+{
+ drmMMListHead head;
+ struct _BPool *parent;
+ struct _DriFenceObject *fence;
+ unsigned long start;
+ int unfenced;
+ int mapped;
+} BBuf;
+
+typedef struct _BPool
+{
+ _glthread_Mutex mutex;
+ unsigned long bufSize;
+ unsigned poolSize;
+ unsigned numFree;
+ unsigned numTot;
+ unsigned numDelayed;
+ unsigned checkDelayed;
+ drmMMListHead free;
+ drmMMListHead delayed;
+ drmMMListHead head;
+ drmBO kernelBO;
+ void *virtual;
+ BBuf *bufs;
+} BPool;
+
+
+static BPool *
+createBPool(int fd, unsigned long bufSize, unsigned numBufs, unsigned flags,
+ unsigned checkDelayed)
+{
+ BPool *p = (BPool *) malloc(sizeof(*p));
+ BBuf *buf;
+ int i;
+
+ if (!p)
+ return NULL;
+
+ p->bufs = (BBuf *) malloc(numBufs * sizeof(*p->bufs));
+ if (!p->bufs) {
+ free(p);
+ return NULL;
+ }
+
+ DRMINITLISTHEAD(&p->free);
+ DRMINITLISTHEAD(&p->head);
+ DRMINITLISTHEAD(&p->delayed);
+
+ p->numTot = numBufs;
+ p->numFree = numBufs;
+ p->bufSize = bufSize;
+ p->numDelayed = 0;
+ p->checkDelayed = checkDelayed;
+
+ _glthread_INIT_MUTEX(p->mutex);
+
+ if (drmBOCreate(fd, 0, numBufs * bufSize, 0, NULL, drm_bo_type_dc,
+ flags, DRM_BO_HINT_DONT_FENCE, &p->kernelBO)) {
+ free(p->bufs);
+ free(p);
+ return NULL;
+ }
+ if (drmBOMap(fd, &p->kernelBO, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0,
+ &p->virtual)) {
+ drmBODestroy(fd, &p->kernelBO);
+ free(p->bufs);
+ free(p);
+ return NULL;
+ }
+
+ /*
+ * We unmap the buffer so that we can validate it later. Note that this is
+ * just a synchronizing operation. The buffer will have a virtual mapping
+ * until it is destroyed.
+ */
+
+ drmBOUnmap(fd, &p->kernelBO);
+
+ buf = p->bufs;
+ for (i = 0; i < numBufs; ++i) {
+ buf->parent = p;
+ buf->fence = NULL;
+ buf->start = i * bufSize;
+ buf->mapped = 0;
+ buf->unfenced = 0;
+ DRMLISTADDTAIL(&buf->head, &p->free);
+ buf++;
+ }
+
+ return p;
+}
+
+
+static void
+pool_checkFree(BPool * p, int wait)
+{
+ drmMMListHead *list, *prev;
+ BBuf *buf;
+ int signaled = 0;
+ int i;
+
+ list = p->delayed.next;
+
+ if (p->numDelayed > 3) {
+ for (i = 0; i < p->numDelayed; i += 3) {
+ list = list->next;
+ }
+ }
+
+ prev = list->prev;
+ for (; list != &p->delayed; list = prev, prev = list->prev) {
+
+ buf = DRMLISTENTRY(BBuf, list, head);
+
+ if (!signaled) {
+ if (wait) {
+ driFenceFinish(buf->fence, DRM_FENCE_TYPE_EXE, 1);
+ signaled = 1;
+ }
+ else {
+ signaled = driFenceSignaled(buf->fence, DRM_FENCE_TYPE_EXE);
+ }
+ }
+
+ if (!signaled)
+ break;
+
+ driFenceUnReference(buf->fence);
+ buf->fence = NULL;
+ DRMLISTDEL(list);
+ p->numDelayed--;
+ DRMLISTADD(list, &p->free);
+ p->numFree++;
+ }
+}
+
+static void *
+pool_create(struct _DriBufferPool *pool,
+ unsigned long size, unsigned flags, unsigned hint,
+ unsigned alignment)
+{
+ BPool *p = (BPool *) pool->data;
+
+ drmMMListHead *item;
+
+ if (alignment && (alignment != 4096))
+ return NULL;
+
+ _glthread_LOCK_MUTEX(p->mutex);
+
+ if (p->numFree == 0)
+ pool_checkFree(p, GL_TRUE);
+
+ if (p->numFree == 0) {
+ fprintf(stderr, "Out of fixed size buffer objects\n");
+ BM_CKFATAL(-ENOMEM);
+ }
+
+ item = p->free.next;
+
+ if (item == &p->free) {
+ fprintf(stderr, "Fixed size buffer pool corruption\n");
+ }
+
+ DRMLISTDEL(item);
+ --p->numFree;
+
+ _glthread_UNLOCK_MUTEX(p->mutex);
+ return (void *) DRMLISTENTRY(BBuf, item, head);
+}
+
+
+static int
+pool_destroy(struct _DriBufferPool *pool, void *private)
+{
+ BBuf *buf = (BBuf *) private;
+ BPool *p = buf->parent;
+
+ _glthread_LOCK_MUTEX(p->mutex);
+
+ if (buf->fence) {
+ DRMLISTADDTAIL(&buf->head, &p->delayed);
+ p->numDelayed++;
+ }
+ else {
+ buf->unfenced = 0;
+ DRMLISTADD(&buf->head, &p->free);
+ p->numFree++;
+ }
+
+ if ((p->numDelayed % p->checkDelayed) == 0)
+ pool_checkFree(p, 0);
+
+ _glthread_UNLOCK_MUTEX(p->mutex);
+ return 0;
+}
+
+
+static int
+pool_map(struct _DriBufferPool *pool, void *private, unsigned flags,
+ int hint, void **virtual)
+{
+
+ BBuf *buf = (BBuf *) private;
+ BPool *p = buf->parent;
+
+ _glthread_LOCK_MUTEX(p->mutex);
+
+ /*
+ * Currently Mesa doesn't have any condition variables to resolve this
+ * cleanly in a multithreading environment.
+ * We bail out instead.
+ */
+
+ if (buf->mapped) {
+ fprintf(stderr, "Trying to map already mapped buffer object\n");
+ BM_CKFATAL(-EINVAL);
+ }
+
+#if 0
+ if (buf->unfenced && !(hint & DRM_BO_HINT_ALLOW_UNFENCED_MAP)) {
+ fprintf(stderr, "Trying to map an unfenced buffer object 0x%08x"
+ " 0x%08x %d\n", hint, flags, buf->start);
+ BM_CKFATAL(-EINVAL);
+ }
+
+#endif
+
+ if (buf->fence) {
+ _glthread_UNLOCK_MUTEX(p->mutex);
+ return -EBUSY;
+ }
+
+ buf->mapped = GL_TRUE;
+ *virtual = (unsigned char *) p->virtual + buf->start;
+ _glthread_UNLOCK_MUTEX(p->mutex);
+ return 0;
+}
+
+static int
+pool_waitIdle(struct _DriBufferPool *pool, void *private, int lazy)
+{
+ BBuf *buf = (BBuf *) private;
+ driFenceFinish(buf->fence, 0, lazy);
+ return 0;
+}
+
+static int
+pool_unmap(struct _DriBufferPool *pool, void *private)
+{
+ BBuf *buf = (BBuf *) private;
+
+ buf->mapped = 0;
+ return 0;
+}
+
+static unsigned long
+pool_offset(struct _DriBufferPool *pool, void *private)
+{
+ BBuf *buf = (BBuf *) private;
+ BPool *p = buf->parent;
+
+ return p->kernelBO.offset + buf->start;
+}
+
+static unsigned
+pool_flags(struct _DriBufferPool *pool, void *private)
+{
+ BPool *p = (BPool *) pool->data;
+
+ return p->kernelBO.flags;
+}
+
+static unsigned long
+pool_size(struct _DriBufferPool *pool, void *private)
+{
+ BPool *p = (BPool *) pool->data;
+
+ return p->bufSize;
+}
+
+
+static int
+pool_fence(struct _DriBufferPool *pool, void *private,
+ struct _DriFenceObject *fence)
+{
+ BBuf *buf = (BBuf *) private;
+ BPool *p = buf->parent;
+
+ _glthread_LOCK_MUTEX(p->mutex);
+ if (buf->fence) {
+ driFenceUnReference(buf->fence);
+ }
+ buf->fence = fence;
+ buf->unfenced = 0;
+ driFenceReference(buf->fence);
+ _glthread_UNLOCK_MUTEX(p->mutex);
+
+ return 0;
+}
+
+static drmBO *
+pool_kernel(struct _DriBufferPool *pool, void *private)
+{
+ BBuf *buf = (BBuf *) private;
+ BPool *p = buf->parent;
+
+ return &p->kernelBO;
+}
+
+static int
+pool_validate(struct _DriBufferPool *pool, void *private)
+{
+ BBuf *buf = (BBuf *) private;
+ BPool *p = buf->parent;
+ _glthread_LOCK_MUTEX(p->mutex);
+ buf->unfenced = GL_TRUE;
+ _glthread_UNLOCK_MUTEX(p->mutex);
+ return 0;
+}
+
+static void
+pool_takedown(struct _DriBufferPool *pool)
+{
+ BPool *p = (BPool *) pool->data;
+
+ /*
+ * Wait on outstanding fences.
+ */
+
+ _glthread_LOCK_MUTEX(p->mutex);
+ while ((p->numFree < p->numTot) && p->numDelayed) {
+ _glthread_UNLOCK_MUTEX(p->mutex);
+ sched_yield();
+ pool_checkFree(p, GL_TRUE);
+ _glthread_LOCK_MUTEX(p->mutex);
+ }
+
+ drmBODestroy(pool->fd, &p->kernelBO);
+ free(p->bufs);
+ _glthread_UNLOCK_MUTEX(p->mutex);
+ free(p);
+ free(pool);
+}
+
+
+struct _DriBufferPool *
+driBatchPoolInit(int fd, unsigned flags,
+ unsigned long bufSize,
+ unsigned numBufs, unsigned checkDelayed)
+{
+ struct _DriBufferPool *pool;
+
+ pool = (struct _DriBufferPool *) malloc(sizeof(*pool));
+ if (!pool)
+ return NULL;
+
+ pool->data = createBPool(fd, bufSize, numBufs, flags, checkDelayed);
+ if (!pool->data)
+ return NULL;
+
+ pool->fd = fd;
+ pool->map = &pool_map;
+ pool->unmap = &pool_unmap;
+ pool->destroy = &pool_destroy;
+ pool->offset = &pool_offset;
+ pool->flags = &pool_flags;
+ pool->size = &pool_size;
+ pool->create = &pool_create;
+ pool->fence = &pool_fence;
+ pool->kernel = &pool_kernel;
+ pool->validate = &pool_validate;
+ pool->waitIdle = &pool_waitIdle;
+ pool->setstatic = NULL;
+ pool->takeDown = &pool_takedown;
+ return pool;
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_blit.c b/src/mesa/drivers/dri/i915pipe/intel_blit.c
new file mode 100644
index 0000000000..28441f4b83
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_blit.c
@@ -0,0 +1,527 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "mtypes.h"
+#include "context.h"
+#include "enums.h"
+
+#include "intel_batchbuffer.h"
+#include "intel_blit.h"
+#include "intel_buffers.h"
+#include "intel_context.h"
+#include "intel_fbo.h"
+#include "intel_reg.h"
+#include "intel_regions.h"
+#include "vblank.h"
+
+#define FILE_DEBUG_FLAG DEBUG_BLIT
+
+/**
+ * Copy the back color buffer to the front color buffer.
+ * Used for SwapBuffers().
+ */
+void
+intelCopyBuffer(__DRIdrawablePrivate * dPriv,
+ const drm_clip_rect_t * rect)
+{
+
+ struct intel_context *intel;
+ const intelScreenPrivate *intelScreen;
+
+ DBG("%s\n", __FUNCTION__);
+
+ assert(dPriv);
+
+ intel = intelScreenContext(dPriv->driScreenPriv->private);
+ if (!intel)
+ return;
+
+ intelScreen = intel->intelScreen;
+
+ if (intel->last_swap_fence) {
+ driFenceFinish(intel->last_swap_fence, DRM_FENCE_TYPE_EXE, GL_TRUE);
+ driFenceUnReference(intel->last_swap_fence);
+ intel->last_swap_fence = NULL;
+ }
+ intel->last_swap_fence = intel->first_swap_fence;
+ intel->first_swap_fence = NULL;
+
+ /* The LOCK_HARDWARE is required for the cliprects. Buffer offsets
+ * should work regardless.
+ */
+ LOCK_HARDWARE(intel);
+ /* if this drawable isn't currently bound the LOCK_HARDWARE done on the
+ current context (which is what intelScreenContext should return) might
+ not get a contended lock and thus cliprects not updated (tests/manywin) */
+ if ((struct intel_context *)dPriv->driContextPriv->driverPrivate != intel)
+ DRI_VALIDATE_DRAWABLE_INFO(intel->driScreen, dPriv);
+
+
+ if (dPriv && dPriv->numClipRects) {
+ struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
+ const struct intel_region *frontRegion
+ = intelScreen->front_region;
+ const struct intel_region *backRegion
+ = intel_fb->Base._ColorDrawBufferMask[0] == BUFFER_BIT_FRONT_LEFT ?
+ intel_get_rb_region(&intel_fb->Base, BUFFER_FRONT_LEFT) :
+ intel_get_rb_region(&intel_fb->Base, BUFFER_BACK_LEFT);
+ const int backWidth = intel_fb->Base.Width;
+ const int backHeight = intel_fb->Base.Height;
+ const int nbox = dPriv->numClipRects;
+ const drm_clip_rect_t *pbox = dPriv->pClipRects;
+ const int pitch = frontRegion->pitch;
+ const int srcpitch = backRegion->pitch;
+ const int cpp = frontRegion->cpp;
+ int BR13, CMD;
+ int i;
+
+ ASSERT(intel_fb);
+ ASSERT(intel_fb->Base.Name == 0); /* Not a user-created FBO */
+ ASSERT(frontRegion);
+ ASSERT(backRegion);
+ ASSERT(frontRegion->cpp == backRegion->cpp);
+
+ DBG("front pitch %d back pitch %d\n",
+ frontRegion->pitch, backRegion->pitch);
+
+ if (cpp == 2) {
+ BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24);
+ CMD = XY_SRC_COPY_BLT_CMD;
+ }
+ else {
+ BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24) | (1 << 25);
+ CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ }
+
+ for (i = 0; i < nbox; i++, pbox++) {
+ drm_clip_rect_t box;
+ drm_clip_rect_t sbox;
+
+ if (pbox->x1 > pbox->x2 ||
+ pbox->y1 > pbox->y2 ||
+ pbox->x2 > intelScreen->width || pbox->y2 > intelScreen->height)
+ continue;
+
+ box = *pbox;
+
+ if (rect) {
+ drm_clip_rect_t rrect;
+
+ rrect.x1 = dPriv->x + rect->x1;
+ rrect.y1 = (dPriv->h - rect->y1 - rect->y2) + dPriv->y;
+ rrect.x2 = rect->x2 + rrect.x1;
+ rrect.y2 = rect->y2 + rrect.y1;
+ if (rrect.x1 > box.x1)
+ box.x1 = rrect.x1;
+ if (rrect.y1 > box.y1)
+ box.y1 = rrect.y1;
+ if (rrect.x2 < box.x2)
+ box.x2 = rrect.x2;
+ if (rrect.y2 < box.y2)
+ box.y2 = rrect.y2;
+
+ if (box.x1 > box.x2 || box.y1 > box.y2)
+ continue;
+ }
+
+ /* restrict blit to size of actually rendered area */
+ if (box.x2 - box.x1 > backWidth)
+ box.x2 = backWidth + box.x1;
+ if (box.y2 - box.y1 > backHeight)
+ box.y2 = backHeight + box.y1;
+
+ DBG("box x1 x2 y1 y2 %d %d %d %d\n",
+ box.x1, box.x2, box.y1, box.y2);
+
+ sbox.x1 = box.x1 - dPriv->x;
+ sbox.y1 = box.y1 - dPriv->y;
+
+ BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS);
+ OUT_BATCH(CMD);
+ OUT_BATCH(BR13);
+ OUT_BATCH((box.y1 << 16) | box.x1);
+ OUT_BATCH((box.y2 << 16) | box.x2);
+
+ OUT_RELOC(frontRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
+ DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0);
+ OUT_BATCH((sbox.y1 << 16) | sbox.x1);
+ OUT_BATCH((srcpitch * cpp) & 0xffff);
+ OUT_RELOC(backRegion->buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
+ DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0);
+
+ ADVANCE_BATCH();
+ }
+
+ if (intel->first_swap_fence)
+ driFenceUnReference(intel->first_swap_fence);
+ intel->first_swap_fence = intel_batchbuffer_flush(intel->batch);
+ driFenceReference(intel->first_swap_fence);
+ }
+
+ UNLOCK_HARDWARE(intel);
+
+ /* XXX this is bogus. The context here may not even be bound to this drawable! */
+ if (intel->lastStamp != dPriv->lastStamp) {
+ GET_CURRENT_CONTEXT(currctx);
+ struct intel_context *intelcurrent = intel_context(currctx);
+ if (intelcurrent == intel && intelcurrent->driDrawable == dPriv) {
+ intelWindowMoved(intel);
+ intel->lastStamp = dPriv->lastStamp;
+ }
+ }
+
+}
+
+
+
+
+void
+intelEmitFillBlit(struct intel_context *intel,
+ GLuint cpp,
+ GLshort dst_pitch,
+ struct _DriBufferObject *dst_buffer,
+ GLuint dst_offset,
+ GLshort x, GLshort y, GLshort w, GLshort h, GLuint color)
+{
+ GLuint BR13, CMD;
+ BATCH_LOCALS;
+
+ dst_pitch *= cpp;
+
+ switch (cpp) {
+ case 1:
+ case 2:
+ case 3:
+ BR13 = dst_pitch | (0xF0 << 16) | (1 << 24);
+ CMD = XY_COLOR_BLT_CMD;
+ break;
+ case 4:
+ BR13 = dst_pitch | (0xF0 << 16) | (1 << 24) | (1 << 25);
+ CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA |
+ XY_COLOR_BLT_WRITE_RGB);
+ break;
+ default:
+ return;
+ }
+
+ DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
+ __FUNCTION__, dst_buffer, dst_pitch, dst_offset, x, y, w, h);
+
+
+ BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS);
+ OUT_BATCH(CMD);
+ OUT_BATCH(BR13);
+ OUT_BATCH((y << 16) | x);
+ OUT_BATCH(((y + h) << 16) | (x + w));
+ OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
+ DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, dst_offset);
+ OUT_BATCH(color);
+ ADVANCE_BATCH();
+}
+
+
+static GLuint translate_raster_op(GLenum logicop)
+{
+ switch(logicop) {
+ case GL_CLEAR: return 0x00;
+ case GL_AND: return 0x88;
+ case GL_AND_REVERSE: return 0x44;
+ case GL_COPY: return 0xCC;
+ case GL_AND_INVERTED: return 0x22;
+ case GL_NOOP: return 0xAA;
+ case GL_XOR: return 0x66;
+ case GL_OR: return 0xEE;
+ case GL_NOR: return 0x11;
+ case GL_EQUIV: return 0x99;
+ case GL_INVERT: return 0x55;
+ case GL_OR_REVERSE: return 0xDD;
+ case GL_COPY_INVERTED: return 0x33;
+ case GL_OR_INVERTED: return 0xBB;
+ case GL_NAND: return 0x77;
+ case GL_SET: return 0xFF;
+ default: return 0;
+ }
+}
+
+
+/* Copy BitBlt
+ */
+void
+intelEmitCopyBlit(struct intel_context *intel,
+ GLuint cpp,
+ GLshort src_pitch,
+ struct _DriBufferObject *src_buffer,
+ GLuint src_offset,
+ GLshort dst_pitch,
+ struct _DriBufferObject *dst_buffer,
+ GLuint dst_offset,
+ GLshort src_x, GLshort src_y,
+ GLshort dst_x, GLshort dst_y,
+ GLshort w, GLshort h,
+ GLenum logic_op)
+{
+ GLuint CMD, BR13;
+ int dst_y2 = dst_y + h;
+ int dst_x2 = dst_x + w;
+ BATCH_LOCALS;
+
+
+ DBG("%s src:buf(%p)/%d+%d %d,%d dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
+ __FUNCTION__,
+ src_buffer, src_pitch, src_offset, src_x, src_y,
+ dst_buffer, dst_pitch, dst_offset, dst_x, dst_y, w, h);
+
+ src_pitch *= cpp;
+ dst_pitch *= cpp;
+
+ switch (cpp) {
+ case 1:
+ case 2:
+ case 3:
+ BR13 = (((GLint) dst_pitch) & 0xffff) |
+ (translate_raster_op(logic_op) << 16) | (1 << 24);
+ CMD = XY_SRC_COPY_BLT_CMD;
+ break;
+ case 4:
+ BR13 =
+ (((GLint) dst_pitch) & 0xffff) |
+ (translate_raster_op(logic_op) << 16) | (1 << 24) | (1 << 25);
+ CMD =
+ (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ break;
+ default:
+ return;
+ }
+
+ if (dst_y2 < dst_y || dst_x2 < dst_x) {
+ return;
+ }
+
+ /* Initial y values don't seem to work with negative pitches. If
+ * we adjust the offsets manually (below), it seems to work fine.
+ *
+ * On the other hand, if we always adjust, the hardware doesn't
+ * know which blit directions to use, so overlapping copypixels get
+ * the wrong result.
+ */
+ if (dst_pitch > 0 && src_pitch > 0) {
+ BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS);
+ OUT_BATCH(CMD);
+ OUT_BATCH(BR13);
+ OUT_BATCH((dst_y << 16) | dst_x);
+ OUT_BATCH((dst_y2 << 16) | dst_x2);
+ OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
+ DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, dst_offset);
+ OUT_BATCH((src_y << 16) | src_x);
+ OUT_BATCH(((GLint) src_pitch & 0xffff));
+ OUT_RELOC(src_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
+ DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, src_offset);
+ ADVANCE_BATCH();
+ }
+ else {
+ BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS);
+ OUT_BATCH(CMD);
+ OUT_BATCH(BR13);
+ OUT_BATCH((0 << 16) | dst_x);
+ OUT_BATCH((h << 16) | dst_x2);
+ OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
+ DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE,
+ dst_offset + dst_y * dst_pitch);
+ OUT_BATCH((0 << 16) | src_x);
+ OUT_BATCH(((GLint) src_pitch & 0xffff));
+ OUT_RELOC(src_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
+ DRM_BO_MASK_MEM | DRM_BO_FLAG_READ,
+ src_offset + src_y * src_pitch);
+ ADVANCE_BATCH();
+ }
+}
+
+
+/**
+ * Use blitting to clear the renderbuffers named by 'flags'.
+ * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferMask field
+ * since that might include software renderbuffers or renderbuffers
+ * which we're clearing with triangles.
+ * \param mask bitmask of BUFFER_BIT_* values indicating buffers to clear
+ */
+void
+intelClearWithBlit(GLcontext * ctx, GLbitfield mask)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct gl_framebuffer *fb = ctx->DrawBuffer;
+ GLuint clear_depth;
+ GLbitfield skipBuffers = 0;
+ BATCH_LOCALS;
+
+ DBG("%s %x\n", __FUNCTION__, mask);
+
+ /*
+ * Compute values for clearing the buffers.
+ */
+ clear_depth = 0;
+ if (mask & BUFFER_BIT_DEPTH) {
+ clear_depth = (GLuint) (fb->_DepthMax * ctx->Depth.Clear);
+ }
+ if (mask & BUFFER_BIT_STENCIL) {
+ clear_depth |= (ctx->Stencil.Clear & 0xff) << 24;
+ }
+
+ /* If clearing both depth and stencil, skip BUFFER_BIT_STENCIL in
+ * the loop below.
+ */
+ if ((mask & BUFFER_BIT_DEPTH) && (mask & BUFFER_BIT_STENCIL)) {
+ skipBuffers = BUFFER_BIT_STENCIL;
+ }
+
+ /* XXX Move this flush/lock into the following conditional? */
+ intelFlush(&intel->ctx);
+ LOCK_HARDWARE(intel);
+
+ if (intel->numClipRects) {
+ GLint cx, cy, cw, ch;
+ drm_clip_rect_t b;
+
+ /* Get clear bounds after locking */
+ cx = fb->_Xmin;
+ cy = fb->_Ymin;
+ cw = fb->_Xmax - cx;
+ ch = fb->_Ymax - cy;
+
+ if (fb->Name == 0) {
+ /* clearing a window */
+ /* flip top to bottom */
+ b.x1 = cx;
+ b.y1 = fb->Height - cy - ch;
+ b.x2 = b.x1 + cw;
+ b.y2 = b.y1 + ch;
+ }
+ else {
+ /* clearing FBO */
+ b.x1 = cx;
+ b.y1 = cy;
+ b.x2 = b.x1 + cw;
+ b.y2 = b.y1 + ch;
+ /* no change to mask */
+ }
+
+ {
+ GLuint buf;
+ GLuint clearMask = mask; /* use copy, since we modify it below */
+ GLboolean all = (cw == fb->Width && ch == fb->Height);
+
+ DBG("clear %d,%d..%d,%d, mask %x\n",
+ b.x1, b.y1, b.x2, b.y2, mask);
+
+ /* Loop over all renderbuffers */
+ for (buf = 0; buf < BUFFER_COUNT && clearMask; buf++) {
+ const GLbitfield bufBit = 1 << buf;
+ if ((clearMask & bufBit) && !(bufBit & skipBuffers)) {
+ /* OK, clear this renderbuffer */
+ struct intel_region *irb_region =
+ intel_get_rb_region(fb, buf);
+ struct _DriBufferObject *write_buffer =
+ intel_region_buffer(intel->intelScreen, irb_region,
+ all ? INTEL_WRITE_FULL :
+ INTEL_WRITE_PART);
+
+ GLuint clearVal;
+ GLint pitch, cpp;
+ GLuint BR13, CMD;
+
+ ASSERT(irb_region);
+
+ pitch = irb_region->pitch;
+ cpp = irb_region->cpp;
+
+ DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n",
+ __FUNCTION__,
+ irb_region->buffer, (pitch * cpp),
+ irb_region->draw_offset,
+ b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1);
+
+
+ /* Setup the blit command */
+ if (cpp == 4) {
+ BR13 = (0xF0 << 16) | (pitch * cpp) | (1 << 24) | (1 << 25);
+ if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) {
+ CMD = XY_COLOR_BLT_CMD;
+ if (clearMask & BUFFER_BIT_DEPTH)
+ CMD |= XY_COLOR_BLT_WRITE_RGB;
+ if (clearMask & BUFFER_BIT_STENCIL)
+ CMD |= XY_COLOR_BLT_WRITE_ALPHA;
+ }
+ else {
+ /* clearing RGBA */
+ CMD = (XY_COLOR_BLT_CMD |
+ XY_COLOR_BLT_WRITE_ALPHA |
+ XY_COLOR_BLT_WRITE_RGB);
+ }
+ }
+ else {
+ ASSERT(cpp == 2 || cpp == 0);
+ BR13 = (0xF0 << 16) | (pitch * cpp) | (1 << 24);
+ CMD = XY_COLOR_BLT_CMD;
+ }
+
+ if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) {
+ clearVal = clear_depth;
+ }
+ else {
+ clearVal = (cpp == 4)
+ ? intel->ClearColor8888 : intel->ClearColor565;
+ }
+ /*
+ _mesa_debug(ctx, "hardware blit clear buf %d rb id %d\n",
+ buf, irb->Base.Name);
+ */
+ intel_wait_flips(intel, INTEL_BATCH_NO_CLIPRECTS);
+
+ BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS);
+ OUT_BATCH(CMD);
+ OUT_BATCH(BR13);
+ OUT_BATCH((b.y1 << 16) | b.x1);
+ OUT_BATCH((b.y2 << 16) | b.x2);
+ OUT_RELOC(write_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE,
+ DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE,
+ irb_region->draw_offset);
+ OUT_BATCH(clearVal);
+ ADVANCE_BATCH();
+ clearMask &= ~bufBit; /* turn off bit, for faster loop exit */
+ }
+ }
+ }
+ intel_batchbuffer_flush(intel->batch);
+ }
+
+ UNLOCK_HARDWARE(intel);
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_blit.h b/src/mesa/drivers/dri/i915pipe/intel_blit.h
new file mode 100644
index 0000000000..77686444fa
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_blit.h
@@ -0,0 +1,62 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef INTEL_BLIT_H
+#define INTEL_BLIT_H
+
+#include "intel_context.h"
+#include "intel_ioctl.h"
+#include "dri_bufmgr.h"
+
+extern void intelCopyBuffer(__DRIdrawablePrivate * dpriv,
+ const drm_clip_rect_t * rect);
+
+extern void intelClearWithBlit(GLcontext * ctx, GLbitfield mask);
+
+extern void intelEmitCopyBlit(struct intel_context *intel,
+ GLuint cpp,
+ GLshort src_pitch,
+ struct _DriBufferObject *src_buffer,
+ GLuint src_offset,
+ GLshort dst_pitch,
+ struct _DriBufferObject *dst_buffer,
+ GLuint dst_offset,
+ GLshort srcx, GLshort srcy,
+ GLshort dstx, GLshort dsty,
+ GLshort w, GLshort h,
+ GLenum logicop );
+
+extern void intelEmitFillBlit(struct intel_context *intel,
+ GLuint cpp,
+ GLshort dst_pitch,
+ struct _DriBufferObject *dst_buffer,
+ GLuint dst_offset,
+ GLshort x, GLshort y,
+ GLshort w, GLshort h, GLuint color);
+
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_buffer_objects.c b/src/mesa/drivers/dri/i915pipe/intel_buffer_objects.c
new file mode 100644
index 0000000000..91c45ad95b
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_buffer_objects.c
@@ -0,0 +1,257 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "imports.h"
+#include "mtypes.h"
+#include "bufferobj.h"
+
+#include "intel_context.h"
+#include "intel_buffer_objects.h"
+#include "intel_regions.h"
+#include "dri_bufmgr.h"
+
+/**
+ * There is some duplication between mesa's bufferobjects and our
+ * bufmgr buffers. Both have an integer handle and a hashtable to
+ * lookup an opaque structure. It would be nice if the handles and
+ * internal structure where somehow shared.
+ */
+static struct gl_buffer_object *
+intel_bufferobj_alloc(GLcontext * ctx, GLuint name, GLenum target)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_buffer_object *obj = CALLOC_STRUCT(intel_buffer_object);
+
+ _mesa_initialize_buffer_object(&obj->Base, name, target);
+
+ driGenBuffers(intel->intelScreen->regionPool,
+ "bufferobj", 1, &obj->buffer, 64,
+ DRM_BO_FLAG_MEM_LOCAL |
+ DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE,
+ 0);
+
+ return &obj->Base;
+}
+
+
+/* Break the COW tie to the region. The region gets to keep the data.
+ */
+void
+intel_bufferobj_release_region(struct intel_context *intel,
+ struct intel_buffer_object *intel_obj)
+{
+ assert(intel_obj->region->buffer == intel_obj->buffer);
+ intel_obj->region->pbo = NULL;
+ intel_obj->region = NULL;
+ driBOUnReference(intel_obj->buffer);
+ intel_obj->buffer = NULL;
+
+ /* This leads to a large number of buffer deletion/creation events.
+ * Currently the drm doesn't like that:
+ */
+ driGenBuffers(intel->intelScreen->regionPool,
+ "buffer object", 1, &intel_obj->buffer, 64, 0, 0);
+ LOCK_HARDWARE(intel);
+ driBOData(intel_obj->buffer, intel_obj->Base.Size, NULL, 0);
+ UNLOCK_HARDWARE(intel);
+}
+
+/* Break the COW tie to the region. Both the pbo and the region end
+ * up with a copy of the data.
+ */
+void
+intel_bufferobj_cow(struct intel_context *intel,
+ struct intel_buffer_object *intel_obj)
+{
+ assert(intel_obj->region);
+ intel_region_cow(intel->intelScreen, intel_obj->region);
+}
+
+
+/**
+ * Deallocate/free a vertex/pixel buffer object.
+ * Called via glDeleteBuffersARB().
+ */
+static void
+intel_bufferobj_free(GLcontext * ctx, struct gl_buffer_object *obj)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
+
+ assert(intel_obj);
+
+ if (intel_obj->region) {
+ intel_bufferobj_release_region(intel, intel_obj);
+ }
+ else if (intel_obj->buffer) {
+ driDeleteBuffers(1, &intel_obj->buffer);
+ }
+
+ _mesa_free(intel_obj);
+}
+
+
+
+/**
+ * Allocate space for and store data in a buffer object. Any data that was
+ * previously stored in the buffer object is lost. If data is NULL,
+ * memory will be allocated, but no copy will occur.
+ * Called via glBufferDataARB().
+ */
+static void
+intel_bufferobj_data(GLcontext * ctx,
+ GLenum target,
+ GLsizeiptrARB size,
+ const GLvoid * data,
+ GLenum usage, struct gl_buffer_object *obj)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
+
+ intel_obj->Base.Size = size;
+ intel_obj->Base.Usage = usage;
+
+ if (intel_obj->region)
+ intel_bufferobj_release_region(intel, intel_obj);
+
+ LOCK_HARDWARE(intel);
+ driBOData(intel_obj->buffer, size, data, 0);
+ UNLOCK_HARDWARE(intel);
+}
+
+
+/**
+ * Replace data in a subrange of buffer object. If the data range
+ * specified by size + offset extends beyond the end of the buffer or
+ * if data is NULL, no copy is performed.
+ * Called via glBufferSubDataARB().
+ */
+static void
+intel_bufferobj_subdata(GLcontext * ctx,
+ GLenum target,
+ GLintptrARB offset,
+ GLsizeiptrARB size,
+ const GLvoid * data, struct gl_buffer_object *obj)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
+
+ assert(intel_obj);
+
+ if (intel_obj->region)
+ intel_bufferobj_cow(intel, intel_obj);
+
+ driBOSubData(intel_obj->buffer, offset, size, data);
+}
+
+
+/**
+ * Called via glGetBufferSubDataARB().
+ */
+static void
+intel_bufferobj_get_subdata(GLcontext * ctx,
+ GLenum target,
+ GLintptrARB offset,
+ GLsizeiptrARB size,
+ GLvoid * data, struct gl_buffer_object *obj)
+{
+ struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
+
+ assert(intel_obj);
+ driBOGetSubData(intel_obj->buffer, offset, size, data);
+}
+
+
+
+/**
+ * Called via glMapBufferARB().
+ */
+static void *
+intel_bufferobj_map(GLcontext * ctx,
+ GLenum target,
+ GLenum access, struct gl_buffer_object *obj)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
+
+ /* XXX: Translate access to flags arg below:
+ */
+ assert(intel_obj);
+
+ if (intel_obj->region)
+ intel_bufferobj_cow(intel, intel_obj);
+
+ obj->Pointer = driBOMap(intel_obj->buffer,
+ DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0);
+ return obj->Pointer;
+}
+
+
+/**
+ * Called via glMapBufferARB().
+ */
+static GLboolean
+intel_bufferobj_unmap(GLcontext * ctx,
+ GLenum target, struct gl_buffer_object *obj)
+{
+ struct intel_buffer_object *intel_obj = intel_buffer_object(obj);
+
+ assert(intel_obj);
+ assert(obj->Pointer);
+ driBOUnmap(intel_obj->buffer);
+ obj->Pointer = NULL;
+ return GL_TRUE;
+}
+
+struct _DriBufferObject *
+intel_bufferobj_buffer(struct intel_context *intel,
+ struct intel_buffer_object *intel_obj, GLuint flag)
+{
+ if (intel_obj->region) {
+ if (flag == INTEL_WRITE_PART)
+ intel_bufferobj_cow(intel, intel_obj);
+ else if (flag == INTEL_WRITE_FULL)
+ intel_bufferobj_release_region(intel, intel_obj);
+ }
+
+ return intel_obj->buffer;
+}
+
+void
+intel_bufferobj_init(struct intel_context *intel)
+{
+ GLcontext *ctx = &intel->ctx;
+
+ ctx->Driver.NewBufferObject = intel_bufferobj_alloc;
+ ctx->Driver.DeleteBuffer = intel_bufferobj_free;
+ ctx->Driver.BufferData = intel_bufferobj_data;
+ ctx->Driver.BufferSubData = intel_bufferobj_subdata;
+ ctx->Driver.GetBufferSubData = intel_bufferobj_get_subdata;
+ ctx->Driver.MapBuffer = intel_bufferobj_map;
+ ctx->Driver.UnmapBuffer = intel_bufferobj_unmap;
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_buffer_objects.h b/src/mesa/drivers/dri/i915pipe/intel_buffer_objects.h
new file mode 100644
index 0000000000..afe9b2f7cf
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_buffer_objects.h
@@ -0,0 +1,86 @@
+ /**************************************************************************
+ *
+ * Copyright 2005 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef INTEL_BUFFEROBJ_H
+#define INTEL_BUFFEROBJ_H
+
+#include "mtypes.h"
+
+struct intel_context;
+struct intel_region;
+struct gl_buffer_object;
+
+
+/**
+ * Intel vertex/pixel buffer object, derived from Mesa's gl_buffer_object.
+ */
+struct intel_buffer_object
+{
+ struct gl_buffer_object Base;
+ struct _DriBufferObject *buffer; /* the low-level buffer manager's buffer handle */
+
+ struct intel_region *region; /* Is there a zero-copy texture
+ associated with this (pixel)
+ buffer object? */
+};
+
+
+/* Get the bm buffer associated with a GL bufferobject:
+ */
+struct _DriBufferObject *intel_bufferobj_buffer(struct intel_context *intel,
+ struct intel_buffer_object
+ *obj, GLuint flag);
+
+/* Hook the bufferobject implementation into mesa:
+ */
+void intel_bufferobj_init(struct intel_context *intel);
+
+
+
+/* Are the obj->Name tests necessary? Unfortunately yes, mesa
+ * allocates a couple of gl_buffer_object structs statically, and
+ * the Name == 0 test is the only way to identify them and avoid
+ * casting them erroneously to our structs.
+ */
+static INLINE struct intel_buffer_object *
+intel_buffer_object(struct gl_buffer_object *obj)
+{
+ if (obj->Name)
+ return (struct intel_buffer_object *) obj;
+ else
+ return NULL;
+}
+
+/* Helpers for zerocopy image uploads. See also intel_regions.h:
+ */
+void intel_bufferobj_cow(struct intel_context *intel,
+ struct intel_buffer_object *intel_obj);
+void intel_bufferobj_release_region(struct intel_context *intel,
+ struct intel_buffer_object *intel_obj);
+
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_buffers.c b/src/mesa/drivers/dri/i915pipe/intel_buffers.c
new file mode 100644
index 0000000000..7684e36e3b
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_buffers.c
@@ -0,0 +1,792 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "intel_screen.h"
+#include "intel_context.h"
+#include "intel_blit.h"
+#include "intel_buffers.h"
+#include "intel_depthstencil.h"
+#include "intel_fbo.h"
+#include "intel_tris.h"
+#include "intel_regions.h"
+#include "intel_batchbuffer.h"
+#include "intel_reg.h"
+#include "context.h"
+#include "utils.h"
+#include "drirenderbuffer.h"
+#include "framebuffer.h"
+#include "swrast/swrast.h"
+#include "vblank.h"
+
+
+/* This block can be removed when libdrm >= 2.3.1 is required */
+
+#ifndef DRM_VBLANK_FLIP
+
+#define DRM_VBLANK_FLIP 0x8000000
+
+typedef struct drm_i915_flip {
+ int pipes;
+} drm_i915_flip_t;
+
+#undef DRM_IOCTL_I915_FLIP
+#define DRM_IOCTL_I915_FLIP DRM_IOW(DRM_COMMAND_BASE + DRM_I915_FLIP, \
+ drm_i915_flip_t)
+
+#endif
+
+
+/**
+ * XXX move this into a new dri/common/cliprects.c file.
+ */
+GLboolean
+intel_intersect_cliprects(drm_clip_rect_t * dst,
+ const drm_clip_rect_t * a,
+ const drm_clip_rect_t * b)
+{
+ GLint bx = b->x1;
+ GLint by = b->y1;
+ GLint bw = b->x2 - bx;
+ GLint bh = b->y2 - by;
+
+ if (bx < a->x1)
+ bw -= a->x1 - bx, bx = a->x1;
+ if (by < a->y1)
+ bh -= a->y1 - by, by = a->y1;
+ if (bx + bw > a->x2)
+ bw = a->x2 - bx;
+ if (by + bh > a->y2)
+ bh = a->y2 - by;
+ if (bw <= 0)
+ return GL_FALSE;
+ if (bh <= 0)
+ return GL_FALSE;
+
+ dst->x1 = bx;
+ dst->y1 = by;
+ dst->x2 = bx + bw;
+ dst->y2 = by + bh;
+
+ return GL_TRUE;
+}
+
+/**
+ * Return pointer to current color drawing region, or NULL.
+ */
+struct intel_region *
+intel_drawbuf_region(struct intel_context *intel)
+{
+ struct intel_renderbuffer *irbColor =
+ intel_renderbuffer(intel->ctx.DrawBuffer->_ColorDrawBuffers[0][0]);
+ if (irbColor)
+ return irbColor->region;
+ else
+ return NULL;
+}
+
+/**
+ * Return pointer to current color reading region, or NULL.
+ */
+struct intel_region *
+intel_readbuf_region(struct intel_context *intel)
+{
+ struct intel_renderbuffer *irb
+ = intel_renderbuffer(intel->ctx.ReadBuffer->_ColorReadBuffer);
+ if (irb)
+ return irb->region;
+ else
+ return NULL;
+}
+
+
+
+/**
+ * Update the following fields for rendering:
+ * intel->numClipRects
+ * intel->pClipRects
+ */
+static void
+intelSetRenderbufferClipRects(struct intel_context *intel)
+{
+ /* zero-sized buffers might be legal? */
+ assert(intel->ctx.DrawBuffer->Width > 0);
+ assert(intel->ctx.DrawBuffer->Height > 0);
+ intel->fboRect.x1 = 0;
+ intel->fboRect.y1 = 0;
+ intel->fboRect.x2 = intel->ctx.DrawBuffer->Width;
+ intel->fboRect.y2 = intel->ctx.DrawBuffer->Height;
+ intel->numClipRects = 1;
+ intel->pClipRects = &intel->fboRect;
+}
+
+
+/**
+ * This will be called whenever the currently bound window is moved/resized.
+ * XXX: actually, it seems to NOT be called when the window is only moved (BP).
+ */
+void
+intelWindowMoved(struct intel_context *intel)
+{
+ GLcontext *ctx = &intel->ctx;
+ __DRIdrawablePrivate *dPriv = intel->driDrawable;
+ struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
+
+ if (!intel->ctx.DrawBuffer) {
+ /* when would this happen? -BP */
+ assert(0);
+ intel->numClipRects = 0;
+ }
+
+ /* Update Mesa's notion of window size */
+ driUpdateFramebufferSize(ctx, dPriv);
+ intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */
+
+ {
+ drmI830Sarea *sarea = intel->sarea;
+ drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w,
+ .y1 = dPriv->y, .y2 = dPriv->y + dPriv->h };
+ drm_clip_rect_t pipeA_rect = { .x1 = sarea->pipeA_x, .y1 = sarea->pipeA_y,
+ .x2 = sarea->pipeA_x + sarea->pipeA_w,
+ .y2 = sarea->pipeA_y + sarea->pipeA_h };
+ drm_clip_rect_t pipeB_rect = { .x1 = sarea->pipeB_x, .y1 = sarea->pipeB_y,
+ .x2 = sarea->pipeB_x + sarea->pipeB_w,
+ .y2 = sarea->pipeB_y + sarea->pipeB_h };
+ GLint areaA = driIntersectArea( drw_rect, pipeA_rect );
+ GLint areaB = driIntersectArea( drw_rect, pipeB_rect );
+ GLuint flags = intel_fb->vblank_flags;
+ GLboolean pf_active;
+ GLint pf_pipes;
+
+ /* Update page flipping info
+ */
+ pf_pipes = 0;
+
+ if (areaA > 0)
+ pf_pipes |= 1;
+
+ if (areaB > 0)
+ pf_pipes |= 2;
+
+ intel_fb->pf_current_page = (intel->sarea->pf_current_page >>
+ (intel_fb->pf_pipes & 0x2)) & 0x3;
+
+ intel_fb->pf_num_pages = 2 /*intel->intelScreen->third.handle ? 3 : 2*/;
+
+ pf_active = pf_pipes && (pf_pipes & intel->sarea->pf_active) == pf_pipes;
+
+ if (INTEL_DEBUG & DEBUG_LOCK)
+ if (pf_active != intel_fb->pf_active)
+ _mesa_printf("%s - Page flipping %sactive\n", __progname,
+ pf_active ? "" : "in");
+
+ if (pf_active) {
+ /* Sync pages between pipes if we're flipping on both at the same time */
+ if (pf_pipes == 0x3 && pf_pipes != intel_fb->pf_pipes &&
+ (intel->sarea->pf_current_page & 0x3) !=
+ (((intel->sarea->pf_current_page) >> 2) & 0x3)) {
+ drm_i915_flip_t flip;
+
+ if (intel_fb->pf_current_page ==
+ (intel->sarea->pf_current_page & 0x3)) {
+ /* XXX: This is ugly, but emitting two flips 'in a row' can cause
+ * lockups for unknown reasons.
+ */
+ intel->sarea->pf_current_page =
+ intel->sarea->pf_current_page & 0x3;
+ intel->sarea->pf_current_page |=
+ ((intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) %
+ intel_fb->pf_num_pages) << 2;
+
+ flip.pipes = 0x2;
+ } else {
+ intel->sarea->pf_current_page =
+ intel->sarea->pf_current_page & (0x3 << 2);
+ intel->sarea->pf_current_page |=
+ (intel_fb->pf_current_page + intel_fb->pf_num_pages - 1) %
+ intel_fb->pf_num_pages;
+
+ flip.pipes = 0x1;
+ }
+
+ drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip));
+ }
+
+ intel_fb->pf_pipes = pf_pipes;
+ }
+
+ intel_fb->pf_active = pf_active;
+ intel_flip_renderbuffers(intel_fb);
+ intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
+
+ /* Update vblank info
+ */
+ if (areaB > areaA || (areaA == areaB && areaB > 0)) {
+ flags = intel_fb->vblank_flags | VBLANK_FLAG_SECONDARY;
+ } else {
+ flags = intel_fb->vblank_flags & ~VBLANK_FLAG_SECONDARY;
+ }
+
+ if (flags != intel_fb->vblank_flags && intel_fb->vblank_flags &&
+ !(intel_fb->vblank_flags & VBLANK_FLAG_NO_IRQ)) {
+ drmVBlank vbl;
+ int i;
+
+ vbl.request.type = DRM_VBLANK_ABSOLUTE;
+
+ if ( intel_fb->vblank_flags & VBLANK_FLAG_SECONDARY ) {
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ }
+
+ for (i = 0; i < intel_fb->pf_num_pages; i++) {
+ if (!intel_fb->color_rb[i] ||
+ (intel_fb->vbl_waited - intel_fb->color_rb[i]->vbl_pending) <=
+ (1<<23))
+ continue;
+
+ vbl.request.sequence = intel_fb->color_rb[i]->vbl_pending;
+ drmWaitVBlank(intel->driFd, &vbl);
+ }
+
+ intel_fb->vblank_flags = flags;
+ driGetCurrentVBlank(dPriv, intel_fb->vblank_flags, &intel_fb->vbl_seq);
+ intel_fb->vbl_waited = intel_fb->vbl_seq;
+
+ for (i = 0; i < intel_fb->pf_num_pages; i++) {
+ if (intel_fb->color_rb[i])
+ intel_fb->color_rb[i]->vbl_pending = intel_fb->vbl_waited;
+ }
+ }
+ }
+
+ /* This will be picked up by looking at the dirty state flags:
+ */
+
+ /* Update hardware scissor */
+// ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
+// ctx->Scissor.Width, ctx->Scissor.Height);
+
+ /* Re-calculate viewport related state */
+// ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far );
+}
+
+
+
+
+
+/**
+ * Called by ctx->Driver.Clear.
+ */
+static void
+intelClear(GLcontext *ctx, GLbitfield mask)
+{
+ const GLuint colorMask = *((GLuint *) & ctx->Color.ColorMask);
+ GLbitfield tri_mask = 0;
+ GLbitfield blit_mask = 0;
+ GLbitfield swrast_mask = 0;
+ struct gl_framebuffer *fb = ctx->DrawBuffer;
+ GLuint i;
+
+ if (0)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ /* HW color buffers (front, back, aux, generic FBO, etc) */
+ if (colorMask == ~0) {
+ /* clear all R,G,B,A */
+ /* XXX FBO: need to check if colorbuffers are software RBOs! */
+ blit_mask |= (mask & BUFFER_BITS_COLOR);
+ }
+ else {
+ /* glColorMask in effect */
+ tri_mask |= (mask & BUFFER_BITS_COLOR);
+ }
+
+ /* HW stencil */
+ if (mask & BUFFER_BIT_STENCIL) {
+ const struct intel_region *stencilRegion
+ = intel_get_rb_region(fb, BUFFER_STENCIL);
+ if (stencilRegion) {
+ /* have hw stencil */
+ if ((ctx->Stencil.WriteMask[0] & 0xff) != 0xff) {
+ /* not clearing all stencil bits, so use triangle clearing */
+ tri_mask |= BUFFER_BIT_STENCIL;
+ }
+ else {
+ /* clearing all stencil bits, use blitting */
+ blit_mask |= BUFFER_BIT_STENCIL;
+ }
+ }
+ }
+
+ /* HW depth */
+ if (mask & BUFFER_BIT_DEPTH) {
+ /* clear depth with whatever method is used for stencil (see above) */
+ if (tri_mask & BUFFER_BIT_STENCIL)
+ tri_mask |= BUFFER_BIT_DEPTH;
+ else
+ blit_mask |= BUFFER_BIT_DEPTH;
+ }
+
+ /* SW fallback clearing */
+ swrast_mask = mask & ~tri_mask & ~blit_mask;
+
+ for (i = 0; i < BUFFER_COUNT; i++) {
+ GLuint bufBit = 1 << i;
+ if ((blit_mask | tri_mask) & bufBit) {
+ if (!fb->Attachment[i].Renderbuffer->ClassID) {
+ blit_mask &= ~bufBit;
+ tri_mask &= ~bufBit;
+ swrast_mask |= bufBit;
+ }
+ }
+ }
+
+
+ intelFlush(ctx); /* XXX intelClearWithBlit also does this */
+
+ if (blit_mask)
+ intelClearWithBlit(ctx, blit_mask);
+
+ if (swrast_mask | tri_mask)
+ _swrast_Clear(ctx, swrast_mask | tri_mask);
+}
+
+
+/* Emit wait for pending flips */
+void
+intel_wait_flips(struct intel_context *intel, GLuint batch_flags)
+{
+ struct intel_framebuffer *intel_fb =
+ (struct intel_framebuffer *) intel->ctx.DrawBuffer;
+ struct intel_renderbuffer *intel_rb =
+ intel_get_renderbuffer(&intel_fb->Base,
+ intel_fb->Base._ColorDrawBufferMask[0] ==
+ BUFFER_BIT_FRONT_LEFT ? BUFFER_FRONT_LEFT :
+ BUFFER_BACK_LEFT);
+
+ if (intel_fb->Base.Name == 0 && intel_rb->pf_pending == intel_fb->pf_seq) {
+ GLint pf_pipes = intel_fb->pf_pipes;
+ BATCH_LOCALS;
+
+ /* Wait for pending flips to take effect */
+ BEGIN_BATCH(2, batch_flags);
+ OUT_BATCH(pf_pipes & 0x1 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP)
+ : 0);
+ OUT_BATCH(pf_pipes & 0x2 ? (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_B_FLIP)
+ : 0);
+ ADVANCE_BATCH();
+
+ intel_rb->pf_pending--;
+ }
+}
+
+#if 0
+/* Flip the front & back buffers
+ */
+static GLboolean
+intelPageFlip(const __DRIdrawablePrivate * dPriv)
+{
+ struct intel_context *intel;
+ int ret;
+ struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
+
+ if (INTEL_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ assert(dPriv);
+ assert(dPriv->driContextPriv);
+ assert(dPriv->driContextPriv->driverPrivate);
+
+ intel = (struct intel_context *) dPriv->driContextPriv->driverPrivate;
+
+ if (intel->intelScreen->drmMinor < 9)
+ return GL_FALSE;
+
+ intelFlush(&intel->ctx);
+
+ ret = 0;
+
+ LOCK_HARDWARE(intel);
+
+ if (dPriv->numClipRects && intel_fb->pf_active) {
+ drm_i915_flip_t flip;
+
+ flip.pipes = intel_fb->pf_pipes;
+
+ ret = drmCommandWrite(intel->driFd, DRM_I915_FLIP, &flip, sizeof(flip));
+ }
+
+ UNLOCK_HARDWARE(intel);
+
+ if (ret || !intel_fb->pf_active)
+ return GL_FALSE;
+
+ if (!dPriv->numClipRects) {
+ usleep(10000); /* throttle invisible client 10ms */
+ }
+
+ intel_fb->pf_current_page = (intel->sarea->pf_current_page >>
+ (intel_fb->pf_pipes & 0x2)) & 0x3;
+
+ if (dPriv->numClipRects != 0) {
+ intel_get_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT)->pf_pending =
+ intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->pf_pending =
+ ++intel_fb->pf_seq;
+ }
+
+ intel_flip_renderbuffers(intel_fb);
+ intel_draw_buffer(&intel->ctx, &intel_fb->Base);
+
+ if (INTEL_DEBUG & DEBUG_IOCTL)
+ fprintf(stderr, "%s: success\n", __FUNCTION__);
+
+ return GL_TRUE;
+}
+#endif
+
+
+static GLboolean
+intelScheduleSwap(const __DRIdrawablePrivate * dPriv, GLboolean *missed_target)
+{
+ struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
+ unsigned int interval = driGetVBlankInterval(dPriv, intel_fb->vblank_flags);
+ struct intel_context *intel =
+ intelScreenContext(dPriv->driScreenPriv->private);
+ const intelScreenPrivate *intelScreen = intel->intelScreen;
+ unsigned int target;
+ drm_i915_vblank_swap_t swap;
+ GLboolean ret;
+
+ if (!intel_fb->vblank_flags ||
+ (intel_fb->vblank_flags & VBLANK_FLAG_NO_IRQ) ||
+ intelScreen->drmMinor < (intel_fb->pf_active ? 9 : 6))
+ return GL_FALSE;
+
+ swap.seqtype = DRM_VBLANK_ABSOLUTE;
+
+ if (intel_fb->vblank_flags & VBLANK_FLAG_SYNC) {
+ swap.seqtype |= DRM_VBLANK_NEXTONMISS;
+ } else if (interval == 0) {
+ return GL_FALSE;
+ }
+
+ swap.drawable = dPriv->hHWDrawable;
+ target = swap.sequence = intel_fb->vbl_seq + interval;
+
+ if ( intel_fb->vblank_flags & VBLANK_FLAG_SECONDARY ) {
+ swap.seqtype |= DRM_VBLANK_SECONDARY;
+ }
+
+ LOCK_HARDWARE(intel);
+
+ intel_batchbuffer_flush(intel->batch);
+
+ if ( intel_fb->pf_active ) {
+ swap.seqtype |= DRM_VBLANK_FLIP;
+
+ intel_fb->pf_current_page = (((intel->sarea->pf_current_page >>
+ (intel_fb->pf_pipes & 0x2)) & 0x3) + 1) %
+ intel_fb->pf_num_pages;
+ }
+
+ if (!drmCommandWriteRead(intel->driFd, DRM_I915_VBLANK_SWAP, &swap,
+ sizeof(swap))) {
+ intel_fb->vbl_seq = swap.sequence;
+ swap.sequence -= target;
+ *missed_target = swap.sequence > 0 && swap.sequence <= (1 << 23);
+
+ intel_get_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT)->vbl_pending =
+ intel_get_renderbuffer(&intel_fb->Base,
+ BUFFER_FRONT_LEFT)->vbl_pending =
+ intel_fb->vbl_seq;
+
+ if (swap.seqtype & DRM_VBLANK_FLIP) {
+ intel_flip_renderbuffers(intel_fb);
+ intel_draw_buffer(&intel->ctx, intel->ctx.DrawBuffer);
+ }
+
+ ret = GL_TRUE;
+ } else {
+ if (swap.seqtype & DRM_VBLANK_FLIP) {
+ intel_fb->pf_current_page = ((intel->sarea->pf_current_page >>
+ (intel_fb->pf_pipes & 0x2)) & 0x3) %
+ intel_fb->pf_num_pages;
+ }
+
+ ret = GL_FALSE;
+ }
+
+ UNLOCK_HARDWARE(intel);
+
+ return ret;
+}
+
+void
+intelSwapBuffers(__DRIdrawablePrivate * dPriv)
+{
+ if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
+ GET_CURRENT_CONTEXT(ctx);
+ struct intel_context *intel;
+
+ if (ctx == NULL)
+ return;
+
+ intel = intel_context(ctx);
+
+ if (ctx->Visual.doubleBufferMode) {
+ GLboolean missed_target;
+ struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
+ int64_t ust;
+
+ _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */
+
+ if (!intelScheduleSwap(dPriv, &missed_target)) {
+ driWaitForVBlank(dPriv, &intel_fb->vbl_seq, intel_fb->vblank_flags,
+ &missed_target);
+
+ intelCopyBuffer(dPriv, NULL);
+ }
+
+ intel_fb->swap_count++;
+ (*dri_interface->getUST) (&ust);
+ if (missed_target) {
+ intel_fb->swap_missed_count++;
+ intel_fb->swap_missed_ust = ust - intel_fb->swap_ust;
+ }
+
+ intel_fb->swap_ust = ust;
+ }
+ }
+ else {
+ /* XXX this shouldn't be an error but we can't handle it for now */
+ fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
+ }
+}
+
+void
+intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h)
+{
+ if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
+ struct intel_context *intel =
+ (struct intel_context *) dPriv->driContextPriv->driverPrivate;
+ GLcontext *ctx = &intel->ctx;
+
+ if (ctx->Visual.doubleBufferMode) {
+ drm_clip_rect_t rect;
+ /* fixup cliprect (driDrawable may have changed?) later */
+ rect.x1 = x;
+ rect.y1 = y;
+ rect.x2 = w;
+ rect.y2 = h;
+ _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */
+ intelCopyBuffer(dPriv, &rect);
+ }
+ }
+ else {
+ /* XXX this shouldn't be an error but we can't handle it for now */
+ fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__);
+ }
+}
+
+
+/**
+ * Update the hardware state for drawing into a window or framebuffer object.
+ *
+ * Called by glDrawBuffer, glBindFramebufferEXT, MakeCurrent, and other
+ * places within the driver.
+ *
+ * Basically, this needs to be called any time the current framebuffer
+ * changes, the renderbuffers change, or we need to draw into different
+ * color buffers.
+ */
+void
+intel_draw_buffer(GLcontext * ctx, struct gl_framebuffer *fb)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_region *colorRegion, *depthRegion = NULL;
+ struct intel_renderbuffer *irbDepth = NULL, *irbStencil = NULL;
+
+ if (!fb) {
+ /* this can happen during the initial context initialization */
+ return;
+ }
+
+ /* Do this here, not core Mesa, since this function is called from
+ * many places within the driver.
+ */
+ if (ctx->NewState & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) {
+ /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */
+ _mesa_update_framebuffer(ctx);
+ /* this updates the DrawBuffer's Width/Height if it's a FBO */
+ _mesa_update_draw_buffer_bounds(ctx);
+ }
+
+ if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ /* this may occur when we're called by glBindFrameBuffer() during
+ * the process of someone setting up renderbuffers, etc.
+ */
+ /*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/
+ return;
+ }
+
+ if (fb->Name)
+ intel_validate_paired_depth_stencil(ctx, fb);
+
+ /*
+ * How many color buffers are we drawing into?
+ */
+ if (fb->_NumColorDrawBuffers[0] != 1) {
+ /* writing to 0 or 2 or 4 color buffers */
+ /*_mesa_debug(ctx, "Software rendering\n");*/
+ FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE);
+ }
+ else {
+ /* draw to exactly one color buffer */
+ /*_mesa_debug(ctx, "Hardware rendering\n");*/
+ FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE);
+ }
+
+ /*
+ * Get the intel_renderbuffer for the colorbuffer we're drawing into.
+ * And set up cliprects.
+ */
+ {
+ struct intel_renderbuffer *irb;
+ intelSetRenderbufferClipRects(intel);
+ irb = intel_renderbuffer(fb->_ColorDrawBuffers[0][0]);
+ colorRegion = (irb && irb->region) ? irb->region : NULL;
+ }
+
+ /* Update culling direction which changes depending on the
+ * orientation of the buffer:
+ */
+ if (ctx->Driver.FrontFace)
+ ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
+ else
+ ctx->NewState |= _NEW_POLYGON;
+
+ if (!colorRegion) {
+ FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE);
+ }
+ else {
+ FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE);
+ }
+
+ /***
+ *** Get depth buffer region and check if we need a software fallback.
+ *** Note that the depth buffer is usually a DEPTH_STENCIL buffer.
+ ***/
+ if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) {
+ irbDepth = intel_renderbuffer(fb->_DepthBuffer->Wrapped);
+ if (irbDepth && irbDepth->region) {
+ FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE);
+ depthRegion = irbDepth->region;
+ }
+ else {
+ FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_TRUE);
+ depthRegion = NULL;
+ }
+ }
+ else {
+ /* not using depth buffer */
+ FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE);
+ depthRegion = NULL;
+ }
+
+ /***
+ *** Stencil buffer
+ *** This can only be hardware accelerated if we're using a
+ *** combined DEPTH_STENCIL buffer (for now anyway).
+ ***/
+ if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) {
+ irbStencil = intel_renderbuffer(fb->_StencilBuffer->Wrapped);
+ if (irbStencil && irbStencil->region) {
+ ASSERT(irbStencil->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE);
+ /* need to re-compute stencil hw state */
+// ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled);
+ if (!depthRegion)
+ depthRegion = irbStencil->region;
+ }
+ else {
+ FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_TRUE);
+ }
+ }
+ else {
+ /* XXX FBO: instead of FALSE, pass ctx->Stencil.Enabled ??? */
+ FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE);
+ /* need to re-compute stencil hw state */
+// ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled);
+ }
+
+
+ /**
+ ** Release old regions, reference new regions
+ **/
+
+ // intel->vtbl.set_draw_region(intel, colorRegion, depthRegion);
+
+ /* update viewport since it depends on window size */
+// ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y,
+// ctx->Viewport.Width, ctx->Viewport.Height);
+
+ /* Update hardware scissor */
+// ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
+// ctx->Scissor.Width, ctx->Scissor.Height);
+}
+
+
+static void
+intelDrawBuffer(GLcontext * ctx, GLenum mode)
+{
+ intel_draw_buffer(ctx, ctx->DrawBuffer);
+}
+
+
+static void
+intelReadBuffer(GLcontext * ctx, GLenum mode)
+{
+ if (ctx->ReadBuffer == ctx->DrawBuffer) {
+ /* This will update FBO completeness status.
+ * A framebuffer will be incomplete if the GL_READ_BUFFER setting
+ * refers to a missing renderbuffer. Calling glReadBuffer can set
+ * that straight and can make the drawing buffer complete.
+ */
+ intel_draw_buffer(ctx, ctx->DrawBuffer);
+ }
+ /* Generally, functions which read pixels (glReadPixels, glCopyPixels, etc)
+ * reference ctx->ReadBuffer and do appropriate state checks.
+ */
+}
+
+
+void
+intelInitBufferFuncs(struct dd_function_table *functions)
+{
+ functions->Clear = intelClear;
+ functions->DrawBuffer = intelDrawBuffer;
+ functions->ReadBuffer = intelReadBuffer;
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_buffers.h b/src/mesa/drivers/dri/i915pipe/intel_buffers.h
new file mode 100644
index 0000000000..13d1a15ffb
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_buffers.h
@@ -0,0 +1,55 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef INTEL_BUFFERS_H
+#define INTEL_BUFFERS_H
+
+
+struct intel_context;
+struct intel_framebuffer;
+
+
+extern GLboolean
+intel_intersect_cliprects(drm_clip_rect_t * dest,
+ const drm_clip_rect_t * a,
+ const drm_clip_rect_t * b);
+
+extern struct intel_region *intel_readbuf_region(struct intel_context *intel);
+
+extern struct intel_region *intel_drawbuf_region(struct intel_context *intel);
+
+extern void intel_wait_flips(struct intel_context *intel, GLuint batch_flags);
+
+extern void intelSwapBuffers(__DRIdrawablePrivate * dPriv);
+
+extern void intelWindowMoved(struct intel_context *intel);
+
+extern void intel_draw_buffer(GLcontext * ctx, struct gl_framebuffer *fb);
+
+extern void intelInitBufferFuncs(struct dd_function_table *functions);
+
+#endif /* INTEL_BUFFERS_H */
diff --git a/src/mesa/drivers/dri/i915pipe/intel_context.c b/src/mesa/drivers/dri/i915pipe/intel_context.c
new file mode 100644
index 0000000000..e8e00b9606
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_context.c
@@ -0,0 +1,768 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "glheader.h"
+#include "context.h"
+#include "matrix.h"
+#include "simple_list.h"
+#include "extensions.h"
+#include "framebuffer.h"
+#include "imports.h"
+#include "points.h"
+
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
+#include "tnl/tnl.h"
+
+#include "tnl/t_pipeline.h"
+#include "tnl/t_vertex.h"
+
+#include "drivers/common/driverfuncs.h"
+
+#include "intel_screen.h"
+
+#include "i830_dri.h"
+
+#include "intel_buffers.h"
+#include "intel_tex.h"
+#include "intel_span.h"
+#include "intel_tris.h"
+#include "intel_ioctl.h"
+#include "intel_batchbuffer.h"
+#include "intel_blit.h"
+#include "intel_pixel.h"
+#include "intel_regions.h"
+#include "intel_buffer_objects.h"
+#include "intel_fbo.h"
+
+#include "pipe/softpipe/sp_context.h"
+#include "state_tracker/st_public.h"
+
+
+#include "drirenderbuffer.h"
+#include "vblank.h"
+#include "utils.h"
+#include "xmlpool.h" /* for symbolic values of enum-type options */
+#ifndef INTEL_DEBUG
+int INTEL_DEBUG = (0);
+#endif
+
+#define need_GL_ARB_multisample
+#define need_GL_ARB_point_parameters
+#define need_GL_ARB_texture_compression
+#define need_GL_ARB_vertex_buffer_object
+#define need_GL_ARB_vertex_program
+#define need_GL_ARB_window_pos
+#define need_GL_EXT_blend_color
+#define need_GL_EXT_blend_equation_separate
+#define need_GL_EXT_blend_func_separate
+#define need_GL_EXT_blend_minmax
+#define need_GL_EXT_cull_vertex
+#define need_GL_EXT_fog_coord
+#define need_GL_EXT_framebuffer_object
+#define need_GL_EXT_multi_draw_arrays
+#define need_GL_EXT_secondary_color
+#define need_GL_NV_vertex_program
+#include "extension_helper.h"
+
+
+#define DRIVER_DATE "20061102"
+
+_glthread_Mutex lockMutex;
+static GLboolean lockMutexInit = GL_FALSE;
+
+
+static const GLubyte *
+intelGetString(GLcontext * ctx, GLenum name)
+{
+ const char *chipset;
+ static char buffer[128];
+
+ switch (name) {
+ case GL_VENDOR:
+ return (GLubyte *) "Tungsten Graphics, Inc";
+ break;
+
+ case GL_RENDERER:
+ switch (intel_context(ctx)->intelScreen->deviceID) {
+ case PCI_CHIP_845_G:
+ chipset = "Intel(R) 845G";
+ break;
+ case PCI_CHIP_I830_M:
+ chipset = "Intel(R) 830M";
+ break;
+ case PCI_CHIP_I855_GM:
+ chipset = "Intel(R) 852GM/855GM";
+ break;
+ case PCI_CHIP_I865_G:
+ chipset = "Intel(R) 865G";
+ break;
+ case PCI_CHIP_I915_G:
+ chipset = "Intel(R) 915G";
+ break;
+ case PCI_CHIP_I915_GM:
+ chipset = "Intel(R) 915GM";
+ break;
+ case PCI_CHIP_I945_G:
+ chipset = "Intel(R) 945G";
+ break;
+ case PCI_CHIP_I945_GM:
+ chipset = "Intel(R) 945GM";
+ break;
+ case PCI_CHIP_I945_GME:
+ chipset = "Intel(R) 945GME";
+ break;
+ case PCI_CHIP_G33_G:
+ chipset = "Intel(R) G33";
+ break;
+ case PCI_CHIP_Q35_G:
+ chipset = "Intel(R) Q35";
+ break;
+ case PCI_CHIP_Q33_G:
+ chipset = "Intel(R) Q33";
+ break;
+ default:
+ chipset = "Unknown Intel Chipset";
+ break;
+ }
+
+ (void) driGetRendererString(buffer, chipset, DRIVER_DATE, 0);
+ return (GLubyte *) buffer;
+
+ default:
+ return NULL;
+ }
+}
+
+
+/**
+ * Extension strings exported by the intel driver.
+ *
+ * \note
+ * It appears that ARB_texture_env_crossbar has "disappeared" compared to the
+ * old i830-specific driver.
+ */
+const struct dri_extension card_extensions[] = {
+ {"GL_ARB_multisample", GL_ARB_multisample_functions},
+ {"GL_ARB_multitexture", NULL},
+ {"GL_ARB_point_parameters", GL_ARB_point_parameters_functions},
+ {"GL_ARB_texture_border_clamp", NULL},
+ {"GL_ARB_texture_compression", GL_ARB_texture_compression_functions},
+ {"GL_ARB_texture_cube_map", NULL},
+ {"GL_ARB_texture_env_add", NULL},
+ {"GL_ARB_texture_env_combine", NULL},
+ {"GL_ARB_texture_env_dot3", NULL},
+ {"GL_ARB_texture_mirrored_repeat", NULL},
+ {"GL_ARB_texture_rectangle", NULL},
+ {"GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions},
+ {"GL_ARB_pixel_buffer_object", NULL},
+ {"GL_ARB_vertex_program", GL_ARB_vertex_program_functions},
+ {"GL_ARB_window_pos", GL_ARB_window_pos_functions},
+ {"GL_EXT_blend_color", GL_EXT_blend_color_functions},
+ {"GL_EXT_blend_equation_separate",
+ GL_EXT_blend_equation_separate_functions},
+ {"GL_EXT_blend_func_separate", GL_EXT_blend_func_separate_functions},
+ {"GL_EXT_blend_minmax", GL_EXT_blend_minmax_functions},
+ {"GL_EXT_blend_subtract", NULL},
+ {"GL_EXT_cull_vertex", GL_EXT_cull_vertex_functions},
+ {"GL_EXT_fog_coord", GL_EXT_fog_coord_functions},
+ {"GL_EXT_framebuffer_object", GL_EXT_framebuffer_object_functions},
+ {"GL_EXT_multi_draw_arrays", GL_EXT_multi_draw_arrays_functions},
+#if 1 /* XXX FBO temporary? */
+ {"GL_EXT_packed_depth_stencil", NULL},
+#endif
+ {"GL_EXT_pixel_buffer_object", NULL},
+ {"GL_EXT_secondary_color", GL_EXT_secondary_color_functions},
+ {"GL_EXT_stencil_wrap", NULL},
+ {"GL_EXT_texture_edge_clamp", NULL},
+ {"GL_EXT_texture_env_combine", NULL},
+ {"GL_EXT_texture_env_dot3", NULL},
+ {"GL_EXT_texture_filter_anisotropic", NULL},
+ {"GL_EXT_texture_lod_bias", NULL},
+ {"GL_3DFX_texture_compression_FXT1", NULL},
+ {"GL_APPLE_client_storage", NULL},
+ {"GL_MESA_pack_invert", NULL},
+ {"GL_MESA_ycbcr_texture", NULL},
+ {"GL_NV_blend_square", NULL},
+ {"GL_NV_vertex_program", GL_NV_vertex_program_functions},
+ {"GL_NV_vertex_program1_1", NULL},
+/* { "GL_SGIS_generate_mipmap", NULL }, */
+ {NULL, NULL}
+};
+
+
+
+
+static const struct dri_debug_control debug_control[] = {
+ {"tex", DEBUG_TEXTURE},
+ {"state", DEBUG_STATE},
+ {"ioctl", DEBUG_IOCTL},
+ {"blit", DEBUG_BLIT},
+ {"mip", DEBUG_MIPTREE},
+ {"fall", DEBUG_FALLBACKS},
+ {"verb", DEBUG_VERBOSE},
+ {"bat", DEBUG_BATCH},
+ {"pix", DEBUG_PIXEL},
+ {"buf", DEBUG_BUFMGR},
+ {"reg", DEBUG_REGION},
+ {"fbo", DEBUG_FBO},
+ {"lock", DEBUG_LOCK},
+ {NULL, 0}
+};
+
+
+static void
+intelInvalidateState(GLcontext * ctx, GLuint new_state)
+{
+ _swrast_InvalidateState(ctx, new_state);
+ _swsetup_InvalidateState(ctx, new_state);
+ _vbo_InvalidateState(ctx, new_state);
+ _tnl_InvalidateState(ctx, new_state);
+ _tnl_invalidate_vertex_state(ctx, new_state);
+
+ st_invalidate_state( ctx, new_state );
+
+ intel_context(ctx)->NewGLState |= new_state;
+}
+
+
+void
+intelFlush(GLcontext * ctx)
+{
+ struct intel_context *intel = intel_context(ctx);
+
+ if (intel->Fallback)
+ _swrast_flush(ctx);
+
+ INTEL_FIREVERTICES(intel);
+
+ if (intel->batch->map != intel->batch->ptr)
+ intel_batchbuffer_flush(intel->batch);
+
+ /* XXX: Need to do an MI_FLUSH here.
+ */
+}
+
+
+/**
+ * Check if we need to rotate/warp the front color buffer to the
+ * rotated screen. We generally need to do this when we get a glFlush
+ * or glFinish after drawing to the front color buffer.
+ * If no rotation, just copy the private fake front buffer to the real one.
+ */
+static void
+intelCheckFrontUpdate(GLcontext * ctx)
+{
+ struct intel_context *intel = intel_context(ctx);
+ /* rely on _ColorDrawBufferMask being kept up to date by mesa
+ even for window-fbos. */
+ /* not sure. Might need that for all masks including
+ BUFFER_BIT_FRONT_LEFT maybe? */
+ if (intel->ctx.DrawBuffer->_ColorDrawBufferMask[0] ==
+ BUFFER_BIT_FRONT_LEFT) {
+ __DRIdrawablePrivate *dPriv = intel->driDrawable;
+ intelCopyBuffer(dPriv, NULL);
+ }
+}
+
+
+/**
+ * Called via glFlush.
+ */
+static void
+intelglFlush(GLcontext * ctx)
+{
+ intelFlush(ctx);
+ intelCheckFrontUpdate(ctx);
+}
+
+void
+intelFinish(GLcontext * ctx)
+{
+ struct intel_context *intel = intel_context(ctx);
+ intelFlush(ctx);
+ if (intel->batch->last_fence) {
+ driFenceFinish(intel->batch->last_fence,
+ 0, GL_FALSE);
+ driFenceUnReference(intel->batch->last_fence);
+ intel->batch->last_fence = NULL;
+ }
+ intelCheckFrontUpdate(ctx);
+}
+
+
+void
+intelInitDriverFunctions(struct dd_function_table *functions)
+{
+ _mesa_init_driver_functions(functions);
+
+ functions->Flush = intelglFlush;
+ functions->Finish = intelFinish;
+ functions->GetString = intelGetString;
+ functions->UpdateState = intelInvalidateState;
+ functions->CopyColorTable = _swrast_CopyColorTable;
+ functions->CopyColorSubTable = _swrast_CopyColorSubTable;
+ functions->CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
+ functions->CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;
+
+ intelInitTextureFuncs(functions);
+ intelInitPixelFuncs(functions);
+ intelInitStateFuncs(functions);
+ intelInitBufferFuncs(functions);
+}
+
+
+
+GLboolean
+intelCreateContext(const __GLcontextModes * mesaVis,
+ __DRIcontextPrivate * driContextPriv,
+ void *sharedContextPrivate)
+{
+ struct dd_function_table functions;
+
+ struct intel_context *intel = CALLOC_STRUCT(intel_context);
+ GLcontext *ctx = &intel->ctx;
+
+ GLcontext *shareCtx = (GLcontext *) sharedContextPrivate;
+ __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv;
+ intelScreenPrivate *intelScreen = (intelScreenPrivate *) sPriv->private;
+ drmI830Sarea *saPriv = (drmI830Sarea *)
+ (((GLubyte *) sPriv->pSAREA) + intelScreen->sarea_priv_offset);
+ int fthrottle_mode;
+ GLboolean havePools;
+
+ DRM_LIGHT_LOCK(sPriv->fd, &sPriv->pSAREA->lock, driContextPriv->hHWContext);
+ havePools = intelCreatePools(intelScreen);
+ DRM_UNLOCK(sPriv->fd, &sPriv->pSAREA->lock, driContextPriv->hHWContext);
+
+ if (!havePools)
+ return GL_FALSE;
+
+ intelInitDriverFunctions(&functions);
+
+ if (!_mesa_initialize_context(&intel->ctx,
+ mesaVis, shareCtx,
+ &functions, (void *) intel))
+ return GL_FALSE;
+
+ driContextPriv->driverPrivate = intel;
+ intel->intelScreen = intelScreen;
+ intel->driScreen = sPriv;
+ intel->sarea = saPriv;
+
+ if (!lockMutexInit) {
+ lockMutexInit = GL_TRUE;
+ _glthread_INIT_MUTEX(lockMutex);
+ }
+
+ driParseConfigFiles(&intel->optionCache, &intelScreen->optionCache,
+ intel->driScreen->myNum, "i915");
+
+ ctx->Const.MaxTextureMaxAnisotropy = 2.0;
+
+ /* This doesn't yet catch all non-conformant rendering, but it's a
+ * start.
+ */
+ if (getenv("INTEL_STRICT_CONFORMANCE")) {
+ intel->strict_conformance = 1;
+ }
+
+ ctx->Const.MinLineWidth = 1.0;
+ ctx->Const.MinLineWidthAA = 1.0;
+ ctx->Const.MaxLineWidth = 3.0;
+ ctx->Const.MaxLineWidthAA = 3.0;
+ ctx->Const.LineWidthGranularity = 1.0;
+
+ ctx->Const.MinPointSize = 1.0;
+ ctx->Const.MinPointSizeAA = 1.0;
+ ctx->Const.MaxPointSize = 255.0;
+ ctx->Const.MaxPointSizeAA = 3.0;
+ ctx->Const.PointSizeGranularity = 1.0;
+
+ /* reinitialize the context point state.
+ * It depend on constants in __GLcontextRec::Const
+ */
+ _mesa_init_point(ctx);
+
+ ctx->Const.MaxColorAttachments = 4; /* XXX FBO: review this */
+
+ /* Initialize the software rasterizer and helper modules. */
+ _swrast_CreateContext(ctx);
+ _vbo_CreateContext(ctx);
+ _tnl_CreateContext(ctx);
+ _swsetup_CreateContext(ctx);
+
+
+ /* Configure swrast to match hardware characteristics: */
+ _swrast_allow_pixel_fog(ctx, GL_FALSE);
+ _swrast_allow_vertex_fog(ctx, GL_TRUE);
+
+ /* Dri stuff */
+ intel->hHWContext = driContextPriv->hHWContext;
+ intel->driFd = sPriv->fd;
+ intel->driHwLock = (drmLock *) & sPriv->pSAREA->lock;
+
+ intel->hw_stipple = 1;
+
+ /* XXX FBO: this doesn't seem to be used anywhere */
+ switch (mesaVis->depthBits) {
+ case 0: /* what to do in this case? */
+ case 16:
+ intel->polygon_offset_scale = 1.0 / 0xffff;
+ break;
+ case 24:
+ intel->polygon_offset_scale = 2.0 / 0xffffff; /* req'd to pass glean */
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ /* Initialize swrast, tnl driver tables: */
+ intelInitSpanFuncs(ctx);
+
+ TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline;
+
+
+ intel->RenderIndex = ~0;
+
+ fthrottle_mode = driQueryOptioni(&intel->optionCache, "fthrottle_mode");
+ intel->iw.irq_seq = -1;
+ intel->irqsEmitted = 0;
+
+ intel->do_irqs = (intel->intelScreen->irq_active &&
+ fthrottle_mode == DRI_CONF_FTHROTTLE_IRQS);
+
+ intel->do_usleeps = (fthrottle_mode == DRI_CONF_FTHROTTLE_USLEEPS);
+
+ _math_matrix_ctr(&intel->ViewportMatrix);
+
+ /* Disable imaging extension until convolution is working in
+ * teximage paths:
+ */
+ driInitExtensions(ctx, card_extensions,
+/* GL_TRUE, */
+ GL_FALSE);
+
+
+ intel->batch = intel_batchbuffer_alloc(intel);
+ intel->last_swap_fence = NULL;
+ intel->first_swap_fence = NULL;
+
+ intel_bufferobj_init(intel);
+ intel_fbo_init(intel);
+
+ if (intel->ctx.Mesa_DXTn) {
+ _mesa_enable_extension(ctx, "GL_EXT_texture_compression_s3tc");
+ _mesa_enable_extension(ctx, "GL_S3_s3tc");
+ }
+ else if (driQueryOptionb(&intel->optionCache, "force_s3tc_enable")) {
+ _mesa_enable_extension(ctx, "GL_EXT_texture_compression_s3tc");
+ }
+
+ intel->prim.primitive = ~0;
+
+
+#if DO_DEBUG
+ INTEL_DEBUG = driParseDebugString(getenv("INTEL_DEBUG"), debug_control);
+#endif
+
+ if (getenv("INTEL_NO_RAST")) {
+ fprintf(stderr, "disabling 3D rasterization\n");
+ FALLBACK(intel, INTEL_FALLBACK_USER, 1);
+ }
+
+
+ st_create_context( &intel->ctx,
+ softpipe_create() );
+
+
+ return GL_TRUE;
+}
+
+void
+intelDestroyContext(__DRIcontextPrivate * driContextPriv)
+{
+ struct intel_context *intel =
+ (struct intel_context *) driContextPriv->driverPrivate;
+
+ assert(intel); /* should never be null */
+ if (intel) {
+ GLboolean release_texture_heaps;
+
+ INTEL_FIREVERTICES(intel);
+
+ //intel->vtbl.destroy(intel);
+
+ release_texture_heaps = (intel->ctx.Shared->RefCount == 1);
+ _swsetup_DestroyContext(&intel->ctx);
+ _tnl_DestroyContext(&intel->ctx);
+ _vbo_DestroyContext(&intel->ctx);
+
+ _swrast_DestroyContext(&intel->ctx);
+ intel->Fallback = 0; /* don't call _swrast_Flush later */
+
+ intel_batchbuffer_free(intel->batch);
+
+ if (intel->last_swap_fence) {
+ driFenceFinish(intel->last_swap_fence, DRM_FENCE_TYPE_EXE, GL_TRUE);
+ driFenceUnReference(intel->last_swap_fence);
+ intel->last_swap_fence = NULL;
+ }
+ if (intel->first_swap_fence) {
+ driFenceFinish(intel->first_swap_fence, DRM_FENCE_TYPE_EXE, GL_TRUE);
+ driFenceUnReference(intel->first_swap_fence);
+ intel->first_swap_fence = NULL;
+ }
+
+
+ if (release_texture_heaps) {
+ /* This share group is about to go away, free our private
+ * texture object data.
+ */
+ if (INTEL_DEBUG & DEBUG_TEXTURE)
+ fprintf(stderr, "do something to free texture heaps\n");
+ }
+
+ /* free the Mesa context */
+ _mesa_free_context_data(&intel->ctx);
+ }
+}
+
+GLboolean
+intelUnbindContext(__DRIcontextPrivate * driContextPriv)
+{
+ struct intel_context *intel = (struct intel_context *) driContextPriv->driverPrivate;
+ /* XXX UnbindContext is called AFTER the new context is made current.
+ Hopefully shouldn't be a problem ? */
+ FLUSH_VERTICES((&intel->ctx), 0);
+ intelFlush(&intel->ctx);
+ return GL_TRUE;
+}
+
+GLboolean
+intelMakeCurrent(__DRIcontextPrivate * driContextPriv,
+ __DRIdrawablePrivate * driDrawPriv,
+ __DRIdrawablePrivate * driReadPriv)
+{
+
+#if 0
+ if (driDrawPriv) {
+ fprintf(stderr, "x %d, y %d, width %d, height %d\n",
+ driDrawPriv->x, driDrawPriv->y, driDrawPriv->w, driDrawPriv->h);
+ }
+#endif
+
+ if (driContextPriv) {
+ struct intel_context *intel =
+ (struct intel_context *) driContextPriv->driverPrivate;
+ struct intel_framebuffer *intel_fb =
+ (struct intel_framebuffer *) driDrawPriv->driverPrivate;
+ GLframebuffer *readFb = (GLframebuffer *) driReadPriv->driverPrivate;
+
+ /* this is a hack so we have a valid context when the region allocation
+ is done. Need a per-screen context? */
+ intel->intelScreen->dummyctxptr = intel;
+
+ /* update GLframebuffer size to match window if needed */
+ driUpdateFramebufferSize(&intel->ctx, driDrawPriv);
+
+ if (driReadPriv != driDrawPriv) {
+ driUpdateFramebufferSize(&intel->ctx, driReadPriv);
+ }
+
+ _mesa_make_current(&intel->ctx, &intel_fb->Base, readFb);
+
+ /* The drawbuffer won't always be updated by _mesa_make_current:
+ */
+ if (intel->ctx.DrawBuffer == &intel_fb->Base) {
+
+ if (intel->driDrawable != driDrawPriv) {
+ if (driDrawPriv->pdraw->swap_interval == (unsigned)-1) {
+ int i;
+
+ intel_fb->vblank_flags = (intel->intelScreen->irq_active != 0)
+ ? driGetDefaultVBlankFlags(&intel->optionCache)
+ : VBLANK_FLAG_NO_IRQ;
+
+ (*dri_interface->getUST) (&intel_fb->swap_ust);
+ driDrawableInitVBlank(driDrawPriv, intel_fb->vblank_flags,
+ &intel_fb->vbl_seq);
+ intel_fb->vbl_waited = intel_fb->vbl_seq;
+
+ for (i = 0; i < 2; i++) {
+ if (intel_fb->color_rb[i])
+ intel_fb->color_rb[i]->vbl_pending = intel_fb->vbl_seq;
+ }
+ }
+ }
+ }
+
+ if ((intel->driDrawable != driDrawPriv) ||
+ (intel->lastStamp != driDrawPriv->lastStamp)) {
+ intel->driDrawable = driDrawPriv;
+ intelWindowMoved(intel);
+ intel->lastStamp = driDrawPriv->lastStamp;
+ }
+
+ }
+ else {
+ _mesa_make_current(NULL, NULL, NULL);
+ }
+
+ return GL_TRUE;
+}
+
+static void
+intelContendedLock(struct intel_context *intel, GLuint flags)
+{
+ __DRIdrawablePrivate *dPriv = intel->driDrawable;
+ __DRIscreenPrivate *sPriv = intel->driScreen;
+ intelScreenPrivate *intelScreen = (intelScreenPrivate *) sPriv->private;
+ drmI830Sarea *sarea = intel->sarea;
+
+ drmGetLock(intel->driFd, intel->hHWContext, flags);
+
+ if (INTEL_DEBUG & DEBUG_LOCK)
+ _mesa_printf("%s - got contended lock\n", __progname);
+
+ /* If the window moved, may need to set a new cliprect now.
+ *
+ * NOTE: This releases and regains the hw lock, so all state
+ * checking must be done *after* this call:
+ */
+ if (dPriv)
+ DRI_VALIDATE_DRAWABLE_INFO(sPriv, dPriv);
+
+ if (sarea->width != intelScreen->width ||
+ sarea->height != intelScreen->height) {
+
+ intelUpdateScreenRotation(sPriv, sarea);
+ }
+
+#if 0
+ if (sarea->width != intel->width ||
+ sarea->height != intel->height ||
+ sarea->rotation != intel->current_rotation) {
+ int numClipRects = intel->numClipRects;
+
+ /*
+ * FIXME: Really only need to do this when drawing to a
+ * common back- or front buffer.
+ */
+
+ /*
+ * This will essentially drop the outstanding batchbuffer on the floor.
+ */
+ intel->numClipRects = 0;
+
+ if (intel->Fallback)
+ _swrast_flush(&intel->ctx);
+
+ INTEL_FIREVERTICES(intel);
+
+ if (intel->batch->map != intel->batch->ptr)
+ intel_batchbuffer_flush(intel->batch);
+
+ intel->numClipRects = numClipRects;
+
+ /* force window update */
+ intel->lastStamp = 0;
+
+ intel->width = sarea->width;
+ intel->height = sarea->height;
+ intel->current_rotation = sarea->rotation;
+ }
+#endif
+}
+
+
+/* Lock the hardware and validate our state.
+ */
+void LOCK_HARDWARE( struct intel_context *intel )
+{
+ char __ret=0;
+ struct intel_framebuffer *intel_fb = NULL;
+ struct intel_renderbuffer *intel_rb = NULL;
+ _glthread_LOCK_MUTEX(lockMutex);
+ assert(!intel->locked);
+
+ if (intel->driDrawable) {
+ intel_fb = intel->driDrawable->driverPrivate;
+
+ if (intel_fb)
+ intel_rb =
+ intel_get_renderbuffer(&intel_fb->Base,
+ intel_fb->Base._ColorDrawBufferMask[0] ==
+ BUFFER_BIT_FRONT_LEFT ? BUFFER_FRONT_LEFT :
+ BUFFER_BACK_LEFT);
+ }
+
+ if (intel_rb && intel_fb->vblank_flags &&
+ !(intel_fb->vblank_flags & VBLANK_FLAG_NO_IRQ) &&
+ (intel_fb->vbl_waited - intel_rb->vbl_pending) > (1<<23)) {
+ drmVBlank vbl;
+
+ vbl.request.type = DRM_VBLANK_ABSOLUTE;
+
+ if ( intel_fb->vblank_flags & VBLANK_FLAG_SECONDARY ) {
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ }
+
+ vbl.request.sequence = intel_rb->vbl_pending;
+ drmWaitVBlank(intel->driFd, &vbl);
+ intel_fb->vbl_waited = vbl.reply.sequence;
+ }
+
+ DRM_CAS(intel->driHwLock, intel->hHWContext,
+ (DRM_LOCK_HELD|intel->hHWContext), __ret);
+
+ if (__ret)
+ intelContendedLock( intel, 0 );
+
+ if (INTEL_DEBUG & DEBUG_LOCK)
+ _mesa_printf("%s - locked\n", __progname);
+
+ intel->locked = 1;
+}
+
+
+ /* Unlock the hardware using the global current context
+ */
+void UNLOCK_HARDWARE( struct intel_context *intel )
+{
+ intel->locked = 0;
+
+ DRM_UNLOCK(intel->driFd, intel->driHwLock, intel->hHWContext);
+
+ _glthread_UNLOCK_MUTEX(lockMutex);
+
+ if (INTEL_DEBUG & DEBUG_LOCK)
+ _mesa_printf("%s - unlocked\n", __progname);
+}
+
diff --git a/src/mesa/drivers/dri/i915pipe/intel_context.h b/src/mesa/drivers/dri/i915pipe/intel_context.h
new file mode 100644
index 0000000000..154be972b9
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_context.h
@@ -0,0 +1,426 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef INTELCONTEXT_INC
+#define INTELCONTEXT_INC
+
+
+
+#include "mtypes.h"
+#include "drm.h"
+#include "mm.h"
+#include "texmem.h"
+
+#include "intel_screen.h"
+#include "i915_drm.h"
+#include "i830_common.h"
+#include "tnl/t_vertex.h"
+
+#define TAG(x) intel##x
+#include "tnl_dd/t_dd_vertex.h"
+#undef TAG
+
+#define DV_PF_555 (1<<8)
+#define DV_PF_565 (2<<8)
+#define DV_PF_8888 (3<<8)
+
+struct intel_region;
+struct intel_context;
+struct _DriBufferObject;
+
+typedef void (*intel_tri_func) (struct intel_context *, intelVertex *,
+ intelVertex *, intelVertex *);
+typedef void (*intel_line_func) (struct intel_context *, intelVertex *,
+ intelVertex *);
+typedef void (*intel_point_func) (struct intel_context *, intelVertex *);
+
+#define INTEL_FALLBACK_DRAW_BUFFER 0x1
+#define INTEL_FALLBACK_READ_BUFFER 0x2
+#define INTEL_FALLBACK_DEPTH_BUFFER 0x4
+#define INTEL_FALLBACK_STENCIL_BUFFER 0x8
+#define INTEL_FALLBACK_USER 0x10
+#define INTEL_FALLBACK_RENDERMODE 0x20
+
+#define FALLBACK( intel, bit, mode ) _mesa_printf("intelFallback not implemented/removed\n")
+
+
+#define INTEL_WRITE_PART 0x1
+#define INTEL_WRITE_FULL 0x2
+#define INTEL_READ 0x4
+
+struct intel_texture_object
+{
+ struct gl_texture_object base; /* The "parent" object */
+
+ /* The mipmap tree must include at least these levels once
+ * validated:
+ */
+ GLuint firstLevel;
+ GLuint lastLevel;
+
+ /* Offset for firstLevel image:
+ */
+ GLuint textureOffset;
+
+ /* On validation any active images held in main memory or in other
+ * regions will be copied to this region and the old storage freed.
+ */
+ struct intel_mipmap_tree *mt;
+
+ GLboolean imageOverride;
+ GLint depthOverride;
+ GLuint pitchOverride;
+};
+
+
+
+struct intel_texture_image
+{
+ struct gl_texture_image base;
+
+ /* These aren't stored in gl_texture_image
+ */
+ GLuint level;
+ GLuint face;
+
+ /* If intelImage->mt != NULL, image data is stored here.
+ * Else if intelImage->base.Data != NULL, image is stored there.
+ * Else there is no image data.
+ */
+ struct intel_mipmap_tree *mt;
+};
+
+
+#define INTEL_MAX_FIXUP 64
+
+struct intel_context
+{
+ GLcontext ctx; /* the parent class */
+
+ GLint refcount;
+ GLuint Fallback;
+ GLuint NewGLState;
+
+ struct _DriFenceObject *last_swap_fence;
+ struct _DriFenceObject *first_swap_fence;
+
+ struct intel_batchbuffer *batch;
+
+ struct
+ {
+ GLuint id;
+ GLuint primitive;
+ GLubyte *start_ptr;
+ void (*flush) (struct intel_context *);
+ } prim;
+
+ GLboolean locked;
+ char *prevLockFile;
+ int prevLockLine;
+
+ GLuint ClearColor565;
+ GLuint ClearColor8888;
+
+ /* Offsets of fields within the current vertex:
+ */
+ GLuint coloroffset;
+ GLuint specoffset;
+ GLuint wpos_offset;
+ GLuint wpos_size;
+
+ struct tnl_attr_map vertex_attrs[VERT_ATTRIB_MAX];
+ GLuint vertex_attr_count;
+
+ GLfloat polygon_offset_scale; /* dependent on depth_scale, bpp */
+
+ GLboolean hw_stipple;
+ GLboolean strict_conformance;
+
+ /* AGP memory buffer manager:
+ */
+ struct bufmgr *bm;
+
+
+ /* State for intelvb.c and inteltris.c.
+ */
+ GLuint RenderIndex;
+ GLmatrix ViewportMatrix;
+ GLenum render_primitive;
+ GLenum reduced_primitive;
+ GLuint vertex_size;
+ GLubyte *verts; /* points to tnl->clipspace.vertex_buf */
+
+
+ /* Fallback rasterization functions
+ */
+ intel_point_func draw_point;
+ intel_line_func draw_line;
+ intel_tri_func draw_tri;
+
+ /* These refer to the current drawing buffer:
+ */
+ GLuint numClipRects; /**< cliprects for drawing */
+ drm_clip_rect_t *pClipRects;
+ drm_clip_rect_t fboRect; /**< cliprect for rendering */
+
+ GLuint do_usleeps;
+ int do_irqs;
+ GLuint irqsEmitted;
+ drm_i915_irq_wait_t iw;
+
+ drm_context_t hHWContext;
+ drmLock *driHwLock;
+ int driFd;
+
+ __DRIdrawablePrivate *driDrawable;
+ __DRIscreenPrivate *driScreen;
+ intelScreenPrivate *intelScreen;
+ drmI830Sarea *sarea;
+
+ GLuint lastStamp;
+
+ /**
+ * Configuration cache
+ */
+ driOptionCache optionCache;
+};
+
+/* These are functions now:
+ */
+void LOCK_HARDWARE( struct intel_context *intel );
+void UNLOCK_HARDWARE( struct intel_context *intel );
+
+extern char *__progname;
+
+
+#define SUBPIXEL_X 0.125
+#define SUBPIXEL_Y 0.125
+
+#define INTEL_FIREVERTICES(intel) \
+do { \
+ if ((intel)->prim.flush) \
+ (intel)->prim.flush(intel); \
+} while (0)
+
+/* ================================================================
+ * Color packing:
+ */
+
+#define INTEL_PACKCOLOR4444(r,g,b,a) \
+ ((((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | ((g) & 0xf0) | ((b) >> 4))
+
+#define INTEL_PACKCOLOR1555(r,g,b,a) \
+ ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) | \
+ ((a) ? 0x8000 : 0))
+
+#define INTEL_PACKCOLOR565(r,g,b) \
+ ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3))
+
+#define INTEL_PACKCOLOR8888(r,g,b,a) \
+ ((a<<24) | (r<<16) | (g<<8) | b)
+
+
+
+/* ================================================================
+ * From linux kernel i386 header files, copes with odd sizes better
+ * than COPY_DWORDS would:
+ * XXX Put this in src/mesa/main/imports.h ???
+ */
+#if defined(i386) || defined(__i386__)
+static INLINE void *
+__memcpy(void *to, const void *from, size_t n)
+{
+ int d0, d1, d2;
+ __asm__ __volatile__("rep ; movsl\n\t"
+ "testb $2,%b4\n\t"
+ "je 1f\n\t"
+ "movsw\n"
+ "1:\ttestb $1,%b4\n\t"
+ "je 2f\n\t"
+ "movsb\n" "2:":"=&c"(d0), "=&D"(d1), "=&S"(d2)
+ :"0"(n / 4), "q"(n), "1"((long) to), "2"((long) from)
+ :"memory");
+ return (to);
+}
+#else
+#define __memcpy(a,b,c) memcpy(a,b,c)
+#endif
+
+
+
+/* ================================================================
+ * Debugging:
+ */
+#define DO_DEBUG 0
+#if DO_DEBUG
+extern int INTEL_DEBUG;
+#else
+#define INTEL_DEBUG 0
+#endif
+
+#define DEBUG_TEXTURE 0x1
+#define DEBUG_STATE 0x2
+#define DEBUG_IOCTL 0x4
+#define DEBUG_BLIT 0x8
+#define DEBUG_MIPTREE 0x10
+#define DEBUG_FALLBACKS 0x20
+#define DEBUG_VERBOSE 0x40
+#define DEBUG_BATCH 0x80
+#define DEBUG_PIXEL 0x100
+#define DEBUG_BUFMGR 0x200
+#define DEBUG_REGION 0x400
+#define DEBUG_FBO 0x800
+#define DEBUG_LOCK 0x1000
+
+#define DBG(...) do { if (INTEL_DEBUG & FILE_DEBUG_FLAG) _mesa_printf(__VA_ARGS__); } while(0)
+
+
+#define PCI_CHIP_845_G 0x2562
+#define PCI_CHIP_I830_M 0x3577
+#define PCI_CHIP_I855_GM 0x3582
+#define PCI_CHIP_I865_G 0x2572
+#define PCI_CHIP_I915_G 0x2582
+#define PCI_CHIP_I915_GM 0x2592
+#define PCI_CHIP_I945_G 0x2772
+#define PCI_CHIP_I945_GM 0x27A2
+#define PCI_CHIP_I945_GME 0x27AE
+#define PCI_CHIP_G33_G 0x29C2
+#define PCI_CHIP_Q35_G 0x29B2
+#define PCI_CHIP_Q33_G 0x29D2
+
+
+/* ================================================================
+ * intel_context.c:
+ */
+
+extern GLboolean intelInitContext(struct intel_context *intel,
+ const __GLcontextModes * mesaVis,
+ __DRIcontextPrivate * driContextPriv,
+ void *sharedContextPrivate,
+ struct dd_function_table *functions);
+
+extern void intelGetLock(struct intel_context *intel, GLuint flags);
+
+extern void intelFinish(GLcontext * ctx);
+extern void intelFlush(GLcontext * ctx);
+
+extern void intelInitDriverFunctions(struct dd_function_table *functions);
+
+
+/* ================================================================
+ * intel_state.c:
+ */
+extern void intelInitStateFuncs(struct dd_function_table *functions);
+
+#define COMPAREFUNC_ALWAYS 0
+#define COMPAREFUNC_NEVER 0x1
+#define COMPAREFUNC_LESS 0x2
+#define COMPAREFUNC_EQUAL 0x3
+#define COMPAREFUNC_LEQUAL 0x4
+#define COMPAREFUNC_GREATER 0x5
+#define COMPAREFUNC_NOTEQUAL 0x6
+#define COMPAREFUNC_GEQUAL 0x7
+
+#define STENCILOP_KEEP 0
+#define STENCILOP_ZERO 0x1
+#define STENCILOP_REPLACE 0x2
+#define STENCILOP_INCRSAT 0x3
+#define STENCILOP_DECRSAT 0x4
+#define STENCILOP_INCR 0x5
+#define STENCILOP_DECR 0x6
+#define STENCILOP_INVERT 0x7
+
+#define LOGICOP_CLEAR 0
+#define LOGICOP_NOR 0x1
+#define LOGICOP_AND_INV 0x2
+#define LOGICOP_COPY_INV 0x3
+#define LOGICOP_AND_RVRSE 0x4
+#define LOGICOP_INV 0x5
+#define LOGICOP_XOR 0x6
+#define LOGICOP_NAND 0x7
+#define LOGICOP_AND 0x8
+#define LOGICOP_EQUIV 0x9
+#define LOGICOP_NOOP 0xa
+#define LOGICOP_OR_INV 0xb
+#define LOGICOP_COPY 0xc
+#define LOGICOP_OR_RVRSE 0xd
+#define LOGICOP_OR 0xe
+#define LOGICOP_SET 0xf
+
+#define BLENDFACT_ZERO 0x01
+#define BLENDFACT_ONE 0x02
+#define BLENDFACT_SRC_COLR 0x03
+#define BLENDFACT_INV_SRC_COLR 0x04
+#define BLENDFACT_SRC_ALPHA 0x05
+#define BLENDFACT_INV_SRC_ALPHA 0x06
+#define BLENDFACT_DST_ALPHA 0x07
+#define BLENDFACT_INV_DST_ALPHA 0x08
+#define BLENDFACT_DST_COLR 0x09
+#define BLENDFACT_INV_DST_COLR 0x0a
+#define BLENDFACT_SRC_ALPHA_SATURATE 0x0b
+#define BLENDFACT_CONST_COLOR 0x0c
+#define BLENDFACT_INV_CONST_COLOR 0x0d
+#define BLENDFACT_CONST_ALPHA 0x0e
+#define BLENDFACT_INV_CONST_ALPHA 0x0f
+#define BLENDFACT_MASK 0x0f
+
+#define MI_BATCH_BUFFER_END (0xA<<23)
+
+
+extern int intel_translate_compare_func(GLenum func);
+extern int intel_translate_stencil_op(GLenum op);
+extern int intel_translate_blend_factor(GLenum factor);
+extern int intel_translate_logic_op(GLenum opcode);
+
+
+/*======================================================================
+ * Inline conversion functions.
+ * These are better-typed than the macros used previously:
+ */
+static INLINE struct intel_context *
+intel_context(GLcontext * ctx)
+{
+ return (struct intel_context *) ctx;
+}
+
+static INLINE struct intel_texture_object *
+intel_texture_object(struct gl_texture_object *obj)
+{
+ return (struct intel_texture_object *) obj;
+}
+
+static INLINE struct intel_texture_image *
+intel_texture_image(struct gl_texture_image *img)
+{
+ return (struct intel_texture_image *) img;
+}
+
+extern struct intel_renderbuffer *intel_renderbuffer(struct gl_renderbuffer
+ *rb);
+
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_depthstencil.c b/src/mesa/drivers/dri/i915pipe/intel_depthstencil.c
new file mode 100644
index 0000000000..d269a85a3c
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_depthstencil.c
@@ -0,0 +1,282 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "glheader.h"
+#include "imports.h"
+#include "context.h"
+#include "depthstencil.h"
+#include "fbobject.h"
+#include "framebuffer.h"
+#include "hash.h"
+#include "mtypes.h"
+#include "renderbuffer.h"
+
+#include "intel_context.h"
+#include "intel_fbo.h"
+#include "intel_depthstencil.h"
+#include "intel_regions.h"
+
+
+/**
+ * The GL_EXT_framebuffer_object allows the user to create their own
+ * framebuffer objects consisting of color renderbuffers (0 or more),
+ * depth renderbuffers (0 or 1) and stencil renderbuffers (0 or 1).
+ *
+ * The spec considers depth and stencil renderbuffers to be totally independent
+ * buffers. In reality, most graphics hardware today uses a combined
+ * depth+stencil buffer (one 32-bit pixel = 24 bits of Z + 8 bits of stencil).
+ *
+ * This causes difficulty because the user may create some number of depth
+ * renderbuffers and some number of stencil renderbuffers and bind them
+ * together in framebuffers in any combination.
+ *
+ * This code manages all that.
+ *
+ * 1. Depth renderbuffers are always allocated in hardware as 32bpp
+ * GL_DEPTH24_STENCIL8 buffers.
+ *
+ * 2. Stencil renderbuffers are initially allocated in software as 8bpp
+ * GL_STENCIL_INDEX8 buffers.
+ *
+ * 3. Depth and Stencil renderbuffers use the PairedStencil and PairedDepth
+ * fields (respectively) to indicate if the buffer's currently paired
+ * with another stencil or depth buffer (respectively).
+ *
+ * 4. When a depth and stencil buffer are initially both attached to the
+ * current framebuffer, we merge the stencil buffer values into the
+ * depth buffer (really a depth+stencil buffer). The then hardware uses
+ * the combined buffer.
+ *
+ * 5. Whenever a depth or stencil buffer is reallocated (with
+ * glRenderbufferStorage) we undo the pairing and copy the stencil values
+ * from the combined depth/stencil buffer back to the stencil-only buffer.
+ *
+ * 6. We also undo the pairing when we find a change in buffer bindings.
+ *
+ * 7. If a framebuffer is only using a depth renderbuffer (no stencil), we
+ * just use the combined depth/stencil buffer and ignore the stencil values.
+ *
+ * 8. If a framebuffer is only using a stencil renderbuffer (no depth) we have
+ * to promote the 8bpp software stencil buffer to a 32bpp hardware
+ * depth+stencil buffer.
+ *
+ */
+
+
+
+static void
+map_regions(GLcontext * ctx,
+ struct intel_renderbuffer *depthRb,
+ struct intel_renderbuffer *stencilRb)
+{
+ struct intel_context *intel = intel_context(ctx);
+ if (depthRb && depthRb->region) {
+ intel_region_map(intel->intelScreen, depthRb->region);
+ depthRb->pfMap = depthRb->region->map;
+ depthRb->pfPitch = depthRb->region->pitch;
+ }
+ if (stencilRb && stencilRb->region) {
+ intel_region_map(intel->intelScreen, stencilRb->region);
+ stencilRb->pfMap = stencilRb->region->map;
+ stencilRb->pfPitch = stencilRb->region->pitch;
+ }
+}
+
+static void
+unmap_regions(GLcontext * ctx,
+ struct intel_renderbuffer *depthRb,
+ struct intel_renderbuffer *stencilRb)
+{
+ struct intel_context *intel = intel_context(ctx);
+ if (depthRb && depthRb->region) {
+ intel_region_unmap(intel->intelScreen, depthRb->region);
+ depthRb->pfMap = NULL;
+ depthRb->pfPitch = 0;
+ }
+ if (stencilRb && stencilRb->region) {
+ intel_region_unmap(intel->intelScreen, stencilRb->region);
+ stencilRb->pfMap = NULL;
+ stencilRb->pfPitch = 0;
+ }
+}
+
+
+
+/**
+ * Undo the pairing/interleaving between depth and stencil buffers.
+ * irb should be a depth/stencil or stencil renderbuffer.
+ */
+void
+intel_unpair_depth_stencil(GLcontext * ctx, struct intel_renderbuffer *irb)
+{
+ if (irb->PairedStencil) {
+ /* irb is a depth/stencil buffer */
+ struct gl_renderbuffer *stencilRb;
+ struct intel_renderbuffer *stencilIrb;
+
+ ASSERT(irb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+
+ stencilRb = _mesa_lookup_renderbuffer(ctx, irb->PairedStencil);
+ stencilIrb = intel_renderbuffer(stencilRb);
+ if (stencilIrb) {
+ /* need to extract stencil values from the depth buffer */
+ ASSERT(stencilIrb->PairedDepth == irb->Base.Name);
+ map_regions(ctx, irb, stencilIrb);
+ _mesa_extract_stencil(ctx, &irb->Base, &stencilIrb->Base);
+ unmap_regions(ctx, irb, stencilIrb);
+ stencilIrb->PairedDepth = 0;
+ }
+ irb->PairedStencil = 0;
+ }
+ else if (irb->PairedDepth) {
+ /* irb is a stencil buffer */
+ struct gl_renderbuffer *depthRb;
+ struct intel_renderbuffer *depthIrb;
+
+ ASSERT(irb->Base._ActualFormat == GL_STENCIL_INDEX8_EXT ||
+ irb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+
+ depthRb = _mesa_lookup_renderbuffer(ctx, irb->PairedDepth);
+ depthIrb = intel_renderbuffer(depthRb);
+ if (depthIrb) {
+ /* need to extract stencil values from the depth buffer */
+ ASSERT(depthIrb->PairedStencil == irb->Base.Name);
+ map_regions(ctx, depthIrb, irb);
+ _mesa_extract_stencil(ctx, &depthIrb->Base, &irb->Base);
+ unmap_regions(ctx, depthIrb, irb);
+ depthIrb->PairedStencil = 0;
+ }
+ irb->PairedDepth = 0;
+ }
+ else {
+ _mesa_problem(ctx, "Problem in undo_depth_stencil_pairing");
+ }
+
+ ASSERT(irb->PairedStencil == 0);
+ ASSERT(irb->PairedDepth == 0);
+}
+
+
+/**
+ * Examine the depth and stencil renderbuffers which are attached to the
+ * framebuffer. If both depth and stencil are attached, make sure that the
+ * renderbuffers are 'paired' (combined). If only depth or only stencil is
+ * attached, undo any previous pairing.
+ *
+ * Must be called if NewState & _NEW_BUFFER (when renderbuffer attachments
+ * change, for example).
+ */
+void
+intel_validate_paired_depth_stencil(GLcontext * ctx,
+ struct gl_framebuffer *fb)
+{
+ struct intel_renderbuffer *depthRb, *stencilRb;
+
+ depthRb = intel_get_renderbuffer(fb, BUFFER_DEPTH);
+ stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL);
+
+ if (depthRb && stencilRb) {
+ if (depthRb == stencilRb) {
+ /* Using a user-created combined depth/stencil buffer.
+ * Nothing to do.
+ */
+ ASSERT(depthRb->Base._BaseFormat == GL_DEPTH_STENCIL_EXT);
+ ASSERT(depthRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ }
+ else {
+ /* Separate depth/stencil buffers, need to interleave now */
+ ASSERT(depthRb->Base._BaseFormat == GL_DEPTH_COMPONENT);
+ ASSERT(stencilRb->Base._BaseFormat == GL_STENCIL_INDEX);
+ /* may need to interleave depth/stencil now */
+ if (depthRb->PairedStencil == stencilRb->Base.Name) {
+ /* OK, the depth and stencil buffers are already interleaved */
+ ASSERT(stencilRb->PairedDepth == depthRb->Base.Name);
+ }
+ else {
+ /* need to setup new pairing/interleaving */
+ if (depthRb->PairedStencil) {
+ intel_unpair_depth_stencil(ctx, depthRb);
+ }
+ if (stencilRb->PairedDepth) {
+ intel_unpair_depth_stencil(ctx, stencilRb);
+ }
+
+ ASSERT(depthRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ ASSERT(stencilRb->Base._ActualFormat == GL_STENCIL_INDEX8_EXT ||
+ stencilRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+
+ /* establish new pairing: interleave stencil into depth buffer */
+ map_regions(ctx, depthRb, stencilRb);
+ _mesa_insert_stencil(ctx, &depthRb->Base, &stencilRb->Base);
+ unmap_regions(ctx, depthRb, stencilRb);
+ depthRb->PairedStencil = stencilRb->Base.Name;
+ stencilRb->PairedDepth = depthRb->Base.Name;
+ }
+
+ }
+ }
+ else if (depthRb) {
+ /* Depth buffer but no stencil buffer.
+ * We'll use a GL_DEPTH24_STENCIL8 buffer and ignore the stencil bits.
+ */
+ /* can't assert this until storage is allocated:
+ ASSERT(depthRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ */
+ /* intel_undo any previous pairing */
+ if (depthRb->PairedStencil) {
+ intel_unpair_depth_stencil(ctx, depthRb);
+ }
+ }
+ else if (stencilRb) {
+ /* Stencil buffer but no depth buffer.
+ * Since h/w doesn't typically support just 8bpp stencil w/out Z,
+ * we'll use a GL_DEPTH24_STENCIL8 buffer and ignore the depth bits.
+ */
+ /* undo any previous pairing */
+ if (stencilRb->PairedDepth) {
+ intel_unpair_depth_stencil(ctx, stencilRb);
+ }
+ if (stencilRb->Base._ActualFormat == GL_STENCIL_INDEX8_EXT) {
+ /* promote buffer to GL_DEPTH24_STENCIL8 for hw rendering */
+ _mesa_promote_stencil(ctx, &stencilRb->Base);
+ ASSERT(stencilRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT);
+ }
+ }
+
+ /* Finally, update the fb->_DepthBuffer and fb->_StencilBuffer fields */
+ _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH);
+ if (depthRb && depthRb->PairedStencil)
+ _mesa_update_stencil_buffer(ctx, fb, BUFFER_DEPTH);
+ else
+ _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL);
+
+
+ /* The hardware should use fb->Attachment[BUFFER_DEPTH].Renderbuffer
+ * first, if present, then fb->Attachment[BUFFER_STENCIL].Renderbuffer
+ * if present.
+ */
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_depthstencil.h b/src/mesa/drivers/dri/i915pipe/intel_depthstencil.h
new file mode 100644
index 0000000000..2d3fc48b3a
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_depthstencil.h
@@ -0,0 +1,14 @@
+
+#ifndef INTEL_DEPTH_STENCIL_H
+#define INTEL_DEPTH_STENCIL_H
+
+
+extern void
+intel_unpair_depth_stencil(GLcontext * ctx, struct intel_renderbuffer *irb);
+
+extern void
+intel_validate_paired_depth_stencil(GLcontext * ctx,
+ struct gl_framebuffer *fb);
+
+
+#endif /* INTEL_DEPTH_STENCIL_H */
diff --git a/src/mesa/drivers/dri/i915pipe/intel_fbo.c b/src/mesa/drivers/dri/i915pipe/intel_fbo.c
new file mode 100644
index 0000000000..a2a5c811b1
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_fbo.c
@@ -0,0 +1,623 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "imports.h"
+#include "mtypes.h"
+#include "fbobject.h"
+#include "framebuffer.h"
+#include "renderbuffer.h"
+#include "context.h"
+#include "texformat.h"
+#include "texrender.h"
+
+#include "intel_context.h"
+#include "intel_buffers.h"
+#include "intel_depthstencil.h"
+#include "intel_fbo.h"
+#include "intel_mipmap_tree.h"
+#include "intel_regions.h"
+#include "intel_span.h"
+
+
+#define FILE_DEBUG_FLAG DEBUG_FBO
+
+#define INTEL_RB_CLASS 0x12345678
+
+
+/* XXX FBO: move this to intel_context.h (inlined) */
+/**
+ * Return a gl_renderbuffer ptr casted to intel_renderbuffer.
+ * NULL will be returned if the rb isn't really an intel_renderbuffer.
+ * This is determiend by checking the ClassID.
+ */
+struct intel_renderbuffer *
+intel_renderbuffer(struct gl_renderbuffer *rb)
+{
+ struct intel_renderbuffer *irb = (struct intel_renderbuffer *) rb;
+ if (irb && irb->Base.ClassID == INTEL_RB_CLASS) {
+ /*_mesa_warning(NULL, "Returning non-intel Rb\n");*/
+ return irb;
+ }
+ else
+ return NULL;
+}
+
+
+struct intel_renderbuffer *
+intel_get_renderbuffer(struct gl_framebuffer *fb, GLuint attIndex)
+{
+ return intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer);
+}
+
+
+void
+intel_flip_renderbuffers(struct intel_framebuffer *intel_fb)
+{
+ int current_page = intel_fb->pf_current_page;
+ int next_page = (current_page + 1) % intel_fb->pf_num_pages;
+ struct gl_renderbuffer *tmp_rb;
+
+ /* Exchange renderbuffers if necessary but make sure their reference counts
+ * are preserved.
+ */
+ if (intel_fb->color_rb[current_page] &&
+ intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer !=
+ &intel_fb->color_rb[current_page]->Base) {
+ tmp_rb = NULL;
+ _mesa_reference_renderbuffer(&tmp_rb,
+ intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
+ tmp_rb = &intel_fb->color_rb[current_page]->Base;
+ _mesa_reference_renderbuffer(
+ &intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer, tmp_rb);
+ _mesa_reference_renderbuffer(&tmp_rb, NULL);
+ }
+
+ if (intel_fb->color_rb[next_page] &&
+ intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer !=
+ &intel_fb->color_rb[next_page]->Base) {
+ tmp_rb = NULL;
+ _mesa_reference_renderbuffer(&tmp_rb,
+ intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer);
+ tmp_rb = &intel_fb->color_rb[next_page]->Base;
+ _mesa_reference_renderbuffer(
+ &intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer, tmp_rb);
+ _mesa_reference_renderbuffer(&tmp_rb, NULL);
+ }
+}
+
+
+struct intel_region *
+intel_get_rb_region(struct gl_framebuffer *fb, GLuint attIndex)
+{
+ struct intel_renderbuffer *irb = intel_get_renderbuffer(fb, attIndex);
+
+ if (irb)
+ return irb->region;
+ else
+ return NULL;
+}
+
+
+
+/**
+ * Create a new framebuffer object.
+ */
+static struct gl_framebuffer *
+intel_new_framebuffer(GLcontext * ctx, GLuint name)
+{
+ /* Only drawable state in intel_framebuffer at this time, just use Mesa's
+ * class
+ */
+ return _mesa_new_framebuffer(ctx, name);
+}
+
+
+static void
+intel_delete_renderbuffer(struct gl_renderbuffer *rb)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_renderbuffer *irb = intel_renderbuffer(rb);
+
+ ASSERT(irb);
+
+ DBG("freeing renderbuffer\n");
+
+ if (irb->PairedStencil || irb->PairedDepth) {
+ intel_unpair_depth_stencil(ctx, irb);
+ }
+
+ if (intel && irb->region) {
+ intel_region_release(&irb->region);
+ }
+
+ _mesa_free(irb);
+}
+
+
+
+/**
+ * Return a pointer to a specific pixel in a renderbuffer.
+ */
+static void *
+intel_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb,
+ GLint x, GLint y)
+{
+ /* By returning NULL we force all software rendering to go through
+ * the span routines.
+ */
+ return NULL;
+}
+
+
+
+/**
+ * Called via glRenderbufferStorageEXT() to set the format and allocate
+ * storage for a user-created (or priv buffer) renderbuffer.
+ */
+static GLboolean
+intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
+ GLenum internalFormat,
+ GLuint width, GLuint height)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_renderbuffer *irb = intel_renderbuffer(rb);
+ GLboolean softwareBuffer = GL_FALSE;
+ int cpp;
+
+ switch (internalFormat) {
+ case GL_R3_G3_B2:
+ case GL_RGB4:
+ case GL_RGB5:
+ rb->_ActualFormat = GL_RGB5;
+ rb->DataType = GL_UNSIGNED_BYTE;
+ rb->RedBits = 5;
+ rb->GreenBits = 6;
+ rb->BlueBits = 5;
+ cpp = 2;
+ break;
+ case GL_RGB:
+ case GL_RGB8:
+ case GL_RGB10:
+ case GL_RGB12:
+ case GL_RGB16:
+ case GL_RGBA:
+ case GL_RGBA2:
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGBA8:
+ case GL_RGB10_A2:
+ case GL_RGBA12:
+ case GL_RGBA16:
+ rb->_ActualFormat = GL_RGBA8;
+ rb->DataType = GL_UNSIGNED_BYTE;
+ rb->RedBits = 8;
+ rb->GreenBits = 8;
+ rb->BlueBits = 8;
+ rb->AlphaBits = 8;
+ cpp = 4;
+ break;
+ case GL_STENCIL_INDEX:
+ case GL_STENCIL_INDEX1_EXT:
+ case GL_STENCIL_INDEX4_EXT:
+ case GL_STENCIL_INDEX8_EXT:
+ case GL_STENCIL_INDEX16_EXT:
+ /* alloc a depth+stencil buffer */
+ rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
+ rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
+ rb->StencilBits = 8;
+ cpp = 4;
+ break;
+ case GL_DEPTH_COMPONENT16:
+ rb->_ActualFormat = GL_DEPTH_COMPONENT16;
+ rb->DataType = GL_UNSIGNED_SHORT;
+ rb->DepthBits = 16;
+ cpp = 2;
+ break;
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_COMPONENT24:
+ case GL_DEPTH_COMPONENT32:
+ rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
+ rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
+ rb->DepthBits = 24;
+ cpp = 4;
+ break;
+ case GL_DEPTH_STENCIL_EXT:
+ case GL_DEPTH24_STENCIL8_EXT:
+ rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT;
+ rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
+ rb->DepthBits = 24;
+ rb->StencilBits = 8;
+ cpp = 4;
+ break;
+ default:
+ _mesa_problem(ctx,
+ "Unexpected format (%x) in intel_alloc_renderbuffer_storage", internalFormat);
+ return GL_FALSE;
+ }
+
+ intelFlush(ctx);
+
+ /* free old region */
+ if (irb->region) {
+ intel_region_release(&irb->region);
+ }
+
+ /* allocate new memory region/renderbuffer */
+ if (softwareBuffer) {
+ return _mesa_soft_renderbuffer_storage(ctx, rb, internalFormat,
+ width, height);
+ }
+ else {
+ /* Choose a pitch to match hardware requirements:
+ */
+ GLuint pitch = ((cpp * width + 63) & ~63) / cpp;
+
+ /* alloc hardware renderbuffer */
+ DBG("Allocating %d x %d Intel RBO (pitch %d)\n", width,
+ height, pitch);
+
+ irb->region = intel_region_alloc(intel->intelScreen, cpp, pitch, height);
+ if (!irb->region)
+ return GL_FALSE; /* out of memory? */
+
+ ASSERT(irb->region->buffer);
+
+ rb->Width = width;
+ rb->Height = height;
+
+#if 1
+ /* update the surface's size too */
+ rb->surface->width = width;
+ rb->surface->height = height;
+#endif
+
+ /* This sets the Get/PutRow/Value functions */
+ intel_set_span_functions(&irb->Base);
+
+ return GL_TRUE;
+ }
+}
+
+
+static void
+intel_resize_buffers(GLcontext *ctx, struct gl_framebuffer *fb,
+ GLuint width, GLuint height)
+{
+ struct intel_framebuffer *intel_fb = (struct intel_framebuffer*)fb;
+ int i;
+
+ _mesa_resize_framebuffer(ctx, fb, width, height);
+
+ fb->Initialized = GL_TRUE; /* XXX remove someday */
+
+ if (fb->Name != 0) {
+ return;
+ }
+
+ /* Make sure all window system renderbuffers are up to date */
+ for (i = 0; i < 3; i++) {
+ struct gl_renderbuffer *rb = &intel_fb->color_rb[i]->Base;
+
+ /* only resize if size is changing */
+ if (rb && (rb->Width != width || rb->Height != height)) {
+ rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height);
+ }
+ }
+}
+
+static GLboolean
+intel_nop_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
+ GLenum internalFormat, GLuint width, GLuint height)
+{
+ _mesa_problem(ctx, "intel_op_alloc_storage should never be called.");
+ return GL_FALSE;
+}
+
+
+
+struct intel_renderbuffer *
+intel_new_renderbuffer_fb(GLuint intFormat)
+{
+ struct intel_renderbuffer *irb;
+
+ irb = CALLOC_STRUCT(intel_renderbuffer);
+ if (!irb) {
+ _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer");
+ return NULL;
+ }
+
+ _mesa_init_renderbuffer(&irb->Base, 0);
+ irb->Base.ClassID = INTEL_RB_CLASS;
+ irb->Base.InternalFormat = intFormat;
+
+ switch (intFormat) {
+ case GL_RGB5:
+ case GL_RGBA8:
+ irb->Base._BaseFormat = GL_RGBA;
+ break;
+ case GL_DEPTH_COMPONENT16:
+ irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
+ break;
+ case GL_DEPTH24_STENCIL8_EXT:
+ irb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT;
+ break;
+ default:
+ _mesa_problem(NULL,
+ "Unexpected intFormat in intel_create_renderbuffer");
+ return NULL;
+ }
+
+ /* intel-specific methods */
+ irb->Base.Delete = intel_delete_renderbuffer;
+ irb->Base.AllocStorage = intel_alloc_renderbuffer_storage;
+ irb->Base.GetPointer = intel_get_pointer;
+ /* span routines set in alloc_storage function */
+
+ irb->Base.surface = intel_new_surface(intFormat);
+ irb->Base.surface->rb = irb;
+
+ return &irb->Base;
+}
+
+/**
+ * Create a new renderbuffer object.
+ * Typically called via glBindRenderbufferEXT().
+ */
+static struct gl_renderbuffer *
+intel_new_renderbuffer(GLcontext * ctx, GLuint name)
+{
+ /*struct intel_context *intel = intel_context(ctx); */
+ struct intel_renderbuffer *irb;
+
+ irb = CALLOC_STRUCT(intel_renderbuffer);
+ if (!irb) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer");
+ return NULL;
+ }
+
+ _mesa_init_renderbuffer(&irb->Base, name);
+ irb->Base.ClassID = INTEL_RB_CLASS;
+
+ /* intel-specific methods */
+ irb->Base.Delete = intel_delete_renderbuffer;
+ irb->Base.AllocStorage = intel_alloc_renderbuffer_storage;
+ irb->Base.GetPointer = intel_get_pointer;
+ /* span routines set in alloc_storage function */
+
+ irb->Base.surface = intel_new_surface(0 /*unknown format*/);
+ irb->Base.surface->rb = irb;
+
+ return &irb->Base;
+}
+
+
+/**
+ * Called via glBindFramebufferEXT().
+ */
+static void
+intel_bind_framebuffer(GLcontext * ctx, GLenum target,
+ struct gl_framebuffer *fb, struct gl_framebuffer *fbread)
+{
+ if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) {
+ intel_draw_buffer(ctx, fb);
+ /* Integer depth range depends on depth buffer bits */
+ /* XXX
+ */
+// ctx->Driver.DepthRange(ctx, ctx->Viewport.Near, ctx->Viewport.Far);
+ }
+ else {
+ /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */
+ }
+}
+
+
+/**
+ * Called via glFramebufferRenderbufferEXT().
+ */
+static void
+intel_framebuffer_renderbuffer(GLcontext * ctx,
+ struct gl_framebuffer *fb,
+ GLenum attachment, struct gl_renderbuffer *rb)
+{
+ DBG("Intel FramebufferRenderbuffer %u %u\n", fb->Name, rb ? rb->Name : 0);
+
+ intelFlush(ctx);
+
+ _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
+ intel_draw_buffer(ctx, fb);
+}
+
+
+/**
+ * When glFramebufferTexture[123]D is called this function sets up the
+ * gl_renderbuffer wrapper around the texture image.
+ * This will have the region info needed for hardware rendering.
+ */
+static struct intel_renderbuffer *
+intel_wrap_texture(GLcontext * ctx, struct gl_texture_image *texImage)
+{
+ const GLuint name = ~0; /* not significant, but distinct for debugging */
+ struct intel_renderbuffer *irb;
+
+ /* make an intel_renderbuffer to wrap the texture image */
+ irb = CALLOC_STRUCT(intel_renderbuffer);
+ if (!irb) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture");
+ return NULL;
+ }
+
+ _mesa_init_renderbuffer(&irb->Base, name);
+ irb->Base.ClassID = INTEL_RB_CLASS;
+
+ if (texImage->TexFormat == &_mesa_texformat_argb8888) {
+ irb->Base._ActualFormat = GL_RGBA8;
+ irb->Base._BaseFormat = GL_RGBA;
+ DBG("Render to RGBA8 texture OK\n");
+ }
+ else if (texImage->TexFormat == &_mesa_texformat_rgb565) {
+ irb->Base._ActualFormat = GL_RGB5;
+ irb->Base._BaseFormat = GL_RGB;
+ DBG("Render to RGB5 texture OK\n");
+ }
+ else if (texImage->TexFormat == &_mesa_texformat_z16) {
+ irb->Base._ActualFormat = GL_DEPTH_COMPONENT16;
+ irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
+ DBG("Render to DEPTH16 texture OK\n");
+ }
+ else {
+ DBG("Render to texture BAD FORMAT %d\n",
+ texImage->TexFormat->MesaFormat);
+ _mesa_free(irb);
+ return NULL;
+ }
+
+ irb->Base.InternalFormat = irb->Base._ActualFormat;
+ irb->Base.Width = texImage->Width;
+ irb->Base.Height = texImage->Height;
+ irb->Base.DataType = GL_UNSIGNED_BYTE; /* FBO XXX fix */
+ irb->Base.RedBits = texImage->TexFormat->RedBits;
+ irb->Base.GreenBits = texImage->TexFormat->GreenBits;
+ irb->Base.BlueBits = texImage->TexFormat->BlueBits;
+ irb->Base.AlphaBits = texImage->TexFormat->AlphaBits;
+ irb->Base.DepthBits = texImage->TexFormat->DepthBits;
+
+ irb->Base.Delete = intel_delete_renderbuffer;
+ irb->Base.AllocStorage = intel_nop_alloc_storage;
+ intel_set_span_functions(&irb->Base);
+
+ irb->RenderToTexture = GL_TRUE;
+
+ return irb;
+}
+
+
+/**
+ * Called by glFramebufferTexture[123]DEXT() (and other places) to
+ * prepare for rendering into texture memory. This might be called
+ * many times to choose different texture levels, cube faces, etc
+ * before intel_finish_render_texture() is ever called.
+ */
+static void
+intel_render_texture(GLcontext * ctx,
+ struct gl_framebuffer *fb,
+ struct gl_renderbuffer_attachment *att)
+{
+ struct gl_texture_image *newImage
+ = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
+ struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer);
+ struct intel_texture_image *intel_image;
+ GLuint imageOffset;
+
+ (void) fb;
+
+ ASSERT(newImage);
+
+ if (!irb) {
+ irb = intel_wrap_texture(ctx, newImage);
+ if (irb) {
+ /* bind the wrapper to the attachment point */
+ _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base);
+ }
+ else {
+ /* fallback to software rendering */
+ _mesa_render_texture(ctx, fb, att);
+ return;
+ }
+ }
+
+ DBG("Begin render texture tid %x tex=%u w=%d h=%d refcount=%d\n",
+ _glthread_GetID(),
+ att->Texture->Name, newImage->Width, newImage->Height,
+ irb->Base.RefCount);
+
+ /* point the renderbufer's region to the texture image region */
+ intel_image = intel_texture_image(newImage);
+ if (irb->region != intel_image->mt->region) {
+ if (irb->region)
+ intel_region_release(&irb->region);
+ intel_region_reference(&irb->region, intel_image->mt->region);
+ }
+
+ /* compute offset of the particular 2D image within the texture region */
+ imageOffset = intel_miptree_image_offset(intel_image->mt,
+ att->CubeMapFace,
+ att->TextureLevel);
+
+ if (att->Texture->Target == GL_TEXTURE_3D) {
+ const GLuint *offsets = intel_miptree_depth_offsets(intel_image->mt,
+ att->TextureLevel);
+ imageOffset += offsets[att->Zoffset];
+ }
+
+ /* store that offset in the region */
+ intel_image->mt->region->draw_offset = imageOffset;
+
+ /* update drawing region, etc */
+ intel_draw_buffer(ctx, fb);
+}
+
+
+/**
+ * Called by Mesa when rendering to a texture is done.
+ */
+static void
+intel_finish_render_texture(GLcontext * ctx,
+ struct gl_renderbuffer_attachment *att)
+{
+ struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer);
+
+ DBG("End render texture (tid %x) tex %u\n", _glthread_GetID(), att->Texture->Name);
+
+ if (irb) {
+ /* just release the region */
+ intel_region_release(&irb->region);
+ }
+ else if (att->Renderbuffer) {
+ /* software fallback */
+ _mesa_finish_render_texture(ctx, att);
+ /* XXX FBO: Need to unmap the buffer (or in intelSpanRenderStart???) */
+ }
+}
+
+
+/**
+ * Do one-time context initializations related to GL_EXT_framebuffer_object.
+ * Hook in device driver functions.
+ */
+void
+intel_fbo_init(struct intel_context *intel)
+{
+ intel->ctx.Driver.NewFramebuffer = intel_new_framebuffer;
+ intel->ctx.Driver.NewRenderbuffer = intel_new_renderbuffer;
+ intel->ctx.Driver.BindFramebuffer = intel_bind_framebuffer;
+ intel->ctx.Driver.FramebufferRenderbuffer = intel_framebuffer_renderbuffer;
+ intel->ctx.Driver.RenderTexture = intel_render_texture;
+ intel->ctx.Driver.FinishRenderTexture = intel_finish_render_texture;
+ intel->ctx.Driver.ResizeBuffers = intel_resize_buffers;
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_fbo.h b/src/mesa/drivers/dri/i915pipe/intel_fbo.h
new file mode 100644
index 0000000000..7dc3967533
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_fbo.h
@@ -0,0 +1,127 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef INTEL_FBO_H
+#define INTEL_FBO_H
+
+
+#include "pipe/p_state.h"
+#include "pipe/softpipe/sp_surface.h"
+
+
+struct intel_context;
+struct intel_region;
+
+
+/**
+ * Intel framebuffer, derived from gl_framebuffer.
+ */
+struct intel_framebuffer
+{
+ struct gl_framebuffer Base;
+
+ struct intel_renderbuffer *color_rb[3];
+
+ /* Drawable page flipping state */
+ GLboolean pf_active;
+ GLuint pf_seq;
+ GLint pf_pipes;
+ GLint pf_current_page;
+ GLint pf_num_pages;
+
+ /* VBI
+ */
+ GLuint vbl_seq;
+ GLuint vblank_flags;
+ GLuint vbl_waited;
+
+ int64_t swap_ust;
+ int64_t swap_missed_ust;
+
+ GLuint swap_count;
+ GLuint swap_missed_count;
+};
+
+
+/**
+ * Intel renderbuffer, derived from gl_renderbuffer.
+ * Note: The PairedDepth and PairedStencil fields use renderbuffer IDs,
+ * not pointers because in some circumstances a deleted renderbuffer could
+ * result in a dangling pointer here.
+ */
+struct intel_renderbuffer
+{
+ struct gl_renderbuffer Base;
+ struct intel_region *region;
+ void *pfMap; /* possibly paged flipped map pointer */
+ GLuint pfPitch; /* possibly paged flipped pitch */
+ GLboolean RenderToTexture; /* RTT? */
+
+ GLuint PairedDepth; /**< only used if this is a depth renderbuffer */
+ GLuint PairedStencil; /**< only used if this is a stencil renderbuffer */
+
+ GLuint pf_pending; /**< sequence number of pending flip */
+
+ GLuint vbl_pending; /**< vblank sequence number of pending flip */
+
+ struct intel_surface *surface;
+};
+
+#if 0
+extern struct intel_renderbuffer *intel_create_renderbuffer(GLenum intFormat,
+ GLsizei width,
+ GLsizei height,
+ int offset,
+ int pitch,
+ int cpp,
+ void *map);
+#endif
+
+extern struct intel_renderbuffer *intel_new_renderbuffer_fb(GLuint intFormat);
+
+extern void intel_fbo_init(struct intel_context *intel);
+
+
+/* XXX make inline or macro */
+extern struct intel_renderbuffer *intel_get_renderbuffer(struct gl_framebuffer
+ *fb,
+ GLuint attIndex);
+
+extern void intel_flip_renderbuffers(struct intel_framebuffer *intel_fb);
+
+
+/* XXX make inline or macro */
+extern struct intel_region *intel_get_rb_region(struct gl_framebuffer *fb,
+ GLuint attIndex);
+
+
+
+extern struct pipe_surface *
+intel_new_surface(GLuint intFormat);
+
+
+#endif /* INTEL_FBO_H */
diff --git a/src/mesa/drivers/dri/i915pipe/intel_ioctl.c b/src/mesa/drivers/dri/i915pipe/intel_ioctl.c
new file mode 100644
index 0000000000..e349a3ecd9
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_ioctl.c
@@ -0,0 +1,137 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sched.h>
+
+#include "mtypes.h"
+#include "context.h"
+#include "swrast/swrast.h"
+
+#include "intel_context.h"
+#include "intel_ioctl.h"
+#include "intel_batchbuffer.h"
+#include "intel_blit.h"
+#include "intel_regions.h"
+#include "drm.h"
+
+#define FILE_DEBUG_FLAG DEBUG_IOCTL
+
+int
+intelEmitIrqLocked(struct intel_context *intel)
+{
+ drmI830IrqEmit ie;
+ int ret, seq;
+
+ assert(((*(int *) intel->driHwLock) & ~DRM_LOCK_CONT) ==
+ (DRM_LOCK_HELD | intel->hHWContext));
+
+ ie.irq_seq = &seq;
+
+ ret = drmCommandWriteRead(intel->driFd, DRM_I830_IRQ_EMIT,
+ &ie, sizeof(ie));
+ if (ret) {
+ fprintf(stderr, "%s: drmI830IrqEmit: %d\n", __FUNCTION__, ret);
+ exit(1);
+ }
+
+ DBG("%s --> %d\n", __FUNCTION__, seq);
+
+ return seq;
+}
+
+void
+intelWaitIrq(struct intel_context *intel, int seq)
+{
+ int ret;
+
+ DBG("%s %d\n", __FUNCTION__, seq);
+
+ intel->iw.irq_seq = seq;
+
+ do {
+ ret =
+ drmCommandWrite(intel->driFd, DRM_I830_IRQ_WAIT, &intel->iw,
+ sizeof(intel->iw));
+ } while (ret == -EAGAIN || ret == -EINTR);
+
+ if (ret) {
+ fprintf(stderr, "%s: drmI830IrqWait: %d\n", __FUNCTION__, ret);
+ exit(1);
+ }
+}
+
+
+void
+intel_batch_ioctl(struct intel_context *intel,
+ GLuint start_offset,
+ GLuint used,
+ GLboolean ignore_cliprects, GLboolean allow_unlock)
+{
+ drmI830BatchBuffer batch;
+
+ assert(intel->locked);
+ assert(used);
+
+ DBG("%s used %d offset %x..%x ignore_cliprects %d\n",
+ __FUNCTION__,
+ used, start_offset, start_offset + used, ignore_cliprects);
+
+ /* Throw away non-effective packets. Won't work once we have
+ * hardware contexts which would preserve statechanges beyond a
+ * single buffer.
+ */
+
+
+
+ batch.start = start_offset;
+ batch.used = used;
+ batch.cliprects = intel->pClipRects;
+ batch.num_cliprects = ignore_cliprects ? 0 : intel->numClipRects;
+ batch.DR1 = 0;
+ batch.DR4 = 0; /* still need this ? */
+
+ DBG("%s: 0x%x..0x%x DR4: %x cliprects: %d\n",
+ __FUNCTION__,
+ batch.start,
+ batch.start + batch.used * 4, batch.DR4, batch.num_cliprects);
+
+ if (drmCommandWrite(intel->driFd, DRM_I830_BATCHBUFFER, &batch,
+ sizeof(batch))) {
+ fprintf(stderr, "DRM_I830_BATCHBUFFER: %d\n", -errno);
+ UNLOCK_HARDWARE(intel);
+ exit(1);
+ }
+
+ /* FIXME: use hardware contexts to avoid 'losing' hardware after
+ * each buffer flush.
+ */
+ //intel->vtbl.lost_hardware(intel);
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_ioctl.h b/src/mesa/drivers/dri/i915pipe/intel_ioctl.h
new file mode 100644
index 0000000000..e8d07de893
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_ioctl.h
@@ -0,0 +1,40 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef INTEL_IOCTL_H
+#define INTEL_IOCTL_H
+
+#include "intel_context.h"
+
+void intelWaitIrq(struct intel_context *intel, int seq);
+int intelEmitIrqLocked(struct intel_context *intel);
+
+void intel_batch_ioctl(struct intel_context *intel,
+ GLuint start_offset,
+ GLuint used,
+ GLboolean ignore_cliprects, GLboolean allow_unlock);
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_mipmap_tree.c b/src/mesa/drivers/dri/i915pipe/intel_mipmap_tree.c
new file mode 100644
index 0000000000..88a9277427
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_mipmap_tree.c
@@ -0,0 +1,358 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "intel_context.h"
+#include "intel_mipmap_tree.h"
+#include "intel_regions.h"
+#include "enums.h"
+
+#define FILE_DEBUG_FLAG DEBUG_MIPTREE
+
+static GLenum
+target_to_target(GLenum target)
+{
+ switch (target) {
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
+ return GL_TEXTURE_CUBE_MAP_ARB;
+ default:
+ return target;
+ }
+}
+
+struct intel_mipmap_tree *
+intel_miptree_create(struct intel_context *intel,
+ GLenum target,
+ GLenum internal_format,
+ GLuint first_level,
+ GLuint last_level,
+ GLuint width0,
+ GLuint height0,
+ GLuint depth0, GLuint cpp, GLuint compress_byte)
+{
+ GLboolean ok;
+ struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1);
+
+ DBG("%s target %s format %s level %d..%d\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr(target),
+ _mesa_lookup_enum_by_nr(internal_format), first_level, last_level);
+
+ mt->target = target_to_target(target);
+ mt->internal_format = internal_format;
+ mt->first_level = first_level;
+ mt->last_level = last_level;
+ mt->width0 = width0;
+ mt->height0 = height0;
+ mt->depth0 = depth0;
+ mt->cpp = compress_byte ? compress_byte : cpp;
+ mt->compressed = compress_byte ? 1 : 0;
+ mt->refcount = 1;
+
+ switch (intel->intelScreen->deviceID) {
+ case PCI_CHIP_I945_G:
+ case PCI_CHIP_I945_GM:
+ case PCI_CHIP_I945_GME:
+ case PCI_CHIP_G33_G:
+ case PCI_CHIP_Q33_G:
+ case PCI_CHIP_Q35_G:
+// ok = i945_miptree_layout(mt);
+ break;
+ case PCI_CHIP_I915_G:
+ case PCI_CHIP_I915_GM:
+ case PCI_CHIP_I830_M:
+ case PCI_CHIP_I855_GM:
+ case PCI_CHIP_I865_G:
+ default:
+ /* All the i830 chips and the i915 use this layout:
+ */
+// ok = i915_miptree_layout(mt);
+ break;
+ }
+
+ ok = 0; /* TODO */
+
+ if (ok)
+ mt->region = intel_region_alloc(intel->intelScreen,
+ mt->cpp, mt->pitch, mt->total_height);
+
+ if (!mt->region) {
+ free(mt);
+ return NULL;
+ }
+
+ return mt;
+}
+
+
+void
+intel_miptree_reference(struct intel_mipmap_tree **dst,
+ struct intel_mipmap_tree *src)
+{
+ src->refcount++;
+ *dst = src;
+ DBG("%s %p refcount now %d\n", __FUNCTION__, src, src->refcount);
+}
+
+void
+intel_miptree_release(struct intel_context *intel,
+ struct intel_mipmap_tree **mt)
+{
+ if (!*mt)
+ return;
+
+ DBG("%s %p refcount will be %d\n", __FUNCTION__, *mt, (*mt)->refcount - 1);
+ if (--(*mt)->refcount <= 0) {
+ GLuint i;
+
+ DBG("%s deleting %p\n", __FUNCTION__, *mt);
+
+ intel_region_release(&((*mt)->region));
+
+ for (i = 0; i < MAX_TEXTURE_LEVELS; i++)
+ if ((*mt)->level[i].image_offset)
+ free((*mt)->level[i].image_offset);
+
+ free(*mt);
+ }
+ *mt = NULL;
+}
+
+
+
+
+/* Can the image be pulled into a unified mipmap tree. This mirrors
+ * the completeness test in a lot of ways.
+ *
+ * Not sure whether I want to pass gl_texture_image here.
+ */
+GLboolean
+intel_miptree_match_image(struct intel_mipmap_tree *mt,
+ struct gl_texture_image *image,
+ GLuint face, GLuint level)
+{
+ /* Images with borders are never pulled into mipmap trees.
+ */
+ if (image->Border)
+ return GL_FALSE;
+
+ if (image->InternalFormat != mt->internal_format ||
+ image->IsCompressed != mt->compressed)
+ return GL_FALSE;
+
+ /* Test image dimensions against the base level image adjusted for
+ * minification. This will also catch images not present in the
+ * tree, changed targets, etc.
+ */
+ if (image->Width != mt->level[level].width ||
+ image->Height != mt->level[level].height ||
+ image->Depth != mt->level[level].depth)
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+
+void
+intel_miptree_set_level_info(struct intel_mipmap_tree *mt,
+ GLuint level,
+ GLuint nr_images,
+ GLuint x, GLuint y, GLuint w, GLuint h, GLuint d)
+{
+
+ mt->level[level].width = w;
+ mt->level[level].height = h;
+ mt->level[level].depth = d;
+ mt->level[level].level_offset = (x + y * mt->pitch) * mt->cpp;
+ mt->level[level].nr_images = nr_images;
+
+ DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
+ level, w, h, d, x, y, mt->level[level].level_offset);
+
+ /* Not sure when this would happen, but anyway:
+ */
+ if (mt->level[level].image_offset) {
+ free(mt->level[level].image_offset);
+ mt->level[level].image_offset = NULL;
+ }
+
+ assert(nr_images);
+
+ mt->level[level].image_offset = malloc(nr_images * sizeof(GLuint));
+ mt->level[level].image_offset[0] = 0;
+}
+
+
+
+void
+intel_miptree_set_image_offset(struct intel_mipmap_tree *mt,
+ GLuint level, GLuint img, GLuint x, GLuint y)
+{
+ if (img == 0 && level == 0)
+ assert(x == 0 && y == 0);
+
+ assert(img < mt->level[level].nr_images);
+
+ mt->level[level].image_offset[img] = (x + y * mt->pitch);
+
+ DBG("%s level %d img %d pos %d,%d image_offset %x\n",
+ __FUNCTION__, level, img, x, y, mt->level[level].image_offset[img]);
+}
+
+
+/* Although we use the image_offset[] array to store relative offsets
+ * to cube faces, Mesa doesn't know anything about this and expects
+ * each cube face to be treated as a separate image.
+ *
+ * These functions present that view to mesa:
+ */
+const GLuint *
+intel_miptree_depth_offsets(struct intel_mipmap_tree *mt, GLuint level)
+{
+ static const GLuint zero = 0;
+
+ if (mt->target != GL_TEXTURE_3D || mt->level[level].nr_images == 1)
+ return &zero;
+ else
+ return mt->level[level].image_offset;
+}
+
+
+GLuint
+intel_miptree_image_offset(struct intel_mipmap_tree * mt,
+ GLuint face, GLuint level)
+{
+ if (mt->target == GL_TEXTURE_CUBE_MAP_ARB)
+ return (mt->level[level].level_offset +
+ mt->level[level].image_offset[face] * mt->cpp);
+ else
+ return mt->level[level].level_offset;
+}
+
+
+
+/**
+ * Map a teximage in a mipmap tree.
+ * \param row_stride returns row stride in bytes
+ * \param image_stride returns image stride in bytes (for 3D textures).
+ * \return address of mapping
+ */
+GLubyte *
+intel_miptree_image_map(struct intel_context * intel,
+ struct intel_mipmap_tree * mt,
+ GLuint face,
+ GLuint level,
+ GLuint * row_stride, GLuint * image_offsets)
+{
+ DBG("%s \n", __FUNCTION__);
+
+ if (row_stride)
+ *row_stride = mt->pitch * mt->cpp;
+
+ if (image_offsets)
+ memcpy(image_offsets, mt->level[level].image_offset,
+ mt->level[level].depth * sizeof(GLuint));
+
+ return (intel_region_map(intel->intelScreen, mt->region) +
+ intel_miptree_image_offset(mt, face, level));
+}
+
+void
+intel_miptree_image_unmap(struct intel_context *intel,
+ struct intel_mipmap_tree *mt)
+{
+ DBG("%s\n", __FUNCTION__);
+ intel_region_unmap(intel->intelScreen, mt->region);
+}
+
+
+
+/* Upload data for a particular image.
+ */
+void
+intel_miptree_image_data(struct intel_context *intel,
+ struct intel_mipmap_tree *dst,
+ GLuint face,
+ GLuint level,
+ void *src,
+ GLuint src_row_pitch, GLuint src_image_pitch)
+{
+ GLuint depth = dst->level[level].depth;
+ GLuint dst_offset = intel_miptree_image_offset(dst, face, level);
+ const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level);
+ GLuint i;
+ GLuint height = 0;
+
+ DBG("%s\n", __FUNCTION__);
+ for (i = 0; i < depth; i++) {
+ height = dst->level[level].height;
+ if(dst->compressed)
+ height /= 4;
+ intel_region_data(intel->intelScreen, dst->region,
+ dst_offset + dst_depth_offset[i], /* dst_offset */
+ 0, 0, /* dstx, dsty */
+ src,
+ src_row_pitch,
+ 0, 0, /* source x, y */
+ dst->level[level].width, height); /* width, height */
+
+ src += src_image_pitch * dst->cpp;
+ }
+}
+
+/* Copy mipmap image between trees
+ */
+void
+intel_miptree_image_copy(struct intel_context *intel,
+ struct intel_mipmap_tree *dst,
+ GLuint face, GLuint level,
+ struct intel_mipmap_tree *src)
+{
+ GLuint width = src->level[level].width;
+ GLuint height = src->level[level].height;
+ GLuint depth = src->level[level].depth;
+ GLuint dst_offset = intel_miptree_image_offset(dst, face, level);
+ GLuint src_offset = intel_miptree_image_offset(src, face, level);
+ const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level);
+ const GLuint *src_depth_offset = intel_miptree_depth_offsets(src, level);
+ GLuint i;
+
+ if (dst->compressed)
+ height /= 4;
+ for (i = 0; i < depth; i++) {
+ intel_region_copy(intel->intelScreen,
+ dst->region, dst_offset + dst_depth_offset[i],
+ 0,
+ 0,
+ src->region, src_offset + src_depth_offset[i],
+ 0, 0, width, height);
+ }
+
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_mipmap_tree.h b/src/mesa/drivers/dri/i915pipe/intel_mipmap_tree.h
new file mode 100644
index 0000000000..ecdb7be244
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_mipmap_tree.h
@@ -0,0 +1,198 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef INTEL_MIPMAP_TREE_H
+#define INTEL_MIPMAP_TREE_H
+
+#include "intel_regions.h"
+
+/* A layer on top of the intel_regions code which adds:
+ *
+ * - Code to size and layout a region to hold a set of mipmaps.
+ * - Query to determine if a new image fits in an existing tree.
+ * - More refcounting
+ * - maybe able to remove refcounting from intel_region?
+ * - ?
+ *
+ * The fixed mipmap layout of intel hardware where one offset
+ * specifies the position of all images in a mipmap hierachy
+ * complicates the implementation of GL texture image commands,
+ * compared to hardware where each image is specified with an
+ * independent offset.
+ *
+ * In an ideal world, each texture object would be associated with a
+ * single bufmgr buffer or 2d intel_region, and all the images within
+ * the texture object would slot into the tree as they arrive. The
+ * reality can be a little messier, as images can arrive from the user
+ * with sizes that don't fit in the existing tree, or in an order
+ * where the tree layout cannot be guessed immediately.
+ *
+ * This structure encodes an idealized mipmap tree. The GL image
+ * commands build these where possible, otherwise store the images in
+ * temporary system buffers.
+ */
+
+
+/**
+ * Describes the location of each texture image within a texture region.
+ */
+struct intel_mipmap_level
+{
+ GLuint level_offset;
+ GLuint width;
+ GLuint height;
+ GLuint depth;
+ GLuint nr_images;
+
+ /* Explicitly store the offset of each image for each cube face or
+ * depth value. Pretty much have to accept that hardware formats
+ * are going to be so diverse that there is no unified way to
+ * compute the offsets of depth/cube images within a mipmap level,
+ * so have to store them as a lookup table:
+ */
+ GLuint *image_offset;
+};
+
+struct intel_mipmap_tree
+{
+ /* Effectively the key:
+ */
+ GLenum target;
+ GLenum internal_format;
+
+ GLuint first_level;
+ GLuint last_level;
+
+ GLuint width0, height0, depth0; /**< Level zero image dimensions */
+ GLuint cpp;
+ GLboolean compressed;
+
+ /* Derived from the above:
+ */
+ GLuint pitch;
+ GLuint depth_pitch; /* per-image on i945? */
+ GLuint total_height;
+
+ /* Includes image offset tables:
+ */
+ struct intel_mipmap_level level[MAX_TEXTURE_LEVELS];
+
+ /* The data is held here:
+ */
+ struct intel_region *region;
+
+ /* These are also refcounted:
+ */
+ GLuint refcount;
+};
+
+
+
+struct intel_mipmap_tree *intel_miptree_create(struct intel_context *intel,
+ GLenum target,
+ GLenum internal_format,
+ GLuint first_level,
+ GLuint last_level,
+ GLuint width0,
+ GLuint height0,
+ GLuint depth0,
+ GLuint cpp,
+ GLuint compress_byte);
+
+void intel_miptree_reference(struct intel_mipmap_tree **dst,
+ struct intel_mipmap_tree *src);
+
+void intel_miptree_release(struct intel_context *intel,
+ struct intel_mipmap_tree **mt);
+
+/* Check if an image fits an existing mipmap tree layout
+ */
+GLboolean intel_miptree_match_image(struct intel_mipmap_tree *mt,
+ struct gl_texture_image *image,
+ GLuint face, GLuint level);
+
+/* Return a pointer to an image within a tree. Return image stride as
+ * well.
+ */
+GLubyte *intel_miptree_image_map(struct intel_context *intel,
+ struct intel_mipmap_tree *mt,
+ GLuint face,
+ GLuint level,
+ GLuint * row_stride, GLuint * image_stride);
+
+void intel_miptree_image_unmap(struct intel_context *intel,
+ struct intel_mipmap_tree *mt);
+
+
+/* Return the linear offset of an image relative to the start of the
+ * tree:
+ */
+GLuint intel_miptree_image_offset(struct intel_mipmap_tree *mt,
+ GLuint face, GLuint level);
+
+/* Return pointers to each 2d slice within an image. Indexed by depth
+ * value.
+ */
+const GLuint *intel_miptree_depth_offsets(struct intel_mipmap_tree *mt,
+ GLuint level);
+
+
+void intel_miptree_set_level_info(struct intel_mipmap_tree *mt,
+ GLuint level,
+ GLuint nr_images,
+ GLuint x, GLuint y,
+ GLuint w, GLuint h, GLuint d);
+
+void intel_miptree_set_image_offset(struct intel_mipmap_tree *mt,
+ GLuint level,
+ GLuint img, GLuint x, GLuint y);
+
+
+/* Upload an image into a tree
+ */
+void intel_miptree_image_data(struct intel_context *intel,
+ struct intel_mipmap_tree *dst,
+ GLuint face,
+ GLuint level,
+ void *src,
+ GLuint src_row_pitch, GLuint src_image_pitch);
+
+/* Copy an image between two trees
+ */
+void intel_miptree_image_copy(struct intel_context *intel,
+ struct intel_mipmap_tree *dst,
+ GLuint face, GLuint level,
+ struct intel_mipmap_tree *src);
+
+/* i915_mipmap_tree.c:
+ */
+GLboolean i915_miptree_layout(struct intel_mipmap_tree *mt);
+GLboolean i945_miptree_layout(struct intel_mipmap_tree *mt);
+
+
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_pixel.c b/src/mesa/drivers/dri/i915pipe/intel_pixel.c
new file mode 100644
index 0000000000..104d288de0
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_pixel.c
@@ -0,0 +1,45 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portionsalloc
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "enums.h"
+#include "state.h"
+#include "swrast/swrast.h"
+
+#include "intel_context.h"
+#include "intel_pixel.h"
+#include "intel_regions.h"
+
+
+void
+intelInitPixelFuncs(struct dd_function_table *functions)
+{
+ functions->Accum = _swrast_Accum;
+ functions->Bitmap = _swrast_Bitmap;
+ functions->CopyPixels = _swrast_CopyPixels;
+ functions->ReadPixels = _swrast_ReadPixels;
+ functions->DrawPixels = _swrast_DrawPixels;
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_pixel.h b/src/mesa/drivers/dri/i915pipe/intel_pixel.h
new file mode 100644
index 0000000000..a6fcf90ce0
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_pixel.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef INTEL_PIXEL_H
+#define INTEL_PIXEL_H
+
+#include "mtypes.h"
+
+void intelInitPixelFuncs(struct dd_function_table *functions);
+
+GLboolean intel_check_blit_fragment_ops(GLcontext * ctx);
+
+GLboolean intel_check_meta_tex_fragment_ops(GLcontext * ctx);
+
+GLboolean intel_check_blit_format(struct intel_region *region,
+ GLenum format, GLenum type);
+
+
+void intelReadPixels(GLcontext * ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const struct gl_pixelstore_attrib *pack,
+ GLvoid * pixels);
+
+void intelDrawPixels(GLcontext * ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format,
+ GLenum type,
+ const struct gl_pixelstore_attrib *unpack,
+ const GLvoid * pixels);
+
+void intelCopyPixels(GLcontext * ctx,
+ GLint srcx, GLint srcy,
+ GLsizei width, GLsizei height,
+ GLint destx, GLint desty, GLenum type);
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_reg.h b/src/mesa/drivers/dri/i915pipe/intel_reg.h
new file mode 100644
index 0000000000..7828ba6ad3
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_reg.h
@@ -0,0 +1,88 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#ifndef _INTEL_REG_H_
+#define _INTEL_REG_H_
+
+
+
+#define CMD_3D (0x3<<29)
+
+
+#define _3DPRIMITIVE ((0x3<<29)|(0x1f<<24))
+#define PRIM_INDIRECT (1<<23)
+#define PRIM_INLINE (0<<23)
+#define PRIM_INDIRECT_SEQUENTIAL (0<<17)
+#define PRIM_INDIRECT_ELTS (1<<17)
+
+#define PRIM3D_TRILIST (0x0<<18)
+#define PRIM3D_TRISTRIP (0x1<<18)
+#define PRIM3D_TRISTRIP_RVRSE (0x2<<18)
+#define PRIM3D_TRIFAN (0x3<<18)
+#define PRIM3D_POLY (0x4<<18)
+#define PRIM3D_LINELIST (0x5<<18)
+#define PRIM3D_LINESTRIP (0x6<<18)
+#define PRIM3D_RECTLIST (0x7<<18)
+#define PRIM3D_POINTLIST (0x8<<18)
+#define PRIM3D_DIB (0x9<<18)
+#define PRIM3D_MASK (0x1f<<18)
+
+#define I915PACKCOLOR4444(r,g,b,a) \
+ ((((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | ((g) & 0xf0) | ((b) >> 4))
+
+#define I915PACKCOLOR1555(r,g,b,a) \
+ ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) | \
+ ((a) ? 0x8000 : 0))
+
+#define I915PACKCOLOR565(r,g,b) \
+ ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3))
+
+#define I915PACKCOLOR8888(r,g,b,a) \
+ ((a<<24) | (r<<16) | (g<<8) | b)
+
+
+
+
+#define BR00_BITBLT_CLIENT 0x40000000
+#define BR00_OP_COLOR_BLT 0x10000000
+#define BR00_OP_SRC_COPY_BLT 0x10C00000
+#define BR13_SOLID_PATTERN 0x80000000
+
+#define XY_COLOR_BLT_CMD ((2<<29)|(0x50<<22)|0x4)
+#define XY_COLOR_BLT_WRITE_ALPHA (1<<21)
+#define XY_COLOR_BLT_WRITE_RGB (1<<20)
+
+#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
+#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
+
+#define MI_WAIT_FOR_EVENT ((0x3<<23))
+#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6)
+#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2)
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_regions.c b/src/mesa/drivers/dri/i915pipe/intel_regions.c
new file mode 100644
index 0000000000..7d19bd07d3
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_regions.c
@@ -0,0 +1,480 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/* Provide additional functionality on top of bufmgr buffers:
+ * - 2d semantics and blit operations
+ * - refcounting of buffers for multiple images in a buffer.
+ * - refcounting of buffer mappings.
+ * - some logic for moving the buffers to the best memory pools for
+ * given operations.
+ *
+ * Most of this is to make it easier to implement the fixed-layout
+ * mipmap tree required by intel hardware in the face of GL's
+ * programming interface where each image can be specifed in random
+ * order and it isn't clear what layout the tree should have until the
+ * last moment.
+ */
+
+#include "intel_context.h"
+#include "intel_regions.h"
+#include "intel_blit.h"
+#include "intel_buffer_objects.h"
+#include "dri_bufmgr.h"
+#include "intel_batchbuffer.h"
+
+#define FILE_DEBUG_FLAG DEBUG_REGION
+
+void
+intel_region_idle(intelScreenPrivate *intelScreen, struct intel_region *region)
+{
+ DBG("%s\n", __FUNCTION__);
+ if (region && region->buffer)
+ driBOWaitIdle(region->buffer, GL_FALSE);
+}
+
+/* XXX: Thread safety?
+ */
+GLubyte *
+intel_region_map(intelScreenPrivate *intelScreen, struct intel_region *region)
+{
+ DBG("%s\n", __FUNCTION__);
+ if (!region->map_refcount++) {
+ if (region->pbo)
+ intel_region_cow(intelScreen, region);
+
+ region->map = driBOMap(region->buffer,
+ DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0);
+ }
+
+ return region->map;
+}
+
+void
+intel_region_unmap(intelScreenPrivate *intelScreen, struct intel_region *region)
+{
+ DBG("%s\n", __FUNCTION__);
+ if (!--region->map_refcount) {
+ driBOUnmap(region->buffer);
+ region->map = NULL;
+ }
+}
+
+#undef TEST_CACHED_TEXTURES
+
+struct intel_region *
+intel_region_alloc(intelScreenPrivate *intelScreen,
+ GLuint cpp, GLuint pitch, GLuint height)
+{
+ struct intel_region *region = calloc(sizeof(*region), 1);
+ struct intel_context *intel = intelScreenContext(intelScreen);
+
+ DBG("%s\n", __FUNCTION__);
+
+ region->cpp = cpp;
+ region->pitch = pitch;
+ region->height = height; /* needed? */
+ region->refcount = 1;
+
+ driGenBuffers(intelScreen->regionPool,
+ "region", 1, &region->buffer, 64,
+#ifdef TEST_CACHED_TEXTURES
+ DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_BIND_CACHED |
+ DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE,
+#else
+ 0,
+#endif
+ 0);
+ LOCK_HARDWARE(intel);
+ driBOData(region->buffer, pitch * cpp * height, NULL, 0);
+ UNLOCK_HARDWARE(intel);
+ return region;
+}
+
+void
+intel_region_reference(struct intel_region **dst, struct intel_region *src)
+{
+ assert(*dst == NULL);
+ if (src) {
+ src->refcount++;
+ *dst = src;
+ }
+}
+
+void
+intel_region_release(struct intel_region **region)
+{
+ if (!*region)
+ return;
+
+ DBG("%s %d\n", __FUNCTION__, (*region)->refcount - 1);
+
+ ASSERT((*region)->refcount > 0);
+ (*region)->refcount--;
+
+ if ((*region)->refcount == 0) {
+ assert((*region)->map_refcount == 0);
+
+ if ((*region)->pbo)
+ (*region)->pbo->region = NULL;
+ (*region)->pbo = NULL;
+ driBOUnReference((*region)->buffer);
+ free(*region);
+ }
+ *region = NULL;
+}
+
+
+struct intel_region *
+intel_region_create_static(intelScreenPrivate *intelScreen,
+ GLuint mem_type,
+ GLuint offset,
+ void *virtual,
+ GLuint cpp, GLuint pitch, GLuint height)
+{
+ struct intel_region *region = calloc(sizeof(*region), 1);
+ DBG("%s\n", __FUNCTION__);
+
+ region->cpp = cpp;
+ region->pitch = pitch;
+ region->height = height; /* needed? */
+ region->refcount = 1;
+
+ /*
+ * We use a "shared" buffer type to indicate buffers created and
+ * shared by others.
+ */
+
+ driGenBuffers(intelScreen->staticPool, "static region", 1,
+ &region->buffer, 64,
+ DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_NO_MOVE |
+ DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0);
+ driBOSetStatic(region->buffer, offset, pitch * cpp * height, virtual, 0);
+
+ return region;
+}
+
+
+
+void
+intel_region_update_static(intelScreenPrivate *intelScreen,
+ struct intel_region *region,
+ GLuint mem_type,
+ GLuint offset,
+ void *virtual,
+ GLuint cpp, GLuint pitch, GLuint height)
+{
+ DBG("%s\n", __FUNCTION__);
+
+ region->cpp = cpp;
+ region->pitch = pitch;
+ region->height = height; /* needed? */
+
+ /*
+ * We use a "shared" buffer type to indicate buffers created and
+ * shared by others.
+ */
+
+ driDeleteBuffers(1, &region->buffer);
+ driGenBuffers(intelScreen->staticPool, "static region", 1,
+ &region->buffer, 64,
+ DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_NO_MOVE |
+ DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0);
+ driBOSetStatic(region->buffer, offset, pitch * cpp * height, virtual, 0);
+
+}
+
+
+
+/*
+ * XXX Move this into core Mesa?
+ */
+static void
+_mesa_copy_rect(GLubyte * dst,
+ GLuint cpp,
+ GLuint dst_pitch,
+ GLuint dst_x,
+ GLuint dst_y,
+ GLuint width,
+ GLuint height,
+ const GLubyte * src,
+ GLuint src_pitch, GLuint src_x, GLuint src_y)
+{
+ GLuint i;
+
+ dst_pitch *= cpp;
+ src_pitch *= cpp;
+ dst += dst_x * cpp;
+ src += src_x * cpp;
+ dst += dst_y * dst_pitch;
+ src += src_y * dst_pitch;
+ width *= cpp;
+
+ if (width == dst_pitch && width == src_pitch)
+ memcpy(dst, src, height * width);
+ else {
+ for (i = 0; i < height; i++) {
+ memcpy(dst, src, width);
+ dst += dst_pitch;
+ src += src_pitch;
+ }
+ }
+}
+
+
+/* Upload data to a rectangular sub-region. Lots of choices how to do this:
+ *
+ * - memcpy by span to current destination
+ * - upload data as new buffer and blit
+ *
+ * Currently always memcpy.
+ */
+void
+intel_region_data(intelScreenPrivate *intelScreen,
+ struct intel_region *dst,
+ GLuint dst_offset,
+ GLuint dstx, GLuint dsty,
+ const void *src, GLuint src_pitch,
+ GLuint srcx, GLuint srcy, GLuint width, GLuint height)
+{
+ struct intel_context *intel = intelScreenContext(intelScreen);
+
+ DBG("%s\n", __FUNCTION__);
+
+ if (intel == NULL)
+ return;
+
+ if (dst->pbo) {
+ if (dstx == 0 &&
+ dsty == 0 && width == dst->pitch && height == dst->height)
+ intel_region_release_pbo(intelScreen, dst);
+ else
+ intel_region_cow(intelScreen, dst);
+ }
+
+
+ LOCK_HARDWARE(intel);
+
+ _mesa_copy_rect(intel_region_map(intelScreen, dst) + dst_offset,
+ dst->cpp,
+ dst->pitch,
+ dstx, dsty, width, height, src, src_pitch, srcx, srcy);
+
+ intel_region_unmap(intelScreen, dst);
+
+ UNLOCK_HARDWARE(intel);
+
+}
+
+/* Copy rectangular sub-regions. Need better logic about when to
+ * push buffers into AGP - will currently do so whenever possible.
+ */
+void
+intel_region_copy(intelScreenPrivate *intelScreen,
+ struct intel_region *dst,
+ GLuint dst_offset,
+ GLuint dstx, GLuint dsty,
+ struct intel_region *src,
+ GLuint src_offset,
+ GLuint srcx, GLuint srcy, GLuint width, GLuint height)
+{
+ struct intel_context *intel = intelScreenContext(intelScreen);
+
+ DBG("%s\n", __FUNCTION__);
+
+ if (intel == NULL)
+ return;
+
+ if (dst->pbo) {
+ if (dstx == 0 &&
+ dsty == 0 && width == dst->pitch && height == dst->height)
+ intel_region_release_pbo(intelScreen, dst);
+ else
+ intel_region_cow(intelScreen, dst);
+ }
+
+ assert(src->cpp == dst->cpp);
+
+ intelEmitCopyBlit(intel,
+ dst->cpp,
+ src->pitch, src->buffer, src_offset,
+ dst->pitch, dst->buffer, dst_offset,
+ srcx, srcy, dstx, dsty, width, height,
+ GL_COPY);
+}
+
+/* Fill a rectangular sub-region. Need better logic about when to
+ * push buffers into AGP - will currently do so whenever possible.
+ */
+void
+intel_region_fill(intelScreenPrivate *intelScreen,
+ struct intel_region *dst,
+ GLuint dst_offset,
+ GLuint dstx, GLuint dsty,
+ GLuint width, GLuint height, GLuint color)
+{
+ struct intel_context *intel = intelScreenContext(intelScreen);
+
+ DBG("%s\n", __FUNCTION__);
+
+ if (intel == NULL)
+ return;
+
+ if (dst->pbo) {
+ if (dstx == 0 &&
+ dsty == 0 && width == dst->pitch && height == dst->height)
+ intel_region_release_pbo(intelScreen, dst);
+ else
+ intel_region_cow(intelScreen, dst);
+ }
+
+ intelEmitFillBlit(intel,
+ dst->cpp,
+ dst->pitch, dst->buffer, dst_offset,
+ dstx, dsty, width, height, color);
+}
+
+/* Attach to a pbo, discarding our data. Effectively zero-copy upload
+ * the pbo's data.
+ */
+void
+intel_region_attach_pbo(intelScreenPrivate *intelScreen,
+ struct intel_region *region,
+ struct intel_buffer_object *pbo)
+{
+ if (region->pbo == pbo)
+ return;
+
+ /* If there is already a pbo attached, break the cow tie now.
+ * Don't call intel_region_release_pbo() as that would
+ * unnecessarily allocate a new buffer we would have to immediately
+ * discard.
+ */
+ if (region->pbo) {
+ region->pbo->region = NULL;
+ region->pbo = NULL;
+ }
+
+ if (region->buffer) {
+ driDeleteBuffers(1, &region->buffer);
+ region->buffer = NULL;
+ }
+
+ region->pbo = pbo;
+ region->pbo->region = region;
+ region->buffer = driBOReference(pbo->buffer);
+}
+
+
+/* Break the COW tie to the pbo. The pbo gets to keep the data.
+ */
+void
+intel_region_release_pbo(intelScreenPrivate *intelScreen,
+ struct intel_region *region)
+{
+ struct intel_context *intel = intelScreenContext(intelScreen);
+
+ assert(region->buffer == region->pbo->buffer);
+ region->pbo->region = NULL;
+ region->pbo = NULL;
+ driBOUnReference(region->buffer);
+ region->buffer = NULL;
+
+ driGenBuffers(intelScreen->regionPool,
+ "region", 1, &region->buffer, 64, 0, 0);
+
+ LOCK_HARDWARE(intel);
+ driBOData(region->buffer,
+ region->cpp * region->pitch * region->height, NULL, 0);
+ UNLOCK_HARDWARE(intel);
+}
+
+/* Break the COW tie to the pbo. Both the pbo and the region end up
+ * with a copy of the data.
+ */
+void
+intel_region_cow(intelScreenPrivate *intelScreen, struct intel_region *region)
+{
+ struct intel_context *intel = intelScreenContext(intelScreen);
+ struct intel_buffer_object *pbo = region->pbo;
+
+ if (intel == NULL)
+ return;
+
+ intel_region_release_pbo(intelScreen, region);
+
+ assert(region->cpp * region->pitch * region->height == pbo->Base.Size);
+
+ DBG("%s (%d bytes)\n", __FUNCTION__, pbo->Base.Size);
+
+ /* Now blit from the texture buffer to the new buffer:
+ */
+
+ intel_batchbuffer_flush(intel->batch);
+
+ if (!intel->locked) {
+ LOCK_HARDWARE(intel);
+ intelEmitCopyBlit(intel,
+ region->cpp,
+ region->pitch,
+ region->buffer, 0,
+ region->pitch,
+ pbo->buffer, 0,
+ 0, 0, 0, 0,
+ region->pitch, region->height,
+ GL_COPY);
+
+ intel_batchbuffer_flush(intel->batch);
+ UNLOCK_HARDWARE(intel);
+ }
+ else {
+ intelEmitCopyBlit(intel,
+ region->cpp,
+ region->pitch,
+ region->buffer, 0,
+ region->pitch,
+ pbo->buffer, 0,
+ 0, 0, 0, 0,
+ region->pitch, region->height,
+ GL_COPY);
+
+ intel_batchbuffer_flush(intel->batch);
+ }
+}
+
+struct _DriBufferObject *
+intel_region_buffer(intelScreenPrivate *intelScreen,
+ struct intel_region *region, GLuint flag)
+{
+ if (region->pbo) {
+ if (flag == INTEL_WRITE_PART)
+ intel_region_cow(intelScreen, region);
+ else if (flag == INTEL_WRITE_FULL)
+ intel_region_release_pbo(intelScreen, region);
+ }
+
+ return region->buffer;
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_regions.h b/src/mesa/drivers/dri/i915pipe/intel_regions.h
new file mode 100644
index 0000000000..d938c107a4
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_regions.h
@@ -0,0 +1,141 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef INTEL_REGIONS_H
+#define INTEL_REGIONS_H
+
+#include "mtypes.h"
+#include "intel_screen.h"
+
+struct intel_context;
+struct intel_buffer_object;
+
+/**
+ * A layer on top of the bufmgr buffers that adds a few useful things:
+ *
+ * - Refcounting for local buffer references.
+ * - Refcounting for buffer maps
+ * - Buffer dimensions - pitch and height.
+ * - Blitter commands for copying 2D regions between buffers. (really???)
+ */
+struct intel_region
+{
+ struct _DriBufferObject *buffer; /**< buffer manager's buffer ID */
+ GLuint refcount; /**< Reference count for region */
+ GLuint cpp; /**< bytes per pixel */
+ GLuint pitch; /**< in pixels */
+ GLuint height; /**< in pixels */
+ GLubyte *map; /**< only non-NULL when region is actually mapped */
+ GLuint map_refcount; /**< Reference count for mapping */
+
+ GLuint draw_offset; /**< Offset of drawing address within the region */
+
+ struct intel_buffer_object *pbo; /* zero-copy uploads */
+};
+
+
+/* Allocate a refcounted region. Pointers to regions should only be
+ * copied by calling intel_reference_region().
+ */
+struct intel_region *intel_region_alloc(intelScreenPrivate *intelScreen,
+ GLuint cpp,
+ GLuint pitch, GLuint height);
+
+void intel_region_reference(struct intel_region **dst,
+ struct intel_region *src);
+
+void intel_region_release(struct intel_region **ib);
+
+extern struct intel_region
+*intel_region_create_static(intelScreenPrivate *intelScreen,
+ GLuint mem_type,
+ GLuint offset,
+ void *virtual,
+ GLuint cpp,
+ GLuint pitch, GLuint height);
+extern void
+intel_region_update_static(intelScreenPrivate *intelScreen,
+ struct intel_region *region,
+ GLuint mem_type,
+ GLuint offset,
+ void *virtual,
+ GLuint cpp, GLuint pitch, GLuint height);
+
+
+void intel_region_idle(intelScreenPrivate *intelScreen,
+ struct intel_region *ib);
+
+/* Map/unmap regions. This is refcounted also:
+ */
+GLubyte *intel_region_map(intelScreenPrivate *intelScreen,
+ struct intel_region *ib);
+
+void intel_region_unmap(intelScreenPrivate *intelScreen, struct intel_region *ib);
+
+
+/* Upload data to a rectangular sub-region
+ */
+void intel_region_data(intelScreenPrivate *intelScreen,
+ struct intel_region *dest,
+ GLuint dest_offset,
+ GLuint destx, GLuint desty,
+ const void *src, GLuint src_stride,
+ GLuint srcx, GLuint srcy, GLuint width, GLuint height);
+
+/* Copy rectangular sub-regions
+ */
+void intel_region_copy(intelScreenPrivate *intelScreen,
+ struct intel_region *dest,
+ GLuint dest_offset,
+ GLuint destx, GLuint desty,
+ struct intel_region *src,
+ GLuint src_offset,
+ GLuint srcx, GLuint srcy, GLuint width, GLuint height);
+
+/* Fill a rectangular sub-region
+ */
+void intel_region_fill(intelScreenPrivate *intelScreen,
+ struct intel_region *dest,
+ GLuint dest_offset,
+ GLuint destx, GLuint desty,
+ GLuint width, GLuint height, GLuint color);
+
+/* Helpers for zerocopy uploads, particularly texture image uploads:
+ */
+void intel_region_attach_pbo(intelScreenPrivate *intelScreen,
+ struct intel_region *region,
+ struct intel_buffer_object *pbo);
+void intel_region_release_pbo(intelScreenPrivate *intelScreen,
+ struct intel_region *region);
+void intel_region_cow(intelScreenPrivate *intelScreen,
+ struct intel_region *region);
+
+struct _DriBufferObject *intel_region_buffer(intelScreenPrivate *intelScreen,
+ struct intel_region *region,
+ GLuint flag);
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_render.c b/src/mesa/drivers/dri/i915pipe/intel_render.c
new file mode 100644
index 0000000000..c8b6d308d9
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_render.c
@@ -0,0 +1,244 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/*
+ * Render unclipped vertex buffers by emitting vertices directly to
+ * dma buffers. Use strip/fan hardware acceleration where possible.
+ *
+ */
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "imports.h"
+#include "mtypes.h"
+#include "enums.h"
+
+#include "tnl/t_context.h"
+#include "tnl/t_vertex.h"
+
+#include "intel_screen.h"
+#include "intel_context.h"
+#include "intel_tris.h"
+#include "intel_batchbuffer.h"
+#include "intel_reg.h"
+
+/*
+ * Render unclipped vertex buffers by emitting vertices directly to
+ * dma buffers. Use strip/fan hardware primitives where possible.
+ * Try to simulate missing primitives with indexed vertices.
+ */
+#define HAVE_POINTS 0 /* Has it, but can't use because subpixel has to
+ * be adjusted for points on the INTEL/I845G
+ */
+#define HAVE_LINES 1
+#define HAVE_LINE_STRIPS 1
+#define HAVE_TRIANGLES 1
+#define HAVE_TRI_STRIPS 1
+#define HAVE_TRI_STRIP_1 0 /* has it, template can't use it yet */
+#define HAVE_TRI_FANS 1
+#define HAVE_POLYGONS 1
+#define HAVE_QUADS 0
+#define HAVE_QUAD_STRIPS 0
+
+#define HAVE_ELTS 0
+
+static GLuint hw_prim[GL_POLYGON + 1] = {
+ 0,
+ PRIM3D_LINELIST,
+ PRIM3D_LINESTRIP,
+ PRIM3D_LINESTRIP,
+ PRIM3D_TRILIST,
+ PRIM3D_TRISTRIP,
+ PRIM3D_TRIFAN,
+ 0,
+ 0,
+ PRIM3D_POLY
+};
+
+static const GLenum reduced_prim[GL_POLYGON + 1] = {
+ GL_POINTS,
+ GL_LINES,
+ GL_LINES,
+ GL_LINES,
+ GL_TRIANGLES,
+ GL_TRIANGLES,
+ GL_TRIANGLES,
+ GL_TRIANGLES,
+ GL_TRIANGLES,
+ GL_TRIANGLES
+};
+
+static const int scale_prim[GL_POLYGON + 1] = {
+ 0, /* fallback case */
+ 1,
+ 2,
+ 2,
+ 1,
+ 3,
+ 3,
+ 0, /* fallback case */
+ 0, /* fallback case */
+ 3
+};
+
+
+static void
+intelDmaPrimitive(struct intel_context *intel, GLenum prim)
+{
+ if (0)
+ fprintf(stderr, "%s %s\n", __FUNCTION__, _mesa_lookup_enum_by_nr(prim));
+ INTEL_FIREVERTICES(intel);
+ intel->vtbl.reduced_primitive_state(intel, reduced_prim[prim]);
+ intelStartInlinePrimitive(intel, hw_prim[prim], INTEL_BATCH_CLIPRECTS);
+}
+
+
+#define LOCAL_VARS struct intel_context *intel = intel_context(ctx)
+#define INIT( prim ) \
+do { \
+ intelDmaPrimitive( intel, prim ); \
+} while (0)
+
+#define FLUSH() INTEL_FIREVERTICES(intel)
+
+#define GET_SUBSEQUENT_VB_MAX_VERTS() \
+ ((intel->batch->size - 1500) / (intel->vertex_size*4))
+#define GET_CURRENT_VB_MAX_VERTS() GET_SUBSEQUENT_VB_MAX_VERTS()
+
+#define ALLOC_VERTS( nr ) \
+ intelExtendInlinePrimitive( intel, (nr) * intel->vertex_size )
+
+#define EMIT_VERTS( ctx, j, nr, buf ) \
+ _tnl_emit_vertices_to_buffer(ctx, j, (j)+(nr), buf )
+
+#define TAG(x) intel_##x
+#include "tnl_dd/t_dd_dmatmp.h"
+
+
+/**********************************************************************/
+/* Render pipeline stage */
+/**********************************************************************/
+
+/* Heuristic to choose between the two render paths:
+ */
+static GLboolean
+choose_render(struct intel_context *intel, struct vertex_buffer *VB)
+{
+ int vertsz = intel->vertex_size;
+ int cost_render = 0;
+ int cost_fallback = 0;
+ int nr_prims = 0;
+ int nr_rprims = 0;
+ int nr_rverts = 0;
+ int rprim = intel->reduced_primitive;
+ int i = 0;
+
+ for (i = 0; i < VB->PrimitiveCount; i++) {
+ GLuint prim = VB->Primitive[i].mode;
+ GLuint length = VB->Primitive[i].count;
+
+ if (!length)
+ continue;
+
+ nr_prims++;
+ nr_rverts += length * scale_prim[prim & PRIM_MODE_MASK];
+
+ if (reduced_prim[prim & PRIM_MODE_MASK] != rprim) {
+ nr_rprims++;
+ rprim = reduced_prim[prim & PRIM_MODE_MASK];
+ }
+ }
+
+ /* One point for each generated primitive:
+ */
+ cost_render = nr_prims;
+ cost_fallback = nr_rprims;
+
+ /* One point for every 1024 dwords (4k) of dma:
+ */
+ cost_render += (vertsz * i) / 1024;
+ cost_fallback += (vertsz * nr_rverts) / 1024;
+
+ if (0)
+ fprintf(stderr, "cost render: %d fallback: %d\n",
+ cost_render, cost_fallback);
+
+ if (cost_render > cost_fallback)
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+intel_run_render(GLcontext * ctx, struct tnl_pipeline_stage *stage)
+{
+ struct intel_context *intel = intel_context(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint i;
+
+ intel->vtbl.render_prevalidate( intel );
+
+ /* Don't handle clipping or indexed vertices.
+ */
+ if (intel->RenderIndex != 0 ||
+ !intel_validate_render(ctx, VB) || !choose_render(intel, VB)) {
+ return GL_TRUE;
+ }
+
+ tnl->clipspace.new_inputs |= VERT_BIT_POS;
+
+ tnl->Driver.Render.Start(ctx);
+
+ for (i = 0; i < VB->PrimitiveCount; i++) {
+ GLuint prim = VB->Primitive[i].mode;
+ GLuint start = VB->Primitive[i].start;
+ GLuint length = VB->Primitive[i].count;
+
+ if (!length)
+ continue;
+
+ intel_render_tab_verts[prim & PRIM_MODE_MASK] (ctx, start,
+ start + length, prim);
+ }
+
+ tnl->Driver.Render.Finish(ctx);
+
+ INTEL_FIREVERTICES(intel);
+
+ return GL_FALSE; /* finished the pipe */
+}
+
+const struct tnl_pipeline_stage _intel_render_stage = {
+ "intel render",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ intel_run_render /* run */
+};
diff --git a/src/mesa/drivers/dri/i915pipe/intel_rotate.c b/src/mesa/drivers/dri/i915pipe/intel_rotate.c
new file mode 100644
index 0000000000..12d98c4ad2
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_rotate.c
@@ -0,0 +1,237 @@
+
+/**
+ * Routines for simple 2D->2D transformations for rotated, flipped screens.
+ *
+ * XXX This code is not intel-specific. Move it into a common/utility
+ * someday.
+ */
+
+#include "intel_rotate.h"
+
+#define MIN2(A, B) ( ((A) < (B)) ? (A) : (B) )
+
+#define ABS(A) ( ((A) < 0) ? -(A) : (A) )
+
+
+void
+matrix23Set(struct matrix23 *m,
+ int m00, int m01, int m02, int m10, int m11, int m12)
+{
+ m->m00 = m00;
+ m->m01 = m01;
+ m->m02 = m02;
+ m->m10 = m10;
+ m->m11 = m11;
+ m->m12 = m12;
+}
+
+
+/*
+ * Transform (x,y) coordinate by the given matrix.
+ */
+void
+matrix23TransformCoordf(const struct matrix23 *m, float *x, float *y)
+{
+ const float x0 = *x;
+ const float y0 = *y;
+
+ *x = m->m00 * x0 + m->m01 * y0 + m->m02;
+ *y = m->m10 * x0 + m->m11 * y0 + m->m12;
+}
+
+
+void
+matrix23TransformCoordi(const struct matrix23 *m, int *x, int *y)
+{
+ const int x0 = *x;
+ const int y0 = *y;
+
+ *x = m->m00 * x0 + m->m01 * y0 + m->m02;
+ *y = m->m10 * x0 + m->m11 * y0 + m->m12;
+}
+
+
+/*
+ * Transform a width and height by the given matrix.
+ * XXX this could be optimized quite a bit.
+ */
+void
+matrix23TransformDistance(const struct matrix23 *m, int *xDist, int *yDist)
+{
+ int x0 = 0, y0 = 0;
+ int x1 = *xDist, y1 = 0;
+ int x2 = 0, y2 = *yDist;
+ matrix23TransformCoordi(m, &x0, &y0);
+ matrix23TransformCoordi(m, &x1, &y1);
+ matrix23TransformCoordi(m, &x2, &y2);
+
+ *xDist = (x1 - x0) + (x2 - x0);
+ *yDist = (y1 - y0) + (y2 - y0);
+
+ if (*xDist < 0)
+ *xDist = -*xDist;
+ if (*yDist < 0)
+ *yDist = -*yDist;
+}
+
+
+/**
+ * Transform the rect defined by (x, y, w, h) by m.
+ */
+void
+matrix23TransformRect(const struct matrix23 *m, int *x, int *y, int *w,
+ int *h)
+{
+ int x0 = *x, y0 = *y;
+ int x1 = *x + *w, y1 = *y;
+ int x2 = *x + *w, y2 = *y + *h;
+ int x3 = *x, y3 = *y + *h;
+ matrix23TransformCoordi(m, &x0, &y0);
+ matrix23TransformCoordi(m, &x1, &y1);
+ matrix23TransformCoordi(m, &x2, &y2);
+ matrix23TransformCoordi(m, &x3, &y3);
+ *w = ABS(x1 - x0) + ABS(x2 - x1);
+ /**w = ABS(*w);*/
+ *h = ABS(y1 - y0) + ABS(y2 - y1);
+ /**h = ABS(*h);*/
+ *x = MIN2(x0, x1);
+ *x = MIN2(*x, x2);
+ *y = MIN2(y0, y1);
+ *y = MIN2(*y, y2);
+}
+
+
+/*
+ * Make rotation matrix for width X height screen.
+ */
+void
+matrix23Rotate(struct matrix23 *m, int width, int height, int angle)
+{
+ switch (angle) {
+ case 0:
+ matrix23Set(m, 1, 0, 0, 0, 1, 0);
+ break;
+ case 90:
+ matrix23Set(m, 0, 1, 0, -1, 0, width);
+ break;
+ case 180:
+ matrix23Set(m, -1, 0, width, 0, -1, height);
+ break;
+ case 270:
+ matrix23Set(m, 0, -1, height, 1, 0, 0);
+ break;
+ default:
+ /*abort() */ ;
+ }
+}
+
+
+/*
+ * Make flip/reflection matrix for width X height screen.
+ */
+void
+matrix23Flip(struct matrix23 *m, int width, int height, int xflip, int yflip)
+{
+ if (xflip) {
+ m->m00 = -1;
+ m->m01 = 0;
+ m->m02 = width - 1;
+ }
+ else {
+ m->m00 = 1;
+ m->m01 = 0;
+ m->m02 = 0;
+ }
+ if (yflip) {
+ m->m10 = 0;
+ m->m11 = -1;
+ m->m12 = height - 1;
+ }
+ else {
+ m->m10 = 0;
+ m->m11 = 1;
+ m->m12 = 0;
+ }
+}
+
+
+/*
+ * result = a * b
+ */
+void
+matrix23Multiply(struct matrix23 *result,
+ const struct matrix23 *a, const struct matrix23 *b)
+{
+ result->m00 = a->m00 * b->m00 + a->m01 * b->m10;
+ result->m01 = a->m00 * b->m01 + a->m01 * b->m11;
+ result->m02 = a->m00 * b->m02 + a->m01 * b->m12 + a->m02;
+
+ result->m10 = a->m10 * b->m00 + a->m11 * b->m10;
+ result->m11 = a->m10 * b->m01 + a->m11 * b->m11;
+ result->m12 = a->m10 * b->m02 + a->m11 * b->m12 + a->m12;
+}
+
+
+#if 000
+
+#include <stdio.h>
+
+int
+main(int argc, char *argv[])
+{
+ int width = 500, height = 400;
+ int rot;
+ int fx = 0, fy = 0; /* flip x and/or y ? */
+ int coords[4][2];
+
+ /* four corner coords to test with */
+ coords[0][0] = 0;
+ coords[0][1] = 0;
+ coords[1][0] = width - 1;
+ coords[1][1] = 0;
+ coords[2][0] = width - 1;
+ coords[2][1] = height - 1;
+ coords[3][0] = 0;
+ coords[3][1] = height - 1;
+
+
+ for (rot = 0; rot < 360; rot += 90) {
+ struct matrix23 rotate, flip, m;
+ int i;
+
+ printf("Rot %d, xFlip %d, yFlip %d:\n", rot, fx, fy);
+
+ /* make transformation matrix 'm' */
+ matrix23Rotate(&rotate, width, height, rot);
+ matrix23Flip(&flip, width, height, fx, fy);
+ matrix23Multiply(&m, &rotate, &flip);
+
+ /* xform four coords */
+ for (i = 0; i < 4; i++) {
+ int x = coords[i][0];
+ int y = coords[i][1];
+ matrix23TransformCoordi(&m, &x, &y);
+ printf(" %d, %d -> %d %d\n", coords[i][0], coords[i][1], x, y);
+ }
+
+ /* xform width, height */
+ {
+ int x = width;
+ int y = height;
+ matrix23TransformDistance(&m, &x, &y);
+ printf(" %d x %d -> %d x %d\n", width, height, x, y);
+ }
+
+ /* xform rect */
+ {
+ int x = 50, y = 10, w = 200, h = 100;
+ matrix23TransformRect(&m, &x, &y, &w, &h);
+ printf(" %d,%d %d x %d -> %d, %d %d x %d\n", 50, 10, 200, 100,
+ x, y, w, h);
+ }
+
+ }
+
+ return 0;
+}
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_rotate.h b/src/mesa/drivers/dri/i915pipe/intel_rotate.h
new file mode 100644
index 0000000000..9c8802ca47
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_rotate.h
@@ -0,0 +1,39 @@
+#ifndef INTEL_ROTATE_H
+#define INTEL_ROTATE_H 1
+
+struct matrix23
+{
+ int m00, m01, m02;
+ int m10, m11, m12;
+};
+
+
+
+extern void
+matrix23Set(struct matrix23 *m,
+ int m00, int m01, int m02, int m10, int m11, int m12);
+
+extern void matrix23TransformCoordi(const struct matrix23 *m, int *x, int *y);
+
+extern void
+matrix23TransformCoordf(const struct matrix23 *m, float *x, float *y);
+
+extern void
+matrix23TransformDistance(const struct matrix23 *m, int *xDist, int *yDist);
+
+extern void
+matrix23TransformRect(const struct matrix23 *m,
+ int *x, int *y, int *w, int *h);
+
+extern void
+matrix23Rotate(struct matrix23 *m, int width, int height, int angle);
+
+extern void
+matrix23Flip(struct matrix23 *m, int width, int height, int xflip, int yflip);
+
+extern void
+matrix23Multiply(struct matrix23 *result,
+ const struct matrix23 *a, const struct matrix23 *b);
+
+
+#endif /* INTEL_ROTATE_H */
diff --git a/src/mesa/drivers/dri/i915pipe/intel_screen.c b/src/mesa/drivers/dri/i915pipe/intel_screen.c
new file mode 100644
index 0000000000..8d8b2523f3
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_screen.c
@@ -0,0 +1,708 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "glheader.h"
+#include "context.h"
+#include "framebuffer.h"
+#include "matrix.h"
+#include "renderbuffer.h"
+#include "simple_list.h"
+#include "utils.h"
+#include "vblank.h"
+#include "xmlpool.h"
+
+
+#include "intel_screen.h"
+
+#include "intel_buffers.h"
+#include "intel_tex.h"
+#include "intel_span.h"
+#include "intel_tris.h"
+#include "intel_ioctl.h"
+#include "intel_fbo.h"
+
+#include "i830_dri.h"
+#include "dri_bufpool.h"
+#include "intel_regions.h"
+#include "intel_batchbuffer.h"
+
+PUBLIC const char __driConfigOptions[] =
+ DRI_CONF_BEGIN DRI_CONF_SECTION_PERFORMANCE
+ DRI_CONF_FTHROTTLE_MODE(DRI_CONF_FTHROTTLE_IRQS)
+ DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_0)
+ DRI_CONF_SECTION_END DRI_CONF_SECTION_QUALITY
+ DRI_CONF_FORCE_S3TC_ENABLE(false)
+ DRI_CONF_ALLOW_LARGE_TEXTURES(1)
+ DRI_CONF_SECTION_END DRI_CONF_END;
+ const GLuint __driNConfigOptions = 4;
+
+#ifdef USE_NEW_INTERFACE
+ static PFNGLXCREATECONTEXTMODES create_context_modes = NULL;
+#endif /*USE_NEW_INTERFACE */
+
+ extern const struct dri_extension card_extensions[];
+
+/**
+ * Map all the memory regions described by the screen.
+ * \return GL_TRUE if success, GL_FALSE if error.
+ */
+GLboolean
+intelMapScreenRegions(__DRIscreenPrivate * sPriv)
+{
+ intelScreenPrivate *intelScreen = (intelScreenPrivate *) sPriv->private;
+
+ if (intelScreen->front.handle) {
+ if (drmMap(sPriv->fd,
+ intelScreen->front.handle,
+ intelScreen->front.size,
+ (drmAddress *) & intelScreen->front.map) != 0) {
+ _mesa_problem(NULL, "drmMap(frontbuffer) failed!");
+ return GL_FALSE;
+ }
+ }
+ else {
+ _mesa_warning(NULL, "no front buffer handle in intelMapScreenRegions!");
+ }
+
+ if (0)
+ printf("Mappings: front: %p\n", intelScreen->front.map);
+ return GL_TRUE;
+}
+
+
+static struct intel_region *
+intel_recreate_static(intelScreenPrivate *intelScreen,
+ struct intel_region *region,
+ GLuint mem_type,
+ GLuint offset,
+ void *virtual,
+ GLuint cpp, GLuint pitch, GLuint height)
+{
+ if (region) {
+ intel_region_update_static(intelScreen, region, mem_type, offset,
+ virtual, cpp, pitch, height);
+ } else {
+ region = intel_region_create_static(intelScreen, mem_type, offset,
+ virtual, cpp, pitch, height);
+ }
+ return region;
+}
+
+
+/* Create intel_region structs to describe the static front,back,depth
+ * buffers created by the xserver.
+ * Only used for real front buffer now.
+ *
+ * Note that these don't allocate video memory, just describe
+ * allocations already made by the X server.
+ */
+static void
+intel_recreate_static_regions(intelScreenPrivate *intelScreen)
+{
+/* this is the real front buffer which is only used for blitting to */
+ intelScreen->front_region =
+ intel_recreate_static(intelScreen,
+ intelScreen->front_region,
+ DRM_BO_FLAG_MEM_TT,
+ intelScreen->front.offset,
+ intelScreen->front.map,
+ intelScreen->cpp,
+ intelScreen->front.pitch / intelScreen->cpp,
+ intelScreen->height);
+
+}
+
+/**
+ * Use the information in the sarea to update the screen parameters
+ * related to screen rotation. Needs to be called locked.
+ */
+void
+intelUpdateScreenRotation(__DRIscreenPrivate * sPriv, drmI830Sarea * sarea)
+{
+ intelScreenPrivate *intelScreen = (intelScreenPrivate *) sPriv->private;
+
+ intelUnmapScreenRegions(intelScreen);
+ intelUpdateScreenFromSAREA(intelScreen, sarea);
+ if (!intelMapScreenRegions(sPriv)) {
+ fprintf(stderr, "ERROR Remapping screen regions!!!\n");
+ }
+ intel_recreate_static_regions(intelScreen);
+}
+
+
+void
+intelUnmapScreenRegions(intelScreenPrivate * intelScreen)
+{
+#define REALLY_UNMAP 1
+ if (intelScreen->front.map) {
+#if REALLY_UNMAP
+ if (drmUnmap(intelScreen->front.map, intelScreen->front.size) != 0)
+ printf("drmUnmap front failed!\n");
+#endif
+ intelScreen->front.map = NULL;
+ }
+}
+
+
+static void
+intelPrintDRIInfo(intelScreenPrivate * intelScreen,
+ __DRIscreenPrivate * sPriv, I830DRIPtr gDRIPriv)
+{
+ fprintf(stderr, "*** Front size: 0x%x offset: 0x%x pitch: %d\n",
+ intelScreen->front.size, intelScreen->front.offset,
+ intelScreen->front.pitch);
+ fprintf(stderr, "*** Memory : 0x%x\n", gDRIPriv->mem);
+}
+
+
+static void
+intelPrintSAREA(const drmI830Sarea * sarea)
+{
+ fprintf(stderr, "SAREA: sarea width %d height %d\n", sarea->width,
+ sarea->height);
+ fprintf(stderr, "SAREA: pitch: %d\n", sarea->pitch);
+ fprintf(stderr,
+ "SAREA: front offset: 0x%08x size: 0x%x handle: 0x%x\n",
+ sarea->front_offset, sarea->front_size,
+ (unsigned) sarea->front_handle);
+ fprintf(stderr,
+ "SAREA: back offset: 0x%08x size: 0x%x handle: 0x%x\n",
+ sarea->back_offset, sarea->back_size,
+ (unsigned) sarea->back_handle);
+ fprintf(stderr, "SAREA: depth offset: 0x%08x size: 0x%x handle: 0x%x\n",
+ sarea->depth_offset, sarea->depth_size,
+ (unsigned) sarea->depth_handle);
+ fprintf(stderr, "SAREA: tex offset: 0x%08x size: 0x%x handle: 0x%x\n",
+ sarea->tex_offset, sarea->tex_size, (unsigned) sarea->tex_handle);
+ fprintf(stderr, "SAREA: rotation: %d\n", sarea->rotation);
+ fprintf(stderr,
+ "SAREA: rotated offset: 0x%08x size: 0x%x\n",
+ sarea->rotated_offset, sarea->rotated_size);
+ fprintf(stderr, "SAREA: rotated pitch: %d\n", sarea->rotated_pitch);
+}
+
+
+/**
+ * A number of the screen parameters are obtained/computed from
+ * information in the SAREA. This function updates those parameters.
+ */
+void
+intelUpdateScreenFromSAREA(intelScreenPrivate * intelScreen,
+ drmI830Sarea * sarea)
+{
+ intelScreen->width = sarea->width;
+ intelScreen->height = sarea->height;
+
+ intelScreen->front.offset = sarea->front_offset;
+ intelScreen->front.pitch = sarea->pitch * intelScreen->cpp;
+ intelScreen->front.handle = sarea->front_handle;
+ intelScreen->front.size = sarea->front_size;
+
+ if (0)
+ intelPrintSAREA(sarea);
+}
+
+GLboolean
+intelCreatePools(intelScreenPrivate *intelScreen)
+{
+ unsigned batchPoolSize = 1024*1024;
+ __DRIscreenPrivate * sPriv = intelScreen->driScrnPriv;
+
+ if (intelScreen->havePools)
+ return GL_TRUE;
+
+ batchPoolSize /= intelScreen->maxBatchSize;
+ intelScreen->regionPool = driDRMPoolInit(sPriv->fd);
+
+ if (!intelScreen->regionPool)
+ return GL_FALSE;
+
+ intelScreen->staticPool = driDRMStaticPoolInit(sPriv->fd);
+
+ if (!intelScreen->staticPool)
+ return GL_FALSE;
+
+ intelScreen->texPool = intelScreen->regionPool;
+
+ intelScreen->batchPool = driBatchPoolInit(sPriv->fd,
+ DRM_BO_FLAG_EXE |
+ DRM_BO_FLAG_MEM_TT |
+ DRM_BO_FLAG_MEM_LOCAL,
+ intelScreen->maxBatchSize,
+ batchPoolSize, 5);
+ if (!intelScreen->batchPool) {
+ fprintf(stderr, "Failed to initialize batch pool - possible incorrect agpgart installed\n");
+ return GL_FALSE;
+ }
+
+ intel_recreate_static_regions(intelScreen);
+ intelScreen->havePools = GL_TRUE;
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+intelInitDriver(__DRIscreenPrivate * sPriv)
+{
+ intelScreenPrivate *intelScreen;
+ I830DRIPtr gDRIPriv = (I830DRIPtr) sPriv->pDevPriv;
+ drmI830Sarea *sarea;
+
+ PFNGLXSCRENABLEEXTENSIONPROC glx_enable_extension =
+ (PFNGLXSCRENABLEEXTENSIONPROC) (*dri_interface->
+ getProcAddress("glxEnableExtension"));
+ void *const psc = sPriv->psc->screenConfigs;
+
+ if (sPriv->devPrivSize != sizeof(I830DRIRec)) {
+ fprintf(stderr,
+ "\nERROR! sizeof(I830DRIRec) does not match passed size from device driver\n");
+ return GL_FALSE;
+ }
+
+ /* Allocate the private area */
+ intelScreen = (intelScreenPrivate *) CALLOC(sizeof(intelScreenPrivate));
+ if (!intelScreen) {
+ fprintf(stderr, "\nERROR! Allocating private area failed\n");
+ return GL_FALSE;
+ }
+ /* parse information in __driConfigOptions */
+ driParseOptionInfo(&intelScreen->optionCache,
+ __driConfigOptions, __driNConfigOptions);
+
+ intelScreen->driScrnPriv = sPriv;
+ sPriv->private = (void *) intelScreen;
+ intelScreen->sarea_priv_offset = gDRIPriv->sarea_priv_offset;
+ sarea = (drmI830Sarea *)
+ (((GLubyte *) sPriv->pSAREA) + intelScreen->sarea_priv_offset);
+
+ intelScreen->maxBatchSize = BATCH_SZ;
+ intelScreen->deviceID = gDRIPriv->deviceID;
+ if (intelScreen->deviceID == PCI_CHIP_I865_G)
+ intelScreen->maxBatchSize = 4096;
+
+ intelScreen->mem = gDRIPriv->mem;
+ intelScreen->cpp = gDRIPriv->cpp;
+
+ switch (gDRIPriv->bitsPerPixel) {
+ case 16:
+ break;
+ case 32:
+ break;
+ default:
+ exit(1);
+ break;
+ }
+
+ intelUpdateScreenFromSAREA(intelScreen, sarea);
+
+ if (!intelMapScreenRegions(sPriv)) {
+ fprintf(stderr, "\nERROR! mapping regions\n");
+ _mesa_free(intelScreen);
+ sPriv->private = NULL;
+ return GL_FALSE;
+ }
+
+
+ intelScreen->sarea_priv_offset = gDRIPriv->sarea_priv_offset;
+
+ if (0)
+ intelPrintDRIInfo(intelScreen, sPriv, gDRIPriv);
+
+ intelScreen->drmMinor = sPriv->drmMinor;
+
+ /* Determine if IRQs are active? */
+ {
+ int ret;
+ drmI830GetParam gp;
+
+ gp.param = I830_PARAM_IRQ_ACTIVE;
+ gp.value = &intelScreen->irq_active;
+
+ ret = drmCommandWriteRead(sPriv->fd, DRM_I830_GETPARAM,
+ &gp, sizeof(gp));
+ if (ret) {
+ fprintf(stderr, "drmI830GetParam: %d\n", ret);
+ return GL_FALSE;
+ }
+ }
+
+ /* Determine if batchbuffers are allowed */
+ {
+ int ret;
+ drmI830GetParam gp;
+
+ gp.param = I830_PARAM_ALLOW_BATCHBUFFER;
+ gp.value = &intelScreen->allow_batchbuffer;
+
+ ret = drmCommandWriteRead(sPriv->fd, DRM_I830_GETPARAM,
+ &gp, sizeof(gp));
+ if (ret) {
+ fprintf(stderr, "drmI830GetParam: (%d) %d\n", gp.param, ret);
+ return GL_FALSE;
+ }
+ }
+
+ if (glx_enable_extension != NULL) {
+ (*glx_enable_extension) (psc, "GLX_SGI_swap_control");
+ (*glx_enable_extension) (psc, "GLX_SGI_video_sync");
+ (*glx_enable_extension) (psc, "GLX_MESA_swap_control");
+ (*glx_enable_extension) (psc, "GLX_MESA_swap_frame_usage");
+ (*glx_enable_extension) (psc, "GLX_SGI_make_current_read");
+ }
+
+ return GL_TRUE;
+}
+
+
+static void
+intelDestroyScreen(__DRIscreenPrivate * sPriv)
+{
+ intelScreenPrivate *intelScreen = (intelScreenPrivate *) sPriv->private;
+
+ intelUnmapScreenRegions(intelScreen);
+
+ if (intelScreen->havePools) {
+ driPoolTakeDown(intelScreen->regionPool);
+ driPoolTakeDown(intelScreen->staticPool);
+ driPoolTakeDown(intelScreen->batchPool);
+ }
+ FREE(intelScreen);
+ sPriv->private = NULL;
+}
+
+
+/**
+ * This is called when we need to set up GL rendering to a new X window.
+ */
+static GLboolean
+intelCreateBuffer(__DRIscreenPrivate * driScrnPriv,
+ __DRIdrawablePrivate * driDrawPriv,
+ const __GLcontextModes * mesaVis, GLboolean isPixmap)
+{
+#if 0
+ intelScreenPrivate *screen = (intelScreenPrivate *) driScrnPriv->private;
+#endif
+
+ if (isPixmap) {
+ return GL_FALSE; /* not implemented */
+ }
+ else {
+ GLboolean swStencil = (mesaVis->stencilBits > 0 &&
+ mesaVis->depthBits != 24);
+ GLenum rgbFormat = (mesaVis->redBits == 5 ? GL_RGB5 : GL_RGBA8);
+
+ struct intel_framebuffer *intel_fb = CALLOC_STRUCT(intel_framebuffer);
+
+ if (!intel_fb)
+ return GL_FALSE;
+
+ _mesa_initialize_framebuffer(&intel_fb->Base, mesaVis);
+
+ {
+ /* fake frontbuffer */
+ /* XXX allocation should only happen in the unusual case
+ it's actually needed */
+ intel_fb->color_rb[0]
+ = intel_new_renderbuffer_fb(rgbFormat);
+ _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_FRONT_LEFT,
+ &intel_fb->color_rb[0]->Base);
+ }
+
+ if (mesaVis->doubleBufferMode) {
+ intel_fb->color_rb[1]
+ = intel_new_renderbuffer_fb(rgbFormat);
+ _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_BACK_LEFT,
+ &intel_fb->color_rb[1]->Base);
+
+#if 0
+ if (screen->third.handle) {
+ struct gl_renderbuffer *tmp_rb = NULL;
+
+ intel_fb->color_rb[2]
+ = intel_new_renderbuffer_fb(rgbFormat);
+ _mesa_reference_renderbuffer(&tmp_rb, &intel_fb->color_rb[2]->Base);
+ }
+#endif
+ }
+
+ if (mesaVis->depthBits == 24 && mesaVis->stencilBits == 8) {
+ /* combined depth/stencil buffer */
+ struct intel_renderbuffer *depthStencilRb
+ = intel_new_renderbuffer_fb(GL_DEPTH24_STENCIL8_EXT);
+ /* note: bind RB to two attachment points */
+ _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_DEPTH,
+ &depthStencilRb->Base);
+ _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_STENCIL,
+ &depthStencilRb->Base);
+ }
+ else if (mesaVis->depthBits == 16) {
+ /* just 16-bit depth buffer, no hw stencil */
+ struct intel_renderbuffer *depthRb
+ = intel_new_renderbuffer_fb(GL_DEPTH_COMPONENT16);
+ _mesa_add_renderbuffer(&intel_fb->Base, BUFFER_DEPTH, &depthRb->Base);
+ }
+
+
+ /* now add any/all software-based renderbuffers we may need */
+ _mesa_add_soft_renderbuffers(&intel_fb->Base,
+ GL_FALSE, /* never sw color */
+ GL_FALSE, /* never sw depth */
+ swStencil, mesaVis->accumRedBits > 0,
+ GL_FALSE, /* never sw alpha */
+ GL_FALSE /* never sw aux */ );
+ driDrawPriv->driverPrivate = (void *) intel_fb;
+
+ return GL_TRUE;
+ }
+}
+
+static void
+intelDestroyBuffer(__DRIdrawablePrivate * driDrawPriv)
+{
+ _mesa_unreference_framebuffer((GLframebuffer **)(&(driDrawPriv->driverPrivate)));
+}
+
+
+/**
+ * Get information about previous buffer swaps.
+ */
+static int
+intelGetSwapInfo(__DRIdrawablePrivate * dPriv, __DRIswapInfo * sInfo)
+{
+ struct intel_framebuffer *intel_fb;
+
+ if ((dPriv == NULL) || (dPriv->driverPrivate == NULL)
+ || (sInfo == NULL)) {
+ return -1;
+ }
+
+ intel_fb = dPriv->driverPrivate;
+ sInfo->swap_count = intel_fb->swap_count;
+ sInfo->swap_ust = intel_fb->swap_ust;
+ sInfo->swap_missed_count = intel_fb->swap_missed_count;
+
+ sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0)
+ ? driCalculateSwapUsage(dPriv, 0, intel_fb->swap_missed_ust)
+ : 0.0;
+
+ return 0;
+}
+
+
+
+
+static const struct __DriverAPIRec intelAPI = {
+ .InitDriver = intelInitDriver,
+ .DestroyScreen = intelDestroyScreen,
+ .CreateContext = intelCreateContext,
+ .DestroyContext = intelDestroyContext,
+ .CreateBuffer = intelCreateBuffer,
+ .DestroyBuffer = intelDestroyBuffer,
+ .SwapBuffers = intelSwapBuffers,
+ .MakeCurrent = intelMakeCurrent,
+ .UnbindContext = intelUnbindContext,
+ .GetSwapInfo = intelGetSwapInfo,
+ .GetMSC = driGetMSC32,
+ .WaitForMSC = driWaitForMSC32,
+ .WaitForSBC = NULL,
+ .SwapBuffersMSC = NULL,
+ .CopySubBuffer = intelCopySubBuffer,
+ .setTexOffset = intelSetTexOffset,
+};
+
+
+static __GLcontextModes *
+intelFillInModes(unsigned pixel_bits, unsigned depth_bits,
+ unsigned stencil_bits, GLboolean have_back_buffer)
+{
+ __GLcontextModes *modes;
+ __GLcontextModes *m;
+ unsigned num_modes;
+ unsigned depth_buffer_factor;
+ unsigned back_buffer_factor;
+ GLenum fb_format;
+ GLenum fb_type;
+
+ /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
+ * support pageflipping at all.
+ */
+ static const GLenum back_buffer_modes[] = {
+ GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML
+ };
+
+ u_int8_t depth_bits_array[3];
+ u_int8_t stencil_bits_array[3];
+
+
+ depth_bits_array[0] = 0;
+ depth_bits_array[1] = depth_bits;
+ depth_bits_array[2] = depth_bits;
+
+ /* Just like with the accumulation buffer, always provide some modes
+ * with a stencil buffer. It will be a sw fallback, but some apps won't
+ * care about that.
+ */
+ stencil_bits_array[0] = 0;
+ stencil_bits_array[1] = 0;
+ if (depth_bits == 24)
+ stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
+
+ stencil_bits_array[2] = (stencil_bits == 0) ? 8 : stencil_bits;
+
+ depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 3 : 1;
+ back_buffer_factor = (have_back_buffer) ? 3 : 1;
+
+ num_modes = depth_buffer_factor * back_buffer_factor * 4;
+
+ if (pixel_bits == 16) {
+ fb_format = GL_RGB;
+ fb_type = GL_UNSIGNED_SHORT_5_6_5;
+ }
+ else {
+ fb_format = GL_BGRA;
+ fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+
+ modes =
+ (*dri_interface->createContextModes) (num_modes,
+ sizeof(__GLcontextModes));
+ m = modes;
+ if (!driFillInModes(&m, fb_format, fb_type,
+ depth_bits_array, stencil_bits_array,
+ depth_buffer_factor, back_buffer_modes,
+ back_buffer_factor, GLX_TRUE_COLOR)) {
+ fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__,
+ __LINE__);
+ return NULL;
+ }
+ if (!driFillInModes(&m, fb_format, fb_type,
+ depth_bits_array, stencil_bits_array,
+ depth_buffer_factor, back_buffer_modes,
+ back_buffer_factor, GLX_DIRECT_COLOR)) {
+ fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__,
+ __LINE__);
+ return NULL;
+ }
+
+ /* Mark the visual as slow if there are "fake" stencil bits.
+ */
+ for (m = modes; m != NULL; m = m->next) {
+ if ((m->stencilBits != 0) && (m->stencilBits != stencil_bits)) {
+ m->visualRating = GLX_SLOW_CONFIG;
+ }
+ }
+
+ return modes;
+}
+
+
+/**
+ * This is the bootstrap function for the driver. libGL supplies all of the
+ * requisite information about the system, and the driver initializes itself.
+ * This routine also fills in the linked list pointed to by \c driver_modes
+ * with the \c __GLcontextModes that the driver can support for windows or
+ * pbuffers.
+ *
+ * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
+ * failure.
+ */
+PUBLIC void *
+__driCreateNewScreen_20050727(__DRInativeDisplay * dpy, int scrn,
+ __DRIscreen * psc,
+ const __GLcontextModes * modes,
+ const __DRIversion * ddx_version,
+ const __DRIversion * dri_version,
+ const __DRIversion * drm_version,
+ const __DRIframebuffer * frame_buffer,
+ drmAddress pSAREA, int fd,
+ int internal_api_version,
+ const __DRIinterfaceMethods * interface,
+ __GLcontextModes ** driver_modes)
+{
+ __DRIscreenPrivate *psp;
+ static const __DRIversion ddx_expected = { 1, 7, 0 };
+ static const __DRIversion dri_expected = { 4, 0, 0 };
+ static const __DRIversion drm_expected = { 1, 7, 0 };
+
+ dri_interface = interface;
+
+ if (!driCheckDriDdxDrmVersions2("i915",
+ dri_version, &dri_expected,
+ ddx_version, &ddx_expected,
+ drm_version, &drm_expected)) {
+ return NULL;
+ }
+
+ psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
+ ddx_version, dri_version, drm_version,
+ frame_buffer, pSAREA, fd,
+ internal_api_version, &intelAPI);
+
+ if (psp != NULL) {
+ I830DRIPtr dri_priv = (I830DRIPtr) psp->pDevPriv;
+ *driver_modes = intelFillInModes(dri_priv->cpp * 8,
+ (dri_priv->cpp == 2) ? 16 : 24,
+ (dri_priv->cpp == 2) ? 0 : 8, 1);
+
+ /* Calling driInitExtensions here, with a NULL context pointer, does not actually
+ * enable the extensions. It just makes sure that all the dispatch offsets for all
+ * the extensions that *might* be enables are known. This is needed because the
+ * dispatch offsets need to be known when _mesa_context_create is called, but we can't
+ * enable the extensions until we have a context pointer.
+ *
+ * Hello chicken. Hello egg. How are you two today?
+ */
+ driInitExtensions(NULL, card_extensions, GL_FALSE);
+ }
+
+ return (void *) psp;
+}
+
+struct intel_context *intelScreenContext(intelScreenPrivate *intelScreen)
+{
+ /*
+ * This should probably change to have the screen allocate a dummy
+ * context at screen creation. For now just use the current context.
+ */
+
+ GET_CURRENT_CONTEXT(ctx);
+ if (ctx == NULL) {
+/* _mesa_problem(NULL, "No current context in intelScreenContext\n");
+ return NULL; */
+ /* need a context for the first time makecurrent is called (for hw lock
+ when allocating priv buffers) */
+ if (intelScreen->dummyctxptr == NULL) {
+ _mesa_problem(NULL, "No current context in intelScreenContext\n");
+ return NULL;
+ }
+ return intelScreen->dummyctxptr;
+ }
+ return intel_context(ctx);
+
+}
+
diff --git a/src/mesa/drivers/dri/i915pipe/intel_screen.h b/src/mesa/drivers/dri/i915pipe/intel_screen.h
new file mode 100644
index 0000000000..eb4685d6e9
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_screen.h
@@ -0,0 +1,129 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _INTEL_INIT_H_
+#define _INTEL_INIT_H_
+
+#include <sys/time.h>
+#include "dri_util.h"
+#include "intel_rotate.h"
+#include "i830_common.h"
+#include "xmlconfig.h"
+#include "dri_bufpool.h"
+
+/* XXX: change name or eliminate to avoid conflict with "struct
+ * intel_region"!!!
+ */
+typedef struct
+{
+ drm_handle_t handle;
+ drmSize size; /* region size in bytes */
+ char *map; /* memory map */
+ int offset; /* from start of video mem, in bytes */
+ int pitch; /* row stride, in bytes */
+} intelRegion;
+
+typedef struct
+{
+ intelRegion front;
+
+ struct intel_region *front_region;
+
+ int deviceID;
+ int width;
+ int height;
+ int mem; /* unused */
+
+ int cpp; /* for front and back buffers */
+
+ __DRIscreenPrivate *driScrnPriv;
+ unsigned int sarea_priv_offset;
+
+ int drmMinor;
+
+ int irq_active;
+ int allow_batchbuffer;
+
+ struct matrix23 rotMatrix;
+
+
+ /**
+ * Configuration cache with default values for all contexts
+ */
+ driOptionCache optionCache;
+ struct _DriBufferPool *batchPool;
+ struct _DriBufferPool *texPool;
+ struct _DriBufferPool *regionPool;
+ struct _DriBufferPool *staticPool;
+ unsigned int maxBatchSize;
+ GLboolean havePools;
+ struct intel_context *dummyctxptr;
+} intelScreenPrivate;
+
+
+
+extern GLboolean intelMapScreenRegions(__DRIscreenPrivate * sPriv);
+
+extern void intelUnmapScreenRegions(intelScreenPrivate * intelScreen);
+
+extern void
+intelUpdateScreenFromSAREA(intelScreenPrivate * intelScreen,
+ drmI830Sarea * sarea);
+
+extern void intelDestroyContext(__DRIcontextPrivate * driContextPriv);
+
+extern GLboolean intelUnbindContext(__DRIcontextPrivate * driContextPriv);
+
+extern GLboolean
+intelMakeCurrent(__DRIcontextPrivate * driContextPriv,
+ __DRIdrawablePrivate * driDrawPriv,
+ __DRIdrawablePrivate * driReadPriv);
+
+extern void intelSwapBuffers(__DRIdrawablePrivate * dPriv);
+
+extern void
+intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h);
+
+extern struct _DriBufferPool *driBatchPoolInit(int fd, unsigned flags,
+ unsigned long bufSize,
+ unsigned numBufs,
+ unsigned checkDelayed);
+
+extern struct intel_context *intelScreenContext(intelScreenPrivate *intelScreen);
+
+extern void
+intelUpdateScreenRotation(__DRIscreenPrivate * sPriv, drmI830Sarea * sarea);
+extern GLboolean
+intelCreatePools(intelScreenPrivate *intelScreen);
+
+extern GLboolean
+intelCreateContext(const __GLcontextModes * mesaVis,
+ __DRIcontextPrivate * driContextPriv,
+ void *sharedContextPrivate);
+
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_span.c b/src/mesa/drivers/dri/i915pipe/intel_span.c
new file mode 100644
index 0000000000..5a978d9ce2
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_span.c
@@ -0,0 +1,401 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "glheader.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "colormac.h"
+
+#include "intel_fbo.h"
+#include "intel_screen.h"
+#include "intel_span.h"
+#include "intel_regions.h"
+#include "intel_ioctl.h"
+#include "intel_tex.h"
+
+#include "swrast/swrast.h"
+
+/*
+ break intelWriteRGBASpan_ARGB8888
+*/
+
+#undef DBG
+#define DBG 0
+
+#define LOCAL_VARS \
+ struct intel_renderbuffer *irb = intel_renderbuffer(rb); \
+ const GLint yScale = irb->RenderToTexture ? 1 : -1; \
+ const GLint yBias = irb->RenderToTexture ? 0 : irb->Base.Height - 1; \
+ GLubyte *buf = (GLubyte *) irb->pfMap; \
+ GLuint p; \
+ assert(irb->pfMap);\
+ (void) p;
+
+/* There is just a single cliploop!
+ */
+#define HW_CLIPLOOP() \
+ do { \
+ int minx = 0; \
+ int miny = 0; \
+ int maxx = irb->Base.Width - 1; \
+ int maxy = irb->Base.Height - 1;
+
+#define HW_ENDCLIPLOOP() \
+ } while (0)
+
+
+#define Y_FLIP(_y) ((_y) * yScale + yBias)
+
+#define HW_LOCK()
+
+#define HW_UNLOCK()
+
+/* 16 bit, RGB565 color spanline and pixel functions
+ */
+#define SPANTMP_PIXEL_FMT GL_RGB
+#define SPANTMP_PIXEL_TYPE GL_UNSIGNED_SHORT_5_6_5
+
+#define TAG(x) intel##x##_RGB565
+#define TAG2(x,y) intel##x##_RGB565##y
+#define GET_PTR(X,Y) (buf + ((Y) * irb->pfPitch + (X)) * 2)
+#include "spantmp2.h"
+
+/* 32 bit, ARGB8888 color spanline and pixel functions
+ */
+#define SPANTMP_PIXEL_FMT GL_BGRA
+#define SPANTMP_PIXEL_TYPE GL_UNSIGNED_INT_8_8_8_8_REV
+
+#define TAG(x) intel##x##_ARGB8888
+#define TAG2(x,y) intel##x##_ARGB8888##y
+#define GET_PTR(X,Y) (buf + ((Y) * irb->pfPitch + (X)) * 4)
+#include "spantmp2.h"
+
+
+#define LOCAL_DEPTH_VARS \
+ struct intel_renderbuffer *irb = intel_renderbuffer(rb); \
+ const GLuint pitch = irb->pfPitch/***XXX region->pitch*/; /* in pixels */ \
+ const GLint yScale = irb->RenderToTexture ? 1 : -1; \
+ const GLint yBias = irb->RenderToTexture ? 0 : irb->Base.Height - 1; \
+ char *buf = (char *) irb->pfMap/*XXX use region->map*/ ;
+
+#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS
+
+/**
+ ** 16-bit depthbuffer functions.
+ **/
+#define WRITE_DEPTH( _x, _y, d ) \
+ ((GLushort *)buf)[(_x) + (_y) * pitch] = d;
+
+#define READ_DEPTH( d, _x, _y ) \
+ d = ((GLushort *)buf)[(_x) + (_y) * pitch];
+
+
+#define TAG(x) intel##x##_z16
+#include "depthtmp.h"
+
+
+/**
+ ** 24/8-bit interleaved depth/stencil functions
+ ** Note: we're actually reading back combined depth+stencil values.
+ ** The wrappers in main/depthstencil.c are used to extract the depth
+ ** and stencil values.
+ **/
+/* Change ZZZS -> SZZZ */
+#define WRITE_DEPTH( _x, _y, d ) { \
+ GLuint tmp = ((d) >> 8) | ((d) << 24); \
+ ((GLuint *)buf)[(_x) + (_y) * pitch] = tmp; \
+}
+
+/* Change SZZZ -> ZZZS */
+#define READ_DEPTH( d, _x, _y ) { \
+ GLuint tmp = ((GLuint *)buf)[(_x) + (_y) * pitch]; \
+ d = (tmp << 8) | (tmp >> 24); \
+}
+
+#define TAG(x) intel##x##_z24_s8
+#include "depthtmp.h"
+
+
+/**
+ ** 8-bit stencil function (XXX FBO: This is obsolete)
+ **/
+#define WRITE_STENCIL( _x, _y, d ) { \
+ GLuint tmp = ((GLuint *)buf)[(_x) + (_y) * pitch]; \
+ tmp &= 0xffffff; \
+ tmp |= ((d) << 24); \
+ ((GLuint *) buf)[(_x) + (_y) * pitch] = tmp; \
+}
+
+#define READ_STENCIL( d, _x, _y ) \
+ d = ((GLuint *)buf)[(_x) + (_y) * pitch] >> 24;
+
+#define TAG(x) intel##x##_z24_s8
+#include "stenciltmp.h"
+
+
+
+/**
+ * Map or unmap all the renderbuffers which we may need during
+ * software rendering.
+ * XXX in the future, we could probably convey extra information to
+ * reduce the number of mappings needed. I.e. if doing a glReadPixels
+ * from the depth buffer, we really only need one mapping.
+ *
+ * XXX Rewrite this function someday.
+ * We can probably just loop over all the renderbuffer attachments,
+ * map/unmap all of them, and not worry about the _ColorDrawBuffers
+ * _ColorReadBuffer, _DepthBuffer or _StencilBuffer fields.
+ */
+static void
+intel_map_unmap_buffers(struct intel_context *intel, GLboolean map)
+{
+ GLcontext *ctx = &intel->ctx;
+ GLuint i, j;
+ struct intel_renderbuffer *irb;
+
+ /* color draw buffers */
+ for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
+ for (j = 0; j < ctx->DrawBuffer->_NumColorDrawBuffers[i]; j++) {
+ struct gl_renderbuffer *rb =
+ ctx->DrawBuffer->_ColorDrawBuffers[i][j];
+ irb = intel_renderbuffer(rb);
+ if (irb) {
+ /* this is a user-created intel_renderbuffer */
+ if (irb->region) {
+ if (map)
+ intel_region_map(intel->intelScreen, irb->region);
+ else
+ intel_region_unmap(intel->intelScreen, irb->region);
+ }
+ irb->pfMap = irb->region->map;
+ irb->pfPitch = irb->region->pitch;
+ }
+ }
+ }
+
+ /* check for render to textures */
+ for (i = 0; i < BUFFER_COUNT; i++) {
+ struct gl_renderbuffer_attachment *att =
+ ctx->DrawBuffer->Attachment + i;
+ struct gl_texture_object *tex = att->Texture;
+ if (tex) {
+ /* render to texture */
+ ASSERT(att->Renderbuffer);
+ if (map) {
+ struct gl_texture_image *texImg;
+ texImg = tex->Image[att->CubeMapFace][att->TextureLevel];
+ intel_tex_map_images(intel, intel_texture_object(tex));
+ }
+ else {
+ intel_tex_unmap_images(intel, intel_texture_object(tex));
+ }
+ }
+ }
+
+ /* color read buffers */
+ irb = intel_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
+ if (irb && irb->region) {
+ if (map)
+ intel_region_map(intel->intelScreen, irb->region);
+ else
+ intel_region_unmap(intel->intelScreen, irb->region);
+ irb->pfMap = irb->region->map;
+ irb->pfPitch = irb->region->pitch;
+ }
+
+ /* Account for front/back color page flipping.
+ * The span routines use the pfMap and pfPitch fields which will
+ * swap the front/back region map/pitch if we're page flipped.
+ * Do this after mapping, above, so the map field is valid.
+ */
+#if 0
+ if (map && ctx->DrawBuffer->Name == 0) {
+ struct intel_renderbuffer *irbFront
+ = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_FRONT_LEFT);
+ struct intel_renderbuffer *irbBack
+ = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_BACK_LEFT);
+ if (irbBack) {
+ /* double buffered */
+ if (intel->sarea->pf_current_page == 0) {
+ irbFront->pfMap = irbFront->region->map;
+ irbFront->pfPitch = irbFront->region->pitch;
+ irbBack->pfMap = irbBack->region->map;
+ irbBack->pfPitch = irbBack->region->pitch;
+ }
+ else {
+ irbFront->pfMap = irbBack->region->map;
+ irbFront->pfPitch = irbBack->region->pitch;
+ irbBack->pfMap = irbFront->region->map;
+ irbBack->pfPitch = irbFront->region->pitch;
+ }
+ }
+ }
+#endif
+
+ /* depth buffer (Note wrapper!) */
+ if (ctx->DrawBuffer->_DepthBuffer) {
+ irb = intel_renderbuffer(ctx->DrawBuffer->_DepthBuffer->Wrapped);
+ if (irb && irb->region) {
+ if (map) {
+ intel_region_map(intel->intelScreen, irb->region);
+ irb->pfMap = irb->region->map;
+ irb->pfPitch = irb->region->pitch;
+ }
+ else {
+ intel_region_unmap(intel->intelScreen, irb->region);
+ irb->pfMap = NULL;
+ irb->pfPitch = 0;
+ }
+ }
+ }
+
+ /* stencil buffer (Note wrapper!) */
+ if (ctx->DrawBuffer->_StencilBuffer) {
+ irb = intel_renderbuffer(ctx->DrawBuffer->_StencilBuffer->Wrapped);
+ if (irb && irb->region) {
+ if (map) {
+ intel_region_map(intel->intelScreen, irb->region);
+ irb->pfMap = irb->region->map;
+ irb->pfPitch = irb->region->pitch;
+ }
+ else {
+ intel_region_unmap(intel->intelScreen, irb->region);
+ irb->pfMap = NULL;
+ irb->pfPitch = 0;
+ }
+ }
+ }
+}
+
+
+
+/**
+ * Prepare for softare rendering. Map current read/draw framebuffers'
+ * renderbuffes and all currently bound texture objects.
+ *
+ * Old note: Moved locking out to get reasonable span performance.
+ */
+void
+intelSpanRenderStart(GLcontext * ctx)
+{
+ struct intel_context *intel = intel_context(ctx);
+ GLuint i;
+
+ intelFinish(&intel->ctx);
+ LOCK_HARDWARE(intel);
+
+#if 0
+ /* Just map the framebuffer and all textures. Bufmgr code will
+ * take care of waiting on the necessary fences:
+ */
+ intel_region_map(intel->intelScreen, intel->front_region);
+ intel_region_map(intel->intelScreen, intel->back_region);
+ intel_region_map(intel->intelScreen, intel->intelScreen->depth_region);
+#endif
+
+ for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
+ if (ctx->Texture.Unit[i]._ReallyEnabled) {
+ struct gl_texture_object *texObj = ctx->Texture.Unit[i]._Current;
+ intel_tex_map_images(intel, intel_texture_object(texObj));
+ }
+ }
+
+ intel_map_unmap_buffers(intel, GL_TRUE);
+}
+
+/**
+ * Called when done softare rendering. Unmap the buffers we mapped in
+ * the above function.
+ */
+void
+intelSpanRenderFinish(GLcontext * ctx)
+{
+ struct intel_context *intel = intel_context(ctx);
+ GLuint i;
+
+ _swrast_flush(ctx);
+
+ /* Now unmap the framebuffer:
+ */
+#if 0
+ intel_region_unmap(intel, intel->front_region);
+ intel_region_unmap(intel, intel->back_region);
+ intel_region_unmap(intel, intel->intelScreen->depth_region);
+#endif
+
+ for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
+ if (ctx->Texture.Unit[i]._ReallyEnabled) {
+ struct gl_texture_object *texObj = ctx->Texture.Unit[i]._Current;
+ intel_tex_unmap_images(intel, intel_texture_object(texObj));
+ }
+ }
+
+ intel_map_unmap_buffers(intel, GL_FALSE);
+
+ UNLOCK_HARDWARE(intel);
+}
+
+
+void
+intelInitSpanFuncs(GLcontext * ctx)
+{
+ struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx);
+ swdd->SpanRenderStart = intelSpanRenderStart;
+ swdd->SpanRenderFinish = intelSpanRenderFinish;
+}
+
+
+/**
+ * Plug in appropriate span read/write functions for the given renderbuffer.
+ * These are used for the software fallbacks.
+ */
+void
+intel_set_span_functions(struct gl_renderbuffer *rb)
+{
+ if (rb->_ActualFormat == GL_RGB5) {
+ /* 565 RGB */
+ intelInitPointers_RGB565(rb);
+ }
+ else if (rb->_ActualFormat == GL_RGBA8) {
+ /* 8888 RGBA */
+ intelInitPointers_ARGB8888(rb);
+ }
+ else if (rb->_ActualFormat == GL_DEPTH_COMPONENT16) {
+ intelInitDepthPointers_z16(rb);
+ }
+ else if (rb->_ActualFormat == GL_DEPTH_COMPONENT24 || /* XXX FBO remove */
+ rb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) {
+ intelInitDepthPointers_z24_s8(rb);
+ }
+ else if (rb->_ActualFormat == GL_STENCIL_INDEX8_EXT) { /* XXX FBO remove */
+ intelInitStencilPointers_z24_s8(rb);
+ }
+ else {
+ _mesa_problem(NULL,
+ "Unexpected _ActualFormat in intelSetSpanFunctions");
+ }
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_span.h b/src/mesa/drivers/dri/i915pipe/intel_span.h
new file mode 100644
index 0000000000..5201f6d6c6
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_span.h
@@ -0,0 +1,38 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _INTEL_SPAN_H
+#define _INTEL_SPAN_H
+
+extern void intelInitSpanFuncs(GLcontext * ctx);
+
+extern void intelSpanRenderFinish(GLcontext * ctx);
+extern void intelSpanRenderStart(GLcontext * ctx);
+
+extern void intel_set_span_functions(struct gl_renderbuffer *rb);
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_state.c b/src/mesa/drivers/dri/i915pipe/intel_state.c
new file mode 100644
index 0000000000..5c5f2c6de5
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_state.c
@@ -0,0 +1,261 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "enums.h"
+#include "colormac.h"
+#include "dd.h"
+
+#include "intel_screen.h"
+#include "intel_context.h"
+#include "intel_fbo.h"
+#include "intel_regions.h"
+#include "swrast/swrast.h"
+
+int
+intel_translate_compare_func(GLenum func)
+{
+ switch (func) {
+ case GL_NEVER:
+ return COMPAREFUNC_NEVER;
+ case GL_LESS:
+ return COMPAREFUNC_LESS;
+ case GL_LEQUAL:
+ return COMPAREFUNC_LEQUAL;
+ case GL_GREATER:
+ return COMPAREFUNC_GREATER;
+ case GL_GEQUAL:
+ return COMPAREFUNC_GEQUAL;
+ case GL_NOTEQUAL:
+ return COMPAREFUNC_NOTEQUAL;
+ case GL_EQUAL:
+ return COMPAREFUNC_EQUAL;
+ case GL_ALWAYS:
+ return COMPAREFUNC_ALWAYS;
+ }
+
+ fprintf(stderr, "Unknown value in %s: %x\n", __FUNCTION__, func);
+ return COMPAREFUNC_ALWAYS;
+}
+
+int
+intel_translate_stencil_op(GLenum op)
+{
+ switch (op) {
+ case GL_KEEP:
+ return STENCILOP_KEEP;
+ case GL_ZERO:
+ return STENCILOP_ZERO;
+ case GL_REPLACE:
+ return STENCILOP_REPLACE;
+ case GL_INCR:
+ return STENCILOP_INCRSAT;
+ case GL_DECR:
+ return STENCILOP_DECRSAT;
+ case GL_INCR_WRAP:
+ return STENCILOP_INCR;
+ case GL_DECR_WRAP:
+ return STENCILOP_DECR;
+ case GL_INVERT:
+ return STENCILOP_INVERT;
+ default:
+ return STENCILOP_ZERO;
+ }
+}
+
+int
+intel_translate_blend_factor(GLenum factor)
+{
+ switch (factor) {
+ case GL_ZERO:
+ return BLENDFACT_ZERO;
+ case GL_SRC_ALPHA:
+ return BLENDFACT_SRC_ALPHA;
+ case GL_ONE:
+ return BLENDFACT_ONE;
+ case GL_SRC_COLOR:
+ return BLENDFACT_SRC_COLR;
+ case GL_ONE_MINUS_SRC_COLOR:
+ return BLENDFACT_INV_SRC_COLR;
+ case GL_DST_COLOR:
+ return BLENDFACT_DST_COLR;
+ case GL_ONE_MINUS_DST_COLOR:
+ return BLENDFACT_INV_DST_COLR;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ return BLENDFACT_INV_SRC_ALPHA;
+ case GL_DST_ALPHA:
+ return BLENDFACT_DST_ALPHA;
+ case GL_ONE_MINUS_DST_ALPHA:
+ return BLENDFACT_INV_DST_ALPHA;
+ case GL_SRC_ALPHA_SATURATE:
+ return BLENDFACT_SRC_ALPHA_SATURATE;
+ case GL_CONSTANT_COLOR:
+ return BLENDFACT_CONST_COLOR;
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ return BLENDFACT_INV_CONST_COLOR;
+ case GL_CONSTANT_ALPHA:
+ return BLENDFACT_CONST_ALPHA;
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ return BLENDFACT_INV_CONST_ALPHA;
+ }
+
+ fprintf(stderr, "Unknown value in %s: %x\n", __FUNCTION__, factor);
+ return BLENDFACT_ZERO;
+}
+
+int
+intel_translate_logic_op(GLenum opcode)
+{
+ switch (opcode) {
+ case GL_CLEAR:
+ return LOGICOP_CLEAR;
+ case GL_AND:
+ return LOGICOP_AND;
+ case GL_AND_REVERSE:
+ return LOGICOP_AND_RVRSE;
+ case GL_COPY:
+ return LOGICOP_COPY;
+ case GL_COPY_INVERTED:
+ return LOGICOP_COPY_INV;
+ case GL_AND_INVERTED:
+ return LOGICOP_AND_INV;
+ case GL_NOOP:
+ return LOGICOP_NOOP;
+ case GL_XOR:
+ return LOGICOP_XOR;
+ case GL_OR:
+ return LOGICOP_OR;
+ case GL_OR_INVERTED:
+ return LOGICOP_OR_INV;
+ case GL_NOR:
+ return LOGICOP_NOR;
+ case GL_EQUIV:
+ return LOGICOP_EQUIV;
+ case GL_INVERT:
+ return LOGICOP_INV;
+ case GL_OR_REVERSE:
+ return LOGICOP_OR_RVRSE;
+ case GL_NAND:
+ return LOGICOP_NAND;
+ case GL_SET:
+ return LOGICOP_SET;
+ default:
+ return LOGICOP_SET;
+ }
+}
+
+
+static void
+intelClearColor(GLcontext * ctx, const GLfloat color[4])
+{
+ struct intel_context *intel = intel_context(ctx);
+ GLubyte clear[4];
+
+ CLAMPED_FLOAT_TO_UBYTE(clear[0], color[0]);
+ CLAMPED_FLOAT_TO_UBYTE(clear[1], color[1]);
+ CLAMPED_FLOAT_TO_UBYTE(clear[2], color[2]);
+ CLAMPED_FLOAT_TO_UBYTE(clear[3], color[3]);
+
+ /* compute both 32 and 16-bit clear values */
+ intel->ClearColor8888 = INTEL_PACKCOLOR8888(clear[0], clear[1],
+ clear[2], clear[3]);
+ intel->ClearColor565 = INTEL_PACKCOLOR565(clear[0], clear[1], clear[2]);
+}
+
+
+/**
+ * Update the viewport transformation matrix. Depends on:
+ * - viewport pos/size
+ * - depthrange
+ * - window size or FBO size
+ */
+static void
+intelCalcViewport(GLcontext * ctx)
+{
+ struct intel_context *intel = intel_context(ctx);
+ const GLfloat *v = ctx->Viewport._WindowMap.m;
+ const GLfloat depthScale = 1.0F / ctx->DrawBuffer->_DepthMaxF;
+ GLfloat *m = intel->ViewportMatrix.m;
+ GLfloat yScale, yBias;
+
+ struct intel_renderbuffer *irb
+ = intel_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0][0]);
+ if (irb && !irb->RenderToTexture) {
+ /* y=0=top */
+ yScale = -1.0;
+ yBias = irb->Base.Height;
+ }
+ else {
+ /* y=0=bottom */
+ yScale = 1.0;
+ yBias = 0.0;
+ }
+
+ m[MAT_SX] = v[MAT_SX];
+ m[MAT_TX] = v[MAT_TX] + SUBPIXEL_X;
+
+ m[MAT_SY] = v[MAT_SY] * yScale;
+ m[MAT_TY] = v[MAT_TY] * yScale + yBias + SUBPIXEL_Y;
+
+ m[MAT_SZ] = v[MAT_SZ] * depthScale;
+ m[MAT_TZ] = v[MAT_TZ] * depthScale;
+}
+
+static void
+intelViewport(GLcontext * ctx,
+ GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ intelCalcViewport(ctx);
+}
+
+static void
+intelDepthRange(GLcontext * ctx, GLclampd nearval, GLclampd farval)
+{
+ intelCalcViewport(ctx);
+}
+
+/* Fallback to swrast for select and feedback.
+ */
+static void
+intelRenderMode(GLcontext * ctx, GLenum mode)
+{
+ struct intel_context *intel = intel_context(ctx);
+ FALLBACK(intel, INTEL_FALLBACK_RENDERMODE, (mode != GL_RENDER));
+}
+
+
+void
+intelInitStateFuncs(struct dd_function_table *functions)
+{
+ functions->RenderMode = intelRenderMode;
+ functions->Viewport = intelViewport;
+ functions->DepthRange = intelDepthRange;
+ functions->ClearColor = intelClearColor;
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_structs.h b/src/mesa/drivers/dri/i915pipe/intel_structs.h
new file mode 100644
index 0000000000..522e3bd92c
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_structs.h
@@ -0,0 +1,132 @@
+#ifndef INTEL_STRUCTS_H
+#define INTEL_STRUCTS_H
+
+struct br0 {
+ GLuint length:8;
+ GLuint pad0:3;
+ GLuint dst_tiled:1;
+ GLuint pad1:8;
+ GLuint write_rgb:1;
+ GLuint write_alpha:1;
+ GLuint opcode:7;
+ GLuint client:3;
+};
+
+
+struct br13 {
+ GLint dest_pitch:16;
+ GLuint rop:8;
+ GLuint color_depth:2;
+ GLuint pad1:3;
+ GLuint mono_source_transparency:1;
+ GLuint clipping_enable:1;
+ GLuint pad0:1;
+};
+
+
+
+/* This is an attempt to move some of the 2D interaction in this
+ * driver to using structs for packets rather than a bunch of #defines
+ * and dwords.
+ */
+struct xy_color_blit {
+ struct br0 br0;
+ struct br13 br13;
+
+ struct {
+ GLuint dest_x1:16;
+ GLuint dest_y1:16;
+ } dw2;
+
+ struct {
+ GLuint dest_x2:16;
+ GLuint dest_y2:16;
+ } dw3;
+
+ GLuint dest_base_addr;
+ GLuint color;
+};
+
+struct xy_src_copy_blit {
+ struct br0 br0;
+ struct br13 br13;
+
+ struct {
+ GLuint dest_x1:16;
+ GLuint dest_y1:16;
+ } dw2;
+
+ struct {
+ GLuint dest_x2:16;
+ GLuint dest_y2:16;
+ } dw3;
+
+ GLuint dest_base_addr;
+
+ struct {
+ GLuint src_x1:16;
+ GLuint src_y1:16;
+ } dw5;
+
+ struct {
+ GLint src_pitch:16;
+ GLuint pad:16;
+ } dw6;
+
+ GLuint src_base_addr;
+};
+
+struct xy_setup_blit {
+ struct br0 br0;
+ struct br13 br13;
+
+ struct {
+ GLuint clip_x1:16;
+ GLuint clip_y1:16;
+ } dw2;
+
+ struct {
+ GLuint clip_x2:16;
+ GLuint clip_y2:16;
+ } dw3;
+
+ GLuint dest_base_addr;
+ GLuint background_color;
+ GLuint foreground_color;
+ GLuint pattern_base_addr;
+};
+
+
+struct xy_text_immediate_blit {
+ struct {
+ GLuint length:8;
+ GLuint pad2:3;
+ GLuint dst_tiled:1;
+ GLuint pad1:4;
+ GLuint byte_packed:1;
+ GLuint pad0:5;
+ GLuint opcode:7;
+ GLuint client:3;
+ } dw0;
+
+ struct {
+ GLuint dest_x1:16;
+ GLuint dest_y1:16;
+ } dw1;
+
+ struct {
+ GLuint dest_x2:16;
+ GLuint dest_y2:16;
+ } dw2;
+
+ /* Src bitmap data follows as inline dwords.
+ */
+};
+
+
+#define CLIENT_2D 0x2
+#define OPCODE_XY_SETUP_BLT 0x1
+#define OPCODE_XY_COLOR_BLT 0x50
+#define OPCODE_XY_TEXT_IMMEDIATE_BLT 0x31
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_surface.c b/src/mesa/drivers/dri/i915pipe/intel_surface.c
new file mode 100644
index 0000000000..043c5aa5fe
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_surface.c
@@ -0,0 +1,259 @@
+#include "glheader.h"
+#include "context.h"
+#include "framebuffer.h"
+#include "renderbuffer.h"
+#include "utils.h"
+#include "main/macros.h"
+
+
+#include "intel_screen.h"
+
+#include "intel_context.h"
+#include "intel_buffers.h"
+#include "intel_regions.h"
+#include "intel_span.h"
+#include "intel_fbo.h"
+
+#include "pipe/p_state.h"
+#include "pipe/p_defines.h"
+#include "pipe/softpipe/sp_surface.h"
+
+
+/*
+ * XXX a lof of this is a temporary kludge
+ */
+
+/**
+ * Note: the arithmetic/addressing in these functions is a little
+ * tricky since we need to invert the Y axis.
+ */
+
+
+static void
+read_quad_f_swz(struct softpipe_surface *sps, GLint x, GLint y,
+ GLfloat (*rrrr)[QUAD_SIZE])
+{
+ const GLint bytesPerRow = sps->surface.stride * sps->surface.cpp;
+ const GLint invY = sps->surface.height - y - 1;
+ const GLubyte *src = sps->surface.ptr + invY * bytesPerRow + x * sps->surface.cpp;
+ GLfloat *dst = (GLfloat *) rrrr;
+ GLubyte temp[16];
+ GLuint j;
+
+ assert(sps->surface.format == PIPE_FORMAT_U_A8_R8_G8_B8);
+
+ memcpy(temp + 8, src, 8);
+ memcpy(temp + 0, src + bytesPerRow, 8);
+
+ for (j = 0; j < 4; j++) {
+ dst[0 * 4 + j] = UBYTE_TO_FLOAT(temp[j * 4 + 2]); /*R*/
+ dst[1 * 4 + j] = UBYTE_TO_FLOAT(temp[j * 4 + 1]); /*G*/
+ dst[2 * 4 + j] = UBYTE_TO_FLOAT(temp[j * 4 + 0]); /*B*/
+ dst[3 * 4 + j] = UBYTE_TO_FLOAT(temp[j * 4 + 3]); /*A*/
+ }
+}
+
+
+static void
+write_quad_f_swz(struct softpipe_surface *sps, GLint x, GLint y,
+ GLfloat (*rrrr)[QUAD_SIZE])
+{
+ const GLfloat *src = (const GLfloat *) rrrr;
+ const GLint bytesPerRow = sps->surface.stride * sps->surface.cpp;
+ const GLint invY = sps->surface.height - y - 1;
+ GLubyte *dst = sps->surface.ptr + invY * bytesPerRow + x * sps->surface.cpp;
+ GLubyte temp[16];
+ GLuint j;
+
+ assert(sps->surface.format == PIPE_FORMAT_U_A8_R8_G8_B8);
+
+ for (j = 0; j < 4; j++) {
+ UNCLAMPED_FLOAT_TO_UBYTE(temp[j * 4 + 2], src[0 * 4 + j]); /*R*/
+ UNCLAMPED_FLOAT_TO_UBYTE(temp[j * 4 + 1], src[1 * 4 + j]); /*G*/
+ UNCLAMPED_FLOAT_TO_UBYTE(temp[j * 4 + 0], src[2 * 4 + j]); /*B*/
+ UNCLAMPED_FLOAT_TO_UBYTE(temp[j * 4 + 3], src[3 * 4 + j]); /*A*/
+ }
+
+ memcpy(dst, temp + 8, 8);
+ memcpy(dst + bytesPerRow, temp + 0, 8);
+}
+
+
+
+static void
+read_quad_z24(struct softpipe_surface *sps,
+ GLint x, GLint y, GLuint zzzz[QUAD_SIZE])
+{
+ static const GLuint mask = 0xffffff;
+ const GLint invY = sps->surface.height - y - 1;
+ const GLuint *src
+ = (GLuint *) (sps->surface.ptr
+ + (invY * sps->surface.stride + x) * sps->surface.cpp);
+
+ assert(sps->surface.format == PIPE_FORMAT_Z24_S8);
+
+ /* extract lower three bytes */
+ zzzz[0] = src[0] & mask;
+ zzzz[1] = src[1] & mask;
+ zzzz[2] = src[-sps->surface.stride] & mask;
+ zzzz[3] = src[-sps->surface.stride + 1] & mask;
+}
+
+static void
+write_quad_z24(struct softpipe_surface *sps,
+ GLint x, GLint y, const GLuint zzzz[QUAD_SIZE])
+{
+ static const GLuint mask = 0xff000000;
+ const GLint invY = sps->surface.height - y - 1;
+ GLuint *dst
+ = (GLuint *) (sps->surface.ptr
+ + (invY * sps->surface.stride + x) * sps->surface.cpp);
+
+ assert(sps->surface.format == PIPE_FORMAT_Z24_S8);
+
+ /* write lower three bytes */
+ dst[0] = (dst[0] & mask) | zzzz[0];
+ dst[1] = (dst[1] & mask) | zzzz[1];
+ dst -= sps->surface.stride;
+ dst[0] = (dst[0] & mask) | zzzz[2];
+ dst[1] = (dst[1] & mask) | zzzz[3];
+}
+
+
+static void
+read_quad_stencil(struct softpipe_surface *sps,
+ GLint x, GLint y, GLubyte ssss[QUAD_SIZE])
+{
+ const GLint invY = sps->surface.height - y - 1;
+ const GLuint *src = (const GLuint *) (sps->surface.ptr
+ + (invY * sps->surface.stride + x) * sps->surface.cpp);
+
+ assert(sps->surface.format == PIPE_FORMAT_Z24_S8);
+
+ /* extract high byte */
+ ssss[0] = src[0] >> 24;
+ ssss[1] = src[1] >> 24;
+ ssss[2] = src[-sps->surface.width] >> 24;
+ ssss[3] = src[-sps->surface.width + 1] >> 24;
+}
+
+static void
+write_quad_stencil(struct softpipe_surface *sps,
+ GLint x, GLint y, const GLubyte ssss[QUAD_SIZE])
+{
+ static const GLuint mask = 0x00ffffff;
+ const GLint invY = sps->surface.height - y - 1;
+ GLuint *dst = (GLuint *) (sps->surface.ptr
+ + (invY * sps->surface.stride + x) * sps->surface.cpp);
+
+ assert(sps->surface.format == PIPE_FORMAT_Z24_S8);
+
+ /* write high byte */
+ dst[0] = (dst[0] & mask) | (ssss[0] << 24);
+ dst[1] = (dst[1] & mask) | (ssss[1] << 24);
+ dst -= sps->surface.stride;
+ dst[0] = (dst[0] & mask) | (ssss[2] << 24);
+ dst[1] = (dst[1] & mask) | (ssss[3] << 24);
+}
+
+
+static void *
+map_surface_buffer(struct pipe_buffer *pb, GLuint access_mode)
+{
+ struct softpipe_surface *sps = (struct softpipe_surface *) pb;
+ struct intel_renderbuffer *irb = (struct intel_renderbuffer *) sps->surface.rb;
+ assert(access_mode == PIPE_MAP_READ_WRITE);
+
+ /*LOCK_HARDWARE(intel);*/
+
+ if (irb->region) {
+ GET_CURRENT_CONTEXT(ctx);
+ struct intel_context *intel = intel_context(ctx);
+#if 0
+ intelFinish(&intel->ctx); /* XXX need this? */
+#endif
+ intel_region_map(intel->intelScreen, irb->region);
+ }
+ pb->ptr = irb->region->map;
+
+ sps->surface.stride = irb->region->pitch;
+ sps->surface.cpp = irb->region->cpp;
+ sps->surface.ptr = irb->region->map;
+
+ return pb->ptr;
+}
+
+
+static void
+unmap_surface_buffer(struct pipe_buffer *pb)
+{
+ struct softpipe_surface *sps = (struct softpipe_surface *) pb;
+ struct intel_renderbuffer *irb = (struct intel_renderbuffer *) sps->surface.rb;
+
+ if (irb->region) {
+ GET_CURRENT_CONTEXT(ctx);
+ struct intel_context *intel = intel_context(ctx);
+ intel_region_unmap(intel->intelScreen, irb->region);
+ }
+ pb->ptr = NULL;
+
+ sps->surface.stride = 0;
+ sps->surface.cpp = 0;
+ sps->surface.ptr = NULL;
+
+ /*UNLOCK_HARDWARE(intel);*/
+}
+
+
+struct pipe_surface *
+intel_new_surface(GLuint intFormat)
+{
+ struct softpipe_surface *sps = CALLOC_STRUCT(softpipe_surface);
+ if (!sps)
+ return NULL;
+
+ sps->surface.width = 0; /* set in intel_alloc_renderbuffer_storage() */
+ sps->surface.height = 0;
+
+ if (intFormat == GL_RGBA8) {
+ sps->surface.format = PIPE_FORMAT_U_A8_R8_G8_B8;
+ sps->read_quad_f_swz = read_quad_f_swz;
+ sps->write_quad_f_swz = write_quad_f_swz;
+ }
+ else if (intFormat == GL_RGB5) {
+ sps->surface.format = PIPE_FORMAT_U_R5_G6_B5;
+
+ }
+ else if (intFormat == GL_DEPTH_COMPONENT16) {
+ sps->surface.format = PIPE_FORMAT_U_Z16;
+
+ }
+ else if (intFormat == GL_DEPTH24_STENCIL8_EXT) {
+ sps->surface.format = PIPE_FORMAT_Z24_S8;
+ sps->read_quad_z = read_quad_z24;
+ sps->write_quad_z = write_quad_z24;
+ sps->read_quad_stencil = read_quad_stencil;
+ sps->write_quad_stencil = write_quad_stencil;
+ }
+ else {
+ /* TBD / unknown */
+
+ }
+
+ sps->surface.buffer.map = map_surface_buffer;
+ sps->surface.buffer.unmap = unmap_surface_buffer;
+
+ return &sps->surface;
+}
+
+
+
+struct pipe_surface *
+xmesa_get_stencil_surface(GLcontext *ctx)
+{
+ /* XXX fix */
+ return NULL;
+}
+
+
+
diff --git a/src/mesa/drivers/dri/i915pipe/intel_tex.c b/src/mesa/drivers/dri/i915pipe/intel_tex.c
new file mode 100644
index 0000000000..b08dee43bc
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_tex.c
@@ -0,0 +1,192 @@
+#include "texobj.h"
+#include "intel_context.h"
+#include "intel_mipmap_tree.h"
+#include "intel_tex.h"
+
+#define FILE_DEBUG_FLAG DEBUG_TEXTURE
+
+static GLboolean
+intelIsTextureResident(GLcontext * ctx, struct gl_texture_object *texObj)
+{
+#if 0
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_texture_object *intelObj = intel_texture_object(texObj);
+
+ return
+ intelObj->mt &&
+ intelObj->mt->region &&
+ intel_is_region_resident(intel, intelObj->mt->region);
+#endif
+ return 1;
+}
+
+
+
+static struct gl_texture_image *
+intelNewTextureImage(GLcontext * ctx)
+{
+ DBG("%s\n", __FUNCTION__);
+ (void) ctx;
+ return (struct gl_texture_image *) CALLOC_STRUCT(intel_texture_image);
+}
+
+
+static struct gl_texture_object *
+intelNewTextureObject(GLcontext * ctx, GLuint name, GLenum target)
+{
+ struct intel_texture_object *obj = CALLOC_STRUCT(intel_texture_object);
+
+ DBG("%s\n", __FUNCTION__);
+ _mesa_initialize_texture_object(&obj->base, name, target);
+
+ return &obj->base;
+}
+
+static void
+intelDeleteTextureObject(GLcontext *ctx,
+ struct gl_texture_object *texObj)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_texture_object *intelObj = intel_texture_object(texObj);
+
+ if (intelObj->mt)
+ intel_miptree_release(intel, &intelObj->mt);
+
+ _mesa_delete_texture_object(ctx, texObj);
+}
+
+
+static void
+intelFreeTextureImageData(GLcontext * ctx, struct gl_texture_image *texImage)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_texture_image *intelImage = intel_texture_image(texImage);
+
+ DBG("%s\n", __FUNCTION__);
+
+ if (intelImage->mt) {
+ intel_miptree_release(intel, &intelImage->mt);
+ }
+
+ if (texImage->Data) {
+ free(texImage->Data);
+ texImage->Data = NULL;
+ }
+}
+
+
+/* The system memcpy (at least on ubuntu 5.10) has problems copying
+ * to agp (writecombined) memory from a source which isn't 64-byte
+ * aligned - there is a 4x performance falloff.
+ *
+ * The x86 __memcpy is immune to this but is slightly slower
+ * (10%-ish) than the system memcpy.
+ *
+ * The sse_memcpy seems to have a slight cliff at 64/32 bytes, but
+ * isn't much faster than x86_memcpy for agp copies.
+ *
+ * TODO: switch dynamically.
+ */
+static void *
+do_memcpy(void *dest, const void *src, size_t n)
+{
+ if ((((unsigned) src) & 63) || (((unsigned) dest) & 63)) {
+ return __memcpy(dest, src, n);
+ }
+ else
+ return memcpy(dest, src, n);
+}
+
+
+#if DO_DEBUG
+
+#ifndef __x86_64__
+static unsigned
+fastrdtsc(void)
+{
+ unsigned eax;
+ __asm__ volatile ("\t"
+ "pushl %%ebx\n\t"
+ "cpuid\n\t" ".byte 0x0f, 0x31\n\t"
+ "popl %%ebx\n":"=a" (eax)
+ :"0"(0)
+ :"ecx", "edx", "cc");
+
+ return eax;
+}
+#else
+static unsigned
+fastrdtsc(void)
+{
+ unsigned eax;
+ __asm__ volatile ("\t" "cpuid\n\t" ".byte 0x0f, 0x31\n\t":"=a" (eax)
+ :"0"(0)
+ :"ecx", "edx", "ebx", "cc");
+
+ return eax;
+}
+#endif
+
+static unsigned
+time_diff(unsigned t, unsigned t2)
+{
+ return ((t < t2) ? t2 - t : 0xFFFFFFFFU - (t - t2 - 1));
+}
+
+
+static void *
+timed_memcpy(void *dest, const void *src, size_t n)
+{
+ void *ret;
+ unsigned t1, t2;
+ double rate;
+
+ if ((((unsigned) src) & 63) || (((unsigned) dest) & 63))
+ _mesa_printf("Warning - non-aligned texture copy!\n");
+
+ t1 = fastrdtsc();
+ ret = do_memcpy(dest, src, n);
+ t2 = fastrdtsc();
+
+ rate = time_diff(t1, t2);
+ rate /= (double) n;
+ _mesa_printf("timed_memcpy: %u %u --> %f clocks/byte\n", t1, t2, rate);
+ return ret;
+}
+#endif /* DO_DEBUG */
+
+
+void
+intelInitTextureFuncs(struct dd_function_table *functions)
+{
+ functions->ChooseTextureFormat = intelChooseTextureFormat;
+ functions->TexImage1D = intelTexImage1D;
+ functions->TexImage2D = intelTexImage2D;
+ functions->TexImage3D = intelTexImage3D;
+ functions->TexSubImage1D = intelTexSubImage1D;
+ functions->TexSubImage2D = intelTexSubImage2D;
+ functions->TexSubImage3D = intelTexSubImage3D;
+ functions->CopyTexImage1D = intelCopyTexImage1D;
+ functions->CopyTexImage2D = intelCopyTexImage2D;
+ functions->CopyTexSubImage1D = intelCopyTexSubImage1D;
+ functions->CopyTexSubImage2D = intelCopyTexSubImage2D;
+ functions->GetTexImage = intelGetTexImage;
+
+ /* compressed texture functions */
+ functions->CompressedTexImage2D = intelCompressedTexImage2D;
+ functions->GetCompressedTexImage = intelGetCompressedTexImage;
+
+ functions->NewTextureObject = intelNewTextureObject;
+ functions->NewTextureImage = intelNewTextureImage;
+ functions->DeleteTexture = intelDeleteTextureObject;
+ functions->FreeTexImageData = intelFreeTextureImageData;
+ functions->UpdateTexturePalette = 0;
+ functions->IsTextureResident = intelIsTextureResident;
+
+#if DO_DEBUG
+ if (INTEL_DEBUG & DEBUG_BUFMGR)
+ functions->TextureMemCpy = timed_memcpy;
+ else
+#endif
+ functions->TextureMemCpy = do_memcpy;
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_tex.h b/src/mesa/drivers/dri/i915pipe/intel_tex.h
new file mode 100644
index 0000000000..b77d7a1d8a
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_tex.h
@@ -0,0 +1,151 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef INTELTEX_INC
+#define INTELTEX_INC
+
+#include "mtypes.h"
+#include "intel_context.h"
+#include "texmem.h"
+
+
+void intelInitTextureFuncs(struct dd_function_table *functions);
+
+const struct gl_texture_format *intelChooseTextureFormat(GLcontext * ctx,
+ GLint internalFormat,
+ GLenum format,
+ GLenum type);
+
+
+void intelTexImage3D(GLcontext * ctx,
+ GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint depth,
+ GLint border,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage);
+
+void intelTexSubImage3D(GLcontext * ctx,
+ GLenum target,
+ GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type,
+ const GLvoid * pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage);
+
+void intelTexImage2D(GLcontext * ctx,
+ GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint border,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage);
+
+void intelTexSubImage2D(GLcontext * ctx,
+ GLenum target,
+ GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const GLvoid * pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage);
+
+void intelTexImage1D(GLcontext * ctx,
+ GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint border,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage);
+
+void intelTexSubImage1D(GLcontext * ctx,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLsizei width,
+ GLenum format, GLenum type,
+ const GLvoid * pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage);
+
+void intelCopyTexImage1D(GLcontext * ctx, GLenum target, GLint level,
+ GLenum internalFormat,
+ GLint x, GLint y, GLsizei width, GLint border);
+
+void intelCopyTexImage2D(GLcontext * ctx, GLenum target, GLint level,
+ GLenum internalFormat,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border);
+
+void intelCopyTexSubImage1D(GLcontext * ctx, GLenum target, GLint level,
+ GLint xoffset, GLint x, GLint y, GLsizei width);
+
+void intelCopyTexSubImage2D(GLcontext * ctx, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLint x, GLint y, GLsizei width, GLsizei height);
+
+void intelGetTexImage(GLcontext * ctx, GLenum target, GLint level,
+ GLenum format, GLenum type, GLvoid * pixels,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage);
+
+void intelCompressedTexImage2D( GLcontext *ctx, GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint border,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage );
+
+void intelGetCompressedTexImage(GLcontext *ctx, GLenum target, GLint level,
+ GLvoid *pixels,
+ const struct gl_texture_object *texObj,
+ const struct gl_texture_image *texImage);
+
+void intelSetTexOffset(__DRIcontext *pDRICtx, GLint texname,
+ unsigned long long offset, GLint depth, GLuint pitch);
+
+GLuint intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit);
+
+void intel_tex_map_images(struct intel_context *intel,
+ struct intel_texture_object *intelObj);
+
+void intel_tex_unmap_images(struct intel_context *intel,
+ struct intel_texture_object *intelObj);
+
+int intel_compressed_num_bytes(GLuint mesaFormat);
+
+#endif
diff --git a/src/mesa/drivers/dri/i915pipe/intel_tex_copy.c b/src/mesa/drivers/dri/i915pipe/intel_tex_copy.c
new file mode 100644
index 0000000000..8d7f8f9d91
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_tex_copy.c
@@ -0,0 +1,293 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "mtypes.h"
+#include "enums.h"
+#include "image.h"
+#include "teximage.h"
+#include "swrast/swrast.h"
+
+#include "intel_screen.h"
+#include "intel_context.h"
+#include "intel_batchbuffer.h"
+#include "intel_buffers.h"
+#include "intel_mipmap_tree.h"
+#include "intel_regions.h"
+#include "intel_fbo.h"
+#include "intel_tex.h"
+#include "intel_blit.h"
+#include "intel_pixel.h"
+
+#define FILE_DEBUG_FLAG DEBUG_TEXTURE
+
+/**
+ * Get the intel_region which is the source for any glCopyTex[Sub]Image call.
+ *
+ * Do the best we can using the blitter. A future project is to use
+ * the texture engine and fragment programs for these copies.
+ */
+static const struct intel_region *
+get_teximage_source(struct intel_context *intel, GLenum internalFormat)
+{
+ struct intel_renderbuffer *irb;
+
+ DBG("%s %s\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr(internalFormat));
+
+ switch (internalFormat) {
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_COMPONENT16_ARB:
+ irb = intel_get_renderbuffer(intel->ctx.ReadBuffer, BUFFER_DEPTH);
+ if (irb && irb->region && irb->region->cpp == 2)
+ return irb->region;
+ return NULL;
+ case GL_DEPTH24_STENCIL8_EXT:
+ case GL_DEPTH_STENCIL_EXT:
+ irb = intel_get_renderbuffer(intel->ctx.ReadBuffer, BUFFER_DEPTH);
+ if (irb && irb->region && irb->region->cpp == 4)
+ return irb->region;
+ return NULL;
+ case GL_RGBA:
+ case GL_RGBA8:
+ return intel_readbuf_region(intel);
+ case GL_RGB:
+ if (intel->intelScreen->cpp == 2)
+ return intel_readbuf_region(intel);
+ return NULL;
+ default:
+ return NULL;
+ }
+}
+
+
+static GLboolean
+do_copy_texsubimage(struct intel_context *intel,
+ struct intel_texture_image *intelImage,
+ GLenum internalFormat,
+ GLint dstx, GLint dsty,
+ GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ GLcontext *ctx = &intel->ctx;
+ const struct intel_region *src =
+ get_teximage_source(intel, internalFormat);
+
+ if (!intelImage->mt || !src) {
+ DBG("%s fail %p %p\n", __FUNCTION__, intelImage->mt, src);
+ return GL_FALSE;
+ }
+
+ intelFlush(ctx);
+ /* XXX still need the lock ? */
+ LOCK_HARDWARE(intel);
+ {
+ GLuint image_offset = intel_miptree_image_offset(intelImage->mt,
+ intelImage->face,
+ intelImage->level);
+ const GLint orig_x = x;
+ const GLint orig_y = y;
+ const struct gl_framebuffer *fb = ctx->DrawBuffer;
+
+ if (_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax,
+ &x, &y, &width, &height)) {
+ /* Update dst for clipped src. Need to also clip the source rect.
+ */
+ dstx += x - orig_x;
+ dsty += y - orig_y;
+
+ if (!(ctx->ReadBuffer->Name == 0)) {
+ /* XXX this looks bogus ? */
+ /* FBO: invert Y */
+ y = ctx->ReadBuffer->Height - y - 1;
+ }
+
+ /* A bit of fiddling to get the blitter to work with -ve
+ * pitches. But we get a nice inverted blit this way, so it's
+ * worth it:
+ */
+ intelEmitCopyBlit(intel,
+ intelImage->mt->cpp,
+ -src->pitch,
+ src->buffer,
+ src->height * src->pitch * src->cpp,
+ intelImage->mt->pitch,
+ intelImage->mt->region->buffer,
+ image_offset,
+ x, y + height, dstx, dsty, width, height,
+ GL_COPY); /* ? */
+
+ intel_batchbuffer_flush(intel->batch);
+ }
+ }
+
+
+ UNLOCK_HARDWARE(intel);
+
+#if 0
+ /* GL_SGIS_generate_mipmap -- this can be accelerated now.
+ * XXX Add a ctx->Driver.GenerateMipmaps() function?
+ */
+ if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
+ intel_generate_mipmap(ctx, target,
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+ texObj);
+ }
+#endif
+
+ return GL_TRUE;
+}
+
+
+
+
+
+void
+intelCopyTexImage1D(GLcontext * ctx, GLenum target, GLint level,
+ GLenum internalFormat,
+ GLint x, GLint y, GLsizei width, GLint border)
+{
+ struct gl_texture_unit *texUnit =
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+ struct gl_texture_object *texObj =
+ _mesa_select_tex_object(ctx, texUnit, target);
+ struct gl_texture_image *texImage =
+ _mesa_select_tex_image(ctx, texObj, target, level);
+
+ if (border)
+ goto fail;
+
+ /* Setup or redefine the texture object, mipmap tree and texture
+ * image. Don't populate yet.
+ */
+ ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
+ width, border,
+ GL_RGBA, CHAN_TYPE, NULL,
+ &ctx->DefaultPacking, texObj, texImage);
+
+ if (!do_copy_texsubimage(intel_context(ctx),
+ intel_texture_image(texImage),
+ internalFormat, 0, 0, x, y, width, 1))
+ goto fail;
+
+ return;
+
+ fail:
+ _swrast_copy_teximage1d(ctx, target, level, internalFormat, x, y,
+ width, border);
+}
+
+void
+intelCopyTexImage2D(GLcontext * ctx, GLenum target, GLint level,
+ GLenum internalFormat,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border)
+{
+ struct gl_texture_unit *texUnit =
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+ struct gl_texture_object *texObj =
+ _mesa_select_tex_object(ctx, texUnit, target);
+ struct gl_texture_image *texImage =
+ _mesa_select_tex_image(ctx, texObj, target, level);
+
+ if (border)
+ goto fail;
+
+ /* Setup or redefine the texture object, mipmap tree and texture
+ * image. Don't populate yet.
+ */
+ ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
+ width, height, border,
+ GL_RGBA, CHAN_TYPE, NULL,
+ &ctx->DefaultPacking, texObj, texImage);
+
+
+ if (!do_copy_texsubimage(intel_context(ctx),
+ intel_texture_image(texImage),
+ internalFormat, 0, 0, x, y, width, height))
+ goto fail;
+
+ return;
+
+ fail:
+ _swrast_copy_teximage2d(ctx, target, level, internalFormat, x, y,
+ width, height, border);
+}
+
+
+void
+intelCopyTexSubImage1D(GLcontext * ctx, GLenum target, GLint level,
+ GLint xoffset, GLint x, GLint y, GLsizei width)
+{
+ struct gl_texture_unit *texUnit =
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+ struct gl_texture_object *texObj =
+ _mesa_select_tex_object(ctx, texUnit, target);
+ struct gl_texture_image *texImage =
+ _mesa_select_tex_image(ctx, texObj, target, level);
+ GLenum internalFormat = texImage->InternalFormat;
+
+ /* XXX need to check <border> as in above function? */
+
+ /* Need to check texture is compatible with source format.
+ */
+
+ if (!do_copy_texsubimage(intel_context(ctx),
+ intel_texture_image(texImage),
+ internalFormat, xoffset, 0, x, y, width, 1)) {
+ _swrast_copy_texsubimage1d(ctx, target, level, xoffset, x, y, width);
+ }
+}
+
+
+
+void
+intelCopyTexSubImage2D(GLcontext * ctx, GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ struct gl_texture_unit *texUnit =
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+ struct gl_texture_object *texObj =
+ _mesa_select_tex_object(ctx, texUnit, target);
+ struct gl_texture_image *texImage =
+ _mesa_select_tex_image(ctx, texObj, target, level);
+ GLenum internalFormat = texImage->InternalFormat;
+
+
+ /* Need to check texture is compatible with source format.
+ */
+
+ if (!do_copy_texsubimage(intel_context(ctx),
+ intel_texture_image(texImage),
+ internalFormat,
+ xoffset, yoffset, x, y, width, height)) {
+
+ DBG("%s - fallback to swrast\n", __FUNCTION__);
+
+ _swrast_copy_texsubimage2d(ctx, target, level,
+ xoffset, yoffset, x, y, width, height);
+ }
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_tex_format.c b/src/mesa/drivers/dri/i915pipe/intel_tex_format.c
new file mode 100644
index 0000000000..6e058dff69
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_tex_format.c
@@ -0,0 +1,172 @@
+#include "intel_context.h"
+#include "intel_tex.h"
+#include "texformat.h"
+#include "enums.h"
+
+/* It works out that this function is fine for all the supported
+ * hardware. However, there is still a need to map the formats onto
+ * hardware descriptors.
+ */
+/* Note that the i915 can actually support many more formats than
+ * these if we take the step of simply swizzling the colors
+ * immediately after sampling...
+ */
+const struct gl_texture_format *
+intelChooseTextureFormat(GLcontext * ctx, GLint internalFormat,
+ GLenum format, GLenum type)
+{
+ struct intel_context *intel = intel_context(ctx);
+ const GLboolean do32bpt = (intel->intelScreen->cpp == 4);
+
+ switch (internalFormat) {
+ case 4:
+ case GL_RGBA:
+ case GL_COMPRESSED_RGBA:
+ if (format == GL_BGRA) {
+ if (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) {
+ return &_mesa_texformat_argb8888;
+ }
+ else if (type == GL_UNSIGNED_SHORT_4_4_4_4_REV) {
+ return &_mesa_texformat_argb4444;
+ }
+ else if (type == GL_UNSIGNED_SHORT_1_5_5_5_REV) {
+ return &_mesa_texformat_argb1555;
+ }
+ }
+ return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
+
+ case 3:
+ case GL_RGB:
+ case GL_COMPRESSED_RGB:
+ if (format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5) {
+ return &_mesa_texformat_rgb565;
+ }
+ return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
+
+ case GL_RGBA8:
+ case GL_RGB10_A2:
+ case GL_RGBA12:
+ case GL_RGBA16:
+ return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
+
+ case GL_RGBA4:
+ case GL_RGBA2:
+ return &_mesa_texformat_argb4444;
+
+ case GL_RGB5_A1:
+ return &_mesa_texformat_argb1555;
+
+ case GL_RGB8:
+ case GL_RGB10:
+ case GL_RGB12:
+ case GL_RGB16:
+ return &_mesa_texformat_argb8888;
+
+ case GL_RGB5:
+ case GL_RGB4:
+ case GL_R3_G3_B2:
+ return &_mesa_texformat_rgb565;
+
+ case GL_ALPHA:
+ case GL_ALPHA4:
+ case GL_ALPHA8:
+ case GL_ALPHA12:
+ case GL_ALPHA16:
+ case GL_COMPRESSED_ALPHA:
+ return &_mesa_texformat_a8;
+
+ case 1:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE4:
+ case GL_LUMINANCE8:
+ case GL_LUMINANCE12:
+ case GL_LUMINANCE16:
+ case GL_COMPRESSED_LUMINANCE:
+ return &_mesa_texformat_l8;
+
+ case 2:
+ case GL_LUMINANCE_ALPHA:
+ case GL_LUMINANCE4_ALPHA4:
+ case GL_LUMINANCE6_ALPHA2:
+ case GL_LUMINANCE8_ALPHA8:
+ case GL_LUMINANCE12_ALPHA4:
+ case GL_LUMINANCE12_ALPHA12:
+ case GL_LUMINANCE16_ALPHA16:
+ case GL_COMPRESSED_LUMINANCE_ALPHA:
+ return &_mesa_texformat_al88;
+
+ case GL_INTENSITY:
+ case GL_INTENSITY4:
+ case GL_INTENSITY8:
+ case GL_INTENSITY12:
+ case GL_INTENSITY16:
+ case GL_COMPRESSED_INTENSITY:
+ return &_mesa_texformat_i8;
+
+ case GL_YCBCR_MESA:
+ if (type == GL_UNSIGNED_SHORT_8_8_MESA || type == GL_UNSIGNED_BYTE)
+ return &_mesa_texformat_ycbcr;
+ else
+ return &_mesa_texformat_ycbcr_rev;
+
+ case GL_COMPRESSED_RGB_FXT1_3DFX:
+ return &_mesa_texformat_rgb_fxt1;
+ case GL_COMPRESSED_RGBA_FXT1_3DFX:
+ return &_mesa_texformat_rgba_fxt1;
+
+ case GL_RGB_S3TC:
+ case GL_RGB4_S3TC:
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ return &_mesa_texformat_rgb_dxt1;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ return &_mesa_texformat_rgba_dxt1;
+
+ case GL_RGBA_S3TC:
+ case GL_RGBA4_S3TC:
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ return &_mesa_texformat_rgba_dxt3;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ return &_mesa_texformat_rgba_dxt5;
+
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_COMPONENT16:
+ case GL_DEPTH_COMPONENT24:
+ case GL_DEPTH_COMPONENT32:
+ return &_mesa_texformat_z16;
+
+ case GL_DEPTH_STENCIL_EXT:
+ case GL_DEPTH24_STENCIL8_EXT:
+ return &_mesa_texformat_z24_s8;
+
+ default:
+ fprintf(stderr, "unexpected texture format %s in %s\n",
+ _mesa_lookup_enum_by_nr(internalFormat), __FUNCTION__);
+ return NULL;
+ }
+
+ return NULL; /* never get here */
+}
+
+int intel_compressed_num_bytes(GLuint mesaFormat)
+{
+ int bytes = 0;
+ switch(mesaFormat) {
+
+ case MESA_FORMAT_RGB_FXT1:
+ case MESA_FORMAT_RGBA_FXT1:
+ case MESA_FORMAT_RGB_DXT1:
+ case MESA_FORMAT_RGBA_DXT1:
+ bytes = 2;
+ break;
+
+ case MESA_FORMAT_RGBA_DXT3:
+ case MESA_FORMAT_RGBA_DXT5:
+ bytes = 4;
+ default:
+ break;
+ }
+
+ return bytes;
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_tex_image.c b/src/mesa/drivers/dri/i915pipe/intel_tex_image.c
new file mode 100644
index 0000000000..f790b1e6f7
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_tex_image.c
@@ -0,0 +1,691 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "glheader.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "enums.h"
+#include "colortab.h"
+#include "convolve.h"
+#include "context.h"
+#include "simple_list.h"
+#include "texcompress.h"
+#include "texformat.h"
+#include "texobj.h"
+#include "texstore.h"
+
+#include "intel_context.h"
+#include "intel_mipmap_tree.h"
+#include "intel_buffer_objects.h"
+#include "intel_batchbuffer.h"
+#include "intel_tex.h"
+#include "intel_ioctl.h"
+#include "intel_blit.h"
+
+#define FILE_DEBUG_FLAG DEBUG_TEXTURE
+
+/* Functions to store texture images. Where possible, mipmap_tree's
+ * will be created or further instantiated with image data, otherwise
+ * images will be stored in malloc'd memory. A validation step is
+ * required to pull those images into a mipmap tree, or otherwise
+ * decide a fallback is required.
+ */
+
+
+static int
+logbase2(int n)
+{
+ GLint i = 1;
+ GLint log2 = 0;
+
+ while (n > i) {
+ i *= 2;
+ log2++;
+ }
+
+ return log2;
+}
+
+
+/* Otherwise, store it in memory if (Border != 0) or (any dimension ==
+ * 1).
+ *
+ * Otherwise, if max_level >= level >= min_level, create tree with
+ * space for textures from min_level down to max_level.
+ *
+ * Otherwise, create tree with space for textures from (level
+ * 0)..(1x1). Consider pruning this tree at a validation if the
+ * saving is worth it.
+ */
+static void
+guess_and_alloc_mipmap_tree(struct intel_context *intel,
+ struct intel_texture_object *intelObj,
+ struct intel_texture_image *intelImage)
+{
+ GLuint firstLevel;
+ GLuint lastLevel;
+ GLuint width = intelImage->base.Width;
+ GLuint height = intelImage->base.Height;
+ GLuint depth = intelImage->base.Depth;
+ GLuint l2width, l2height, l2depth;
+ GLuint i, comp_byte = 0;
+
+ DBG("%s\n", __FUNCTION__);
+
+ if (intelImage->base.Border)
+ return;
+
+ if (intelImage->level > intelObj->base.BaseLevel &&
+ (intelImage->base.Width == 1 ||
+ (intelObj->base.Target != GL_TEXTURE_1D &&
+ intelImage->base.Height == 1) ||
+ (intelObj->base.Target == GL_TEXTURE_3D &&
+ intelImage->base.Depth == 1)))
+ return;
+
+ /* If this image disrespects BaseLevel, allocate from level zero.
+ * Usually BaseLevel == 0, so it's unlikely to happen.
+ */
+ if (intelImage->level < intelObj->base.BaseLevel)
+ firstLevel = 0;
+ else
+ firstLevel = intelObj->base.BaseLevel;
+
+
+ /* Figure out image dimensions at start level.
+ */
+ for (i = intelImage->level; i > firstLevel; i--) {
+ width <<= 1;
+ if (height != 1)
+ height <<= 1;
+ if (depth != 1)
+ depth <<= 1;
+ }
+
+ /* Guess a reasonable value for lastLevel. This is probably going
+ * to be wrong fairly often and might mean that we have to look at
+ * resizable buffers, or require that buffers implement lazy
+ * pagetable arrangements.
+ */
+ if ((intelObj->base.MinFilter == GL_NEAREST ||
+ intelObj->base.MinFilter == GL_LINEAR) &&
+ intelImage->level == firstLevel) {
+ lastLevel = firstLevel;
+ }
+ else {
+ l2width = logbase2(width);
+ l2height = logbase2(height);
+ l2depth = logbase2(depth);
+ lastLevel = firstLevel + MAX2(MAX2(l2width, l2height), l2depth);
+ }
+
+ assert(!intelObj->mt);
+ if (intelImage->base.IsCompressed)
+ comp_byte = intel_compressed_num_bytes(intelImage->base.TexFormat->MesaFormat);
+ intelObj->mt = intel_miptree_create(intel,
+ intelObj->base.Target,
+ intelImage->base.InternalFormat,
+ firstLevel,
+ lastLevel,
+ width,
+ height,
+ depth,
+ intelImage->base.TexFormat->TexelBytes,
+ comp_byte);
+
+ DBG("%s - success\n", __FUNCTION__);
+}
+
+
+
+
+static GLuint
+target_to_face(GLenum target)
+{
+ switch (target) {
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
+ return ((GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X);
+ default:
+ return 0;
+ }
+}
+
+/* There are actually quite a few combinations this will work for,
+ * more than what I've listed here.
+ */
+static GLboolean
+check_pbo_format(GLint internalFormat,
+ GLenum format, GLenum type,
+ const struct gl_texture_format *mesa_format)
+{
+ switch (internalFormat) {
+ case 4:
+ case GL_RGBA:
+ return (format == GL_BGRA &&
+ (type == GL_UNSIGNED_BYTE ||
+ type == GL_UNSIGNED_INT_8_8_8_8_REV) &&
+ mesa_format == &_mesa_texformat_argb8888);
+ case 3:
+ case GL_RGB:
+ return (format == GL_RGB &&
+ type == GL_UNSIGNED_SHORT_5_6_5 &&
+ mesa_format == &_mesa_texformat_rgb565);
+ case GL_YCBCR_MESA:
+ return (type == GL_UNSIGNED_SHORT_8_8_MESA || type == GL_UNSIGNED_BYTE);
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/* XXX: Do this for TexSubImage also:
+ */
+static GLboolean
+try_pbo_upload(struct intel_context *intel,
+ struct intel_texture_image *intelImage,
+ const struct gl_pixelstore_attrib *unpack,
+ GLint internalFormat,
+ GLint width, GLint height,
+ GLenum format, GLenum type, const void *pixels)
+{
+ struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj);
+ GLuint src_offset, src_stride;
+ GLuint dst_offset, dst_stride;
+
+ if (!pbo ||
+ intel->ctx._ImageTransferState ||
+ unpack->SkipPixels || unpack->SkipRows) {
+ _mesa_printf("%s: failure 1\n", __FUNCTION__);
+ return GL_FALSE;
+ }
+
+ src_offset = (GLuint) pixels;
+
+ if (unpack->RowLength > 0)
+ src_stride = unpack->RowLength;
+ else
+ src_stride = width;
+
+ dst_offset = intel_miptree_image_offset(intelImage->mt,
+ intelImage->face,
+ intelImage->level);
+
+ dst_stride = intelImage->mt->pitch;
+
+ intelFlush(&intel->ctx);
+ LOCK_HARDWARE(intel);
+ {
+ struct _DriBufferObject *src_buffer =
+ intel_bufferobj_buffer(intel, pbo, INTEL_READ);
+ struct _DriBufferObject *dst_buffer =
+ intel_region_buffer(intel->intelScreen, intelImage->mt->region,
+ INTEL_WRITE_FULL);
+
+
+ intelEmitCopyBlit(intel,
+ intelImage->mt->cpp,
+ src_stride, src_buffer, src_offset,
+ dst_stride, dst_buffer, dst_offset,
+ 0, 0, 0, 0, width, height,
+ GL_COPY);
+
+ intel_batchbuffer_flush(intel->batch);
+ }
+ UNLOCK_HARDWARE(intel);
+
+ return GL_TRUE;
+}
+
+
+
+static GLboolean
+try_pbo_zcopy(struct intel_context *intel,
+ struct intel_texture_image *intelImage,
+ const struct gl_pixelstore_attrib *unpack,
+ GLint internalFormat,
+ GLint width, GLint height,
+ GLenum format, GLenum type, const void *pixels)
+{
+ struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj);
+ GLuint src_offset, src_stride;
+ GLuint dst_offset, dst_stride;
+
+ if (!pbo ||
+ intel->ctx._ImageTransferState ||
+ unpack->SkipPixels || unpack->SkipRows) {
+ _mesa_printf("%s: failure 1\n", __FUNCTION__);
+ return GL_FALSE;
+ }
+
+ src_offset = (GLuint) pixels;
+
+ if (unpack->RowLength > 0)
+ src_stride = unpack->RowLength;
+ else
+ src_stride = width;
+
+ dst_offset = intel_miptree_image_offset(intelImage->mt,
+ intelImage->face,
+ intelImage->level);
+
+ dst_stride = intelImage->mt->pitch;
+
+ if (src_stride != dst_stride || dst_offset != 0 || src_offset != 0) {
+ _mesa_printf("%s: failure 2\n", __FUNCTION__);
+ return GL_FALSE;
+ }
+
+ intel_region_attach_pbo(intel->intelScreen, intelImage->mt->region, pbo);
+
+ return GL_TRUE;
+}
+
+
+
+
+
+
+static void
+intelTexImage(GLcontext * ctx,
+ GLint dims,
+ GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint depth,
+ GLint border,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *unpack,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage, GLsizei imageSize, int compressed)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_texture_object *intelObj = intel_texture_object(texObj);
+ struct intel_texture_image *intelImage = intel_texture_image(texImage);
+ GLint postConvWidth = width;
+ GLint postConvHeight = height;
+ GLint texelBytes, sizeInBytes;
+ GLuint dstRowStride;
+
+
+ DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr(target), level, width, height, depth, border);
+
+ intelFlush(ctx);
+
+ intelImage->face = target_to_face(target);
+ intelImage->level = level;
+
+ if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) {
+ _mesa_adjust_image_for_convolution(ctx, dims, &postConvWidth,
+ &postConvHeight);
+ }
+
+ /* choose the texture format */
+ texImage->TexFormat = intelChooseTextureFormat(ctx, internalFormat,
+ format, type);
+
+ _mesa_set_fetch_functions(texImage, dims);
+
+ if (texImage->TexFormat->TexelBytes == 0) {
+ /* must be a compressed format */
+ texelBytes = 0;
+ texImage->IsCompressed = GL_TRUE;
+ texImage->CompressedSize =
+ ctx->Driver.CompressedTextureSize(ctx, texImage->Width,
+ texImage->Height, texImage->Depth,
+ texImage->TexFormat->MesaFormat);
+ } else {
+ texelBytes = texImage->TexFormat->TexelBytes;
+
+ /* Minimum pitch of 32 bytes */
+ if (postConvWidth * texelBytes < 32) {
+ postConvWidth = 32 / texelBytes;
+ texImage->RowStride = postConvWidth;
+ }
+
+ assert(texImage->RowStride == postConvWidth);
+ }
+
+ /* Release the reference to a potentially orphaned buffer.
+ * Release any old malloced memory.
+ */
+ if (intelImage->mt) {
+ intel_miptree_release(intel, &intelImage->mt);
+ assert(!texImage->Data);
+ }
+ else if (texImage->Data) {
+ _mesa_align_free(texImage->Data);
+ }
+
+ /* If this is the only texture image in the tree, could call
+ * bmBufferData with NULL data to free the old block and avoid
+ * waiting on any outstanding fences.
+ */
+ if (intelObj->mt &&
+ intelObj->mt->first_level == level &&
+ intelObj->mt->last_level == level &&
+ intelObj->mt->target != GL_TEXTURE_CUBE_MAP_ARB &&
+ !intel_miptree_match_image(intelObj->mt, &intelImage->base,
+ intelImage->face, intelImage->level)) {
+
+ DBG("release it\n");
+ intel_miptree_release(intel, &intelObj->mt);
+ assert(!intelObj->mt);
+ }
+
+ if (!intelObj->mt) {
+ guess_and_alloc_mipmap_tree(intel, intelObj, intelImage);
+ if (!intelObj->mt) {
+ DBG("guess_and_alloc_mipmap_tree: failed\n");
+ }
+ }
+
+ assert(!intelImage->mt);
+
+ if (intelObj->mt &&
+ intel_miptree_match_image(intelObj->mt, &intelImage->base,
+ intelImage->face, intelImage->level)) {
+
+ intel_miptree_reference(&intelImage->mt, intelObj->mt);
+ assert(intelImage->mt);
+ }
+
+ if (!intelImage->mt)
+ DBG("XXX: Image did not fit into tree - storing in local memory!\n");
+
+ /* PBO fastpaths:
+ */
+ if (dims <= 2 &&
+ intelImage->mt &&
+ intel_buffer_object(unpack->BufferObj) &&
+ check_pbo_format(internalFormat, format,
+ type, intelImage->base.TexFormat)) {
+
+ DBG("trying pbo upload\n");
+
+ /* Attempt to texture directly from PBO data (zero copy upload).
+ *
+ * Currently disable as it can lead to worse as well as better
+ * performance (in particular when intel_region_cow() is
+ * required).
+ */
+ if (intelObj->mt == intelImage->mt &&
+ intelObj->mt->first_level == level &&
+ intelObj->mt->last_level == level) {
+
+ if (try_pbo_zcopy(intel, intelImage, unpack,
+ internalFormat,
+ width, height, format, type, pixels)) {
+
+ DBG("pbo zcopy upload succeeded\n");
+ return;
+ }
+ }
+
+
+ /* Otherwise, attempt to use the blitter for PBO image uploads.
+ */
+ if (try_pbo_upload(intel, intelImage, unpack,
+ internalFormat,
+ width, height, format, type, pixels)) {
+ DBG("pbo upload succeeded\n");
+ return;
+ }
+
+ DBG("pbo upload failed\n");
+ }
+
+
+
+ /* intelCopyTexImage calls this function with pixels == NULL, with
+ * the expectation that the mipmap tree will be set up but nothing
+ * more will be done. This is where those calls return:
+ */
+ if (compressed) {
+ pixels = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, pixels,
+ unpack,
+ "glCompressedTexImage");
+ } else {
+ pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, 1,
+ format, type,
+ pixels, unpack, "glTexImage");
+ }
+ if (!pixels)
+ return;
+
+
+ if (intelImage->mt)
+ intel_region_idle(intel->intelScreen, intelImage->mt->region);
+
+ LOCK_HARDWARE(intel);
+
+ if (intelImage->mt) {
+ texImage->Data = intel_miptree_image_map(intel,
+ intelImage->mt,
+ intelImage->face,
+ intelImage->level,
+ &dstRowStride,
+ intelImage->base.ImageOffsets);
+ }
+ else {
+ /* Allocate regular memory and store the image there temporarily. */
+ if (texImage->IsCompressed) {
+ sizeInBytes = texImage->CompressedSize;
+ dstRowStride =
+ _mesa_compressed_row_stride(texImage->TexFormat->MesaFormat, width);
+ assert(dims != 3);
+ }
+ else {
+ dstRowStride = postConvWidth * texelBytes;
+ sizeInBytes = depth * dstRowStride * postConvHeight;
+ }
+
+ texImage->Data = malloc(sizeInBytes);
+ }
+
+ DBG("Upload image %dx%dx%d row_len %x "
+ "pitch %x\n",
+ width, height, depth, width * texelBytes, dstRowStride);
+
+ /* Copy data. Would like to know when it's ok for us to eg. use
+ * the blitter to copy. Or, use the hardware to do the format
+ * conversion and copy:
+ */
+ if (compressed) {
+ memcpy(texImage->Data, pixels, imageSize);
+ } else if (!texImage->TexFormat->StoreImage(ctx, dims,
+ texImage->_BaseFormat,
+ texImage->TexFormat,
+ texImage->Data, 0, 0, 0, /* dstX/Y/Zoffset */
+ dstRowStride,
+ texImage->ImageOffsets,
+ width, height, depth,
+ format, type, pixels, unpack)) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
+ }
+
+ _mesa_unmap_teximage_pbo(ctx, unpack);
+
+ if (intelImage->mt) {
+ intel_miptree_image_unmap(intel, intelImage->mt);
+ texImage->Data = NULL;
+ }
+
+ UNLOCK_HARDWARE(intel);
+
+#if 0
+ /* GL_SGIS_generate_mipmap -- this can be accelerated now.
+ */
+ if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
+ intel_generate_mipmap(ctx, target,
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+ texObj);
+ }
+#endif
+}
+
+void
+intelTexImage3D(GLcontext * ctx,
+ GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint depth,
+ GLint border,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *unpack,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ intelTexImage(ctx, 3, target, level,
+ internalFormat, width, height, depth, border,
+ format, type, pixels, unpack, texObj, texImage, 0, 0);
+}
+
+
+void
+intelTexImage2D(GLcontext * ctx,
+ GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint border,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *unpack,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ intelTexImage(ctx, 2, target, level,
+ internalFormat, width, height, 1, border,
+ format, type, pixels, unpack, texObj, texImage, 0, 0);
+}
+
+void
+intelTexImage1D(GLcontext * ctx,
+ GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint border,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *unpack,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ intelTexImage(ctx, 1, target, level,
+ internalFormat, width, 1, 1, border,
+ format, type, pixels, unpack, texObj, texImage, 0, 0);
+}
+
+void intelCompressedTexImage2D( GLcontext *ctx, GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint border,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage )
+{
+ intelTexImage(ctx, 2, target, level,
+ internalFormat, width, height, 1, border,
+ 0, 0, data, &ctx->Unpack, texObj, texImage, imageSize, 1);
+}
+
+/**
+ * Need to map texture image into memory before copying image data,
+ * then unmap it.
+ */
+static void
+intel_get_tex_image(GLcontext * ctx, GLenum target, GLint level,
+ GLenum format, GLenum type, GLvoid * pixels,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage, int compressed)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_texture_image *intelImage = intel_texture_image(texImage);
+
+ /* Map */
+ if (intelImage->mt) {
+ /* Image is stored in hardware format in a buffer managed by the
+ * kernel. Need to explicitly map and unmap it.
+ */
+ intelImage->base.Data =
+ intel_miptree_image_map(intel,
+ intelImage->mt,
+ intelImage->face,
+ intelImage->level,
+ &intelImage->base.RowStride,
+ intelImage->base.ImageOffsets);
+ intelImage->base.RowStride /= intelImage->mt->cpp;
+ }
+ else {
+ /* Otherwise, the image should actually be stored in
+ * intelImage->base.Data. This is pretty confusing for
+ * everybody, I'd much prefer to separate the two functions of
+ * texImage->Data - storage for texture images in main memory
+ * and access (ie mappings) of images. In other words, we'd
+ * create a new texImage->Map field and leave Data simply for
+ * storage.
+ */
+ assert(intelImage->base.Data);
+ }
+
+
+ if (compressed) {
+ _mesa_get_compressed_teximage(ctx, target, level, pixels,
+ texObj, texImage);
+ } else {
+ _mesa_get_teximage(ctx, target, level, format, type, pixels,
+ texObj, texImage);
+ }
+
+
+ /* Unmap */
+ if (intelImage->mt) {
+ intel_miptree_image_unmap(intel, intelImage->mt);
+ intelImage->base.Data = NULL;
+ }
+}
+
+void
+intelGetTexImage(GLcontext * ctx, GLenum target, GLint level,
+ GLenum format, GLenum type, GLvoid * pixels,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ intel_get_tex_image(ctx, target, level, format, type, pixels,
+ texObj, texImage, 0);
+
+
+}
+
+void
+intelGetCompressedTexImage(GLcontext *ctx, GLenum target, GLint level,
+ GLvoid *pixels,
+ const struct gl_texture_object *texObj,
+ const struct gl_texture_image *texImage)
+{
+ intel_get_tex_image(ctx, target, level, 0, 0, pixels,
+ texObj, texImage, 1);
+
+}
+
+void
+intelSetTexOffset(__DRIcontext *pDRICtx, GLint texname,
+ unsigned long long offset, GLint depth, GLuint pitch)
+{
+ struct intel_context *intel = (struct intel_context*)
+ ((__DRIcontextPrivate*)pDRICtx->private)->driverPrivate;
+ struct gl_texture_object *tObj = _mesa_lookup_texture(&intel->ctx, texname);
+ struct intel_texture_object *intelObj = intel_texture_object(tObj);
+
+ if (!intelObj)
+ return;
+
+ if (intelObj->mt)
+ intel_miptree_release(intel, &intelObj->mt);
+
+ intelObj->imageOverride = GL_TRUE;
+ intelObj->depthOverride = depth;
+ intelObj->pitchOverride = pitch;
+
+ if (offset)
+ intelObj->textureOffset = offset;
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_tex_layout.c b/src/mesa/drivers/dri/i915pipe/intel_tex_layout.c
new file mode 120000
index 0000000000..fe61b44194
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_tex_layout.c
@@ -0,0 +1 @@
+../intel/intel_tex_layout.c \ No newline at end of file
diff --git a/src/mesa/drivers/dri/i915pipe/intel_tex_subimage.c b/src/mesa/drivers/dri/i915pipe/intel_tex_subimage.c
new file mode 100644
index 0000000000..3935787806
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_tex_subimage.c
@@ -0,0 +1,182 @@
+
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "mtypes.h"
+#include "texobj.h"
+#include "texstore.h"
+#include "enums.h"
+
+#include "intel_context.h"
+#include "intel_tex.h"
+#include "intel_mipmap_tree.h"
+
+#define FILE_DEBUG_FLAG DEBUG_TEXTURE
+
+static void
+intelTexSubimage(GLcontext * ctx,
+ GLint dims,
+ GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLint width, GLint height, GLint depth,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ struct intel_context *intel = intel_context(ctx);
+ struct intel_texture_image *intelImage = intel_texture_image(texImage);
+ GLuint dstRowStride;
+
+ DBG("%s target %s level %d offset %d,%d %dx%d\n", __FUNCTION__,
+ _mesa_lookup_enum_by_nr(target),
+ level, xoffset, yoffset, width, height);
+
+ intelFlush(ctx);
+
+ pixels =
+ _mesa_validate_pbo_teximage(ctx, dims, width, height, depth, format,
+ type, pixels, packing, "glTexSubImage2D");
+ if (!pixels)
+ return;
+
+ if (intelImage->mt)
+ intel_region_idle(intel->intelScreen, intelImage->mt->region);
+
+ LOCK_HARDWARE(intel);
+
+ /* Map buffer if necessary. Need to lock to prevent other contexts
+ * from uploading the buffer under us.
+ */
+ if (intelImage->mt)
+ texImage->Data = intel_miptree_image_map(intel,
+ intelImage->mt,
+ intelImage->face,
+ intelImage->level,
+ &dstRowStride,
+ texImage->ImageOffsets);
+
+ assert(dstRowStride);
+
+ if (!texImage->TexFormat->StoreImage(ctx, dims, texImage->_BaseFormat,
+ texImage->TexFormat,
+ texImage->Data,
+ xoffset, yoffset, zoffset,
+ dstRowStride,
+ texImage->ImageOffsets,
+ width, height, depth,
+ format, type, pixels, packing)) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "intelTexSubImage");
+ }
+
+#if 0
+ /* GL_SGIS_generate_mipmap */
+ if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
+ _mesa_generate_mipmap(ctx, target,
+ &ctx->Texture.Unit[ctx->Texture.CurrentUnit],
+ texObj);
+ }
+#endif
+
+ _mesa_unmap_teximage_pbo(ctx, packing);
+
+ if (intelImage->mt) {
+ intel_miptree_image_unmap(intel, intelImage->mt);
+ texImage->Data = NULL;
+ }
+
+ UNLOCK_HARDWARE(intel);
+}
+
+
+
+
+
+void
+intelTexSubImage3D(GLcontext * ctx,
+ GLenum target,
+ GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type,
+ const GLvoid * pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+
+ intelTexSubimage(ctx, 3,
+ target, level,
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ format, type, pixels, packing, texObj, texImage);
+
+}
+
+
+
+void
+intelTexSubImage2D(GLcontext * ctx,
+ GLenum target,
+ GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const GLvoid * pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+
+ intelTexSubimage(ctx, 2,
+ target, level,
+ xoffset, yoffset, 0,
+ width, height, 1,
+ format, type, pixels, packing, texObj, texImage);
+
+}
+
+
+void
+intelTexSubImage1D(GLcontext * ctx,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLsizei width,
+ GLenum format, GLenum type,
+ const GLvoid * pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage)
+{
+ intelTexSubimage(ctx, 1,
+ target, level,
+ xoffset, 0, 0,
+ width, 1, 1,
+ format, type, pixels, packing, texObj, texImage);
+
+}
diff --git a/src/mesa/drivers/dri/i915pipe/intel_tex_validate.c b/src/mesa/drivers/dri/i915pipe/intel_tex_validate.c
new file mode 100644
index 0000000000..af18c26d55
--- /dev/null
+++ b/src/mesa/drivers/dri/i915pipe/intel_tex_validate.c
@@ -0,0 +1,272 @@
+#include "mtypes.h"
+#include "macros.h"
+
+#include "intel_context.h"
+#include "intel_batchbuffer.h"
+#include "intel_mipmap_tree.h"
+#include "intel_tex.h"
+
+#define FILE_DEBUG_FLAG DEBUG_TEXTURE
+
+/**
+ * Compute which mipmap levels that really need to be sent to the hardware.
+ * This depends on the base image size, GL_TEXTURE_MIN_LOD,
+ * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
+ */
+static void
+intel_calculate_first_last_level(struct intel_texture_object *intelObj)
+{
+ struct gl_texture_object *tObj = &intelObj->base;
+ const struct gl_texture_image *const baseImage =
+ tObj->Image[0][tObj->BaseLevel];
+
+ /* These must be signed values. MinLod and MaxLod can be negative numbers,
+ * and having firstLevel and lastLevel as signed prevents the need for
+ * extra sign checks.
+ */
+ int firstLevel;
+ int lastLevel;
+
+ /* Yes, this looks overly complicated, but it's all needed.
+ */
+ switch (tObj->Target) {
+ case GL_TEXTURE_1D:
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_3D:
+ case GL_TEXTURE_CUBE_MAP:
+ if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) {
+ /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
+ */
+ firstLevel = lastLevel = tObj->BaseLevel;
+ }
+ else {
+ firstLevel = tObj->BaseLevel + (GLint) (tObj->MinLod + 0.5);
+ firstLevel = MAX2(firstLevel, tObj->BaseLevel);
+ lastLevel = tObj->BaseLevel + (GLint) (tObj->MaxLod + 0.5);
+ lastLevel = MAX2(lastLevel, tObj->BaseLevel);
+ lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2);
+ lastLevel = MIN2(lastLevel, tObj->MaxLevel);
+ lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
+ }
+ break;
+ case GL_TEXTURE_RECTANGLE_NV:
+ case GL_TEXTURE_4D_SGIS:
+ firstLevel = lastLevel = 0;
+ break;
+ default:
+ return;
+ }
+
+ /* save these values */
+ intelObj->firstLevel = firstLevel;
+ intelObj->lastLevel = lastLevel;
+}
+
+static void
+copy_image_data_to_tree(struct intel_context *intel,
+ struct intel_texture_object *intelObj,
+ struct intel_texture_image *intelImage)
+{
+ if (intelImage->mt) {
+ /* Copy potentially with the blitter:
+ */
+ intel_miptree_image_copy(intel,
+ intelObj->mt,
+ intelImage->face,
+ intelImage->level, intelImage->mt);
+
+ intel_miptree_release(intel, &intelImage->mt);
+ }
+ else {
+ assert(intelImage->base.Data != NULL);
+
+ /* More straightforward upload.
+ */
+ intel_miptree_image_data(intel,
+ intelObj->mt,
+ intelImage->face,
+ intelImage->level,
+ intelImage->base.Data,
+ intelImage->base.RowStride,
+ intelImage->base.RowStride *
+ intelImage->base.Height);
+ _mesa_align_free(intelImage->base.Data);
+ intelImage->base.Data = NULL;
+ }
+
+ intel_miptree_reference(&intelImage->mt, intelObj->mt);
+}
+
+
+/*
+ */
+GLuint
+intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit)
+{
+ struct gl_texture_object *tObj = intel->ctx.Texture.Unit[unit]._Current;
+ struct intel_texture_object *intelObj = intel_texture_object(tObj);
+ int comp_byte = 0;
+ int cpp;
+
+ GLuint face, i;
+ GLuint nr_faces = 0;
+ struct intel_texture_image *firstImage;
+
+ GLboolean need_flush = GL_FALSE;
+
+ /* We know/require this is true by now:
+ */
+ assert(intelObj->base._Complete);
+
+ /* What levels must the tree include at a minimum?
+ */
+ intel_calculate_first_last_level(intelObj);
+ firstImage =
+ intel_texture_image(intelObj->base.Image[0][intelObj->firstLevel]);
+
+ /* Fallback case:
+ */
+ if (firstImage->base.Border) {
+ if (intelObj->mt) {
+ intel_miptree_release(intel, &intelObj->mt);
+ }
+ return GL_FALSE;
+ }
+
+
+ /* If both firstImage and intelObj have a tree which can contain
+ * all active images, favour firstImage. Note that because of the
+ * completeness requirement, we know that the image dimensions
+ * will match.
+ */
+ if (firstImage->mt &&
+ firstImage->mt != intelObj->mt &&
+ firstImage->mt->first_level <= intelObj->firstLevel &&
+ firstImage->mt->last_level >= intelObj->lastLevel) {
+
+ if (intelObj->mt)
+ intel_miptree_release(intel, &intelObj->mt);
+
+ intel_miptree_reference(&intelObj->mt, firstImage->mt);
+ }
+
+ if (firstImage->base.IsCompressed) {
+ comp_byte = intel_compressed_num_bytes(firstImage->base.TexFormat->MesaFormat);
+ cpp = comp_byte;
+ }
+ else cpp = firstImage->base.TexFormat->TexelBytes;
+
+ /* Check tree can hold all active levels. Check tree matches
+ * target, imageFormat, etc.
+ *
+ * XXX: For some layouts (eg i945?), the test might have to be
+ * first_level == firstLevel, as the tree isn't valid except at the
+ * original start level. Hope to get around this by
+ * programming minLod, maxLod, baseLevel into the hardware and
+ * leaving the tree alone.
+ */
+ if (intelObj->mt &&
+ (intelObj->mt->target != intelObj->base.Target ||
+ intelObj->mt->internal_format != firstImage->base.InternalFormat ||
+ intelObj->mt->first_level != intelObj->firstLevel ||
+ intelObj->mt->last_level != intelObj->lastLevel ||
+ intelObj->mt->width0 != firstImage->base.Width ||
+ intelObj->mt->height0 != firstImage->base.Height ||
+ intelObj->mt->depth0 != firstImage->base.Depth ||
+ intelObj->mt->cpp != cpp ||
+ intelObj->mt->compressed != firstImage->base.IsCompressed)) {
+ intel_miptree_release(intel, &intelObj->mt);
+ }
+
+
+ /* May need to create a new tree:
+ */
+ if (!intelObj->mt) {
+ intelObj->mt = intel_miptree_create(intel,
+ intelObj->base.Target,
+ firstImage->base.InternalFormat,
+ intelObj->firstLevel,
+ intelObj->lastLevel,
+ firstImage->base.Width,
+ firstImage->base.Height,
+ firstImage->base.Depth,
+ cpp,
+ comp_byte);
+ }
+
+ /* Pull in any images not in the object's tree:
+ */
+ nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
+ for (face = 0; face < nr_faces; face++) {
+ for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++) {
+ struct intel_texture_image *intelImage =
+ intel_texture_image(intelObj->base.Image[face][i]);
+
+ /* Need to import images in main memory or held in other trees.
+ */
+ if (intelObj->mt != intelImage->mt) {
+ copy_image_data_to_tree(intel, intelObj, intelImage);
+ need_flush = GL_TRUE;
+ }
+ }
+ }
+
+ if (need_flush)
+ intel_batchbuffer_flush(intel->batch);
+
+ return GL_TRUE;
+}
+
+
+
+void
+intel_tex_map_images(struct intel_context *intel,
+ struct intel_texture_object *intelObj)
+{
+ GLuint nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
+ GLuint face, i;
+
+ DBG("%s\n", __FUNCTION__);
+
+ for (face = 0; face < nr_faces; face++) {
+ for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++) {
+ struct intel_texture_image *intelImage =
+ intel_texture_image(intelObj->base.Image[face][i]);
+
+ if (intelImage->mt) {
+ intelImage->base.Data =
+ intel_miptree_image_map(intel,
+ intelImage->mt,
+ intelImage->face,
+ intelImage->level,
+ &intelImage->base.RowStride,
+ intelImage->base.ImageOffsets);
+ /* convert stride to texels, not bytes */
+ intelImage->base.RowStride /= intelImage->mt->cpp;
+/* intelImage->base.ImageStride /= intelImage->mt->cpp; */
+ }
+ }
+ }
+}
+
+
+
+void
+intel_tex_unmap_images(struct intel_context *intel,
+ struct intel_texture_object *intelObj)
+{
+ GLuint nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
+ GLuint face, i;
+
+ for (face = 0; face < nr_faces; face++) {
+ for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++) {
+ struct intel_texture_image *intelImage =
+ intel_texture_image(intelObj->base.Image[face][i]);
+
+ if (intelImage->mt) {
+ intel_miptree_image_unmap(intel, intelImage->mt);
+ intelImage->base.Data = NULL;
+ }
+ }
+ }
+}