From 7ece36c006eb7db78cde3776f270d3d92cfeb63f Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 9 Sep 2023 13:28:23 +1000 Subject: [PATCH] WIP PS3 stuff --- Makefile | 2 + src/Core.h | 6 + src/Graphics_Dreamcast.c | 2 - src/Graphics_PS3.c | 453 +++++++++++++++++++++++++++++++++++++ src/Makefile_PS3 | 124 ++++++++++ src/PackedCol.h | 26 +-- src/Platform_PS3.c | 476 +++++++++++++++++++++++++++++++++++++++ src/Window_PS3.c | 176 +++++++++++++++ 8 files changed, 1250 insertions(+), 15 deletions(-) create mode 100644 src/Graphics_PS3.c create mode 100644 src/Makefile_PS3 create mode 100644 src/Platform_PS3.c create mode 100644 src/Window_PS3.c diff --git a/Makefile b/Makefile index ac6f0f489..902599f41 100644 --- a/Makefile +++ b/Makefile @@ -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: diff --git a/src/Core.h b/src/Core.h index 97a7e7a19..34e9c9800 100644 --- a/src/Core.h +++ b/src/Core.h @@ -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 diff --git a/src/Graphics_Dreamcast.c b/src/Graphics_Dreamcast.c index e7db59ff1..c6b9a3c2a 100644 --- a/src/Graphics_Dreamcast.c +++ b/src/Graphics_Dreamcast.c @@ -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); } diff --git a/src/Graphics_PS3.c b/src/Graphics_PS3.c new file mode 100644 index 000000000..eadf17ee9 --- /dev/null +++ b/src/Graphics_PS3.c @@ -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 +#include +#include + +/* 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 \ No newline at end of file diff --git a/src/Makefile_PS3 b/src/Makefile_PS3 new file mode 100644 index 000000000..9c5b27a1a --- /dev/null +++ b/src/Makefile_PS3 @@ -0,0 +1,124 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +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 +#--------------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/PackedCol.h b/src/PackedCol.h index 6c84772a1..c91208c99 100644 --- a/src/PackedCol.h +++ b/src/PackedCol.h @@ -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) diff --git a/src/Platform_PS3.c b/src/Platform_PS3.c new file mode 100644 index 000000000..a37f755ec --- /dev/null +++ b/src/Platform_PS3.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 \ No newline at end of file diff --git a/src/Window_PS3.c b/src/Window_PS3.c new file mode 100644 index 000000000..36f353f20 --- /dev/null +++ b/src/Window_PS3.c @@ -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 +#include +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 \ No newline at end of file