psp: using the maximum amount of VRAM

This commit is contained in:
Crow-bar
2022-08-10 16:58:20 +03:00
parent b8ff41eac9
commit 91d6fdd190
8 changed files with 208 additions and 111 deletions

View File

@@ -0,0 +1,8 @@
.set noreorder
#include "pspstub.s"
STUB_START "KernelAccess",0x40090000,0x00020005
STUB_FUNC 0x8A5C745F,kaGeEdramSetSize
STUB_FUNC 0x71570ECF,kaGeEdramGetHwSize
STUB_END

View File

@@ -0,0 +1,30 @@
/*
kamod.h - kernel access module header
Copyright (C) 2022 Sergey Galushko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either 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.
*/
#ifndef KAMOD_H
#define KAMOD_H
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
int kaGeEdramSetSize(int size);
int kaGeEdramGetHwSize(void);
#ifdef __cplusplus
}
#endif
#endif // KAMOD_H

View File

@@ -14,6 +14,7 @@ GNU General Public License for more details.
*/
#include "platform/platform.h"
#include "platform/psp/ka/ka.h"
#include <pspsdk.h>
#include <pspkernel.h>
#include <psppower.h>
@@ -256,11 +257,14 @@ int Platform_UnloadModule( SceUID modid, int *sce_code )
return -1;
*sce_code = sceKernelUnloadModule( modid );
return ( ( ( *sce_code ) < 0 ) ? -2 : 0 );
return ( ( ( *sce_code ) < 0 ) ? -2 : 0 );
}
void Platform_Init( void )
{
SceUID kamID;
int result;
// disable fpu exceptions (division by zero and etc...)
pspSdkDisableFPUExceptions();
@@ -269,6 +273,16 @@ void Platform_Init( void )
// set max cpu/gpu frequency
scePowerSetClockFrequency( 333, 333, 166 );
// set max VRAM
kamID = Platform_LoadModule( "ka.prx", 1, 0, NULL );
if( kamID >= 0 )
{
result = kaGeEdramGetHwSize();
if( result > 0 )
result = kaGeEdramSetSize( result );
Platform_UnloadModule( kamID, &result );
}
}
void Platform_Shutdown( void )

View File

@@ -137,6 +137,7 @@ def build(bld):
if bld.env.DEST_OS == 'psp':
source += bld.path.ant_glob(['platform/psp/*.c'])
source += bld.path.ant_glob(['platform/psp/*/*.S'])
# add client files
if not bld.env.DEDICATED:

View File

@@ -417,6 +417,12 @@ qboolean R_Init( void )
if( glw_state.initialized )
return true;
if( vinit() < 0 )
{
gEngfuncs.Host_Error( "Can't initialize video subsystem\nVRam unavailable" );
return false;
}
GL_InitCommands();
GL_InitRandomTable();

View File

@@ -10,20 +10,31 @@
*/
#include "gu_vram.h"
#include <stdio.h>
#include <pspge.h>
#include <stdlib.h>
#define _MBEINVRAM
//#define _DEBUG
// Configure the memory to be managed
#define __MEM_SIZE 0x00200000
#define __MEM_START 0x04000000
static unsigned int __mem_size = 0;
static unsigned int __mem_start = 0;
static int __mem_num_blocks = 0;
static unsigned int *__mem_blocks;
static int __largest_update = 0;
static int __largest_block = 0;
static int __mem_free = 0;
// Configure the block size the memory gets subdivided into (page size)
// __MEM_SIZE/__BLOCK_SIZE may not exceed 2^16-1 = 65535
// __mem_size/__BLOCK_SIZE may not exceed 2^16-1 = 65535
// The block size also defines the alignment of allocations
// Larger block sizes perform better, because the blocktable is smaller and therefore fits better into cache
// however the overhead is also bigger and more memory is wasted
#define __BLOCK_SIZE 512
#define __MEM_BLOCKS (__MEM_SIZE/__BLOCK_SIZE)
#define __BLOCKS(x) ((x+__BLOCK_SIZE-1)/__BLOCK_SIZE)
#define __BLOCKSIZE(x) ((x+__BLOCK_SIZE-1)&~(__BLOCK_SIZE-1))
#define __BLOCK_SIZE 512
#define __BLOCKS(x) (( x + __BLOCK_SIZE - 1 ) / __BLOCK_SIZE )
#define __BLOCKSIZE(x) (( x + __BLOCK_SIZE - 1 ) & ~( __BLOCK_SIZE - 1 ))
// A MEMORY BLOCK ENTRY IS MADE UP LIKE THAT:
@@ -37,36 +48,56 @@
//
// This management can handle a max amount of 2^16-1 = 65535 blocks, which resolves to 64MB at blocksize of 1024 bytes
//
#define __BLOCK_GET_SIZE(x) ((x & 0x7FFF))
#define __BLOCK_GET_PREV(x) ((x >> 15) & 0x7FFF)
#define __BLOCK_GET_FREE(x) ((x >> 31))
#define __BLOCK_GET_BLOCK(x) ((x >> 30) & 0x1)
#define __BLOCK_SET_SIZE(x,y) x=((x & ~0x7FFF) | ((y) & 0x7FFF))
#define __BLOCK_ADD_SIZE(x,y) x=((x & ~0x7FFF) | (((x & 0x7FFF)+((y) & 0x7FFF)) & 0x7FFF))
#define __BLOCK_SET_PREV(x,y) x=((x & ~0x3FFF8000) | (((y) & 0x7FFF)<<15))
#define __BLOCK_SET_FREE(x,y) x=((x & 0x7FFFFFFF) | (((y) & 0x1)<<31))
#define __BLOCK_SET_BLOCK(x,y) x=((x & 0xBFFFFFFF) | (((y) & 0x1)<<30))
#define __BLOCK_MAKE(s,p,f,n) (((f & 0x1)<<31) | ((n & 0x1)<<30) | (((p) & 0x7FFF)<<15) | ((s) & 0x7FFF))
#define __BLOCK_GET_FREEBLOCK(x) ((x>>30) & 0x3) // returns 11b if block is a starting block and free, 10b if block is a starting block and allocated, 0xb if it is a non-starting block (don't change)
#define __BLOCK0 ((__MEM_BLOCKS) | (1<<31) | (1<<30))
#define __BLOCK_GET_SIZE( x ) (( x & 0x7FFF ))
#define __BLOCK_GET_PREV( x ) (( x >> 15 ) & 0x7FFF )
#define __BLOCK_GET_FREE( x ) (( x >> 31 ))
#define __BLOCK_GET_BLOCK( x ) (( x >> 30) & 0x1 )
#define __BLOCK_SET_SIZE( x, y ) x = (( x & ~0x7FFF ) | (( y ) & 0x7FFF ))
#define __BLOCK_ADD_SIZE( x, y ) x = (( x & ~0x7FFF ) | ((( x & 0x7FFF ) + (( y ) & 0x7FFF )) & 0x7FFF ))
#define __BLOCK_SET_PREV( x, y ) x = (( x & ~0x3FFF8000 ) | ((( y ) & 0x7FFF ) << 15 ))
#define __BLOCK_SET_FREE( x, y ) x = (( x & 0x7FFFFFFF ) | ((( y ) & 0x1 ) << 31 ))
#define __BLOCK_SET_BLOCK( x, y ) x = (( x & 0xBFFFFFFF ) | ((( y ) & 0x1 ) << 30 ))
#define __BLOCK_MAKE( s, p, f, n ) ((( f & 0x1 ) << 31 ) | (( n & 0x1 ) << 30 ) | ((( p ) & 0x7FFF ) << 15 ) | (( s ) & 0x7FFF ))
#define __BLOCK_GET_FREEBLOCK( x ) (( x >> 30 ) & 0x3 ) // returns 11b if block is a starting block and free, 10b if block is a starting block and allocated, 0xb if it is a non-starting block (don't change)
#define __BLOCK0 (( __mem_num_blocks ) | ( 1 << 31 ) | ( 1 << 30 ))
int vinit( void )
{
if( __mem_start ) return 0;
unsigned int __mem_blocks[__MEM_BLOCKS] = { 0 };
__mem_size = sceGeEdramGetSize();
__mem_start = ( unsigned int )sceGeEdramGetAddr();
#ifdef _MBEINVRAM
__mem_num_blocks = __mem_size / ( __BLOCK_SIZE + sizeof( unsigned int ));
__mem_size = __mem_num_blocks * __BLOCK_SIZE;
__mem_blocks = ( unsigned int* )( __mem_start + __mem_size ); // to end
#else
__mem_num_blocks = __mem_size / __BLOCK_SIZE;
__mem_blocks = ( unsigned int* )calloc( __mem_num_blocks, sizeof( unsigned int ));
if( !__mem_blocks )
{
__mem_size = 0;
__mem_start = 0;
return -1;
}
#endif
__largest_block = __mem_num_blocks;
__mem_free = __mem_num_blocks;
static int __largest_update = 0;
static int __largest_block = __MEM_BLOCKS;
static int __mem_free = __MEM_BLOCKS;
return 0;
}
inline void* vrelptr( void *ptr )
{
return (void*)((unsigned int)ptr & ~__MEM_START);
if( !__mem_start ) return NULL;
return ( void* )(( unsigned int )ptr & ~__mem_start );
}
inline void* vabsptr( void *ptr )
{
return (void*)((unsigned int)ptr | __MEM_START);
if( !__mem_start ) return NULL;
return ( void* )(( unsigned int )ptr | __mem_start );
}
@@ -74,10 +105,10 @@ static void __find_largest_block( void )
{
int i = 0;
__largest_block = 0;
while (i<__MEM_BLOCKS)
while( i < __mem_num_blocks )
{
int csize = __BLOCK_GET_SIZE(__mem_blocks[i]);
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[i])==3 && csize>__largest_block)
int csize = __BLOCK_GET_SIZE( __mem_blocks[i] );
if( __BLOCK_GET_FREEBLOCK( __mem_blocks[i] ) == 3 && csize > __largest_block )
__largest_block = csize;
i += csize;
}
@@ -88,158 +119,161 @@ static void __find_largest_block( void )
void __memwalk( void )
{
int i = 0;
if (__mem_blocks[0]==0) __mem_blocks[0] = __BLOCK0;
while (i<__MEM_BLOCKS)
if( !__mem_start ) return;
if( __mem_blocks[0] == 0 ) __mem_blocks[0] = __BLOCK0;
while( i < __mem_num_blocks )
{
printf("BLOCK %i:\n", i);
printf(" free: %i\n", __BLOCK_GET_FREEBLOCK(__mem_blocks[i]));
printf(" size: %i\n", __BLOCK_GET_SIZE(__mem_blocks[i]));
printf(" prev: %i\n", __BLOCK_GET_PREV(__mem_blocks[i]));
i+=__BLOCK_GET_SIZE(__mem_blocks[i]);
printf( "BLOCK %i:\n", i );
printf( " free: %i\n", __BLOCK_GET_FREEBLOCK( __mem_blocks[i] ));
printf( " size: %i\n", __BLOCK_GET_SIZE( __mem_blocks[i] ));
printf( " prev: %i\n", __BLOCK_GET_PREV( __mem_blocks[i] ));
i += __BLOCK_GET_SIZE( __mem_blocks[i] );
}
}
#endif
void* valloc( size_t size )
{
if( !__mem_start ) return NULL;
// Initialize memory block, if not yet done
if (__mem_blocks[0]==0) __mem_blocks[0] = __BLOCK0;
if( __mem_blocks[0] == 0 ) __mem_blocks[0] = __BLOCK0;
int i = 0;
int j = 0;
int bsize = __BLOCKS(size);
if (__largest_update==0 && __largest_block<bsize)
int bsize = __BLOCKS( size );
if( __largest_update == 0 && __largest_block < bsize )
{
#ifdef _DEBUG
printf("Not enough memory to allocate %i bytes (largest: %i)!\n",size,vlargestblock());
#endif
return(0);
#ifdef _DEBUG
printf( "Not enough memory to allocate %i bytes (largest: %i)!\n", size, vlargestblock());
#endif
return( 0 );
}
#ifdef _DEBUG
printf("allocating %i bytes, in %i blocks\n", size, bsize);
#endif
#ifdef _DEBUG
printf( "allocating %i bytes, in %i blocks\n", size, bsize );
#endif
// Find smallest block that still fits the requested size
int bestblock = -1;
int bestblock_prev = 0;
int bestblock_size = __MEM_BLOCKS+1;
while (i<__MEM_BLOCKS)
int bestblock_size = __mem_num_blocks + 1;
while( i < __mem_num_blocks )
{
int csize = __BLOCK_GET_SIZE(__mem_blocks[i]);
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[i])==3 && csize>=bsize)
int csize = __BLOCK_GET_SIZE( __mem_blocks[i] );
if( __BLOCK_GET_FREEBLOCK( __mem_blocks[i] ) == 3 && csize >= bsize )
{
if (csize<bestblock_size)
if( csize < bestblock_size )
{
bestblock = i;
bestblock_prev = j;
bestblock_size = csize;
}
if (csize==bsize)
if( csize == bsize )
break;
}
j = i;
i += csize;
}
if (bestblock<0)
if( bestblock < 0 )
{
#ifdef _DEBUG
printf("Not enough memory to allocate %i bytes (largest: %i)!\n",size,vlargestblock());
#endif
return(0);
#ifdef _DEBUG
printf( "Not enough memory to allocate %i bytes (largest: %i)!\n", size, vlargestblock());
#endif
return( 0 );
}
i = bestblock;
j = bestblock_prev;
j = bestblock_prev;
int csize = bestblock_size;
__mem_blocks[i] = __BLOCK_MAKE(bsize,j,0,1);
int next = i+bsize;
if (csize>bsize && next<__MEM_BLOCKS)
__mem_blocks[i] = __BLOCK_MAKE( bsize, j, 0, 1 );
int next = i + bsize;
if( csize > bsize && next < __mem_num_blocks )
{
__mem_blocks[next] = __BLOCK_MAKE(csize-bsize,i,1,1);
int nextnext = i+csize;
if (nextnext<__MEM_BLOCKS)
__mem_blocks[next] = __BLOCK_MAKE( csize - bsize, i, 1, 1 );
int nextnext = i + csize;
if ( nextnext < __mem_num_blocks )
{
__BLOCK_SET_PREV(__mem_blocks[nextnext], next);
__BLOCK_SET_PREV( __mem_blocks[nextnext], next );
}
}
__mem_free -= bsize;
if (__largest_block==csize) // if we just allocated from one of the largest blocks
if( __largest_block == csize ) // if we just allocated from one of the largest blocks
{
if ((csize-bsize)>(__mem_free/2))
__largest_block = (csize-bsize); // there can't be another largest block
if(( csize - bsize ) > ( __mem_free / 2 ))
__largest_block = ( csize - bsize ); // there can't be another largest block
else
__largest_update = 1;
}
return ((void*)(__MEM_START + (i*__BLOCK_SIZE)));
return (( void* )( __mem_start + ( i * __BLOCK_SIZE )));
}
void vfree( void* ptr )
{
if (ptr==0) return;
if( ptr == 0 ) return;
int block = ((unsigned int)ptr - __MEM_START)/__BLOCK_SIZE;
if (block<0 || block>__MEM_BLOCKS)
int block = (( unsigned int )ptr - __mem_start ) / __BLOCK_SIZE;
if( block < 0 || block > __mem_num_blocks )
{
#ifdef _DEBUG
printf("Block is out of range: %i (0x%x)\n", block, (int)ptr);
#endif
#ifdef _DEBUG
printf( "Block is out of range: %i (0x%x)\n", block, (int)ptr );
#endif
return;
}
int csize = __BLOCK_GET_SIZE(__mem_blocks[block]);
#ifdef _DEBUG
int csize = __BLOCK_GET_SIZE( __mem_blocks[block] );
#ifdef _DEBUG
printf("freeing block %i (0x%x), size: %i\n", block, (int)ptr, csize);
#endif
#endif
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[block])!=1 || csize==0)
if( __BLOCK_GET_FREEBLOCK( __mem_blocks[block] ) != 1 || csize == 0 )
{
#ifdef _DEBUG
printf("Block was not allocated!\n");
#endif
#ifdef _DEBUG
printf( "Block was not allocated!\n" );
#endif
return;
}
// Mark block as free
__BLOCK_SET_FREE(__mem_blocks[block],1);
__BLOCK_SET_FREE( __mem_blocks[block], 1 );
__mem_free += csize;
int next = block+csize;
int next = block + csize;
// Merge with previous block if possible
int prev = __BLOCK_GET_PREV(__mem_blocks[block]);
if (prev<block)
int prev = __BLOCK_GET_PREV( __mem_blocks[block] );
if( prev < block )
{
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[prev])==3)
if ( __BLOCK_GET_FREEBLOCK( __mem_blocks[prev] ) == 3 )
{
__BLOCK_ADD_SIZE(__mem_blocks[prev], csize);
__BLOCK_SET_BLOCK(__mem_blocks[block],0); // mark current block as inter block
if (next<__MEM_BLOCKS)
__BLOCK_SET_PREV(__mem_blocks[next], prev);
__BLOCK_ADD_SIZE( __mem_blocks[prev], csize );
__BLOCK_SET_BLOCK( __mem_blocks[block], 0 ); // mark current block as inter block
if ( next < __mem_num_blocks )
__BLOCK_SET_PREV( __mem_blocks[next], prev );
block = prev;
}
}
// Merge with next block if possible
if (next<__MEM_BLOCKS)
if( next < __mem_num_blocks )
{
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[next])==3)
if ( __BLOCK_GET_FREEBLOCK( __mem_blocks[next] ) == 3 )
{
__BLOCK_ADD_SIZE(__mem_blocks[block], __BLOCK_GET_SIZE(__mem_blocks[next]));
__BLOCK_SET_BLOCK(__mem_blocks[next],0); // mark next block as inter block
int nextnext = next + __BLOCK_GET_SIZE(__mem_blocks[next]);
if (nextnext<__MEM_BLOCKS)
__BLOCK_SET_PREV(__mem_blocks[nextnext], block);
__BLOCK_ADD_SIZE( __mem_blocks[block], __BLOCK_GET_SIZE( __mem_blocks[next] ));
__BLOCK_SET_BLOCK( __mem_blocks[next], 0 ); // mark next block as inter block
int nextnext = next + __BLOCK_GET_SIZE( __mem_blocks[next] );
if ( nextnext < __mem_num_blocks )
__BLOCK_SET_PREV( __mem_blocks[nextnext], block );
}
}
// Update if a new largest block emerged
if (__largest_block<__BLOCK_GET_SIZE(__mem_blocks[block]))
if( __largest_block < __BLOCK_GET_SIZE( __mem_blocks[block] ))
{
__largest_block = __BLOCK_GET_SIZE(__mem_blocks[block]);
__largest_block = __BLOCK_GET_SIZE( __mem_blocks[block] );
__largest_update = 0; // No update necessary any more, because update only necessary when largest has shrinked at most
}
}
@@ -247,13 +281,14 @@ void vfree( void* ptr )
size_t vmemavail( void )
{
if( !__mem_start ) return( 0 );
return __mem_free * __BLOCK_SIZE;
}
size_t vlargestblock( void )
{
if (__largest_update) __find_largest_block();
if( !__mem_start ) return( 0 );
if( __largest_update ) __find_largest_block();
return __largest_block * __BLOCK_SIZE;
}

View File

@@ -17,6 +17,8 @@
extern "C" {
#endif
int vinit( void );
void* vrelptr( void *ptr ); // make a pointer relative to memory base address (ATTENTION: A NULL rel ptr is not illegal/invalid!)
void* vabsptr( void *ptr ); // make a pointer absolute (default return type of valloc)

View File

@@ -463,6 +463,7 @@ def configure(conf):
conf.env.PACK_PBP = conf.find_program('pack-pbp', path_list = psp.binutils_path)
conf.env.FIXUP = conf.find_program('psp-fixup-imports', path_list = psp.binutils_path)
conf.env.ASFLAGS += psp.cflags()
conf.env.CFLAGS += psp.cflags()
conf.env.CXXFLAGS += psp.cflags()
conf.env.LINKFLAGS += psp.linkflags()