| /* |
| Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. |
| |
| The Weather Channel (TM) funded Tungsten Graphics to develop the |
| initial release of the Radeon 8500 driver under the XFree86 license. |
| This notice must be preserved. |
| |
| 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, sublicense, 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 NONINFRINGEMENT. |
| IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. |
| */ |
| |
| /* |
| * Authors: |
| * Keith Whitwell <keith@tungstengraphics.com> |
| */ |
| |
| #include "glheader.h" |
| #include "imports.h" |
| #include "macros.h" |
| #include "context.h" |
| #include "swrast/swrast.h" |
| #include "simple_list.h" |
| |
| #include "r200_context.h" |
| #include "r200_state.h" |
| #include "r200_ioctl.h" |
| #include "r200_tcl.h" |
| #include "r200_sanity.h" |
| #include "radeon_reg.h" |
| |
| static void print_state_atom( struct r200_state_atom *state ) |
| { |
| int i; |
| |
| fprintf(stderr, "emit %s/%d\n", state->name, state->cmd_size); |
| |
| if (0 & R200_DEBUG & DEBUG_VERBOSE) |
| for (i = 0 ; i < state->cmd_size ; i++) |
| fprintf(stderr, "\t%s[%d]: %x\n", state->name, i, state->cmd[i]); |
| |
| } |
| |
| /* The state atoms will be emitted in the order they appear in the atom list, |
| * so this step is important. |
| */ |
| void r200SetUpAtomList( r200ContextPtr rmesa ) |
| { |
| int i, mtu; |
| |
| mtu = rmesa->glCtx->Const.MaxTextureUnits; |
| |
| make_empty_list(&rmesa->hw.atomlist); |
| rmesa->hw.atomlist.name = "atom-list"; |
| |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.ctx ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.set ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.lin ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.msk ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.vpt ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.vtx ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.vap ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.vte ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.msc ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.cst ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.zbs ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.tcl ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.msl ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.tcg ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.grd ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.fog ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.tam ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.tf ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.atf ); |
| for (i = 0; i < mtu; ++i) |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.tex[i] ); |
| for (i = 0; i < mtu; ++i) |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.cube[i] ); |
| for (i = 0; i < 6; ++i) |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.pix[i] ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.afs[0] ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.afs[1] ); |
| for (i = 0; i < 8; ++i) |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.lit[i] ); |
| for (i = 0; i < 3 + mtu; ++i) |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.mat[i] ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.eye ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.glt ); |
| for (i = 0; i < 2; ++i) |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.mtl[i] ); |
| for (i = 0; i < 6; ++i) |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.ucp[i] ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.spr ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.ptp ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.prf ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.pvs ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.vpp[0] ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.vpp[1] ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.vpi[0] ); |
| insert_at_tail( &rmesa->hw.atomlist, &rmesa->hw.vpi[1] ); |
| } |
| |
| static void r200SaveHwState( r200ContextPtr rmesa ) |
| { |
| struct r200_state_atom *atom; |
| char * dest = rmesa->backup_store.cmd_buf; |
| |
| if (R200_DEBUG & DEBUG_STATE) |
| fprintf(stderr, "%s\n", __FUNCTION__); |
| |
| rmesa->backup_store.cmd_used = 0; |
| |
| foreach( atom, &rmesa->hw.atomlist ) { |
| if ( atom->check( rmesa->glCtx, atom->idx ) ) { |
| int size = atom->cmd_size * 4; |
| memcpy( dest, atom->cmd, size); |
| dest += size; |
| rmesa->backup_store.cmd_used += size; |
| if (R200_DEBUG & DEBUG_STATE) |
| print_state_atom( atom ); |
| } |
| } |
| |
| assert( rmesa->backup_store.cmd_used <= R200_CMD_BUF_SZ ); |
| if (R200_DEBUG & DEBUG_STATE) |
| fprintf(stderr, "Returning to r200EmitState\n"); |
| } |
| |
| void r200EmitState( r200ContextPtr rmesa ) |
| { |
| char *dest; |
| int mtu; |
| struct r200_state_atom *atom; |
| |
| if (R200_DEBUG & (DEBUG_STATE|DEBUG_PRIMS)) |
| fprintf(stderr, "%s\n", __FUNCTION__); |
| |
| if (rmesa->save_on_next_emit) { |
| r200SaveHwState(rmesa); |
| rmesa->save_on_next_emit = GL_FALSE; |
| } |
| |
| if (!rmesa->hw.is_dirty && !rmesa->hw.all_dirty) |
| return; |
| |
| mtu = rmesa->glCtx->Const.MaxTextureUnits; |
| |
| /* To avoid going across the entire set of states multiple times, just check |
| * for enough space for the case of emitting all state, and inline the |
| * r200AllocCmdBuf code here without all the checks. |
| */ |
| r200EnsureCmdBufSpace( rmesa, rmesa->hw.max_state_size ); |
| |
| /* we need to calculate dest after EnsureCmdBufSpace |
| as we may flush the buffer - airlied */ |
| dest = rmesa->store.cmd_buf + rmesa->store.cmd_used; |
| if (R200_DEBUG & DEBUG_STATE) { |
| foreach( atom, &rmesa->hw.atomlist ) { |
| if ( atom->dirty || rmesa->hw.all_dirty ) { |
| if ( atom->check( rmesa->glCtx, atom->idx ) ) |
| print_state_atom( atom ); |
| else |
| fprintf(stderr, "skip state %s\n", atom->name); |
| } |
| } |
| } |
| |
| foreach( atom, &rmesa->hw.atomlist ) { |
| if ( rmesa->hw.all_dirty ) |
| atom->dirty = GL_TRUE; |
| if ( atom->dirty ) { |
| if ( atom->check( rmesa->glCtx, atom->idx ) ) { |
| int size = atom->cmd_size * 4; |
| memcpy( dest, atom->cmd, size); |
| dest += size; |
| rmesa->store.cmd_used += size; |
| atom->dirty = GL_FALSE; |
| } |
| } |
| } |
| |
| assert( rmesa->store.cmd_used <= R200_CMD_BUF_SZ ); |
| |
| rmesa->hw.is_dirty = GL_FALSE; |
| rmesa->hw.all_dirty = GL_FALSE; |
| } |
| |
| /* Fire a section of the retained (indexed_verts) buffer as a regular |
| * primtive. |
| */ |
| void r200EmitVbufPrim( r200ContextPtr rmesa, |
| GLuint primitive, |
| GLuint vertex_nr ) |
| { |
| drm_radeon_cmd_header_t *cmd; |
| |
| assert(!(primitive & R200_VF_PRIM_WALK_IND)); |
| |
| r200EmitState( rmesa ); |
| |
| if (R200_DEBUG & (DEBUG_IOCTL|DEBUG_PRIMS)) |
| fprintf(stderr, "%s cmd_used/4: %d prim %x nr %d\n", __FUNCTION__, |
| rmesa->store.cmd_used/4, primitive, vertex_nr); |
| |
| cmd = (drm_radeon_cmd_header_t *)r200AllocCmdBuf( rmesa, VBUF_BUFSZ, |
| __FUNCTION__ ); |
| cmd[0].i = 0; |
| cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP; |
| cmd[1].i = R200_CP_CMD_3D_DRAW_VBUF_2; |
| cmd[2].i = (primitive | |
| R200_VF_PRIM_WALK_LIST | |
| R200_VF_COLOR_ORDER_RGBA | |
| (vertex_nr << R200_VF_VERTEX_NUMBER_SHIFT)); |
| } |
| |
| |
| void r200FlushElts( r200ContextPtr rmesa ) |
| { |
| int *cmd = (int *)(rmesa->store.cmd_buf + rmesa->store.elts_start); |
| int dwords; |
| int nr = (rmesa->store.cmd_used - (rmesa->store.elts_start + 12)) / 2; |
| |
| if (R200_DEBUG & (DEBUG_IOCTL|DEBUG_PRIMS)) |
| fprintf(stderr, "%s\n", __FUNCTION__); |
| |
| assert( rmesa->dma.flush == r200FlushElts ); |
| rmesa->dma.flush = NULL; |
| |
| /* Cope with odd number of elts: |
| */ |
| rmesa->store.cmd_used = (rmesa->store.cmd_used + 2) & ~2; |
| dwords = (rmesa->store.cmd_used - rmesa->store.elts_start) / 4; |
| |
| cmd[1] |= (dwords - 3) << 16; |
| cmd[2] |= nr << R200_VF_VERTEX_NUMBER_SHIFT; |
| |
| if (R200_DEBUG & DEBUG_SYNC) { |
| fprintf(stderr, "%s: Syncing\n", __FUNCTION__); |
| r200Finish( rmesa->glCtx ); |
| } |
| } |
| |
| |
| GLushort *r200AllocEltsOpenEnded( r200ContextPtr rmesa, |
| GLuint primitive, |
| GLuint min_nr ) |
| { |
| drm_radeon_cmd_header_t *cmd; |
| GLushort *retval; |
| |
| if (R200_DEBUG & DEBUG_IOCTL) |
| fprintf(stderr, "%s %d prim %x\n", __FUNCTION__, min_nr, primitive); |
| |
| assert((primitive & R200_VF_PRIM_WALK_IND)); |
| |
| r200EmitState( rmesa ); |
| |
| cmd = (drm_radeon_cmd_header_t *)r200AllocCmdBuf( rmesa, ELTS_BUFSZ(min_nr), |
| __FUNCTION__ ); |
| cmd[0].i = 0; |
| cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP; |
| cmd[1].i = R200_CP_CMD_3D_DRAW_INDX_2; |
| cmd[2].i = (primitive | |
| R200_VF_PRIM_WALK_IND | |
| R200_VF_COLOR_ORDER_RGBA); |
| |
| |
| retval = (GLushort *)(cmd+3); |
| |
| if (R200_DEBUG & DEBUG_PRIMS) |
| fprintf(stderr, "%s: header 0x%x prim %x \n", |
| __FUNCTION__, |
| cmd[1].i, primitive); |
| |
| assert(!rmesa->dma.flush); |
| rmesa->glCtx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; |
| rmesa->dma.flush = r200FlushElts; |
| |
| rmesa->store.elts_start = ((char *)cmd) - rmesa->store.cmd_buf; |
| |
| return retval; |
| } |
| |
| |
| |
| void r200EmitVertexAOS( r200ContextPtr rmesa, |
| GLuint vertex_size, |
| GLuint offset ) |
| { |
| drm_radeon_cmd_header_t *cmd; |
| |
| if (R200_DEBUG & (DEBUG_PRIMS|DEBUG_IOCTL)) |
| fprintf(stderr, "%s: vertex_size 0x%x offset 0x%x \n", |
| __FUNCTION__, vertex_size, offset); |
| |
| cmd = (drm_radeon_cmd_header_t *)r200AllocCmdBuf( rmesa, VERT_AOS_BUFSZ, |
| __FUNCTION__ ); |
| |
| cmd[0].header.cmd_type = RADEON_CMD_PACKET3; |
| cmd[1].i = R200_CP_CMD_3D_LOAD_VBPNTR | (2 << 16); |
| cmd[2].i = 1; |
| cmd[3].i = vertex_size | (vertex_size << 8); |
| cmd[4].i = offset; |
| } |
| |
| |
| void r200EmitAOS( r200ContextPtr rmesa, |
| struct r200_dma_region **component, |
| GLuint nr, |
| GLuint offset ) |
| { |
| drm_radeon_cmd_header_t *cmd; |
| int sz = AOS_BUFSZ(nr); |
| int i; |
| int *tmp; |
| |
| if (R200_DEBUG & DEBUG_IOCTL) |
| fprintf(stderr, "%s nr arrays: %d\n", __FUNCTION__, nr); |
| |
| cmd = (drm_radeon_cmd_header_t *)r200AllocCmdBuf( rmesa, sz, __FUNCTION__ ); |
| cmd[0].i = 0; |
| cmd[0].header.cmd_type = RADEON_CMD_PACKET3; |
| cmd[1].i = R200_CP_CMD_3D_LOAD_VBPNTR | (((sz / sizeof(int)) - 3) << 16); |
| cmd[2].i = nr; |
| tmp = &cmd[0].i; |
| cmd += 3; |
| |
| for (i = 0 ; i < nr ; i++) { |
| if (i & 1) { |
| cmd[0].i |= ((component[i]->aos_stride << 24) | |
| (component[i]->aos_size << 16)); |
| cmd[2].i = (component[i]->aos_start + |
| offset * component[i]->aos_stride * 4); |
| cmd += 3; |
| } |
| else { |
| cmd[0].i = ((component[i]->aos_stride << 8) | |
| (component[i]->aos_size << 0)); |
| cmd[1].i = (component[i]->aos_start + |
| offset * component[i]->aos_stride * 4); |
| } |
| } |
| |
| if (R200_DEBUG & DEBUG_VERTS) { |
| fprintf(stderr, "%s:\n", __FUNCTION__); |
| for (i = 0 ; i < sz ; i++) |
| fprintf(stderr, " %d: %x\n", i, tmp[i]); |
| } |
| } |
| |
| void r200EmitBlit( r200ContextPtr rmesa, |
| GLuint color_fmt, |
| GLuint src_pitch, |
| GLuint src_offset, |
| GLuint dst_pitch, |
| GLuint dst_offset, |
| GLint srcx, GLint srcy, |
| GLint dstx, GLint dsty, |
| GLuint w, GLuint h ) |
| { |
| drm_radeon_cmd_header_t *cmd; |
| |
| if (R200_DEBUG & DEBUG_IOCTL) |
| fprintf(stderr, "%s src %x/%x %d,%d dst: %x/%x %d,%d sz: %dx%d\n", |
| __FUNCTION__, |
| src_pitch, src_offset, srcx, srcy, |
| dst_pitch, dst_offset, dstx, dsty, |
| w, h); |
| |
| assert( (src_pitch & 63) == 0 ); |
| assert( (dst_pitch & 63) == 0 ); |
| assert( (src_offset & 1023) == 0 ); |
| assert( (dst_offset & 1023) == 0 ); |
| assert( w < (1<<16) ); |
| assert( h < (1<<16) ); |
| |
| cmd = (drm_radeon_cmd_header_t *)r200AllocCmdBuf( rmesa, 8 * sizeof(int), |
| __FUNCTION__ ); |
| |
| |
| cmd[0].header.cmd_type = RADEON_CMD_PACKET3; |
| cmd[1].i = R200_CP_CMD_BITBLT_MULTI | (5 << 16); |
| cmd[2].i = (RADEON_GMC_SRC_PITCH_OFFSET_CNTL | |
| RADEON_GMC_DST_PITCH_OFFSET_CNTL | |
| RADEON_GMC_BRUSH_NONE | |
| (color_fmt << 8) | |
| RADEON_GMC_SRC_DATATYPE_COLOR | |
| RADEON_ROP3_S | |
| RADEON_DP_SRC_SOURCE_MEMORY | |
| RADEON_GMC_CLR_CMP_CNTL_DIS | |
| RADEON_GMC_WR_MSK_DIS ); |
| |
| cmd[3].i = ((src_pitch/64)<<22) | (src_offset >> 10); |
| cmd[4].i = ((dst_pitch/64)<<22) | (dst_offset >> 10); |
| cmd[5].i = (srcx << 16) | srcy; |
| cmd[6].i = (dstx << 16) | dsty; /* dst */ |
| cmd[7].i = (w << 16) | h; |
| } |
| |
| |
| void r200EmitWait( r200ContextPtr rmesa, GLuint flags ) |
| { |
| drm_radeon_cmd_header_t *cmd; |
| |
| assert( !(flags & ~(RADEON_WAIT_2D|RADEON_WAIT_3D)) ); |
| |
| cmd = (drm_radeon_cmd_header_t *)r200AllocCmdBuf( rmesa, 1 * sizeof(int), |
| __FUNCTION__ ); |
| cmd[0].i = 0; |
| cmd[0].wait.cmd_type = RADEON_CMD_WAIT; |
| cmd[0].wait.flags = flags; |
| } |