Files
parallel-dc/core/rend/TexCache.cpp
T
Flyinghead 3a44070a35 Use xxhash for palette hashing. extra depth scale for NHL 2K2
Use xxhash for palette hashing (faster)
Change extra depth scale in rom lut tables and enable it for NHL 2K2
Change 'TV (VBS/Y+S/C)' to 'TV (Composite)'
2018-12-03 14:54:03 +01:00

404 lines
9.7 KiB
C++

#ifdef HAVE_TEXUPSCALE
#include <list>
#include <functional>
#ifndef TARGET_NO_OPENMP
#include <omp.h>
#endif
#endif
#include "TexCache.h"
#include "hw/pvr/pvr_regs.h"
#include "hw/pvr/ta.h"
#include "hw/mem/_vmem.h"
#ifdef HAVE_TEXUPSCALE
#include "deps/xbrz/xbrz.h"
#endif
#include "deps/xxhash/xxhash.h"
u8* vq_codebook;
u32 palette_index;
bool KillTex=false;
u32 palette16_ram[1024];
u32 palette32_ram[1024];
u32 pal_hash_256[4];
u32 pal_hash_16[64];
u32 detwiddle[2][8][1024];
//input : address in the yyyyyxxxxx format
//output : address in the xyxyxyxy format
//U : x resolution , V : y resolution
//twiddle works on 64b words
u32 twiddle_slow(u32 x,u32 y,u32 x_sz,u32 y_sz)
{
u32 sh=0;
u32 rv=0;//low 2 bits are directly passed -> needs some misc stuff to work.However
//Pvr internally maps the 64b banks "as if" they were twiddled :p
x_sz>>=1;
y_sz>>=1;
while(x_sz!=0 || y_sz!=0)
{
if (y_sz)
{
u32 temp=y&1;
rv|=temp<<sh;
y_sz>>=1;
y>>=1;
sh++;
}
if (x_sz)
{
u32 temp=x&1;
rv|=temp<<sh;
x_sz>>=1;
x>>=1;
sh++;
}
}
return rv;
}
void BuildTwiddleTables(void)
{
for (u32 s=0;s<8;s++)
{
u32 x_sz=1024;
u32 y_sz=8<<s;
for (u32 i=0;i<x_sz;i++)
{
detwiddle[0][s][i]=twiddle_slow(i,0,x_sz,y_sz);
detwiddle[1][s][i]=twiddle_slow(0,i,y_sz,x_sz);
}
}
}
static OnLoad btt(&BuildTwiddleTables);
void palette_update(void)
{
if (!pal_needs_update)
return;
pal_needs_update=false;
switch(PAL_RAM_CTRL&3)
{
case 0:
for (int i=0;i<1024;i++)
{
palette16_ram[i] = ARGB1555(PALETTE_RAM[i]);
palette32_ram[i] = ARGB1555_32(PALETTE_RAM[i]);
}
break;
case 1:
for (int i=0;i<1024;i++)
{
palette16_ram[i] = ARGB565(PALETTE_RAM[i]);
palette32_ram[i] = ARGB565_32(PALETTE_RAM[i]);
}
break;
case 2:
for (int i=0;i<1024;i++)
{
palette16_ram[i] = ARGB4444(PALETTE_RAM[i]);
palette32_ram[i] = ARGB4444_32(PALETTE_RAM[i]);
}
break;
case 3:
for (int i=0;i<1024;i++)
{
palette16_ram[i] = ARGB8888(PALETTE_RAM[i]);
palette32_ram[i] = ARGB8888_32(PALETTE_RAM[i]);
}
break;
}
for (int i = 0; i < 64; i++)
pal_hash_16[i] = XXH32(&palette32_ram[i << 4], 16 * 4, 7);
for (int i = 0; i < 4; i++)
pal_hash_256[i] = XXH32(&palette32_ram[i << 8], 256 * 4, 7);
}
using namespace std;
/* Naomi edit - allow for max possible VRAM_SIZE here */
vector<vram_block*> VramLocks[/*VRAM_SIZE*/(16*1024*1024)/PAGE_SIZE];
//vram 32-64b
VArray2 vram;
//List functions
//
void vramlock_list_remove(vram_block* block)
{
u32 base = block->start/PAGE_SIZE;
u32 end = block->end/PAGE_SIZE;
for (u32 i=base;i<=end;i++)
{
vector<vram_block*>* list=&VramLocks[i];
for (size_t j=0;j<list->size();j++)
{
if ((*list)[j]==block)
{
(*list)[j]=0;
}
}
}
}
void vramlock_list_add(vram_block* block)
{
u32 base = block->start/PAGE_SIZE;
u32 end = block->end/PAGE_SIZE;
for (u32 i=base;i<=end;i++)
{
vector<vram_block*>* list=&VramLocks[i];
for (u32 j=0;j<list->size();j++)
{
if ((*list)[j]==0)
{
(*list)[j]=block;
goto added_it;
}
}
list->push_back(block);
added_it:
i=i;
}
}
cMutex vramlist_lock;
//simple IsInRange test
static INLINE bool IsInRange(vram_block* block,u32 offset)
{
return (block->start<=offset) && (block->end>=offset);
}
vram_block* libCore_vramlock_Lock(u32 start_offset64,
u32 end_offset64,void* userdata)
{
vram_block* block=(vram_block* )malloc(sizeof(vram_block));
if (end_offset64>(VRAM_SIZE-1))
{
msgboxf("vramlock_Lock_64: end_offset64>(VRAM_SIZE-1) \n Tried to lock area out of vram , possibly bug on the pvr plugin",MBX_OK);
end_offset64=(VRAM_SIZE-1);
}
if (start_offset64>end_offset64)
{
msgboxf("vramlock_Lock_64: start_offset64>end_offset64 \n Tried to lock negative block , possibly bug on the pvr plugin",MBX_OK);
start_offset64=0;
}
block->end=end_offset64;
block->start=start_offset64;
block->len=end_offset64-start_offset64+1;
block->userdata=userdata;
block->type=64;
{
vramlist_lock.Lock();
vram.LockRegion(block->start,block->len);
//TODO: Fix this for 32M wrap as well
if (_nvmem_enabled() && VRAM_SIZE == 0x800000) {
vram.LockRegion(block->start + VRAM_SIZE, block->len);
}
vramlock_list_add(block);
vramlist_lock.Unlock();
}
return block;
}
bool VramLockedWrite(u8* address)
{
size_t offset=address-vram.data;
if (offset<VRAM_SIZE)
{
size_t addr_hash = offset/PAGE_SIZE;
vector<vram_block*>* list=&VramLocks[addr_hash];
{
vramlist_lock.Lock();
for (size_t i=0;i<list->size();i++)
{
if ((*list)[i])
{
libPvr_LockedBlockWrite((*list)[i],(u32)offset);
if ((*list)[i])
{
msgboxf("Error : pvr is supposed to remove lock",MBX_OK);
dbgbreak;
}
}
}
list->clear();
vram.UnLockRegion((u32)offset&(~(PAGE_SIZE-1)),PAGE_SIZE);
//TODO: Fix this for 32M wrap as well
if (_nvmem_enabled() && VRAM_SIZE == 0x800000) {
vram.UnLockRegion((u32)offset&(~(PAGE_SIZE-1)) + VRAM_SIZE,PAGE_SIZE);
}
vramlist_lock.Unlock();
}
return true;
}
else
return false;
}
//unlocks mem
//also frees the handle
void libCore_vramlock_Unlock_block(vram_block* block)
{
vramlist_lock.Lock();
libCore_vramlock_Unlock_block_wb(block);
vramlist_lock.Unlock();
}
void libCore_vramlock_Unlock_block_wb(vram_block* block)
{
if (block->end>VRAM_SIZE)
msgboxf("Error : block end is after vram , skipping unlock",MBX_OK);
else
{
vramlock_list_remove(block);
//more work needed
free(block);
}
}
#ifdef HAVE_TEXUPSCALE
//
// deposterization: smoothes posterized gradients from low-color-depth (e.g. 444, 565, compressed) sources
// Shamelessly stolen from ppsspp
// Copyright (c) 2012- PPSSPP Project.
//
#define BLOCK_SIZE 32
static void deposterizeH(u32* data, u32* out, int w, int l, int u) {
static const int T = 8;
for (int y = l; y < u; ++y) {
for (int x = 0; x < w; ++x) {
int inpos = y*w + x;
u32 center = data[inpos];
if (x == 0 || x == w - 1) {
out[y*w + x] = center;
continue;
}
u32 left = data[inpos - 1];
u32 right = data[inpos + 1];
out[y*w + x] = 0;
for (int c = 0; c < 4; ++c) {
u8 lc = ((left >> c * 8) & 0xFF);
u8 cc = ((center >> c * 8) & 0xFF);
u8 rc = ((right >> c * 8) & 0xFF);
if ((lc != rc) && ((lc == cc && abs((int)((int)rc) - cc) <= T) || (rc == cc && abs((int)((int)lc) - cc) <= T))) {
// blend this component
out[y*w + x] |= ((rc + lc) / 2) << (c * 8);
} else {
// no change for this component
out[y*w + x] |= cc << (c * 8);
}
}
}
}
}
static void deposterizeV(u32* data, u32* out, int w, int h, int l, int u) {
static const int T = 8;
for (int xb = 0; xb < w / BLOCK_SIZE + 1; ++xb) {
for (int y = l; y < u; ++y) {
for (int x = xb*BLOCK_SIZE; x < (xb + 1)*BLOCK_SIZE && x < w; ++x) {
u32 center = data[y * w + x];
if (y == 0 || y == h - 1) {
out[y*w + x] = center;
continue;
}
u32 upper = data[(y - 1) * w + x];
u32 lower = data[(y + 1) * w + x];
out[y*w + x] = 0;
for (int c = 0; c < 4; ++c) {
u8 uc = ((upper >> c * 8) & 0xFF);
u8 cc = ((center >> c * 8) & 0xFF);
u8 lc = ((lower >> c * 8) & 0xFF);
if ((uc != lc) && ((uc == cc && abs((int)((int)lc) - cc) <= T) || (lc == cc && abs((int)((int)uc) - cc) <= T))) {
// blend this component
out[y*w + x] |= ((lc + uc) / 2) << (c * 8);
} else {
// no change for this component
out[y*w + x] |= cc << (c * 8);
}
}
}
}
}
}
#ifndef TARGET_NO_OPENMP
void parallelize(const std::function<void(int,int)> &func, int start, int end, int width /* = 0 */)
{
int tcount = omp_get_num_procs() - 1;
if (tcount < 1)
tcount = 1;
tcount = min(tcount, (int)settings.pvr.MaxThreads);
#pragma omp parallel num_threads(tcount)
{
int num_threads = omp_get_num_threads();
int thread = omp_get_thread_num();
int chunk = (end - start) / num_threads;
func(start + chunk * thread,
num_threads == thread + 1 ? end
: (start + chunk * (thread + 1)));
}
}
void DePosterize(u32* source, u32* dest, int width, int height) {
u32 *tmpbuf = (u32 *)malloc(width * height * sizeof(u32));
parallelize(std::bind(&deposterizeH, source, tmpbuf, width, std::placeholders::_1, std::placeholders::_2), 0, height, width);
parallelize(std::bind(&deposterizeV, tmpbuf, dest, width, height, std::placeholders::_1, std::placeholders::_2), 0, height, width);
parallelize(std::bind(&deposterizeH, dest, tmpbuf, width, std::placeholders::_1, std::placeholders::_2), 0, height, width);
parallelize(std::bind(&deposterizeV, tmpbuf, dest, width, height, std::placeholders::_1, std::placeholders::_2), 0, height, width);
free(tmpbuf);
}
#endif
struct xbrz::ScalerCfg xbrz_cfg;
void UpscalexBRZ(int factor, u32* source, u32* dest, int width, int height, bool has_alpha) {
#ifndef TARGET_NO_OPENMP
parallelize(
std::bind(&xbrz::scale, factor, source, dest, width, height, has_alpha ? xbrz::ColorFormat::ARGB : xbrz::ColorFormat::RGB, xbrz_cfg,
std::placeholders::_1, std::placeholders::_2), 0, height, width);
// xbrz::scale(factor, source, dest, width, height, has_alpha ? xbrz::ColorFormat::ARGB : xbrz::ColorFormat::RGB, xbrz_cfg);
#else
xbrz::scale(factor, source, dest, width, height, has_alpha ? xbrz::ColorFormat::ARGB : xbrz::ColorFormat::RGB, xbrz_cfg);
#endif
}
void shutdown_thread_pool()
{
}
#endif