2017-01-17 20:58:51 +01:00

821 lines
28 KiB
C

#include <psp2/display.h>
#include <psp2/gxm.h>
#include <psp2/types.h>
#include <psp2/kernel/sysmem.h>
#include <psp2/message_dialog.h>
#include <psp2/sysmodule.h>
#include <string.h>
#include <stdlib.h>
#include "vita2d.h"
#include "utils.h"
#ifdef DEBUG_BUILD
# include <stdio.h>
# define VITA2D_DEBUG(...) printf(__VA_ARGS__)
#else
# define VITA2D_DEBUG(...)
#endif
/* Defines */
#define DISPLAY_WIDTH 960
#define DISPLAY_HEIGHT 544
#define DISPLAY_STRIDE_IN_PIXELS 1024
#define DISPLAY_COLOR_FORMAT SCE_GXM_COLOR_FORMAT_A8B8G8R8
#define DISPLAY_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8
#define DISPLAY_BUFFER_COUNT 3
#define DISPLAY_MAX_PENDING_SWAPS 2
#define MSAA_MODE SCE_GXM_MULTISAMPLE_NONE
#define DEFAULT_TEMP_POOL_SIZE (1 * 1024 * 1024)
typedef struct vita2d_display_data {
void *address;
} vita2d_display_data;
/* Extern */
extern const SceGxmProgram clear_v_gxp;
extern const SceGxmProgram clear_f_gxp;
extern const SceGxmProgram color_v_gxp;
extern const SceGxmProgram color_f_gxp;
extern const SceGxmProgram texture_v_gxp;
extern const SceGxmProgram texture_f_gxp;
extern const SceGxmProgram texture_tint_f_gxp;
/* Static variables */
static int pgf_module_was_loaded = 0;
static const SceGxmProgram *const clearVertexProgramGxp = &clear_v_gxp;
static const SceGxmProgram *const clearFragmentProgramGxp = &clear_f_gxp;
static const SceGxmProgram *const colorVertexProgramGxp = &color_v_gxp;
static const SceGxmProgram *const colorFragmentProgramGxp = &color_f_gxp;
static const SceGxmProgram *const textureVertexProgramGxp = &texture_v_gxp;
static const SceGxmProgram *const textureFragmentProgramGxp = &texture_f_gxp;
static const SceGxmProgram *const textureTintFragmentProgramGxp = &texture_tint_f_gxp;
static int vita2d_initialized = 0;
static float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
static unsigned int clear_color_u = 0xff000000;
static int vblank_wait = 1;
static SceUID vdmRingBufferUid;
static SceUID vertexRingBufferUid;
static SceUID fragmentRingBufferUid;
static SceUID fragmentUsseRingBufferUid;
static SceGxmContextParams contextParams;
static SceGxmRenderTarget *renderTarget = NULL;
static SceUID displayBufferUid[DISPLAY_BUFFER_COUNT];
static void *displayBufferData[DISPLAY_BUFFER_COUNT];
static SceUID displayBufferUid[DISPLAY_BUFFER_COUNT];
static SceGxmColorSurface displaySurface[DISPLAY_BUFFER_COUNT];
static SceGxmSyncObject *displayBufferSync[DISPLAY_BUFFER_COUNT];
static SceUID depthBufferUid;
static SceGxmDepthStencilSurface depthSurface;
static void *depthBufferData = NULL;
static unsigned int backBufferIndex = 0;
static unsigned int frontBufferIndex = 0;
static SceGxmShaderPatcher *shaderPatcher = NULL;
static SceGxmVertexProgram *clearVertexProgram = NULL;
static SceGxmFragmentProgram *clearFragmentProgram = NULL;
static SceGxmShaderPatcherId clearVertexProgramId;
static SceGxmShaderPatcherId clearFragmentProgramId;
static SceGxmShaderPatcherId colorVertexProgramId;
static SceGxmShaderPatcherId colorFragmentProgramId;
static SceGxmShaderPatcherId textureVertexProgramId;
static SceGxmShaderPatcherId textureFragmentProgramId;
static SceGxmShaderPatcherId textureTintFragmentProgramId;
static SceUID patcherBufferUid;
static SceUID patcherVertexUsseUid;
static SceUID patcherFragmentUsseUid;
static SceUID clearVerticesUid;
static SceUID clearIndicesUid;
static vita2d_clear_vertex *clearVertices = NULL;
static uint16_t *clearIndices = NULL;
/* Shared with other .c */
float _vita2d_ortho_matrix[4*4];
SceGxmContext *_vita2d_context = NULL;
SceGxmVertexProgram *_vita2d_colorVertexProgram = NULL;
SceGxmFragmentProgram *_vita2d_colorFragmentProgram = NULL;
SceGxmVertexProgram *_vita2d_textureVertexProgram = NULL;
SceGxmFragmentProgram *_vita2d_textureFragmentProgram = NULL;
SceGxmFragmentProgram *_vita2d_textureTintFragmentProgram = NULL;
const SceGxmProgramParameter *_vita2d_clearClearColorParam = NULL;
const SceGxmProgramParameter *_vita2d_colorWvpParam = NULL;
const SceGxmProgramParameter *_vita2d_textureWvpParam = NULL;
const SceGxmProgramParameter *_vita2d_textureTintColorParam = NULL;
// Temporary memory pool
static void *pool_addr = NULL;
static SceUID poolUid;
static unsigned int pool_index = 0;
static unsigned int pool_size = 0;
/* Static functions */
static void *patcher_host_alloc(void *user_data, unsigned int size)
{
return malloc(size);
}
static void patcher_host_free(void *user_data, void *mem)
{
free(mem);
}
static void display_callback(const void *callback_data)
{
SceDisplayFrameBuf framebuf;
const vita2d_display_data *display_data = (const vita2d_display_data *)callback_data;
memset(&framebuf, 0x00, sizeof(SceDisplayFrameBuf));
framebuf.size = sizeof(SceDisplayFrameBuf);
framebuf.base = display_data->address;
framebuf.pitch = DISPLAY_STRIDE_IN_PIXELS;
framebuf.pixelformat = DISPLAY_PIXEL_FORMAT;
framebuf.width = DISPLAY_WIDTH;
framebuf.height = DISPLAY_HEIGHT;
sceDisplaySetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_NEXTFRAME);
if (vblank_wait) {
sceDisplayWaitVblankStart();
}
}
int vita2d_init()
{
return vita2d_init_advanced(DEFAULT_TEMP_POOL_SIZE);
}
int vita2d_init_advanced(unsigned int temp_pool_size)
{
int err;
unsigned int i, x, y;
UNUSED(err);
if (vita2d_initialized) {
VITA2D_DEBUG("libvita2d is already initialized!\n");
return 1;
}
SceGxmInitializeParams initializeParams;
memset(&initializeParams, 0, sizeof(SceGxmInitializeParams));
initializeParams.flags = 0;
initializeParams.displayQueueMaxPendingCount = DISPLAY_MAX_PENDING_SWAPS;
initializeParams.displayQueueCallback = display_callback;
initializeParams.displayQueueCallbackDataSize = sizeof(vita2d_display_data);
initializeParams.parameterBufferSize = SCE_GXM_DEFAULT_PARAMETER_BUFFER_SIZE;
err = sceGxmInitialize(&initializeParams);
VITA2D_DEBUG("sceGxmInitialize(): 0x%08X\n", err);
// allocate ring buffer memory using default sizes
void *vdmRingBuffer = gpu_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE,
4,
SCE_GXM_MEMORY_ATTRIB_READ,
&vdmRingBufferUid);
void *vertexRingBuffer = gpu_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE,
4,
SCE_GXM_MEMORY_ATTRIB_READ,
&vertexRingBufferUid);
void *fragmentRingBuffer = gpu_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE,
4,
SCE_GXM_MEMORY_ATTRIB_READ,
&fragmentRingBufferUid);
unsigned int fragmentUsseRingBufferOffset;
void *fragmentUsseRingBuffer = fragment_usse_alloc(
SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE,
&fragmentUsseRingBufferUid,
&fragmentUsseRingBufferOffset);
memset(&contextParams, 0, sizeof(SceGxmContextParams));
contextParams.hostMem = malloc(SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE);
contextParams.hostMemSize = SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE;
contextParams.vdmRingBufferMem = vdmRingBuffer;
contextParams.vdmRingBufferMemSize = SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE;
contextParams.vertexRingBufferMem = vertexRingBuffer;
contextParams.vertexRingBufferMemSize = SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE;
contextParams.fragmentRingBufferMem = fragmentRingBuffer;
contextParams.fragmentRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE;
contextParams.fragmentUsseRingBufferMem = fragmentUsseRingBuffer;
contextParams.fragmentUsseRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE;
contextParams.fragmentUsseRingBufferOffset = fragmentUsseRingBufferOffset;
err = sceGxmCreateContext(&contextParams, &_vita2d_context);
VITA2D_DEBUG("sceGxmCreateContext(): 0x%08X\n", err);
// set up parameters
SceGxmRenderTargetParams renderTargetParams;
memset(&renderTargetParams, 0, sizeof(SceGxmRenderTargetParams));
renderTargetParams.flags = 0;
renderTargetParams.width = DISPLAY_WIDTH;
renderTargetParams.height = DISPLAY_HEIGHT;
renderTargetParams.scenesPerFrame = 1;
renderTargetParams.multisampleMode = MSAA_MODE;
renderTargetParams.multisampleLocations = 0;
renderTargetParams.driverMemBlock = -1; // Invalid UID
// create the render target
err = sceGxmCreateRenderTarget(&renderTargetParams, &renderTarget);
VITA2D_DEBUG("sceGxmCreateRenderTarget(): 0x%08X\n", err);
// allocate memory and sync objects for display buffers
for (i = 0; i < DISPLAY_BUFFER_COUNT; i++) {
// allocate memory for display
displayBufferData[i] = gpu_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
4*DISPLAY_STRIDE_IN_PIXELS*DISPLAY_HEIGHT,
SCE_GXM_COLOR_SURFACE_ALIGNMENT,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&displayBufferUid[i]);
// memset the buffer to black
for (y = 0; y < DISPLAY_HEIGHT; y++) {
unsigned int *row = (unsigned int *)displayBufferData[i] + y*DISPLAY_STRIDE_IN_PIXELS;
for (x = 0; x < DISPLAY_WIDTH; x++) {
row[x] = 0xff000000;
}
}
// initialize a color surface for this display buffer
err = sceGxmColorSurfaceInit(
&displaySurface[i],
DISPLAY_COLOR_FORMAT,
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_IN_PIXELS,
displayBufferData[i]);
// create a sync object that we will associate with this buffer
err = sceGxmSyncObjectCreate(&displayBufferSync[i]);
}
// compute the memory footprint of the depth buffer
const unsigned int alignedWidth = ALIGN(DISPLAY_WIDTH, SCE_GXM_TILE_SIZEX);
const unsigned int alignedHeight = ALIGN(DISPLAY_HEIGHT, SCE_GXM_TILE_SIZEY);
unsigned int sampleCount = alignedWidth*alignedHeight;
unsigned int depthStrideInSamples = alignedWidth;
if (MSAA_MODE == SCE_GXM_MULTISAMPLE_4X) {
// samples increase in X and Y
sampleCount *= 4;
depthStrideInSamples *= 2;
} else if (MSAA_MODE == SCE_GXM_MULTISAMPLE_2X) {
// samples increase in Y only
sampleCount *= 2;
}
// allocate the depth buffer
depthBufferData = gpu_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,
&depthBufferUid);
// create the SceGxmDepthStencilSurface structure
err = sceGxmDepthStencilSurfaceInit(
&depthSurface,
SCE_GXM_DEPTH_STENCIL_FORMAT_S8D24,
SCE_GXM_DEPTH_STENCIL_SURFACE_TILED,
depthStrideInSamples,
depthBufferData,
NULL);
// set buffer sizes for this sample
const unsigned int patcherBufferSize = 64*1024;
const unsigned int patcherVertexUsseSize = 64*1024;
const unsigned int patcherFragmentUsseSize = 64*1024;
// allocate memory for buffers and USSE code
void *patcherBuffer = gpu_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
patcherBufferSize,
4,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&patcherBufferUid);
unsigned int patcherVertexUsseOffset;
void *patcherVertexUsse = vertex_usse_alloc(
patcherVertexUsseSize,
&patcherVertexUsseUid,
&patcherVertexUsseOffset);
unsigned int patcherFragmentUsseOffset;
void *patcherFragmentUsse = fragment_usse_alloc(
patcherFragmentUsseSize,
&patcherFragmentUsseUid,
&patcherFragmentUsseOffset);
// create a shader patcher
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 = patcherBuffer;
patcherParams.bufferMemSize = patcherBufferSize;
patcherParams.vertexUsseAllocCallback = NULL;
patcherParams.vertexUsseFreeCallback = NULL;
patcherParams.vertexUsseMem = patcherVertexUsse;
patcherParams.vertexUsseMemSize = patcherVertexUsseSize;
patcherParams.vertexUsseOffset = patcherVertexUsseOffset;
patcherParams.fragmentUsseAllocCallback = NULL;
patcherParams.fragmentUsseFreeCallback = NULL;
patcherParams.fragmentUsseMem = patcherFragmentUsse;
patcherParams.fragmentUsseMemSize = patcherFragmentUsseSize;
patcherParams.fragmentUsseOffset = patcherFragmentUsseOffset;
err = sceGxmShaderPatcherCreate(&patcherParams, &shaderPatcher);
VITA2D_DEBUG("sceGxmShaderPatcherCreate(): 0x%08X\n", err);
// check the shaders
err = sceGxmProgramCheck(clearVertexProgramGxp);
VITA2D_DEBUG("clear_v sceGxmProgramCheck(): 0x%08X\n", err);
err = sceGxmProgramCheck(clearFragmentProgramGxp);
VITA2D_DEBUG("clear_f sceGxmProgramCheck(): 0x%08X\n", err);
err = sceGxmProgramCheck(colorVertexProgramGxp);
VITA2D_DEBUG("color_v sceGxmProgramCheck(): 0x%08X\n", err);
err = sceGxmProgramCheck(colorFragmentProgramGxp);
VITA2D_DEBUG("color_f sceGxmProgramCheck(): 0x%08X\n", err);
err = sceGxmProgramCheck(textureVertexProgramGxp);
VITA2D_DEBUG("texture_v sceGxmProgramCheck(): 0x%08X\n", err);
err = sceGxmProgramCheck(textureFragmentProgramGxp);
VITA2D_DEBUG("texture_f sceGxmProgramCheck(): 0x%08X\n", err);
err = sceGxmProgramCheck(textureTintFragmentProgramGxp);
VITA2D_DEBUG("texture_tint_f sceGxmProgramCheck(): 0x%08X\n", err);
// register programs with the patcher
err = sceGxmShaderPatcherRegisterProgram(shaderPatcher, clearVertexProgramGxp, &clearVertexProgramId);
VITA2D_DEBUG("clear_v sceGxmShaderPatcherRegisterProgram(): 0x%08X\n", err);
err = sceGxmShaderPatcherRegisterProgram(shaderPatcher, clearFragmentProgramGxp, &clearFragmentProgramId);
VITA2D_DEBUG("clear_f sceGxmShaderPatcherRegisterProgram(): 0x%08X\n", err);
err = sceGxmShaderPatcherRegisterProgram(shaderPatcher, colorVertexProgramGxp, &colorVertexProgramId);
VITA2D_DEBUG("color_v sceGxmShaderPatcherRegisterProgram(): 0x%08X\n", err);
err = sceGxmShaderPatcherRegisterProgram(shaderPatcher, colorFragmentProgramGxp, &colorFragmentProgramId);
VITA2D_DEBUG("color_f sceGxmShaderPatcherRegisterProgram(): 0x%08X\n", err);
err = sceGxmShaderPatcherRegisterProgram(shaderPatcher, textureVertexProgramGxp, &textureVertexProgramId);
VITA2D_DEBUG("texture_v sceGxmShaderPatcherRegisterProgram(): 0x%08X\n", err);
err = sceGxmShaderPatcherRegisterProgram(shaderPatcher, textureFragmentProgramGxp, &textureFragmentProgramId);
VITA2D_DEBUG("texture_f sceGxmShaderPatcherRegisterProgram(): 0x%08X\n", err);
err = sceGxmShaderPatcherRegisterProgram(shaderPatcher, textureTintFragmentProgramGxp, &textureTintFragmentProgramId);
VITA2D_DEBUG("texture_tint_f sceGxmShaderPatcherRegisterProgram(): 0x%08X\n", err);
// Fill SceGxmBlendInfo
static const SceGxmBlendInfo blend_info = {
.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_ZERO,
.colorMask = SCE_GXM_COLOR_MASK_ALL
};
// get attributes by name to create vertex format bindings
const SceGxmProgramParameter *paramClearPositionAttribute = sceGxmProgramFindParameterByName(clearVertexProgramGxp, "aPosition");
// create clear vertex format
SceGxmVertexAttribute clearVertexAttributes[1];
SceGxmVertexStream clearVertexStreams[1];
clearVertexAttributes[0].streamIndex = 0;
clearVertexAttributes[0].offset = 0;
clearVertexAttributes[0].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
clearVertexAttributes[0].componentCount = 2;
clearVertexAttributes[0].regIndex = sceGxmProgramParameterGetResourceIndex(paramClearPositionAttribute);
clearVertexStreams[0].stride = sizeof(vita2d_clear_vertex);
clearVertexStreams[0].indexSource = SCE_GXM_INDEX_SOURCE_INDEX_16BIT;
// create clear programs
err = sceGxmShaderPatcherCreateVertexProgram(
shaderPatcher,
clearVertexProgramId,
clearVertexAttributes,
1,
clearVertexStreams,
1,
&clearVertexProgram);
VITA2D_DEBUG("clear sceGxmShaderPatcherCreateVertexProgram(): 0x%08X\n", err);
err = sceGxmShaderPatcherCreateFragmentProgram(
shaderPatcher,
clearFragmentProgramId,
SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
MSAA_MODE,
NULL,
clearVertexProgramGxp,
&clearFragmentProgram);
VITA2D_DEBUG("clear sceGxmShaderPatcherCreateFragmentProgram(): 0x%08X\n", err);
// create the clear triangle vertex/index data
clearVertices = (vita2d_clear_vertex *)gpu_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
3*sizeof(vita2d_clear_vertex),
4,
SCE_GXM_MEMORY_ATTRIB_READ,
&clearVerticesUid);
clearIndices = (uint16_t *)gpu_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
3*sizeof(uint16_t),
2,
SCE_GXM_MEMORY_ATTRIB_READ,
&clearIndicesUid);
clearVertices[0].x = -1.0f;
clearVertices[0].y = -1.0f;
clearVertices[1].x = 3.0f;
clearVertices[1].y = -1.0f;
clearVertices[2].x = -1.0f;
clearVertices[2].y = 3.0f;
clearIndices[0] = 0;
clearIndices[1] = 1;
clearIndices[2] = 2;
const SceGxmProgramParameter *paramColorPositionAttribute = sceGxmProgramFindParameterByName(colorVertexProgramGxp, "aPosition");
VITA2D_DEBUG("aPosition sceGxmProgramFindParameterByName(): %p\n", paramColorPositionAttribute);
const SceGxmProgramParameter *paramColorColorAttribute = sceGxmProgramFindParameterByName(colorVertexProgramGxp, "aColor");
VITA2D_DEBUG("aColor sceGxmProgramFindParameterByName(): %p\n", paramColorColorAttribute);
// create color vertex format
SceGxmVertexAttribute colorVertexAttributes[2];
SceGxmVertexStream colorVertexStreams[1];
/* x,y,z: 3 float 32 bits */
colorVertexAttributes[0].streamIndex = 0;
colorVertexAttributes[0].offset = 0;
colorVertexAttributes[0].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
colorVertexAttributes[0].componentCount = 3; // (x, y, z)
colorVertexAttributes[0].regIndex = sceGxmProgramParameterGetResourceIndex(paramColorPositionAttribute);
/* color: 4 unsigned char = 32 bits */
colorVertexAttributes[1].streamIndex = 0;
colorVertexAttributes[1].offset = 12; // (x, y, z) * 4 = 12 bytes
colorVertexAttributes[1].format = SCE_GXM_ATTRIBUTE_FORMAT_U8N;
colorVertexAttributes[1].componentCount = 4; // (color)
colorVertexAttributes[1].regIndex = sceGxmProgramParameterGetResourceIndex(paramColorColorAttribute);
// 16 bit (short) indices
colorVertexStreams[0].stride = sizeof(vita2d_color_vertex);
colorVertexStreams[0].indexSource = SCE_GXM_INDEX_SOURCE_INDEX_16BIT;
// create color shaders
err = sceGxmShaderPatcherCreateVertexProgram(
shaderPatcher,
colorVertexProgramId,
colorVertexAttributes,
2,
colorVertexStreams,
1,
&_vita2d_colorVertexProgram);
VITA2D_DEBUG("color sceGxmShaderPatcherCreateVertexProgram(): 0x%08X\n", err);
err = sceGxmShaderPatcherCreateFragmentProgram(
shaderPatcher,
colorFragmentProgramId,
SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
MSAA_MODE,
&blend_info,
colorVertexProgramGxp,
&_vita2d_colorFragmentProgram);
VITA2D_DEBUG("color sceGxmShaderPatcherCreateFragmentProgram(): 0x%08X\n", err);
const SceGxmProgramParameter *paramTexturePositionAttribute = sceGxmProgramFindParameterByName(textureVertexProgramGxp, "aPosition");
VITA2D_DEBUG("aPosition sceGxmProgramFindParameterByName(): %p\n", paramTexturePositionAttribute);
const SceGxmProgramParameter *paramTextureTexcoordAttribute = sceGxmProgramFindParameterByName(textureVertexProgramGxp, "aTexcoord");
VITA2D_DEBUG("aTexcoord sceGxmProgramFindParameterByName(): %p\n", paramTextureTexcoordAttribute);
// create texture vertex format
SceGxmVertexAttribute textureVertexAttributes[2];
SceGxmVertexStream textureVertexStreams[1];
/* x,y,z: 3 float 32 bits */
textureVertexAttributes[0].streamIndex = 0;
textureVertexAttributes[0].offset = 0;
textureVertexAttributes[0].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
textureVertexAttributes[0].componentCount = 3; // (x, y, z)
textureVertexAttributes[0].regIndex = sceGxmProgramParameterGetResourceIndex(paramTexturePositionAttribute);
/* u,v: 2 floats 32 bits */
textureVertexAttributes[1].streamIndex = 0;
textureVertexAttributes[1].offset = 12; // (x, y, z) * 4 = 12 bytes
textureVertexAttributes[1].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
textureVertexAttributes[1].componentCount = 2; // (u, v)
textureVertexAttributes[1].regIndex = sceGxmProgramParameterGetResourceIndex(paramTextureTexcoordAttribute);
// 16 bit (short) indices
textureVertexStreams[0].stride = sizeof(vita2d_texture_vertex);
textureVertexStreams[0].indexSource = SCE_GXM_INDEX_SOURCE_INDEX_16BIT;
// create texture shaders
err = sceGxmShaderPatcherCreateVertexProgram(
shaderPatcher,
textureVertexProgramId,
textureVertexAttributes,
2,
textureVertexStreams,
1,
&_vita2d_textureVertexProgram);
VITA2D_DEBUG("texture sceGxmShaderPatcherCreateVertexProgram(): 0x%08X\n", err);
err = sceGxmShaderPatcherCreateFragmentProgram(
shaderPatcher,
textureFragmentProgramId,
SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
MSAA_MODE,
&blend_info,
textureVertexProgramGxp,
&_vita2d_textureFragmentProgram);
VITA2D_DEBUG("texture sceGxmShaderPatcherCreateFragmentProgram(): 0x%08X\n", err);
err = sceGxmShaderPatcherCreateFragmentProgram(
shaderPatcher,
textureTintFragmentProgramId,
SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
MSAA_MODE,
&blend_info,
textureVertexProgramGxp,
&_vita2d_textureTintFragmentProgram);
VITA2D_DEBUG("texture_tint sceGxmShaderPatcherCreateFragmentProgram(): 0x%08X\n", err);
// find vertex uniforms by name and cache parameter information
_vita2d_clearClearColorParam = sceGxmProgramFindParameterByName(clearFragmentProgramGxp, "uClearColor");
VITA2D_DEBUG("_vita2d_clearClearColorParam sceGxmProgramFindParameterByName(): %p\n", _vita2d_clearClearColorParam);
_vita2d_colorWvpParam = sceGxmProgramFindParameterByName(colorVertexProgramGxp, "wvp");
VITA2D_DEBUG("color wvp sceGxmProgramFindParameterByName(): %p\n", _vita2d_colorWvpParam);
_vita2d_textureWvpParam = sceGxmProgramFindParameterByName(textureVertexProgramGxp, "wvp");
VITA2D_DEBUG("texture wvp sceGxmProgramFindParameterByName(): %p\n", _vita2d_textureWvpParam);
_vita2d_textureTintColorParam = sceGxmProgramFindParameterByName(textureTintFragmentProgramGxp, "uTintColor");
VITA2D_DEBUG("texture wvp sceGxmProgramFindParameterByName(): %p\n", _vita2d_textureWvpParam);
// Allocate memory for the memory pool
pool_size = temp_pool_size;
pool_addr = gpu_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW,
pool_size,
sizeof(void *),
SCE_GXM_MEMORY_ATTRIB_READ,
&poolUid);
matrix_init_orthographic(_vita2d_ortho_matrix, 0.0f, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0.0f, 0.0f, 1.0f);
backBufferIndex = 0;
frontBufferIndex = 0;
pgf_module_was_loaded = sceSysmoduleIsLoaded(SCE_SYSMODULE_PGF);
if (pgf_module_was_loaded != SCE_SYSMODULE_LOADED)
sceSysmoduleLoadModule(SCE_SYSMODULE_PGF);
vita2d_initialized = 1;
return 1;
}
void vita2d_wait_rendering_done()
{
sceGxmFinish(_vita2d_context);
}
int vita2d_fini()
{
unsigned int i;
if (!vita2d_initialized) {
VITA2D_DEBUG("libvita2d is not initialized!\n");
return 1;
}
// wait until rendering is done
sceGxmFinish(_vita2d_context);
// clean up allocations
sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, clearFragmentProgram);
sceGxmShaderPatcherReleaseVertexProgram(shaderPatcher, clearVertexProgram);
sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, _vita2d_colorFragmentProgram);
sceGxmShaderPatcherReleaseVertexProgram(shaderPatcher, _vita2d_colorVertexProgram);
sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, _vita2d_textureFragmentProgram);
sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, _vita2d_textureTintFragmentProgram);
sceGxmShaderPatcherReleaseVertexProgram(shaderPatcher, _vita2d_textureVertexProgram);
gpu_free(clearIndicesUid);
gpu_free(clearVerticesUid);
// wait until display queue is finished before deallocating display buffers
sceGxmDisplayQueueFinish();
// clean up display queue
gpu_free(depthBufferUid);
for (i = 0; i < DISPLAY_BUFFER_COUNT; i++) {
// clear the buffer then deallocate
memset(displayBufferData[i], 0, DISPLAY_HEIGHT*DISPLAY_STRIDE_IN_PIXELS*4);
gpu_free(displayBufferUid[i]);
// destroy the sync object
sceGxmSyncObjectDestroy(displayBufferSync[i]);
}
// free the depth buffer
gpu_free(depthBufferUid);
// unregister programs and destroy shader patcher
sceGxmShaderPatcherUnregisterProgram(shaderPatcher, clearFragmentProgramId);
sceGxmShaderPatcherUnregisterProgram(shaderPatcher, clearVertexProgramId);
sceGxmShaderPatcherUnregisterProgram(shaderPatcher, colorFragmentProgramId);
sceGxmShaderPatcherUnregisterProgram(shaderPatcher, colorVertexProgramId);
sceGxmShaderPatcherUnregisterProgram(shaderPatcher, textureFragmentProgramId);
sceGxmShaderPatcherUnregisterProgram(shaderPatcher, textureTintFragmentProgramId);
sceGxmShaderPatcherUnregisterProgram(shaderPatcher, textureVertexProgramId);
sceGxmShaderPatcherDestroy(shaderPatcher);
fragment_usse_free(patcherFragmentUsseUid);
vertex_usse_free(patcherVertexUsseUid);
gpu_free(patcherBufferUid);
// destroy the render target
sceGxmDestroyRenderTarget(renderTarget);
// destroy the _vita2d_context
sceGxmDestroyContext(_vita2d_context);
fragment_usse_free(fragmentUsseRingBufferUid);
gpu_free(fragmentRingBufferUid);
gpu_free(vertexRingBufferUid);
gpu_free(vdmRingBufferUid);
free(contextParams.hostMem);
gpu_free(poolUid);
// terminate libgxm
sceGxmTerminate();
/* if (pgf_module_was_loaded != SCE_SYSMODULE_LOADED)
sceSysmoduleUnloadModule(SCE_SYSMODULE_PGF); */
vita2d_initialized = 0;
return 1;
}
void vita2d_clear_screen()
{
// set clear shaders
sceGxmSetVertexProgram(_vita2d_context, clearVertexProgram);
sceGxmSetFragmentProgram(_vita2d_context, clearFragmentProgram);
// set the clear color
void *color_buffer;
sceGxmReserveFragmentDefaultUniformBuffer(_vita2d_context, &color_buffer);
sceGxmSetUniformDataF(color_buffer, _vita2d_clearClearColorParam, 0, 4, clear_color);
// draw the clear triangle
sceGxmSetVertexStream(_vita2d_context, 0, clearVertices);
sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLES, SCE_GXM_INDEX_FORMAT_U16, clearIndices, 3);
}
void vita2d_swap_buffers()
{
sceGxmPadHeartbeat(&displaySurface[backBufferIndex], displayBufferSync[backBufferIndex]);
// queue the display swap for this frame
vita2d_display_data displayData;
displayData.address = displayBufferData[backBufferIndex];
sceGxmDisplayQueueAddEntry(
displayBufferSync[frontBufferIndex], // OLD fb
displayBufferSync[backBufferIndex], // NEW fb
&displayData);
// update buffer indices
frontBufferIndex = backBufferIndex;
backBufferIndex = (backBufferIndex + 1) % DISPLAY_BUFFER_COUNT;
}
void vita2d_start_drawing()
{
/* Reset the temporary memory pool */
vita2d_pool_reset();
sceGxmBeginScene(
_vita2d_context,
0,
renderTarget,
NULL,
NULL,
displayBufferSync[backBufferIndex],
&displaySurface[backBufferIndex],
&depthSurface);
}
void vita2d_end_drawing()
{
sceGxmEndScene(_vita2d_context, NULL, NULL);
}
int vita2d_common_dialog_update()
{
SceCommonDialogUpdateParam updateParam;
memset(&updateParam, 0, sizeof(updateParam));
updateParam.renderTarget.colorFormat = DISPLAY_COLOR_FORMAT;
updateParam.renderTarget.surfaceType = SCE_GXM_COLOR_SURFACE_LINEAR;
updateParam.renderTarget.width = DISPLAY_WIDTH;
updateParam.renderTarget.height = DISPLAY_HEIGHT;
updateParam.renderTarget.strideInPixels = DISPLAY_STRIDE_IN_PIXELS;
updateParam.renderTarget.colorSurfaceData = displayBufferData[backBufferIndex];
updateParam.renderTarget.depthSurfaceData = depthBufferData;
updateParam.displaySyncObject = displayBufferSync[backBufferIndex];
return sceCommonDialogUpdate(&updateParam);
}
void vita2d_set_clear_color(unsigned int color)
{
clear_color[0] = ((color >> 8*0) & 0xFF)/255.0f;
clear_color[1] = ((color >> 8*1) & 0xFF)/255.0f;
clear_color[2] = ((color >> 8*2) & 0xFF)/255.0f;
clear_color[3] = ((color >> 8*3) & 0xFF)/255.0f;
clear_color_u = color;
}
unsigned int vita2d_get_clear_color(){
return clear_color_u;
}
void vita2d_set_vblank_wait(int enable)
{
vblank_wait = enable;
}
void *vita2d_get_current_fb()
{
return displayBufferData[frontBufferIndex];
}
void vita2d_set_region_clip(SceGxmRegionClipMode mode, unsigned int x_min, unsigned int y_min, unsigned int x_max, unsigned int y_max)
{
sceGxmSetRegionClip(_vita2d_context, mode, x_min, y_min, x_max, y_max);
}
void *vita2d_pool_malloc(unsigned int size)
{
if ((pool_index + size) < pool_size) {
void *addr = (void *)((unsigned int)pool_addr + pool_index);
pool_index += size;
return addr;
}
return NULL;
}
void *vita2d_pool_memalign(unsigned int size, unsigned int alignment)
{
unsigned int new_index = (pool_index + alignment - 1) & ~(alignment - 1);
if ((new_index + size) < pool_size) {
void *addr = (void *)((unsigned int)pool_addr + new_index);
pool_index = new_index + size;
return addr;
}
return NULL;
}
unsigned int vita2d_pool_free_space()
{
return pool_size - pool_index;
}
void vita2d_pool_reset()
{
pool_index = 0;
}