Skip to content

Commit eaf781f

Browse files
committed
Implementing swizzling
1 parent 31d9485 commit eaf781f

File tree

1 file changed

+151
-20
lines changed

1 file changed

+151
-20
lines changed

src/render/psp/SDL_render_psp.c

Lines changed: 151 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,21 @@ typedef struct
5454
typedef struct
5555
{
5656
void *data; /**< Image data. */
57-
unsigned int width; /**< Image width. */
58-
unsigned int height; /**< Image height. */
59-
unsigned int textureWidth; /**< Texture width (power of two). */
60-
unsigned int textureHeight; /**< Texture height (power of two). */
61-
unsigned int format; /**< Image format - one of ::pgePixelFormat. */
62-
unsigned int size; /**< Image size in bytes. */
63-
unsigned int filter; /**< Image filter - one of GU_NEAREST or GU_LINEAR. */
64-
unsigned int pitch;
57+
void *swizzledData; /**< Swizzled image data. */
58+
uint32_t textureWidth; /**< Texture width (power of two). */
59+
uint32_t textureHeight; /**< Texture height (power of two). */
60+
uint32_t width; /**< Image width. */
61+
uint32_t height; /**< Image height. */
62+
uint32_t pitch; /**< Image pitch. */
63+
uint32_t swizzledWidth; /**< Swizzled image width. */
64+
uint32_t swizzledHeight;/**< Swizzled image height. */
65+
uint32_t swizzledPitch; /**< Swizzled image pitch. */
66+
uint32_t size; /**< Image size in bytes. */
67+
uint32_t swizzledSize; /**< Swizzled image size in bytes. */
68+
uint8_t format; /**< Image format - one of ::pgePixelFormat. */
69+
uint8_t filter; /**< Image filter - one of GU_NEAREST or GU_LINEAR. */
70+
uint8_t swizzled; /**< Whether the image is swizzled or not. */
71+
6572
} PSP_Texture;
6673

6774
typedef struct
@@ -177,6 +184,20 @@ static inline int calculatePitchForTextureFormat(int width, int format)
177184
}
178185
}
179186

187+
static inline int calculateHeightForSwizzledTexture(int height, int format)
188+
{
189+
switch (format) {
190+
case GU_PSM_5650:
191+
case GU_PSM_5551:
192+
case GU_PSM_4444:
193+
return (height + 15) & ~15;
194+
case GU_PSM_8888:
195+
return (height + 7) & ~7;
196+
default:
197+
return height;
198+
}
199+
}
200+
180201
/* Return next power of 2 */
181202
static inline int calculateNextPow2(int value)
182203
{
@@ -187,7 +208,8 @@ static inline int calculateNextPow2(int value)
187208
return i;
188209
}
189210

190-
static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const SDL_FRect *dstrect, SliceSize *sliceSize, SliceSize *sliceDimension) {
211+
static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const SDL_FRect *dstrect, SliceSize *sliceSize, SliceSize *sliceDimension)
212+
{
191213
PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata;
192214

193215
// We split in blocks of (64 x destiny height) when 16 bits per color
@@ -214,7 +236,8 @@ static inline int calculateBestSliceSizeForSprite(SDL_Renderer *renderer, const
214236
}
215237

216238
static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, SliceSize *sliceSize,
217-
const SDL_Rect *srcrect, const SDL_FRect *dstrect) {
239+
const SDL_Rect *srcrect, const SDL_FRect *dstrect)
240+
{
218241
int i, j;
219242
int remainingWidth = (int)dstrect->w % sliceSize->width;
220243
int remainingHeight = (int)dstrect->h % sliceSize->height;
@@ -257,6 +280,92 @@ static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, S
257280
}
258281
}
259282

283+
// The slize when swizzling is always 16x32 bytes, no matter the texture format
284+
// so the algorithm is the same for all formats
285+
static inline int swizzle(PSP_Texture *psp_texture)
286+
{
287+
uint32_t i, j, verticalSlice, dstOffset;
288+
uint32_t *src, *dst, *srcBlock, *dstBlock;
289+
uint32_t srcWidth = psp_texture->pitch >> 2;
290+
uint32_t dstWidth = psp_texture->swizzledPitch >> 2;
291+
uint32_t srcWidthBlocks = srcWidth >> 2;
292+
uint8_t blockSizeBytes = 16; // 4 pixels of 32 bits
293+
294+
dst = (uint32_t *)psp_texture->swizzledData;
295+
for (j = 0; j < psp_texture->height; j++) {
296+
src = (uint32_t *)psp_texture->data + j * srcWidth;
297+
verticalSlice = (((j >> 3) << 3) * dstWidth) + ((j % 8) << 2);
298+
for (i = 0; i < srcWidthBlocks; i++) {
299+
srcBlock = src + (i << 2);
300+
dstOffset = verticalSlice + (i << 5);
301+
dstBlock = dst + dstOffset;
302+
memcpy(dstBlock, srcBlock, blockSizeBytes);
303+
}
304+
}
305+
306+
return 1;
307+
}
308+
309+
static inline int unswizzle(PSP_Texture *psp_texture)
310+
{
311+
uint32_t i, j, verticalSlice, srcOffset;
312+
uint32_t *src, *dst, *srcBlock, *dstBlock;
313+
uint32_t srcWidth = psp_texture->swizzledPitch >> 2;
314+
uint32_t dstWidth = psp_texture->pitch >> 2;
315+
uint32_t dstWidthBlocks = dstWidth >> 2;
316+
uint8_t blockSizeBytes = 16; // 4 pixels of 32 bits
317+
318+
src = (uint32_t *)psp_texture->swizzledData;
319+
for (j = 0; j < psp_texture->height; j++) {
320+
dst = (uint32_t *)psp_texture->data + j * dstWidth;
321+
verticalSlice = (((j >> 3) << 3) * srcWidth) + ((j % 8) << 2);
322+
for (i = 0; i < dstWidthBlocks; i++) {
323+
dstBlock = dst + (i << 2);
324+
srcOffset = verticalSlice + (i << 5);
325+
srcBlock = src + srcOffset;
326+
memcpy(dstBlock, srcBlock, blockSizeBytes);
327+
}
328+
}
329+
330+
return 1;
331+
}
332+
333+
static inline void prepareTextureForUpload(PSP_Texture *psp_tex)
334+
{
335+
if (psp_tex->swizzled)
336+
return;
337+
338+
psp_tex->swizzledData = vramalloc(psp_tex->swizzledSize);
339+
if (!psp_tex->swizzledData) {
340+
sceKernelDcacheWritebackRange(psp_tex->data, psp_tex->size);
341+
return;
342+
}
343+
344+
swizzle(psp_tex);
345+
SDL_free(psp_tex->data);
346+
psp_tex->swizzled = GU_TRUE;
347+
348+
sceKernelDcacheWritebackRange(psp_tex->swizzledData, psp_tex->swizzledSize);
349+
}
350+
351+
static inline void prepareTextureForDownload(PSP_Texture *psp_tex)
352+
{
353+
if (!psp_tex->swizzled)
354+
return;
355+
356+
psp_tex->data = SDL_malloc(psp_tex->size);
357+
if (!psp_tex->data) {
358+
sceKernelDcacheInvalidateRange(psp_tex->swizzledData, psp_tex->swizzledSize);
359+
return;
360+
}
361+
362+
unswizzle(psp_tex);
363+
vfree(psp_tex->swizzledData);
364+
psp_tex->swizzled = GU_FALSE;
365+
366+
sceKernelDcacheInvalidateRange(psp_tex->data, psp_tex->size);
367+
}
368+
260369
static void PSP_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
261370
{
262371
}
@@ -270,15 +379,21 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
270379
}
271380

272381
psp_tex->format = pixelFormatToPSPFMT(texture->format);
273-
psp_tex->width = calculatePitchForTextureFormat(texture->w, psp_tex->format);
274-
psp_tex->height = texture->h;
275382
psp_tex->textureWidth = calculateNextPow2(texture->w);
276383
psp_tex->textureHeight = calculateNextPow2(texture->h);
384+
psp_tex->width = calculatePitchForTextureFormat(texture->w, psp_tex->format);
385+
psp_tex->height = texture->h;
386+
psp_tex->pitch = psp_tex->width * SDL_BYTESPERPIXEL(texture->format);
387+
psp_tex->swizzledWidth = psp_tex->textureWidth;
388+
psp_tex->swizzledHeight = calculateHeightForSwizzledTexture(texture->h, psp_tex->format);
389+
psp_tex->swizzledPitch = psp_tex->swizzledWidth * SDL_BYTESPERPIXEL(texture->format);
277390
psp_tex->size = getMemorySize(psp_tex->width, psp_tex->height, psp_tex->format);
278-
psp_tex->data = vramalloc(psp_tex->size);
391+
psp_tex->swizzledSize = getMemorySize(psp_tex->swizzledWidth, psp_tex->swizzledHeight, psp_tex->format);
392+
psp_tex->data = SDL_calloc(1, psp_tex->size);
393+
psp_tex->swizzled = GU_FALSE;
279394

280395
if (!psp_tex->data) {
281-
vfree(psp_tex);
396+
SDL_free(psp_tex);
282397
return SDL_OutOfMemory();
283398
}
284399

@@ -292,6 +407,9 @@ static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
292407
{
293408
PSP_Texture *psp_texture = (PSP_Texture *)texture->driverdata;
294409

410+
// How a pointer to the texture data is returned it need to be unswizzled before it can be used
411+
prepareTextureForDownload(psp_texture);
412+
295413
*pixels =
296414
(void *)((Uint8 *)psp_texture->data + rect->y * psp_texture->width * SDL_BYTESPERPIXEL(texture->format) +
297415
rect->x * SDL_BYTESPERPIXEL(texture->format));
@@ -632,11 +750,17 @@ static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL
632750
PSP_SetBlendMode(data, blendInfo);
633751

634752
if (cmd->data.draw.texture) {
753+
uint32_t tbw, twp;
635754
const VertTCV *verts = (VertTCV *)(vertices + cmd->data.draw.first);
636755
PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata;
637756

638-
sceGuTexMode(psp_tex->format, 0, 0, GU_FALSE);
639-
sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->width, psp_tex->data);
757+
prepareTextureForUpload(psp_tex);
758+
759+
tbw = psp_tex->swizzled ? psp_tex->swizzledWidth : psp_tex->width;
760+
twp = psp_tex->swizzled ? psp_tex->swizzledData : psp_tex->data;
761+
762+
sceGuTexMode(psp_tex->format, 0, 0, psp_tex->swizzled);
763+
sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, tbw, twp);
640764
sceGuTexFilter(psp_tex->filter, psp_tex->filter);
641765
sceGuEnable(GU_TEXTURE_2D);
642766
sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
@@ -700,19 +824,25 @@ static inline int PSP_RenderPoints(SDL_Renderer *renderer, void *vertices, SDL_R
700824

701825
static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_RenderCommand *cmd)
702826
{
827+
uint32_t tbw, twp;
703828
PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata;
704829
PSP_Texture *psp_tex = (PSP_Texture *)cmd->data.draw.texture->driverdata;
705830
const size_t count = cmd->data.draw.count;
706831
const VertTV *verts = (VertTV *)(vertices + cmd->data.draw.first);
707-
PSP_BlendInfo blendInfo = {
832+
const PSP_BlendInfo blendInfo = {
708833
.mode = cmd->data.draw.blend,
709834
.shade = GU_FLAT
710835
};
711836

712837
PSP_SetBlendMode(data, blendInfo);
713838

714-
sceGuTexMode(psp_tex->format, 0, 0, GU_FALSE);
715-
sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, psp_tex->width, psp_tex->data);
839+
prepareTextureForUpload(psp_tex);
840+
841+
tbw = psp_tex->swizzled ? psp_tex->textureWidth : psp_tex->width;
842+
twp = psp_tex->swizzled ? psp_tex->swizzledData : psp_tex->data;
843+
844+
sceGuTexMode(psp_tex->format, 0, 0, psp_tex->swizzled);
845+
sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, tbw, twp);
716846
sceGuTexFilter(psp_tex->filter, psp_tex->filter);
717847
sceGuEnable(GU_TEXTURE_2D);
718848
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
@@ -834,7 +964,8 @@ static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
834964
return;
835965
}
836966

837-
vfree(psp_texture->data);
967+
vfree(psp_texture->swizzledData);
968+
SDL_free(psp_texture->data);
838969
SDL_free(psp_texture);
839970
texture->driverdata = NULL;
840971
}

0 commit comments

Comments
 (0)