Skip to content

Commit 346f81c

Browse files
committed
SDL_render_psp.c: Implemented working viewport support
Since it's no known way to use geuine viewport with PSP SDK, I implemented the workaround using manually added/subtracted offsets to vertices passing to the render API. To assign viewport and cliprect in valid way, I copied part of code from the Vita's module and adjusted it to work on PSP.
1 parent 641201a commit 346f81c

File tree

1 file changed

+191
-21
lines changed

1 file changed

+191
-21
lines changed

src/render/psp/SDL_render_psp.c

Lines changed: 191 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,26 @@ typedef struct
7676
SDL_Texture *texture;
7777
} PSP_BlendState;
7878

79+
typedef struct
80+
{
81+
SDL_Rect viewport;
82+
SDL_bool viewport_dirty;
83+
SDL_bool viewport_is_set;
84+
85+
SDL_bool cliprect_enabled_dirty;
86+
SDL_bool cliprect_enabled;
87+
SDL_bool cliprect_dirty;
88+
SDL_Rect cliprect;
89+
90+
SDL_Texture *target;
91+
92+
float draw_offset_x;
93+
float draw_offset_y;
94+
95+
int drawablew;
96+
int drawableh;
97+
} PSP_DrawstateCache;
98+
7999
typedef struct
80100
{
81101
void *frontbuffer; /**< main screen buffer */
@@ -91,6 +111,7 @@ typedef struct
91111
PSP_TextureData *most_recent_target; /**< start of render target LRU double linked list */
92112
PSP_TextureData *least_recent_target; /**< end of the LRU list */
93113

114+
PSP_DrawstateCache drawstate;
94115
SDL_bool vblank_not_reached; /**< whether vblank wasn't reached */
95116
} PSP_RenderData;
96117

@@ -1034,10 +1055,101 @@ static void PSP_SetBlendState(PSP_RenderData *data, PSP_BlendState *state)
10341055
*current = *state;
10351056
}
10361057

1058+
static void ClampCliprectToViewport(SDL_Rect *clip, const SDL_Rect *viewport)
1059+
{
1060+
int max_x_v, max_y_v, max_x_c, max_y_c;
1061+
1062+
if (clip->x < 0) {
1063+
clip->w += clip->x;
1064+
clip->x = 0;
1065+
}
1066+
1067+
if (clip->y < 0) {
1068+
clip->h += clip->y;
1069+
clip->y = 0;
1070+
}
1071+
1072+
max_x_c = clip->x + clip->w;
1073+
max_y_c = clip->y + clip->h;
1074+
1075+
max_x_v = viewport->x + viewport->w;
1076+
max_y_v = viewport->y + viewport->h;
1077+
1078+
if (max_x_c > max_x_v) {
1079+
clip->w -= (max_x_v - max_x_c);
1080+
}
1081+
1082+
if (max_y_c > max_y_v) {
1083+
clip->h -= (max_y_v - max_y_c);
1084+
}
1085+
}
1086+
1087+
static void SetDrawState(PSP_RenderData *data)
1088+
{
1089+
if (data->drawstate.viewport_dirty) {
1090+
SDL_Rect *viewport = &data->drawstate.viewport;
1091+
/* FIXME: Find a genuine way to make viewport work (right now calling these functions here give no effect) */
1092+
/*
1093+
sceGuOffset(2048 - (480 >> 1) + viewport->x, 2048 - (272 >> 1) + viewport->y);
1094+
sceGuViewport(2048, 2048, viewport->w, viewport->h);
1095+
*/
1096+
data->drawstate.draw_offset_x = viewport->x;
1097+
data->drawstate.draw_offset_y = viewport->y;
1098+
data->drawstate.viewport_dirty = SDL_FALSE;
1099+
}
1100+
1101+
if (data->drawstate.cliprect_enabled_dirty) {
1102+
if (!data->drawstate.cliprect_enabled && !data->drawstate.viewport_is_set) {
1103+
sceGuDisable(GU_SCISSOR_TEST);
1104+
}
1105+
data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
1106+
}
1107+
1108+
if ((data->drawstate.cliprect_enabled || data->drawstate.viewport_is_set) && data->drawstate.cliprect_dirty) {
1109+
SDL_Rect rect;
1110+
SDL_Rect *viewport = &data->drawstate.viewport;
1111+
SDL_copyp(&rect, &data->drawstate.cliprect);
1112+
if (data->drawstate.viewport_is_set) {
1113+
ClampCliprectToViewport(&rect, viewport);
1114+
rect.x += viewport->x;
1115+
rect.y += viewport->y;
1116+
}
1117+
sceGuEnable(GU_SCISSOR_TEST);
1118+
sceGuScissor(rect.x, rect.y, rect.w, rect.h);
1119+
data->drawstate.cliprect_dirty = SDL_FALSE;
1120+
}
1121+
}
1122+
1123+
#define PSP_SetViewportOffsetFunk(FunkName, Type) \
1124+
static void FunkName(const PSP_DrawstateCache *drawstate, Type *verts, int count, SDL_bool add) \
1125+
{ \
1126+
size_t i; \
1127+
float off_x, off_y; \
1128+
\
1129+
if (!drawstate->viewport_is_set) { \
1130+
return; \
1131+
} \
1132+
\
1133+
off_x = add ? drawstate->draw_offset_x : -drawstate->draw_offset_x; \
1134+
off_y = add ? drawstate->draw_offset_y : -drawstate->draw_offset_y; \
1135+
\
1136+
for (i = 0; i < count; ++i) { \
1137+
verts[i].x += off_x; \
1138+
verts[i].y += off_y; \
1139+
} \
1140+
}
1141+
1142+
PSP_SetViewportOffsetFunk(PSP_SetViewportOffset, VertV)
1143+
PSP_SetViewportOffsetFunk(PSP_SetViewportOffsetT, VertTV)
1144+
PSP_SetViewportOffsetFunk(PSP_SetViewportOffsetC, VertCV)
1145+
PSP_SetViewportOffsetFunk(PSP_SetViewportOffsetTC, VertTCV)
1146+
10371147
static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
10381148
{
10391149
PSP_RenderData *data = (PSP_RenderData *)renderer->driverdata;
10401150
Uint8 *gpumem = NULL;
1151+
int w = 0, h = 0;
1152+
10411153
StartDrawing(renderer);
10421154

10431155
/* note that before the renderer interface change, this would do extrememly small
@@ -1052,6 +1164,23 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
10521164
}
10531165
SDL_memcpy(gpumem, vertices, vertsize);
10541166

1167+
data->drawstate.target = renderer->target;
1168+
if (!data->drawstate.target) {
1169+
SDL_GL_GetDrawableSize(renderer->window, &w, &h);
1170+
} else {
1171+
if (SDL_QueryTexture(renderer->target, NULL, NULL, &w, &h) < 0) {
1172+
w = data->drawstate.drawablew;
1173+
h = data->drawstate.drawableh;
1174+
}
1175+
}
1176+
1177+
if ((w != data->drawstate.drawablew) || (h != data->drawstate.drawableh)) {
1178+
data->drawstate.viewport_dirty = SDL_TRUE; /* if the window dimensions changed, invalidate the current viewport, etc. */
1179+
data->drawstate.cliprect_dirty = SDL_TRUE;
1180+
data->drawstate.drawablew = w;
1181+
data->drawstate.drawableh = h;
1182+
}
1183+
10551184
while (cmd) {
10561185
switch (cmd->command) {
10571186
case SDL_RENDERCMD_SETDRAWCOLOR:
@@ -1061,22 +1190,42 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
10611190

10621191
case SDL_RENDERCMD_SETVIEWPORT:
10631192
{
1064-
SDL_Rect *viewport = &cmd->data.viewport.rect;
1065-
sceGuOffset(2048 - (viewport->w >> 1), 2048 - (viewport->h >> 1));
1066-
sceGuViewport(2048, 2048, viewport->w, viewport->h);
1067-
sceGuScissor(viewport->x, viewport->y, viewport->w, viewport->h);
1068-
/* FIXME: We need to update the clip rect too, see https://github.com/libsdl-org/SDL/issues/9094 */
1193+
SDL_Rect *viewport = &data->drawstate.viewport;
1194+
if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) {
1195+
SDL_copyp(viewport, &cmd->data.viewport.rect);
1196+
data->drawstate.viewport_dirty = SDL_TRUE;
1197+
data->drawstate.cliprect_dirty = SDL_TRUE;
1198+
data->drawstate.viewport_is_set = viewport->x != 0 || viewport->y != 0 || viewport->w != data->drawstate.drawablew || viewport->h != data->drawstate.drawableh;
1199+
if (!data->drawstate.cliprect_enabled) {
1200+
if (data->drawstate.viewport_is_set) {
1201+
SDL_copyp(&data->drawstate.cliprect, viewport);
1202+
data->drawstate.cliprect.x = 0;
1203+
data->drawstate.cliprect.y = 0;
1204+
} else {
1205+
data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
1206+
}
1207+
}
1208+
}
10691209
break;
10701210
}
10711211

10721212
case SDL_RENDERCMD_SETCLIPRECT:
10731213
{
10741214
const SDL_Rect *rect = &cmd->data.cliprect.rect;
1075-
if (cmd->data.cliprect.enabled) {
1076-
sceGuEnable(GU_SCISSOR_TEST);
1077-
sceGuScissor(rect->x, rect->y, rect->w, rect->h);
1078-
} else {
1079-
sceGuDisable(GU_SCISSOR_TEST);
1215+
const SDL_Rect *viewport = &data->drawstate.viewport;
1216+
if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
1217+
data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
1218+
data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
1219+
if (!data->drawstate.cliprect_enabled && data->drawstate.viewport_is_set) {
1220+
SDL_copyp(&data->drawstate.cliprect, viewport);
1221+
data->drawstate.cliprect.x = 0;
1222+
data->drawstate.cliprect.y = 0;
1223+
}
1224+
}
1225+
1226+
if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof(*rect)) != 0) {
1227+
SDL_copyp(&data->drawstate.cliprect, rect);
1228+
data->drawstate.cliprect_dirty = SDL_TRUE;
10801229
}
10811230
break;
10821231
}
@@ -1087,6 +1236,7 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
10871236
const Uint8 g = cmd->data.color.g;
10881237
const Uint8 b = cmd->data.color.b;
10891238
const Uint8 a = cmd->data.color.a;
1239+
SetDrawState(data);
10901240
sceGuClearColor(GU_RGBA(r, g, b, a));
10911241
sceGuClearStencil(a);
10921242
sceGuClear(GU_COLOR_BUFFER_BIT | GU_STENCIL_BUFFER_BIT);
@@ -1095,122 +1245,142 @@ static int PSP_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, v
10951245

10961246
case SDL_RENDERCMD_DRAW_POINTS:
10971247
{
1098-
const size_t count = cmd->data.draw.count;
1099-
const VertV *verts = (VertV *)(gpumem + cmd->data.draw.first);
11001248
const Uint8 r = cmd->data.draw.r;
11011249
const Uint8 g = cmd->data.draw.g;
11021250
const Uint8 b = cmd->data.draw.b;
11031251
const Uint8 a = cmd->data.draw.a;
1252+
const size_t count = cmd->data.draw.count;
1253+
VertV *verts = (VertV *)(gpumem + cmd->data.draw.first);
11041254
PSP_BlendState state = {
11051255
.color = GU_RGBA(r, g, b, a),
11061256
.texture = NULL,
11071257
.mode = cmd->data.draw.blend,
11081258
.shadeModel = GU_FLAT
11091259
};
1260+
SetDrawState(data);
1261+
PSP_SetViewportOffset(&data->drawstate, verts, count, SDL_TRUE);
11101262
PSP_SetBlendState(data, &state);
11111263
sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
1264+
PSP_SetViewportOffset(&data->drawstate, verts, count, SDL_FALSE);
11121265
break;
11131266
}
11141267

11151268
case SDL_RENDERCMD_DRAW_LINES:
11161269
{
1117-
const size_t count = cmd->data.draw.count;
1118-
const VertV *verts = (VertV *)(gpumem + cmd->data.draw.first);
11191270
const Uint8 r = cmd->data.draw.r;
11201271
const Uint8 g = cmd->data.draw.g;
11211272
const Uint8 b = cmd->data.draw.b;
11221273
const Uint8 a = cmd->data.draw.a;
1274+
const size_t count = cmd->data.draw.count;
1275+
VertV *verts = (VertV *)(gpumem + cmd->data.draw.first);
11231276
PSP_BlendState state = {
11241277
.color = GU_RGBA(r, g, b, a),
11251278
.texture = NULL,
11261279
.mode = cmd->data.draw.blend,
11271280
.shadeModel = GU_FLAT
11281281
};
1282+
SetDrawState(data);
1283+
PSP_SetViewportOffset(&data->drawstate, verts, count, SDL_TRUE);
11291284
PSP_SetBlendState(data, &state);
11301285
sceGuDrawArray(GU_LINE_STRIP, GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
1286+
PSP_SetViewportOffset(&data->drawstate, verts, count, SDL_FALSE);
11311287
break;
11321288
}
11331289

11341290
case SDL_RENDERCMD_FILL_RECTS:
11351291
{
1136-
const size_t count = cmd->data.draw.count;
1137-
const VertV *verts = (VertV *)(gpumem + cmd->data.draw.first);
11381292
const Uint8 r = cmd->data.draw.r;
11391293
const Uint8 g = cmd->data.draw.g;
11401294
const Uint8 b = cmd->data.draw.b;
11411295
const Uint8 a = cmd->data.draw.a;
1296+
const size_t count = cmd->data.draw.count;
1297+
VertV *verts = (VertV *)(gpumem + cmd->data.draw.first);
11421298
PSP_BlendState state = {
11431299
.color = GU_RGBA(r, g, b, a),
11441300
.texture = NULL,
11451301
.mode = cmd->data.draw.blend,
11461302
.shadeModel = GU_FLAT
11471303
};
1304+
SetDrawState(data);
1305+
PSP_SetViewportOffset(&data->drawstate, verts, 2 * count, SDL_TRUE);
11481306
PSP_SetBlendState(data, &state);
11491307
sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2 * count, 0, verts);
1308+
PSP_SetViewportOffset(&data->drawstate, verts, 2 * count, SDL_FALSE);
11501309
break;
11511310
}
11521311

11531312
case SDL_RENDERCMD_COPY:
11541313
{
1155-
const size_t count = cmd->data.draw.count;
1156-
const VertTV *verts = (VertTV *)(gpumem + cmd->data.draw.first);
11571314
const Uint8 a = cmd->data.draw.a;
11581315
const Uint8 r = cmd->data.draw.r;
11591316
const Uint8 g = cmd->data.draw.g;
11601317
const Uint8 b = cmd->data.draw.b;
1318+
const size_t count = cmd->data.draw.count;
1319+
VertTV *verts = (VertTV *)(gpumem + cmd->data.draw.first);
11611320
PSP_BlendState state = {
11621321
.color = GU_RGBA(r, g, b, a),
11631322
.texture = cmd->data.draw.texture,
11641323
.mode = cmd->data.draw.blend,
11651324
.shadeModel = GU_SMOOTH
11661325
};
1326+
SetDrawState(data);
1327+
PSP_SetViewportOffsetT(&data->drawstate, verts, 2 * count, SDL_TRUE);
11671328
PSP_SetBlendState(data, &state);
11681329
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2 * count, 0, verts);
1330+
PSP_SetViewportOffsetT(&data->drawstate, verts, 2 * count, SDL_FALSE);
11691331
break;
11701332
}
11711333

11721334
case SDL_RENDERCMD_COPY_EX:
11731335
{
1174-
const VertTV *verts = (VertTV *)(gpumem + cmd->data.draw.first);
11751336
const Uint8 a = cmd->data.draw.a;
11761337
const Uint8 r = cmd->data.draw.r;
11771338
const Uint8 g = cmd->data.draw.g;
11781339
const Uint8 b = cmd->data.draw.b;
1340+
VertTV *verts = (VertTV *)(gpumem + cmd->data.draw.first);
11791341
PSP_BlendState state = {
11801342
.color = GU_RGBA(r, g, b, a),
11811343
.texture = cmd->data.draw.texture,
11821344
.mode = cmd->data.draw.blend,
11831345
.shadeModel = GU_SMOOTH
11841346
};
1347+
SetDrawState(data);
1348+
PSP_SetViewportOffsetT(&data->drawstate, verts, 4, SDL_TRUE);
11851349
PSP_SetBlendState(data, &state);
11861350
sceGuDrawArray(GU_TRIANGLE_FAN, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 4, 0, verts);
1351+
PSP_SetViewportOffsetT(&data->drawstate, verts, 4, SDL_FALSE);
11871352
break;
11881353
}
11891354

11901355
case SDL_RENDERCMD_GEOMETRY:
11911356
{
11921357
const size_t count = cmd->data.draw.count;
1358+
SetDrawState(data);
11931359
if (!cmd->data.draw.texture) {
1194-
const VertCV *verts = (VertCV *)(gpumem + cmd->data.draw.first);
1360+
VertCV *verts = (VertCV *)(gpumem + cmd->data.draw.first);
1361+
PSP_SetViewportOffsetC(&data->drawstate, verts, count, SDL_TRUE);
11951362
sceGuDisable(GU_TEXTURE_2D);
11961363
/* In GU_SMOOTH mode */
11971364
sceGuDrawArray(GU_TRIANGLES, GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
11981365
sceGuEnable(GU_TEXTURE_2D);
1366+
PSP_SetViewportOffsetC(&data->drawstate, verts, count, SDL_FALSE);
11991367
} else {
1200-
const VertTCV *verts = (VertTCV *)(gpumem + cmd->data.draw.first);
12011368
const Uint8 a = cmd->data.draw.a;
12021369
const Uint8 r = cmd->data.draw.r;
12031370
const Uint8 g = cmd->data.draw.g;
12041371
const Uint8 b = cmd->data.draw.b;
1372+
VertTCV *verts = (VertTCV *)(gpumem + cmd->data.draw.first);
12051373
PSP_BlendState state = {
12061374
.color = GU_RGBA(r, g, b, a),
12071375
.texture = NULL,
12081376
.mode = cmd->data.draw.blend,
12091377
.shadeModel = GU_FLAT
12101378
};
1379+
PSP_SetViewportOffsetTC(&data->drawstate, verts, count, SDL_TRUE);
12111380
TextureActivate(cmd->data.draw.texture);
12121381
PSP_SetBlendState(data, &state);
12131382
sceGuDrawArray(GU_TRIANGLES, GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_VERTEX_32BITF | GU_TRANSFORM_2D, count, 0, verts);
1383+
PSP_SetViewportOffsetTC(&data->drawstate, verts, count, SDL_FALSE);
12141384
}
12151385
break;
12161386
}

0 commit comments

Comments
 (0)