From afc08b4b6ed5bfa5c59602e74d369caaeb3d26db Mon Sep 17 00:00:00 2001 From: "wagic.the.homebrew@gmail.com" Date: Mon, 7 Dec 2009 11:54:59 +0000 Subject: [PATCH] Erwan - fix issue 92 (purple screen). Many thanks to Yeshua and Raphael! - Switched valloc to vram, more recent and faster. --- JGE/Makefile | 2 +- JGE/include/JRenderer.h | 3 +- JGE/include/valloc.h | 33 ----- JGE/include/vram.h | 54 ++++++++ JGE/src/JGfx.cpp | 24 ++-- JGE/src/valloc.c | 284 ---------------------------------------- JGE/src/vram.c | 275 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 347 insertions(+), 328 deletions(-) delete mode 100644 JGE/include/valloc.h create mode 100644 JGE/include/vram.h delete mode 100644 JGE/src/valloc.c create mode 100644 JGE/src/vram.c diff --git a/JGE/Makefile b/JGE/Makefile index f22568070..d4037364a 100644 --- a/JGE/Makefile +++ b/JGE/Makefile @@ -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 diff --git a/JGE/include/JRenderer.h b/JGE/include/JRenderer.h index 43931923e..ea2a2d38e 100644 --- a/JGE/include/JRenderer.h +++ b/JGE/include/JRenderer.h @@ -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); diff --git a/JGE/include/valloc.h b/JGE/include/valloc.h deleted file mode 100644 index 3a7158ec3..000000000 --- a/JGE/include/valloc.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _VALLOC_H -#define _VALLOC_H - -#include - - -#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 diff --git a/JGE/include/vram.h b/JGE/include/vram.h new file mode 100644 index 000000000..66cf93284 --- /dev/null +++ b/JGE/include/vram.h @@ -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' + * 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 + +#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__ diff --git a/JGE/src/JGfx.cpp b/JGE/src/JGfx.cpp index 6f438a858..c4296bd64 100644 --- a/JGE/src/JGfx.cpp +++ b/JGE/src/JGfx.cpp @@ -18,7 +18,7 @@ #include #include #include -#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 +*/ } diff --git a/JGE/src/valloc.c b/JGE/src/valloc.c deleted file mode 100644 index 4c602ba90..000000000 --- a/JGE/src/valloc.c +++ /dev/null @@ -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 - * - */ -//#include -//#include -#include -#include -#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)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_botnext; - 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; -} - diff --git a/JGE/src/vram.c b/JGE/src/vram.c new file mode 100644 index 000000000..f90908eeb --- /dev/null +++ b/JGE/src/vram.c @@ -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' + * 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 + +// 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) + { + if (csizebsize && 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