- fix issue 92 (purple screen). Many thanks to Yeshua and Raphael!
- Switched valloc to vram, more recent and faster.
This commit is contained in:
wagic.the.homebrew@gmail.com
2009-12-07 11:54:59 +00:00
parent ca6f507d0a
commit afc08b4b6e
7 changed files with 347 additions and 328 deletions

View File

@@ -16,7 +16,7 @@ GENERIC_OBJS = src/JApp.o src/JGBKFont.o \
src/tinyxml/tinyxmlparser.o src/tinyxml/tinyxmlerror.o \
src/Encoding.o src/JTTFont.o \
src/JMD2Model.o src/JOBJModel.o
PSP_OBJS = src/JSocket.o src/JGfx.o src/JSfx.o src/JAudio.o src/JMP3.o src/decoder_prx.o src/main.o src/valloc.o
PSP_OBJS = src/JSocket.o src/JGfx.o src/JSfx.o src/JAudio.o src/JMP3.o src/decoder_prx.o src/main.o src/vram.o
LINUX_OBJS = src/linux/JGfx.o src/linux/JSfx.o src/Xmain.o

View File

@@ -83,10 +83,11 @@ public:
//////////////////////////////////////////////////////////////////////////
static JRenderer* GetInstance();
/*
//START PurpleScreen Debug
static int debugged;
//END PurpleScreen Debug
*/
static void Destroy();
static void Set3DFlag(bool flag);

View File

@@ -1,33 +0,0 @@
#ifndef _VALLOC_H
#define _VALLOC_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#define vrelptr vGuPointer
#define vabsptr vCPUPointer
size_t vgetMemorySize(unsigned int width, unsigned int height, unsigned int psm);
// Return a pointer relative to VRAM Base address useable by GU
void* vGuPointer( void* ptr );
// Return an absolute pointer useable by CPU
void* vCPUPointer( void* ptr );
// Returns an absolute pointer useable by CPU
void* valloc( size_t size );
void vfree( void* ptr );
size_t vmemavail();
size_t vlargestblock();
#ifdef __cplusplus
}
#endif
#endif // _VALLOC_H

54
JGE/include/vram.h Normal file
View File

@@ -0,0 +1,54 @@
/*
* Helper for use with the PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under GPL
*
* vram.c - Standard C high performance VRAM allocation routines.
*
* Copyright (c) 2007 Alexander Berl 'Raphael' <raphael@fx-world.org>
* http://wordpress.fx-world.org
*
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef vram_h__
#define vram_h__
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
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)
void* valloc( size_t size );
void vfree( void* ptr );
size_t vmemavail();
size_t vlargestblock();
#ifdef _DEBUG
// Debug printf (to stdout) a trace of the current Memblocks
void __memwalk();
#endif
#ifdef __cplusplus
}
#endif
#endif // ifdef vram_h__

View File

@@ -18,7 +18,7 @@
#include <pspdebug.h>
#include <pspdisplay.h>
#include <png.h>
#include "../include/valloc.h"
#include "../include/vram.h"
#ifdef __cplusplus
extern "C" {
@@ -39,6 +39,7 @@ static unsigned int __attribute__((aligned(16))) list[262144];
extern void SwizzlePlot(u8* out, PIXEL_TYPE color, int i, int j, unsigned int width);
/*
//START PurpleScreen Debug
int JRenderer::debugged = 0;
typedef struct
@@ -88,7 +89,7 @@ extern GuDisplayList* gu_list;
//END PurpleScreen Debug
*/
void Swap(float *a, float *b)
{
@@ -245,19 +246,19 @@ void JRenderer::InitRenderer()
sceGuInit();
fbp0 = ( u32* ) vrelptr ( valloc ( FRAME_BUFFER_SIZE ) );
fbp1 = ( u32* ) vrelptr ( valloc ( FRAME_BUFFER_SIZE ) );
fbp0 = ( u32* ) valloc ( FRAME_BUFFER_SIZE ) ;
fbp1 = ( u32* ) valloc ( FRAME_BUFFER_SIZE );
zbp = NULL;
// setup GU
sceGuStart(GU_DIRECT,list);
sceGuDrawBuffer(BUFFER_FORMAT, fbp0, FRAME_BUFFER_WIDTH);
sceGuDispBuffer(SCREEN_WIDTH, SCREEN_HEIGHT, fbp1, FRAME_BUFFER_WIDTH);
sceGuDrawBuffer(BUFFER_FORMAT, vrelptr (fbp0), FRAME_BUFFER_WIDTH);
sceGuDispBuffer(SCREEN_WIDTH, SCREEN_HEIGHT, vrelptr (fbp1), FRAME_BUFFER_WIDTH);
if (m3DEnabled)
{
zbp = ( u16* ) vrelptr ( valloc ( FRAME_BUFFER_WIDTH*SCREEN_HEIGHT*2) );
sceGuDepthBuffer(zbp, FRAME_BUFFER_WIDTH);
zbp = ( u16* ) valloc ( FRAME_BUFFER_WIDTH*SCREEN_HEIGHT*2);
sceGuDepthBuffer(vrelptr (zbp), FRAME_BUFFER_WIDTH);
}
sceGuOffset(2048 - (SCREEN_WIDTH/2), 2048 - (SCREEN_HEIGHT/2));
@@ -359,7 +360,7 @@ void JRenderer::DestroyRenderer()
sceGuTerm();
vfree(fbp0);
vfree(fbp1);
debugged = 0;
//debugged = 0;
if (zbp) vfree(zbp);
}
@@ -382,6 +383,9 @@ void JRenderer::BeginScene()
else
sceGuTexFilter(GU_LINEAR, GU_LINEAR); // GU_LINEAR good for scaling
//Keep this until we get rev 2489 (or better) of the SDK
//See http://code.google.com/p/wagic/issues/detail?id=92
sceGuSendCommandi(210,BUFFER_FORMAT);
}
@@ -399,6 +403,7 @@ void JRenderer::EndScene()
mCurrentTex = -1;
mCurrentBlend = -1;
/*
//START PurpleScreen Debug
if (!debugged){
debugged = 1;
@@ -419,6 +424,7 @@ void JRenderer::EndScene()
fclose (pFile);
}
//END PurpleScreen Debug
*/
}

View File

@@ -1,284 +0,0 @@
/*
* Helper for use with the PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed as 'free to use and modify as long as credited appropriately'
*
* valloc.c - Standard C library VRAM allocation routines.
*
* Copyright (c) 2006 Alexander Berl <a.berl@gmx.de>
*
*/
//#include <psptypes.h>
//#include <pspkernel.h>
#include <pspgu.h>
#include <malloc.h>
#include "valloc.h"
/* Use this to set the default valloc() alignment. */
#define DEFAULT_VALIGNMENT 16
#ifndef ALIGN
#define ALIGN(x, align) (((x)+((align)-1))&~((align)-1))
#endif
#define VRAM_SIZE 0x200000
#define VRAM_BASE ((unsigned int)sceGeEdramGetAddr())
/* _vram_mem_block_header structure. */
typedef struct _vram_mem_header {
void * ptr;
size_t size;
struct _vram_mem_header * prev;
struct _vram_mem_header * next;
} vram_mem_header_t;
void * __valloc_vram_base = (void*)0;
vram_mem_header_t *__valloc_vram_head = NULL;
vram_mem_header_t *__valloc_vram_tail = NULL;
size_t vgetMemorySize(unsigned int width, unsigned int height, unsigned int psm)
{
switch (psm)
{
case GU_PSM_T4:
return (width * height) >> 1;
case GU_PSM_T8:
return width * height;
case GU_PSM_5650:
case GU_PSM_5551:
case GU_PSM_4444:
case GU_PSM_T16:
return 2 * width * height;
case GU_PSM_8888:
case GU_PSM_T32:
return 4 * width * height;
default:
return 0;
}
}
inline void* vGuPointer( void *ptr )
{
return (void*)((u32)ptr & ~VRAM_BASE);
}
inline void* vCPUPointer( void *ptr )
{
return (void*)((u32)ptr | VRAM_BASE);
}
/* Find the smallest block that we can allocate AFTER, returning NULL if there
are none. */
vram_mem_header_t * _vram_mem_fit(vram_mem_header_t *head, size_t size)
{
vram_mem_header_t *prev_mem = head, *best_fit = NULL;
u32 prev_top, next_bot;
size_t best_size = 0;
if (((u32)head->ptr+head->size+size)<VRAM_SIZE) {
best_fit = head;
best_size = VRAM_SIZE - ((u32)head->ptr+head->size);
}
while (prev_mem != NULL) {
if (prev_mem->next != NULL) {
prev_top = (u32)prev_mem->ptr;
next_bot = prev_top - ((u32)prev_mem->next->ptr + prev_mem->next->size);
if (next_bot >= size) {
if (best_fit==NULL || next_bot<best_size) {
best_fit = prev_mem->next;
best_size = next_bot;
}
}
}
prev_mem = prev_mem->next;
}
return best_fit;
}
void * valloc(size_t size)
{
void *ptr = NULL;
vram_mem_header_t *new_mem, *prev_mem;
size_t mem_sz;
mem_sz = size;
if ((mem_sz & (DEFAULT_VALIGNMENT - 1)) != 0)
mem_sz = ALIGN(mem_sz, DEFAULT_VALIGNMENT);
/* If we don't have any allocated blocks, reserve the first block
and initialize __valloc_vram_tail. */
if (__valloc_vram_head == NULL) {
if (size>VRAM_SIZE)
return ptr;
__valloc_vram_head = (vram_mem_header_t *)malloc( sizeof(vram_mem_header_t) );
if (__valloc_vram_head == NULL)
return ptr;
ptr = (void *)__valloc_vram_base;
__valloc_vram_head->ptr = ptr;
__valloc_vram_head->size = mem_sz;
__valloc_vram_head->prev = NULL;
__valloc_vram_head->next = NULL;
__valloc_vram_tail = __valloc_vram_head;
return vabsptr(ptr);
}
/* Check to see if there's free space at the bottom of the heap.
NOTE: This case is now already handled in _vram_mem_fit */
/*if (((u32)__valloc_vram_head->ptr + __valloc_vram_head->size + mem_sz) < VRAM_SIZE) {
new_mem = (vram_mem_header_t *)malloc( sizeof(vram_mem_header_t) );
if (new_mem == NULL)
return ptr;
ptr = (void *)((u32)__valloc_vram_head->ptr + __valloc_vram_head->size);
new_mem->ptr = ptr;
new_mem->size = mem_sz;
new_mem->prev = NULL;
new_mem->next = __valloc_vram_head;
new_mem->next->prev = new_mem;
__valloc_vram_head = new_mem;
return ptr;
}*/
/* See if we can allocate the block anywhere. */
prev_mem = _vram_mem_fit(__valloc_vram_head, mem_sz);
if (prev_mem != NULL) {
new_mem = (vram_mem_header_t *)malloc( sizeof(vram_mem_header_t) );
if (new_mem == NULL)
return ptr;
ptr = (void *)((u32)prev_mem->ptr + prev_mem->size);
new_mem->ptr = ptr;
new_mem->size = mem_sz;
new_mem->prev = prev_mem->prev;
if (new_mem->prev!=NULL)
new_mem->prev->next = new_mem;
new_mem->next = prev_mem;
prev_mem->prev = new_mem;
if (prev_mem == __valloc_vram_head)
__valloc_vram_head = new_mem;
return vabsptr(ptr);
}
/* Now we have a problem: There's no room at the bottom and also no room in between.
So either we do compact the memory (time critical because memcopies needed) or we
just return NULL so the application has to handle this case itself.
For now we'll just return NULL
*/
return ptr;
}
void vfree(void *ptr)
{
vram_mem_header_t *cur;
if (!ptr)
return;
if (!__valloc_vram_head)
return;
ptr = vrelptr(ptr);
/* Freeing the head pointer is a special case. */
if (ptr == __valloc_vram_head->ptr) {
cur = __valloc_vram_head->next;
free(__valloc_vram_head);
__valloc_vram_head = cur;
if (__valloc_vram_head != NULL) {
__valloc_vram_head->prev = NULL;
} else {
__valloc_vram_tail = NULL;
}
return;
}
cur = __valloc_vram_head;
while (ptr != cur->ptr) {
/* ptr isn't in our list */
if (cur->next == NULL) {
return;
}
cur = cur->next;
}
/* Deallocate the block. */
if (cur->next != NULL) {
cur->next->prev = cur->prev;
} else {
/* If this block was the last one in the list, shrink the heap. */
__valloc_vram_tail = cur->prev;
}
cur->prev->next = cur->next;
free( cur );
}
size_t vmemavail()
{
if (__valloc_vram_head==NULL)
return VRAM_SIZE;
vram_mem_header_t *cur;
size_t size = VRAM_SIZE - ((u32)__valloc_vram_head->ptr + __valloc_vram_head->size);
cur = __valloc_vram_head;
while (cur->next!=NULL) {
size += (u32)cur->ptr - ((u32)cur->next->ptr + cur->next->size);
cur = cur->next;
}
return size;
}
size_t vlargestblock()
{
if (__valloc_vram_head==NULL)
return VRAM_SIZE;
vram_mem_header_t *cur;
size_t size = VRAM_SIZE - ((u32)__valloc_vram_head->ptr + __valloc_vram_head->size);
size_t new_size;
cur = __valloc_vram_head;
while (cur->next!=NULL) {
new_size = (u32)cur->ptr - ((u32)cur->next->ptr + cur->next->size);
if (new_size>size) size = new_size;
cur = cur->next;
}
return size;
}

275
JGE/src/vram.c Normal file
View File

@@ -0,0 +1,275 @@
/*
* Helper for use with the PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under GPL
*
* vram.c - Standard C high performance VRAM allocation routines.
*
* Copyright (c) 2007 Alexander Berl 'Raphael' <raphael@fx-world.org>
* http://wordpress.fx-world.org
*
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "vram.h"
#include <stdio.h>
// Configure the memory to be managed
#define __MEM_SIZE 0x00200000
#define __MEM_START 0x04000000
// Configure the block size the memory gets subdivided into (page size)
// __MEM_SIZE/__BLOCK_SIZE may not exceed 2^15 = 32768
// 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))
// A MEMORY BLOCK ENTRY IS MADE UP LIKE THAT:
// bit: 31 32 30 - 15 14-0
// free block prev size
//
// bit 31: free bit, indicating if block is allocated or not
// bit 30: blocked bit, indicating if block is part of a larger block (0) - used for error resilience
// bit 30-15: block index of previous block
// bit 14- 0: size of current block
//
// This management can handle a max amount of 2^15 = 32768 blocks, which resolves to 32MB 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))
unsigned int __mem_blocks[__MEM_BLOCKS] = { 0 };
static int __largest_update = 0;
static int __largest_block = __MEM_BLOCKS;
static int __mem_free = __MEM_BLOCKS;
inline void* vrelptr( void *ptr )
{
return (void*)((unsigned int)ptr & ~__MEM_START);
}
inline void* vabsptr( void *ptr )
{
return (void*)((unsigned int)ptr | __MEM_START);
}
static void __find_largest_block()
{
int i = 0;
__largest_block = 0;
while (i<__MEM_BLOCKS)
{
int csize = __BLOCK_GET_SIZE(__mem_blocks[i]);
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[i])==3 && csize>__largest_block)
__largest_block = csize;
i += csize;
}
__largest_update = 0;
}
#ifdef _DEBUG
void __memwalk()
{
int i = 0;
if (__mem_blocks[0]==0) __mem_blocks[0] = __BLOCK0;
while (i<__MEM_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]);
}
}
#endif
void* valloc( size_t size )
{
// Initialize memory block, if not yet done
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)
{
#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
// 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 csize = __BLOCK_GET_SIZE(__mem_blocks[i]);
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[i])==3 && csize>=bsize)
{
if (csize<bestblock_size)
{
bestblock = i;
bestblock_prev = j;
bestblock_size = csize;
}
if (csize==bsize)
break;
}
j = i;
i += csize;
}
if (bestblock<0)
{
#ifdef _DEBUG
printf("Not enough memory to allocate %i bytes (largest: %i)!\n",size,vlargestblock());
#endif
return(0);
}
i = bestblock;
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[next] = __BLOCK_MAKE(csize-bsize,i,1,1);
int nextnext = i+csize;
if (nextnext<__MEM_BLOCKS)
{
__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 ((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)));
}
void vfree( void* ptr )
{
if (ptr==0) return;
int block = ((unsigned int)ptr - __MEM_START)/__BLOCK_SIZE;
if (block<0 || block>__MEM_BLOCKS)
{
#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
printf("freeing block %i (0x%x), size: %i\n", block, (int)ptr, csize);
#endif
if (__BLOCK_GET_FREEBLOCK(__mem_blocks[block])!=1 || csize==0)
{
#ifdef _DEBUG
printf("Block was not allocated!\n");
#endif
return;
}
// Mark block as free
__BLOCK_SET_FREE(__mem_blocks[block],1);
__mem_free += csize;
int next = block+csize;
// Merge with previous block if possible
int prev = __BLOCK_GET_PREV(__mem_blocks[block]);
if (prev<block)
{
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 = prev;
}
}
// Merge with next block if possible
if (next<__MEM_BLOCKS)
{
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);
}
}
// Update if a new largest block emerged
if (__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
}
}
size_t vmemavail()
{
return __mem_free * __BLOCK_SIZE;
}
size_t vlargestblock()
{
if (__largest_update) __find_largest_block();
return __largest_block * __BLOCK_SIZE;
}