Skip to content

Commit 4c4cd67

Browse files
committed
use sceGuSignal for assuring thread-safe (CPU & GPU)
1 parent ae3f764 commit 4c4cd67

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

src/render/psp/SDL_render_psp.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include <pspdisplay.h>
3030
#include <pspgu.h>
31+
#include <pspthreadman.h>
3132
#include <pspintrman.h>
3233
#include <psputils.h>
3334
#include <vram.h>
@@ -57,6 +58,7 @@ typedef struct
5758
{
5859
void *data; /**< Image data. */
5960
void *swizzledData; /**< Swizzled image data. */
61+
uint32_t semaphore; /**< Semaphore for the texture. */
6062
uint32_t textureWidth; /**< Texture width (power of two). */
6163
uint32_t textureHeight; /**< Texture height (power of two). */
6264
uint32_t width; /**< Image width. */
@@ -128,6 +130,34 @@ static void psp_on_vblank(u32 sub, PSP_RenderData *data)
128130
}
129131
}
130132

133+
static void psp_on_signal(int id)
134+
{
135+
sceKernelSignalSema(id, 1);
136+
}
137+
138+
static inline uint32_t createSemaphore(SDL_Texture *texture)
139+
{
140+
uint32_t semaphore;
141+
char semaphoreName[31];
142+
snprintf(semaphoreName, sizeof(semaphoreName), "PSP_Tex_Sem_%p", texture);
143+
semaphore = sceKernelCreateSema(semaphoreName, 0, 1, 1, NULL);
144+
if (semaphore < 0) {
145+
SDL_SetError("Failed to create texture semaphore");
146+
return -1;
147+
}
148+
return semaphore;
149+
}
150+
151+
static inline void destroySemaphore(uint32_t semaphore)
152+
{
153+
if (semaphore != -1) {
154+
// Wait for all threads to finish using the semaphore
155+
sceKernelWaitSema(semaphore, 1, NULL);
156+
sceKernelDeleteSema(semaphore);
157+
semaphore = -1;
158+
}
159+
}
160+
131161
static inline unsigned int getMemorySize(unsigned int width, unsigned int height, unsigned int psm)
132162
{
133163
switch (psm) {
@@ -460,6 +490,10 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
460490
return SDL_OutOfMemory();
461491
}
462492

493+
psp_tex->semaphore = createSemaphore(texture);
494+
if (psp_tex->semaphore == -1) {
495+
return SDL_OutOfMemory();
496+
}
463497
psp_tex->format = pixelFormatToPSPFMT(texture->format);
464498
psp_tex->textureWidth = calculateNextPow2(texture->w);
465499
psp_tex->textureHeight = calculateNextPow2(texture->h);
@@ -475,12 +509,14 @@ static int PSP_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
475509
if (texture->access != SDL_TEXTUREACCESS_STATIC) {
476510
psp_tex->data = vramalloc(psp_tex->size);
477511
if (!psp_tex->data) {
512+
destroySemaphore(psp_tex->semaphore);
478513
vfree(psp_tex);
479514
return SDL_OutOfMemory();
480515
}
481516
} else {
482517
psp_tex->data = SDL_calloc(1, psp_tex->size);
483518
if (!psp_tex->data) {
519+
destroySemaphore(psp_tex->semaphore);
484520
SDL_free(psp_tex);
485521
return SDL_OutOfMemory();
486522
}
@@ -500,6 +536,7 @@ static int PSP_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
500536
// How a pointer to the texture data is returned it need to be unswizzled before it can be used
501537
prepareTextureForDownload(texture);
502538

539+
sceKernelWaitSema(psp_tex->semaphore, 1, NULL);
503540
*pixels =
504541
(void *)((Uint8 *)psp_tex->data + rect->y * psp_tex->pitch +
505542
rect->x * SDL_BYTESPERPIXEL(texture->format));
@@ -513,6 +550,7 @@ static void PSP_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
513550
PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata;
514551

515552
sceKernelDcacheWritebackRange(psp_tex->data, psp_tex->size);
553+
sceKernelSignalSema(psp_tex->semaphore, 1);
516554
}
517555

518556
static int PSP_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
@@ -561,6 +599,7 @@ static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
561599

562600
if (texture) {
563601
PSP_Texture *psp_tex = (PSP_Texture *)texture->driverdata;
602+
sceKernelWaitSema(psp_tex->semaphore, 1, NULL);
564603
sceGuDrawBufferList(psp_tex->format, vrelptr(psp_tex->data), psp_tex->width);
565604
data->currentDrawBufferFormat = psp_tex->format;
566605

@@ -579,6 +618,7 @@ static int PSP_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
579618
sceGuEnable(GU_SCISSOR_TEST);
580619
sceGuScissor(0, 0, psp_tex->width, psp_tex->height);
581620

621+
sceGuSignal(GU_SIGNAL_WAIT, psp_tex->semaphore);
582622
} else {
583623
sceGuDrawBufferList(data->drawBufferFormat, vrelptr(data->backbuffer), PSP_FRAME_BUFFER_WIDTH);
584624
data->currentDrawBufferFormat = data->drawBufferFormat;
@@ -830,12 +870,14 @@ static inline int PSP_RenderGeometry(SDL_Renderer *renderer, void *vertices, SDL
830870
tbw = psp_tex->swizzled ? psp_tex->swizzledWidth : psp_tex->width;
831871
twp = psp_tex->swizzled ? psp_tex->swizzledData : psp_tex->data;
832872

873+
sceKernelWaitSema(psp_tex->semaphore, 1, NULL);
833874
sceGuTexMode(psp_tex->format, 0, 0, psp_tex->swizzled);
834875
sceGuTexImage(0, psp_tex->textureWidth, psp_tex->textureHeight, tbw, twp);
835876
sceGuTexFilter(psp_tex->filter, psp_tex->filter);
836877
sceGuEnable(GU_TEXTURE_2D);
837878
sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
838879
sceGuDisable(GU_TEXTURE_2D);
880+
sceGuSignal(GU_SIGNAL_WAIT, psp_tex->semaphore);
839881
} else {
840882
const VertCV *verts = (VertCV *)(vertices + cmd->data.draw.first);
841883
sceGuDrawArray(GU_TRIANGLES, GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
@@ -909,6 +951,9 @@ static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_Ren
909951
PSP_SetBlendMode(data, blendInfo);
910952

911953
prepareTextureForUpload(texture);
954+
// We can't use sceKernelWaitSema here because several consecutive SDL_RenderCopy calls
955+
// could be performed by the user.
956+
sceKernelPollSema(psp_tex->semaphore, 1);
912957

913958
tbw = psp_tex->swizzled ? psp_tex->textureWidth : psp_tex->width;
914959
twp = psp_tex->swizzled ? psp_tex->swizzledData : psp_tex->data;
@@ -919,6 +964,7 @@ static inline int PSP_RenderCopy(SDL_Renderer *renderer, void *vertices, SDL_Ren
919964
sceGuEnable(GU_TEXTURE_2D);
920965
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
921966
sceGuDisable(GU_TEXTURE_2D);
967+
sceGuSignal(GU_SIGNAL_WAIT, psp_tex->semaphore);
922968

923969
return 0;
924970
}
@@ -1053,6 +1099,8 @@ static void PSP_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
10531099
return;
10541100
}
10551101

1102+
destroySemaphore(psp_tex->semaphore);
1103+
10561104
if (psp_tex->swizzledData) {
10571105
vfree(psp_tex->swizzledData);
10581106
} else if (texture->access != SDL_TEXTUREACCESS_STATIC) {
@@ -1151,6 +1199,9 @@ static int PSP_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32
11511199
}
11521200
data->vblank_not_reached = SDL_TRUE;
11531201

1202+
// Set the callback for the texture semaphores
1203+
sceGuSetCallback(GU_CALLBACK_SIGNAL, psp_on_signal);
1204+
11541205
renderer->WindowEvent = PSP_WindowEvent;
11551206
renderer->CreateTexture = PSP_CreateTexture;
11561207
renderer->UpdateTexture = PSP_UpdateTexture;

0 commit comments

Comments
 (0)