summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Whitwell <keith@tungstengraphics.com>2006-08-03 15:41:10 +0000
committerKeith Whitwell <keith@tungstengraphics.com>2006-08-03 15:41:10 +0000
commitf9f3de8c316ac63c27a09b04482501b628943f50 (patch)
tree651889882d5e54927e47ffa4d882ccf322ace0c8
parent3d0a073a71f8ce04387b1c4072af83daa93b5326 (diff)
downloadmesa-f9f3de8c316ac63c27a09b04482501b628943f50.tar.gz
first pass at texture uploads from pbo's with the blitter
-rw-r--r--src/mesa/drivers/dri/i915/intel_blit.c511
-rw-r--r--src/mesa/drivers/dri/i915/intel_bufmgr.c454
-rw-r--r--src/mesa/drivers/dri/i915/intel_tex_image.c560
3 files changed, 1525 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i915/intel_blit.c b/src/mesa/drivers/dri/i915/intel_blit.c
new file mode 100644
index 00000000000..83d3e183dad
--- /dev/null
+++ b/src/mesa/drivers/dri/i915/intel_blit.c
@@ -0,0 +1,511 @@
+/**************************************************************************
+ *
+ * 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 "intel_bufmgr.h"
+
+
+/**
+ * Copy the back color buffer to the front color buffer.
+ * Used for SwapBuffers().
+ */
+void intelCopyBuffer( const __DRIdrawablePrivate *dPriv,
+ const drm_clip_rect_t *rect )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct intel_context *intel;
+ GLboolean missed_target;
+ int64_t ust;
+
+ DBG("%s\n", __FUNCTION__);
+
+ assert(dPriv);
+
+ /* We need a rendering context in order to issue the blit cmd.
+ * Use the current context.
+ * XXX need to fix this someday.
+ */
+ if (!ctx) {
+ _mesa_problem(NULL, "No current context in intelCopyBuffer()");
+ return;
+ }
+ intel = (struct intel_context *) ctx;
+
+ /* FIXME: Temporary fix for fence ageing.
+ *
+ */
+
+ if (!intel->last_swap_fence_retired) {
+ bmFinishFence(intel->bm, intel->last_swap_fence);
+ }
+
+
+ if (!rect)
+ {
+ driWaitForVBlank( dPriv, &intel->vbl_seq, intel->vblank_flags, & missed_target );
+ }
+
+
+ /* The LOCK_HARDWARE is required for the cliprects. Buffer offsets
+ * should work regardless.
+ */
+ LOCK_HARDWARE( intel );
+
+ if (intel->driDrawable &&
+ intel->driDrawable->numClipRects)
+ {
+ const intelScreenPrivate *intelScreen = intel->intelScreen;
+ struct gl_framebuffer *fb
+ = (struct gl_framebuffer *) dPriv->driverPrivate;
+ const struct intel_region *frontRegion
+ = intel_get_rb_region(fb, BUFFER_FRONT_LEFT);
+ const struct intel_region *backRegion
+ = intel_get_rb_region(fb, BUFFER_BACK_LEFT);
+ const int nbox = dPriv->numClipRects;
+ const drm_clip_rect_t *pbox = dPriv->pClipRects;
+ const int pitch = frontRegion->pitch;
+ const int cpp = frontRegion->cpp;
+ int BR13, CMD;
+ int i;
+
+ ASSERT(fb);
+ ASSERT(fb->Name == 0); /* Not a user-created FBO */
+ ASSERT(frontRegion);
+ ASSERT(backRegion);
+ ASSERT(frontRegion->pitch == backRegion->pitch);
+ ASSERT(frontRegion->cpp == backRegion->cpp);
+
+ 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;
+
+ if (pbox->x1 > pbox->x2 ||
+ pbox->y1 > pbox->y2 ||
+ pbox->x2 > intelScreen->width ||
+ pbox->y2 > intelScreen->height)
+ continue;
+
+ box = *pbox;
+
+ if (rect)
+ {
+ if (rect->x1 > box.x1)
+ box.x1 = rect->x1;
+ if (rect->y1 > box.y1)
+ box.y1 = rect->y1;
+ if (rect->x2 < box.x2)
+ box.x2 = rect->x2;
+ if (rect->y2 < box.y2)
+ box.y2 = rect->y2;
+
+ if (box.x1 > box.x2 || box.y1 > box.y2)
+ continue;
+ }
+
+ BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS);
+ OUT_BATCH( CMD );
+ OUT_BATCH( BR13 );
+ OUT_BATCH( (pbox->y1 << 16) | pbox->x1 );
+ OUT_BATCH( (pbox->y2 << 16) | pbox->x2 );
+
+ if (intel->sarea->pf_current_page == 0)
+ OUT_RELOC( frontRegion->buffer, DRM_MM_TT|DRM_MM_WRITE, 0 );
+ else
+ OUT_RELOC( backRegion->buffer, DRM_MM_TT|DRM_MM_WRITE, 0 );
+ OUT_BATCH( (pbox->y1 << 16) | pbox->x1 );
+ OUT_BATCH( BR13 & 0xffff );
+
+ if (intel->sarea->pf_current_page == 0)
+ OUT_RELOC( backRegion->buffer, DRM_MM_TT|DRM_MM_READ, 0 );
+ else
+ OUT_RELOC( frontRegion->buffer, DRM_MM_TT|DRM_MM_READ, 0 );
+
+ ADVANCE_BATCH();
+ }
+
+ intel->last_swap_fence = intel_batchbuffer_flush( intel->batch );
+ intel->last_swap_fence_retired = GL_FALSE;
+ }
+ UNLOCK_HARDWARE( intel );
+
+ if (!rect)
+ {
+ intel->swap_count++;
+ (*dri_interface->getUST)(&ust);
+ if (missed_target) {
+ intel->swap_missed_count++;
+ intel->swap_missed_ust = ust - intel->swap_ust;
+ }
+
+ intel->swap_ust = ust;
+ }
+}
+
+
+
+
+void intelEmitFillBlit( struct intel_context *intel,
+ GLuint cpp,
+ GLshort dst_pitch,
+ GLuint 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(%d)/%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_MM_TT|DRM_MM_WRITE, dst_offset );
+ OUT_BATCH( color );
+ ADVANCE_BATCH();
+}
+
+
+/* Copy BitBlt
+ */
+void intelEmitCopyBlit( struct intel_context *intel,
+ GLuint cpp,
+ GLshort src_pitch,
+ GLuint src_buffer,
+ GLuint src_offset,
+ GLshort dst_pitch,
+ GLuint dst_buffer,
+ GLuint dst_offset,
+ GLshort src_x, GLshort src_y,
+ GLshort dst_x, GLshort dst_y,
+ GLshort w, GLshort h )
+{
+ GLuint CMD, BR13;
+ int dst_y2 = dst_y + h;
+ int dst_x2 = dst_x + w;
+ BATCH_LOCALS;
+
+
+ DBG("%s src:buf(%d)/%d+%d %d,%d dst:buf(%d)/%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) | (0xCC << 16) | (1<<24);
+ CMD = XY_SRC_COPY_BLT_CMD;
+ break;
+ case 4:
+ BR13 = (((GLint)dst_pitch)&0xffff) | (0xCC << 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_MM_TT|DRM_MM_WRITE, dst_offset );
+ OUT_BATCH( (src_y << 16) | src_x );
+ OUT_BATCH( ((GLint)src_pitch&0xffff) );
+ OUT_RELOC( src_buffer, DRM_MM_TT|DRM_MM_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_MM_TT|DRM_MM_WRITE, dst_offset + dst_y * dst_pitch );
+ OUT_BATCH( (0 << 16) | src_x );
+ OUT_BATCH( ((GLint)src_pitch&0xffff) );
+ OUT_RELOC( src_buffer, DRM_MM_TT|DRM_MM_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, GLboolean all,
+ GLint cx, GLint cy, GLint cw, GLint ch)
+{
+ struct intel_context *intel = intel_context( ctx );
+ GLuint clear_depth;
+ GLbitfield skipBuffers = 0;
+ BATCH_LOCALS;
+
+ if (INTEL_DEBUG & DEBUG_DRI)
+ _mesa_printf("%s %x\n", __FUNCTION__, mask);
+
+ /*
+ * Compute values for clearing the buffers.
+ */
+ clear_depth = 0;
+ if (mask & BUFFER_BIT_DEPTH) {
+ clear_depth = (GLuint) (ctx->DrawBuffer->_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)
+ {
+ drm_clip_rect_t clear;
+ int i;
+
+ /* Refresh the cx/y/w/h values as they may have been invalidated
+ * by a new window position or size picked up when we did
+ * LOCK_HARDWARE above. The values passed by mesa are not
+ * reliable.
+ */
+ {
+ cx = ctx->DrawBuffer->_Xmin;
+ cy = ctx->DrawBuffer->_Ymin;
+ ch = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
+ cw = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
+ }
+
+ if (intel->ctx.DrawBuffer->Name == 0) {
+ /* clearing a window */
+
+ /* flip top to bottom */
+ clear.x1 = cx + intel->drawX;
+ clear.y1 = intel->driDrawable->y + intel->driDrawable->h - cy - ch;
+ clear.x2 = clear.x1 + cw;
+ clear.y2 = clear.y1 + ch;
+
+ /* adjust for page flipping */
+ if ( intel->sarea->pf_current_page == 1 ) {
+ const GLuint tmp = mask;
+ mask &= ~(BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT);
+ if ( tmp & BUFFER_BIT_FRONT_LEFT ) mask |= BUFFER_BIT_BACK_LEFT;
+ if ( tmp & BUFFER_BIT_BACK_LEFT ) mask |= BUFFER_BIT_FRONT_LEFT;
+ }
+ }
+ else {
+ /* clearing FBO */
+ ASSERT(intel->numClipRects == 1);
+ ASSERT(intel->pClipRects == &intel->fboRect);
+ clear.x1 = cx;
+ clear.y1 = intel->ctx.DrawBuffer->Height - cy - ch;
+ clear.x2 = clear.y1 + cw;
+ clear.y2 = clear.y1 + ch;
+ /* no change to mask */
+ }
+
+ for (i = 0 ; i < intel->numClipRects ; i++)
+ {
+ const drm_clip_rect_t *box = &intel->pClipRects[i];
+ drm_clip_rect_t b;
+ GLuint buf;
+ GLuint clearMask = mask; /* use copy, since we modify it below */
+
+ if (!all) {
+ intel_intersect_cliprects(&b, &clear, box);
+ } else {
+ b = *box;
+ }
+
+ if (0)
+ _mesa_printf("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 */
+ const struct intel_renderbuffer *irb
+ = intel_renderbuffer(ctx->DrawBuffer->
+ Attachment[buf].Renderbuffer);
+ GLuint clearVal;
+ GLint pitch, cpp;
+ GLuint BR13, CMD;
+
+ ASSERT(irb);
+ ASSERT(irb->region);
+
+ pitch = irb->region->pitch;
+ cpp = irb->region->cpp;
+
+ DBG("%s dst:buf(%d)/%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);
+ */
+ 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( irb->region->buffer, DRM_MM_TT|DRM_MM_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/i915/intel_bufmgr.c b/src/mesa/drivers/dri/i915/intel_bufmgr.c
new file mode 100644
index 00000000000..c9efed9f431
--- /dev/null
+++ b/src/mesa/drivers/dri/i915/intel_bufmgr.c
@@ -0,0 +1,454 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Steamboat Springs, CO.
+ * 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.
+ *
+ *
+ **************************************************************************/
+
+#include "intel_bufmgr.h"
+
+#include "intel_context.h"
+#include "intel_ioctl.h"
+
+#include "hash.h"
+#include "simple_list.h"
+#include "mm.h"
+#include "imports.h"
+#include "glthread.h"
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <drm.h>
+
+struct _mesa_HashTable;
+
+/* The buffer manager is really part of the gl_shared_state struct.
+ * TODO: Organize for the bufmgr to be created/deleted with the shared
+ * state and stored within the DriverData of that struct. Currently
+ * there are no mesa callbacks for this.
+ */
+
+#define BM_MAX 16
+static struct bufmgr
+{
+ _glthread_Mutex mutex; /**< for thread safety */
+ int driFd;
+ int refcount;
+ struct _mesa_HashTable *hash;
+
+ unsigned buf_nr; /* for generating ids */
+ drmMMPool batchPool;
+ drmFence initFence;
+} bufmgr_pool[BM_MAX];
+
+static int nr_bms;
+
+#define LOCK(bm) _glthread_LOCK_MUTEX(bm->mutex)
+#define UNLOCK(bm) _glthread_UNLOCK_MUTEX(bm->mutex)
+
+static void
+bmError(int val, const char *file, const char *function, int line)
+{
+ _mesa_printf("Fatal video memory manager error \"%s\".\n"
+ "Check kernel logs or set the LIBGL_DEBUG\n"
+ "environment variable to \"verbose\" for more info.\n"
+ "Detected in file %s, line %d, function %s.\n",
+ strerror(-val), file, line, function);
+#ifndef NDEBUG
+ exit(-1);
+#else
+ abort();
+#endif
+}
+
+#define BM_CKFATAL(val) \
+ do{ \
+ int tstVal = (val); \
+ if (tstVal) \
+ bmError(tstVal, __FILE__, __FUNCTION__, __LINE__); \
+ } while(0);
+
+/***********************************************************************
+ * Public functions
+ */
+
+/* The initialization functions are skewed in the fake implementation.
+ * This call would be to attach to an existing manager, rather than to
+ * create a local one.
+ */
+
+struct bufmgr *
+bm_intel_Attach(struct intel_context *intel)
+{
+ GLuint i;
+
+ for (i = 0; i < nr_bms; i++)
+ if (bufmgr_pool[i].driFd == intel->driFd) {
+ bufmgr_pool[i].refcount++;
+ _mesa_printf("retrieive old bufmgr for fd %d\n",
+ bufmgr_pool[i].driFd);
+ return &bufmgr_pool[i];
+ }
+
+ if (nr_bms < BM_MAX) {
+ struct bufmgr *bm = &bufmgr_pool[nr_bms++];
+
+ _mesa_printf("create new bufmgr for fd %d\n", intel->driFd);
+ bm->driFd = intel->driFd;
+ bm->hash = _mesa_NewHashTable();
+ bm->refcount = 1;
+ _glthread_INIT_MUTEX(bm->mutex);
+
+ drmGetLock(bm->driFd, intel->hHWContext, 0);
+ BM_CKFATAL(drmMMAllocBufferPool(bm->driFd, mmPoolRing, 0,
+ DRM_MM_TT | DRM_MM_NO_EVICT |
+ DRM_MM_READ | DRM_MM_EXE |
+ BM_BATCHBUFFER, 1024 * 1024, 4096,
+ &bm->batchPool));
+
+
+ BM_CKFATAL(drmEmitFence(bm->driFd, 0, &bm->initFence));
+ drmUnlock(bm->driFd, intel->hHWContext);
+ return bm;
+ }
+
+ _mesa_printf("failed to create new bufmgr for fd %d\n", intel->driFd);
+ return NULL;
+}
+
+void
+bmGenBuffers(struct bufmgr *bm, unsigned n, unsigned *buffers, unsigned flags)
+{
+ LOCK(bm);
+ {
+ unsigned i;
+ unsigned bFlags =
+ (flags) ? flags : DRM_MM_TT | DRM_MM_VRAM | DRM_MM_SYSTEM;
+
+ for (i = 0; i < n; i++) {
+ drmMMBuf *buf = calloc(sizeof(*buf), 1);
+
+ BM_CKFATAL(drmMMInitBuffer(bm->driFd, bFlags, 12, buf));
+ buf->client_priv = ++bm->buf_nr;
+ buffers[i] = buf->client_priv;
+ _mesa_HashInsert(bm->hash, buffers[i], buf);
+ }
+ }
+ UNLOCK(bm);
+}
+
+void
+bmSetShared(struct bufmgr *bm, unsigned buffer, unsigned flags,
+ unsigned long offset, void *virtual)
+{
+ LOCK(bm);
+ {
+ drmMMBuf *buf = _mesa_HashLookup(bm->hash, buffer);
+
+ assert(buf);
+
+ buf->flags = DRM_MM_NO_EVICT | DRM_MM_SHARED
+ | DRM_MM_WRITE | DRM_MM_READ;
+ buf->flags |= flags & DRM_MM_MEMTYPE_MASK;
+ buf->offset = offset;
+ buf->virtual = virtual;
+ BM_CKFATAL(drmMMAllocBuffer(bm->driFd, 0, NULL, 0, buf));
+ }
+ UNLOCK(bm);
+}
+
+void
+bmDeleteBuffers(struct bufmgr *bm, unsigned n, unsigned *buffers)
+{
+ LOCK(bm);
+ {
+ unsigned i;
+
+ for (i = 0; i < n; i++) {
+ drmMMBuf *buf = _mesa_HashLookup(bm->hash, buffers[i]);
+
+ if (buf) {
+ BM_CKFATAL(drmMMFreeBuffer(bm->driFd, buf));
+
+ _mesa_HashRemove(bm->hash, buffers[i]);
+ }
+ }
+ }
+ UNLOCK(bm);
+}
+
+/* If buffer size changes, free and reallocate. Otherwise update in
+ * place.
+ */
+
+void
+bmBufferData(struct bufmgr *bm,
+ unsigned buffer, unsigned size, const void *data, unsigned flags)
+{
+ LOCK(bm);
+ {
+ drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer);
+
+ DBG("bmBufferData %d sz 0x%x data: %p\n", buffer, size, data);
+
+ assert(buf);
+ assert(!buf->mapped);
+ assert(size);
+
+ if (buf->flags & BM_BATCHBUFFER) {
+ BM_CKFATAL(drmMMFreeBuffer(bm->driFd, buf));
+ BM_CKFATAL(drmMMAllocBuffer
+ (bm->driFd, size, &bm->batchPool, 1, buf));
+ } else if (!(buf->flags & DRM_MM_SHARED)) {
+
+ if (buf->block && (buf->size < size || drmBufIsBusy(bm->driFd, buf))) {
+ BM_CKFATAL(drmMMFreeBuffer(bm->driFd, buf));
+ }
+ if (!buf->block) {
+ BM_CKFATAL(drmMMAllocBuffer(bm->driFd, size, NULL, 0, buf));
+ }
+
+ }
+
+ if (data != NULL) {
+
+ memcpy(drmMMMapBuffer(bm->driFd, buf), data, size);
+ drmMMUnmapBuffer(bm->driFd, buf);
+
+ }
+ }
+ UNLOCK(bm);
+}
+
+/* Update the buffer in place, in whatever space it is currently resident:
+ */
+void
+bmBufferSubData(struct bufmgr *bm,
+ unsigned buffer,
+ unsigned offset, unsigned size, const void *data)
+{
+ LOCK(bm);
+ {
+ drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer);
+
+ DBG("bmBufferSubdata %d offset 0x%x sz 0x%x\n", buffer, offset, size);
+
+ assert(buf);
+ drmBufWaitBusy(bm->driFd, buf);
+
+ if (size) {
+ memcpy((unsigned char *) drmMMMapBuffer(bm->driFd, buf) + offset,
+ data, size);
+ drmMMUnmapBuffer(bm->driFd, buf);
+ }
+ }
+ UNLOCK(bm);
+}
+
+/* Extract data from the buffer:
+ */
+void
+bmBufferGetSubData(struct bufmgr *bm,
+ unsigned buffer,
+ unsigned offset, unsigned size, void *data)
+{
+ LOCK(bm);
+ {
+ drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer);
+
+ DBG("bmBufferSubdata %d offset 0x%x sz 0x%x\n", buffer, offset, size);
+
+ assert(buf);
+ drmBufWaitBusy(bm->driFd, buf);
+
+ if (size) {
+ memcpy(data,
+ (unsigned char *) drmMMMapBuffer(bm->driFd, buf) + offset,
+ size);
+ drmMMUnmapBuffer(bm->driFd, buf);
+ }
+ }
+ UNLOCK(bm);
+}
+
+/* Return a pointer to whatever space the buffer is currently resident in:
+ */
+void *
+bmMapBuffer(struct bufmgr *bm, unsigned buffer, unsigned flags)
+{
+ void *retval;
+
+ LOCK(bm);
+ {
+ drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer);
+
+ DBG("bmMapBuffer %d\n", buffer);
+ DBG("Map: Block is 0x%x\n", &buf->block);
+
+ assert(buf);
+ /* assert(!buf->mapped); */
+ retval = drmMMMapBuffer(bm->driFd, buf);
+ }
+ UNLOCK(bm);
+
+ return retval;
+}
+
+void
+bmUnmapBuffer(struct bufmgr *bm, unsigned buffer)
+{
+ LOCK(bm);
+ {
+ drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer);
+
+ if (!buf)
+ goto out;
+
+ DBG("bmUnmapBuffer %d\n", buffer);
+
+ drmMMUnmapBuffer(bm->driFd, buf);
+ }
+ out:
+ UNLOCK(bm);
+}
+
+/* Build the list of buffers to validate. Note that the buffer list
+ * isn't a shared structure so we don't need mutexes when manipulating
+ * it.
+ *
+ * XXX: need refcounting for drmMMBuf structs so that they can't be
+ * deleted while on these lists.
+ */
+struct _drmMMBufList *
+bmNewBufferList(void)
+{
+ return drmMMInitListHead();
+}
+
+int
+bmAddBuffer(struct bufmgr *bm,
+ struct _drmMMBufList *list,
+ unsigned buffer,
+ unsigned flags,
+ unsigned *memtype_return, unsigned long *offset_return)
+{
+ drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer);
+
+ assert(buf);
+ return drmMMBufListAdd(list, buf, 0, flags, memtype_return, offset_return);
+}
+
+void
+bmFreeBufferList(struct _drmMMBufList *list)
+{
+ drmMMFreeBufList(list);
+}
+
+int
+bmScanBufferList(struct bufmgr *bm,
+ struct _drmMMBufList *list, unsigned buffer)
+{
+ drmMMBuf *buf = (drmMMBuf *) _mesa_HashLookup(bm->hash, buffer);
+
+ assert(buf);
+ return drmMMScanBufList(list, buf);
+}
+
+/* To be called prior to emitting commands to hardware which reference
+ * these buffers. The buffer_usage list provides information on where
+ * the buffers should be placed and whether their contents need to be
+ * preserved on copying. The offset and pool data elements are return
+ * values from this function telling the driver exactly where the
+ * buffers are currently located.
+ */
+
+int
+bmValidateBufferList(struct bufmgr *bm,
+ struct _drmMMBufList *list, unsigned flags)
+{
+ BM_CKFATAL(drmMMValidateBuffers(bm->driFd, list));
+ return 0;
+}
+
+/* After commands are emitted but before unlocking, this must be
+ * called so that the buffer manager can correctly age the buffers.
+ * The buffer manager keeps track of the list of validated buffers, so
+ * already knows what to apply the fence to.
+ *
+ * The buffer manager knows how to emit and test fences directly
+ * through the drm and without callbacks or whatever into the driver.
+ */
+unsigned
+bmFenceBufferList(struct bufmgr *bm, struct _drmMMBufList *list)
+{
+ drmFence fence;
+
+ BM_CKFATAL(drmMMFenceBuffers(bm->driFd, list));
+ BM_CKFATAL(drmEmitFence(bm->driFd, 0, &fence));
+
+ return fence.fenceSeq;
+}
+
+/* This functionality is used by the buffer manager, not really sure
+ * if we need to be exposing it in this way, probably libdrm will
+ * offer equivalent calls.
+ *
+ * For now they can stay, but will likely change/move before final:
+ */
+unsigned
+bmSetFence(struct bufmgr *bm)
+{
+ drmFence dFence;
+
+ BM_CKFATAL(drmEmitFence(bm->driFd, 0, &dFence));
+
+ return dFence.fenceSeq;
+}
+
+int
+bmTestFence(struct bufmgr *bm, unsigned fence)
+{
+ drmFence dFence;
+ int retired;
+
+ dFence.fenceType = 0;
+ dFence.fenceSeq = fence;
+ BM_CKFATAL(drmTestFence(bm->driFd, dFence, 0, &retired));
+ return retired;
+}
+
+void
+bmFinishFence(struct bufmgr *bm, unsigned fence)
+{
+ drmFence dFence;
+ dFence.fenceType = 0;
+ dFence.fenceSeq = fence;
+ BM_CKFATAL(drmWaitFence(bm->driFd, dFence));
+ bm->initFence = dFence;
+}
+
+unsigned
+bmInitFence(struct bufmgr *bm)
+{
+ return bm->initFence.fenceSeq;
+}
diff --git a/src/mesa/drivers/dri/i915/intel_tex_image.c b/src/mesa/drivers/dri/i915/intel_tex_image.c
new file mode 100644
index 00000000000..ea52ec360a2
--- /dev/null
+++ b/src/mesa/drivers/dri/i915/intel_tex_image.c
@@ -0,0 +1,560 @@
+
+#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_tex.h"
+#include "intel_ioctl.h"
+#include "intel_blit.h"
+
+
+/* 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;
+
+ 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);
+ intelObj->mt = intel_miptree_create( intel,
+ intelObj->base.Target,
+ intelImage->base.InternalFormat,
+ firstLevel,
+ lastLevel,
+ width,
+ height,
+ depth,
+ intelImage->base.TexFormat->TexelBytes,
+ intelImage->base.IsCompressed );
+
+ 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_blit( 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_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;
+ }
+}
+
+
+
+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 *intelObj = intel_buffer_object(unpack->BufferObj);
+ GLuint src_offset, src_stride;
+ GLuint dst_offset, dst_stride;
+
+ if (!intelObj ||
+ intel->ctx._ImageTransferState ||
+ unpack->SkipPixels ||
+ unpack->SkipRows) {
+ _mesa_printf("%s: failure 1\n", __FUNCTION__);
+ return GL_FALSE;
+ }
+
+ if (!check_pbo_blit(internalFormat, format, type, intelImage->base.TexFormat)) {
+ _mesa_printf("%s - bad format for blit\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 );
+
+ intelEmitCopyBlit( intel,
+ intelImage->mt->cpp,
+ src_stride, intel_bufferobj_buffer(intelObj), src_offset,
+ dst_stride, intelImage->mt->region->buffer, dst_offset,
+ 0,
+ 0,
+ 0,
+ 0,
+ width,
+ height );
+
+ intel_batchbuffer_flush( intel->batch );
+ UNLOCK_HARDWARE( intel );
+
+ 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)
+{
+ 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);
+
+ assert(texImage->TexFormat);
+
+ switch (dims) {
+ case 1:
+ texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D;
+ texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df;
+ break;
+ case 2:
+ texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D;
+ texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df;
+ break;
+ case 3:
+ texImage->FetchTexelc = texImage->TexFormat->FetchTexel3D;
+ texImage->FetchTexelf = texImage->TexFormat->FetchTexel3Df;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ 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) {
+ 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) {
+ if (INTEL_DEBUG & DEBUG_TEXTURE)
+ _mesa_printf("guess_and_alloc_mipmap_tree: failed\n");
+ }
+ }
+
+
+ if (intelObj->mt &&
+ intelObj->mt != intelImage->mt &&
+ intel_miptree_match_image(intelObj->mt, &intelImage->base,
+ intelImage->face, intelImage->level)) {
+
+ if (intelImage->mt) {
+ intel_miptree_release(intel, &intelImage->mt);
+ }
+
+ intel_miptree_reference(&intelImage->mt, intelObj->mt);
+ assert(intelImage->mt);
+ }
+
+ if (!intelImage->mt) {
+ if (INTEL_DEBUG & DEBUG_TEXTURE)
+ _mesa_printf("XXX: Image did not fit into tree - storing in local memory!\n");
+ }
+
+
+ /* Attempt to use the blitter for PBO image uploads:
+ *
+ * Next step would be texturing directly from PBO's.
+ */
+ if (dims <= 2 &&
+ intelImage->mt &&
+ intel_buffer_object(unpack->BufferObj)) {
+
+ _mesa_printf("trying pbo upload\n");
+
+ if (try_pbo_upload(intel, intelImage, unpack,
+ internalFormat,
+ width, height, format, type, pixels)) {
+ _mesa_printf("pbo upload succeeded\n");
+ return;
+ }
+
+ _mesa_printf("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:
+ */
+ pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, 1,
+ format, type,
+ pixels, unpack, "glTexImage");
+ if (!pixels)
+ return;
+
+
+ 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->InternalFormat,width);
+ assert(dims != 3);
+ }
+ else {
+ dstRowStride = postConvWidth * texelBytes;
+ sizeInBytes = depth * dstRowStride * postConvHeight;
+ }
+
+ texImage->Data = malloc(sizeInBytes);
+ }
+
+ if (INTEL_DEBUG & DEBUG_TEXTURE)
+ _mesa_printf("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 (!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 );
+}
+
+
+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 );
+}
+
+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 );
+}
+
+
+
+/**
+ * Need to map texture image into memory before copying image data,
+ * then unmap it.
+ */
+void intelGetTexImage( GLcontext *ctx, GLenum target, GLint level,
+ GLenum format, GLenum type, GLvoid *pixels,
+ 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);
+
+ /* 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);
+ }
+ 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);
+ }
+
+ _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;
+ }
+}
+