@@ -54,14 +54,21 @@ typedef struct
54
54
typedef struct
55
55
{
56
56
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
+
65
72
} PSP_Texture ;
66
73
67
74
typedef struct
@@ -177,6 +184,20 @@ static inline int calculatePitchForTextureFormat(int width, int format)
177
184
}
178
185
}
179
186
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
+
180
201
/* Return next power of 2 */
181
202
static inline int calculateNextPow2 (int value )
182
203
{
@@ -187,7 +208,8 @@ static inline int calculateNextPow2(int value)
187
208
return i ;
188
209
}
189
210
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
+ {
191
213
PSP_RenderData * data = (PSP_RenderData * )renderer -> driverdata ;
192
214
193
215
// 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
214
236
}
215
237
216
238
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
+ {
218
241
int i , j ;
219
242
int remainingWidth = (int )dstrect -> w % sliceSize -> width ;
220
243
int remainingHeight = (int )dstrect -> h % sliceSize -> height ;
@@ -257,6 +280,92 @@ static inline void fillSpriteVertices(VertTV *vertices, SliceSize *dimensions, S
257
280
}
258
281
}
259
282
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
+
260
369
static void PSP_WindowEvent (SDL_Renderer * renderer , const SDL_WindowEvent * event )
261
370
{
262
371
}
@@ -270,15 +379,21 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
270
379
}
271
380
272
381
psp_tex -> format = pixelFormatToPSPFMT (texture -> format );
273
- psp_tex -> width = calculatePitchForTextureFormat (texture -> w , psp_tex -> format );
274
- psp_tex -> height = texture -> h ;
275
382
psp_tex -> textureWidth = calculateNextPow2 (texture -> w );
276
383
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 );
277
390
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 ;
279
394
280
395
if (!psp_tex -> data ) {
281
- vfree (psp_tex );
396
+ SDL_free (psp_tex );
282
397
return SDL_OutOfMemory ();
283
398
}
284
399
@@ -292,6 +407,9 @@ static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
292
407
{
293
408
PSP_Texture * psp_texture = (PSP_Texture * )texture -> driverdata ;
294
409
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
+
295
413
* pixels =
296
414
(void * )((Uint8 * )psp_texture -> data + rect -> y * psp_texture -> width * SDL_BYTESPERPIXEL (texture -> format ) +
297
415
rect -> x * SDL_BYTESPERPIXEL (texture -> format ));
@@ -632,11 +750,17 @@ static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL
632
750
PSP_SetBlendMode (data , blendInfo );
633
751
634
752
if (cmd -> data .draw .texture ) {
753
+ uint32_t tbw , twp ;
635
754
const VertTCV * verts = (VertTCV * )(vertices + cmd -> data .draw .first );
636
755
PSP_Texture * psp_tex = (PSP_Texture * )cmd -> data .draw .texture -> driverdata ;
637
756
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 );
640
764
sceGuTexFilter (psp_tex -> filter , psp_tex -> filter );
641
765
sceGuEnable (GU_TEXTURE_2D );
642
766
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
700
824
701
825
static inline int PSP_RenderCopy (SDL_Renderer * renderer , void * vertices , SDL_RenderCommand * cmd )
702
826
{
827
+ uint32_t tbw , twp ;
703
828
PSP_RenderData * data = (PSP_RenderData * )renderer -> driverdata ;
704
829
PSP_Texture * psp_tex = (PSP_Texture * )cmd -> data .draw .texture -> driverdata ;
705
830
const size_t count = cmd -> data .draw .count ;
706
831
const VertTV * verts = (VertTV * )(vertices + cmd -> data .draw .first );
707
- PSP_BlendInfo blendInfo = {
832
+ const PSP_BlendInfo blendInfo = {
708
833
.mode = cmd -> data .draw .blend ,
709
834
.shade = GU_FLAT
710
835
};
711
836
712
837
PSP_SetBlendMode (data , blendInfo );
713
838
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 );
716
846
sceGuTexFilter (psp_tex -> filter , psp_tex -> filter );
717
847
sceGuEnable (GU_TEXTURE_2D );
718
848
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)
834
964
return ;
835
965
}
836
966
837
- vfree (psp_texture -> data );
967
+ vfree (psp_texture -> swizzledData );
968
+ SDL_free (psp_texture -> data );
838
969
SDL_free (psp_texture );
839
970
texture -> driverdata = NULL ;
840
971
}
0 commit comments