Port code from r200 that implements color blending. Seems to work.
[mesa.git] / src / mesa / drivers / dri / r300 / r300_ioctl.c
index a59b1efc9ea4216697537fe38476bd9d822eb2b5..b4b1aebc4d80693ce9db8ecd3ca3000d042f56f9 100644 (file)
@@ -1,5 +1,7 @@
 /*
-Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
+Copyright (C) The Weather Channel, Inc.  2002.
+Copyright (C) 2004 Nicolai Haehnle.
+All Rights Reserved.
 
 The Weather Channel (TM) funded Tungsten Graphics to develop the
 initial release of the Radeon 8500 driver under the XFree86 license.
@@ -53,7 +55,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "vblank.h"
 
 
-static void r300ClearColorBuffer(r300ContextPtr r300, int buffer)
+#define CLEARBUFFER_COLOR      0x1
+#define CLEARBUFFER_DEPTH      0x2
+
+static void r300ClearBuffer(r300ContextPtr r300, int flags, int buffer)
 {
        GLcontext* ctx = r300->radeon.glCtx;
        __DRIdrawablePrivate *dPriv = r300->radeon.dri.drawable;
@@ -62,8 +67,9 @@ static void r300ClearColorBuffer(r300ContextPtr r300, int buffer)
        drm_r300_cmd_header_t* cmd;
 
        if (RADEON_DEBUG & DEBUG_IOCTL)
-               fprintf(stderr, "%s: %s buffer\n", __FUNCTION__,
-                       buffer ? "back" : "front");
+               fprintf(stderr, "%s: %s buffer (%i,%i %ix%i)\n",
+                       __FUNCTION__, buffer ? "back" : "front",
+                       dPriv->x, dPriv->y, dPriv->w, dPriv->h);
 
        if (buffer) {
                cboffset = r300->radeon.radeonScreen->backOffset;
@@ -72,8 +78,29 @@ static void r300ClearColorBuffer(r300ContextPtr r300, int buffer)
                cboffset = r300->radeon.radeonScreen->frontOffset;
                cbpitch = r300->radeon.radeonScreen->frontPitch;
        }
-       cboffset = r300->radeon.radeonScreen->fbLocation;
 
+       cboffset += r300->radeon.radeonScreen->fbLocation;
+
+       R300_STATECHANGE(r300, vir[0]);
+       ((drm_r300_cmd_header_t*)r300->hw.vir[0].cmd)->unchecked_state.count = 1;
+       r300->hw.vir[0].cmd[1] = 0x21030003;
+
+       R300_STATECHANGE(r300, vir[1]);
+       ((drm_r300_cmd_header_t*)r300->hw.vir[1].cmd)->unchecked_state.count = 1;
+       r300->hw.vir[1].cmd[1] = 0xF688F688;
+
+       R300_STATECHANGE(r300, vic);
+       r300->hw.vic.cmd[R300_VIR_CNTL_0] = 0x00000001;
+       r300->hw.vic.cmd[R300_VIR_CNTL_1] = 0x00000405;
+       
+       R300_STATECHANGE(r300, vof);
+       r300->hw.vof.cmd[R300_VOF_CNTL_0] = R300_VAP_OUTPUT_VTX_FMT_0__POS_PRESENT
+                               | R300_VAP_OUTPUT_VTX_FMT_0__COLOR_PRESENT;
+       r300->hw.vof.cmd[R300_VOF_CNTL_1] = 0; /* no textures */
+       
+       R300_STATECHANGE(r300, txe);
+       r300->hw.txe.cmd[R300_TXE_ENABLE] = 0;
+       
        R300_STATECHANGE(r300, vpt);
        r300->hw.vpt.cmd[R300_VPT_XSCALE] = r300PackFloat32(1.0);
        r300->hw.vpt.cmd[R300_VPT_XOFFSET] = r300PackFloat32(dPriv->x);
@@ -82,6 +109,13 @@ static void r300ClearColorBuffer(r300ContextPtr r300, int buffer)
        r300->hw.vpt.cmd[R300_VPT_ZSCALE] = r300PackFloat32(1.0);
        r300->hw.vpt.cmd[R300_VPT_ZOFFSET] = r300PackFloat32(0.0);
 
+       R300_STATECHANGE(r300, at);
+       r300->hw.at.cmd[R300_AT_ALPHA_TEST] = 0;
+       
+       R300_STATECHANGE(r300, bld);
+       r300->hw.bld.cmd[R300_BLD_CBLEND] = 0;
+       r300->hw.bld.cmd[R300_BLD_ABLEND] = 0;
+       
        R300_STATECHANGE(r300, cb);
        r300->hw.cb.cmd[R300_CB_OFFSET] = cboffset;
        r300->hw.cb.cmd[R300_CB_PITCH] = cbpitch | R300_COLOR_UNKNOWN_22_23;
@@ -89,14 +123,35 @@ static void r300ClearColorBuffer(r300ContextPtr r300, int buffer)
        R300_STATECHANGE(r300, unk221C);
        r300->hw.unk221C.cmd[1] = R300_221C_CLEAR;
 
+       R300_STATECHANGE(r300, ps);
+       r300->hw.ps.cmd[R300_PS_POINTSIZE] =
+               ((dPriv->w * 6) << R300_POINTSIZE_X_SHIFT) |
+               ((dPriv->h * 6) << R300_POINTSIZE_Y_SHIFT);
+
        R300_STATECHANGE(r300, ri);
        for(i = 1; i <= 8; ++i)
                r300->hw.ri.cmd[i] = R300_RS_INTERP_USED;
 
+       R300_STATECHANGE(r300, rc);
+       /* The second constant is needed to get glxgears display anything .. */
+       r300->hw.rc.cmd[1] = R300_RS_CNTL_0_UNKNOWN_7 | R300_RS_CNTL_0_UNKNOWN_18;
+       r300->hw.rc.cmd[2] = 0;
+       
        R300_STATECHANGE(r300, rr);
        ((drm_r300_cmd_header_t*)r300->hw.rr.cmd)->unchecked_state.count = 1;
        r300->hw.rr.cmd[1] = 0x00004000;
 
+       R300_STATECHANGE(r300, cmk);
+       if (flags & CLEARBUFFER_COLOR) {
+               r300->hw.cmk.cmd[R300_CMK_COLORMASK] =
+                       (ctx->Color.ColorMask[BCOMP] ? R300_COLORMASK0_B : 0) |
+                       (ctx->Color.ColorMask[GCOMP] ? R300_COLORMASK0_G : 0) |
+                       (ctx->Color.ColorMask[RCOMP] ? R300_COLORMASK0_R : 0) |
+                       (ctx->Color.ColorMask[ACOMP] ? R300_COLORMASK0_A : 0);
+       } else {
+               r300->hw.cmk.cmd[R300_CMK_COLORMASK] = 0;
+       }
+
        R300_STATECHANGE(r300, fp);
        r300->hw.fp.cmd[R300_FP_CNTL0] = 0; /* 1 pass, no textures */
        r300->hw.fp.cmd[R300_FP_CNTL1] = 0; /* no temporaries */
@@ -145,6 +200,24 @@ static void r300ClearColorBuffer(r300ContextPtr r300, int buffer)
        r300->hw.vpi.cmd[7] = VP_ZERO();
        r300->hw.vpi.cmd[8] = 0;
 
+       R300_STATECHANGE(r300, zc);
+       if (flags & CLEARBUFFER_DEPTH) {
+               r300->hw.zc.cmd[R300_ZC_CNTL_0] = 0x6; // test and write
+               r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_ALWAYS;
+/*
+               R300_STATECHANGE(r300, zb);
+               r300->hw.zb.cmd[R300_ZB_OFFSET] =
+                       1024*4*300 +
+                       r300->radeon.radeonScreen->frontOffset +
+                       r300->radeon.radeonScreen->fbLocation;
+               r300->hw.zb.cmd[R300_ZB_PITCH] =
+                       r300->radeon.radeonScreen->depthPitch;
+*/
+       } else {
+               r300->hw.zc.cmd[R300_ZC_CNTL_0] = 0; // disable
+               r300->hw.zc.cmd[R300_ZC_CNTL_1] = 0;
+       }
+
        /* Make sure we have enough space */
        r300EnsureCmdBufSpace(r300, r300->hw.max_state_size + 9, __FUNCTION__);
 
@@ -153,9 +226,9 @@ static void r300ClearColorBuffer(r300ContextPtr r300, int buffer)
        cmd = (drm_r300_cmd_header_t*)r300AllocCmdBuf(r300, 9, __FUNCTION__);
        cmd[0].packet3.cmd_type = R300_CMD_PACKET3;
        cmd[0].packet3.packet = R300_CMD_PACKET3_CLEAR;
-       cmd[1].u = r300PackFloat32(dPriv->w / 2.0); /* my guess is as good as yours */
+       cmd[1].u = r300PackFloat32(dPriv->w / 2.0);
        cmd[2].u = r300PackFloat32(dPriv->h / 2.0);
-       cmd[3].u = r300PackFloat32(0.0);
+       cmd[3].u = r300PackFloat32(ctx->Depth.Clear);
        cmd[4].u = r300PackFloat32(1.0);
        cmd[5].u = r300PackFloat32(ctx->Color.ClearColor[0]);
        cmd[6].u = r300PackFloat32(ctx->Color.ClearColor[1]);
@@ -173,6 +246,7 @@ static void r300Clear(GLcontext * ctx, GLbitfield mask, GLboolean all,
        r300ContextPtr r300 = R300_CONTEXT(ctx);
        __DRIdrawablePrivate *dPriv = r300->radeon.dri.drawable;
        int flags = 0;
+       int bits = 0;
        int swapped;
 
        if (RADEON_DEBUG & DEBUG_IOCTL)
@@ -196,6 +270,11 @@ static void r300Clear(GLcontext * ctx, GLbitfield mask, GLboolean all,
                mask &= ~DD_BACK_LEFT_BIT;
        }
 
+       if (mask & DD_DEPTH_BIT) {
+               bits |= CLEARBUFFER_DEPTH;
+               mask &= ~DD_DEPTH_BIT;
+       }
+
        if (mask) {
                if (RADEON_DEBUG & DEBUG_FALLBACKS)
                        fprintf(stderr, "%s: swrast clear, mask: %x\n",
@@ -205,13 +284,20 @@ static void r300Clear(GLcontext * ctx, GLbitfield mask, GLboolean all,
 
        swapped = r300->radeon.doPageFlip && (r300->radeon.sarea->pfCurrentPage == 1);
 
-       if (flags & DD_FRONT_LEFT_BIT)
-               r300ClearColorBuffer(r300, swapped);
+       if (flags & DD_FRONT_LEFT_BIT) {
+               r300ClearBuffer(r300, bits | CLEARBUFFER_COLOR, swapped);
+               bits = 0;
+       }
+
+       if (flags & DD_BACK_LEFT_BIT) {
+               r300ClearBuffer(r300, bits | CLEARBUFFER_COLOR, swapped ^ 1);
+               bits = 0;
+       }
 
-       if (flags & DD_BACK_LEFT_BIT)
-               r300ClearColorBuffer(r300, swapped ^ 1);
+       if (bits)
+               r300ClearBuffer(r300, bits, 0);
 
-       /* Recalculate the hardware set. This could be done more efficiently,
+       /* Recalculate the hardware state. This could be done more efficiently,
         * but do keep it like this for now.
         */
        r300ResetHwState(r300);
@@ -228,6 +314,195 @@ void r300Flush(GLcontext * ctx)
                r300FlushCmdBuf(r300, __FUNCTION__);
 }
 
+void r300RefillCurrentDmaRegion(r300ContextPtr rmesa)
+{
+       struct r200_dma_buffer *dmabuf;
+       int fd = rmesa->radeon.dri.fd;
+       int index = 0;
+       int size = 0;
+       drmDMAReq dma;
+       int ret;
+
+       if (RADEON_DEBUG & (DEBUG_IOCTL | DEBUG_DMA))
+               fprintf(stderr, "%s\n", __FUNCTION__);
+
+       if (rmesa->dma.flush) {
+               rmesa->dma.flush(rmesa);
+       }
+
+       if (rmesa->dma.current.buf)
+               r300ReleaseDmaRegion(rmesa, &rmesa->dma.current, __FUNCTION__);
+
+       if (rmesa->dma.nr_released_bufs > 4)
+               r300FlushCmdBuf(rmesa, __FUNCTION__);
+
+       dma.context = rmesa->radeon.dri.hwContext;
+       dma.send_count = 0;
+       dma.send_list = NULL;
+       dma.send_sizes = NULL;
+       dma.flags = 0;
+       dma.request_count = 1;
+       dma.request_size = RADEON_BUFFER_SIZE;
+       dma.request_list = &index;
+       dma.request_sizes = &size;
+       dma.granted_count = 0;
+
+       LOCK_HARDWARE(&rmesa->radeon);  /* no need to validate */
+
+       while (1) {
+               ret = drmDMA(fd, &dma);
+               if (ret == 0)
+                       break;
+
+               if (rmesa->dma.nr_released_bufs) {
+                       r200FlushCmdBufLocked(rmesa, __FUNCTION__);
+               }
+
+               if (rmesa->radeon.do_usleeps) {
+                       UNLOCK_HARDWARE(&rmesa->radeon);
+                       DO_USLEEP(1);
+                       LOCK_HARDWARE(&rmesa->radeon);
+               }
+       }
+
+       UNLOCK_HARDWARE(&rmesa->radeon);
+
+       if (RADEON_DEBUG & DEBUG_DMA)
+               fprintf(stderr, "Allocated buffer %d\n", index);
+
+       dmabuf = CALLOC_STRUCT(r300_dma_buffer);
+       dmabuf->buf = &rmesa->radeon.radeonScreen->buffers->list[index];
+       dmabuf->refcount = 1;
+
+       rmesa->dma.current.buf = dmabuf;
+       rmesa->dma.current.address = dmabuf->buf->address;
+       rmesa->dma.current.end = dmabuf->buf->total;
+       rmesa->dma.current.start = 0;
+       rmesa->dma.current.ptr = 0;
+}
+
+void r300ReleaseDmaRegion(r300ContextPtr rmesa,
+                         struct r300_dma_region *region, const char *caller)
+{
+       if (RADEON_DEBUG & DEBUG_IOCTL)
+               fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);
+
+       if (!region->buf)
+               return;
+
+       if (rmesa->dma.flush)
+               rmesa->dma.flush(rmesa);
+
+       if (--region->buf->refcount == 0) {
+               drm_radeon_cmd_header_t *cmd;
+
+               if (RADEON_DEBUG & (DEBUG_IOCTL | DEBUG_DMA))
+                       fprintf(stderr, "%s -- DISCARD BUF %d\n", __FUNCTION__,
+                               region->buf->buf->idx);
+
+               cmd =
+                   (drm_radeon_cmd_header_t *) r300AllocCmdBuf(rmesa,
+                                                               sizeof(*cmd),
+                                                               __FUNCTION__);
+               cmd->dma.cmd_type = RADEON_CMD_DMA_DISCARD;
+               cmd->dma.buf_idx = region->buf->buf->idx;
+               FREE(region->buf);
+               rmesa->dma.nr_released_bufs++;
+       }
+
+       region->buf = 0;
+       region->start = 0;
+}
+
+/* Allocates a region from rmesa->dma.current.  If there isn't enough
+ * space in current, grab a new buffer (and discard what was left of current)
+ */
+void r300AllocDmaRegion(r300ContextPtr rmesa,
+                       struct r300_dma_region *region,
+                       int bytes, int alignment)
+{
+       if (RADEON_DEBUG & DEBUG_IOCTL)
+               fprintf(stderr, "%s %d\n", __FUNCTION__, bytes);
+
+       if (rmesa->dma.flush)
+               rmesa->dma.flush(rmesa);
+
+       if (region->buf)
+               r300ReleaseDmaRegion(rmesa, region, __FUNCTION__);
+
+       alignment--;
+       rmesa->dma.current.start = rmesa->dma.current.ptr =
+           (rmesa->dma.current.ptr + alignment) & ~alignment;
+
+       if (rmesa->dma.current.ptr + bytes > rmesa->dma.current.end)
+               r300RefillCurrentDmaRegion(rmesa);
+
+       region->start = rmesa->dma.current.start;
+       region->ptr = rmesa->dma.current.start;
+       region->end = rmesa->dma.current.start + bytes;
+       region->address = rmesa->dma.current.address;
+       region->buf = rmesa->dma.current.buf;
+       region->buf->refcount++;
+
+       rmesa->dma.current.ptr += bytes;        /* bug - if alignment > 7 */
+       rmesa->dma.current.start =
+           rmesa->dma.current.ptr = (rmesa->dma.current.ptr + 0x7) & ~0x7;
+
+       assert(rmesa->dma.current.ptr <= rmesa->dma.current.end);
+}
+
+/* Called via glXGetMemoryOffsetMESA() */
+GLuint r300GetMemoryOffsetMESA(__DRInativeDisplay * dpy, int scrn,
+                              const GLvoid * pointer)
+{
+       GET_CURRENT_CONTEXT(ctx);
+       r300ContextPtr rmesa;
+       GLuint card_offset;
+
+       if (!ctx || !(rmesa = R300_CONTEXT(ctx))) {
+               fprintf(stderr, "%s: no context\n", __FUNCTION__);
+               return ~0;
+       }
+
+       if (!r300IsGartMemory(rmesa, pointer, 0))
+               return ~0;
+
+       if (rmesa->radeon.dri.drmMinor < 6)
+               return ~0;
+
+       card_offset = r300GartOffsetFromVirtual(rmesa, pointer);
+
+       return card_offset - rmesa->radeon.radeonScreen->gart_base;
+}
+
+GLboolean r300IsGartMemory(r300ContextPtr rmesa, const GLvoid * pointer,
+                          GLint size)
+{
+       int offset =
+           (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
+       int valid = (size >= 0 && offset >= 0
+                    && offset + size < rmesa->radeon.radeonScreen->gartTextures.size);
+
+       if (RADEON_DEBUG & DEBUG_IOCTL)
+               fprintf(stderr, "r300IsGartMemory( %p ) : %d\n", pointer,
+                       valid);
+
+       return valid;
+}
+
+GLuint r300GartOffsetFromVirtual(r300ContextPtr rmesa, const GLvoid * pointer)
+{
+       int offset =
+           (char *)pointer - (char *)rmesa->radeon.radeonScreen->gartTextures.map;
+
+       fprintf(stderr, "offset=%08x\n", offset);
+
+       if (offset < 0 || offset > rmesa->radeon.radeonScreen->gartTextures.size)
+               return ~0;
+       else
+               return rmesa->radeon.radeonScreen->gart_texture_offset + offset;
+}
+
 void r300InitIoctlFuncs(struct dd_function_table *functions)
 {
        functions->Clear = r300Clear;