blob: 035e8a63c4ef562d524d903b0f50d13a7127dbfc [file] [log] [blame]
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_RENDER_VITA_GXM
#include "SDL_hints.h"
#include "../SDL_sysrender.h"
#include "SDL_log.h"
#include <psp2/kernel/processmgr.h>
#include <psp2/appmgr.h>
#include <psp2/display.h>
#include <psp2/gxm.h>
#include <psp2/types.h>
#include <psp2/kernel/sysmem.h>
#include <psp2/message_dialog.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdarg.h>
#include <stdlib.h>
#include "SDL_render_vita_gxm_tools.h"
#include "SDL_render_vita_gxm_types.h"
#include "SDL_render_vita_gxm_memory.h"
#include "SDL_render_vita_gxm_shaders.h"
void
init_orthographic_matrix(float *m, float left, float right, float bottom, float top, float near, float far)
{
m[0x0] = 2.0f/(right-left);
m[0x4] = 0.0f;
m[0x8] = 0.0f;
m[0xC] = -(right+left)/(right-left);
m[0x1] = 0.0f;
m[0x5] = 2.0f/(top-bottom);
m[0x9] = 0.0f;
m[0xD] = -(top+bottom)/(top-bottom);
m[0x2] = 0.0f;
m[0x6] = 0.0f;
m[0xA] = -2.0f/(far-near);
m[0xE] = (far+near)/(far-near);
m[0x3] = 0.0f;
m[0x7] = 0.0f;
m[0xB] = 0.0f;
m[0xF] = 1.0f;
}
static void *
patcher_host_alloc(void *user_data, unsigned int size)
{
void *mem = SDL_malloc(size);
(void)user_data;
return mem;
}
static void
patcher_host_free(void *user_data, void *mem)
{
(void)user_data;
SDL_free(mem);
}
void *
pool_malloc(VITA_GXM_RenderData *data, unsigned int size)
{
if ((data->pool_index + size) < VITA_GXM_POOL_SIZE) {
void *addr = (void *)((unsigned int)data->pool_addr[data->current_pool] + data->pool_index);
data->pool_index += size;
return addr;
}
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "POOL OVERFLOW\n");
return NULL;
}
void *
pool_memalign(VITA_GXM_RenderData *data, unsigned int size, unsigned int alignment)
{
unsigned int new_index = (data->pool_index + alignment - 1) & ~(alignment - 1);
if ((new_index + size) < VITA_GXM_POOL_SIZE) {
void *addr = (void *)((unsigned int)data->pool_addr[data->current_pool] + new_index);
data->pool_index = new_index + size;
return addr;
}
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "POOL OVERFLOW\n");
return NULL;
}
static int
tex_format_to_bytespp(SceGxmTextureFormat format)
{
switch (format & 0x9f000000U) {
case SCE_GXM_TEXTURE_BASE_FORMAT_U8:
case SCE_GXM_TEXTURE_BASE_FORMAT_S8:
case SCE_GXM_TEXTURE_BASE_FORMAT_P8:
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2: // YUV actually uses 12 bits per pixel. UV planes bits/mem are handled elsewhere
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3:
return 1;
case SCE_GXM_TEXTURE_BASE_FORMAT_U4U4U4U4:
case SCE_GXM_TEXTURE_BASE_FORMAT_U8U3U3U2:
case SCE_GXM_TEXTURE_BASE_FORMAT_U1U5U5U5:
case SCE_GXM_TEXTURE_BASE_FORMAT_U5U6U5:
case SCE_GXM_TEXTURE_BASE_FORMAT_S5S5U6:
case SCE_GXM_TEXTURE_BASE_FORMAT_U8U8:
case SCE_GXM_TEXTURE_BASE_FORMAT_S8S8:
return 2;
case SCE_GXM_TEXTURE_BASE_FORMAT_U8U8U8:
case SCE_GXM_TEXTURE_BASE_FORMAT_S8S8S8:
return 3;
case SCE_GXM_TEXTURE_BASE_FORMAT_U8U8U8U8:
case SCE_GXM_TEXTURE_BASE_FORMAT_S8S8S8S8:
case SCE_GXM_TEXTURE_BASE_FORMAT_F32:
case SCE_GXM_TEXTURE_BASE_FORMAT_U32:
case SCE_GXM_TEXTURE_BASE_FORMAT_S32:
default:
return 4;
}
}
static void
display_callback(const void *callback_data)
{
SceDisplayFrameBuf framebuf;
const VITA_GXM_DisplayData *display_data = (const VITA_GXM_DisplayData *)callback_data;
SDL_memset(&framebuf, 0x00, sizeof(SceDisplayFrameBuf));
framebuf.size = sizeof(SceDisplayFrameBuf);
framebuf.base = display_data->address;
framebuf.pitch = VITA_GXM_SCREEN_STRIDE;
framebuf.pixelformat = VITA_GXM_PIXEL_FORMAT;
framebuf.width = VITA_GXM_SCREEN_WIDTH;
framebuf.height = VITA_GXM_SCREEN_HEIGHT;
sceDisplaySetFrameBuf(&framebuf, SCE_DISPLAY_SETBUF_NEXTFRAME);
if (display_data->wait_vblank) {
sceDisplayWaitVblankStart();
}
}
static void
free_fragment_programs(VITA_GXM_RenderData *data, fragment_programs *out)
{
sceGxmShaderPatcherReleaseFragmentProgram(data->shaderPatcher, out->color);
sceGxmShaderPatcherReleaseFragmentProgram(data->shaderPatcher, out->texture);
}
static void
make_fragment_programs(VITA_GXM_RenderData *data, fragment_programs *out,
const SceGxmBlendInfo *blend_info)
{
int err;
err = sceGxmShaderPatcherCreateFragmentProgram(
data->shaderPatcher,
data->colorFragmentProgramId,
SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
0,
blend_info,
colorVertexProgramGxp,
&out->color
);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Patcher create fragment failed: %d\n", err);
return;
}
err = sceGxmShaderPatcherCreateFragmentProgram(
data->shaderPatcher,
data->textureFragmentProgramId,
SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
0,
blend_info,
textureVertexProgramGxp,
&out->texture
);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Patcher create fragment failed: %d\n", err);
return;
}
}
static void
set_stencil_mask(VITA_GXM_RenderData *data, float x, float y, float w, float h)
{
void *vertexDefaultBuffer;
color_vertex *vertices = (color_vertex *)pool_memalign(
data,
4 * sizeof(color_vertex), // 4 vertices
sizeof(color_vertex)
);
vertices[0].x = x;
vertices[0].y = y;
vertices[0].color.r = 0;
vertices[0].color.g = 0;
vertices[0].color.b = 0;
vertices[0].color.a = 0;
vertices[1].x = x + w;
vertices[1].y = y;
vertices[1].color.r = 0;
vertices[1].color.g = 0;
vertices[1].color.b = 0;
vertices[1].color.a = 0;
vertices[2].x = x;
vertices[2].y = y + h;
vertices[2].color.r = 0;
vertices[2].color.g = 0;
vertices[2].color.b = 0;
vertices[2].color.a = 0;
vertices[3].x = x + w;
vertices[3].y = y + h;
vertices[3].color.r = 0;
vertices[3].color.g = 0;
vertices[3].color.b = 0;
vertices[3].color.a = 0;
data->drawstate.fragment_program = data->colorFragmentProgram;
data->drawstate.vertex_program = data->colorVertexProgram;
sceGxmSetVertexProgram(data->gxm_context, data->colorVertexProgram);
sceGxmSetFragmentProgram(data->gxm_context, data->colorFragmentProgram);
sceGxmReserveVertexDefaultUniformBuffer(data->gxm_context, &vertexDefaultBuffer);
sceGxmSetUniformDataF(vertexDefaultBuffer, data->colorWvpParam, 0, 16, data->ortho_matrix);
sceGxmSetVertexStream(data->gxm_context, 0, vertices);
sceGxmDraw(data->gxm_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, data->linearIndices, 4);
}
void
set_clip_rectangle(VITA_GXM_RenderData *data, int x_min, int y_min, int x_max, int y_max)
{
if(data->drawing) {
// clear the stencil buffer to 0
sceGxmSetFrontStencilFunc(
data->gxm_context,
SCE_GXM_STENCIL_FUNC_NEVER,
SCE_GXM_STENCIL_OP_ZERO,
SCE_GXM_STENCIL_OP_ZERO,
SCE_GXM_STENCIL_OP_ZERO,
0xFF,
0xFF
);
set_stencil_mask(data, 0, 0, VITA_GXM_SCREEN_WIDTH, VITA_GXM_SCREEN_HEIGHT);
// set the stencil to 1 in the desired region
sceGxmSetFrontStencilFunc(
data->gxm_context,
SCE_GXM_STENCIL_FUNC_NEVER,
SCE_GXM_STENCIL_OP_REPLACE,
SCE_GXM_STENCIL_OP_REPLACE,
SCE_GXM_STENCIL_OP_REPLACE,
0xFF,
0xFF
);
set_stencil_mask(data, x_min, y_min, x_max - x_min, y_max - y_min);
// set the stencil function to only accept pixels where the stencil is 1
sceGxmSetFrontStencilFunc(
data->gxm_context,
SCE_GXM_STENCIL_FUNC_EQUAL,
SCE_GXM_STENCIL_OP_KEEP,
SCE_GXM_STENCIL_OP_KEEP,
SCE_GXM_STENCIL_OP_KEEP,
0xFF,
0xFF
);
}
}
void
unset_clip_rectangle(VITA_GXM_RenderData *data)
{
sceGxmSetFrontStencilFunc(
data->gxm_context,
SCE_GXM_STENCIL_FUNC_ALWAYS,
SCE_GXM_STENCIL_OP_KEEP,
SCE_GXM_STENCIL_OP_KEEP,
SCE_GXM_STENCIL_OP_KEEP,
0xFF,
0xFF
);
}
int
gxm_init(SDL_Renderer *renderer)
{
unsigned int i, x, y;
int err;
void *vdmRingBuffer;
void *vertexRingBuffer;
void *fragmentRingBuffer;
unsigned int fragmentUsseRingBufferOffset;
void *fragmentUsseRingBuffer;
unsigned int patcherVertexUsseOffset;
unsigned int patcherFragmentUsseOffset;
void *patcherBuffer;
void *patcherVertexUsse;
void *patcherFragmentUsse;
SceGxmRenderTargetParams renderTargetParams;
SceGxmShaderPatcherParams patcherParams;
// compute the memory footprint of the depth buffer
const unsigned int alignedWidth = ALIGN(VITA_GXM_SCREEN_WIDTH, SCE_GXM_TILE_SIZEX);
const unsigned int alignedHeight = ALIGN(VITA_GXM_SCREEN_HEIGHT, SCE_GXM_TILE_SIZEY);
unsigned int sampleCount = alignedWidth * alignedHeight;
unsigned int depthStrideInSamples = alignedWidth;
// set buffer sizes for this sample
const unsigned int patcherBufferSize = 64*1024;
const unsigned int patcherVertexUsseSize = 64*1024;
const unsigned int patcherFragmentUsseSize = 64*1024;
// Fill SceGxmBlendInfo
static const SceGxmBlendInfo blend_info_none = {
.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,
.colorMask = SCE_GXM_COLOR_MASK_ALL
};
static const SceGxmBlendInfo blend_info_blend = {
.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,
.colorMask = SCE_GXM_COLOR_MASK_ALL
};
static const SceGxmBlendInfo blend_info_add = {
.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,
.alphaSrc = SCE_GXM_BLEND_FACTOR_ZERO,
.alphaDst = SCE_GXM_BLEND_FACTOR_ONE,
.colorMask = SCE_GXM_COLOR_MASK_ALL
};
static const SceGxmBlendInfo blend_info_mod = {
.colorFunc = SCE_GXM_BLEND_FUNC_ADD,
.alphaFunc = SCE_GXM_BLEND_FUNC_ADD,
.colorSrc = SCE_GXM_BLEND_FACTOR_ZERO,
.colorDst = SCE_GXM_BLEND_FACTOR_SRC_COLOR,
.alphaSrc = SCE_GXM_BLEND_FACTOR_ZERO,
.alphaDst = SCE_GXM_BLEND_FACTOR_ONE,
.colorMask = SCE_GXM_COLOR_MASK_ALL
};
static const SceGxmBlendInfo blend_info_mul = {
.colorFunc = SCE_GXM_BLEND_FUNC_ADD,
.alphaFunc = SCE_GXM_BLEND_FUNC_ADD,
.colorSrc = SCE_GXM_BLEND_FACTOR_DST_COLOR,
.colorDst = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.alphaSrc = SCE_GXM_BLEND_FACTOR_DST_ALPHA,
.alphaDst = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.colorMask = SCE_GXM_COLOR_MASK_ALL
};
VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
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\n", err);
return err;
}
// allocate ring buffer memory using default sizes
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);
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);
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);
fragmentUsseRingBuffer = vita_mem_fragment_usse_alloc(
SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE,
&data->fragmentUsseRingBufferUid,
&fragmentUsseRingBufferOffset);
SDL_memset(&data->contextParams, 0, sizeof(SceGxmContextParams));
data->contextParams.hostMem = SDL_malloc(SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE);
data->contextParams.hostMemSize = SCE_GXM_MINIMUM_CONTEXT_HOST_MEM_SIZE;
data->contextParams.vdmRingBufferMem = vdmRingBuffer;
data->contextParams.vdmRingBufferMemSize = SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE;
data->contextParams.vertexRingBufferMem = vertexRingBuffer;
data->contextParams.vertexRingBufferMemSize = SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE;
data->contextParams.fragmentRingBufferMem = fragmentRingBuffer;
data->contextParams.fragmentRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE;
data->contextParams.fragmentUsseRingBufferMem = fragmentUsseRingBuffer;
data->contextParams.fragmentUsseRingBufferMemSize = SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE;
data->contextParams.fragmentUsseRingBufferOffset = fragmentUsseRingBufferOffset;
err = sceGxmCreateContext(&data->contextParams, &data->gxm_context);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create context failed: %d\n", err);
return err;
}
// set up parameters
SDL_memset(&renderTargetParams, 0, sizeof(SceGxmRenderTargetParams));
renderTargetParams.flags = 0;
renderTargetParams.width = VITA_GXM_SCREEN_WIDTH;
renderTargetParams.height = VITA_GXM_SCREEN_HEIGHT;
renderTargetParams.scenesPerFrame = 1;
renderTargetParams.multisampleMode = 0;
renderTargetParams.multisampleLocations = 0;
renderTargetParams.driverMemBlock = -1; // Invalid UID
// create the render target
err = sceGxmCreateRenderTarget(&renderTargetParams, &data->renderTarget);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "render target creation failed: %d\n", err);
return err;
}
// allocate memory and sync objects for display buffers
for (i = 0; i < VITA_GXM_BUFFERS; i++) {
// allocate memory for display
data->displayBufferData[i] = 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->displayBufferUid[i]);
// SDL_memset the buffer to black
for (y = 0; y < VITA_GXM_SCREEN_HEIGHT; y++) {
unsigned int *row = (unsigned int *)data->displayBufferData[i] + y * VITA_GXM_SCREEN_STRIDE;
for (x = 0; x < VITA_GXM_SCREEN_WIDTH; x++) {
row[x] = 0xff000000;
}
}
// initialize a color surface for this display buffer
err = sceGxmColorSurfaceInit(
&data->displaySurface[i],
VITA_GXM_COLOR_FORMAT,
SCE_GXM_COLOR_SURFACE_LINEAR,
SCE_GXM_COLOR_SURFACE_SCALE_NONE,
SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT,
VITA_GXM_SCREEN_WIDTH,
VITA_GXM_SCREEN_HEIGHT,
VITA_GXM_SCREEN_STRIDE,
data->displayBufferData[i]
);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %d\n", err);
return err;
}
// create a sync object that we will associate with this buffer
err = sceGxmSyncObjectCreate(&data->displayBufferSync[i]);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "sync object creation failed: %d\n", err);
return err;
}
}
// allocate the depth buffer
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);
// allocate the stencil buffer
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);
// create the SceGxmDepthStencilSurface structure
err = sceGxmDepthStencilSurfaceInit(
&data->depthSurface,
SCE_GXM_DEPTH_STENCIL_FORMAT_S8D24,
SCE_GXM_DEPTH_STENCIL_SURFACE_TILED,
depthStrideInSamples,
data->depthBufferData,
data->stencilBufferData);
// set the stencil test reference (this is currently assumed to always remain 1 after here for region clipping)
sceGxmSetFrontStencilRef(data->gxm_context, 1);
// set the stencil function (this wouldn't actually be needed, as the set clip rectangle function has to call this at the begginning of every scene)
sceGxmSetFrontStencilFunc(
data->gxm_context,
SCE_GXM_STENCIL_FUNC_ALWAYS,
SCE_GXM_STENCIL_OP_KEEP,
SCE_GXM_STENCIL_OP_KEEP,
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,
patcherBufferSize,
4,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&data->patcherBufferUid);
patcherVertexUsse = vita_mem_vertex_usse_alloc(
patcherVertexUsseSize,
&data->patcherVertexUsseUid,
&patcherVertexUsseOffset);
patcherFragmentUsse = vita_mem_fragment_usse_alloc(
patcherFragmentUsseSize,
&data->patcherFragmentUsseUid,
&patcherFragmentUsseOffset);
// create a shader patcher
SDL_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, &data->shaderPatcher);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "shader patcher creation failed: %d\n", err);
return err;
}
// check the shaders
err = sceGxmProgramCheck(clearVertexProgramGxp);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (clear vertex) failed: %d\n", err);
return err;
}
err = sceGxmProgramCheck(clearFragmentProgramGxp);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (clear fragment) failed: %d\n", err);
return err;
}
err = sceGxmProgramCheck(colorVertexProgramGxp);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (color vertex) failed: %d\n", err);
return err;
}
err = sceGxmProgramCheck(colorFragmentProgramGxp);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (color fragment) failed: %d\n", err);
return err;
}
err = sceGxmProgramCheck(textureVertexProgramGxp);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (texture vertex) failed: %d\n", err);
return err;
}
err = sceGxmProgramCheck(textureFragmentProgramGxp);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "check program (texture fragment) failed: %d\n", err);
return err;
}
// register programs with the patcher
err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, clearVertexProgramGxp, &data->clearVertexProgramId);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (clear vertex) failed: %d\n", err);
return err;
}
err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, clearFragmentProgramGxp, &data->clearFragmentProgramId);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (clear fragment) failed: %d\n", err);
return err;
}
err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, colorVertexProgramGxp, &data->colorVertexProgramId);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (color vertex) failed: %d\n", err);
return err;
}
err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, colorFragmentProgramGxp, &data->colorFragmentProgramId);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (color fragment) failed: %d\n", err);
return err;
}
err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, textureVertexProgramGxp, &data->textureVertexProgramId);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (texture vertex) failed: %d\n", err);
return err;
}
err = sceGxmShaderPatcherRegisterProgram(data->shaderPatcher, textureFragmentProgramGxp, &data->textureFragmentProgramId);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "register program (texture fragment) failed: %d\n", err);
return err;
}
{
// 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(clear_vertex);
clearVertexStreams[0].indexSource = SCE_GXM_INDEX_SOURCE_INDEX_16BIT;
// create clear programs
err = sceGxmShaderPatcherCreateVertexProgram(
data->shaderPatcher,
data->clearVertexProgramId,
clearVertexAttributes,
1,
clearVertexStreams,
1,
&data->clearVertexProgram
);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (clear vertex) failed: %d\n", err);
return err;
}
err = sceGxmShaderPatcherCreateFragmentProgram(
data->shaderPatcher,
data->clearFragmentProgramId,
SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4,
0,
NULL,
clearVertexProgramGxp,
&data->clearFragmentProgram
);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (clear fragment) failed: %d\n", err);
return err;
}
// create the clear triangle vertex/index data
data->clearVertices = (clear_vertex *)vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
3*sizeof(clear_vertex),
4,
SCE_GXM_MEMORY_ATTRIB_READ,
&data->clearVerticesUid
);
}
// Allocate a 64k * 2 bytes = 128 KiB buffer and store all possible
// 16-bit indices in linear ascending order, so we can use this for
// all drawing operations where we don't want to use indexing.
data->linearIndices = (uint16_t *)vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
UINT16_MAX*sizeof(uint16_t),
sizeof(uint16_t),
SCE_GXM_MEMORY_ATTRIB_READ,
&data->linearIndicesUid
);
for (i = 0; i <= UINT16_MAX; ++i)
{
data->linearIndices[i] = i;
}
data->clearVertices[0].x = -1.0f;
data->clearVertices[0].y = -1.0f;
data->clearVertices[1].x = 3.0f;
data->clearVertices[1].y = -1.0f;
data->clearVertices[2].x = -1.0f;
data->clearVertices[2].y = 3.0f;
{
const SceGxmProgramParameter *paramColorPositionAttribute = sceGxmProgramFindParameterByName(colorVertexProgramGxp, "aPosition");
const SceGxmProgramParameter *paramColorColorAttribute = sceGxmProgramFindParameterByName(colorVertexProgramGxp, "aColor");
// create color vertex format
SceGxmVertexAttribute colorVertexAttributes[2];
SceGxmVertexStream colorVertexStreams[1];
/* x,y: 2 float 32 bits */
colorVertexAttributes[0].streamIndex = 0;
colorVertexAttributes[0].offset = 0;
colorVertexAttributes[0].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
colorVertexAttributes[0].componentCount = 2; // (x, y)
colorVertexAttributes[0].regIndex = sceGxmProgramParameterGetResourceIndex(paramColorPositionAttribute);
/* color: 4 unsigned char = 32 bits */
colorVertexAttributes[1].streamIndex = 0;
colorVertexAttributes[1].offset = 8; // (x, y) * 4 = 8 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(color_vertex);
colorVertexStreams[0].indexSource = SCE_GXM_INDEX_SOURCE_INDEX_16BIT;
// create color shaders
err = sceGxmShaderPatcherCreateVertexProgram(
data->shaderPatcher,
data->colorVertexProgramId,
colorVertexAttributes,
2,
colorVertexStreams,
1,
&data->colorVertexProgram
);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (color vertex) failed: %d\n", err);
return err;
}
}
{
const SceGxmProgramParameter *paramTexturePositionAttribute = sceGxmProgramFindParameterByName(textureVertexProgramGxp, "aPosition");
const SceGxmProgramParameter *paramTextureTexcoordAttribute = sceGxmProgramFindParameterByName(textureVertexProgramGxp, "aTexcoord");
const SceGxmProgramParameter *paramTextureColorAttribute = sceGxmProgramFindParameterByName(textureVertexProgramGxp, "aColor");
// create texture vertex format
SceGxmVertexAttribute textureVertexAttributes[3];
SceGxmVertexStream textureVertexStreams[1];
/* x,y: 2 float 32 bits */
textureVertexAttributes[0].streamIndex = 0;
textureVertexAttributes[0].offset = 0;
textureVertexAttributes[0].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
textureVertexAttributes[0].componentCount = 2; // (x, y)
textureVertexAttributes[0].regIndex = sceGxmProgramParameterGetResourceIndex(paramTexturePositionAttribute);
/* u,v: 2 floats 32 bits */
textureVertexAttributes[1].streamIndex = 0;
textureVertexAttributes[1].offset = 8; // (x, y) * 4 = 8 bytes
textureVertexAttributes[1].format = SCE_GXM_ATTRIBUTE_FORMAT_F32;
textureVertexAttributes[1].componentCount = 2; // (u, v)
textureVertexAttributes[1].regIndex = sceGxmProgramParameterGetResourceIndex(paramTextureTexcoordAttribute);
/* r,g,b,a: 4 unsigned chars 32 bits */
textureVertexAttributes[2].streamIndex = 0;
textureVertexAttributes[2].offset = 16; // (x, y, u, v) * 4 = 16 bytes
textureVertexAttributes[2].format = SCE_GXM_ATTRIBUTE_FORMAT_U8N;
textureVertexAttributes[2].componentCount = 4; // (r, g, b, a)
textureVertexAttributes[2].regIndex = sceGxmProgramParameterGetResourceIndex(paramTextureColorAttribute);
// 16 bit (short) indices
textureVertexStreams[0].stride = sizeof(texture_vertex);
textureVertexStreams[0].indexSource = SCE_GXM_INDEX_SOURCE_INDEX_16BIT;
// create texture shaders
err = sceGxmShaderPatcherCreateVertexProgram(
data->shaderPatcher,
data->textureVertexProgramId,
textureVertexAttributes,
3,
textureVertexStreams,
1,
&data->textureVertexProgram
);
if (err != 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create program (texture vertex) failed: %x\n", err);
return err;
}
}
// Create variations of the fragment program based on blending mode
make_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_none, &blend_info_none);
make_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_blend, &blend_info_blend);
make_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_add, &blend_info_add);
make_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mod, &blend_info_mod);
make_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mul, &blend_info_mul);
{
// Default to blend blending mode
fragment_programs *in = &data->blendFragmentPrograms.blend_mode_blend;
data->colorFragmentProgram = in->color;
data->textureFragmentProgram = in->texture;
}
// find vertex uniforms by name and cache parameter information
data->clearClearColorParam = (SceGxmProgramParameter *)sceGxmProgramFindParameterByName(clearFragmentProgramGxp, "uClearColor");
data->colorWvpParam = (SceGxmProgramParameter *)sceGxmProgramFindParameterByName(colorVertexProgramGxp, "wvp");
data->textureWvpParam = (SceGxmProgramParameter *)sceGxmProgramFindParameterByName(textureVertexProgramGxp, "wvp");
// Allocate memory for the memory pool
data->pool_addr[0] = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW,
VITA_GXM_POOL_SIZE,
sizeof(void *),
SCE_GXM_MEMORY_ATTRIB_READ,
&data->poolUid[0]
);
data->pool_addr[1] = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW,
VITA_GXM_POOL_SIZE,
sizeof(void *),
SCE_GXM_MEMORY_ATTRIB_READ,
&data->poolUid[1]
);
init_orthographic_matrix(data->ortho_matrix, 0.0f, VITA_GXM_SCREEN_WIDTH, VITA_GXM_SCREEN_HEIGHT, 0.0f, 0.0f, 1.0f);
data->backBufferIndex = 0;
data->frontBufferIndex = 0;
data->pool_index = 0;
data->current_pool = 0;
data->currentBlendMode = SDL_BLENDMODE_BLEND;
return 0;
}
void gxm_finish(SDL_Renderer *renderer)
{
VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
// wait until rendering is done
sceGxmFinish(data->gxm_context);
// clean up allocations
sceGxmShaderPatcherReleaseFragmentProgram(data->shaderPatcher, data->clearFragmentProgram);
sceGxmShaderPatcherReleaseVertexProgram(data->shaderPatcher, data->clearVertexProgram);
sceGxmShaderPatcherReleaseVertexProgram(data->shaderPatcher, data->colorVertexProgram);
sceGxmShaderPatcherReleaseVertexProgram(data->shaderPatcher, data->textureVertexProgram);
free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_none);
free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_blend);
free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_add);
free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mod);
free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mul);
vita_mem_free(data->linearIndicesUid);
vita_mem_free(data->clearVerticesUid);
// wait until display queue is finished before deallocating display buffers
sceGxmDisplayQueueFinish();
// clean up display queue
vita_mem_free(data->depthBufferUid);
for (size_t i = 0; i < VITA_GXM_BUFFERS; i++)
{
// clear the buffer then deallocate
SDL_memset(data->displayBufferData[i], 0, VITA_GXM_SCREEN_HEIGHT * VITA_GXM_SCREEN_STRIDE * 4);
vita_mem_free(data->displayBufferUid[i]);
// destroy the sync object
sceGxmSyncObjectDestroy(data->displayBufferSync[i]);
}
// Free the depth and stencil buffer
vita_mem_free(data->depthBufferUid);
vita_mem_free(data->stencilBufferUid);
// unregister programs and destroy shader patcher
sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->clearFragmentProgramId);
sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->clearVertexProgramId);
sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->colorFragmentProgramId);
sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->colorVertexProgramId);
sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->textureFragmentProgramId);
sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->textureVertexProgramId);
sceGxmShaderPatcherDestroy(data->shaderPatcher);
vita_mem_fragment_usse_free(data->patcherFragmentUsseUid);
vita_mem_vertex_usse_free(data->patcherVertexUsseUid);
vita_mem_free(data->patcherBufferUid);
// destroy the render target
sceGxmDestroyRenderTarget(data->renderTarget);
// destroy the gxm context
sceGxmDestroyContext(data->gxm_context);
vita_mem_fragment_usse_free(data->fragmentUsseRingBufferUid);
vita_mem_free(data->fragmentRingBufferUid);
vita_mem_free(data->vertexRingBufferUid);
vita_mem_free(data->vdmRingBufferUid);
SDL_free(data->contextParams.hostMem);
vita_mem_free(data->poolUid[0]);
vita_mem_free(data->poolUid[1]);
vita_gpu_mem_destroy(data);
// terminate libgxm
sceGxmTerminate();
}
// textures
void
free_gxm_texture(VITA_GXM_RenderData *data, gxm_texture *texture)
{
if (texture) {
if (texture->gxm_rendertarget) {
sceGxmDestroyRenderTarget(texture->gxm_rendertarget);
}
if (texture->depth_UID) {
vita_mem_free(texture->depth_UID);
}
if (texture->cdram) {
vita_gpu_mem_free(data, sceGxmTextureGetData(&texture->gxm_tex));
} else {
vita_mem_free(texture->data_UID);
}
SDL_free(texture);
}
}
SceGxmTextureFormat
gxm_texture_get_format(const gxm_texture *texture)
{
return sceGxmTextureGetFormat(&texture->gxm_tex);
}
void *
gxm_texture_get_datap(const gxm_texture *texture)
{
return sceGxmTextureGetData(&texture->gxm_tex);
}
gxm_texture *
create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget, unsigned int *return_w, unsigned int *return_h, unsigned int *return_pitch, float *return_wscale)
{
gxm_texture *texture = SDL_calloc(1, sizeof(gxm_texture));
int aligned_w = ALIGN(w, 8);
int texture_w = w;
int tex_size = aligned_w * h * tex_format_to_bytespp(format);
void *texture_data;
int ret;
*return_wscale = 1.0f;
// SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3/P2 based formats require width aligned to 16
if ( (format & 0x9f000000U) == SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3 || (format & 0x9f000000U) == SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2) {
aligned_w = ALIGN(w, 16);
texture_w = aligned_w;
tex_size = aligned_w * h * tex_format_to_bytespp(format);
*return_wscale = (float) (w) / texture_w;
// add storage for UV planes
tex_size += (((aligned_w + 1) / 2) * ((h + 1) / 2)) * 2;
}
if (!texture)
return NULL;
*return_w = w;
*return_h = h;
*return_pitch = aligned_w * tex_format_to_bytespp(format);
/* Allocate a GPU buffer for the texture */
texture_data = vita_gpu_mem_alloc(
data,
tex_size
);
/* Try SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE in case we're out of VRAM */
if (!texture_data) {
SDL_LogWarn(SDL_LOG_CATEGORY_RENDER, "CDRAM texture allocation failed\n");
texture_data = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
tex_size,
SCE_GXM_TEXTURE_ALIGNMENT,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&texture->data_UID
);
texture->cdram = 0;
} else {
texture->cdram = 1;
}
if (!texture_data) {
SDL_free(texture);
return NULL;
}
/* Clear the texture */
SDL_memset(texture_data, 0, tex_size);
/* Create the gxm texture */
ret = sceGxmTextureInitLinear( &texture->gxm_tex, texture_data, format, texture_w, h, 0);
if (ret < 0) {
free_gxm_texture(data, texture);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "texture init failed: %x\n", ret);
return NULL;
}
if (isRenderTarget) {
void *depthBufferData;
const uint32_t alignedWidth = ALIGN(w, SCE_GXM_TILE_SIZEX);
const uint32_t alignedHeight = ALIGN(h, SCE_GXM_TILE_SIZEY);
uint32_t sampleCount = alignedWidth*alignedHeight;
uint32_t depthStrideInSamples = alignedWidth;
const uint32_t alignedColorSurfaceStride = ALIGN(w, 8);
int err = sceGxmColorSurfaceInit(
&texture->gxm_colorsurface,
SCE_GXM_COLOR_FORMAT_A8B8G8R8,
SCE_GXM_COLOR_SURFACE_LINEAR,
SCE_GXM_COLOR_SURFACE_SCALE_NONE,
SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT,
w,
h,
alignedColorSurfaceStride,
texture_data
);
if (err < 0) {
free_gxm_texture(data, texture);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %x\n", err);
return NULL;
}
// allocate it
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,
&texture->depth_UID);
// create the SceGxmDepthStencilSurface structure
err = sceGxmDepthStencilSurfaceInit(
&texture->gxm_depthstencil,
SCE_GXM_DEPTH_STENCIL_FORMAT_S8D24,
SCE_GXM_DEPTH_STENCIL_SURFACE_TILED,
depthStrideInSamples,
depthBufferData,
NULL);
if (err < 0) {
free_gxm_texture(data, texture);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "depth stencil init failed: %x\n", err);
return NULL;
}
{
SceGxmRenderTarget *tgt = NULL;
// set up parameters
SceGxmRenderTargetParams renderTargetParams;
SDL_memset(&renderTargetParams, 0, sizeof(SceGxmRenderTargetParams));
renderTargetParams.flags = 0;
renderTargetParams.width = w;
renderTargetParams.height = h;
renderTargetParams.scenesPerFrame = 1;
renderTargetParams.multisampleMode = SCE_GXM_MULTISAMPLE_NONE;
renderTargetParams.multisampleLocations = 0;
renderTargetParams.driverMemBlock = -1;
// create the render target
err = sceGxmCreateRenderTarget(&renderTargetParams, &tgt);
texture->gxm_rendertarget = tgt;
if (err < 0) {
free_gxm_texture(data, texture);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create render target failed: %x\n", err);
return NULL;
}
}
}
return texture;
}
void
gxm_texture_set_filters(gxm_texture *texture, SceGxmTextureFilter min_filter, SceGxmTextureFilter mag_filter)
{
sceGxmTextureSetMinFilter(&texture->gxm_tex, min_filter);
sceGxmTextureSetMagFilter(&texture->gxm_tex, mag_filter);
}
static unsigned int back_buffer_index_for_common_dialog = 0;
static unsigned int front_buffer_index_for_common_dialog = 0;
struct
{
VITA_GXM_DisplayData displayData;
SceGxmSyncObject* sync;
SceGxmColorSurface surf;
SceUID uid;
} buffer_for_common_dialog[VITA_GXM_BUFFERS];
void gxm_minimal_init_for_common_dialog(void)
{
SceGxmInitializeParams initializeParams;
SDL_zero(initializeParams);
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;
sceGxmInitialize(&initializeParams);
}
void gxm_minimal_term_for_common_dialog(void)
{
sceGxmTerminate();
}
void gxm_init_for_common_dialog(void)
{
for (int i = 0; i < VITA_GXM_BUFFERS; i += 1)
{
buffer_for_common_dialog[i].displayData.wait_vblank = SDL_TRUE;
buffer_for_common_dialog[i].displayData.address = 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,
&buffer_for_common_dialog[i].uid);
sceGxmColorSurfaceInit(
&buffer_for_common_dialog[i].surf,
VITA_GXM_PIXEL_FORMAT,
SCE_GXM_COLOR_SURFACE_LINEAR,
SCE_GXM_COLOR_SURFACE_SCALE_NONE,
SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT,
VITA_GXM_SCREEN_WIDTH,
VITA_GXM_SCREEN_HEIGHT,
VITA_GXM_SCREEN_STRIDE,
buffer_for_common_dialog[i].displayData.address
);
sceGxmSyncObjectCreate(&buffer_for_common_dialog[i].sync);
}
sceGxmDisplayQueueFinish();
}
void gxm_swap_for_common_dialog(void)
{
SceCommonDialogUpdateParam updateParam;
SDL_zero(updateParam);
updateParam.renderTarget.colorFormat = VITA_GXM_PIXEL_FORMAT;
updateParam.renderTarget.surfaceType = SCE_GXM_COLOR_SURFACE_LINEAR;
updateParam.renderTarget.width = VITA_GXM_SCREEN_WIDTH;
updateParam.renderTarget.height = VITA_GXM_SCREEN_HEIGHT;
updateParam.renderTarget.strideInPixels = VITA_GXM_SCREEN_STRIDE;
updateParam.renderTarget.colorSurfaceData = buffer_for_common_dialog[back_buffer_index_for_common_dialog].displayData.address;
updateParam.displaySyncObject = buffer_for_common_dialog[back_buffer_index_for_common_dialog].sync;
SDL_memset(buffer_for_common_dialog[back_buffer_index_for_common_dialog].displayData.address, 0, 4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT);
sceCommonDialogUpdate(&updateParam);
sceGxmDisplayQueueAddEntry(buffer_for_common_dialog[front_buffer_index_for_common_dialog].sync, buffer_for_common_dialog[back_buffer_index_for_common_dialog].sync, &buffer_for_common_dialog[back_buffer_index_for_common_dialog].displayData);
front_buffer_index_for_common_dialog = back_buffer_index_for_common_dialog;
back_buffer_index_for_common_dialog = (back_buffer_index_for_common_dialog + 1) % VITA_GXM_BUFFERS;
}
void gxm_term_for_common_dialog(void)
{
sceGxmDisplayQueueFinish();
for (int i = 0; i < VITA_GXM_BUFFERS; i += 1)
{
vita_mem_free(buffer_for_common_dialog[i].uid);
sceGxmSyncObjectDestroy(buffer_for_common_dialog[i].sync);
}
}
#endif /* SDL_VIDEO_RENDER_VITA_GXM */
/* vi: set ts=4 sw=4 expandtab: */