From b38091ba1bddff461f8d882feb585860256a5525 Mon Sep 17 00:00:00 2001 From: olebeck <31539311+olebeck@users.noreply.github.com> Date: Tue, 24 Jun 2025 16:36:09 +0200 Subject: [PATCH] add gxm renderer (not working with display yet) --- CMakeLists.txt | 28 +- ISLE/isleapp.cpp | 14 +- miniwin/CMakeLists.txt | 14 + miniwin/src/d3drm/backends/gxm/.gitignore | 1 + miniwin/src/d3drm/backends/gxm/Makefile | 7 + miniwin/src/d3drm/backends/gxm/clear.frag.cg | 5 + miniwin/src/d3drm/backends/gxm/clear.frag.gxp | Bin 0 -> 220 bytes miniwin/src/d3drm/backends/gxm/clear.vert.cg | 7 + miniwin/src/d3drm/backends/gxm/clear.vert.gxp | Bin 0 -> 252 bytes .../backends/gxm/libSceRazorCapture_stub.a | Bin 0 -> 9578 bytes miniwin/src/d3drm/backends/gxm/main.frag.cg | 66 ++ miniwin/src/d3drm/backends/gxm/main.frag.gxp | Bin 0 -> 1480 bytes miniwin/src/d3drm/backends/gxm/main.vert.cg | 20 + miniwin/src/d3drm/backends/gxm/main.vert.gxp | Bin 0 -> 728 bytes miniwin/src/d3drm/backends/gxm/memory.cpp | 128 +++ miniwin/src/d3drm/backends/gxm/memory.h | 25 + miniwin/src/d3drm/backends/gxm/renderer.cpp | 948 ++++++++++++++++++ miniwin/src/d3drm/backends/gxm/utils.h | 24 + miniwin/src/d3drm/d3drm.cpp | 8 + miniwin/src/ddraw/ddraw.cpp | 18 +- miniwin/src/internal/d3drmrenderer_gxm.h | 167 +++ sdl3.patch | 413 ++++++++ 22 files changed, 1876 insertions(+), 17 deletions(-) create mode 100644 miniwin/src/d3drm/backends/gxm/.gitignore create mode 100644 miniwin/src/d3drm/backends/gxm/Makefile create mode 100644 miniwin/src/d3drm/backends/gxm/clear.frag.cg create mode 100644 miniwin/src/d3drm/backends/gxm/clear.frag.gxp create mode 100644 miniwin/src/d3drm/backends/gxm/clear.vert.cg create mode 100644 miniwin/src/d3drm/backends/gxm/clear.vert.gxp create mode 100644 miniwin/src/d3drm/backends/gxm/libSceRazorCapture_stub.a create mode 100644 miniwin/src/d3drm/backends/gxm/main.frag.cg create mode 100644 miniwin/src/d3drm/backends/gxm/main.frag.gxp create mode 100644 miniwin/src/d3drm/backends/gxm/main.vert.cg create mode 100644 miniwin/src/d3drm/backends/gxm/main.vert.gxp create mode 100644 miniwin/src/d3drm/backends/gxm/memory.cpp create mode 100644 miniwin/src/d3drm/backends/gxm/memory.h create mode 100644 miniwin/src/d3drm/backends/gxm/renderer.cpp create mode 100644 miniwin/src/d3drm/backends/gxm/utils.h create mode 100644 miniwin/src/internal/d3drmrenderer_gxm.h create mode 100644 sdl3.patch diff --git a/CMakeLists.txt b/CMakeLists.txt index eb131fba..79c838fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,12 +71,14 @@ if(VITA) set(CMAKE_POSITION_INDEPENDENT_CODE OFF) set(ISLE_DEBUG OFF) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/modules") - + set(VITA_USE_OPENGLES2 ON) +endif() + +if(VITA_USE_OPENGLES2) include(FetchContent) include(cmake/modules/pvr_psp2.cmake) include(cmake/modules/sdl3_pvr_psp2.cmake) - fetch_iniparser() elseif (DOWNLOAD_DEPENDENCIES) @@ -87,6 +89,7 @@ elseif (DOWNLOAD_DEPENDENCIES) SDL3 GIT_REPOSITORY "https://github.com/libsdl-org/SDL.git" GIT_TAG "main" + UPDATE_DISCONNECTED TRUE EXCLUDE_FROM_ALL ) FetchContent_MakeAvailable(SDL3) @@ -512,8 +515,9 @@ if (ISLE_BUILD_APP) target_link_libraries(isle PRIVATE winmm) endif() - if(VITA) + if(VITA AND VITA_USE_OPENGLES2) target_link_libraries(isle PRIVATE GLESv2) + target_compile_definitions(isle PRIVATE USE_OPENGLES2) endif() # Link LEGO1 @@ -670,7 +674,9 @@ set(CPACK_PACKAGE_FILE_NAME "isle-${PROJECT_VERSION}-${ISLE_PACKAGE_NAME}-${CMAK if(VITA) include("${VITASDK}/share/vita.cmake" REQUIRED) - target_link_libraries(lego1 PRIVATE GLESv2) + if(VITA_USE_OPENGLES2) + target_link_libraries(lego1 PRIVATE GLESv2) + endif() set(ISLE_PACKAGE_NAME "vita-isle") set(VITA_APP_NAME "Lego Island") @@ -679,12 +685,14 @@ if(VITA) vita_create_self(isle.self isle UNSAFE) - set(VPK_FILE_ARGS) - get_target_property(gles_modules GLESv2 MODULES) - foreach(file IN LISTS gles_modules) - get_filename_component(fname ${file} NAME) - list(APPEND VPK_FILE_ARGS FILE ${file} module/${fname}) - endforeach() + if(VITA_USE_OPENGLES2) + set(VPK_FILE_ARGS) + get_target_property(gles_modules GLESv2 MODULES) + foreach(file IN LISTS gles_modules) + get_filename_component(fname ${file} NAME) + list(APPEND VPK_FILE_ARGS FILE ${file} module/${fname}) + endforeach() + endif() vita_create_vpk(isle.vpk ${VITA_TITLEID} isle.self VERSION ${VITA_VERSION} diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index 561d3eec..ae207002 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -51,8 +51,12 @@ #endif #ifdef __vita__ +#include +#endif + +#if defined(__vita__) && defined(USE_OPENGLES2) extern "C"{ -#include + #include } #include @@ -71,6 +75,7 @@ extern "C"{ #error GPU Memory exceeds maximum memblck size #endif +extern SDL_Window* DDWindow; int _newlib_heap_size_user = NEWLIB_HEAP_SIZE; unsigned int sceLibcHeapSize = LIBC_HEAP_SIZE; @@ -289,9 +294,8 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); -#if __vita__ +#if defined(__vita__) && defined(USE_OPENGLES2) SDL_SetHint("VITA_PVR_SKIP_INIT", "enable"); - SDL_SetHint("SDL_RENDER_OPENGLES2_TEXCOORD_PRECISION", "high"); // not really needed PVRSRV_PSP2_APPHINT hint; sceKernelLoadStartModule("vs0:sys/external/libfios2.suprx", 0, NULL, 0, NULL, NULL); @@ -708,7 +712,7 @@ MxResult IsleApp::SetupWindow() SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, g_targetHeight); SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, m_fullScreen); SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE); -#ifdef MINIWIN +#if defined(MINIWIN) && !defined(USE_GXM) SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); #endif @@ -720,6 +724,8 @@ MxResult IsleApp::SetupWindow() (HWND) SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); #endif + DDWindow = window; + SDL_DestroyProperties(props); if (!m_windowHandle) { diff --git a/miniwin/CMakeLists.txt b/miniwin/CMakeLists.txt index 88e0d471..2600bc72 100644 --- a/miniwin/CMakeLists.txt +++ b/miniwin/CMakeLists.txt @@ -52,6 +52,20 @@ else() message(STATUS "🧩 OpenGL ES 2.x support not enabled") endif() +if(VITA) + target_sources(miniwin PRIVATE + src/d3drm/backends/gxm/renderer.cpp + src/d3drm/backends/gxm/memory.cpp + ) + target_link_libraries(miniwin PRIVATE + SceGxm_stub + SceRazorCapture_stub + ) + # for shaders incbin + target_include_directories(miniwin PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/d3drm/backends/gxm) + target_link_directories(miniwin PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/d3drm/backends/gxm) +endif() + if(WIN32) target_sources(miniwin PRIVATE src/d3drm/backends/directx9/actual.cpp diff --git a/miniwin/src/d3drm/backends/gxm/.gitignore b/miniwin/src/d3drm/backends/gxm/.gitignore new file mode 100644 index 00000000..adb36c82 --- /dev/null +++ b/miniwin/src/d3drm/backends/gxm/.gitignore @@ -0,0 +1 @@ +*.exe \ No newline at end of file diff --git a/miniwin/src/d3drm/backends/gxm/Makefile b/miniwin/src/d3drm/backends/gxm/Makefile new file mode 100644 index 00000000..8e4e01b2 --- /dev/null +++ b/miniwin/src/d3drm/backends/gxm/Makefile @@ -0,0 +1,7 @@ +all: main.frag.gxp main.vert.gxp clear.frag.gxp clear.vert.gxp + +%.vert.gxp: %.vert.cg + ./psp2cgc.exe -Wperf -profile sce_vp_psp2 $< -o $@ + +%.frag.gxp: %.frag.cg + ./psp2cgc.exe -Wperf -profile sce_fp_psp2 $< -o $@ diff --git a/miniwin/src/d3drm/backends/gxm/clear.frag.cg b/miniwin/src/d3drm/backends/gxm/clear.frag.cg new file mode 100644 index 00000000..a82d8165 --- /dev/null +++ b/miniwin/src/d3drm/backends/gxm/clear.frag.cg @@ -0,0 +1,5 @@ +void main( + out float4 outColor : COLOR +) { + outColor = float4(0.0, 0.0, 0.5, 1.0); +} diff --git a/miniwin/src/d3drm/backends/gxm/clear.frag.gxp b/miniwin/src/d3drm/backends/gxm/clear.frag.gxp new file mode 100644 index 0000000000000000000000000000000000000000..5f175abd04f57a80eeca7853d29195339813b886 GIT binary patch literal 220 zcmZ>d2w-4j4Pd^*z`)QU?-Dd2w-4j4PgGoz`&5UY|)H8tu4MR43a<|0x$xZJAk+Vh*{vmj9_*HlwSg*LGrjj z1yI7lju|YS167m)rDLFU2$c4L(h${94u}#!vK~p8f!*a7&@~fU1($L#GK5WN6l~^T gU{F}V5TO2B0HltEn*rnp5J(KjFU~B<%+CX|0R)2=Qvd(} literal 0 HcmV?d00001 diff --git a/miniwin/src/d3drm/backends/gxm/libSceRazorCapture_stub.a b/miniwin/src/d3drm/backends/gxm/libSceRazorCapture_stub.a new file mode 100644 index 0000000000000000000000000000000000000000..4030b429887d5bc1634069eda4287d939a9066ea GIT binary patch literal 9578 zcmeI2%}*0S6u@6C2(82jeuM-=3L#32Zs~W83REl&mLj1fdNHttrBq5wwp${aVB*!p zM9!Er#)I*$p8O9?Ogwn-;=x4YO|N>;w{&M`cj>xID{*6Yl4ZW$eC)jW&6|Ct?;^`D zEDyWA9(C|V0)db}6h0sHc!qYWlz%;*KqM?Rn0EsJJ}plG+CBpuIt6gJ0MPjo;Mfm< z?s0&gEr8zl0R8=?1#X7DQ{>0kHKELN6Qzm5G+)f}T&V<_x-=)u^0{o5%N2>L`}ar?}N3zfoflDs`D#D)L-1x3E%M zO#3dXk)+B$y-r$Sc|m%cRB@35@M@K&R^hH(IO>;mmR9RwPMg>0Lb+B<(d*WVYxA1s zRFw@imX~KQz0h@5ZHW51sCOOcB-g9_4aadA3sZ}s4j zceC;DAA(Ie`oS<&*#1dt2 zLJM>$3ow5i^BrqG{o zw6Q9%8H@$K8ZVQSfJZMdi>$x`lfl!QSyQ6CNAz<;_03}q zh;aYd905d4aCAkFBY)UODKc}Pquv@LdsH!LkA6M~y=xwhlpp@qz{q9@AYy`{F+GL? z{>YvfiW1Xhe5ZS6lA&|=UALNtA?mS`U0>Ef$+kzhUx!VwbXAX~py-FA!T4VH_gQ*1 z_2pqRvP8YV)_}>jO8_G#SW4=$6d`cz0A 0.0) { + // Diffuse contribution + diffuse += dotNL * lightColor; + + // Specular + if (uShininess > 0.0) { + float3 viewVec = normalize(-vViewPos); // Assuming camera at origin + float3 halfVec = normalize(lightVec + viewVec); + float dotNH = max(dot(normal, halfVec), 0.0); + float spec = pow(dotNH, uShininess); + specular += spec * lightColor; + } + } + + outColor = uColor; + outColor.rgb = clamp(diffuse * uColor.rgb + specular, 0.0, 1.0); + if (uUseTexture != 0) { + float4 texel = tex2D(uTexture, vTexCoord); + outColor.rgb *= texel.rgb; + outColor.rgb = clamp(outColor.rgb, 0.0, 1.0); + } + } +} \ No newline at end of file diff --git a/miniwin/src/d3drm/backends/gxm/main.frag.gxp b/miniwin/src/d3drm/backends/gxm/main.frag.gxp new file mode 100644 index 0000000000000000000000000000000000000000..7058d1242404de6cd1b5f20eebb56d34d514871f GIT binary patch literal 1480 zcmZuxPe>F|82{ePxche1ommwd%~GR7hp4qn9?ZrRT0zO^4}nC8Ex8b`xGr>xH?x~; zDp}#N!=`x?v|}JLLO~rOFF{9@4jrYFmbQK0%$TFw2XDUj`+eW<``&vqZ?4|y16I~2 ze<%a!eqKA*|F!3utm_~FXbfCa(JjaTBj_tYgGPsDa2x$H4wOP3#{v$&p~Nwc&zlI0 zcA4rzE6%BQpO-+GEQX%qXV9Nj9LjqzMM4Epa-Cg4Y6Z|cTu;%a9eNr}*(UE;uIv%R1~7-DUv zSuM-~{gV1w796-FD9`rtOfOGh9;>#^4b1D63xJtIUVAbTiVJ0ZJq)Zb63qUbsuTtU z>`e|PV%fungUxJk$qexL6ssWyyUnb% zs0g;Uo81%vp{-rSECXQ2^729+Mh8X+wsD^-?GxCE>GzY(dg*?d=I*x_1ON}ZdgshY z9~pP`|I^vdIrTyTbtrTCoqXo?n~kbMFdbH2YSsjcN8P%6ycsNE79iAOSOPoJ3pD`# zpmX%~Q>3?Py=rdqwYT0w=iVqLH}nYA&zm}=l*SyN=d4|*P$6O<*cXxC&>b8RvG93; zudo2+mu-pq?f0pjaQi6cyW%qT<1C7G-|Flh);m7Wv2JucM7}p_fyoWEMyf9ptrD#h z;P=O(O8(zD1uXYFQOxKxt?y7Bc2H;4)8#cq%5}WqpR_J14>n)%_;9YS@EE_F{rgD$ zXzqOYc+Ax}=ipwV-D0sw7ng0gIT(U+!rxs?S_yH77Y`t&gJ#M>e$j`K2AT9;oL(yT zVY-YVAJ!08`fv^6Dj(JnSNm`S;$uGCgt!552XQz*je~3k(TqEF`b!FP;zTj;|KWv8 zT;|45ayU7hNT(swnR=KSh0LvV;%4H}SY|Wp|Ny-?C!ZiH+Vpdq|(W;WNO%- pbU!(o7(7I_991GwqC~D#dEuxMi4rApN0pta%EVD_{w?d8T9y1A zm51LXZ~5h~BNL$B;6C13Is%VT2-eE+pW#sHPwj8aOMimo2|KLQX!%xfJ0xqIwTjOf zaDJ5z>NMjugob7RM61uA6OlX#j?3#Oy@pV=^*(>zl$;-v^;*U6*CBb#`*d$js3!Ze zvc9>$xa4VYoRVFq(_RDhjJD4CVe|<|$6im24TVZ}t%_$%xHDI*k5N@6__aEo6z1on zZpyQNI8;#x31B|t?g$3=pJ(?SQG&+nQ*QDj+qWqhW^stJfgPI=+rFbI_8$l;K=&ya zz0aE1L_aKW4YrH>;o-dCh~OZ`vw}6jVT`BH$pg0VJerP9?g99fcB5xF%XR*vnTEBI zFXpW^Ftb)+)m#Ddb8dUYvI + +#include + + + + +void *patcher_host_alloc(void *user_data, unsigned int size) +{ + void *mem = SDL_malloc(size); + (void)user_data; + return mem; +} + +void patcher_host_free(void *user_data, void *mem) +{ + (void)user_data; + SDL_free(mem); +} + +void* vita_mem_alloc( + unsigned int type, + size_t size, + size_t alignment, + int attribs, + SceUID *uid, + const char* name, + size_t* alignedSize +) { + void *mem; + + if (type == SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW) { + size = ALIGN(size, 256 * 1024); + } else if (type == SCE_KERNEL_MEMBLOCK_TYPE_USER_MAIN_PHYCONT_NC_RW) { + size = ALIGN(size, 1024 * 1024); + } else { + size = ALIGN(size, 4 * 1024); + } + + *uid = sceKernelAllocMemBlock(name, type, size, NULL); + + if (*uid < 0) { + SDL_Log("sceKernelAllocMemBlock: 0x%x", *uid); + return NULL; + } + + if (sceKernelGetMemBlockBase(*uid, &mem) < 0) { + return NULL; + } + + if (sceGxmMapMemory(mem, size, (SceGxmMemoryAttribFlags)attribs) < 0) { + SDL_Log("sceGxmMapMemory 0x%x 0x%x %d failed", mem, size, attribs); + return NULL; + } + + if(alignedSize) { + *alignedSize = size; + } + + return mem; +} + +void vita_mem_free(SceUID uid) +{ + void *mem = NULL; + if (sceKernelGetMemBlockBase(uid, &mem) < 0) { + return; + } + sceGxmUnmapMemory(mem); + sceKernelFreeMemBlock(uid); +} + +void *vita_mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) +{ + void *mem = NULL; + + size = ALIGN(size, 4096); + *uid = sceKernelAllocMemBlock("vertex_usse", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, size, NULL); + + if (sceKernelGetMemBlockBase(*uid, &mem) < 0) { + return NULL; + } + if (sceGxmMapVertexUsseMemory(mem, size, usse_offset) < 0) { + return NULL; + } + + return mem; +} + +void vita_mem_vertex_usse_free(SceUID uid) +{ + void *mem = NULL; + if (sceKernelGetMemBlockBase(uid, &mem) < 0) { + return; + } + sceGxmUnmapVertexUsseMemory(mem); + sceKernelFreeMemBlock(uid); +} + +void *vita_mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) +{ + void *mem = NULL; + + size = ALIGN(size, 4096); + *uid = sceKernelAllocMemBlock("fragment_usse", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, size, NULL); + + if (sceKernelGetMemBlockBase(*uid, &mem) < 0) { + return NULL; + } + if (sceGxmMapFragmentUsseMemory(mem, size, usse_offset) < 0) { + return NULL; + } + + return mem; +} + +void vita_mem_fragment_usse_free(SceUID uid) +{ + void *mem = NULL; + if (sceKernelGetMemBlockBase(uid, &mem) < 0) { + return; + } + sceGxmUnmapFragmentUsseMemory(mem); + sceKernelFreeMemBlock(uid); +} diff --git a/miniwin/src/d3drm/backends/gxm/memory.h b/miniwin/src/d3drm/backends/gxm/memory.h new file mode 100644 index 00000000..80876903 --- /dev/null +++ b/miniwin/src/d3drm/backends/gxm/memory.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include +#include + +void *patcher_host_alloc(void *user_data, unsigned int size); +void patcher_host_free(void *user_data, void *mem); + +void* vita_mem_alloc( + unsigned int type, + size_t size, + size_t alignment, + int attribs, + SceUID* uid, + const char* name, + size_t* alignedSize +); +void vita_mem_free(SceUID uid); + +void *vita_mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); +void vita_mem_vertex_usse_free(SceUID uid); +void *vita_mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); +void vita_mem_fragment_usse_free(SceUID uid); \ No newline at end of file diff --git a/miniwin/src/d3drm/backends/gxm/renderer.cpp b/miniwin/src/d3drm/backends/gxm/renderer.cpp new file mode 100644 index 00000000..86c9ebce --- /dev/null +++ b/miniwin/src/d3drm/backends/gxm/renderer.cpp @@ -0,0 +1,948 @@ +#include "d3drmrenderer_gxm.h" +#include "meshutils.h" + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "utils.h" +#include "memory.h" + +bool with_razor = false; + + + #define VITA_GXM_SCREEN_WIDTH 960 + #define VITA_GXM_SCREEN_HEIGHT 544 + #define VITA_GXM_SCREEN_STRIDE 960 + + #define VITA_GXM_COLOR_FORMAT SCE_GXM_COLOR_FORMAT_A8B8G8R8 + #define VITA_GXM_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8 + +struct SceneLightGXM { + float color[4]; + float position[4]; + float direction[4]; +}; + +typedef struct Vertex { + float position[3]; + float normal[3]; + float texCoord[2]; +} Vertex; + + +static bool make_fragment_program( + GXMRendererData* data, + const SceGxmProgram* vertexProgramGxp, + const SceGxmBlendInfo *blendInfo, + SceGxmFragmentProgram** fragmentProgram +) { + return SCE_ERR(sceGxmShaderPatcherCreateFragmentProgram, + data->shaderPatcher, + data->mainFragmentProgramId, + SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4, + SCE_GXM_MULTISAMPLE_NONE, + blendInfo, + vertexProgramGxp, + fragmentProgram + ); +} + + +INCBIN("main.vert.gxp", main_vert_gxp_start); +INCBIN("main.frag.gxp", main_frag_gxp_start); +INCBIN("clear.vert.gxp", clear_vert_gxp_start); +INCBIN("clear.frag.gxp", clear_frag_gxp_start); + +const SceGxmProgram* clearVertexProgramGxp = (const SceGxmProgram*)&clear_vert_gxp_start; +const SceGxmProgram* clearFragmentProgramGxp = (const SceGxmProgram*)&clear_frag_gxp_start; +const SceGxmProgram* mainVertexProgramGxp = (const SceGxmProgram*)&main_vert_gxp_start; +const SceGxmProgram* mainFragmentProgramGxp = (const SceGxmProgram*)&main_frag_gxp_start; + + +static const size_t clearMeshVerticiesSize = 3 * sizeof(float)*2; +static const size_t clearMeshIndiciesSize = 3 * sizeof(uint16_t); + + +extern "C" int sceRazorGpuCaptureSetTrigger(int frames, const char* path); +extern "C" int sceRazorGpuCaptureEnableSalvage(const char* path); +extern "C" int sceRazorGpuCaptureSetTriggerNextFrame(const char* path); + + + +#define GET_SHADER_PARAM(var, gxp, name) \ + const SceGxmProgramParameter* var = sceGxmProgramFindParameterByName(gxp, name); \ + if(!var) { \ + SDL_Log("Failed to find param %s", name); \ + return false; \ + } + +static bool create_gxm_renderer(int width, int height, GXMRendererData* data) { + const unsigned int alignedWidth = ALIGN(width, SCE_GXM_TILE_SIZEX); + const unsigned int alignedHeight = ALIGN(height, SCE_GXM_TILE_SIZEY); + + unsigned int sampleCount = alignedWidth * alignedHeight; + unsigned int depthStrideInSamples = alignedWidth; + + const unsigned int patcherBufferSize = 64 * 1024; + const unsigned int patcherVertexUsseSize = 64 * 1024; + const unsigned int patcherFragmentUsseSize = 64 * 1024; + + + static const SceGxmBlendInfo blendInfoOpaque = { + .colorMask = SCE_GXM_COLOR_MASK_ALL, + .colorFunc = SCE_GXM_BLEND_FUNC_NONE, + .alphaFunc = SCE_GXM_BLEND_FUNC_NONE, + .colorSrc = SCE_GXM_BLEND_FACTOR_ZERO, + .colorDst = SCE_GXM_BLEND_FACTOR_ZERO, + .alphaSrc = SCE_GXM_BLEND_FACTOR_ZERO, + .alphaDst = SCE_GXM_BLEND_FACTOR_ZERO, + }; + + static const SceGxmBlendInfo blendInfoTransparent = { + .colorMask = SCE_GXM_COLOR_MASK_ALL, + .colorFunc = SCE_GXM_BLEND_FUNC_ADD, + .alphaFunc = SCE_GXM_BLEND_FUNC_ADD, + .colorSrc = SCE_GXM_BLEND_FACTOR_SRC_ALPHA, + .colorDst = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaSrc = SCE_GXM_BLEND_FACTOR_ONE, + .alphaDst = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + }; + + data->cdramPool = SDL_gxm_get_cdramPool(); + if(!data->cdramPool) { + SDL_Log("failed to allocate cdramPool"); + return false; + } + + // allocate buffers + data->vdmRingBuffer = vita_mem_alloc( + SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, + SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE, + 4, + SCE_GXM_MEMORY_ATTRIB_READ, + &data->vdmRingBufferUid, + "vdmRingBuffer", + nullptr + ); + + data->vertexRingBuffer = vita_mem_alloc( + SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, + SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE, + 4, + SCE_GXM_MEMORY_ATTRIB_READ, + &data->vertexRingBufferUid, + "vertexRingBuffer", + nullptr + ); + + data->fragmentRingBuffer = vita_mem_alloc( + SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, + SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE, + 4, + SCE_GXM_MEMORY_ATTRIB_READ, + &data->fragmentRingBufferUid, + "fragmentRingBuffer", + nullptr + ); + + data->fragmentUsseRingBuffer = vita_mem_fragment_usse_alloc( + SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE, + &data->fragmentUsseRingBufferUid, + &data->fragmentUsseRingBufferOffset); + + // create context + SceGxmContextParams contextParams; + memset(&contextParams, 0, sizeof(SceGxmContextParams)); + contextParams.hostMem = SDL_malloc(SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE); + contextParams.hostMemSize = SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE; + contextParams.vdmRingBufferMem = data->vdmRingBuffer; + contextParams.vdmRingBufferMemSize = SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE; + contextParams.vertexRingBufferMem = data->vertexRingBuffer; + contextParams.vertexRingBufferMemSize = SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE; + contextParams.fragmentRingBufferMem = data->fragmentRingBuffer; + contextParams.fragmentRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE; + contextParams.fragmentUsseRingBufferMem = data->fragmentUsseRingBuffer; + contextParams.fragmentUsseRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE; + contextParams.fragmentUsseRingBufferOffset = data->fragmentUsseRingBufferOffset; + + if(SCE_ERR(sceGxmCreateContext, &contextParams, &data->context)) { + return false; + } + data->contextHostMem = contextParams.hostMem; + + // shader patcher + data->patcherBuffer = vita_mem_alloc( + SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, + patcherBufferSize, + 4, + SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, + &data->patcherBufferUid, + "patcherBuffer", + nullptr + ); + + data->patcherVertexUsse = vita_mem_vertex_usse_alloc( + patcherVertexUsseSize, + &data->patcherVertexUsseUid, + &data->patcherVertexUsseOffset); + + data->patcherFragmentUsse = vita_mem_fragment_usse_alloc( + patcherFragmentUsseSize, + &data->patcherFragmentUsseUid, + &data->patcherFragmentUsseOffset); + + SceGxmShaderPatcherParams patcherParams; + memset(&patcherParams, 0, sizeof(SceGxmShaderPatcherParams)); + patcherParams.userData = NULL; + patcherParams.hostAllocCallback = &patcher_host_alloc; + patcherParams.hostFreeCallback = &patcher_host_free; + patcherParams.bufferAllocCallback = NULL; + patcherParams.bufferFreeCallback = NULL; + patcherParams.bufferMem = data->patcherBuffer; + patcherParams.bufferMemSize = patcherBufferSize; + patcherParams.vertexUsseAllocCallback = NULL; + patcherParams.vertexUsseFreeCallback = NULL; + patcherParams.vertexUsseMem = data->patcherVertexUsse; + patcherParams.vertexUsseMemSize = patcherVertexUsseSize; + patcherParams.vertexUsseOffset = data->patcherVertexUsseOffset; + patcherParams.fragmentUsseAllocCallback = NULL; + patcherParams.fragmentUsseFreeCallback = NULL; + patcherParams.fragmentUsseMem = data->patcherFragmentUsse; + patcherParams.fragmentUsseMemSize = patcherFragmentUsseSize; + patcherParams.fragmentUsseOffset = data->patcherFragmentUsseOffset; + + if(SCE_ERR(sceGxmShaderPatcherCreate, &patcherParams, &data->shaderPatcher)) { + return false; + } + + // render target + SceGxmRenderTargetParams renderTargetParams; + memset(&renderTargetParams, 0, sizeof(SceGxmRenderTargetParams)); + renderTargetParams.flags = 0; + renderTargetParams.width = width; + renderTargetParams.height = height; + renderTargetParams.scenesPerFrame = 1; + renderTargetParams.multisampleMode = 0; + renderTargetParams.multisampleLocations = 0; + renderTargetParams.driverMemBlock = -1; // Invalid UID + + if(SCE_ERR(sceGxmCreateRenderTarget, &renderTargetParams, &data->renderTarget)) { + return false; + } + + data->renderBuffer = vita_mem_alloc( + SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, + 4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT, + SCE_GXM_COLOR_SURFACE_ALIGNMENT, + SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, + &data->renderBufferUid, "display", nullptr); + + // color surface + if(SCE_ERR(sceGxmColorSurfaceInit, + &data->renderSurface, + SCE_GXM_COLOR_FORMAT_A8B8G8R8, + SCE_GXM_COLOR_SURFACE_LINEAR, + SCE_GXM_COLOR_SURFACE_SCALE_NONE, + SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT, + width, height, + width, + data->renderBuffer + )) { + return false; + }; + + if(SCE_ERR(sceGxmSyncObjectCreate, &data->renderBufferSync)) { + return false; + } + + + // depth & stencil + data->depthBufferData = vita_mem_alloc( + SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, + 4 * sampleCount, + SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, + SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, + &data->depthBufferUid, + "depthBufferData", + nullptr + ); + + data->stencilBufferData = vita_mem_alloc( + SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, + 4 * sampleCount, + SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, + SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, + &data->stencilBufferUid, + "stencilBufferData", + nullptr + ); + + if(SCE_ERR(sceGxmDepthStencilSurfaceInit, + &data->depthSurface, + SCE_GXM_DEPTH_STENCIL_FORMAT_S8D24, + SCE_GXM_DEPTH_STENCIL_SURFACE_TILED, + depthStrideInSamples, + data->depthBufferData, + data->stencilBufferData + )) { + return false; + } + + + // clear shader + { + if(SCE_ERR(sceGxmShaderPatcherRegisterProgram, data->shaderPatcher, clearVertexProgramGxp, &data->clearVertexProgramId)) { + return false; + } + if(SCE_ERR(sceGxmShaderPatcherRegisterProgram, data->shaderPatcher, clearFragmentProgramGxp, &data->clearFragmentProgramId)) { + return false; + } + GET_SHADER_PARAM(positionAttribute, clearVertexProgramGxp, "aPosition"); + + SceGxmVertexAttribute vertexAttributes[1]; + SceGxmVertexStream vertexStreams[1]; + vertexAttributes[0].streamIndex = 0; + vertexAttributes[0].offset = 0; + vertexAttributes[0].format = SCE_GXM_ATTRIBUTE_FORMAT_F32; + vertexAttributes[0].componentCount = 2; + vertexAttributes[0].regIndex = sceGxmProgramParameterGetResourceIndex(positionAttribute); + vertexStreams[0].stride = sizeof(float)*2; + vertexStreams[0].indexSource = SCE_GXM_INDEX_SOURCE_INDEX_16BIT; + + if(SCE_ERR(sceGxmShaderPatcherCreateVertexProgram, + data->shaderPatcher, + data->clearVertexProgramId, + vertexAttributes, 1, + vertexStreams, 1, + &data->clearVertexProgram + )) { + return false; + } + + if(SCE_ERR(sceGxmShaderPatcherCreateFragmentProgram, + data->shaderPatcher, + data->clearFragmentProgramId, + SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4, + SCE_GXM_MULTISAMPLE_NONE, + NULL, + clearVertexProgramGxp, + &data->clearFragmentProgram + )) { + return false; + } + } + + // main shader + { + if(SCE_ERR(sceGxmShaderPatcherRegisterProgram, data->shaderPatcher, mainVertexProgramGxp, &data->mainVertexProgramId)) { + return false; + } + if(SCE_ERR(sceGxmShaderPatcherRegisterProgram, data->shaderPatcher, mainFragmentProgramGxp, &data->mainFragmentProgramId)) { + return false; + } + + GET_SHADER_PARAM(positionAttribute, mainVertexProgramGxp, "aPosition"); + GET_SHADER_PARAM(normalAttribute, mainVertexProgramGxp, "aNormal"); + GET_SHADER_PARAM(texCoordAttribute, mainVertexProgramGxp, "aTexCoord"); + + SceGxmVertexAttribute vertexAttributes[3]; + SceGxmVertexStream vertexStreams[1]; + + // position + vertexAttributes[0].streamIndex = 0; + vertexAttributes[0].offset = 0; + vertexAttributes[0].format = SCE_GXM_ATTRIBUTE_FORMAT_F32; + vertexAttributes[0].componentCount = 3; + vertexAttributes[0].regIndex = sceGxmProgramParameterGetResourceIndex(positionAttribute); + + // normal + vertexAttributes[1].streamIndex = 0; + vertexAttributes[1].offset = 12; + vertexAttributes[1].format = SCE_GXM_ATTRIBUTE_FORMAT_F32; + vertexAttributes[1].componentCount = 3; + vertexAttributes[1].regIndex = sceGxmProgramParameterGetResourceIndex(normalAttribute); + + vertexAttributes[2].streamIndex = 0; + vertexAttributes[2].offset = 24; + vertexAttributes[2].format = SCE_GXM_ATTRIBUTE_FORMAT_F32; + vertexAttributes[2].componentCount = 2; + vertexAttributes[2].regIndex = sceGxmProgramParameterGetResourceIndex(texCoordAttribute); + + vertexStreams[0].stride = sizeof(Vertex); + vertexStreams[0].indexSource = SCE_GXM_INDEX_SOURCE_INDEX_16BIT; + + if(SCE_ERR(sceGxmShaderPatcherCreateVertexProgram, + data->shaderPatcher, + data->mainVertexProgramId, + vertexAttributes, 3, + vertexStreams, 1, + &data->mainVertexProgram + )) { + return false; + } + } + + if(make_fragment_program(data, mainVertexProgramGxp, &blendInfoOpaque, &data->opaqueFragmentProgram)) { + return false; + } + + if(make_fragment_program(data, mainVertexProgramGxp, &blendInfoTransparent, &data->transparentFragmentProgram)) { + return false; + } + + // vertex uniforms + data->uModelViewMatrixParam = sceGxmProgramFindParameterByName(mainVertexProgramGxp, "uModelViewMatrix"); + data->uNormalMatrixParam = sceGxmProgramFindParameterByName(mainVertexProgramGxp, "uNormalMatrix"); + data->uProjectionMatrixParam = sceGxmProgramFindParameterByName(mainVertexProgramGxp, "uProjectionMatrix"); + + // fragment uniforms + data->uLights = sceGxmProgramFindParameterByName(mainFragmentProgramGxp, "uLights"); // SceneLight[3] + data->uLightCount = sceGxmProgramFindParameterByName(mainFragmentProgramGxp, "uLightCount"); // int + data->uShininess = sceGxmProgramFindParameterByName(mainFragmentProgramGxp, "uShininess"); // float + data->uColor = sceGxmProgramFindParameterByName(mainFragmentProgramGxp, "uColor"); // vec4 + data->uUseTexture = sceGxmProgramFindParameterByName(mainFragmentProgramGxp, "uUseTexture"); // int + + + // clear mesh + data->clearMeshBuffer = sceClibMspaceMalloc(data->cdramPool, clearMeshVerticiesSize + clearMeshIndiciesSize); + data->clearVerticies = (float*)data->clearMeshBuffer; + data->clearIndicies = (uint16_t*)((uint8_t*)(data->clearMeshBuffer)+clearMeshVerticiesSize); + + data->clearVerticies[0] = -1.0 * width; + data->clearVerticies[1] = -1.0 * height; + data->clearVerticies[2] = 3.0 * width; + data->clearVerticies[3] = -1.0 * height; + data->clearVerticies[4] = -1.0; + data->clearVerticies[5] = 3.0; + + data->clearIndicies[0] = 0; + data->clearIndicies[1] = 1; + data->clearIndicies[2] = 2; + + // light uniforms buffer + data->lightDataBuffer = sceClibMspaceMalloc(data->cdramPool, + 3 * sizeof(SceneLightGXM) + 4 // 3 lights + light count + ); + sceGxmSetFragmentUniformBuffer(data->context, 0, data->lightDataBuffer); + + sceGxmSetFrontStencilRef(data->context, 1); + sceGxmSetFrontStencilFunc( + data->context, + SCE_GXM_STENCIL_FUNC_ALWAYS, + SCE_GXM_STENCIL_OP_KEEP, + SCE_GXM_STENCIL_OP_KEEP, + SCE_GXM_STENCIL_OP_KEEP, + 0xFF, + 0xFF + ); + return true; +} + + +#define VITA_GXM_PENDING_SWAPS 2 + +/* +#include +static tai_hook_ref_t local_open_hook; + +extern "C" { + SceUID hook_local_open(const char *path, int flags, SceMode mode) { + SceUID fd = ({ + struct _tai_hook_user *cur, *next; + cur = (struct _tai_hook_user *)(local_open_hook); + next = (struct _tai_hook_user *)cur->next; + (next == __null) ? + ((SceUID(*)(const char*, int, int))cur->old)(path, flags, mode) : + ((SceUID(*)(const char*, int, int))next->func)(path, flags, mode); + }); + + printf("open in razor: %s, ret: %x", path, fd); + return fd; + } +} +*/ + +extern "C" void load_razor() { + int mod_id = _sceKernelLoadModule("app0:librazorcapture_es4.suprx", 0, nullptr); + int status; + if(!SCE_ERR(sceKernelStartModule, mod_id, 0, nullptr, 0, nullptr, &status)) { + with_razor = true; + } + + + if(with_razor) { + sceRazorGpuCaptureEnableSalvage("ux0:data/gpu_crash.sgx"); + } +} + + +bool gxm_init() { + if(SDL_gxm_is_init()) { + return true; + } + + SDL_gxm_init(); + + /* + SceGxmInitializeParams initializeParams; + SDL_memset(&initializeParams, 0, sizeof(SceGxmInitializeParams)); + initializeParams.flags = 0; + initializeParams.displayQueueMaxPendingCount = VITA_GXM_PENDING_SWAPS; + initializeParams.displayQueueCallback = display_callback; + initializeParams.displayQueueCallbackDataSize = sizeof(GXMDisplayData); + initializeParams.parameterBufferSize = SCE_GXM_DEFAULT_PARAMETER_BUFFER_SIZE; + + int err = sceGxmInitialize(&initializeParams); + if (err != 0) { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "gxm init failed: %d", err); + return err; + } + */ + return true; +} + +Direct3DRMRenderer* GXMRenderer::Create(DWORD width, DWORD height) +{ + SDL_Log("GXMRenderer::Create width=%d height=%d", width, height); + + bool success = gxm_init(); + if(!success) { + return nullptr; + } + + GXMRendererData gxm_data; + success = create_gxm_renderer(width, height, &gxm_data); + if(!success) { + return nullptr; + } + + return new GXMRenderer(width, height, gxm_data); +} + +GXMRenderer::GXMRenderer( + DWORD width, + DWORD height, + GXMRendererData data +) : m_width(width), m_height(height), m_data(data) { +} + +GXMRenderer::~GXMRenderer() { + if(!m_initialized) { + return; + } + sceGxmShaderPatcherDestroy(this->m_data.shaderPatcher); + sceGxmDestroyRenderTarget(this->m_data.renderTarget); + + vita_mem_free(this->m_data.renderBufferUid); + sceGxmSyncObjectDestroy(this->m_data.renderBufferSync); + + vita_mem_free(this->m_data.depthBufferUid); + this->m_data.depthBufferData = nullptr; + vita_mem_free(this->m_data.stencilBufferUid); + this->m_data.stencilBufferData = nullptr; + + sceGxmDestroyContext(this->m_data.context); + vita_mem_fragment_usse_free(this->m_data.fragmentUsseRingBufferUid); + vita_mem_free(this->m_data.fragmentRingBufferUid); + vita_mem_free(this->m_data.vertexRingBufferUid); + vita_mem_free(this->m_data.vdmRingBufferUid); + SDL_free(this->m_data.contextHostMem); +} + +void* GXMRenderer::AllocateGpu(size_t size, size_t align) { + return sceClibMspaceMemalign(this->m_data.cdramPool, align, size); +} +void GXMRenderer::FreeGpu(void* ptr) { + sceClibMspaceFree(this->m_data.cdramPool, ptr); +} + +void GXMRenderer::PushLights(const SceneLight* lightsArray, size_t count) +{ + if (count > 3) { + SDL_Log("Unsupported number of lights (%d)", static_cast(count)); + count = 3; + } + + m_lights.assign(lightsArray, lightsArray + count); +} + +void GXMRenderer::SetFrustumPlanes(const Plane* frustumPlanes) +{ +} + +void GXMRenderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) +{ + memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); + m_projection[1][1] *= -1.0f; // OpenGL is upside down +} + +struct TextureDestroyContextGLS2 { + GXMRenderer* renderer; + Uint32 textureId; +}; + +void GXMRenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture) +{ + auto* ctx = new TextureDestroyContextGLS2{this, id}; + texture->AddDestroyCallback( + [](IDirect3DRMObject* obj, void* arg) { + auto* ctx = static_cast(arg); + auto& cache = ctx->renderer->m_textures[ctx->textureId]; + void* textureData = sceGxmTextureGetData(&cache.gxmTexture); + ctx->renderer->FreeGpu(textureData); + delete ctx; + }, + ctx + ); +} + +Uint32 GXMRenderer::GetTextureId(IDirect3DRMTexture* iTexture) +{ + auto texture = static_cast(iTexture); + auto surface = static_cast(texture->m_surface); + + for (Uint32 i = 0; i < m_textures.size(); ++i) { + auto& tex = m_textures[i]; + if (tex.texture == texture) { + if (tex.version != texture->m_version) { + SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888); + if (!surf) { + return NO_TEXTURE_ID; + } + void* textureData = sceGxmTextureGetData(&tex.gxmTexture); + memcpy(textureData, surf->pixels, surf->w*surf->h*4); + SDL_DestroySurface(surf); + tex.version = texture->m_version; + } + return i; + } + } + + SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888); + if (!surf) { + return NO_TEXTURE_ID; + } + void* textureData = this->AllocateGpu(surf->w*surf->h*4, SCE_GXM_TEXTURE_ALIGNMENT); + memcpy(textureData, surf->pixels, surf->w*surf->h*4); + SDL_DestroySurface(surf); + + SceGxmTexture gxmTexture; + sceGxmTextureInitLinear(&gxmTexture, textureData, SCE_GXM_TEXTURE_FORMAT_U8U8U8U8_RGBA, surf->w, surf->h, 1); + sceGxmTextureSetMinFilter(&gxmTexture, SCE_GXM_TEXTURE_FILTER_LINEAR); + sceGxmTextureSetMagFilter(&gxmTexture, SCE_GXM_TEXTURE_FILTER_LINEAR); + + for (Uint32 i = 0; i < m_textures.size(); ++i) { + auto& tex = m_textures[i]; + if (!tex.texture) { + tex.texture = texture; + tex.version = texture->m_version; + tex.gxmTexture = gxmTexture; + AddTextureDestroyCallback(i, texture); + return i; + } + } + + m_textures.push_back({texture, texture->m_version, gxmTexture}); + AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture); + return (Uint32) (m_textures.size() - 1); +} + +GXMMeshCacheEntry GXMRenderer::GXMUploadMesh(const MeshGroup& meshGroup) +{ + GXMMeshCacheEntry cache{&meshGroup, meshGroup.version}; + + cache.flat = meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT; + + std::vector vertices; + std::vector indices; + if (cache.flat) { + FlattenSurfaces( + meshGroup.vertices.data(), + meshGroup.vertices.size(), + meshGroup.indices.data(), + meshGroup.indices.size(), + meshGroup.texture != nullptr, + vertices, + indices + ); + } + else { + vertices = meshGroup.vertices; + indices.resize(meshGroup.indices.size()); + std::transform(meshGroup.indices.begin(), meshGroup.indices.end(), indices.begin(), [](DWORD index) { + return static_cast(index); + }); + } + + size_t vertexBufferSize = sizeof(Vertex)*vertices.size(); + size_t indexBufferSize = sizeof(uint16_t)*indices.size(); + void* meshData = this->AllocateGpu(vertexBufferSize+indexBufferSize); + + Vertex* vertexBuffer = (Vertex*)meshData; + uint16_t* indexBuffer = (uint16_t*)((uint8_t*)meshData + vertexBufferSize); + + for(int i = 0; i < vertices.size(); i++) { + D3DRMVERTEX vertex = vertices.data()[i]; + vertexBuffer[i] = Vertex{ + .position = { + vertex.position.x, + vertex.position.y, + vertex.position.z, + }, + .normal = { + vertex.normal.x, + vertex.normal.y, + vertex.normal.z, + }, + .texCoord = { + vertex.tu, + vertex.tv, + } + }; + } + memcpy(indexBuffer, indices.data(), indices.size()*sizeof(uint16_t)); + + cache.meshData = meshData; + cache.vertexBuffer = vertexBuffer; + cache.indexBuffer = indexBuffer; + cache.indexCount = indices.size(); + + return cache; +} + +struct GXMMeshDestroyContext { + GXMRenderer* renderer; + Uint32 id; +}; + +void GXMRenderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh) +{ + auto* ctx = new GXMMeshDestroyContext{this, id}; + mesh->AddDestroyCallback( + [](IDirect3DRMObject*, void* arg) { + auto* ctx = static_cast(arg); + auto& cache = ctx->renderer->m_meshes[ctx->id]; + cache.meshGroup = nullptr; + ctx->renderer->FreeGpu(cache.meshData); + delete ctx; + }, + ctx + ); +} + +Uint32 GXMRenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) +{ + for (Uint32 i = 0; i < m_meshes.size(); ++i) { + auto& cache = m_meshes[i]; + if (cache.meshGroup == meshGroup) { + if (cache.version != meshGroup->version) { + cache = std::move(this->GXMUploadMesh(*meshGroup)); + } + return i; + } + } + + auto newCache = this->GXMUploadMesh(*meshGroup); + + for (Uint32 i = 0; i < m_meshes.size(); ++i) { + auto& cache = m_meshes[i]; + if (!cache.meshGroup) { + cache = std::move(newCache); + AddMeshDestroyCallback(i, mesh); + return i; + } + } + + m_meshes.push_back(std::move(newCache)); + AddMeshDestroyCallback((Uint32) (m_meshes.size() - 1), mesh); + return (Uint32) (m_meshes.size() - 1); +} + +DWORD GXMRenderer::GetWidth() +{ + return m_width; +} + +DWORD GXMRenderer::GetHeight() +{ + return m_height; +} + +void GXMRenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) +{ + halDesc->dcmColorModel = D3DCOLORMODEL::RGB; + halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; + halDesc->dwDeviceZBufferBitDepth = DDBD_16; + halDesc->dwDeviceZBufferBitDepth |= DDBD_32; + helDesc->dwDeviceRenderBitDepth = DDBD_32; + halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; + halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; + halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; + + memset(helDesc, 0, sizeof(D3DDEVICEDESC)); +} + +const char* GXMRenderer::GetName() +{ + return "GXM"; +} + + +bool razor_triggered = false; + +HRESULT GXMRenderer::BeginFrame() +{ + SDL_Log("GXMRenderer::BeginFrame"); + + if(with_razor && !razor_triggered) { + SDL_Log("trigger razor for next frame"); + sceRazorGpuCaptureSetTriggerNextFrame("ux0:/data/capture.sgx"); + razor_triggered = true; + } + + sceGxmBeginScene( + this->m_data.context, + 0, + this->m_data.renderTarget, + nullptr, + nullptr, + this->m_data.renderBufferSync, + &this->m_data.renderSurface, + &this->m_data.depthSurface + ); + + sceGxmSetViewport(this->m_data.context, 0, m_width, 0, m_height, 0, 0); + + // clear screen + sceGxmSetVertexProgram(this->m_data.context, this->m_data.clearVertexProgram); + sceGxmSetFragmentProgram(this->m_data.context, this->m_data.clearFragmentProgram); + sceGxmSetVertexStream(this->m_data.context, 0, this->m_data.clearVerticies); + sceGxmDraw( + this->m_data.context, + SCE_GXM_PRIMITIVE_TRIANGLES, + SCE_GXM_INDEX_FORMAT_U16, + this->m_data.clearIndicies, 3 + ); + + // set light data + int lightCount = std::min(static_cast(m_lights.size()), 3); + + SceneLightGXM* lightData = (SceneLightGXM*)this->m_data.lightDataBuffer; + int* pLightCount = (int*)((uint8_t*)(this->m_data.lightDataBuffer)+sizeof(SceneLightGXM)*3); + *pLightCount = lightCount; + + for (int i = 0; i < lightCount; ++i) { + const auto& src = m_lights[i]; + lightData[i].color[0] = src.color.r; + lightData[i].color[1] = src.color.g; + lightData[i].color[2] = src.color.b; + lightData[i].color[3] = src.color.a; + + lightData[i].position[0] = src.position.x; + lightData[i].position[1] = src.position.y; + lightData[i].position[2] = src.position.z; + lightData[i].position[3] = src.positional; + + lightData[i].direction[0] = src.direction.x; + lightData[i].direction[1] = src.direction.y; + lightData[i].direction[2] = src.direction.z; + lightData[i].direction[3] = src.directional; + } + + sceGxmSetVertexProgram(this->m_data.context, this->m_data.mainVertexProgram); + sceGxmSetFragmentProgram(this->m_data.context, this->m_data.opaqueFragmentProgram); + + return DD_OK; +} + +void GXMRenderer::EnableTransparency() +{ + sceGxmSetFragmentProgram(this->m_data.context, this->m_data.transparentFragmentProgram); +} + +#define SET_UNIFORM(buffer, param, value) \ + do { \ + size_t __offset = sceGxmProgramParameterGetResourceIndex(param); \ + void* __dst = (uint8_t*)(buffer) + (__offset * sizeof(uint32_t)); \ + memcpy(__dst, reinterpret_cast(&(value)), sizeof(value)); \ + } while (0) + +void TransposeD3DRMMATRIX4D(const D3DRMMATRIX4D input, D3DRMMATRIX4D output) { + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + output[j][i] = input[i][j]; + } + } +} + +void GXMRenderer::SubmitDraw( + DWORD meshId, + const D3DRMMATRIX4D& modelViewMatrix, + const Matrix3x3& normalMatrix, + const Appearance& appearance +) +{ + auto& mesh = m_meshes[meshId]; + + void* vertUniforms; + void* fragUniforms; + sceGxmReserveVertexDefaultUniformBuffer(this->m_data.context, &vertUniforms); + sceGxmReserveFragmentDefaultUniformBuffer(this->m_data.context, &fragUniforms); + + SET_UNIFORM(vertUniforms, this->m_data.uModelViewMatrixParam, modelViewMatrix); + SET_UNIFORM(vertUniforms, this->m_data.uNormalMatrixParam, normalMatrix); + SET_UNIFORM(vertUniforms, this->m_data.uProjectionMatrixParam, m_projection); + + float color[4] = { + appearance.color.r / 255.0f, + appearance.color.g / 255.0f, + appearance.color.b / 255.0f, + appearance.color.a / 255.0f + }; + SET_UNIFORM(fragUniforms, this->m_data.uColor, color); + SET_UNIFORM(fragUniforms, this->m_data.uShininess, appearance.shininess); + + int useTexture = appearance.textureId != NO_TEXTURE_ID ? 1 : 0; + SET_UNIFORM(fragUniforms, this->m_data.uUseTexture, useTexture); + if(useTexture) { + auto& texture = m_textures[appearance.textureId]; + sceGxmSetFragmentTexture(this->m_data.context, 0, &texture.gxmTexture); + } + + sceGxmSetVertexStream(this->m_data.context, 0, mesh.vertexBuffer); + sceGxmDraw( + this->m_data.context, + SCE_GXM_PRIMITIVE_TRIANGLES, + SCE_GXM_INDEX_FORMAT_U16, + mesh.indexBuffer, + mesh.indexCount + ); +} + +HRESULT GXMRenderer::FinalizeFrame() +{ + sceGxmEndScene( + this->m_data.context, + nullptr, nullptr + ); + + SDL_Surface* renderedImage = SDL_CreateSurfaceFrom( + m_width, m_height, SDL_PIXELFORMAT_ABGR8888, + this->m_data.renderBuffer, this->m_width*4 + ); + SDL_BlitSurface(renderedImage, nullptr, DDBackBuffer, nullptr); + SDL_DestroySurface(renderedImage); + + return DD_OK; +} diff --git a/miniwin/src/d3drm/backends/gxm/utils.h b/miniwin/src/d3drm/backends/gxm/utils.h new file mode 100644 index 00000000..c0bfdd07 --- /dev/null +++ b/miniwin/src/d3drm/backends/gxm/utils.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +static bool _sce_err(const char* expr, int err) { + if(err >= 0) { + SDL_Log("sce: %s", expr); + return false; + } + SDL_Log("SCE_ERR: %s failed 0x%x", expr, err); + return true; +} + +#define SCE_ERR(func, ...) _sce_err(#func, func(__VA_ARGS__)) + +#define ALIGN(x, a) (((x) + ((a)-1)) & ~((a)-1)) + +#define INCBIN(filename, symbol) \ + __asm__( \ + ".balign 16 \n" \ + #symbol ":" \ + ".incbin \"" filename "\"" \ + ); \ + extern const void* symbol diff --git a/miniwin/src/d3drm/d3drm.cpp b/miniwin/src/d3drm/d3drm.cpp index 01375d8c..89385ab9 100644 --- a/miniwin/src/d3drm/d3drm.cpp +++ b/miniwin/src/d3drm/d3drm.cpp @@ -16,6 +16,9 @@ #ifdef _WIN32 #include "d3drmrenderer_directx9.h" #endif +#ifdef __vita__ +#include "d3drmrenderer_gxm.h" +#endif #include "d3drmrenderer_sdl3gpu.h" #include "d3drmrenderer_software.h" #include "d3drmtexture_impl.h" @@ -164,6 +167,11 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface( else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) { renderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } +#endif +#ifdef __vita__ + else if (SDL_memcmp(&guid, &GXM_GUID, sizeof(GUID)) == 0) { + renderer = GXMRenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + } #endif else { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized"); diff --git a/miniwin/src/ddraw/ddraw.cpp b/miniwin/src/ddraw/ddraw.cpp index d0ba9995..c8d38fd2 100644 --- a/miniwin/src/ddraw/ddraw.cpp +++ b/miniwin/src/ddraw/ddraw.cpp @@ -7,6 +7,9 @@ #ifdef _WIN32 #include "d3drmrenderer_directx9.h" #endif +#ifdef __vita__ +#include "d3drmrenderer_gxm.h" +#endif #include "d3drmrenderer_sdl3gpu.h" #include "d3drmrenderer_software.h" #include "ddpalette_impl.h" @@ -222,15 +225,20 @@ void EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx, Direct3DRMRenderer* devi HRESULT DirectDrawImpl::EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) { +#ifndef __vita__ Direct3DRMSDL3GPU_EnumDevice(cb, ctx); +#endif #ifdef USE_OPENGLES2 - OpenGLES2Renderer_EnumDevice(cb, ctx); + //OpenGLES2Renderer_EnumDevice(cb, ctx); #endif #ifdef USE_OPENGL1 OpenGL1Renderer_EnumDevice(cb, ctx); #endif #ifdef _WIN32 DirectX9Renderer_EnumDevice(cb, ctx); +#endif +#ifdef __vita__ + //GXMRenderer_EnumDevice(cb, ctx); #endif Direct3DRMSoftware_EnumDevice(cb, ctx); @@ -296,8 +304,7 @@ HRESULT DirectDrawImpl::SetCooperativeLevel(HWND hWnd, DDSCLFlags dwFlags) return DDERR_INVALIDPARAMS; } - -#ifdef __vita__ +#if defined(__vita__) && defined(USE_OPENGLES2) const char* sdlRendererName = "opengles2"; #else const char* sdlRendererName = nullptr; @@ -350,6 +357,11 @@ HRESULT DirectDrawImpl::CreateDevice( else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) { renderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } +#endif +#ifdef __vita__ + else if (SDL_memcmp(&guid, &GXM_GUID, sizeof(GUID)) == 0) { + renderer = GXMRenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + } #endif else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) { renderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); diff --git a/miniwin/src/internal/d3drmrenderer_gxm.h b/miniwin/src/internal/d3drmrenderer_gxm.h new file mode 100644 index 00000000..76a12a30 --- /dev/null +++ b/miniwin/src/internal/d3drmrenderer_gxm.h @@ -0,0 +1,167 @@ +#pragma once + +#include "d3drmrenderer.h" +#include "d3drmtexture_impl.h" +#include "ddraw_impl.h" + +#include +#include + +#include +#include +#include + +DEFINE_GUID(GXM_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x58, 0x4D); + +#define VITA_GXM_DISPLAY_BUFFER_COUNT 2 + +struct GXMTextureCacheEntry { + IDirect3DRMTexture* texture; + Uint32 version; + SceGxmTexture gxmTexture; +}; + +struct GXMMeshCacheEntry { + const MeshGroup* meshGroup; + int version; + bool flat; + + void* meshData; + void* vertexBuffer; + void* indexBuffer; + uint16_t indexCount; +}; + +typedef struct GXMRendererInit { + SceGxmContext* context; + SceGxmShaderPatcher* shaderPatcher; + SceClibMspace gpuPool; +} GXMRendererInit; + +typedef struct GXMRendererData { + SceUID vdmRingBufferUid; + SceUID vertexRingBufferUid; + SceUID fragmentRingBufferUid; + SceUID fragmentUsseRingBufferUid; + size_t fragmentUsseRingBufferOffset; + + void* vdmRingBuffer; + void* vertexRingBuffer; + void* fragmentRingBuffer; + void* fragmentUsseRingBuffer; + + SceClibMspace cdramPool; + + void* contextHostMem; + SceGxmContext* context; + + SceGxmRenderTarget* renderTarget; + SceUID renderBufferUid; + void* renderBuffer; + SceGxmColorSurface renderSurface; + SceGxmSyncObject* renderBufferSync; + + SceUID depthBufferUid; + void* depthBufferData; + SceUID stencilBufferUid; + void* stencilBufferData; + SceGxmDepthStencilSurface depthSurface; + + SceUID patcherBufferUid; + void* patcherBuffer; + + SceUID patcherVertexUsseUid; + size_t patcherVertexUsseOffset; + void* patcherVertexUsse; + + SceUID patcherFragmentUsseUid; + size_t patcherFragmentUsseOffset; + void* patcherFragmentUsse; + + SceGxmShaderPatcher* shaderPatcher; + + SceGxmShaderPatcherId clearVertexProgramId; + SceGxmVertexProgram* clearVertexProgram; + SceGxmShaderPatcherId clearFragmentProgramId; + SceGxmFragmentProgram* clearFragmentProgram; + + SceGxmShaderPatcherId mainVertexProgramId; + SceGxmShaderPatcherId mainFragmentProgramId; + SceGxmVertexProgram* mainVertexProgram; + SceGxmFragmentProgram* opaqueFragmentProgram; + SceGxmFragmentProgram* transparentFragmentProgram; + + const SceGxmProgramParameter* uModelViewMatrixParam; + const SceGxmProgramParameter* uNormalMatrixParam; + const SceGxmProgramParameter* uProjectionMatrixParam; + + const SceGxmProgramParameter* uLights; + const SceGxmProgramParameter* uLightCount; + const SceGxmProgramParameter* uShininess; + const SceGxmProgramParameter* uColor; + const SceGxmProgramParameter* uUseTexture; + + void* clearMeshBuffer; + float* clearVerticies; + uint16_t* clearIndicies; + + void* lightDataBuffer; +} GXMRendererData; + +class GXMRenderer : public Direct3DRMRenderer { +public: + static Direct3DRMRenderer* Create(DWORD width, DWORD height); + GXMRenderer( + DWORD width, + DWORD height, + GXMRendererData data + ); + GXMRenderer(int forEnum) {}; + ~GXMRenderer() override; + + void PushLights(const SceneLight* lightsArray, size_t count) override; + void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; + void SetFrustumPlanes(const Plane* frustumPlanes) override; + Uint32 GetTextureId(IDirect3DRMTexture* texture) override; + Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; + DWORD GetWidth() override; + DWORD GetHeight() override; + void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; + const char* GetName() override; + HRESULT BeginFrame() override; + void EnableTransparency() override; + void SubmitDraw( + DWORD meshId, + const D3DRMMATRIX4D& modelViewMatrix, + const Matrix3x3& normalMatrix, + const Appearance& appearance + ) override; + HRESULT FinalizeFrame() override; + +private: + void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); + void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); + + void* AllocateGpu(size_t size, size_t align = 4); + void FreeGpu(void* ptr); + + GXMMeshCacheEntry GXMUploadMesh(const MeshGroup& meshGroup); + + std::vector m_textures; + std::vector m_meshes; + D3DRMMATRIX4D m_projection; + DWORD m_width, m_height; + std::vector m_lights; + + GXMRendererData m_data; + bool m_initialized = false; +}; + +inline static void GXMRenderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) +{ + Direct3DRMRenderer* device = new GXMRenderer(1); + if (device) { + EnumDevice(cb, ctx, device, GXM_GUID); + delete device; + } +} diff --git a/sdl3.patch b/sdl3.patch new file mode 100644 index 00000000..2f2c218e --- /dev/null +++ b/sdl3.patch @@ -0,0 +1,413 @@ +diff --git a/include/SDL3/SDL_gxm.h b/include/SDL3/SDL_gxm.h +new file mode 100644 +index 000000000..1a80e2664 +--- /dev/null ++++ b/include/SDL3/SDL_gxm.h +@@ -0,0 +1,33 @@ ++#ifndef SDL_gxm_h_ ++#define SDL_gxm_h_ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++/* Set up for C function definitions, even when using C++ */ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef struct { ++ void *address; ++ Uint8 wait_vblank; ++} VITA_GXM_DisplayData; ++ ++extern SceClibMspace SDL_gxm_get_cdramPool(); ++ ++extern int SDL_gxm_init(); ++extern bool SDL_gxm_is_init(); ++ ++ ++/* Ends C function definitions when using C++ */ ++#ifdef __cplusplus ++} ++#endif ++#include ++ ++#endif +\ No newline at end of file +diff --git a/src/SDL_error.c b/src/SDL_error.c +index 3f4273b4f..e41b8d81b 100644 +--- a/src/SDL_error.c ++++ b/src/SDL_error.c +@@ -66,7 +66,7 @@ bool SDL_SetErrorV(SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) + // Enable this if you want to see all errors printed as they occur. + // Note that there are many recoverable errors that may happen internally and + // can be safely ignored if the public API doesn't return an error code. +-#if 0 ++#if 1 + SDL_LogError(SDL_LOG_CATEGORY_ERROR, "%s", error->str); + #endif + } +diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c +index 0a088a8b4..cace29340 100644 +--- a/src/render/SDL_render.c ++++ b/src/render/SDL_render.c +@@ -2871,7 +2871,7 @@ static void SDL_RenderLogicalPresentation(SDL_Renderer *renderer) + + // now set everything back. + view->logical_presentation_mode = mode; +- SDL_SetRenderViewport(renderer, &orig_viewport); ++ //SDL_SetRenderViewport(renderer, &orig_viewport); + if (clipping_enabled) { + SDL_SetRenderClipRect(renderer, &orig_cliprect); + } +@@ -3040,7 +3040,7 @@ bool SDL_SetRenderViewport(SDL_Renderer *renderer, const SDL_Rect *rect) + SDL_RenderViewState *view = renderer->view; + if (rect) { + if ((rect->w < 0) || (rect->h < 0)) { +- return SDL_SetError("rect has a negative size"); ++ return SDL_SetError("rect has a negative size %d %d", rect->w, rect->h); + } + SDL_copyp(&view->viewport, rect); + } else { +diff --git a/src/render/opengles2/SDL_shaders_gles2.c b/src/render/opengles2/SDL_shaders_gles2.c +index 3bff21178..0b6dace68 100644 +--- a/src/render/opengles2/SDL_shaders_gles2.c ++++ b/src/render/opengles2/SDL_shaders_gles2.c +@@ -130,9 +130,7 @@ static const char GLES2_Fragment_TextureARGB[] = + "void main()\n" + "{\n" + " mediump vec4 color = texture2D(u_texture, v_texCoord);\n" +-" gl_FragColor = color;\n" +-" gl_FragColor.r = color.b;\n" +-" gl_FragColor.b = color.r;\n" ++" gl_FragColor.rgba = color.bgra;\n" + " gl_FragColor *= v_color;\n" + "}\n" + ; +@@ -144,9 +142,7 @@ static const char GLES2_Fragment_TextureRGB[] = + "void main()\n" + "{\n" + " mediump vec4 color = texture2D(u_texture, v_texCoord);\n" +-" gl_FragColor = color;\n" +-" gl_FragColor.r = color.b;\n" +-" gl_FragColor.b = color.r;\n" ++" gl_FragColor.rgb = color.bgr;\n" + " gl_FragColor.a = 1.0;\n" + " gl_FragColor *= v_color;\n" + "}\n" +@@ -183,9 +179,7 @@ static const char GLES2_Fragment_TextureARGB_PixelArt[] = + "void main()\n" + "{\n" + RGB_PIXELART_GETCOLOR +-" gl_FragColor = color;\n" +-" gl_FragColor.r = color.b;\n" +-" gl_FragColor.b = color.r;\n" ++" gl_FragColor.rgba = color.bgra;\n" + " gl_FragColor *= v_color;\n" + "}\n" + ; +@@ -197,9 +191,7 @@ static const char GLES2_Fragment_TextureRGB_PixelArt[] = + "void main()\n" + "{\n" + RGB_PIXELART_GETCOLOR +-" gl_FragColor = color;\n" +-" gl_FragColor.r = color.b;\n" +-" gl_FragColor.b = color.r;\n" ++" gl_FragColor.rgb = color.bgr;\n" + " gl_FragColor.a = 1.0;\n" + " gl_FragColor *= v_color;\n" + "}\n" +diff --git a/src/render/vitagxm/SDL_render_vita_gxm.c b/src/render/vitagxm/SDL_render_vita_gxm.c +index 039155b73..dc1640634 100644 +--- a/src/render/vitagxm/SDL_render_vita_gxm.c ++++ b/src/render/vitagxm/SDL_render_vita_gxm.c +@@ -1197,6 +1197,11 @@ static bool VITA_GXM_RenderPresent(SDL_Renderer *renderer) + VITA_GXM_RenderData *data = (VITA_GXM_RenderData *)renderer->internal; + SceCommonDialogUpdateParam updateParam; + ++ uint32_t* pixels = data->displayBufferData[data->backBufferIndex]; ++ for(int i = 0; i < 10*960; i++) { ++ pixels[i] = 0xffffffff; ++ } ++ + data->displayData.address = data->displayBufferData[data->backBufferIndex]; + + SDL_memset(&updateParam, 0, sizeof(updateParam)); +diff --git a/src/render/vitagxm/SDL_render_vita_gxm_memory.c b/src/render/vitagxm/SDL_render_vita_gxm_memory.c +index e37a345c3..1a3904433 100644 +--- a/src/render/vitagxm/SDL_render_vita_gxm_memory.c ++++ b/src/render/vitagxm/SDL_render_vita_gxm_memory.c +@@ -25,6 +25,9 @@ + + #include "SDL_render_vita_gxm_memory.h" + ++static SceUID cdramPoolUID = -1; ++static SceClibMspace cdramPool = NULL; ++ + void *vita_mem_alloc(unsigned int type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid) + { + void *mem; +@@ -64,61 +67,70 @@ void vita_mem_free(SceUID uid) + sceKernelFreeMemBlock(uid); + } + +-void *vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int size) +-{ +- void *mem; ++static bool cdramPool_init() { ++ if(cdramPool) { ++ return true; ++ } ++ int poolsize; ++ int ret; ++ void* mem; ++ SceKernelFreeMemorySizeInfo info; ++ info.size = sizeof(SceKernelFreeMemorySizeInfo); ++ sceKernelGetFreeMemorySize(&info); ++ ++ poolsize = ALIGN(info.size_cdram, 256 * 1024); ++ if (poolsize > info.size_cdram) { ++ poolsize = ALIGN(info.size_cdram - 256 * 1024, 256 * 1024); ++ } ++ poolsize -= 16 * 1024 * 1024; ++ cdramPoolUID = sceKernelAllocMemBlock("gpu_cdram_pool", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, poolsize, NULL); ++ if (cdramPool < 0) { ++ return false; ++ } + +- if (!data->texturePool) { +- int poolsize; +- int ret; +- SceKernelFreeMemorySizeInfo info; +- info.size = sizeof(SceKernelFreeMemorySizeInfo); +- sceKernelGetFreeMemorySize(&info); ++ ret = sceKernelGetMemBlockBase(cdramPoolUID, &mem); ++ if (ret < 0) { ++ return false; ++ } ++ cdramPool = sceClibMspaceCreate(mem, poolsize); + +- poolsize = ALIGN(info.size_cdram, 256 * 1024); +- if (poolsize > info.size_cdram) { +- poolsize = ALIGN(info.size_cdram - 256 * 1024, 256 * 1024); +- } +- data->texturePoolUID = sceKernelAllocMemBlock("gpu_texture_pool", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, poolsize, NULL); +- if (data->texturePoolUID < 0) { +- return NULL; +- } ++ if (!cdramPool) { ++ return false; ++ } ++ ret = sceGxmMapMemory(mem, poolsize, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE); ++ if (ret < 0) { ++ return false; ++ } ++ return true; ++} + +- ret = sceKernelGetMemBlockBase(data->texturePoolUID, &mem); +- if (ret < 0) { +- return NULL; +- } +- data->texturePool = sceClibMspaceCreate(mem, poolsize); ++SceClibMspace SDL_gxm_get_cdramPool() { ++ cdramPool_init(); ++ return cdramPool; ++} + +- if (!data->texturePool) { +- return NULL; +- } +- ret = sceGxmMapMemory(mem, poolsize, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE); +- if (ret < 0) { +- return NULL; +- } +- } +- return sceClibMspaceMemalign(data->texturePool, SCE_GXM_TEXTURE_ALIGNMENT, size); ++void *vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int alignment, unsigned int size) ++{ ++ cdramPool_init(); ++ return sceClibMspaceMemalign(cdramPool, alignment, size); + } + + void vita_gpu_mem_free(VITA_GXM_RenderData *data, void *ptr) + { +- if (data->texturePool) { +- sceClibMspaceFree(data->texturePool, ptr); +- } ++ sceClibMspaceFree(cdramPool, ptr); + } + + void vita_gpu_mem_destroy(VITA_GXM_RenderData *data) + { + void *mem = NULL; +- if (data->texturePool) { +- sceClibMspaceDestroy(data->texturePool); +- data->texturePool = NULL; +- if (sceKernelGetMemBlockBase(data->texturePoolUID, &mem) < 0) { ++ if (cdramPool) { ++ sceClibMspaceDestroy(cdramPool); ++ cdramPool = NULL; ++ if (sceKernelGetMemBlockBase(cdramPoolUID, &mem) < 0) { + return; + } + sceGxmUnmapMemory(mem); +- sceKernelFreeMemBlock(data->texturePoolUID); ++ sceKernelFreeMemBlock(cdramPoolUID); + } + } + +diff --git a/src/render/vitagxm/SDL_render_vita_gxm_memory.h b/src/render/vitagxm/SDL_render_vita_gxm_memory.h +index cc548b3ba..18d011c8b 100644 +--- a/src/render/vitagxm/SDL_render_vita_gxm_memory.h ++++ b/src/render/vitagxm/SDL_render_vita_gxm_memory.h +@@ -31,7 +31,7 @@ + + void *vita_mem_alloc(unsigned int type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid); + void vita_mem_free(SceUID uid); +-void *vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int size); ++void *vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int alignment, unsigned int size); + void vita_gpu_mem_free(VITA_GXM_RenderData *data, void *ptr); + void vita_gpu_mem_destroy(VITA_GXM_RenderData *data); + void *vita_mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); +diff --git a/src/render/vitagxm/SDL_render_vita_gxm_tools.c b/src/render/vitagxm/SDL_render_vita_gxm_tools.c +index 48af7b8f6..b12a5bfd9 100644 +--- a/src/render/vitagxm/SDL_render_vita_gxm_tools.c ++++ b/src/render/vitagxm/SDL_render_vita_gxm_tools.c +@@ -291,6 +291,38 @@ void unset_clip_rectangle(VITA_GXM_RenderData *data) + 0xFF); + } + ++static bool gxm_initialized = false; ++ ++bool SDL_gxm_is_init() { ++ return gxm_initialized; ++} ++ ++__weak_symbol void load_razor() {} ++ ++int SDL_gxm_init() { ++ if(gxm_initialized) { ++ return 0; ++ } ++ ++ load_razor(); ++ ++ SceGxmInitializeParams initializeParams; ++ SDL_memset(&initializeParams, 0, sizeof(SceGxmInitializeParams)); ++ initializeParams.flags = 0; ++ initializeParams.displayQueueMaxPendingCount = VITA_GXM_PENDING_SWAPS; ++ initializeParams.displayQueueCallback = display_callback; ++ initializeParams.displayQueueCallbackDataSize = sizeof(VITA_GXM_DisplayData); ++ initializeParams.parameterBufferSize = SCE_GXM_DEFAULT_PARAMETER_BUFFER_SIZE; ++ ++ int err = sceGxmInitialize(&initializeParams); ++ if (err != 0) { ++ SDL_LogError(SDL_LOG_CATEGORY_RENDER, "gxm init failed: %d", err); ++ return err; ++ } ++ gxm_initialized = true; ++ return 0; ++} ++ + int gxm_init(SDL_Renderer *renderer) + { + unsigned int i, x, y; +@@ -376,18 +408,8 @@ int gxm_init(SDL_Renderer *renderer) + + VITA_GXM_RenderData *data = (VITA_GXM_RenderData *)renderer->internal; + +- SceGxmInitializeParams initializeParams; +- SDL_memset(&initializeParams, 0, sizeof(SceGxmInitializeParams)); +- initializeParams.flags = 0; +- initializeParams.displayQueueMaxPendingCount = VITA_GXM_PENDING_SWAPS; +- initializeParams.displayQueueCallback = display_callback; +- initializeParams.displayQueueCallbackDataSize = sizeof(VITA_GXM_DisplayData); +- initializeParams.parameterBufferSize = SCE_GXM_DEFAULT_PARAMETER_BUFFER_SIZE; +- +- err = sceGxmInitialize(&initializeParams); +- +- if (err != 0) { +- SDL_LogError(SDL_LOG_CATEGORY_RENDER, "gxm init failed: %d", err); ++ err = SDL_gxm_init(); ++ if(err != 0) { + return err; + } + +@@ -464,6 +486,10 @@ int gxm_init(SDL_Renderer *renderer) + SCE_GXM_COLOR_SURFACE_ALIGNMENT, + SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, + &data->displayBufferUid[i]); ++ if(!data->displayBufferData[i]) { ++ SDL_Log("failed to allocate display buffer"); ++ return -1; ++ } + + // SDL_memset the buffer to black + for (y = 0; y < VITA_GXM_SCREEN_HEIGHT; y++) { +@@ -535,7 +561,6 @@ int gxm_init(SDL_Renderer *renderer) + SCE_GXM_STENCIL_OP_KEEP, + 0xFF, + 0xFF); +- + // allocate memory for buffers and USSE code + patcherBuffer = vita_mem_alloc( + SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, +@@ -1012,6 +1037,7 @@ gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsig + // Allocate a GPU buffer for the texture + texture_data = vita_gpu_mem_alloc( + data, ++ SCE_GXM_TEXTURE_ALIGNMENT, + tex_size); + + // Try SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE in case we're out of VRAM +diff --git a/src/render/vitagxm/SDL_render_vita_gxm_types.h b/src/render/vitagxm/SDL_render_vita_gxm_types.h +index 6fc2c9e81..06ccecc91 100644 +--- a/src/render/vitagxm/SDL_render_vita_gxm_types.h ++++ b/src/render/vitagxm/SDL_render_vita_gxm_types.h +@@ -25,6 +25,7 @@ + #include "SDL_internal.h" + + #include "../SDL_sysrender.h" ++#include + + #include + #include +@@ -47,12 +48,6 @@ + #define VITA_GXM_PENDING_SWAPS 2 + #define VITA_GXM_POOL_SIZE 2 * 1024 * 1024 + +-typedef struct +-{ +- void *address; +- Uint8 wait_vblank; +-} VITA_GXM_DisplayData; +- + typedef struct clear_vertex + { + float x; +@@ -193,8 +188,6 @@ typedef struct + blend_fragment_programs blendFragmentPrograms; + + gxm_drawstate_cache drawstate; +- SceClibMspace texturePool; +- SceUID texturePoolUID; + } VITA_GXM_RenderData; + + typedef struct +diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c +index f40a92d85..b46b94730 100644 +--- a/src/video/SDL_surface.c ++++ b/src/video/SDL_surface.c +@@ -271,6 +271,7 @@ SDL_Surface *SDL_CreateSurfaceFrom(int width, int height, SDL_PixelFormat format + } + + if (pitch < 0 || (size_t)pitch < minimalPitch) { ++ SDL_Log("pitch=%d minimalPitch=%d", pitch, minimalPitch); + SDL_InvalidParamError("pitch"); + return NULL; + }