/*
-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.
#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;
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;
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);
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;
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 */
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__);
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]);
r300ContextPtr r300 = R300_CONTEXT(ctx);
__DRIdrawablePrivate *dPriv = r300->radeon.dri.drawable;
int flags = 0;
+ int bits = 0;
int swapped;
if (RADEON_DEBUG & DEBUG_IOCTL)
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",
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);
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;