diff --git a/src/gl/wdgl.cpp b/src/gl/wdgl.cpp index 123c7d5..cd4def3 100644 --- a/src/gl/wdgl.cpp +++ b/src/gl/wdgl.cpp @@ -820,7 +820,7 @@ Texture::upload(void) switch(r->format & 0xF00){ case Raster::C8888: glTexImage2D(GL_TEXTURE_2D, 0, 4, r->width, r->height, - 0, GL_RGBA, GL_UNSIGNED_BYTE, r->texels); + 0, GL_RGBA, GL_UNSIGNED_BYTE, r->pixels); break; default: printf("unsupported raster format: %x\n", r->format); diff --git a/src/image.cpp b/src/image.cpp index 45599b1..e32606e 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -918,7 +918,7 @@ Raster::create(int32 width, int32 height, int32 depth, int32 format, int32 platf raster->width = width; raster->height = height; raster->depth = depth; - raster->texels = raster->palette = nil; + raster->pixels = raster->palette = nil; s_plglist.construct(raster); // printf("%d %d %d %d\n", raster->type, raster->width, raster->height, raster->depth); diff --git a/src/ps2/ps2raster.cpp b/src/ps2/ps2raster.cpp index 2a9e9fb..292e7a8 100644 --- a/src/ps2/ps2raster.cpp +++ b/src/ps2/ps2raster.cpp @@ -42,7 +42,7 @@ enum Psm { // i don't really understand this, stolen from RW static void -ps2MinSize(int32 psm, int32 flags, int32 *minw, int32 *minh) +transferMinSize(int32 psm, int32 flags, int32 *minw, int32 *minh) { *minh = 1; switch(psm){ @@ -66,16 +66,17 @@ ps2MinSize(int32 psm, int32 flags, int32 *minw, int32 *minh) *minw = 8; // everything else break; } - if(flags & 0x2 && psm == 0x13){ // PSMT8 + if(flags & 0x2 && psm == PSMT8){ *minw = 16; *minh = 4; } - if(flags & 0x4 && psm == 0x14){ // PSMT4 + if(flags & 0x4 && psm == PSMT4){ *minw = 32; *minh = 4; } } +#define ALIGN(x,a) ((x) + (a)-1 & ~((a)-1)) #define ALIGN16(x) ((x) + 0xF & ~0xF) #define ALIGN64(x) ((x) + 0x3F & ~0x3F) #define NSIZE(dim,pagedim) (((dim) + (pagedim)-1)/(pagedim)) @@ -310,56 +311,73 @@ getRasterFormat(Raster *raster) */ static uint8 blockmap_PSMCT32[32] = { - 0, 1, 4, 5, 16, 17, 20, 21, - 2, 3, 6, 7, 18, 19, 22, 23, - 8, 9, 12, 13, 24, 25, 28, 29, - 10, 11, 14, 15, 26, 27, 30, 31, + 0, 1, 4, 5, 16, 17, 20, 21, + 2, 3, 6, 7, 18, 19, 22, 23, + 8, 9, 12, 13, 24, 25, 28, 29, + 10, 11, 14, 15, 26, 27, 30, 31, }; static uint8 blockmap_PSMCT16[32] = { - 0, 2, 8, 10, - 1, 3, 9, 11, - 4, 6, 12, 14, - 5, 7, 13, 15, - 16, 18, 24, 26, - 17, 19, 25, 27, - 20, 22, 28, 30, - 21, 23, 29, 31, + 0, 2, 8, 10, + 1, 3, 9, 11, + 4, 6, 12, 14, + 5, 7, 13, 15, + 16, 18, 24, 26, + 17, 19, 25, 27, + 20, 22, 28, 30, + 21, 23, 29, 31, }; static uint8 blockmap_PSMCT16S[32] = { - 0, 2, 16, 18, - 1, 3, 17, 19, - 8, 10, 24, 26, - 9, 11, 25, 27, - 4, 6, 20, 22, - 5, 7, 21, 23, - 12, 14, 28, 30, - 13, 15, 29, 31, + 0, 2, 16, 18, + 1, 3, 17, 19, + 8, 10, 24, 26, + 9, 11, 25, 27, + 4, 6, 20, 22, + 5, 7, 21, 23, + 12, 14, 28, 30, + 13, 15, 29, 31, }; static uint8 blockmap_PSMZ32[32] = { - 24, 25, 28, 29, 8, 9, 12, 13, - 26, 27, 30, 31, 10, 11, 14, 15, - 16, 17, 20, 21, 0, 1, 4, 5, - 18, 19, 22, 23, 2, 3, 6, 7, + 24, 25, 28, 29, 8, 9, 12, 13, + 26, 27, 30, 31, 10, 11, 14, 15, + 16, 17, 20, 21, 0, 1, 4, 5, + 18, 19, 22, 23, 2, 3, 6, 7, }; static uint8 blockmap_PSMZ16[32] = { - 24, 26, 16, 18, - 25, 27, 17, 19, - 28, 30, 20, 22, - 29, 31, 21, 23, - 8, 10, 0, 2, - 9, 11, 1, 3, - 12, 14, 4, 6, - 13, 15, 5, 7, + 24, 26, 16, 18, + 25, 27, 17, 19, + 28, 30, 20, 22, + 29, 31, 21, 23, + 8, 10, 0, 2, + 9, 11, 1, 3, + 12, 14, 4, 6, + 13, 15, 5, 7, }; static uint8 blockmap_PSMZ16S[32] = { - 24, 26, 8, 10, - 25, 27, 9, 11, - 16, 18, 0, 2, - 17, 19, 1, 3, - 28, 30, 12, 14, - 29, 31, 13, 15, - 20, 22, 4, 6, - 21, 23, 5, 7, + 24, 26, 8, 10, + 25, 27, 9, 11, + 16, 18, 0, 2, + 17, 19, 1, 3, + 28, 30, 12, 14, + 29, 31, 13, 15, + 20, 22, 4, 6, + 21, 23, 5, 7, +}; + +static uint8 blockmaprev_PSMCT32[32] = { + 0, 1, 8, 9, 2, 3, 10, 11, + 16, 17, 24, 25, 18, 19, 26, 27, + 4, 5, 12, 13, 6, 7, 14, 15, + 20, 21, 28, 29, 22, 23, 30, 31, +}; +static uint8 blockmaprev_PSMCT16[32] = { + 0, 4, 1, 5, + 8, 12, 9, 13, + 2, 6, 3, 7, + 10, 14, 11, 15, + 16, 20, 17, 21, + 24, 28, 25, 29, + 18, 22, 19, 23, + 26, 30, 27, 31, }; /* Suffixes used: @@ -603,7 +621,7 @@ calcOffsets(int32 width_Px, int32 height_Px, int32 psm, uint64 *bufferBase_B, ui uint32 bufpage_B = bufferPage_B[0]; uint32 pixeloff; for(n = 0; n < nlevels; n++){ - // Calculate TRXPOS register + // Calculate TRXPOS register (DSAX and DSAY, shifted up later) // Start of buffer on current page (x in pixels, y in blocks) pixeloff = (bufferBase_B[n] - bufpage_B) * blockWidth_Px; // y coordinate of first pixel @@ -612,7 +630,7 @@ calcOffsets(int32 width_Px, int32 height_Px, int32 psm, uint64 *bufferBase_B, ui xoff_Px = pixeloff % (bufwidth_W*64); if(bufferWidth_W[n] == bufwidth_W && // Not quite sure what's the meaning of this. - // SSAY is 11 bits, but so is SSAX and it is not checked? + // DSAY is 11 bits, but so is DSAX and it is not checked? yoff_Px < 0x800){ trxpos[n] = yoff_Px<<16 | xoff_Px; }else{ @@ -765,7 +783,7 @@ createTexRaster(Raster *raster) uint64 bufferWidth[7]; // in number of pixels / 64 uint64 bufferBase[7]; // block address - uint32 trxpos[8]; + uint32 trxpos_hi[8]; int32 width, height, depth; int32 pageWidth, pageHeight; int32 paletteWidth, paletteHeight, paletteDepth; @@ -926,7 +944,7 @@ createTexRaster(Raster *raster) // Do the real work here uint32 paletteBase; uint32 totalSize; - calcOffsets(width, height, psm, bufferBase, bufferWidth, trxpos, &totalSize, &paletteBase); + calcOffsets(width, height, psm, bufferBase, bufferWidth, trxpos_hi, &totalSize, &paletteBase); ras->paletteSize = paletteWidth*paletteHeight*paletteDepth; ras->miptbp1 = @@ -1007,35 +1025,63 @@ createTexRaster(Raster *raster) (raster->width*raster->height*raster->depth/8/0x10) >= 0x7FFF){ ras->dataSize = ras->paletteSize+ras->pixelSize; uint8 *data = (uint8*)mallocalign(ras->dataSize, 0x40); + assert(data); ras->data = data; - raster->texels = data; + raster->pixels = data; if(ras->paletteSize) raster->palette = data + ras->pixelSize; if(raster->depth == 8) ras->flags |= Ps2Raster::SWIZZLED8; }else{ - ras->flags |= Ps2Raster::HASGIFPACKETS; - //int32 cpsm = ras->tex0[1]>>19 & 0x3F; + ras->flags |= Ps2Raster::NEWSTYLE; + uint64 paltrxpos = 0; + uint32 dsax = trxpos_hi[numLevels-1] & 0x7FF; + uint32 dsay = trxpos_hi[numLevels-1]>>16 & 0x7FF; + // Set swizzle flags and calculate TRXPOS for palette if(psm == PSMT8){ ras->flags |= Ps2Raster::SWIZZLED8; - // TODO: crazy stuff + if(cpsm == PSMCT32 && bufferWidth[numLevels-1] == 2){ // one page + // unswizzle the starting block of the last buffer and palette + uint32 bufbase_B = bufferBase[numLevels-1]&~0x1F | (uint64)blockmaprev_PSMCT32[bufferBase[numLevels-1]&0x1F]; + uint32 palbase_B = ras->paletteBase&~0x1F | (uint64)blockmaprev_PSMCT32[ras->paletteBase&0x1F]; + // find start of page of last level (16,16 are PSMT8 block dimensions) + uint32 page_B = bufbase_B - 8*(dsay/16) - dsax/16; + // find palette DSAX/Y (in PSMCT32!) + dsay = (palbase_B - page_B)/8 * 8; // block/blocksPerPageX * blockHeight + dsax = (palbase_B - page_B)*8 % 64; // block*blockWidth % pageWidth + if(dsay < 0x800) + paltrxpos = dsay<<16 | dsax; + } } if(psm == PSMT4){ - // swizzle flag probably depends on version :/ + // swizzle flag depends on version :/ // but which version? .... - if(rw::version > 0x31000) + if(rw::version > 0x31000){ ras->flags |= Ps2Raster::SWIZZLED4; - // TODO: crazy stuff + // Where can this come from? if anything we're using PSMCT16S + if(cpsm == PSMCT16){ + // unswizzle the starting block of the last buffer and palette + uint32 bufbase_B = bufferBase[numLevels-1]&~0x1F | (uint64)blockmaprev_PSMCT16[bufferBase[numLevels-1]&0x1F]; + uint32 palbase_B = ras->paletteBase&~0x1F | (uint64)blockmaprev_PSMCT16[ras->paletteBase&0x1F]; + // find start of page of last level (32,16 are PSMT4 block dimensions) + uint32 page_B = bufbase_B - 4*(dsay/32) - dsax/16; + // find palette DSAX/Y (in PSMCT16!) + dsay = (palbase_B - page_B)/4 * 8; // block/blocksPerPageX * blockHeight + dsax = (palbase_B - page_B)*16 % 128; // block*blockWidth % pageWidth + if(dsay < 0x800) + paltrxpos = dsay<<16 | dsax; + } + } } ras->pixelSize = 0x50*numLevels; // GIF packets int32 minW, minH; - ps2MinSize(psm, ras->flags, &minW, &minH); + transferMinSize(psm, ras->flags, &minW, &minH); w = raster->width; h = raster->height; n = numLevels; while(n--){ - mipw = w < minW ? minW : w; - miph = h < minH ? minH : h; + mipw = max(w, minW); + miph = max(h, minH); ras->pixelSize += ALIGN16(mipw*miph*raster->depth/8); w /= 2; h /= 2; @@ -1046,25 +1092,44 @@ createTexRaster(Raster *raster) ras->paletteSize = 0x50 + paletteDepth*paletteWidth*paletteHeight; } - // TODO: allocate space for more DMA packets - // every upload as 4 qwords: + // One transfer per buffer width, 4 qwords: // DMAcnt(2) [NOP, DIRECT] // GIF tag A+D // BITBLTBUF // DMAref(pixel data) [NOP, DIRECT] - ras->dataSize = ras->paletteSize+ras->pixelSize; + uint32 extrasize = 0x10; // PixelPtr + int32 numTransfers = 0; + for(n = 0; n < numLevels; n++) + if(trxpos_hi[n] == 0){ + extrasize += 0x40; + numTransfers++; + } + if(ras->paletteSize){ + extrasize += 0x40; + numTransfers++; + } + // What happens here? + if(ras->paletteSize && paltrxpos == 0) + ras->dataSize = ALIGN(ras->pixelSize,128) + ALIGN(ras->paletteSize,64) + extrasize + 0x70; + else + ras->dataSize = ALIGN(ras->paletteSize+ras->pixelSize,64) + extrasize + 0x70; uint8 *data = (uint8*)mallocalign(ras->dataSize, 0x40); + uint32 *xferchain = (uint32*)(data + 0x10); assert(data); ras->data = data; - raster->texels = data + 0x50; + Ps2Raster::PixelPtr *pp = (Ps2Raster::PixelPtr*)data; + pp->numTransfers = numTransfers; + pp->numTotalTransfers = numTransfers; + pp->pixels = (uint8*)ALIGN((uintptr)data + extrasize, 128); + raster->pixels = (uint8*)pp; if(ras->paletteSize) - raster->palette = data + ras->pixelSize + 0x50; - uint32 *p = (uint32*)data; + raster->palette = pp->pixels + ALIGN(ras->pixelSize, 128) + 0x50; + uint32 *p = (uint32*)pp->pixels; w = raster->width; h = raster->height; for(n = 0; n < numLevels; n++){ - mipw = w < minW ? minW : w; - miph = h < minH ? minH : h; + mipw = max(w, minW); + miph = max(h, minH); // GIF tag *p++ = 3; // NLOOP = 3 @@ -1073,8 +1138,14 @@ createTexRaster(Raster *raster) *p++ = 0; // TRXPOS - *p++ = 0; // TODO - *p++ = 0; // TODO + if(ras->flags & Ps2Raster::SWIZZLED8 && psm == PSMT8 || + ras->flags & Ps2Raster::SWIZZLED4 && psm == PSMT4){ + *p++ = 0; // SSAX/Y is always 0 + *p++ = (trxpos_hi[n] & ~0x10001)/2; // divide both DSAX/Y by 2 + }else{ + *p++ = 0; + *p++ = trxpos_hi[n]; + } *p++ = 0x51; *p++ = 0; @@ -1097,18 +1168,62 @@ createTexRaster(Raster *raster) *p++ = 0; // GIF tag - uint32 sz = mipw*miph*raster->depth/8 + 0xF >> 4; - *p++ = sz; + uint32 sz = ALIGN16(mipw*miph*raster->depth/8)/16; + *p++ = sz & 0x7FFF; *p++ = 0x08000000; // IMAGE *p++ = 0; *p++ = 0; + if(trxpos_hi[n] == 0){ + // Add a transfer, see above for layout + + *xferchain++ = 0x10000002; // DMAcnt, 2 qwords + *xferchain++ = 0; + *xferchain++ = 0; // VIF nop + *xferchain++ = 0x50000002; // VIF DIRECT 2 qwords + + // GIF tag + *xferchain++ = 1; // NLOOP = 1 + *xferchain++ = 0x10000000; // NREG = 1 + *xferchain++ = 0xE; // A+D + *xferchain++ = 0; + + // BITBLTBUF + if(ras->flags & Ps2Raster::SWIZZLED8 && psm == PSMT8){ + // PSMT8 is swizzled to PSMCT32 and dimensions are halved + *xferchain++ = PSMCT32<<24 | bufferWidth[n]/2<<16; // src buffer + *xferchain++ = PSMCT32<<24 | bufferWidth[n]/2<<16 | bufferBase[n]; // dst buffer + }else if(ras->flags & Ps2Raster::SWIZZLED4 && psm == PSMT4){ + // PSMT4 is swizzled to PSMCT16 and dimensions are halved + *xferchain++ = PSMCT16<<24 | bufferWidth[n]/2<<16; // src buffer + *xferchain++ = PSMCT16<<24 | bufferWidth[n]/2<<16 | bufferBase[n]; // dst buffer + }else{ + *xferchain++ = psm<<24 | bufferWidth[n]<<16; // src buffer + *xferchain++ = psm<<24 | bufferWidth[n]<<16 | bufferBase[n]; // dst buffer + } + *xferchain++ = 0x50; + *xferchain++ = 0; + + *xferchain++ = 0x30000000 | sz+5; // DMAref + // this obviously only works with 32 bit pointers, but it's only needed on the PS2 anyway + *xferchain++ = (uint32)(uintptr)p - 0x50; + *xferchain++ = 0; // VIF nop + *xferchain++ = 0x50000000 | sz+5; // VIF DIRECT 2 qwords + }else{ + // Add to existing transfer + xferchain[-4] = 0x30000000 | (xferchain[-4]&0xFFFF) + sz+5; // last DMAref + xferchain[-1] = 0x50000000 | (xferchain[-1]&0xFFFF) + sz+5; // last DIRECT + } + p += sz*4; w /= 2; h /= 2; } if(ras->paletteSize){ + // huh? + if(paltrxpos) + raster->palette = (uint8*)p + 0x50; p = (uint32*)(raster->palette - 0x50); // GIF tag *p++ = 3; // NLOOP = 3 @@ -1117,8 +1232,8 @@ createTexRaster(Raster *raster) *p++ = 0; // TRXPOS - *p++ = 0; // TODO - *p++ = 0; // TODO + *(uint64*)p = paltrxpos; + p += 2; *p++ = 0x51; *p++ = 0; @@ -1135,13 +1250,54 @@ createTexRaster(Raster *raster) *p++ = 0; // GIF tag - uint32 sz = ras->paletteSize - 0x50 + 0xF >> 4; - *p++ = sz; + uint32 sz = ALIGN16(ras->paletteSize - 0x50)/16; + *p++ = sz & 0x7FFF; *p++ = 0x08000000; // IMAGE *p++ = 0; *p++ = 0; + + // Transfer + *xferchain++ = 0x10000002; // DMAcnt, 2 qwords + *xferchain++ = 0; + *xferchain++ = 0; // VIF nop + *xferchain++ = 0x50000002; // VIF DIRECT 2 qwords + + // GIF tag + *xferchain++ = 1; // NLOOP = 1 + *xferchain++ = 0x10000000; // NREG = 1 + *xferchain++ = 0xE; // A+D + *xferchain++ = 0; + + // BITBLTBUF + if(paltrxpos == 0){ + *xferchain++ = cpsm<<24 | 1<<16; // src buffer + *xferchain++ = cpsm<<24 | 1<<16 | ras->paletteBase; // dst buffer + *xferchain++ = 0x50; + *xferchain++ = 0; + }else{ + // copy last pixel bitbltbuf...if uploading palette separately it's still the same buffer + xferchain[0] = xferchain[-16]; + xferchain[1] = xferchain[-15]; + xferchain[2] = xferchain[-14]; + xferchain[3] = xferchain[-13]; + // Add to last transfer + xferchain[-16] = 0x30000000 | (xferchain[-16]&0xFFFF) + sz+5; // last DMAref + xferchain[-13] = 0x50000000 | (xferchain[-13]&0xFFFF) + sz+5; // last DIRECT + xferchain += 4; + pp->numTransfers--; + } + + *xferchain++ = 0x30000000 | sz+5; // DMAref + // this obviously only works with 32 bit pointers, but it's only needed on the PS2 anyway + *xferchain++ = (uint32)(uintptr)p - 0x50; + *xferchain++ = 0; // VIF nop + *xferchain++ = 0x50000000 | sz+5; // VIF DIRECT 2 qwords } } + raster->originalPixels = raster->pixels; + raster->originalStride = raster->stride; + if(ras->flags & Ps2Raster::NEWSTYLE) + raster->pixels = ((Ps2Raster::PixelPtr*)raster->pixels)->pixels + 0x50; } void @@ -1151,9 +1307,15 @@ rasterCreate(Raster *raster) return; // init raster + raster->pixels = nil; + raster->palette = nil; + raster->originalWidth = raster->width; + raster->originalHeight = raster->height; + raster->originalPixels = raster->pixels; if(raster->width == 0 || raster->height == 0){ raster->flags = Raster::DONTALLOCATE; raster->stride = 0; + raster->originalStride = 0; return; } @@ -1203,7 +1365,7 @@ int32 rasterNumLevels(Raster *raster) { Ps2Raster *ras = PLUGINOFFSET(Ps2Raster, raster, nativeRasterOffset); - if(raster->texels == nil) return 0; + if(raster->pixels == nil) return 0; if(raster->format & Raster::MIPMAP) return MAXLEVEL(ras)+1; return 1; @@ -1489,9 +1651,9 @@ streamExt.mipmapVal); goto fail; } if(streamExt.type < 2){ - stream->read(raster->texels, length); + stream->read(raster->pixels, length); }else{ - stream->read(raster->texels-0x50, natras->pixelSize); + stream->read(((Ps2Raster::PixelPtr*)raster->originalPixels)->pixels, natras->pixelSize); stream->read(raster->palette-0x50, natras->paletteSize); } //printf("\n"); @@ -1528,7 +1690,7 @@ writeNativeTexture(Texture *tex, Stream *stream) streamExt.type = 0; if(ras->flags == Ps2Raster::SWIZZLED8 && raster->depth == 8) streamExt.type = 1; - if(ras->flags & Ps2Raster::HASGIFPACKETS) + if(ras->flags & Ps2Raster::NEWSTYLE) streamExt.type = 2; streamExt.tex0 = ras->tex0; streamExt.paletteOffset = ras->paletteBase; @@ -1543,9 +1705,9 @@ writeNativeTexture(Texture *tex, Stream *stream) writeChunkHeader(stream, ID_STRUCT, sz); if(streamExt.type < 2){ - stream->write(raster->texels, sz); + stream->write(raster->pixels, sz); }else{ - stream->write(raster->texels-0x50, ras->pixelSize); + stream->write(((Ps2Raster::PixelPtr*)raster->originalPixels)->pixels, ras->pixelSize); stream->write(raster->palette-0x50, ras->paletteSize); } } diff --git a/src/ps2/rwps2.h b/src/ps2/rwps2.h index ca75940..f98f4a2 100755 --- a/src/ps2/rwps2.h +++ b/src/ps2/rwps2.h @@ -183,9 +183,18 @@ void registerPluginPDSPipes(void); struct Ps2Raster { enum Flags { - HASGIFPACKETS = 0x1, - SWIZZLED8 = 0x2, - SWIZZLED4 = 0x4, + NEWSTYLE = 0x1, // has GIF tags and transfer DMA chain + SWIZZLED8 = 0x2, + SWIZZLED4 = 0x4, + }; + struct PixelPtr { + // RW has pixels as second element but we don't want this struct + // to be longer than 16 bytes + uint8 *pixels; + // palette can be allocated in last level, in that case numTransfers is + // one less than numTotalTransfers. + int32 numTransfers; + int32 numTotalTransfers; }; uint64 tex0; diff --git a/src/rwobjects.h b/src/rwobjects.h index 0a4c336..afd1846 100755 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -227,10 +227,14 @@ struct Raster int32 format; int32 width, height, depth; int32 stride; - uint8 *texels; + uint8 *pixels; uint8 *palette; + uint8 *originalPixels; + // TODO: use them (for locking mainly) + int32 originalWidth; + int32 originalHeight; + int32 originalStride; // TODO: - // original pixels, width, height, stride (used for locking) // parent raster and offset static Raster *create(int32 width, int32 height, int32 depth,