Francisco José García García 51922ea5be Squashed 'deps/vitaGL/' changes from c816fec50f..2934af8af0
2934af8af0 Added Patreon sponsor link.
c8f18b6f0f Getting current program only when required for vglDrawObjects.
4c5d136b0d Added directive to enable vitaShaRK usage from cmd.
4a10df3be5 Minor adjustments and bugfixes.
14a0124acf Added GL_TEXTURE_LOD_BIAS support.
40c8c6205e Added GL_NONE def and fixed glUniform4f impl.
868079c51e Added glUniform4f implementation.
0a682cbad2 Typo fix.
be3ce61ae7 Added GL_DEPTH_BITS and GL_STENCIL_BITS support.
21e6d1d330 Added runtime shader compiler support.
696e40bc62 Beautify error handler code.
537b37b110 Added glUniform3fv implementation.
7dd1403015 Fixed GLenum size and added missing types defines.
0c75f27ff1 Moved to NEON optimized memcpy usage.
98951895de Added gluPerspective implementation.
23e0b0b309 Fix for vglInitExtended not working on sys app mode.
4989c33ef5 Run clang-format.
429f1c1d8a Added system mode support.
9231680d02 Initializing sceGxm before free mem checking on vglInitExtended.
091e5e7882 Added vglInitWithCustomSizes.
f4c646ea78 Added vglSetParamBufferSize.
1b9a063c41 Beautify some code.
089e81efc5 Fix for duplicated symbols
789dcbf812 Typo fix in readRGBA4444.
1514a4b2cb Disabling lto due to it being broken on vitasdk with gcc 9.1.
fca18d9ab7 Added support for RGBA4444 texture format.
d449f12808 Added support for RGB565 texture format.

git-subtree-dir: deps/vitaGL
git-subtree-split: 2934af8af083a9acf598ab75233c518a251c6f0d
2020-07-05 11:43:47 +02:00

473 lines
18 KiB
C

/*
* This file is part of vitaGL
* Copyright 2017, 2018, 2019, 2020 Rinnegatamante
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* gxm.c:
* Implementation for setup and cleanup for sceGxm specific stuffs
*/
#include "shared.h"
static uint32_t gxm_param_buf_size = SCE_GXM_DEFAULT_PARAMETER_BUFFER_SIZE; // Param buffer size for sceGxm
static void *vdm_ring_buffer_addr; // VDM ring buffer memblock starting address
static void *vertex_ring_buffer_addr; // vertex ring buffer memblock starting address
static void *fragment_ring_buffer_addr; // fragment ring buffer memblock starting address
static void *fragment_usse_ring_buffer_addr; // fragment USSE ring buffer memblock starting address
static SceGxmRenderTarget *gxm_render_target; // Display render target
static SceGxmColorSurface gxm_color_surfaces[DISPLAY_BUFFER_COUNT]; // Display color surfaces
static void *gxm_color_surfaces_addr[DISPLAY_BUFFER_COUNT]; // Display color surfaces memblock starting addresses
static SceGxmSyncObject *gxm_sync_objects[DISPLAY_BUFFER_COUNT]; // Display sync objects
static unsigned int gxm_front_buffer_index; // Display front buffer id
static unsigned int gxm_back_buffer_index; // Display back buffer id
static unsigned int gxm_scene_flags = 0; // Current gxm scene flags
static void *gxm_shader_patcher_buffer_addr; // Shader PAtcher buffer memblock starting address
static void *gxm_shader_patcher_vertex_usse_addr; // Shader Patcher vertex USSE memblock starting address
static void *gxm_shader_patcher_fragment_usse_addr; // Shader Patcher fragment USSE memblock starting address
static void *gxm_depth_surface_addr; // Depth surface memblock starting address
static void *gxm_stencil_surface_addr; // Stencil surface memblock starting address
static SceGxmDepthStencilSurface gxm_depth_stencil_surface; // Depth/Stencil surfaces setup for sceGxm
static SceUID shared_fb; // In-use hared framebuffer identifier
static SceSharedFbInfo shared_fb_info; // In-use shared framebuffer info struct
SceGxmContext *gxm_context; // sceGxm context instance
GLenum vgl_error = GL_NO_ERROR; // Error returned by glGetError
SceGxmShaderPatcher *gxm_shader_patcher; // sceGxmShaderPatcher shader patcher instance
matrix4x4 mvp_matrix; // ModelViewProjection Matrix
matrix4x4 projection_matrix; // Projection Matrix
matrix4x4 modelview_matrix; // ModelView Matrix
int DISPLAY_WIDTH; // Display width in pixels
int DISPLAY_HEIGHT; // Display height in pixels
int DISPLAY_STRIDE; // Display stride in pixels
float DISPLAY_WIDTH_FLOAT; // Display width in pixels (float)
float DISPLAY_HEIGHT_FLOAT; // Display height in pixels (float)
uint8_t system_app_mode = 0; // Flag for system app mode usage
static uint8_t gxm_initialized = 0; // Current sceGxm state
// sceDisplay callback data
struct display_queue_callback_data {
void *addr;
};
// sceGxmShaderPatcher custom allocator
static void *shader_patcher_host_alloc_cb(void *user_data, unsigned int size) {
return malloc(size);
}
// sceGxmShaderPatcher custom deallocator
static void shader_patcher_host_free_cb(void *user_data, void *mem) {
free(mem);
}
// sceDisplay callback
static void display_queue_callback(const void *callbackData) {
// Populating sceDisplay framebuffer parameters
SceDisplayFrameBuf display_fb;
const struct display_queue_callback_data *cb_data = callbackData;
memset(&display_fb, 0, sizeof(SceDisplayFrameBuf));
display_fb.size = sizeof(SceDisplayFrameBuf);
display_fb.base = cb_data->addr;
display_fb.pitch = DISPLAY_STRIDE;
display_fb.pixelformat = SCE_DISPLAY_PIXELFORMAT_A8B8G8R8;
display_fb.width = DISPLAY_WIDTH;
display_fb.height = DISPLAY_HEIGHT;
// Setting sceDisplay framebuffer
sceDisplaySetFrameBuf(&display_fb, SCE_DISPLAY_SETBUF_NEXTFRAME);
// Performing VSync if enabled
if (vblank)
sceDisplayWaitVblankStart();
}
void initGxm(void) {
if (gxm_initialized)
return;
// Initializing runtime shader compiler
if (use_shark) {
#ifdef HAVE_SHARK
if (shark_init(NULL) >= 0)
is_shark_online = 1;
else
#endif
is_shark_online = 0;
}
// Checking if the running application is a system one
SceAppMgrBudgetInfo info;
info.size = sizeof(SceAppMgrBudgetInfo);
if (!sceAppMgrGetBudgetInfo(&info))
system_app_mode = 1;
// Initializing sceGxm init parameters
SceGxmInitializeParams gxm_init_params;
memset(&gxm_init_params, 0, sizeof(SceGxmInitializeParams));
gxm_init_params.flags = system_app_mode ? 0x0A : 0;
gxm_init_params.displayQueueMaxPendingCount = DISPLAY_BUFFER_COUNT - 1;
gxm_init_params.displayQueueCallback = display_queue_callback;
gxm_init_params.displayQueueCallbackDataSize = sizeof(struct display_queue_callback_data);
gxm_init_params.parameterBufferSize = gxm_param_buf_size;
// Initializing sceGxm
if (system_app_mode)
sceGxmVshInitialize(&gxm_init_params);
else
sceGxmInitialize(&gxm_init_params);
gxm_initialized = 1;
}
void initGxmContext(void) {
vglMemType type = VGL_MEM_VRAM;
// Allocating VDM ring buffer
vdm_ring_buffer_addr = gpu_alloc_mapped(SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE, &type);
// Allocating vertex ring buffer
vertex_ring_buffer_addr = gpu_alloc_mapped(SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE, &type);
// Allocating fragment ring buffer
fragment_ring_buffer_addr = gpu_alloc_mapped(SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE, &type);
// Allocating fragment USSE ring buffer
unsigned int fragment_usse_offset;
fragment_usse_ring_buffer_addr = gpu_fragment_usse_alloc_mapped(
SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE, &fragment_usse_offset);
// Setting sceGxm context parameters
SceGxmContextParams gxm_context_params;
memset(&gxm_context_params, 0, sizeof(SceGxmContextParams));
gxm_context_params.hostMem = malloc(SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE);
gxm_context_params.hostMemSize = SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE;
gxm_context_params.vdmRingBufferMem = vdm_ring_buffer_addr;
gxm_context_params.vdmRingBufferMemSize = SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE;
gxm_context_params.vertexRingBufferMem = vertex_ring_buffer_addr;
gxm_context_params.vertexRingBufferMemSize = SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE;
gxm_context_params.fragmentRingBufferMem = fragment_ring_buffer_addr;
gxm_context_params.fragmentRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE;
gxm_context_params.fragmentUsseRingBufferMem = fragment_usse_ring_buffer_addr;
gxm_context_params.fragmentUsseRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE;
gxm_context_params.fragmentUsseRingBufferOffset = fragment_usse_offset;
// Initializing sceGxm context
sceGxmCreateContext(&gxm_context_params, &gxm_context);
}
void termGxmContext(void) {
// Deallocating ring buffers
mempool_free(vdm_ring_buffer_addr, VGL_MEM_VRAM);
mempool_free(vertex_ring_buffer_addr, VGL_MEM_VRAM);
mempool_free(fragment_ring_buffer_addr, VGL_MEM_VRAM);
gpu_fragment_usse_free_mapped(fragment_usse_ring_buffer_addr);
// Destroying sceGxm context
sceGxmDestroyContext(gxm_context);
if (system_app_mode) {
sceSharedFbBegin(shared_fb, &shared_fb_info);
sceGxmUnmapMemory(shared_fb_info.fb_base);
sceSharedFbEnd(shared_fb);
sceSharedFbClose(shared_fb);
}
#ifdef HAVE_SHARK
// Shutting down runtime shader compiler
if (is_shark_online) shark_end();
#endif
}
void createDisplayRenderTarget(void) {
// Populating sceGxmRenderTarget parameters
SceGxmRenderTargetParams render_target_params;
memset(&render_target_params, 0, sizeof(SceGxmRenderTargetParams));
render_target_params.flags = 0;
render_target_params.width = DISPLAY_WIDTH;
render_target_params.height = DISPLAY_HEIGHT;
render_target_params.scenesPerFrame = 1;
render_target_params.multisampleMode = msaa_mode;
render_target_params.multisampleLocations = 0;
render_target_params.driverMemBlock = -1;
// Creating render target for the display
sceGxmCreateRenderTarget(&render_target_params, &gxm_render_target);
}
void destroyDisplayRenderTarget(void) {
// Destroying render target for the display
sceGxmDestroyRenderTarget(gxm_render_target);
}
void initDisplayColorSurfaces(void) {
// Getting access to the shared framebuffer on system app mode
while (system_app_mode) {
shared_fb = sceSharedFbOpen(1);
memset(&shared_fb_info, 0, sizeof(SceSharedFbInfo));
sceSharedFbGetInfo(shared_fb, &shared_fb_info);
if (shared_fb_info.index == 1)
sceSharedFbClose(shared_fb);
else {
sceGxmMapMemory(shared_fb_info.fb_base, shared_fb_info.fb_size, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE);
gxm_color_surfaces_addr[0] = shared_fb_info.fb_base;
gxm_color_surfaces_addr[1] = shared_fb_info.fb_base2;
memset(&shared_fb_info, 0, sizeof(SceSharedFbInfo));
break;
}
}
vglMemType type = VGL_MEM_VRAM;
int i;
for (i = 0; i < DISPLAY_BUFFER_COUNT; i++) {
// Allocating color surface memblock
if (!system_app_mode) {
gxm_color_surfaces_addr[i] = gpu_alloc_mapped(
ALIGN(4 * DISPLAY_STRIDE * DISPLAY_HEIGHT, 1 * 1024 * 1024),
&type);
memset(gxm_color_surfaces_addr[i], 0, DISPLAY_STRIDE * DISPLAY_HEIGHT);
}
// Initializing allocated color surface
sceGxmColorSurfaceInit(&gxm_color_surfaces[i],
SCE_GXM_COLOR_FORMAT_A8B8G8R8,
SCE_GXM_COLOR_SURFACE_LINEAR,
msaa_mode == SCE_GXM_MULTISAMPLE_NONE ? SCE_GXM_COLOR_SURFACE_SCALE_NONE : SCE_GXM_COLOR_SURFACE_SCALE_MSAA_DOWNSCALE,
SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT,
DISPLAY_WIDTH,
DISPLAY_HEIGHT,
DISPLAY_STRIDE,
gxm_color_surfaces_addr[i]);
// Creating a display sync object for the allocated color surface
sceGxmSyncObjectCreate(&gxm_sync_objects[i]);
}
}
void termDisplayColorSurfaces(void) {
// Deallocating display's color surfaces and destroying sync objects
int i;
for (i = 0; i < DISPLAY_BUFFER_COUNT; i++) {
if (!system_app_mode)
mempool_free(gxm_color_surfaces_addr[i], VGL_MEM_VRAM);
sceGxmSyncObjectDestroy(gxm_sync_objects[i]);
}
}
void initDepthStencilBuffer(uint32_t w, uint32_t h, SceGxmDepthStencilSurface *surface, void **depth_buffer, void **stencil_buffer, vglMemType *depth_type, vglMemType *stencil_type) {
// Calculating sizes for depth and stencil surfaces
unsigned int depth_stencil_width = ALIGN(w, SCE_GXM_TILE_SIZEX);
unsigned int depth_stencil_height = ALIGN(h, SCE_GXM_TILE_SIZEY);
unsigned int depth_stencil_samples = depth_stencil_width * depth_stencil_height;
if (msaa_mode == SCE_GXM_MULTISAMPLE_2X)
depth_stencil_samples = depth_stencil_samples * 2;
else if (msaa_mode == SCE_GXM_MULTISAMPLE_4X)
depth_stencil_samples = depth_stencil_samples * 4;
// Allocating depth surface
*depth_type = VGL_MEM_VRAM;
*depth_buffer = gpu_alloc_mapped(4 * depth_stencil_samples, depth_type);
// Allocating stencil surface
*stencil_type = VGL_MEM_VRAM;
*stencil_buffer = gpu_alloc_mapped(1 * depth_stencil_samples, stencil_type);
// Initializing depth and stencil surfaces
sceGxmDepthStencilSurfaceInit(surface,
SCE_GXM_DEPTH_STENCIL_FORMAT_DF32M_S8,
SCE_GXM_DEPTH_STENCIL_SURFACE_LINEAR,
msaa_mode == SCE_GXM_MULTISAMPLE_4X ? depth_stencil_width * 2 : depth_stencil_width,
*depth_buffer,
*stencil_buffer);
}
void initDepthStencilSurfaces(void) {
vglMemType t1, t2;
initDepthStencilBuffer(DISPLAY_WIDTH, DISPLAY_HEIGHT, &gxm_depth_stencil_surface, &gxm_depth_surface_addr, &gxm_stencil_surface_addr, &t1, &t2);
}
void termDepthStencilSurfaces(void) {
// Deallocating depth and stencil surfaces memblocks
mempool_free(gxm_depth_surface_addr, VGL_MEM_VRAM);
mempool_free(gxm_stencil_surface_addr, VGL_MEM_VRAM);
}
void startShaderPatcher(void) {
// Constants for shader patcher buffers
static const unsigned int shader_patcher_buffer_size = 1024 * 1024;
static const unsigned int shader_patcher_vertex_usse_size = 1024 * 1024;
static const unsigned int shader_patcher_fragment_usse_size = 1024 * 1024;
vglMemType type = VGL_MEM_VRAM;
// Allocating Shader Patcher buffer
gxm_shader_patcher_buffer_addr = gpu_alloc_mapped(
shader_patcher_buffer_size, &type);
// Allocating Shader Patcher vertex USSE buffer
unsigned int shader_patcher_vertex_usse_offset;
gxm_shader_patcher_vertex_usse_addr = gpu_vertex_usse_alloc_mapped(
shader_patcher_vertex_usse_size, &shader_patcher_vertex_usse_offset);
// Allocating Shader Patcher fragment USSE buffer
unsigned int shader_patcher_fragment_usse_offset;
gxm_shader_patcher_fragment_usse_addr = gpu_fragment_usse_alloc_mapped(
shader_patcher_fragment_usse_size, &shader_patcher_fragment_usse_offset);
// Populating shader patcher parameters
SceGxmShaderPatcherParams shader_patcher_params;
memset(&shader_patcher_params, 0, sizeof(SceGxmShaderPatcherParams));
shader_patcher_params.userData = NULL;
shader_patcher_params.hostAllocCallback = shader_patcher_host_alloc_cb;
shader_patcher_params.hostFreeCallback = shader_patcher_host_free_cb;
shader_patcher_params.bufferAllocCallback = NULL;
shader_patcher_params.bufferFreeCallback = NULL;
shader_patcher_params.bufferMem = gxm_shader_patcher_buffer_addr;
shader_patcher_params.bufferMemSize = shader_patcher_buffer_size;
shader_patcher_params.vertexUsseAllocCallback = NULL;
shader_patcher_params.vertexUsseFreeCallback = NULL;
shader_patcher_params.vertexUsseMem = gxm_shader_patcher_vertex_usse_addr;
shader_patcher_params.vertexUsseMemSize = shader_patcher_vertex_usse_size;
shader_patcher_params.vertexUsseOffset = shader_patcher_vertex_usse_offset;
shader_patcher_params.fragmentUsseAllocCallback = NULL;
shader_patcher_params.fragmentUsseFreeCallback = NULL;
shader_patcher_params.fragmentUsseMem = gxm_shader_patcher_fragment_usse_addr;
shader_patcher_params.fragmentUsseMemSize = shader_patcher_fragment_usse_size;
shader_patcher_params.fragmentUsseOffset = shader_patcher_fragment_usse_offset;
// Creating shader patcher instance
sceGxmShaderPatcherCreate(&shader_patcher_params, &gxm_shader_patcher);
}
void stopShaderPatcher(void) {
// Destroying shader patcher instance
sceGxmShaderPatcherDestroy(gxm_shader_patcher);
// Freeing shader patcher buffers
mempool_free(gxm_shader_patcher_buffer_addr, VGL_MEM_VRAM);
gpu_vertex_usse_free_mapped(gxm_shader_patcher_vertex_usse_addr);
gpu_fragment_usse_free_mapped(gxm_shader_patcher_fragment_usse_addr);
}
void waitRenderingDone(void) {
// Wait for rendering to be finished
sceGxmDisplayQueueFinish();
sceGxmFinish(gxm_context);
}
/*
* ------------------------------
* - IMPLEMENTATION STARTS HERE -
* ------------------------------
*/
void vglSetParamBufferSize(uint32_t size) {
gxm_param_buf_size = size;
}
void vglStartRendering(void) {
// Starting drawing scene
if (active_write_fb == NULL) { // Default framebuffer is used
if (system_app_mode) {
sceSharedFbBegin(shared_fb, &shared_fb_info);
shared_fb_info.vsync = vblank;
gxm_back_buffer_index = (shared_fb_info.index + 1) % 2;
}
sceGxmBeginScene(gxm_context, gxm_scene_flags, gxm_render_target,
NULL, NULL,
gxm_sync_objects[gxm_back_buffer_index],
&gxm_color_surfaces[gxm_back_buffer_index],
&gxm_depth_stencil_surface);
gxm_scene_flags &= ~SCE_GXM_SCENE_VERTEX_WAIT_FOR_DEPENDENCY;
} else {
gxm_scene_flags |= SCE_GXM_SCENE_FRAGMENT_SET_DEPENDENCY;
sceGxmBeginScene(gxm_context, gxm_scene_flags, active_write_fb->target,
NULL, NULL, NULL,
&active_write_fb->colorbuffer,
&active_write_fb->depthbuffer);
gxm_scene_flags |= SCE_GXM_SCENE_VERTEX_WAIT_FOR_DEPENDENCY;
gxm_scene_flags &= ~SCE_GXM_SCENE_FRAGMENT_SET_DEPENDENCY;
}
// Setting back current viewport if enabled cause sceGxm will reset it at sceGxmEndScene call
sceGxmSetViewport(gxm_context, x_port, x_scale, y_port, y_scale, z_port, z_scale);
if (scissor_test_state)
sceGxmSetRegionClip(gxm_context, SCE_GXM_REGION_CLIP_OUTSIDE, region.x, region.y, region.x + region.w - 1, region.y + region.h - 1);
else
sceGxmSetRegionClip(gxm_context, SCE_GXM_REGION_CLIP_OUTSIDE, 0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
}
void vglStopRenderingInit(void) {
// Ending drawing scene
sceGxmEndScene(gxm_context, NULL, NULL);
if (system_app_mode && vblank)
sceDisplayWaitVblankStart();
}
void vglStopRenderingTerm(void) {
if (active_write_fb == NULL) { // Default framebuffer is used
// Properly requesting a display update
if (system_app_mode)
sceSharedFbEnd(shared_fb);
else {
struct display_queue_callback_data queue_cb_data;
queue_cb_data.addr = gxm_color_surfaces_addr[gxm_back_buffer_index];
sceGxmDisplayQueueAddEntry(gxm_sync_objects[gxm_front_buffer_index],
gxm_sync_objects[gxm_back_buffer_index], &queue_cb_data);
gxm_front_buffer_index = gxm_back_buffer_index;
gxm_back_buffer_index = (gxm_back_buffer_index + 1) % DISPLAY_BUFFER_COUNT;
}
}
// Resetting vitaGL mempool
gpu_pool_reset();
}
void vglStopRendering() {
// Ending drawing scene
vglStopRenderingInit();
// Updating display and resetting vitaGL mempool
vglStopRenderingTerm();
}
void vglUpdateCommonDialog() {
// Populating SceCommonDialog parameters
SceCommonDialogUpdateParam updateParam;
memset(&updateParam, 0, sizeof(updateParam));
updateParam.renderTarget.colorFormat = SCE_GXM_COLOR_FORMAT_A8B8G8R8;
updateParam.renderTarget.surfaceType = SCE_GXM_COLOR_SURFACE_LINEAR;
updateParam.renderTarget.width = DISPLAY_WIDTH;
updateParam.renderTarget.height = DISPLAY_HEIGHT;
updateParam.renderTarget.strideInPixels = DISPLAY_STRIDE;
updateParam.renderTarget.colorSurfaceData = gxm_color_surfaces_addr[gxm_back_buffer_index];
updateParam.renderTarget.depthSurfaceData = gxm_depth_surface_addr;
updateParam.displaySyncObject = gxm_sync_objects[gxm_back_buffer_index];
// Updating sceCommonDialog
sceCommonDialogUpdate(&updateParam);
}
void glFinish(void) {
// Waiting for GPU to finish drawing jobs
sceGxmFinish(gxm_context);
}