diff options
Diffstat (limited to 'backends/ps2/DmaPipe.cpp')
| -rw-r--r-- | backends/ps2/DmaPipe.cpp | 307 | 
1 files changed, 307 insertions, 0 deletions
diff --git a/backends/ps2/DmaPipe.cpp b/backends/ps2/DmaPipe.cpp new file mode 100644 index 0000000000..6390b66b7a --- /dev/null +++ b/backends/ps2/DmaPipe.cpp @@ -0,0 +1,307 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2004 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. + * + * $Header$ + * + */ + +// minimalistic gfx pipe implementation based on Vzzrzzn's GfxPipe. + +#include <kernel.h> +#include <malloc.h> +#include "DmaPipe.h" +#include "GsDefs.h" + +class SinglePipe { +public: +	SinglePipe(uint64 *buf, uint32 size); +	uint32 spaceLeft(void); +	void flush(void); +	void setGifRegListTag(uint8 numRegs, uint64 list); +	void setGifLoopTag(uint16 nLoop); +	void setReg(uint64 reg, uint64 value); +	void setListReg(uint64 value1, uint64 value2); +	void appendChain(uint64 dmaTag); +	void init(void); +	uint64 *_chainHead; +private: +	uint64 *_bufPos; +	uint16 *_chainSize; +	uint64 *_buf; +	uint32 _size; +}; + +DmaPipe::DmaPipe(uint32 size) { +	size &= ~0x1F; +	_buf = (uint64*)memalign(64, size); +	_curPipe = 0; +    _pipes[0] = new SinglePipe(_buf, size >> 4); +	_pipes[1] = new SinglePipe(_buf + (size >> 4), size >> 4); + +	// reset DMAC Channel 2 +	D2_CHCR = 0; +	D2_TADR = 0; +	D2_MADR = 0; +	D2_ASR1 = 0; +	D2_ASR0 = 0; +	D_STAT  = 0xFF1F; +	D_CTRL  = 0; +	D_PCR   = 0; +	D_SQWC  = 0; +	D_RBOR  = 0; +	D_RBSR  = 0; +	D_CTRL  = 1; +	if (!(D_STAT & CIM2)) // channel 2 interrupts enabled? +		D_STAT = CIM2;	  // enable them +	if (D_STAT & CIS2)	  // is there an old interrupt we have to acknowledge? +		D_STAT = CIS2;	  // do so... +	SifSetDChain(); +} + +void DmaPipe::uploadTex(uint32 dest, uint16 bufWidth, uint16 destOfsX, uint16 destOfsY, uint8 pixelFmt, const void *src, uint16 width, uint16 height) { + +	checkSpace(5); +	*(_pipes[_curPipe]->_chainHead) &= 0xffffffff8fffffff; // change last chain tag id, from 'end' to 'cnt' +	*(_pipes[_curPipe]->_chainHead) |= (1 << 28); +	_pipes[_curPipe]->setGifLoopTag(4); +	_pipes[_curPipe]->setReg(GPR_BITBLTBUF, GS_SET_DEST_BLTBUF((dest/256) & 0x3fff, (bufWidth/64) & 0x3f, pixelFmt & 0x3f)); +	_pipes[_curPipe]->setReg(	GPR_TRXPOS, GS_SET_DEST_TRXPOS(destOfsX, destOfsY)); +	_pipes[_curPipe]->setReg(   GPR_TRXREG, GS_SET_TRXREG(width, height)); +	_pipes[_curPipe]->setReg(   GPR_TRXDIR, 0); +	 +	checkSpace(15); +	uint32 numq = width * height; +	switch (pixelFmt) { +		case GS_PSMCT32: +			numq = (numq + 3) >> 2; break; +		case GS_PSMCT24: +			numq = (numq + 2) / 3; break; +		case GS_PSMCT16: +		case GS_PSMCT16S: +			numq = (numq + 7) >> 3; break; +		case GS_PSMT8: +		case GS_PSMT8H: +			numq = (numq + 15) >> 4; break; +		case GS_PSMT4HL: +		case GS_PSMT4HH: +		case GS_PSMT4: +			numq = (numq + 31) >> 5; break; +		default: +			numq = 0; +	} +	uint64 texSrc = (uint32)src & 0x7fffffff; +	while (numq) { +		uint64 sendQuads = (numq <= 0x7FF0) ? numq : 0x7FF0; +		_pipes[_curPipe]->appendChain((1 << 28) | 1); +		_pipes[_curPipe]->appendChain(0x0800000000000000 + sendQuads); // IMAGE mode giftag. Flg = 10b, nloop = currq +		_pipes[_curPipe]->appendChain((texSrc << 32) | 0x0000000030000000 | sendQuads); // set up dma tag for image transfer. next = tex addr, id = 11b, qwc = numq +		numq -= sendQuads; +		texSrc += sendQuads * 16; +	} +	_pipes[_curPipe]->appendChain(0x0000000070000000); // next dma tag +	_pipes[_curPipe]->setGifLoopTag(1); +	_pipes[_curPipe]->setReg(GPR_TEXFLUSH, 1); +} + +void DmaPipe::setTex(uint32 tex, uint32 texBufWidth, uint8 texPowW, uint8 texPowH, uint8 texPixFmt, uint32 clut, uint8 csm, uint32 clutBufWidth, uint32 clutPixFmt) { +	checkSpace(7); +	_pipes[_curPipe]->setGifLoopTag(6); +	_pipes[_curPipe]->setReg( GPR_TEXCLUT, 256 / 64); +	_pipes[_curPipe]->setReg(GPR_TEXFLUSH, 0); +	_pipes[_curPipe]->setReg(    GPR_TEXA, GS_SET_TEXA(128, 1, 0)); +	_pipes[_curPipe]->setReg(  GPR_TEX1_1, GS_SET_TEX1(0, 0, FILTER_LINEAR, FILTER_LINEAR, 0, 0, 0)); +	_pipes[_curPipe]->setReg(  GPR_TEX0_1, GS_SET_TEX0(tex / 256, texBufWidth / 64, texPixFmt, texPowW, texPowH, 1, 0, clut / 256, clutBufWidth / 64, csm, 0, 1)); +	_pipes[_curPipe]->setReg( GPR_CLAMP_1, 0); +} + +void DmaPipe::textureRect(uint16 x1, uint16 y1, uint16 u1, uint16 v1, uint16 x2, uint16 y2, uint16 u2, uint16 v2, uint16 z, uint32 colour) { +	checkSpace(4); +	_pipes[_curPipe]->setGifRegListTag( 6, 0xffffffffff535310); +	_pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_SPRITE, 0, 1, 0, 1, 0, 1, 0, 0), +								  GS_SET_COLQ(colour)); +	_pipes[_curPipe]->setListReg( GS_SET_UV(u1, v1), +								  GS_SET_XYZ(x1, y1, z)); +	_pipes[_curPipe]->setListReg( GS_SET_UV(u2, v2), +								  GS_SET_XYZ(x2, y2, z)); +} + +void DmaPipe::textureRect(const GsVertex *p1, const GsVertex *p2, const GsVertex *p3, const GsVertex *p4, const TexVertex *t1, const TexVertex *t2, const TexVertex *t3, const TexVertex *t4, uint32 rgba) { +	checkSpace(6); +	_pipes[_curPipe]->setGifRegListTag(10, 0xffffff5353535310); + +	_pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_TRIANGLESTRIP, 0, 1, 0, 1, 0, 1, 0, 0), +								  GS_SET_COLQ(rgba)); +	_pipes[_curPipe]->setListReg( GS_SET_UV(t1->u, t1->v), +								  GS_SET_XYZ(p1->x, p1->y, p1->z)); +	_pipes[_curPipe]->setListReg( GS_SET_UV(t2->u, t2->v), +								  GS_SET_XYZ(p2->x, p2->y, p2->z)); +	_pipes[_curPipe]->setListReg( GS_SET_UV(t3->u, t3->v), +								  GS_SET_XYZ(p3->x, p3->y, p3->z)); +	_pipes[_curPipe]->setListReg( GS_SET_UV(t4->u, t4->v), +								  GS_SET_XYZ(p4->x, p4->y, p4->z)); +} + +/*void DmaPipe::flatRect(uint16 x1, uint16 y1, uint16 x2, uint16 y2, uint16 x3, uint16 y3, uint16 x4, uint16 y4, uint16 z, uint32 rgba) { +	checkSpace(4); +	_pipes[_curPipe]->setGifRegListTag( 6, 0xffffffffff555510); +	//_pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_TRIANGLESTRIP, 0, 0, 0, 1, 0, 0, 0, 0), +	_pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_TRIANGLESTRIP, 0, 0, 0, 0, 0, 0, 0, 0), +								  GS_SET_COLQ(rgba)); +	_pipes[_curPipe]->setListReg( GS_SET_XYZ(x2, y2, z), +								  GS_SET_XYZ(x1, y1, z)); +	_pipes[_curPipe]->setListReg( GS_SET_XYZ(x3, y3, z), +								  GS_SET_XYZ(x4, y4, z)); +}*/ + +void DmaPipe::flatRect(const GsVertex *p1, const GsVertex *p2, const GsVertex *p3, const GsVertex *p4, uint32 rgba) { +	checkSpace(4); +	_pipes[_curPipe]->setGifRegListTag( 6, 0xffffffffff555510); +	_pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_TRIANGLESTRIP, 0, 0, 0, 0, 0, 0, 0, 0), +								  GS_SET_COLQ(rgba)); +	_pipes[_curPipe]->setListReg( GS_SET_XYZ(p1->x, p1->y, p1->z), +								  GS_SET_XYZ(p2->x, p2->y, p2->z)); +	_pipes[_curPipe]->setListReg( GS_SET_XYZ(p3->x, p3->y, p3->z), +								  GS_SET_XYZ(p4->x, p4->y, p4->z)); +} + +void DmaPipe::flatRect(const GsVertex *p1, const GsVertex *p2, uint32 rgba) { +	checkSpace(3); +	_pipes[_curPipe]->setGifRegListTag( 4, 0xffffffffffff5510); +	_pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_SPRITE, 0, 0, 0, 0, 0, 0, 0, 0), +								  GS_SET_COLQ(rgba)); +	_pipes[_curPipe]->setListReg( GS_SET_XYZ(p1->x, p1->y, p1->z), +								  GS_SET_XYZ(p2->x, p2->y, p2->z)); +} + +void DmaPipe::setOrigin(uint16 x, uint16 y) { +	checkSpace(2); +	_pipes[_curPipe]->setGifLoopTag(1); +	_pipes[_curPipe]->setReg( GPR_XYOFFSET_1, GS_SET_XYOFFSET(x, y)); +} + +void DmaPipe::setAlphaBlend(AlphaBlendColor a, AlphaBlendColor b, AlphaBlendAlpha c, AlphaBlendColor d, uint8 fix) { +	checkSpace(2); +	_pipes[_curPipe]->setGifLoopTag(1); +	_pipes[_curPipe]->setReg(GPR_ALPHA_1, GS_SET_ALPHA(a, b, c, d, fix)); +} + +void DmaPipe::setConfig(uint8 prModeCont, uint8 dither, uint8 colClamp) { +	checkSpace(9); +	_pipes[_curPipe]->setGifLoopTag(8); + +	// set some defaults +	// alpha blending formula: (A-B) * C + D +		// set: A = source pixel, b = 0, C = source alpha, D = destination pixel, fix = don't care +	//_pipes[_curPipe]->setReg(GPR_ALPHA_1, GS_SET_ALPHA(SOURCE_COLOR, ZERO_COLOR, SOURCE_ALPHA, DEST_COLOR, 0)); +	// set: A = source pixel, b = dest pixel, C = source alpha, D = destination pixel, fix = don't care +	//_pipes[_curPipe]->setReg( GPR_ALPHA_1, GS_SET_ALPHA(SOURCE_COLOR, DEST_COLOR, SOURCE_ALPHA, DEST_COLOR, 0x7F)); + +	_pipes[_curPipe]->setReg(GPR_ALPHA_1, GS_SET_ALPHA(DEST_COLOR, ZERO_COLOR, SOURCE_ALPHA, SOURCE_COLOR, 0)); +	_pipes[_curPipe]->setReg(   GPR_PRIM, 0); +	_pipes[_curPipe]->setReg(   GPR_PABE, 0); // alpha blending off +	_pipes[_curPipe]->setReg( GPR_TEST_1, GS_SET_TEST(0, 0, 0, 0, 0, 0, 1, 1)); // ztest off +	_pipes[_curPipe]->setReg( GPR_ZBUF_1, (uint64)1 << 32); // zbuffer off + +	_pipes[_curPipe]->setReg( GPR_PRMODECONT, prModeCont & 1); +	_pipes[_curPipe]->setReg( GPR_DTHE, dither & 1); +	_pipes[_curPipe]->setReg( GPR_COLCLAMP, colClamp & 1); +} + +void DmaPipe::setScissorRect(uint64 x1, uint64 y1, uint64 x2, uint64 y2) { +	checkSpace(2); +	_pipes[_curPipe]->setGifLoopTag(1); +	_pipes[_curPipe]->setReg( GPR_SCISSOR_1, GS_SET_SCISSOR(x1, x2, y1, y2)); +} + +void DmaPipe::setDrawBuffer(uint64 base, uint64 width, uint8 pixelFmt, uint64 mask) { +	checkSpace(2); +	_pipes[_curPipe]->setGifLoopTag(1); +	_pipes[_curPipe]->setReg( GPR_FRAME_1, GS_SET_FRAME(base / 8192, width / 64, pixelFmt, mask)); +} + +void DmaPipe::checkSpace(uint32 needed) { +	if (_pipes[_curPipe]->spaceLeft() < (needed << 1)) +		flush(); +} + +void DmaPipe::waitForDma(void) { +	while (D2_CHCR & 0x100) {} +} + +void DmaPipe::flush(void) { +	waitForDma(); +	FlushCache(0); +	_pipes[_curPipe]->flush(); +	_curPipe ^= 1; +	_pipes[_curPipe]->init(); +} + +SinglePipe::SinglePipe(uint64 *buf, uint32 size) { +	_buf = buf; +	_size = size; +	init(); +} + +void SinglePipe::flush(void) { +	D2_TADR = (uint32)_buf; +	D2_QWC  = 0; +	D2_CHCR |= 0x185; +} + +void SinglePipe::init(void) { +	_buf[0] = 0x0000000070000000; +	_buf[1] = 0; +	_chainHead = _buf; +	_chainSize = (uint16*)_chainHead; +	_bufPos = _buf + 2; +} + +uint32 SinglePipe::spaceLeft(void) { +	return (_size - (_bufPos - _buf)); +} + +void SinglePipe::appendChain(uint64 dmaTag) { +	_chainHead = _bufPos; +	_chainHead[0] = dmaTag; +	_chainHead[1] = 0; +	_chainSize = (uint16*)_chainHead; +	_bufPos += 2; +} + +void SinglePipe::setReg(uint64 reg, uint64 value) { +	*_bufPos++ = value; +	*_bufPos++ = reg; +    (*_chainSize)++; +} + +void SinglePipe::setListReg(uint64 value1, uint64 value2) { +	*_bufPos++ = value1; +	*_bufPos++ = value2; +	(*_chainSize)++; +} + +void SinglePipe::setGifRegListTag(uint8 numRegs, uint64 list) { +	*_bufPos++ = GIF_SET_TAG(1, 1, 0, 0, 1, 0) | ((uint64)numRegs << 60); +	*_bufPos++ = list; +	(*_chainSize)++; +} + +void SinglePipe::setGifLoopTag(uint16 nLoop) { +	*_bufPos++ = GIF_SET_TAG(0, 1, 0, 0, 0, 1) | nLoop; +	*_bufPos++ = 0xfffffffffffffffe; +	(*_chainSize)++; +}  | 
