diff --git a/src/ClassiCube.vcxproj b/src/ClassiCube.vcxproj index bc22d758b..92c6ce1e5 100644 --- a/src/ClassiCube.vcxproj +++ b/src/ClassiCube.vcxproj @@ -470,6 +470,7 @@ + diff --git a/src/ClassiCube.vcxproj.filters b/src/ClassiCube.vcxproj.filters index 6f062f985..0efffd4e7 100644 --- a/src/ClassiCube.vcxproj.filters +++ b/src/ClassiCube.vcxproj.filters @@ -659,6 +659,9 @@ Source Files\Graphics + + Source Files\Graphics + diff --git a/src/Graphics_PSVita.c b/src/Graphics_PSVita.c new file mode 100644 index 000000000..4e9ac3a96 --- /dev/null +++ b/src/Graphics_PSVita.c @@ -0,0 +1,529 @@ +#include "Core.h" +#if defined CC_BUILD_PSVITA +#include "_GraphicsBase.h" +#include "Errors.h" +#include "Logger.h" +#include "Window.h" +#include +/* Current format and size of vertices */ +static int gfx_stride, gfx_format = -1; + +#define DISPLAY_WIDTH 960 +#define DISPLAY_HEIGHT 544 +#define DISPLAY_STRIDE 1024 + +#define NUM_DISPLAY_BUFFERS 2 +#define MAX_PENDING_SWAPS (NUM_DISPLAY_BUFFERS - 1) + +static SceGxmContext* gxm_context; + +static SceUID vdm_ring_buffer_uid; +static void* vdm_ring_buffer_addr; +static SceUID vertex_ring_buffer_uid; +static void* vertex_ring_buffer_addr; +static SceUID fragment_ring_buffer_uid; +static void* fragment_ring_buffer_addr; +static SceUID fragment_usse_ring_buffer_uid; +static void* fragment_usse_ring_buffer_addr; +static unsigned int fragment_usse_offset; + +static SceGxmRenderTarget* gxm_render_target; +static SceGxmColorSurface gxm_color_surfaces[NUM_DISPLAY_BUFFERS]; +static SceUID gxm_color_surfaces_uid[NUM_DISPLAY_BUFFERS]; +static void* gxm_color_surfaces_addr[NUM_DISPLAY_BUFFERS]; +static SceGxmSyncObject* gxm_sync_objects[NUM_DISPLAY_BUFFERS]; + +static SceUID gxm_depth_stencil_surface_uid; +static void* gxm_depth_stencil_surface_addr; +static SceGxmDepthStencilSurface gxm_depth_stencil_surface; + +/*########################################################################################################################* +*---------------------------------------------------------Memory----------------------------------------------------------* +*#########################################################################################################################*/ +#define ALIGNUP(size, a) (((size) + ((a) - 1)) & ~((a) - 1)) + +void* AllocGPUMemory(int size, int type, int gpu_access, SceUID* ret_uid) { + SceUID uid; + void* addr; + + if (type == SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW) { + size = ALIGNUP(size, 256 * 1024); + } else { + size = ALIGNUP(size, 4 * 1024); + } + + // https://wiki.henkaku.xyz/vita/SceSysmem + uid = sceKernelAllocMemBlock("GPU memory", type, size, NULL); + if (uid < 0) Logger_Abort2(uid, "Failed to allocate GPU memory block"); + + int res1 = sceKernelGetMemBlockBase(uid, &addr); + if (res1 < 0) Logger_Abort2(res1, "Failed to get base of GPU memory block"); + + int res2 = sceGxmMapMemory(addr, size, gpu_access); + if (res1 < 0) Logger_Abort2(res2, "Failed to map memory for GPU usage"); + // https://wiki.henkaku.xyz/vita/GPU + + *ret_uid = uid; + return addr; +} + +void* AllocGPUVertexUSSE(size_t size, SceUID* ret_uid, unsigned int* ret_usse_offset) { + SceUID uid; + void *addr; + + size = ALIGNUP(size, 4 * 1024); + + uid = sceKernelAllocMemBlock("GPU vertex USSE", + SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, size, NULL); + if (uid < 0) Logger_Abort2(uid, "Failed to allocate vertex USSE block"); + + int res1 = sceKernelGetMemBlockBase(uid, &addr); + if (res1 < 0) Logger_Abort2(res1, "Failed to get base of vertex USSE memory block"); + + int res2 = sceGxmMapVertexUsseMemory(addr, size, ret_usse_offset); + if (res1 < 0) Logger_Abort2(res2, "Failed to map vertex USSE memory"); + + *ret_uid = uid; + return addr; +} + +void* AllocGPUFragmentUSSE(size_t size, SceUID* ret_uid, unsigned int* ret_usse_offset) { + SceUID uid; + void *addr; + + size = ALIGNUP(size, 4 * 1024); + + uid = sceKernelAllocMemBlock("GPU fragment USSE", + SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, size, NULL); + if (uid < 0) Logger_Abort2(uid, "Failed to allocate fragment USSE block"); + + int res1 = sceKernelGetMemBlockBase(uid, &addr); + if (res1 < 0) Logger_Abort2(res1, "Failed to get base of fragment USSE memory block"); + + int res2 = sceGxmMapFragmentUsseMemory(addr, size, ret_usse_offset); + if (res1 < 0) Logger_Abort2(res2, "Failed to map fragment USSE memory"); + + *ret_uid = uid; + return addr; +} + + +/*########################################################################################################################* +*-----------------------------------------------------Initialisation------------------------------------------------------* +*#########################################################################################################################*/ +static void DisplayQueueCallback(const void *callback_data) { + SceDisplayFrameBuf fb = { 0 }; + void* addr = *((void **)callback_data); + + fb.size = sizeof(SceDisplayFrameBuf); + fb.base = addr; + fb.pitch = DISPLAY_STRIDE; + fb.pixelformat = SCE_DISPLAY_PIXELFORMAT_A8B8G8R8; + fb.width = DISPLAY_WIDTH; + fb.height = DISPLAY_HEIGHT; + + sceDisplaySetFrameBuf(&fb, SCE_DISPLAY_SETBUF_NEXTFRAME); +} + +static void InitGXM(void) { + SceGxmInitializeParams params = { 0 }; + + params.displayQueueMaxPendingCount = MAX_PENDING_SWAPS; + params.displayQueueCallback = DisplayQueueCallback; + params.displayQueueCallbackDataSize = sizeof(void*); + params.parameterBufferSize = SCE_GXM_DEFAULT_PARAMETER_BUFFER_SIZE; + + sceGxmInitialize(¶ms); +} + +static void AllocRingBuffers(void) { + vdm_ring_buffer_addr = AllocGPUMemory(SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE, + SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, SCE_GXM_MEMORY_ATTRIB_READ, + &vdm_ring_buffer_uid); + + vertex_ring_buffer_addr = AllocGPUMemory(SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE, + SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, SCE_GXM_MEMORY_ATTRIB_READ, + &vertex_ring_buffer_uid); + + fragment_ring_buffer_addr = AllocGPUMemory(SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE, + SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, SCE_GXM_MEMORY_ATTRIB_READ, + &fragment_ring_buffer_uid); + + fragment_usse_ring_buffer_addr = AllocGPUFragmentUSSE(SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE, + &fragment_ring_buffer_uid, &fragment_usse_offset); +} + +static void AllocGXMContext(void) { + SceGxmContextParams params = { 0 }; + + params.hostMem = Mem_TryAlloc(SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE, 1); + params.hostMemSize = SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE; + + params.vdmRingBufferMem = vdm_ring_buffer_addr; + params.vdmRingBufferMemSize = SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE; + + params.vertexRingBufferMem = vertex_ring_buffer_addr; + params.vertexRingBufferMemSize = SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE; + + params.fragmentRingBufferMem = fragment_ring_buffer_addr; + params.fragmentRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE; + + params.fragmentUsseRingBufferMem = fragment_usse_ring_buffer_addr; + params.fragmentUsseRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE; + params.fragmentUsseRingBufferOffset = fragment_usse_offset; + + sceGxmCreateContext(¶ms, &gxm_context); +} + +static void AllocRenderTarget(void) { + SceGxmRenderTargetParams params = { 0 }; + + params.width = DISPLAY_WIDTH; + params.height = DISPLAY_HEIGHT; + params.scenesPerFrame = 1; + params.driverMemBlock = -1; + + sceGxmCreateRenderTarget(¶ms, &gxm_render_target); +} + +static void AllocColorBuffer(int i) { + int size = ALIGNUP(4 * DISPLAY_STRIDE * DISPLAY_HEIGHT, 1 * 1024 * 1024); + + gxm_color_surfaces_addr[i] = AllocGPUMemory(size, SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, + SCE_GXM_MEMORY_ATTRIB_RW, &gxm_color_surfaces_uid[i]); + + sceGxmColorSurfaceInit(&gxm_color_surfaces[i], + SCE_GXM_COLOR_FORMAT_A8B8G8R8, + SCE_GXM_COLOR_SURFACE_LINEAR, + SCE_GXM_COLOR_SURFACE_SCALE_NONE, + SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT, + DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_STRIDE, + gxm_color_surfaces_addr[i]); + + sceGxmSyncObjectCreate(&gxm_sync_objects[i]); +} + +static void AllocDepthBuffer(void) { + int width = ALIGNUP(DISPLAY_WIDTH, SCE_GXM_TILE_SIZEX); + int height = ALIGNUP(DISPLAY_HEIGHT, SCE_GXM_TILE_SIZEY); + int samples = width * height; + + gxm_depth_stencil_surface_addr = AllocGPUMemory(4 * samples, SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, + SCE_GXM_MEMORY_ATTRIB_RW, &gxm_depth_stencil_surface_uid); + + sceGxmDepthStencilSurfaceInit(&gxm_depth_stencil_surface, + SCE_GXM_DEPTH_STENCIL_FORMAT_S8D24, + SCE_GXM_DEPTH_STENCIL_SURFACE_TILED, + width, gxm_depth_stencil_surface_addr, NULL); +} + + +/*########################################################################################################################* +*---------------------------------------------------------General---------------------------------------------------------* +*#########################################################################################################################*/ +static GfxResourceID white_square; +void Gfx_Create(void) { + Gfx.MaxTexWidth = 512; + Gfx.MaxTexHeight = 512; + Gfx.Created = true; + + InitGXM(); + AllocRingBuffers(); + AllocGXMContext(); + + AllocRenderTarget(); + for (int i = 0; i < NUM_DISPLAY_BUFFERS; i++) + { + AllocColorBuffer(i); + } + AllocDepthBuffer(); + + InitDefaultResources(); + + // 1x1 dummy white texture + struct Bitmap bmp; + BitmapCol pixels[1] = { BITMAPCOLOR_WHITE }; + Bitmap_Init(bmp, 1, 1, pixels); + white_square = Gfx_CreateTexture(&bmp, 0, false); + // TODO +} + +void Gfx_Free(void) { + FreeDefaultResources(); + Gfx_DeleteTexture(&white_square); +} + +cc_bool Gfx_TryRestoreContext(void) { return true; } +void Gfx_RestoreState(void) { } +void Gfx_FreeState(void) { } + +/*########################################################################################################################* +*---------------------------------------------------------Textures--------------------------------------------------------* +*#########################################################################################################################*/ +GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps) { + return (void*)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); +} + +void Gfx_DeleteTexture(GfxResourceID* texId) { + // TODO + *texId = NULL; +} + +void Gfx_EnableMipmaps(void) { } +void Gfx_DisableMipmaps(void) { } + +void Gfx_BindTexture(GfxResourceID texId) { + // TODO +} + + +/*########################################################################################################################* +*-----------------------------------------------------State management----------------------------------------------------* +*#########################################################################################################################*/ +void Gfx_SetFaceCulling(cc_bool enabled) { } // TODO +void Gfx_SetAlphaBlending(cc_bool enabled) { } // TODO +void Gfx_SetAlphaArgBlend(cc_bool enabled) { } + +void Gfx_ClearCol(PackedCol color) { + // TODO +} + +void Gfx_SetColWriteMask(cc_bool r, cc_bool g, cc_bool b, cc_bool a) { + // TODO +} + +void Gfx_SetDepthWrite(cc_bool enabled) { + // TODO +} +void Gfx_SetDepthTest(cc_bool enabled) { } // 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 + // NOTE: Shared with OpenGL. might be wrong to do that though? + *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 PS VITA (%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; +} + +void Gfx_BeginFrame(void) { + // TODO +} +void Gfx_Clear(void) { } // TODO + +void Gfx_EndFrame(void) { + Platform_LogConst("SWAP BUFFERS"); + // TODO + if (gfx_minFrameMs) LimitFPS(); +} + +void Gfx_OnWindowResize(void) { } + + +/*########################################################################################################################* +*-------------------------------------------------------Index buffers-----------------------------------------------------* +*#########################################################################################################################*/ +GfxResourceID Gfx_CreateIb2(int count, Gfx_FillIBFunc fillFunc, void* obj) { + //fillFunc(gfx_indices, count, obj); + return 1; +} + +void Gfx_BindIb(GfxResourceID ib) { } +void Gfx_DeleteIb(GfxResourceID* ib) { } + + +/*########################################################################################################################* +*----------------------------------------------------------Buffers--------------------------------------------------------* +*#########################################################################################################################*/ +static void* gfx_vertices; +static int vb_size; + +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; + // TODO +} + +void Gfx_BindVb(GfxResourceID vb) { gfx_vertices = vb; } + +void Gfx_DeleteVb(GfxResourceID* vb) { + GfxResourceID data = *vb; + if (data) Mem_Free(data); + *vb = 0; + // TODO +} + +void* Gfx_LockVb(GfxResourceID vb, VertexFormat fmt, int count) { + vb_size = count * strideSizes[fmt]; + return vb; + // TODO +} + +void Gfx_UnlockVb(GfxResourceID vb) { + gfx_vertices = vb; + // TODO +} + + +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 +} + +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 +} + +void Gfx_SetDynamicVbData(GfxResourceID vb, void* vertices, int vCount) { + gfx_vertices = vb; + Mem_Copy(vb, vertices, vCount * gfx_stride); + // TODO +} + + +/*########################################################################################################################* +*-----------------------------------------------------State management----------------------------------------------------* +*#########################################################################################################################*/ +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 +} + +void Gfx_SetAlphaTest(cc_bool enabled) { } + // TODO + +void Gfx_DepthOnlyRendering(cc_bool depthOnly) { + // TODO +} + + +/*########################################################################################################################* +*---------------------------------------------------------Matrices--------------------------------------------------------* +*#########################################################################################################################*/ +void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) { + // TODO +} + +void Gfx_LoadIdentityMatrix(MatrixType type) { + // TODO +} + +void Gfx_EnableTextureOffset(float x, float y) { + // TODO +} + +void Gfx_DisableTextureOffset(void) { + // TODO +} + + + +/*########################################################################################################################* +*---------------------------------------------------------Drawing---------------------------------------------------------* +*#########################################################################################################################*/ +cc_bool Gfx_WarnIfNecessary(void) { return false; } + +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 diff --git a/src/Window_PSVita.c b/src/Window_PSVita.c index 62300fe09..c3228d094 100644 --- a/src/Window_PSVita.c +++ b/src/Window_PSVita.c @@ -137,27 +137,7 @@ void Window_AllocFramebuffer(struct Bitmap* bmp) { fb_bmp = *bmp; } -#define ALIGNUP(size, a) (((size) + ((a) - 1)) & ~((a) - 1)) - -static void AllocGPUMemory(int size, SceUID* ret_uid, void** ret_mem) { - SceUID uid; - void* mem; - size = ALIGNUP(size, 256 * 1024); - - // https://wiki.henkaku.xyz/vita/SceSysmem - uid = sceKernelAllocMemBlock("CC Framebuffer", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, size, NULL); - if (uid < 0) Logger_Abort2(uid, "Failed to allocate 2D framebuffer"); - - int res1 = sceKernelGetMemBlockBase(uid, &mem); - if (res1 < 0) Logger_Abort2(res1, "Failed to get base of 2D framebuffer"); - - int res2 = sceGxmMapMemory(mem, size, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE); - if (res1 < 0) Logger_Abort2(res2, "Failed to map framebuffer for GPU usage"); - // https://wiki.henkaku.xyz/vita/GPU - - *ret_uid = uid; - *ret_mem = mem; -} +extern void* AllocGPUMemory(int size, int type, int gpu_access, SceUID* ret_uid); void Window_DrawFramebuffer(Rect2D r) { static SceUID fb_uid; @@ -165,8 +145,11 @@ void Window_DrawFramebuffer(Rect2D r) { // TODO: Purge when closing the 2D window, so more memory for 3D ClassiCube // TODO: Use framebuffers directly instead of our own internal framebuffer too.. - if (!fb) - AllocGPUMemory(4 * SCREEN_WIDTH * SCREEN_HEIGHT, &fb_uid, &fb); + if (!fb) { + int size = 4 * SCREEN_WIDTH * SCREEN_HEIGHT; + fb = AllocGPUMemory(size, SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, + SCE_GXM_MEMORY_ATTRIB_RW, &fb_uid); + } sceDisplayWaitVblankStart();