WIP PS3 stuff

This commit is contained in:
UnknownShadow200 2023-09-09 13:28:23 +10:00
parent e6d1f593d2
commit 7ece36c006
8 changed files with 1250 additions and 15 deletions

View File

@ -147,6 +147,8 @@ psp:
$(MAKE) -f src/Makefile_PSP PLAT=psp
vita:
$(MAKE) -f src/Makefile_vita PLAT=vita
ps3:
$(MAKE) -f src/Makefile_PS3 PLAT=ps3
3ds:
$(MAKE) -f src/Makefile_3DS PLAT=3ds
wii:

View File

@ -292,6 +292,12 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_DREAMCAST
#define CC_BUILD_LOWMEM
#undef CC_BUILD_FREETYPE
#elif defined PLAT_PS3
#define CC_BUILD_HTTPCLIENT
#define CC_BUILD_OPENAL
#define CC_BUILD_PS3
#define CC_BUILD_LOWMEM
#undef CC_BUILD_FREETYPE
#endif
#endif

View File

@ -142,8 +142,6 @@ void Gfx_EndFrame(void) {
}
void Gfx_OnWindowResize(void) {
/* TODO: Eliminate this nasty hack.. */
Game_UpdateDimensions();
glViewport(0, 0, Game.Width, Game.Height);
}

453
src/Graphics_PS3.c Normal file
View File

@ -0,0 +1,453 @@
#include "Core.h"
#if defined CC_BUILD_PS3
#include "_GraphicsBase.h"
#include "Errors.h"
#include "Logger.h"
#include "Window.h"
#include <malloc.h>
#include <rsx/rsx.h>
#include <sysutil/video.h>
/* Current format and size of vertices */
static int gfx_stride, gfx_format = -1;
static cc_bool renderingDisabled;
static gcmContextData* context;
static u32 cur_fb = 0;
#define CB_SIZE 0x100000 // TODO: smaller command buffer?
#define HOST_SIZE (32 * 1024 * 1024)
/*########################################################################################################################*
*---------------------------------------------------------- setup---------------------------------------------------------*
*#########################################################################################################################*/
static u32 color_pitch;
static u32 color_offset[2];
static u32* color_buffer[2];
static u32 depth_pitch;
static u32 depth_offset;
static u32* depth_buffer;
static void Gfx_FreeState(void) { FreeDefaultResources(); }
static void Gfx_RestoreState(void) {
InitDefaultResources();
gfx_format = -1;/* TODO */
rsxSetColorMaskMrt(context, 0);
rsxSetDepthFunc(context, GCM_LEQUAL);
rsxSetClearDepthStencil(context, 0xFFFFFF);
}
static void CreateContext(void) {
void* host_addr = memalign(1024 * 1024, HOST_SIZE);
rsxInit(&context, CB_SIZE, HOST_SIZE, host_addr);
}
static void ConfigureVideo(void) {
videoState state;
videoGetState(0, 0, &state);
videoConfiguration vconfig = { 0 };
vconfig.resolution = state.displayMode.resolution;
vconfig.format = VIDEO_BUFFER_FORMAT_XRGB;
vconfig.pitch = DisplayInfo.Width * sizeof(u32);
videoConfigure(0, &vconfig, NULL, 0);
}
static void SetupBlendingState(void) {
rsxSetBlendFunc(context, GCM_SRC_ALPHA, GCM_ONE_MINUS_SRC_ALPHA, GCM_SRC_ALPHA, GCM_ONE_MINUS_SRC_ALPHA);
rsxSetBlendEquation(context, GCM_FUNC_ADD, GCM_FUNC_ADD);
}
static void AllocColorSurface(u32 i) {
color_pitch = DisplayInfo.Width * 4;
color_buffer[i] = (u32*)rsxMemalign(64, DisplayInfo.Height * color_pitch);
rsxAddressToOffset(color_buffer[i], &color_offset[i]);
gcmSetDisplayBuffer(i, color_offset[i], color_pitch,
DisplayInfo.Width, DisplayInfo.Height);
}
static void AllocDepthSurface(void) {
depth_pitch = DisplayInfo.Width * 4;
depth_buffer = (u32*)rsxMemalign(64, DisplayInfo.Height * depth_pitch);
rsxAddressToOffset(depth_buffer, &depth_offset);
}
/*########################################################################################################################*
*---------------------------------------------------------General---------------------------------------------------------*
*#########################################################################################################################*/
void SetRenderTarget(u32 index) {
gcmSurface sf;
sf.colorFormat = GCM_SURFACE_X8R8G8B8;
sf.colorTarget = GCM_SURFACE_TARGET_0;
sf.colorLocation[0] = GCM_LOCATION_RSX;
sf.colorOffset[0] = color_offset[index];
sf.colorPitch[0] = color_pitch;
sf.colorLocation[1] = GCM_LOCATION_RSX;
sf.colorLocation[2] = GCM_LOCATION_RSX;
sf.colorLocation[3] = GCM_LOCATION_RSX;
sf.colorOffset[1] = 0;
sf.colorOffset[2] = 0;
sf.colorOffset[3] = 0;
sf.colorPitch[1] = 64;
sf.colorPitch[2] = 64;
sf.colorPitch[3] = 64;
sf.depthFormat = GCM_SURFACE_ZETA_Z24S8;
sf.depthLocation = GCM_LOCATION_RSX;
sf.depthOffset = depth_offset;
sf.depthPitch = depth_pitch;
sf.type = GCM_SURFACE_TYPE_LINEAR;
sf.antiAlias = GCM_SURFACE_CENTER_1;
sf.width = DisplayInfo.Width;
sf.height = DisplayInfo.Height;
sf.x = 0;
sf.y = 0;
rsxSetSurface(context,&sf);
}
void Gfx_Create(void) {
// TODO rethink all this
if (Gfx.Created) return;
Gfx.MaxTexWidth = 1024;
Gfx.MaxTexHeight = 1024;
Gfx.Created = true;
// https://github.com/ps3dev/PSL1GHT/blob/master/ppu/include/rsx/rsx.h#L30
CreateContext();
ConfigureVideo();
gcmSetFlipMode(GCM_FLIP_VSYNC);
AllocColorSurface(0);
AllocColorSurface(1);
AllocDepthSurface();
gcmResetFlipStatus();
SetupBlendingState();
Gfx_RestoreState();
SetRenderTarget(cur_fb);
}
cc_bool Gfx_TryRestoreContext(void) { return true; }
cc_bool Gfx_WarnIfNecessary(void) { return false; }
void Gfx_Free(void) {
Gfx_FreeState();
}
u32* Gfx_AllocImage(u32* offset, s32 w, s32 h) {
u32* pixels = (u32*)rsxMemalign(64, w * h * 4);
rsxAddressToOffset(pixels, offset);
return pixels;
}
void Gfx_TransferImage(u32 offset, s32 w, s32 h) {
rsxSetTransferImage(context, GCM_TRANSFER_LOCAL_TO_LOCAL,
color_offset[cur_fb], color_pitch, -w/2, -h/2,
offset, w * 4, 0, 0, w, h, 4);
}
/*########################################################################################################################*
*-----------------------------------------------------State management----------------------------------------------------*
*#########################################################################################################################*/
static PackedCol gfx_clearColor;
void Gfx_SetFaceCulling(cc_bool enabled) {
rsxSetCullFaceEnable(context, enabled);
}
void Gfx_SetAlphaBlending(cc_bool enabled) {
rsxSetBlendEnable(context, enabled);
}
void Gfx_SetAlphaArgBlend(cc_bool enabled) { }
void Gfx_ClearCol(PackedCol color) {
rsxSetClearColor(context, color);
}
void Gfx_SetColWriteMask(cc_bool r, cc_bool g, cc_bool b, cc_bool a) {
unsigned mask = 0;
if (r) mask |= GCM_COLOR_MASK_R;
if (g) mask |= GCM_COLOR_MASK_G;
if (b) mask |= GCM_COLOR_MASK_B;
if (a) mask |= GCM_COLOR_MASK_A;
rsxSetColorMask(context, mask);
}
void Gfx_SetDepthWrite(cc_bool enabled) {
rsxSetDepthWriteEnable(context, enabled);
}
void Gfx_SetDepthTest(cc_bool enabled) {
rsxSetDepthTestEnable(context, enabled);
}
void Gfx_SetTexturing(cc_bool enabled) { }
void Gfx_SetAlphaTest(cc_bool enabled) { /* TODO */ }
void Gfx_DepthOnlyRendering(cc_bool depthOnly) {/* TODO */
}
/*########################################################################################################################*
*---------------------------------------------------------Matrices--------------------------------------------------------*
*#########################################################################################################################*/
void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float zNear, float zFar) {
/* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glortho */
/* The simplified calculation below uses: L = 0, R = width, T = 0, B = height */
*matrix = Matrix_Identity;
matrix->row1.X = 2.0f / width;
matrix->row2.Y = -2.0f / height;
matrix->row3.Z = -2.0f / (zFar - zNear);
matrix->row4.X = -1.0f;
matrix->row4.Y = 1.0f;
matrix->row4.Z = -(zFar + zNear) / (zFar - zNear);
}
static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); }
void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) {
float zNear = 0.1f;
float c = (float)Cotangent(0.5f * fov);
/* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum */
/* For a FOV based perspective matrix, left/right/top/bottom are calculated as: */
/* left = -c * aspect, right = c * aspect, bottom = -c, top = c */
/* Calculations are simplified because of left/right and top/bottom symmetry */
*matrix = Matrix_Identity;
matrix->row1.X = c / aspect;
matrix->row2.Y = c;
matrix->row3.Z = -(zFar + zNear) / (zFar - zNear);
matrix->row3.W = -1.0f;
matrix->row4.Z = -(2.0f * zFar * zNear) / (zFar - zNear);
matrix->row4.W = 0.0f;
}
/*########################################################################################################################*
*-----------------------------------------------------------Misc----------------------------------------------------------*
*#########################################################################################################################*/
cc_result Gfx_TakeScreenshot(struct Stream* output) {
return ERR_NOT_SUPPORTED;
}
void Gfx_GetApiInfo(cc_string* info) {
int pointerSize = sizeof(void*) * 8;
String_Format1(info, "-- Using PS3 (%i bit) --\n", &pointerSize);
String_Format2(info, "Max texture size: (%i, %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight);
}
void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) {
gfx_minFrameMs = minFrameMs;
gfx_vsync = vsync;
}
// https://github.com/ps3dev/PSL1GHT/blob/master/ppu/include/rsx/rsx.h#L30
static cc_bool everFlipped;
void Gfx_BeginFrame(void) {
// TODO: remove everFlipped
if (everFlipped) {
while (gcmGetFlipStatus() != 0) usleep(200);
}
everFlipped = true;
gcmResetFlipStatus();
}
void Gfx_Clear(void) {
rsxClearSurface(context, GCM_CLEAR_R | GCM_CLEAR_G | GCM_CLEAR_B | GCM_CLEAR_A
| GCM_CLEAR_S | GCM_CLEAR_Z);
}
void Gfx_EndFrame(void) {
gcmSetFlip(context, cur_fb);
rsxFlushBuffer(context);
gcmSetWaitFlip(context);
cur_fb ^= 1;
SetRenderTarget(cur_fb);
if (gfx_minFrameMs) LimitFPS();
}
void Gfx_OnWindowResize(void) {/* TODO */
}
/*########################################################################################################################*
*-------------------------------------------------------Index buffers-----------------------------------------------------*
*#########################################################################################################################*/
static void* gfx_vertices;
static int vb_size;
GfxResourceID Gfx_CreateIb2(int count, Gfx_FillIBFunc fillFunc, void* obj) {
return 1;/* TODO */
}
void Gfx_BindIb(GfxResourceID ib) { }
void Gfx_DeleteIb(GfxResourceID* ib) { }
/*########################################################################################################################*
*------------------------------------------------------Vertex buffers-----------------------------------------------------*
*#########################################################################################################################*/
GfxResourceID Gfx_CreateVb(VertexFormat fmt, int count) {
void* data = memalign(16, count * strideSizes[fmt]);
if (!data) Logger_Abort("Failed to allocate memory for GFX VB");
return data;
//return Mem_Alloc(count, strideSizes[fmt], "gfx VB");/* TODO */
}
void Gfx_BindVb(GfxResourceID vb) { gfx_vertices = vb;/* TODO */ }
void Gfx_DeleteVb(GfxResourceID* vb) {
GfxResourceID data = *vb;/* TODO */
if (data) Mem_Free(data);
*vb = 0;
}
void* Gfx_LockVb(GfxResourceID vb, VertexFormat fmt, int count) {
vb_size = count * strideSizes[fmt];/* TODO */
return vb;
}
void Gfx_UnlockVb(GfxResourceID vb) {
gfx_vertices = vb;/* TODO */
//sceKernelDcacheWritebackInvalidateRange(vb, vb_size);
}
GfxResourceID Gfx_CreateDynamicVb(VertexFormat fmt, int maxVertices) {
void* data = memalign(16, maxVertices * strideSizes[fmt]);
if (!data) Logger_Abort("Failed to allocate memory for GFX VB");
return data;/* TODO */
//return Mem_Alloc(maxVertices, strideSizes[fmt], "gfx VB");
}
void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) {
vb_size = count * strideSizes[fmt];
return vb; /* TODO */
}
void Gfx_UnlockDynamicVb(GfxResourceID vb) {
gfx_vertices = vb; /* TODO */
//dcache_flush_range(vb, vb_size);
}
void Gfx_SetDynamicVbData(GfxResourceID vb, void* vertices, int vCount) {
gfx_vertices = vb;/* TODO */
Mem_Copy(vb, vertices, vCount * gfx_stride);
//dcache_flush_range(vertices, vCount * gfx_stride);
}
/*########################################################################################################################*
*---------------------------------------------------------Textures--------------------------------------------------------*
*#########################################################################################################################*/
void Gfx_BindTexture(GfxResourceID texId) {
/* TODO */
}
void Gfx_DeleteTexture(GfxResourceID* texId) {
/* TODO */
}
void Gfx_EnableMipmaps(void) { }
void Gfx_DisableMipmaps(void) { }
GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps) {
return 1;/* TODO */
}
void Gfx_UpdateTexture(GfxResourceID texId, int x, int y, struct Bitmap* part, int rowWidth, cc_bool mipmaps) {
/* TODO */
}
void Gfx_UpdateTexturePart(GfxResourceID texId, int x, int y, struct Bitmap* part, cc_bool mipmaps) {
Gfx_UpdateTexture(texId, x, y, part, part->width, mipmaps);
}
/*########################################################################################################################*
*-----------------------------------------------------State management----------------------------------------------------*
*#########################################################################################################################*/
static PackedCol gfx_fogColor;
static float gfx_fogEnd = 16.0f, gfx_fogDensity = 1.0f;
static FogFunc gfx_fogMode = -1;
void Gfx_SetFog(cc_bool enabled) {/* TODO */
}
void Gfx_SetFogCol(PackedCol color) {/* TODO */
}
void Gfx_SetFogDensity(float value) {/* TODO */
}
void Gfx_SetFogEnd(float value) {/* TODO */
}
void Gfx_SetFogMode(FogFunc func) {/* TODO */
}
/*########################################################################################################################*
*---------------------------------------------------------Matrices--------------------------------------------------------*
*#########################################################################################################################*/
void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) {
/* TODO */
}
void Gfx_LoadIdentityMatrix(MatrixType type) {
Gfx_LoadMatrix(type, &Matrix_Identity);
}
void Gfx_EnableTextureOffset(float x, float y) {
/* TODO */
}
void Gfx_DisableTextureOffset(void) {
/* TODO */
}
/*########################################################################################################################*
*----------------------------------------------------------Drawing--------------------------------------------------------*
*#########################################################################################################################*/
void Gfx_SetVertexFormat(VertexFormat fmt) {
if (fmt == gfx_format) return;
gfx_format = fmt;
gfx_stride = strideSizes[fmt];/* TODO */
}
void Gfx_DrawVb_Lines(int verticesCount) {/* TODO */
}
void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) {/* TODO */
}
void Gfx_DrawVb_IndexedTris(int verticesCount) {/* TODO */
}
void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) {/* TODO */
}
#endif

124
src/Makefile_PS3 Normal file
View File

@ -0,0 +1,124 @@
#---------------------------------------------------------------------------------
# Clear the implicit built in rules
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(PSL1GHT)),)
$(error "Please set PSL1GHT in your environment. export PSL1GHT=<path>")
endif
include $(PSL1GHT)/ppu_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET := ClassiCube-PS3
BUILD := build-ps3
SOURCES := src
INCLUDES :=
TITLE := ClassiCube
APPID := CUBE00200
CONTENTID := UP0001-$(APPID)_00-0000000000000000
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -O2 -DPLAT_PS3 -Wall -mcpu=cell $(MACHDEP) $(INCLUDE)
CXXFLAGS = $(CFLAGS)
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lrsx -lgcm_sys -lio -lsysutil -lrt -llv2 -lm -lnet -lsysmodule
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
export BUILDDIR := $(CURDIR)/$(BUILD)
#---------------------------------------------------------------------------------
# automatically build a list of object files for our project
#---------------------------------------------------------------------------------
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
export LD := $(CC)
export OFILES := $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o)
#---------------------------------------------------------------------------------
# build a list of include paths
#---------------------------------------------------------------------------------
export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
$(LIBPSL1GHT_INC) \
-I$(CURDIR)/$(BUILD)
#---------------------------------------------------------------------------------
# build a list of library paths
#---------------------------------------------------------------------------------
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
$(LIBPSL1GHT_LIB)
export OUTPUT := $(CURDIR)/$(TARGET)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/src/Makefile_PS3
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).self
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).self: $(OUTPUT).elf
$(OUTPUT).elf: $(OFILES)
#---------------------------------------------------------------------------------
# This rule links in binary data with the .bin extension
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------

View File

@ -6,21 +6,21 @@
*/
typedef cc_uint32 PackedCol;
#if defined CC_BUILD_D3D9 || defined CC_BUILD_XBOX || defined CC_BUILD_DREAMCAST
#define PACKEDCOL_B_SHIFT 0
#define PACKEDCOL_G_SHIFT 8
#define PACKEDCOL_R_SHIFT 16
#define PACKEDCOL_A_SHIFT 24
#if defined CC_BUILD_D3D9 || defined CC_BUILD_XBOX || defined CC_BUILD_DREAMCAST || defined CC_BUILD_PS3
#define PACKEDCOL_B_SHIFT 0
#define PACKEDCOL_G_SHIFT 8
#define PACKEDCOL_R_SHIFT 16
#define PACKEDCOL_A_SHIFT 24
#elif defined CC_BIG_ENDIAN
#define PACKEDCOL_R_SHIFT 24
#define PACKEDCOL_G_SHIFT 16
#define PACKEDCOL_B_SHIFT 8
#define PACKEDCOL_A_SHIFT 0
#define PACKEDCOL_R_SHIFT 24
#define PACKEDCOL_G_SHIFT 16
#define PACKEDCOL_B_SHIFT 8
#define PACKEDCOL_A_SHIFT 0
#else
#define PACKEDCOL_R_SHIFT 0
#define PACKEDCOL_G_SHIFT 8
#define PACKEDCOL_B_SHIFT 16
#define PACKEDCOL_A_SHIFT 24
#define PACKEDCOL_R_SHIFT 0
#define PACKEDCOL_G_SHIFT 8
#define PACKEDCOL_B_SHIFT 16
#define PACKEDCOL_A_SHIFT 24
#endif
#define PACKEDCOL_R_MASK (0xFFU << PACKEDCOL_R_SHIFT)

476
src/Platform_PS3.c Normal file
View File

@ -0,0 +1,476 @@
#include "Core.h"
#if defined PLAT_PS3
#include "_PlatformBase.h"
#include "Stream.h"
#include "ExtMath.h"
#include "Funcs.h"
#include "Window.h"
#include "Utils.h"
#include "Errors.h"
#include "PackedCol.h"
#include <errno.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <utime.h>
#include <signal.h>
#include <net/net.h>
#include <net/poll.h>
#include <ppu-lv2.h>
#include <sys/lv2errno.h>
#include <sys/mutex.h>
#include <sys/sem.h>
#include <sys/thread.h>
#include <sys/systime.h>
#include <sys/tty.h>
#include "_PlatformConsole.h"
const cc_result ReturnCode_FileShareViolation = 1000000000; // not used
const cc_result ReturnCode_FileNotFound = 0x80010006; // ENOENT;
//const cc_result ReturnCode_SocketInProgess = 0x80010032; // EINPROGRESS
//const cc_result ReturnCode_SocketWouldBlock = 0x80010001; // EWOULDBLOCK;
const cc_result ReturnCode_DirectoryExists = 0x80010014; // EEXIST
const cc_result ReturnCode_SocketInProgess = NET_EINPROGRESS;
const cc_result ReturnCode_SocketWouldBlock = NET_EWOULDBLOCK;
const char* Platform_AppNameSuffix = " PS3";
/*########################################################################################################################*
*------------------------------------------------------Logging/Time-------------------------------------------------------*
*#########################################################################################################################*/
void Platform_Log(const char* msg, int len) {
u32 done = 0;
sysTtyWrite(STDOUT_FILENO, msg, len, &done);
sysTtyWrite(STDOUT_FILENO, "\n", 1, &done);
}
#define UnixTime_TotalMS(time) ((cc_uint64)time.tv_sec * 1000 + UNIX_EPOCH + (time.tv_usec / 1000))
TimeMS DateTime_CurrentUTC_MS(void) {
struct timeval cur;
gettimeofday(&cur, NULL);
return UnixTime_TotalMS(cur);
}
void DateTime_CurrentLocal(struct DateTime* t) {
struct timeval cur;
struct tm loc_time;
gettimeofday(&cur, NULL);
localtime_r(&cur.tv_sec, &loc_time);
t->year = loc_time.tm_year + 1900;
t->month = loc_time.tm_mon + 1;
t->day = loc_time.tm_mday;
t->hour = loc_time.tm_hour;
t->minute = loc_time.tm_min;
t->second = loc_time.tm_sec;
}
/*########################################################################################################################*
*--------------------------------------------------------Stopwatch--------------------------------------------------------*
*#########################################################################################################################*/
#define NS_PER_SEC 1000000000ULL
cc_uint64 Stopwatch_Measure(void) {
u64 sec, nsec;
sysGetCurrentTime(&sec, &nsec);
return sec * NS_PER_SEC + nsec;
}
cc_uint64 Stopwatch_ElapsedMicroseconds(cc_uint64 beg, cc_uint64 end) {
if (end < beg) return 0;
return (end - beg) / 1000;
}
/*########################################################################################################################*
*-----------------------------------------------------Directory/File------------------------------------------------------*
*#########################################################################################################################*/
cc_result Directory_Create(const cc_string* path) {
char str[NATIVE_STR_LEN];
String_EncodeUtf8(str, path);
/* read/write/search permissions for owner and group, and with read/search permissions for others. */
/* TODO: Is the default mode in all cases */
return mkdir(str, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1 ? errno : 0;
}
int File_Exists(const cc_string* path) {
char str[NATIVE_STR_LEN];
struct stat sb;
String_EncodeUtf8(str, path);
return stat(str, &sb) == 0 && S_ISREG(sb.st_mode);
}
cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCallback callback) {
cc_string path; char pathBuffer[FILENAME_SIZE];
char str[NATIVE_STR_LEN];
DIR* dirPtr;
struct dirent* entry;
char* src;
int len, res, is_dir;
String_EncodeUtf8(str, dirPath);
dirPtr = opendir(str);
if (!dirPtr) return errno;
/* POSIX docs: "When the end of the directory is encountered, a null pointer is returned and errno is not changed." */
/* errno is sometimes leftover from previous calls, so always reset it before readdir gets called */
errno = 0;
String_InitArray(path, pathBuffer);
while ((entry = readdir(dirPtr))) {
path.length = 0;
String_Format1(&path, "%s/", dirPath);
/* ignore . and .. entry */
src = entry->d_name;
if (src[0] == '.' && src[1] == '\0') continue;
if (src[0] == '.' && src[1] == '.' && src[2] == '\0') continue;
len = String_Length(src);
String_AppendUtf8(&path, src, len);
#if defined CC_BUILD_HAIKU || defined CC_BUILD_SOLARIS || defined CC_BUILD_IRIX || defined CC_BUILD_BEOS
{
char full_path[NATIVE_STR_LEN];
struct stat sb;
String_EncodeUtf8(full_path, &path);
is_dir = stat(full_path, &sb) == 0 && S_ISDIR(sb.st_mode);
}
#else
is_dir = entry->d_type == DT_DIR;
/* TODO: fallback to stat when this fails */
#endif
if (is_dir) {
res = Directory_Enum(&path, obj, callback);
if (res) { closedir(dirPtr); return res; }
} else {
callback(&path, obj);
}
errno = 0;
}
res = errno; /* return code from readdir */
closedir(dirPtr);
return res;
}
static cc_result File_Do(cc_file* file, const cc_string* path, int mode) {
char str[NATIVE_STR_LEN];
String_EncodeUtf8(str, path);
*file = open(str, mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
return *file == -1 ? errno : 0;
}
cc_result File_Open(cc_file* file, const cc_string* path) {
return File_Do(file, path, O_RDONLY);
}
cc_result File_Create(cc_file* file, const cc_string* path) {
return File_Do(file, path, O_RDWR | O_CREAT | O_TRUNC);
}
cc_result File_OpenOrCreate(cc_file* file, const cc_string* path) {
return File_Do(file, path, O_RDWR | O_CREAT);
}
cc_result File_Read(cc_file file, void* data, cc_uint32 count, cc_uint32* bytesRead) {
*bytesRead = read(file, data, count);
return *bytesRead == -1 ? errno : 0;
}
cc_result File_Write(cc_file file, const void* data, cc_uint32 count, cc_uint32* bytesWrote) {
*bytesWrote = write(file, data, count);
return *bytesWrote == -1 ? errno : 0;
}
cc_result File_Close(cc_file file) {
return close(file) == -1 ? errno : 0;
}
cc_result File_Seek(cc_file file, int offset, int seekType) {
static cc_uint8 modes[3] = { SEEK_SET, SEEK_CUR, SEEK_END };
return lseek(file, offset, modes[seekType]) == -1 ? errno : 0;
}
cc_result File_Position(cc_file file, cc_uint32* pos) {
*pos = lseek(file, 0, SEEK_CUR);
return *pos == -1 ? errno : 0;
}
cc_result File_Length(cc_file file, cc_uint32* len) {
struct stat st;
if (fstat(file, &st) == -1) { *len = -1; return errno; }
*len = st.st_size; return 0;
}
/*########################################################################################################################*
*--------------------------------------------------------Threading--------------------------------------------------------*
*#########################################################################################################################*/
void Thread_Sleep(cc_uint32 milliseconds) {
sysUsleep(milliseconds * 1000);
}
static void ExecThread(void* param) {
((Thread_StartFunc)param)();
}
#define STACK_SIZE (128 * 1024)
void* Thread_Create(Thread_StartFunc func) {
return Mem_Alloc(1, sizeof(sys_ppu_thread_t), "thread");
}
void Thread_Start2(void* handle, Thread_StartFunc func) {
sys_ppu_thread_t* thread = (sys_ppu_thread_t*)handle;
int res = sysThreadCreate(thread, ExecThread, (void*)func,
0, STACK_SIZE, THREAD_JOINABLE, "CC thread");
if (res) Logger_Abort2(res, "Creating thread");
}
void Thread_Detach(void* handle) {
sys_ppu_thread_t* thread = (sys_ppu_thread_t*)handle;
int res = sysThreadDetach(*thread);
if (res) Logger_Abort2(res, "Detaching thread");
Mem_Free(thread);
}
void Thread_Join(void* handle) {
u64 retVal;
sys_ppu_thread_t* thread = (sys_ppu_thread_t*)handle;
int res = sysThreadJoin(*thread, &retVal);
if (res) Logger_Abort2(res, "Joining thread");
Mem_Free(thread);
}
void* Mutex_Create(void) {
sys_mutex_attr_t attr;
sysMutexAttrInitialize(attr);
sys_mutex_t* mutex = (sys_mutex_t*)Mem_Alloc(1, sizeof(sys_mutex_t), "mutex");
int res = sysMutexCreate(mutex, &attr);
if (res) Logger_Abort2(res, "Creating mutex");
return mutex;
}
void Mutex_Free(void* handle) {
sys_mutex_t* mutex = (sys_mutex_t*)handle;
int res = sysMutexDestroy(*mutex);
if (res) Logger_Abort2(res, "Destroying mutex");
Mem_Free(mutex);
}
void Mutex_Lock(void* handle) {
sys_mutex_t* mutex = (sys_mutex_t*)handle;
int res = sysMutexLock(*mutex, 0);
if (res) Logger_Abort2(res, "Locking mutex");
}
void Mutex_Unlock(void* handle) {
sys_mutex_t* mutex = (sys_mutex_t*)handle;
int res = sysMutexUnlock(*mutex);
if (res) Logger_Abort2(res, "Unlocking mutex");
}
void* Waitable_Create(void) {
sys_sem_attr_t attr = { 0 };
attr.attr_protocol = SYS_SEM_ATTR_PROTOCOL;
attr.attr_pshared = SYS_SEM_ATTR_PSHARED;
sys_sem_t* sem = (sys_sem_t*)Mem_Alloc(1, sizeof(sys_sem_t), "waitable");
int res = sysSemCreate(sem, &attr, 0, 1000000);
if (res) Logger_Abort2(res, "Creating waitable");
return sem;
}
void Waitable_Free(void* handle) {
sys_sem_t* sem = (sys_sem_t*)handle;
int res = sysSemDestroy(*sem);
if (res) Logger_Abort2(res, "Destroying waitable");
Mem_Free(sem);
}
void Waitable_Signal(void* handle) {
sys_sem_t* sem = (sys_sem_t*)handle;
int res = sysSemPost(*sem, 1);
if (res) Logger_Abort2(res, "Signalling event");
}
void Waitable_Wait(void* handle) {
sys_sem_t* sem = (sys_sem_t*)handle;
int res = sysSemWait(*sem, 0);
if (res) Logger_Abort2(res, "Waitable wait");
}
void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) {
sys_sem_t* sem = (sys_sem_t*)handle;
int res = sysSemWait(*sem, milliseconds * 1000);
if (res) Logger_Abort2(res, "Waitable wait for");
}
/*########################################################################################################################*
*---------------------------------------------------------Socket----------------------------------------------------------*
*#########################################################################################################################*/
union SocketAddress {
struct sockaddr raw;
struct sockaddr_in v4;
};
static int ParseHost(union SocketAddress* addr, const char* host) {
struct net_hostent* res = netGetHostByName(host);
if (!res) return net_h_errno;
// Must have at least one IPv4 address
if (res->h_addrtype != AF_INET) return ERR_INVALID_ARGUMENT;
if (!res->h_addr_list) return ERR_INVALID_ARGUMENT;
// TODO probably wrong....
addr->v4.sin_addr = *(struct in_addr*)&res->h_addr_list;
return 0;
}
static int ParseAddress(union SocketAddress* addr, const cc_string* address) {
char str[NATIVE_STR_LEN];
String_EncodeUtf8(str, address);
if (inet_aton(str, &addr->v4.sin_addr) > 0) return 0;
return ParseHost(addr, str);
}
int Socket_ValidAddress(const cc_string* address) {
union SocketAddress addr;
return ParseAddress(&addr, address) == 0;
}
cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) {
union SocketAddress addr;
int res;
*s = -1;
res = ParseAddress(&addr, address);
if (res) return res;
res = sysNetSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (res < 0) return res;
*s = res;
// TODO: RPCS3 makes sockets non blocking by default anyways ?
/*if (nonblocking) {
int blocking_raw = -1;
ioctl(*s, FIONBIO, &blocking_raw);
}*/
addr.v4.sin_family = AF_INET;
addr.v4.sin_port = htons(port);
return sysNetConnect(*s, &addr.raw, sizeof(addr.v4));
}
cc_result Socket_Read(cc_socket s, cc_uint8* data, cc_uint32 count, cc_uint32* modified) {
int res = sysNetRecvfrom(s, data, count, 0, NULL, NULL);
if (res < 0) return res;
*modified = res; return 0;
}
cc_result Socket_Write(cc_socket s, const cc_uint8* data, cc_uint32 count, cc_uint32* modified) {
int res = sysNetSendto(s, data, count, 0, NULL, 0);
if (res < 0) return res;
*modified = res; return 0;
}
void Socket_Close(cc_socket s) {
sysNetShutdown(s, SHUT_RDWR);
sysNetClose(s);
}
LV2_SYSCALL CC_sysNetPoll(struct pollfd* fds, s32 nfds, s32 ms)
{
lv2syscall3(715, (u64)fds, nfds, ms);
return_to_user_prog(s32);
}
static cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) {
struct pollfd pfd;
int flags, res;
pfd.fd = s;
pfd.events = mode == SOCKET_POLL_READ ? POLLIN : POLLOUT;
res = CC_sysNetPoll(&pfd, 1, 0);
if (res) return res;
/* to match select, closed socket still counts as readable */
flags = mode == SOCKET_POLL_READ ? (POLLIN | POLLHUP) : POLLOUT;
*success = (pfd.revents & flags) != 0;
return 0;
}
cc_result Socket_CheckReadable(cc_socket s, cc_bool* readable) {
return Socket_Poll(s, SOCKET_POLL_READ, readable);
}
cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) {
socklen_t resultSize = sizeof(socklen_t);
cc_result res = Socket_Poll(s, SOCKET_POLL_WRITE, writable);
if (res || *writable) return res;
/* https://stackoverflow.com/questions/29479953/so-error-value-after-successful-socket-operation */
netGetSockOpt(s, SOL_SOCKET, SO_ERROR, &res, &resultSize);
return res;
}
/*########################################################################################################################*
*--------------------------------------------------------Platform---------------------------------------------------------*
*#########################################################################################################################*/
cc_result Process_StartOpen(const cc_string* args) {
return ERR_NOT_SUPPORTED;
}
void Platform_Init(void) {
netInitialize();
}
void Platform_Free(void) { }
cc_bool Platform_DescribeError(cc_result res, cc_string* dst) {
char chars[NATIVE_STR_LEN];
int len;
/* For unrecognised error codes, strerror_r might return messages */
/* such as 'No error information', which is not very useful */
/* (could check errno here but quicker just to skip entirely) */
if (res >= 1000) return false;
len = strerror_r(res, chars, NATIVE_STR_LEN);
if (len == -1) return false;
len = String_CalcLen(chars, NATIVE_STR_LEN);
String_AppendUtf8(dst, chars, len);
return true;
}
/*########################################################################################################################*
*-------------------------------------------------------Encryption--------------------------------------------------------*
*#########################################################################################################################*/
static cc_result GetMachineID(cc_uint32* key) {
return ERR_NOT_SUPPORTED;
}
#endif

176
src/Window_PS3.c Normal file
View File

@ -0,0 +1,176 @@
#include "Core.h"
#if defined CC_BUILD_PS3
#include "Window.h"
#include "Platform.h"
#include "Input.h"
#include "Event.h"
#include "Graphics.h"
#include "String.h"
#include "Funcs.h"
#include "Bitmap.h"
#include "Errors.h"
#include "ExtMath.h"
#include "Logger.h"
#include <io/pad.h>
#include <sysutil/video.h>
static cc_bool launcherMode;
static padInfo pad_info;
static padData pad_data;
struct _DisplayData DisplayInfo;
struct _WinData WindowInfo;
// no DPI scaling on PS Vita
int Display_ScaleX(int x) { return x; }
int Display_ScaleY(int y) { return y; }
void Window_Init(void) {
videoState state;
videoResolution resolution;
videoGetState(0, 0, &state);
videoGetResolution(state.displayMode.resolution, &resolution);
DisplayInfo.Width = resolution.width;
DisplayInfo.Height = resolution.height;
DisplayInfo.Depth = 4; // 32 bit
DisplayInfo.ScaleX = 1;
DisplayInfo.ScaleY = 1;
WindowInfo.Width = resolution.width;
WindowInfo.Height = resolution.height;
WindowInfo.Focused = true;
WindowInfo.Exists = true;
Input.Sources = INPUT_SOURCE_GAMEPAD;
ioPadInit(7);
}
void Window_Create2D(int width, int height) {
launcherMode = true;
Gfx_Create(); // launcher also uses RSX to draw
}
void Window_Create3D(int width, int height) {
launcherMode = false;
}
void Window_SetTitle(const cc_string* title) { }
void Clipboard_GetText(cc_string* value) { } // TODO sceClipboardGetText
void Clipboard_SetText(const cc_string* value) { } // TODO sceClipboardSetText
int Window_GetWindowState(void) { return WINDOW_STATE_FULLSCREEN; }
cc_result Window_EnterFullscreen(void) { return 0; }
cc_result Window_ExitFullscreen(void) { return 0; }
int Window_IsObscured(void) { return 0; }
void Window_Show(void) { }
void Window_SetSize(int width, int height) { }
void Window_Close(void) {
/* TODO implement */
}
/*########################################################################################################################*
*----------------------------------------------------Input processing-----------------------------------------------------*
*#########################################################################################################################*/
static void HandleButtons(padData* data) {
Input_SetNonRepeatable(CCPAD_A, data->BTN_TRIANGLE);
Input_SetNonRepeatable(CCPAD_B, data->BTN_SQUARE);
Input_SetNonRepeatable(CCPAD_X, data->BTN_CROSS);
Input_SetNonRepeatable(CCPAD_Y, data->BTN_CIRCLE);
Input_SetNonRepeatable(CCPAD_START, data->BTN_START);
Input_SetNonRepeatable(CCPAD_SELECT, data->BTN_SELECT);
Input_SetNonRepeatable(CCPAD_LEFT, data->BTN_LEFT);
Input_SetNonRepeatable(CCPAD_RIGHT, data->BTN_RIGHT);
Input_SetNonRepeatable(CCPAD_UP, data->BTN_UP);
Input_SetNonRepeatable(CCPAD_DOWN, data->BTN_DOWN);
Input_SetNonRepeatable(CCPAD_L, data->BTN_L1);
Input_SetNonRepeatable(CCPAD_R, data->BTN_R1);
Input_SetNonRepeatable(CCPAD_ZL, data->BTN_L2);
Input_SetNonRepeatable(CCPAD_ZR, data->BTN_R2);
}
static void ProcessPadInput(double delta, padData* pad) {
HandleButtons(pad);
//if (Input.RawMode)
// ProcessCircleInput(&pad, delta);
}
void Window_ProcessEvents(double delta) {
ioPadGetInfo(&pad_info);
if (pad_info.status[0]) {
ioPadGetData(0, &pad_data);
ProcessPadInput(delta, &pad_data);
}
}
void Cursor_SetPosition(int x, int y) { } // Makes no sense for PS Vita
void Window_EnableRawMouse(void) { Input.RawMode = true; }
void Window_UpdateRawMouse(void) { }
void Window_DisableRawMouse(void) { Input.RawMode = false; }
/*########################################################################################################################*
*------------------------------------------------------Framebuffer--------------------------------------------------------*
*#########################################################################################################################*/
static struct Bitmap fb_bmp;
static u32 fb_offset;
extern u32* Gfx_AllocImage(u32* offset, s32 w, s32 h);
extern void Gfx_TransferImage(u32 offset, s32 w, s32 h);
void Window_AllocFramebuffer(struct Bitmap* bmp) {
u32* pixels = Gfx_AllocImage(&fb_offset, bmp->width, bmp->height);
bmp->scan0 = pixels;
fb_bmp = *bmp;
}
void Window_DrawFramebuffer(Rect2D r) {
// TODO test
Thread_Sleep(1000);
Platform_Log1("FRAME START (%h)", &fb_offset);
Gfx_BeginFrame();
Gfx_ClearCol(PackedCol_Make(0x40, 0x60, 0x80, 0xFF));
Gfx_Clear();
Gfx_TransferImage(fb_offset, fb_bmp.width, fb_bmp.height);
Gfx_EndFrame();
Platform_LogConst("FRAME END");
}
void Window_FreeFramebuffer(struct Bitmap* bmp) {
//Mem_Free(bmp->scan0);
/* TODO free framebuffer */
}
/*########################################################################################################################*
*------------------------------------------------------Soft keyboard------------------------------------------------------*
*#########################################################################################################################*/
void Window_OpenKeyboard(struct OpenKeyboardArgs* args) { /* TODO implement */ }
void Window_SetKeyboardText(const cc_string* text) { }
void Window_CloseKeyboard(void) { /* TODO implement */ }
/*########################################################################################################################*
*-------------------------------------------------------Misc/Other--------------------------------------------------------*
*#########################################################################################################################*/
void Window_ShowDialog(const char* title, const char* msg) {
/* TODO implement */
Platform_LogConst(title);
Platform_LogConst(msg);
}
cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
return ERR_NOT_SUPPORTED;
}
cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
return ERR_NOT_SUPPORTED;
}
#endif