mirror of
https://github.com/libretro/parallel-dc.git
synced 2026-11-07 12:37:53 -10:00
handle some palette textures on the GPU. vulkan: some linear tiling
get rid of PixerPacker templates gl4: no need for GLSL precision qualifier in GL4 vk: Refactor base and oit renderers to avoid code dup vk: Linear tiling is faster for small, frequently updated textures Fix Hello Kitty crash with empty first TR polygon Fix Test Drive Le Mans crash on invalid textures
This commit is contained in:
1 parent
0e10e86ea9
commit
c2f735809c
32 files changed
+1070
-767
No files matched your search
+83
-38
@@ -21,6 +21,7 @@ u32 palette16_ram[1024];
|
||||
u32 palette32_ram[1024];
|
||||
u32 pal_hash_256[4];
|
||||
u32 pal_hash_16[64];
|
||||
bool palette_updated;
|
||||
|
||||
// Rough approximation of LoD bias from D adjust param, only used to increase LoD
|
||||
const std::array<f32, 16> D_Adjust_LoD_Bias = {
|
||||
@@ -86,8 +87,9 @@ void palette_update()
|
||||
{
|
||||
if (!pal_needs_update)
|
||||
return;
|
||||
pal_needs_update = false;
|
||||
palette_updated = true;
|
||||
|
||||
pal_needs_update=false;
|
||||
switch(PAL_RAM_CTRL&3)
|
||||
{
|
||||
case 0:
|
||||
@@ -129,8 +131,7 @@ void palette_update()
|
||||
}
|
||||
|
||||
static std::vector<vram_block*> VramLocks[VRAM_SIZE_MAX / PAGE_SIZE];
|
||||
//vram 32-64b
|
||||
VArray2 vram;
|
||||
VArray2 vram; // vram 32-64b
|
||||
|
||||
//List functions
|
||||
//
|
||||
@@ -251,14 +252,7 @@ bool VramLockedWrite(u8* address)
|
||||
|
||||
//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)
|
||||
static void libCore_vramlock_Unlock_block_wb(vram_block* block)
|
||||
{
|
||||
if (mmu_enabled())
|
||||
vmem32_unprotect_vram(block->start, block->len);
|
||||
@@ -266,6 +260,13 @@ void libCore_vramlock_Unlock_block_wb(vram_block* block)
|
||||
free(block);
|
||||
}
|
||||
|
||||
void libCore_vramlock_Unlock_block(vram_block* block)
|
||||
{
|
||||
vramlist_lock.Lock();
|
||||
libCore_vramlock_Unlock_block_wb(block);
|
||||
vramlist_lock.Unlock();
|
||||
}
|
||||
|
||||
#ifdef HAVE_TEXUPSCALE
|
||||
//
|
||||
// deposterization: smoothes posterized gradients from low-color-depth (e.g. 444, 565, compressed) sources
|
||||
@@ -400,17 +401,19 @@ struct PvrTexInfo
|
||||
TexConvFP32 *PL32;
|
||||
TexConvFP32 *TW32;
|
||||
TexConvFP32 *VQ32;
|
||||
// Conversion to 8 bpp (palette)
|
||||
TexConvFP8 *TW8;
|
||||
};
|
||||
|
||||
static const PvrTexInfo format[8] =
|
||||
{ // name bpp Final format Planar Twiddled VQ Planar(32b) Twiddled(32b) VQ (32b)
|
||||
{"1555", 16, TextureType::_5551, tex1555_PL, tex1555_TW, tex1555_VQ, tex1555_PL32, tex1555_TW32, tex1555_VQ32 }, //1555
|
||||
{"565", 16, TextureType::_565, tex565_PL, tex565_TW, tex565_VQ, tex565_PL32, tex565_TW32, tex565_VQ32 }, //565
|
||||
{"4444", 16, TextureType::_4444, tex4444_PL, tex4444_TW, tex4444_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32 }, //4444
|
||||
{"yuv", 16, TextureType::_8888, NULL, NULL, NULL, texYUV422_PL, texYUV422_TW, texYUV422_VQ }, //yuv
|
||||
{"bumpmap", 16, TextureType::_4444, texBMP_PL, texBMP_TW, texBMP_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32 }, //bump map
|
||||
{"pal4", 4, TextureType::_5551, 0, texPAL4_TW, texPAL4_VQ, NULL, texPAL4_TW32, texPAL4_VQ32 }, //pal4
|
||||
{"pal8", 8, TextureType::_5551, 0, texPAL8_TW, texPAL8_VQ, NULL, texPAL8_TW32, texPAL8_VQ32 }, //pal8
|
||||
{ // name bpp Final format Planar Twiddled VQ Planar(32b) Twiddled(32b) VQ (32b) Palette (8b)
|
||||
{"1555", 16, TextureType::_5551, tex1555_PL, tex1555_TW, tex1555_VQ, tex1555_PL32, tex1555_TW32, tex1555_VQ32, nullptr }, //1555
|
||||
{"565", 16, TextureType::_565, tex565_PL, tex565_TW, tex565_VQ, tex565_PL32, tex565_TW32, tex565_VQ32, nullptr }, //565
|
||||
{"4444", 16, TextureType::_4444, tex4444_PL, tex4444_TW, tex4444_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32, nullptr }, //4444
|
||||
{"yuv", 16, TextureType::_8888, nullptr, nullptr, nullptr, texYUV422_PL, texYUV422_TW, texYUV422_VQ, nullptr }, //yuv
|
||||
{"bumpmap", 16, TextureType::_4444, texBMP_PL, texBMP_TW, texBMP_VQ, tex4444_PL32, tex4444_TW32, tex4444_VQ32, nullptr }, //bump map
|
||||
{"pal4", 4, TextureType::_5551, nullptr, texPAL4_TW, texPAL4_VQ, nullptr, texPAL4_TW32, texPAL4_VQ32, texPAL4PT_TW }, //pal4
|
||||
{"pal8", 8, TextureType::_5551, nullptr, texPAL8_TW, texPAL8_VQ, nullptr, texPAL8_TW32, texPAL8_VQ32, texPAL8PT_TW }, //pal8
|
||||
{"ns/1555", 0}, // Not supported (1555)
|
||||
};
|
||||
|
||||
@@ -454,16 +457,16 @@ void BaseTextureCacheData::PrintTextureName()
|
||||
|
||||
if (tcw.VQ_Comp)
|
||||
strcat(str, " VQ");
|
||||
|
||||
if (tcw.ScanOrder==0)
|
||||
else if (tcw.ScanOrder == 0)
|
||||
strcat(str, " TW");
|
||||
|
||||
if (tcw.MipMapped)
|
||||
strcat(str, " MM");
|
||||
|
||||
if (tcw.StrideSel)
|
||||
else if (tcw.StrideSel)
|
||||
strcat(str, " Stride");
|
||||
|
||||
if (tcw.ScanOrder == 0 && tcw.MipMapped)
|
||||
strcat(str, " MM");
|
||||
if (tsp.FilterMode != 0)
|
||||
strcat(str, " Bilinear");
|
||||
|
||||
sprintf(str + strlen(str), " %dx%d @ 0x%X", 8 << tsp.TexU, 8 << tsp.TexV, tcw.TexAddr << 3);
|
||||
std::string id = GetId();
|
||||
sprintf(str + strlen(str), " id=%s", id.c_str());
|
||||
@@ -472,9 +475,15 @@ void BaseTextureCacheData::PrintTextureName()
|
||||
|
||||
//true if : dirty or paletted texture and hashes don't match
|
||||
bool BaseTextureCacheData::NeedsUpdate() {
|
||||
bool rc = dirty
|
||||
|| (tcw.PixelFmt == PixelPal4 && palette_hash != pal_hash_16[tcw.PalSelect])
|
||||
|| (tcw.PixelFmt == PixelPal8 && palette_hash != pal_hash_256[tcw.PalSelect >> 4]);
|
||||
bool rc = dirty != 0;
|
||||
if (tex_type != TextureType::_8)
|
||||
{
|
||||
if (tcw.PixelFmt == PixelPal4 && palette_hash != pal_hash_16[tcw.PalSelect])
|
||||
rc = true;
|
||||
else if (tcw.PixelFmt == PixelPal8 && palette_hash != pal_hash_256[tcw.PalSelect >> 4])
|
||||
rc = true;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -500,7 +509,6 @@ bool BaseTextureCacheData::Delete()
|
||||
void BaseTextureCacheData::Create()
|
||||
{
|
||||
//Reset state info ..
|
||||
Lookups = 0;
|
||||
Updates = 0;
|
||||
dirty = FrameCount;
|
||||
lock_block = nullptr;
|
||||
@@ -521,19 +529,27 @@ void BaseTextureCacheData::Create()
|
||||
else if (tex->bpp == 8)
|
||||
palette_index = (tcw.PalSelect >> 4) << 8;
|
||||
|
||||
texconv8 = nullptr;
|
||||
|
||||
if (tcw.ScanOrder && (tex->PL || tex->PL32))
|
||||
{
|
||||
//Texture is stored 'planar' in memory, no deswizzle is needed
|
||||
//verify(tcw.VQ_Comp==0);
|
||||
if (tcw.VQ_Comp != 0)
|
||||
{
|
||||
WARN_LOG(RENDERER, "Warning: planar texture with VQ set (invalid)");
|
||||
tcw.VQ_Comp = 0;
|
||||
}
|
||||
if (tcw.MipMapped != 0)
|
||||
{
|
||||
WARN_LOG(RENDERER, "Warning: planar texture with mipmaps (invalid)");
|
||||
tcw.MipMapped = 0;
|
||||
}
|
||||
|
||||
//Planar textures support stride selection, mostly used for non power of 2 textures (videos)
|
||||
int stride = 0;
|
||||
int stride = w;
|
||||
if (tcw.StrideSel)
|
||||
stride = (TEXT_CONTROL & 31) * 32;
|
||||
if (stride == 0)
|
||||
stride = w;
|
||||
|
||||
//Call the format specific conversion code
|
||||
texconv = tex->PL;
|
||||
@@ -543,6 +559,8 @@ void BaseTextureCacheData::Create()
|
||||
}
|
||||
else
|
||||
{
|
||||
tcw.ScanOrder = 0;
|
||||
tcw.StrideSel = 0;
|
||||
// Quake 3 Arena uses one
|
||||
if (tcw.MipMapped)
|
||||
// Mipmapped texture must be square and TexV is ignored
|
||||
@@ -566,6 +584,7 @@ void BaseTextureCacheData::Create()
|
||||
texconv = tex->TW;
|
||||
texconv32 = tex->TW32;
|
||||
size = w * h * tex->bpp / 8;
|
||||
texconv8 = tex->TW8;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -590,9 +609,14 @@ void BaseTextureCacheData::Update()
|
||||
bool has_alpha = false;
|
||||
if (IsPaletted())
|
||||
{
|
||||
tex_type = PAL_TYPE[PAL_RAM_CTRL&3];
|
||||
if (tex_type != TextureType::_565)
|
||||
has_alpha = true;
|
||||
if (IsGpuHandledPaletted(tsp, tcw))
|
||||
tex_type = TextureType::_8;
|
||||
else
|
||||
{
|
||||
tex_type = PAL_TYPE[PAL_RAM_CTRL&3];
|
||||
if (tex_type != TextureType::_565)
|
||||
has_alpha = true;
|
||||
}
|
||||
|
||||
// Get the palette hash to check for future updates
|
||||
if (tcw.PixelFmt == PixelPal4)
|
||||
@@ -613,7 +637,7 @@ void BaseTextureCacheData::Update()
|
||||
u32 original_h = h;
|
||||
if (sa_tex > VRAM_SIZE || size == 0 || sa + size > VRAM_SIZE)
|
||||
{
|
||||
if (sa + size > VRAM_SIZE)
|
||||
if (sa < VRAM_SIZE && sa + size > VRAM_SIZE && tcw.ScanOrder && stride > 0)
|
||||
{
|
||||
// Shenmue Space Harrier mini-arcade loads a texture that goes beyond the end of VRAM
|
||||
// but only uses the top portion of it
|
||||
@@ -635,11 +659,12 @@ void BaseTextureCacheData::Update()
|
||||
|
||||
PixelBuffer<u16> pb16;
|
||||
PixelBuffer<u32> pb32;
|
||||
PixelBuffer<u8> pb8;
|
||||
|
||||
// Figure out if we really need to use a 32-bit pixel buffer
|
||||
bool textureUpscaling = settings.rend.TextureUpscale > 1
|
||||
// Don't process textures that are too big
|
||||
&& w * h <= settings.rend.MaxFilteredTextureSize * settings.rend.MaxFilteredTextureSize
|
||||
&& (int)(w * h) <= settings.rend.MaxFilteredTextureSize * settings.rend.MaxFilteredTextureSize
|
||||
// Don't process YUV textures
|
||||
&& tcw.PixelFmt != PixelYUV;
|
||||
bool need_32bit_buffer = true;
|
||||
@@ -725,6 +750,26 @@ void BaseTextureCacheData::Update()
|
||||
}
|
||||
temp_tex_buffer = pb32.data();
|
||||
}
|
||||
else if (texconv8 != NULL && tex_type == TextureType::_8)
|
||||
{
|
||||
if (mipmapped)
|
||||
{
|
||||
pb8.init(w, h, true);
|
||||
for (u32 i = 0; i <= tsp.TexU + 3u; i++)
|
||||
{
|
||||
pb8.set_mipmap(i);
|
||||
u32 vram_addr = sa_tex + OtherMipPoint[i] * tex->bpp / 8;
|
||||
texconv8(&pb8, &vram[vram_addr], 1 << i, 1 << i);
|
||||
}
|
||||
pb8.set_mipmap(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pb8.init(w, h);
|
||||
texconv8(&pb8, &vram[sa], stride, h);
|
||||
}
|
||||
temp_tex_buffer = pb8.data();
|
||||
}
|
||||
else if (texconv != NULL)
|
||||
{
|
||||
if (mipmapped)
|
||||
|
||||
+115
-105
@@ -1,12 +1,11 @@
|
||||
#pragma once
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <array>
|
||||
#include "hw/pvr/pvr_regs.h"
|
||||
#undef ID
|
||||
#include "hw/pvr/ta_structs.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
|
||||
extern u8* vq_codebook;
|
||||
extern u32 palette_index;
|
||||
@@ -16,6 +15,7 @@ extern bool pal_needs_update,fog_needs_update;
|
||||
extern u32 pal_hash_256[4];
|
||||
extern u32 pal_hash_16[64];
|
||||
extern bool KillTex;
|
||||
extern bool palette_updated;
|
||||
|
||||
extern u32 detwiddle[2][11][1024];
|
||||
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void palette_update(void);
|
||||
void palette_update();
|
||||
|
||||
#define clamp(minv,maxv,x) min(maxv,max(minv,x))
|
||||
|
||||
@@ -151,47 +151,22 @@ void palette_update(void);
|
||||
|
||||
#define ARGB8888_32( word ) ( ((word >> 0) & 0xFF000000) | (((word >> 16) & 0xFF) << 0) | (((word >> 8) & 0xFF) << 8) | ((word & 0xFF) << 16) )
|
||||
|
||||
template<class PixelPacker>
|
||||
__forceinline u32 YUV422(s32 Y,s32 Yu,s32 Yv)
|
||||
inline static u32 YUV422(s32 Y,s32 Yu,s32 Yv)
|
||||
{
|
||||
Yu-=128;
|
||||
Yv-=128;
|
||||
|
||||
//s32 B = (76283*(Y - 16) + 132252*(Yu - 128))>>16;
|
||||
//s32 G = (76283*(Y - 16) - 53281 *(Yv - 128) - 25624*(Yu - 128))>>16;
|
||||
//s32 R = (76283*(Y - 16) + 104595*(Yv - 128))>>16;
|
||||
|
||||
s32 R = Y + Yv*11/8; // Y + (Yv-128) * (11/8) ?
|
||||
s32 G = Y - (Yu*11 + Yv*22)/32; // Y - (Yu-128) * (11/8) * 0.25 - (Yv-128) * (11/8) * 0.5 ?
|
||||
s32 B = Y + Yu*110/64; // Y + (Yu-128) * (11/8) * 1.25 ?
|
||||
|
||||
return PixelPacker::packRGB(clamp(0,255,R),clamp(0,255,G),clamp(0,255,B));
|
||||
return clamp(0, 255, R) | (clamp(0, 255, G) << 8) | (clamp(0, 255, B) << 16) | 0xFF000000;
|
||||
}
|
||||
|
||||
#define twop(x,y,bcx,bcy) (detwiddle[0][bcy][x]+detwiddle[1][bcx][y])
|
||||
|
||||
//pixel packers !
|
||||
struct pp_565
|
||||
{
|
||||
__forceinline static u32 packRGB(u8 R,u8 G,u8 B)
|
||||
{
|
||||
R>>=3;
|
||||
G>>=2;
|
||||
B>>=3;
|
||||
return (R<<11) | (G<<5) | (B<<0);
|
||||
}
|
||||
};
|
||||
|
||||
struct pp_8888
|
||||
{
|
||||
__forceinline static u32 packRGB(u8 R,u8 G,u8 B)
|
||||
{
|
||||
return (R << 0) | (G << 8) | (B << 16) | 0xFF000000;
|
||||
}
|
||||
};
|
||||
|
||||
//pixel convertors !
|
||||
#define pixelcvt_start_base(name,x,y,type) template<class PixelPacker> \
|
||||
#define pixelcvt_start_base(name,x,y,type) \
|
||||
struct name \
|
||||
{ \
|
||||
static const u32 xpp=x;\
|
||||
@@ -202,7 +177,7 @@ struct pp_8888
|
||||
#define pixelcvt_start(name,x,y) pixelcvt_start_base(name, x, y, u16)
|
||||
#define pixelcvt32_start(name,x,y) pixelcvt_start_base(name, x, y, u32)
|
||||
|
||||
#define pixelcvt_size_start(name, x, y) template<class PixelPacker, class pixel_size> \
|
||||
#define pixelcvt_size_start(name, x, y) template<class pixel_size> \
|
||||
struct name \
|
||||
{ \
|
||||
static const u32 xpp=x;\
|
||||
@@ -315,9 +290,9 @@ pixelcvt32_start(convYUV_PL,4,1)
|
||||
s32 Yv = (p_in[0]>>16) &255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(0,YUV422<PixelPacker>(Y0,Yu,Yv));
|
||||
pb->prel(0,YUV422(Y0,Yu,Yv));
|
||||
//1,0
|
||||
pb->prel(1,YUV422<PixelPacker>(Y1,Yu,Yv));
|
||||
pb->prel(1,YUV422(Y1,Yu,Yv));
|
||||
|
||||
//next 4 bytes
|
||||
p_in+=1;
|
||||
@@ -328,9 +303,9 @@ pixelcvt32_start(convYUV_PL,4,1)
|
||||
Yv = (p_in[0]>>16) &255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(2,YUV422<PixelPacker>(Y0,Yu,Yv));
|
||||
pb->prel(2,YUV422(Y0,Yu,Yv));
|
||||
//1,0
|
||||
pb->prel(3,YUV422<PixelPacker>(Y1,Yu,Yv));
|
||||
pb->prel(3,YUV422(Y1,Yu,Yv));
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
@@ -436,9 +411,9 @@ pixelcvt32_start(convYUV_TW,2,2)
|
||||
s32 Yv = (p_in[2]>>0) &255; //p_in[2]
|
||||
|
||||
//0,0
|
||||
pb->prel(0,0,YUV422<PixelPacker>(Y0,Yu,Yv));
|
||||
pb->prel(0,0,YUV422(Y0,Yu,Yv));
|
||||
//1,0
|
||||
pb->prel(1,0,YUV422<PixelPacker>(Y1,Yu,Yv));
|
||||
pb->prel(1,0,YUV422(Y1,Yu,Yv));
|
||||
|
||||
//next 4 bytes
|
||||
//p_in+=2;
|
||||
@@ -449,9 +424,9 @@ pixelcvt32_start(convYUV_TW,2,2)
|
||||
Yv = (p_in[3]>>0) &255; //p_in[2]
|
||||
|
||||
//0,1
|
||||
pb->prel(0,1,YUV422<PixelPacker>(Y0,Yu,Yv));
|
||||
pb->prel(0,1,YUV422(Y0,Yu,Yv));
|
||||
//1,1
|
||||
pb->prel(1,1,YUV422<PixelPacker>(Y1,Yu,Yv));
|
||||
pb->prel(1,1,YUV422(Y1,Yu,Yv));
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
@@ -483,6 +458,33 @@ pixelcvt_size_start(convPAL4_TW,4,4)
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
// Palette 4bpp -> 8bpp
|
||||
pixelcvt_size_start(convPAL4PT_TW, 4, 4)
|
||||
{
|
||||
u8* p_in = (u8 *)data;
|
||||
|
||||
pb->prel(0, 0, p_in[0] & 0xF);
|
||||
pb->prel(0, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(1, 0, p_in[0] & 0xF);
|
||||
pb->prel(1, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
|
||||
pb->prel(0, 2, p_in[0] & 0xF);
|
||||
pb->prel(0, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(1, 2, p_in[0] & 0xF);
|
||||
pb->prel(1, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
|
||||
pb->prel(2, 0, p_in[0] & 0xF);
|
||||
pb->prel(2, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(3, 0, p_in[0] & 0xF);
|
||||
pb->prel(3, 1, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
|
||||
pb->prel(2, 2, p_in[0] & 0xF);
|
||||
pb->prel(2, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
pb->prel(3, 2, p_in[0] & 0xF);
|
||||
pb->prel(3, 3, (p_in[0] >> 4) & 0xF); p_in++;
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
pixelcvt_size_start(convPAL8_TW,2,4)
|
||||
{
|
||||
u8* p_in=(u8*)data;
|
||||
@@ -500,6 +502,24 @@ pixelcvt_size_start(convPAL8_TW,2,4)
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
// Palette 8bpp -> 8bpp (untwiddle only)
|
||||
pixelcvt_size_start(convPAL8PT_TW, 2, 4)
|
||||
{
|
||||
u8* p_in = (u8 *)data;
|
||||
|
||||
pb->prel(0, 0, p_in[0]); p_in++;
|
||||
pb->prel(0, 1, p_in[0]); p_in++;
|
||||
pb->prel(1, 0, p_in[0]); p_in++;
|
||||
pb->prel(1, 1, p_in[0]); p_in++;
|
||||
|
||||
pb->prel(0, 2, p_in[0]); p_in++;
|
||||
pb->prel(0, 3, p_in[0]); p_in++;
|
||||
pb->prel(1, 2, p_in[0]); p_in++;
|
||||
pb->prel(1, 3, p_in[0]); p_in++;
|
||||
}
|
||||
pixelcvt_end;
|
||||
|
||||
|
||||
//handler functions
|
||||
template<class PixelConvertor, class pixel_type>
|
||||
void texture_PL(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
@@ -569,74 +589,51 @@ void texture_VQ(PixelBuffer<pixel_type>* pb,u8* p_in,u32 Width,u32 Height)
|
||||
}
|
||||
}
|
||||
|
||||
//We ask the compiler to generate the templates here
|
||||
//;)
|
||||
//planar formats !
|
||||
template void texture_PL<conv565_PL<pp_565>, u16>(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_PL<conv1555_PL<pp_565>, u16>(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_PL<conv4444_PL<pp_565>, u16>(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_PL<convYUV_PL<pp_8888>, u32>(PixelBuffer<u32>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
|
||||
//twiddled formats !
|
||||
template void texture_TW<conv565_TW<pp_565>, u16>(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_TW<conv1555_TW<pp_565>, u16>(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_TW<conv4444_TW<pp_565>, u16>(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_TW<convYUV_TW<pp_8888>, u32>(PixelBuffer<u32>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
|
||||
template void texture_TW<convPAL4_TW<pp_565, u16>, u16>(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_TW<convPAL8_TW<pp_565, u16>, u16>(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_TW<convPAL4_TW<pp_8888, u32>, u32>(PixelBuffer<u32>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_TW<convPAL8_TW<pp_8888, u32>, u32>(PixelBuffer<u32>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
|
||||
//VQ formats !
|
||||
template void texture_VQ<conv565_TW<pp_565>, u16>(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_VQ<conv1555_TW<pp_565>, u16>(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_VQ<conv4444_TW<pp_565>, u16>(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
template void texture_VQ<convYUV_TW<pp_8888>, u32>(PixelBuffer<u32>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
|
||||
//Planar
|
||||
#define tex565_PL texture_PL<conv565_PL<pp_565>, u16>
|
||||
#define tex1555_PL texture_PL<conv1555_PL<pp_565>, u16>
|
||||
#define tex4444_PL texture_PL<conv4444_PL<pp_565>, u16>
|
||||
#define texYUV422_PL texture_PL<convYUV_PL<pp_8888>, u32>
|
||||
#define tex565_PL texture_PL<conv565_PL, u16>
|
||||
#define tex1555_PL texture_PL<conv1555_PL, u16>
|
||||
#define tex4444_PL texture_PL<conv4444_PL, u16>
|
||||
#define texYUV422_PL texture_PL<convYUV_PL, u32>
|
||||
#define texBMP_PL tex4444_PL
|
||||
|
||||
#define tex565_PL32 texture_PL<conv565_PL32<pp_8888>, u32>
|
||||
#define tex1555_PL32 texture_PL<conv1555_PL32<pp_8888>, u32>
|
||||
#define tex4444_PL32 texture_PL<conv4444_PL32<pp_8888>, u32>
|
||||
#define tex565_PL32 texture_PL<conv565_PL32, u32>
|
||||
#define tex1555_PL32 texture_PL<conv1555_PL32, u32>
|
||||
#define tex4444_PL32 texture_PL<conv4444_PL32, u32>
|
||||
|
||||
//Twiddle
|
||||
#define tex565_TW texture_TW<conv565_TW<pp_565>, u16>
|
||||
#define tex1555_TW texture_TW<conv1555_TW<pp_565>, u16>
|
||||
#define tex4444_TW texture_TW<conv4444_TW<pp_565>, u16>
|
||||
#define texYUV422_TW texture_TW<convYUV_TW<pp_8888>, u32>
|
||||
#define tex565_TW texture_TW<conv565_TW, u16>
|
||||
#define tex1555_TW texture_TW<conv1555_TW, u16>
|
||||
#define tex4444_TW texture_TW<conv4444_TW, u16>
|
||||
#define texYUV422_TW texture_TW<convYUV_TW, u32>
|
||||
#define texBMP_TW tex4444_TW
|
||||
#define texPAL4_TW texture_TW<convPAL4_TW<pp_565, u16>, u16>
|
||||
#define texPAL8_TW texture_TW<convPAL8_TW<pp_565, u16>, u16>
|
||||
#define texPAL4_TW32 texture_TW<convPAL4_TW<pp_8888, u32>, u32>
|
||||
#define texPAL8_TW32 texture_TW<convPAL8_TW<pp_8888, u32>, u32>
|
||||
#define texPAL4_TW texture_TW<convPAL4_TW<u16>, u16>
|
||||
#define texPAL8_TW texture_TW<convPAL8_TW<u16>, u16>
|
||||
#define texPAL4_TW32 texture_TW<convPAL4_TW<u32>, u32>
|
||||
#define texPAL8_TW32 texture_TW<convPAL8_TW<u32>, u32>
|
||||
#define texPAL4PT_TW texture_TW<convPAL4PT_TW<u8>, u8>
|
||||
#define texPAL8PT_TW texture_TW<convPAL8PT_TW<u8>, u8>
|
||||
|
||||
#define tex565_TW32 texture_TW<conv565_TW32<pp_8888>, u32>
|
||||
#define tex1555_TW32 texture_TW<conv1555_TW32<pp_8888>, u32>
|
||||
#define tex4444_TW32 texture_TW<conv4444_TW32<pp_8888>, u32>
|
||||
#define tex565_TW32 texture_TW<conv565_TW32, u32>
|
||||
#define tex1555_TW32 texture_TW<conv1555_TW32, u32>
|
||||
#define tex4444_TW32 texture_TW<conv4444_TW32, u32>
|
||||
|
||||
//VQ
|
||||
#define tex565_VQ texture_VQ<conv565_TW<pp_565>, u16>
|
||||
#define tex1555_VQ texture_VQ<conv1555_TW<pp_565>, u16>
|
||||
#define tex4444_VQ texture_VQ<conv4444_TW<pp_565>, u16>
|
||||
#define texYUV422_VQ texture_VQ<convYUV_TW<pp_8888>, u32>
|
||||
#define tex565_VQ texture_VQ<conv565_TW, u16>
|
||||
#define tex1555_VQ texture_VQ<conv1555_TW, u16>
|
||||
#define tex4444_VQ texture_VQ<conv4444_TW, u16>
|
||||
#define texYUV422_VQ texture_VQ<convYUV_TW, u32>
|
||||
#define texBMP_VQ tex4444_VQ
|
||||
// According to the documentation, a texture cannot be compressed and use
|
||||
// a palette at the same time. However the hardware displays them
|
||||
// just fine.
|
||||
#define texPAL4_VQ texture_VQ<convPAL4_TW<pp_565, u16>, u16>
|
||||
#define texPAL8_VQ texture_VQ<convPAL8_TW<pp_565, u16>, u16>
|
||||
#define texPAL4_VQ texture_VQ<convPAL4_TW<u16>, u16>
|
||||
#define texPAL8_VQ texture_VQ<convPAL8_TW<u16>, u16>
|
||||
|
||||
#define tex565_VQ32 texture_VQ<conv565_TW32<pp_8888>, u32>
|
||||
#define tex1555_VQ32 texture_VQ<conv1555_TW32<pp_8888>, u32>
|
||||
#define tex4444_VQ32 texture_VQ<conv4444_TW32<pp_8888>, u32>
|
||||
#define texPAL4_VQ32 texture_VQ<convPAL4_TW<pp_8888, u32>, u32>
|
||||
#define texPAL8_VQ32 texture_VQ<convPAL8_TW<pp_8888, u32>, u32>
|
||||
#define tex565_VQ32 texture_VQ<conv565_TW32, u32>
|
||||
#define tex1555_VQ32 texture_VQ<conv1555_TW32, u32>
|
||||
#define tex4444_VQ32 texture_VQ<conv4444_TW32, u32>
|
||||
#define texPAL4_VQ32 texture_VQ<convPAL4_TW<u32>, u32>
|
||||
#define texPAL8_VQ32 texture_VQ<convPAL8_TW<u32>, u32>
|
||||
|
||||
bool VramLockedWriteOffset(size_t offset);
|
||||
#ifdef HAVE_TEXUPSCALE
|
||||
@@ -647,19 +644,19 @@ void UpscalexBRZ(int factor, u32* source, u32* dest, int width, int height, bool
|
||||
struct PvrTexInfo;
|
||||
template <class pixel_type> class PixelBuffer;
|
||||
typedef void TexConvFP(PixelBuffer<u16>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
typedef void TexConvFP8(PixelBuffer<u8>* pb, u8* p_in, u32 Width, u32 Height);
|
||||
typedef void TexConvFP32(PixelBuffer<u32>* pb,u8* p_in,u32 Width,u32 Height);
|
||||
enum class TextureType { _565, _5551, _4444, _8888, _8 };
|
||||
|
||||
struct BaseTextureCacheData
|
||||
class BaseTextureCacheData
|
||||
{
|
||||
public:
|
||||
TSP tsp; //dreamcast texture parameters
|
||||
TCW tcw;
|
||||
|
||||
// Decoded/filtered texture format
|
||||
TextureType tex_type;
|
||||
|
||||
u32 Lookups;
|
||||
|
||||
u32 sa; //pixel data start address in vram (might be offset for mipmaps/etc)
|
||||
u32 sa_tex; //texture data start address in vram
|
||||
u32 w,h; //width & height of the texture
|
||||
@@ -668,6 +665,7 @@ struct BaseTextureCacheData
|
||||
const PvrTexInfo* tex;
|
||||
TexConvFP* texconv;
|
||||
TexConvFP32* texconv32;
|
||||
TexConvFP8 *texconv8;
|
||||
|
||||
u32 dirty;
|
||||
vram_block* lock_block;
|
||||
@@ -728,6 +726,18 @@ struct BaseTextureCacheData
|
||||
bool NeedsUpdate();
|
||||
virtual bool Delete();
|
||||
virtual ~BaseTextureCacheData() {}
|
||||
static bool IsGpuHandledPaletted(TSP tsp, TCW tcw)
|
||||
{
|
||||
// Some palette textures are handled on the GPU
|
||||
// This is currently limited to textures using nearest filtering and not mipmapped.
|
||||
// Enabling texture upscaling or dumping also disables this mode.
|
||||
return (tcw.PixelFmt == PixelPal4 || tcw.PixelFmt == PixelPal8)
|
||||
&& settings.rend.TextureUpscale == 1
|
||||
&& !settings.rend.DumpTextures
|
||||
&& tsp.FilterMode == 0
|
||||
&& !tcw.MipMapped
|
||||
&& !tcw.VQ_Comp;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Texture>
|
||||
@@ -738,12 +748,13 @@ public:
|
||||
Texture *getTextureCacheData(TSP tsp, TCW tcw)
|
||||
{
|
||||
u64 key = tsp.full & TSPTextureCacheMask.full;
|
||||
if (tcw.PixelFmt == PixelPal4 || tcw.PixelFmt == PixelPal8)
|
||||
if ((tcw.PixelFmt == PixelPal4 || tcw.PixelFmt == PixelPal8)
|
||||
&& !BaseTextureCacheData::IsGpuHandledPaletted(tsp, tcw))
|
||||
// Paletted textures have a palette selection that must be part of the key
|
||||
// We also add the palette type to the key to avoid thrashing the cache
|
||||
// when the palette type is changed. If the palette type is changed back in the future,
|
||||
// this texture will stil be available.
|
||||
key |= ((u64)tcw.full << 32) | ((PAL_RAM_CTRL & 3) << 6);
|
||||
key |= ((u64)tcw.full << 32) | ((PAL_RAM_CTRL & 3) << 6) | ((tsp.FilterMode != 0) << 8);
|
||||
else
|
||||
key |= (u64)(tcw.full & TCWTextureCacheMask.full) << 32;
|
||||
|
||||
@@ -763,16 +774,15 @@ public:
|
||||
texture->tsp = tsp;
|
||||
texture->tcw = tcw;
|
||||
}
|
||||
texture->Lookups++;
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void CollectCleanup()
|
||||
{
|
||||
vector<u64> list;
|
||||
std::vector<u64> list;
|
||||
|
||||
u32 TargetFrame = max((u32)120, FrameCount) - 120;
|
||||
u32 TargetFrame = std::max((u32)120, FrameCount) - 120;
|
||||
|
||||
for (const auto& pair : cache)
|
||||
{
|
||||
|
||||
@@ -423,7 +423,7 @@ void DrawTranslucentModVols(int first, int count)
|
||||
|
||||
int mod_base = -1;
|
||||
|
||||
for (u32 cmv = 0; cmv < count; cmv++)
|
||||
for (int cmv = 0; cmv < count; cmv++)
|
||||
{
|
||||
ModifierVolumeParam& param = params[cmv];
|
||||
|
||||
@@ -432,7 +432,7 @@ void DrawTranslucentModVols(int first, int count)
|
||||
|
||||
u32 mv_mode = param.isp.DepthMode;
|
||||
|
||||
verify(param.first >= 0 && param.first + param.count <= pvrrc.modtrig.used());
|
||||
verify(param.first >= 0 && param.first + param.count <= (u32)pvrrc.modtrig.used());
|
||||
|
||||
if (mod_base == -1)
|
||||
mod_base = param.first;
|
||||
|
||||
+35
-21
@@ -10,28 +10,38 @@ struct gl4PipelineShader
|
||||
{
|
||||
GLuint program;
|
||||
|
||||
GLuint scale;
|
||||
GLuint extra_depth_scale;
|
||||
GLuint pp_ClipTest,cp_AlphaTestValue;
|
||||
GLuint sp_FOG_COL_RAM,sp_FOG_COL_VERT,sp_FOG_DENSITY;
|
||||
GLuint shade_scale_factor;
|
||||
GLuint pp_Number;
|
||||
GLuint blend_mode;
|
||||
GLuint use_alpha;
|
||||
GLuint ignore_tex_alpha;
|
||||
GLuint shading_instr;
|
||||
GLuint fog_control;
|
||||
GLuint trilinear_alpha;
|
||||
GLuint fog_clamp_min, fog_clamp_max;
|
||||
GLint scale;
|
||||
GLint extra_depth_scale;
|
||||
GLint pp_ClipTest;
|
||||
GLint cp_AlphaTestValue;
|
||||
GLint sp_FOG_COL_RAM;
|
||||
GLint sp_FOG_COL_VERT;
|
||||
GLint sp_FOG_DENSITY;
|
||||
GLint shade_scale_factor;
|
||||
GLint pp_Number;
|
||||
GLint blend_mode;
|
||||
GLint use_alpha;
|
||||
GLint ignore_tex_alpha;
|
||||
GLint shading_instr;
|
||||
GLint fog_control;
|
||||
GLint trilinear_alpha;
|
||||
GLint fog_clamp_min, fog_clamp_max;
|
||||
GLint palette_index;
|
||||
|
||||
u32 cp_AlphaTest;
|
||||
bool cp_AlphaTest;
|
||||
s32 pp_ClipTestMode;
|
||||
u32 pp_Texture, pp_UseAlpha, pp_IgnoreTexA, pp_ShadInstr, pp_Offset, pp_FogCtrl;
|
||||
bool pp_Texture;
|
||||
bool pp_UseAlpha;
|
||||
bool pp_IgnoreTexA;
|
||||
u32 pp_ShadInstr;
|
||||
bool pp_Offset;
|
||||
u32 pp_FogCtrl;
|
||||
Pass pass;
|
||||
bool pp_TwoVolumes;
|
||||
bool pp_Gouraud;
|
||||
bool pp_BumpMap;
|
||||
bool fog_clamping;
|
||||
bool palette;
|
||||
};
|
||||
|
||||
|
||||
@@ -41,8 +51,8 @@ struct gl4_ctx
|
||||
{
|
||||
GLuint program;
|
||||
|
||||
GLuint scale;
|
||||
GLuint extra_depth_scale;
|
||||
GLint scale;
|
||||
GLint extra_depth_scale;
|
||||
} modvol_shader;
|
||||
|
||||
std::unordered_map<u32, gl4PipelineShader> shaders;
|
||||
@@ -85,8 +95,8 @@ void gl4DrawGunCrosshair(u8 port);
|
||||
\n\
|
||||
layout(r32ui, binding = 4) uniform coherent restrict uimage2D abufferPointerImg; \n\
|
||||
struct Pixel { \n\
|
||||
highp vec4 color; \n\
|
||||
highp float depth; \n\
|
||||
vec4 color; \n\
|
||||
float depth; \n\
|
||||
uint seq_num; \n\
|
||||
uint next; \n\
|
||||
}; \n\
|
||||
@@ -117,7 +127,7 @@ uint getNextPixelIndex() \n\
|
||||
\n\
|
||||
void setFragDepth(void) \n\
|
||||
{ \n\
|
||||
highp float w = 100000.0 * gl_FragCoord.w; \n\
|
||||
float w = 100000.0 * gl_FragCoord.w; \n\
|
||||
gl_FragDepth = log2(1.0 + w) / 34.0; \n\
|
||||
} \n\
|
||||
struct PolyParam { \n\
|
||||
@@ -244,8 +254,9 @@ extern struct gl4ShaderUniforms_t
|
||||
TCW tcw1;
|
||||
float fog_clamp_min[4];
|
||||
float fog_clamp_max[4];
|
||||
float palette_index;
|
||||
|
||||
void setUniformArray(GLuint location, int v0, int v1)
|
||||
void setUniformArray(GLint location, int v0, int v1)
|
||||
{
|
||||
int array[] = { v0, v1 };
|
||||
glUniform1iv(location, 2, array);
|
||||
@@ -301,6 +312,9 @@ extern struct gl4ShaderUniforms_t
|
||||
glUniform4fv(s->fog_clamp_min, 1, fog_clamp_min);
|
||||
if (s->fog_clamp_max != -1)
|
||||
glUniform4fv(s->fog_clamp_max, 1, fog_clamp_max);
|
||||
|
||||
if (s->palette_index != -1)
|
||||
glUniform1f(s->palette_index, palette_index);
|
||||
}
|
||||
|
||||
} gl4ShaderUniforms;
|
||||
|
||||
+52
-35
@@ -19,14 +19,15 @@ GLuint depth_fbo;
|
||||
GLuint depthSaveTexId;
|
||||
|
||||
static gl4PipelineShader *gl4GetProgram(
|
||||
u32 cp_AlphaTest,
|
||||
bool cp_AlphaTest,
|
||||
s32 pp_ClipTestMode,
|
||||
u32 pp_Texture,
|
||||
u32 pp_UseAlpha,
|
||||
u32 pp_IgnoreTexA,
|
||||
bool pp_Texture,
|
||||
bool pp_UseAlpha,
|
||||
bool pp_IgnoreTexA,
|
||||
u32 pp_ShadInstr,
|
||||
u32 pp_Offset,
|
||||
u32 pp_FogCtrl, bool pp_TwoVolumes, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, Pass pass)
|
||||
bool pp_Offset,
|
||||
u32 pp_FogCtrl, bool pp_TwoVolumes, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping,
|
||||
bool palette, Pass pass)
|
||||
{
|
||||
u32 rv=0;
|
||||
|
||||
@@ -38,10 +39,11 @@ static gl4PipelineShader *gl4GetProgram(
|
||||
rv<<=2; rv|=pp_ShadInstr;
|
||||
rv<<=1; rv|=pp_Offset;
|
||||
rv<<=2; rv|=pp_FogCtrl;
|
||||
rv <<= 1; rv |= (int)pp_TwoVolumes;
|
||||
rv <<= 1; rv |= (int)pp_Gouraud;
|
||||
rv <<= 1; rv |= pp_TwoVolumes;
|
||||
rv <<= 1; rv |= pp_Gouraud;
|
||||
rv <<= 1; rv |= pp_BumpMap;
|
||||
rv <<= 1; rv |= fog_clamping;
|
||||
rv <<= 1; rv |= palette;
|
||||
rv <<= 2; rv |= (int)pass;
|
||||
|
||||
gl4PipelineShader *shader = &gl4.shaders[rv];
|
||||
@@ -59,6 +61,7 @@ static gl4PipelineShader *gl4GetProgram(
|
||||
shader->pp_Gouraud = pp_Gouraud;
|
||||
shader->pp_BumpMap = pp_BumpMap;
|
||||
shader->fog_clamping = fog_clamping;
|
||||
shader->palette = palette;
|
||||
shader->pass = pass;
|
||||
gl4CompilePipelineShader(shader);
|
||||
}
|
||||
@@ -88,6 +91,7 @@ static void SetGPState(const PolyParam* gp)
|
||||
gl4ShaderUniforms.trilinear_alpha = 1.0;
|
||||
|
||||
s32 clipping = SetTileClip(gp->tileclip, -1);
|
||||
bool palette = false;
|
||||
|
||||
if (pass == Pass::Depth)
|
||||
{
|
||||
@@ -103,13 +107,15 @@ static void SetGPState(const PolyParam* gp)
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
pass);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Two volumes mode only supported for OP and PT
|
||||
bool two_volumes_mode = (gp->tsp1.full != -1) && Type != ListType_Translucent;
|
||||
bool two_volumes_mode = (gp->tsp1.full != -1) && Type != ListType_Translucent;
|
||||
bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff);
|
||||
palette = BaseTextureCacheData::IsGpuHandledPaletted(gp->tsp, gp->tcw);
|
||||
|
||||
CurrentShader = gl4GetProgram(Type == ListType_Punch_Through ? 1 : 0,
|
||||
clipping,
|
||||
@@ -123,11 +129,19 @@ static void SetGPState(const PolyParam* gp)
|
||||
gp->pcw.Gouraud,
|
||||
gp->tcw.PixelFmt == PixelBumpMap,
|
||||
color_clamp,
|
||||
palette,
|
||||
pass);
|
||||
}
|
||||
|
||||
glcache.UseProgram(CurrentShader->program);
|
||||
|
||||
if (palette)
|
||||
{
|
||||
if (gp->tcw.PixelFmt == PixelPal4)
|
||||
gl4ShaderUniforms.palette_index = float(gp->tcw.PalSelect << 4) / 1023.f;
|
||||
else
|
||||
gl4ShaderUniforms.palette_index = float((gp->tcw.PalSelect >> 4) << 8) / 1023.f;
|
||||
}
|
||||
|
||||
gl4ShaderUniforms.tsp0 = gp->tsp;
|
||||
gl4ShaderUniforms.tsp1 = gp->tsp1;
|
||||
gl4ShaderUniforms.tcw0 = gp->tcw;
|
||||
@@ -156,9 +170,9 @@ static void SetGPState(const PolyParam* gp)
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
GLuint texid = (GLuint)(i == 0 ? gp->texid : gp->texid1);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texid == -1 ? 0 : texid);
|
||||
glBindTexture(GL_TEXTURE_2D, texid == (GLuint)-1 ? 0 : texid);
|
||||
|
||||
if (texid != -1)
|
||||
if (texid != (GLuint)-1)
|
||||
{
|
||||
TSP tsp = i == 0 ? gp->tsp : gp->tsp1;
|
||||
TCW tcw = i == 0 ? gp->tcw : gp->tcw1;
|
||||
@@ -294,7 +308,7 @@ void gl4SetupMainVBO()
|
||||
glVertexAttribPointer(VERTEX_UV1_ARRAY, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, u1)); glCheck();
|
||||
}
|
||||
|
||||
void gl4SetupModvolVBO(void)
|
||||
void gl4SetupModvolVBO()
|
||||
{
|
||||
glBindVertexArray(gl4.vbo.modvol_vao);
|
||||
|
||||
@@ -334,7 +348,7 @@ static void DrawModVols(int first, int count)
|
||||
|
||||
int mod_base = -1;
|
||||
|
||||
for (u32 cmv = 0; cmv < count; cmv++)
|
||||
for (int cmv = 0; cmv < count; cmv++)
|
||||
{
|
||||
ModifierVolumeParam& param = params[cmv];
|
||||
|
||||
@@ -450,17 +464,17 @@ void gl4DrawStrips(GLuint output_fbo, int width, int height)
|
||||
// Check if we can skip this pass, in part or completely, in case nothing is drawn (Cosmic Smash)
|
||||
bool skip_op_pt = true;
|
||||
bool skip_tr = true;
|
||||
for (int j = previous_pass.op_count; skip_op_pt && j < current_pass.op_count; j++)
|
||||
for (u32 j = previous_pass.op_count; skip_op_pt && j < current_pass.op_count; j++)
|
||||
{
|
||||
if (pvrrc.global_param_op.head()[j].count > 2)
|
||||
skip_op_pt = false;
|
||||
}
|
||||
for (int j = previous_pass.pt_count; skip_op_pt && j < current_pass.pt_count; j++)
|
||||
for (u32 j = previous_pass.pt_count; skip_op_pt && j < current_pass.pt_count; j++)
|
||||
{
|
||||
if (pvrrc.global_param_pt.head()[j].count > 2)
|
||||
skip_op_pt = false;
|
||||
}
|
||||
for (int j = previous_pass.tr_count; skip_tr && j < current_pass.tr_count; j++)
|
||||
for (u32 j = previous_pass.tr_count; skip_tr && j < current_pass.tr_count; j++)
|
||||
{
|
||||
if (pvrrc.global_param_tr.head()[j].count > 2)
|
||||
skip_tr = false;
|
||||
@@ -664,18 +678,19 @@ static void gl4_draw_quad_texture(GLuint texture, float w, float h)
|
||||
|
||||
gl4ShaderUniforms.trilinear_alpha = 1.0;
|
||||
|
||||
CurrentShader = gl4GetProgram(0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
CurrentShader = gl4GetProgram(false,
|
||||
0,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
0,
|
||||
false,
|
||||
2,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Pass::Color);
|
||||
glcache.UseProgram(CurrentShader->program);
|
||||
gl4ShaderUniforms.Set(CurrentShader);
|
||||
@@ -760,18 +775,19 @@ void gl4DrawVmuTexture(u8 vmu_screen_number)
|
||||
glBindVertexArray(gl4.vbo.main_vao);
|
||||
|
||||
gl4ShaderUniforms.trilinear_alpha = 1.0;
|
||||
CurrentShader = gl4GetProgram(0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
CurrentShader = gl4GetProgram(false,
|
||||
0,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
2,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Pass::Color);
|
||||
glcache.UseProgram(CurrentShader->program);
|
||||
gl4ShaderUniforms.Set(CurrentShader);
|
||||
@@ -871,18 +887,19 @@ void gl4DrawGunCrosshair(u8 port)
|
||||
glBindVertexArray(gl4.vbo.main_vao);
|
||||
|
||||
gl4ShaderUniforms.trilinear_alpha = 1.0;
|
||||
CurrentShader = gl4GetProgram(0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
CurrentShader = gl4GetProgram(false,
|
||||
0,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
2,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Pass::Color);
|
||||
glcache.UseProgram(CurrentShader->program);
|
||||
gl4ShaderUniforms.Set(CurrentShader);
|
||||
|
||||
+82
-56
@@ -25,23 +25,23 @@ static const char* VertexShaderSource = R"(#version 130
|
||||
#endif
|
||||
|
||||
/* Vertex constants*/
|
||||
uniform highp vec4 scale;
|
||||
uniform highp float extra_depth_scale;
|
||||
uniform vec4 scale;
|
||||
uniform float extra_depth_scale;
|
||||
/* Vertex input */
|
||||
in highp vec4 in_pos;
|
||||
in lowp vec4 in_base;
|
||||
in lowp vec4 in_offs;
|
||||
in mediump vec2 in_uv;
|
||||
in lowp vec4 in_base1;
|
||||
in lowp vec4 in_offs1;
|
||||
in mediump vec2 in_uv1;
|
||||
in vec4 in_pos;
|
||||
in vec4 in_base;
|
||||
in vec4 in_offs;
|
||||
in vec2 in_uv;
|
||||
in vec4 in_base1;
|
||||
in vec4 in_offs1;
|
||||
in vec2 in_uv1;
|
||||
/* output */
|
||||
INTERPOLATION out lowp vec4 vtx_base;
|
||||
INTERPOLATION out lowp vec4 vtx_offs;
|
||||
out mediump vec2 vtx_uv;
|
||||
INTERPOLATION out lowp vec4 vtx_base1;
|
||||
INTERPOLATION out lowp vec4 vtx_offs1;
|
||||
out mediump vec2 vtx_uv1;
|
||||
INTERPOLATION out vec4 vtx_base;
|
||||
INTERPOLATION out vec4 vtx_offs;
|
||||
out vec2 vtx_uv;
|
||||
INTERPOLATION out vec4 vtx_base1;
|
||||
INTERPOLATION out vec4 vtx_offs1;
|
||||
out vec2 vtx_uv1;
|
||||
void main()
|
||||
{
|
||||
vtx_base=in_base;
|
||||
@@ -74,6 +74,7 @@ R"(
|
||||
#define pp_Gouraud %d
|
||||
#define pp_BumpMap %d
|
||||
#define FogClamping %d
|
||||
#define pp_Palette %d
|
||||
#define PASS %d
|
||||
#define PI 3.1415926
|
||||
|
||||
@@ -98,19 +99,21 @@ R"(
|
||||
#endif
|
||||
|
||||
/* Shader program params*/
|
||||
uniform lowp float cp_AlphaTestValue;
|
||||
uniform lowp vec4 pp_ClipTest;
|
||||
uniform lowp vec3 sp_FOG_COL_RAM,sp_FOG_COL_VERT;
|
||||
uniform highp float sp_FOG_DENSITY;
|
||||
uniform highp float shade_scale_factor;
|
||||
uniform float cp_AlphaTestValue;
|
||||
uniform vec4 pp_ClipTest;
|
||||
uniform vec3 sp_FOG_COL_RAM,sp_FOG_COL_VERT;
|
||||
uniform float sp_FOG_DENSITY;
|
||||
uniform float shade_scale_factor;
|
||||
uniform sampler2D tex0, tex1;
|
||||
layout(binding = 5) uniform sampler2D fog_table;
|
||||
uniform int pp_Number;
|
||||
uniform usampler2D shadow_stencil;
|
||||
uniform sampler2D DepthTex;
|
||||
uniform lowp float trilinear_alpha;
|
||||
uniform lowp vec4 fog_clamp_min;
|
||||
uniform lowp vec4 fog_clamp_max;
|
||||
uniform float trilinear_alpha;
|
||||
uniform vec4 fog_clamp_min;
|
||||
uniform vec4 fog_clamp_max;
|
||||
uniform sampler2D palette;
|
||||
uniform float palette_index;
|
||||
|
||||
uniform ivec2 blend_mode[2];
|
||||
#if pp_TwoVolumes == 1
|
||||
@@ -121,24 +124,24 @@ uniform int fog_control[2];
|
||||
#endif
|
||||
|
||||
/* Vertex input*/
|
||||
INTERPOLATION in lowp vec4 vtx_base;
|
||||
INTERPOLATION in lowp vec4 vtx_offs;
|
||||
in mediump vec2 vtx_uv;
|
||||
INTERPOLATION in lowp vec4 vtx_base1;
|
||||
INTERPOLATION in lowp vec4 vtx_offs1;
|
||||
in mediump vec2 vtx_uv1;
|
||||
INTERPOLATION in vec4 vtx_base;
|
||||
INTERPOLATION in vec4 vtx_offs;
|
||||
in vec2 vtx_uv;
|
||||
INTERPOLATION in vec4 vtx_base1;
|
||||
INTERPOLATION in vec4 vtx_offs1;
|
||||
in vec2 vtx_uv1;
|
||||
|
||||
lowp float fog_mode2(highp float w)
|
||||
float fog_mode2(float w)
|
||||
{
|
||||
highp float z = clamp(w * sp_FOG_DENSITY, 1.0, 255.9999);
|
||||
uint i = uint(floor(log2(z)));
|
||||
highp float m = z * 16 / pow(2, i) - 16;
|
||||
float idx = floor(m) + i * 16 + 0.5;
|
||||
vec4 fog_coef = texture(fog_table, vec2(idx / 128, 0.75 - (m - floor(m)) / 2));
|
||||
return fog_coef.r;
|
||||
float z = clamp(w * sp_FOG_DENSITY, 1.0, 255.9999);
|
||||
float exp = floor(log2(z));
|
||||
float m = z * 16.0 / pow(2.0, exp) - 16.0;
|
||||
float idx = floor(m) + exp * 16.0 + 0.5;
|
||||
vec4 fog_coef = texture(fog_table, vec2(idx / 128.0, 0.75 - (m - floor(m)) / 2.0));
|
||||
return fog_coef.r;
|
||||
}
|
||||
|
||||
highp vec4 fog_clamp(highp vec4 col)
|
||||
vec4 fog_clamp(vec4 col)
|
||||
{
|
||||
#if FogClamping == 1
|
||||
return clamp(col, fog_clamp_min, fog_clamp_max);
|
||||
@@ -147,13 +150,23 @@ highp vec4 fog_clamp(highp vec4 col)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if pp_Palette == 1
|
||||
|
||||
vec4 palettePixel(sampler2D tex, vec2 coords)
|
||||
{
|
||||
vec4 c = vec4(texture(tex, coords).r * 255.0 / 1023.0 + palette_index, 0.5, 0.0, 0.0);
|
||||
return texture(palette, c.xy);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
setFragDepth();
|
||||
|
||||
#if PASS == PASS_OIT
|
||||
// Manual depth testing
|
||||
highp float frontDepth = texture(DepthTex, gl_FragCoord.xy / textureSize(DepthTex, 0)).r;
|
||||
float frontDepth = texture(DepthTex, gl_FragCoord.xy / textureSize(DepthTex, 0)).r;
|
||||
if (gl_FragDepth < frontDepth)
|
||||
discard;
|
||||
#endif
|
||||
@@ -171,9 +184,9 @@ void main()
|
||||
discard;
|
||||
#endif
|
||||
|
||||
highp vec4 color = vtx_base;
|
||||
lowp vec4 offset = vtx_offs;
|
||||
mediump vec2 uv = vtx_uv;
|
||||
vec4 color = vtx_base;
|
||||
vec4 offset = vtx_offs;
|
||||
vec2 uv = vtx_uv;
|
||||
bool area1 = false;
|
||||
ivec2 cur_blend_mode = blend_mode[0];
|
||||
|
||||
@@ -208,11 +221,19 @@ void main()
|
||||
#endif
|
||||
#if pp_Texture==1
|
||||
{
|
||||
highp vec4 texcol;
|
||||
if (area1)
|
||||
texcol = texture(tex1, uv);
|
||||
else
|
||||
texcol = texture(tex0, uv);
|
||||
vec4 texcol;
|
||||
#if pp_Palette == 0
|
||||
if (area1)
|
||||
texcol = texture(tex1, uv);
|
||||
else
|
||||
texcol = texture(tex0, uv);
|
||||
#else
|
||||
if (area1)
|
||||
texcol = palettePixel(tex1, uv);
|
||||
else
|
||||
texcol = palettePixel(tex0, uv);
|
||||
#endif
|
||||
|
||||
#if pp_BumpMap == 1
|
||||
float s = PI / 2.0 * (texcol.a * 15.0 * 16.0 + texcol.r * 15.0) / 255.0;
|
||||
float r = 2.0 * PI * (texcol.g * 15.0 * 16.0 + texcol.b * 15.0) / 255.0;
|
||||
@@ -383,8 +404,10 @@ bool gl4CompilePipelineShader(gl4PipelineShader *s, const char *pixel_source /*
|
||||
char pshader[16384];
|
||||
|
||||
sprintf(pshader, pixel_source,
|
||||
s->cp_AlphaTest,s->pp_ClipTestMode,s->pp_UseAlpha,
|
||||
s->pp_Texture,s->pp_IgnoreTexA,s->pp_ShadInstr,s->pp_Offset,s->pp_FogCtrl, s->pp_TwoVolumes, s->pp_Gouraud, s->pp_BumpMap, s->fog_clamping, (int)s->pass);
|
||||
s->cp_AlphaTest, s->pp_ClipTestMode, s->pp_UseAlpha,
|
||||
s->pp_Texture, s->pp_IgnoreTexA, s->pp_ShadInstr, s->pp_Offset, s->pp_FogCtrl,
|
||||
s->pp_TwoVolumes, s->pp_Gouraud, s->pp_BumpMap, s->fog_clamping, s->palette,
|
||||
(int)s->pass);
|
||||
|
||||
|
||||
s->program = gl_CompileAndLink(vshader, pshader);
|
||||
@@ -457,6 +480,11 @@ bool gl4CompilePipelineShader(gl4PipelineShader *s, const char *pixel_source /*
|
||||
s->shading_instr = glGetUniformLocation(s->program, "shading_instr");
|
||||
s->fog_control = glGetUniformLocation(s->program, "fog_control");
|
||||
|
||||
gu = glGetUniformLocation(s->program, "palette");
|
||||
if (gu != -1)
|
||||
glUniform1i(gu, 6); // GL_TEXTURE6
|
||||
s->palette_index = glGetUniformLocation(s->program, "palette_index");
|
||||
|
||||
return glIsProgram(s->program)==GL_TRUE;
|
||||
}
|
||||
|
||||
@@ -553,7 +581,7 @@ static void resize(int w, int h)
|
||||
}
|
||||
}
|
||||
|
||||
static bool RenderFrame(void)
|
||||
static bool RenderFrame()
|
||||
{
|
||||
int vmu_screen_number = 0 ;
|
||||
int lightgun_port = 0 ;
|
||||
@@ -683,6 +711,11 @@ static bool RenderFrame(void)
|
||||
fog_needs_update=false;
|
||||
UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE5, GL_RED);
|
||||
}
|
||||
if (palette_updated)
|
||||
{
|
||||
UpdatePaletteTexture(GL_TEXTURE6);
|
||||
palette_updated = false;
|
||||
}
|
||||
|
||||
glcache.UseProgram(gl4.modvol_shader.program);
|
||||
|
||||
@@ -768,13 +801,6 @@ static bool RenderFrame(void)
|
||||
//not all scaling affects pixel operations, scale to adjust for that
|
||||
scale_x *= scissoring_scale_x;
|
||||
|
||||
#if 0
|
||||
//handy to debug really stupid render-not-working issues ...
|
||||
DEBUG_LOG(RENDERER, "SS: %dx%d", screen_width, screen_height);
|
||||
DEBUG_LOG(RENDERER, "SCI: %d, %f", pvrrc.fb_X_CLIP.max, dc2s_scale_h);
|
||||
DEBUG_LOG(RENDERER, "SCI: %f, %f, %f, %f", offs_x+pvrrc.fb_X_CLIP.min/scale_x,(pvrrc.fb_Y_CLIP.min/scale_y)*dc2s_scale_h,(pvrrc.fb_X_CLIP.max-pvrrc.fb_X_CLIP.min+1)/scale_x*dc2s_scale_h,(pvrrc.fb_Y_CLIP.max-pvrrc.fb_Y_CLIP.min+1)/scale_y*dc2s_scale_h);
|
||||
#endif
|
||||
|
||||
bool wide_screen_on = !is_rtt && settings.rend.WideScreen
|
||||
&& pvrrc.fb_X_CLIP.min == 0
|
||||
&& lroundf((pvrrc.fb_X_CLIP.max + 1) / scale_x) == 640L
|
||||
|
||||
@@ -13,10 +13,10 @@ GLuint gl4BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt)
|
||||
gl.rtt.TexAddr=addy>>3;
|
||||
|
||||
// Find the smallest power of two texture that fits the viewport
|
||||
int fbh2 = 8;
|
||||
u32 fbh2 = 8;
|
||||
while (fbh2 < fbh)
|
||||
fbh2 *= 2;
|
||||
int fbw2 = 8;
|
||||
u32 fbw2 = 8;
|
||||
while (fbw2 < fbw)
|
||||
fbw2 *= 2;
|
||||
|
||||
@@ -28,20 +28,20 @@ GLuint gl4BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt)
|
||||
fbh2 *= settings.rend.RenderToTextureUpscale;
|
||||
}
|
||||
|
||||
/* Create a texture for rendering to */
|
||||
// Create a texture for rendering to
|
||||
gl.rtt.tex = glcache.GenTexture();
|
||||
glcache.BindTexture(GL_TEXTURE_2D, gl.rtt.tex);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, channels, fbw2, fbh2, 0, channels, fmt, 0);
|
||||
|
||||
/* Create the object that will allow us to render to the aforementioned texture */
|
||||
// Create the object that will allow us to render to the aforementioned texture
|
||||
glGenFramebuffers(1, &gl.rtt.fbo);
|
||||
glBindFramebuffer(RARCH_GL_FRAMEBUFFER, gl.rtt.fbo);
|
||||
|
||||
/* Attach the texture to the FBO */
|
||||
// Attach the texture to the FBO
|
||||
glFramebufferTexture2D(RARCH_GL_FRAMEBUFFER, RARCH_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl.rtt.tex, 0);
|
||||
|
||||
/* Check that our FBO creation was successful */
|
||||
// Check that our FBO creation was successful
|
||||
GLuint uStatus = glCheckFramebufferStatus(RARCH_GL_FRAMEBUFFER);
|
||||
|
||||
verify(uStatus == RARCH_GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
@@ -171,6 +171,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
|
||||
{
|
||||
if (x != _scissor.x || y != _scissor.y || width != _scissor.width || height != _scissor.height || _disable_cache)
|
||||
{
|
||||
_scissor.x = x;
|
||||
_scissor.y = y;
|
||||
_scissor.width = width;
|
||||
_scissor.height = height;
|
||||
glScissor(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void TexParameteri(GLenum target, GLenum pname, GLint param)
|
||||
{
|
||||
if (target == GL_TEXTURE_2D && !_disable_cache)
|
||||
@@ -178,22 +190,22 @@ public:
|
||||
TextureParameters &cur_params = _texture_params[_texture];
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
if (cur_params._min_filter == param)
|
||||
if (cur_params._min_filter == (GLenum)param)
|
||||
return;
|
||||
cur_params._min_filter = param;
|
||||
break;
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
if (cur_params._mag_filter == param)
|
||||
if (cur_params._mag_filter == (GLenum)param)
|
||||
return;
|
||||
cur_params._mag_filter = param;
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
if (cur_params._wrap_s == param)
|
||||
if (cur_params._wrap_s == (GLenum)param)
|
||||
return;
|
||||
cur_params._wrap_s = param;
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
if (cur_params._wrap_t == param)
|
||||
if (cur_params._wrap_t == (GLenum)param)
|
||||
return;
|
||||
cur_params._wrap_t = param;
|
||||
break;
|
||||
@@ -209,7 +221,7 @@ public:
|
||||
}
|
||||
return _texture_ids[--_texture_cache_size];
|
||||
}
|
||||
|
||||
|
||||
void Reset() {
|
||||
_texture = 0xFFFFFFFFu;
|
||||
_texture_params.clear();
|
||||
@@ -236,6 +248,10 @@ public:
|
||||
_stencil_dpfail = 0xFFFFFFFFu;
|
||||
_stencil_dppass = 0xFFFFFFFFu;
|
||||
_stencil_mask = 0;
|
||||
_scissor.x = -1;
|
||||
_scissor.y = -1;
|
||||
_scissor.width = -1;
|
||||
_scissor.height = -1;
|
||||
if (_texture_cache_size > 0)
|
||||
{
|
||||
glDeleteTextures(_texture_cache_size, _texture_ids);
|
||||
@@ -289,6 +305,12 @@ private:
|
||||
GLenum _stencil_dpfail;
|
||||
GLenum _stencil_dppass;
|
||||
GLuint _stencil_mask;
|
||||
struct {
|
||||
GLint x;
|
||||
GLint y;
|
||||
GLsizei width;
|
||||
GLsizei height;
|
||||
} _scissor;
|
||||
GLuint _texture_ids[TEXTURE_ID_CACHE_SIZE];
|
||||
GLuint _texture_cache_size;
|
||||
std::map<GLuint, TextureParameters> _texture_params;
|
||||
|
||||
+25
-15
@@ -32,8 +32,8 @@ const u32 Zfunction[] =
|
||||
/*
|
||||
0 Zero (0, 0, 0, 0)
|
||||
1 One (1, 1, 1, 1)
|
||||
2 Dither Color (OR, OG, OB, OA)
|
||||
3 Inverse Dither Color (1-OR, 1-OG, 1-OB, 1-OA)
|
||||
2 Other Color (OR, OG, OB, OA)
|
||||
3 Inverse Other Color (1-OR, 1-OG, 1-OB, 1-OA)
|
||||
4 SRC Alpha (SA, SA, SA, SA)
|
||||
5 Inverse SRC Alpha (1-SA, 1-SA, 1-SA, 1-SA)
|
||||
6 DST Alpha (DA, DA, DA, DA)
|
||||
@@ -159,6 +159,7 @@ __forceinline static void SetGPState(const PolyParam* gp,u32 cflip=0)
|
||||
ShaderUniforms.trilinear_alpha = 1.f;
|
||||
|
||||
bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff);
|
||||
bool palette = BaseTextureCacheData::IsGpuHandledPaletted(gp->tsp, gp->tcw);
|
||||
|
||||
CurrentShader = GetProgram(Type == ListType_Punch_Through ? 1 : 0,
|
||||
SetTileClip(gp->tileclip, -1) + 1,
|
||||
@@ -171,11 +172,20 @@ __forceinline static void SetGPState(const PolyParam* gp,u32 cflip=0)
|
||||
gp->pcw.Gouraud,
|
||||
gp->tcw.PixelFmt == PixelBumpMap,
|
||||
color_clamp,
|
||||
ShaderUniforms.trilinear_alpha != 1.f);
|
||||
ShaderUniforms.trilinear_alpha != 1.f,
|
||||
palette);
|
||||
|
||||
glcache.UseProgram(CurrentShader->program);
|
||||
if (CurrentShader->trilinear_alpha != -1)
|
||||
glUniform1f(CurrentShader->trilinear_alpha, ShaderUniforms.trilinear_alpha);
|
||||
if (palette)
|
||||
{
|
||||
if (gp->tcw.PixelFmt == PixelPal4)
|
||||
ShaderUniforms.palette_index = float(gp->tcw.PalSelect << 4) / 1023.f;
|
||||
else
|
||||
ShaderUniforms.palette_index = float((gp->tcw.PalSelect >> 4) << 8) / 1023.f;
|
||||
glUniform1f(CurrentShader->palette_index, ShaderUniforms.palette_index);
|
||||
}
|
||||
SetTileClip(gp->tileclip, CurrentShader->pp_ClipTest);
|
||||
|
||||
// This bit controls which pixels are affected
|
||||
@@ -183,12 +193,12 @@ __forceinline static void SetGPState(const PolyParam* gp,u32 cflip=0)
|
||||
const u32 stencil = (gp->pcw.Shadow!=0)?0x80:0;
|
||||
glcache.StencilFunc(GL_ALWAYS, stencil, stencil);
|
||||
|
||||
glcache.BindTexture(GL_TEXTURE_2D, gp->texid == -1 ? 0 : (GLuint)gp->texid);
|
||||
glcache.BindTexture(GL_TEXTURE_2D, gp->texid == (u64)-1 ? 0 : (GLuint)gp->texid);
|
||||
SetTextureRepeatMode(GL_TEXTURE_WRAP_S, gp->tsp.ClampU, gp->tsp.FlipU);
|
||||
SetTextureRepeatMode(GL_TEXTURE_WRAP_T, gp->tsp.ClampV, gp->tsp.FlipV);
|
||||
|
||||
//set texture filter mode
|
||||
if (gp->tsp.FilterMode == 0)
|
||||
if (gp->tsp.FilterMode == 0 || palette)
|
||||
{
|
||||
//disable filtering, mipmaps
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
@@ -234,7 +244,7 @@ __forceinline static void SetGPState(const PolyParam* gp,u32 cflip=0)
|
||||
//gcflip is global clip flip, needed for when rendering to texture due to mirrored Y direction
|
||||
SetCull(gp->isp.CullMode ^ cflip ^ gcflip);
|
||||
|
||||
/* Set Z mode, only if required */
|
||||
//set Z mode, only if required
|
||||
if (Type == ListType_Punch_Through || (Type == ListType_Translucent && SortingEnabled))
|
||||
{
|
||||
glcache.DepthFunc(GL_GEQUAL);
|
||||
@@ -284,11 +294,11 @@ static void DrawList(const List<PolyParam>& gply, int first, int count)
|
||||
}
|
||||
}
|
||||
|
||||
static vector<SortTrigDrawParam> pidx_sort;
|
||||
static std::vector<SortTrigDrawParam> pidx_sort;
|
||||
|
||||
static void SortTriangles(int first, int count)
|
||||
{
|
||||
vector<u32> vidx_sort;
|
||||
std::vector<u32> vidx_sort;
|
||||
GenSorted(first, count, pidx_sort, vidx_sort);
|
||||
|
||||
//Upload to GPU if needed
|
||||
@@ -303,7 +313,7 @@ static void SortTriangles(int first, int count)
|
||||
if (short_vidx.daty != NULL)
|
||||
short_vidx.Free();
|
||||
short_vidx.Init(vidx_sort.size(), &overrun, NULL);
|
||||
for (int i = 0; i < vidx_sort.size(); i++)
|
||||
for (u32 i = 0; i < vidx_sort.size(); i++)
|
||||
*(short_vidx.Append()) = vidx_sort[i];
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, short_vidx.bytes(), short_vidx.head(), GL_STREAM_DRAW);
|
||||
}
|
||||
@@ -532,7 +542,7 @@ static void DrawModVols(int first, int count)
|
||||
|
||||
int mod_base = -1;
|
||||
|
||||
for (u32 cmv = 0; cmv < count; cmv++)
|
||||
for (int cmv = 0; cmv < count; cmv++)
|
||||
{
|
||||
ModifierVolumeParam& param = params[cmv];
|
||||
|
||||
@@ -571,7 +581,7 @@ static void DrawModVols(int first, int count)
|
||||
glcache.StencilFunc(GL_EQUAL, 0x81, 0x81); //only pixels that are Modvol enabled, and in area 1
|
||||
|
||||
//clear the stencil result bit
|
||||
glcache.StencilMask(0x3); /* write to LSB */
|
||||
glcache.StencilMask(0x3); //write to lsb
|
||||
glcache.StencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
|
||||
|
||||
//don't do depth testing
|
||||
@@ -584,7 +594,7 @@ static void DrawModVols(int first, int count)
|
||||
glcache.Enable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void DrawStrips(void)
|
||||
void DrawStrips()
|
||||
{
|
||||
SetupMainVBO();
|
||||
//Draw the strips !
|
||||
@@ -661,7 +671,7 @@ void DrawFramebuffer(float w, float h)
|
||||
|
||||
ShaderUniforms.trilinear_alpha = 1.0;
|
||||
|
||||
PipelineShader *shader = GetProgram(0, 1, 1, 0, 1, 0, 0, 2, false, false, false, false);
|
||||
PipelineShader *shader = GetProgram(0, 1, 1, 0, 1, 0, 0, 2, false, false, false, false, false);
|
||||
glcache.UseProgram(shader->program);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
@@ -787,7 +797,7 @@ void DrawVmuTexture(u8 vmu_screen_number)
|
||||
glcache.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
SetupMainVBO();
|
||||
PipelineShader *shader = GetProgram(0, 1, 1, 1, 0, 0, 0, 2, false, false, false, false);
|
||||
PipelineShader *shader = GetProgram(0, 1, 1, 1, 0, 0, 0, 2, false, false, false, false, false);
|
||||
glcache.UseProgram(shader->program);
|
||||
|
||||
{
|
||||
@@ -881,7 +891,7 @@ void DrawGunCrosshair(u8 port)
|
||||
glcache.BlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
|
||||
SetupMainVBO();
|
||||
PipelineShader *shader = GetProgram(0, 1, 1, 1, 0, 0, 0, 2, false, false, false, false);
|
||||
PipelineShader *shader = GetProgram(0, 1, 1, 1, 0, 0, 0, 2, false, false, false, false, false);
|
||||
glcache.UseProgram(shader->program);
|
||||
|
||||
{
|
||||
|
||||
+70
-20
@@ -119,6 +119,8 @@ R"(%s
|
||||
#define pp_BumpMap %d
|
||||
#define FogClamping %d
|
||||
#define pp_TriLinear %d
|
||||
#define pp_Palette %d
|
||||
|
||||
#define PI 3.1415926
|
||||
|
||||
#define GLES2 0
|
||||
@@ -165,6 +167,9 @@ uniform sampler2D tex,fog_table;
|
||||
uniform lowp float trilinear_alpha;
|
||||
uniform lowp vec4 fog_clamp_min;
|
||||
uniform lowp vec4 fog_clamp_max;
|
||||
uniform sampler2D palette;
|
||||
uniform mediump float palette_index;
|
||||
|
||||
/* Vertex input*/
|
||||
INTERPOLATION in lowp vec4 vtx_base;
|
||||
INTERPOLATION in lowp vec4 vtx_offs;
|
||||
@@ -196,6 +201,16 @@ highp vec4 fog_clamp(highp vec4 col)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if pp_Palette == 1
|
||||
|
||||
lowp vec4 palettePixel(highp vec2 coords)
|
||||
{
|
||||
highp vec4 c = vec4(texture(tex, coords).FOG_CHANNEL * 255.0 / 1023.0 + palette_index, 0.5, 0.0, 0.0);
|
||||
return texture(palette, c.xy);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
// Clip outside the box
|
||||
@@ -220,7 +235,11 @@ void main()
|
||||
#endif
|
||||
#if pp_Texture==1
|
||||
{
|
||||
lowp vec4 texcol=texture(tex, vtx_uv);
|
||||
#if pp_Palette == 0
|
||||
lowp vec4 texcol = texture(tex, vtx_uv);
|
||||
#else
|
||||
lowp vec4 texcol = palettePixel(vtx_uv);
|
||||
#endif
|
||||
|
||||
#if pp_BumpMap == 1
|
||||
highp float s = PI / 2.0 * (texcol.a * 15.0 * 16.0 + texcol.r * 15.0) / 255.0;
|
||||
@@ -331,6 +350,7 @@ void main()
|
||||
int screen_width = 640;
|
||||
int screen_height = 480;
|
||||
GLuint fogTextureId;
|
||||
GLuint paletteTextureId;
|
||||
|
||||
PipelineShader *GetProgram(
|
||||
u32 cp_AlphaTest,
|
||||
@@ -344,7 +364,8 @@ PipelineShader *GetProgram(
|
||||
bool pp_Gouraud,
|
||||
bool pp_BumpMap,
|
||||
bool fog_clamping,
|
||||
bool trilinear)
|
||||
bool trilinear,
|
||||
bool palette)
|
||||
{
|
||||
u32 rv=0;
|
||||
|
||||
@@ -360,6 +381,7 @@ PipelineShader *GetProgram(
|
||||
rv<<=1; rv|=pp_BumpMap;
|
||||
rv<<=1; rv|=fog_clamping;
|
||||
rv<<=1; rv|=trilinear;
|
||||
rv<<=1; rv|=palette;
|
||||
|
||||
PipelineShader *shader = &gl.shaders[rv];
|
||||
if (shader->program == 0)
|
||||
@@ -376,6 +398,7 @@ PipelineShader *GetProgram(
|
||||
shader->pp_BumpMap = pp_BumpMap;
|
||||
shader->fog_clamping = fog_clamping;
|
||||
shader->trilinear = trilinear;
|
||||
shader->palette = palette;
|
||||
CompilePipelineShader(shader);
|
||||
}
|
||||
#ifdef RPI4_SET_UNIFORM_ATTRIBUTES_BUG
|
||||
@@ -426,7 +449,7 @@ void findGLVersion()
|
||||
gl.glsl_version_header = "";
|
||||
gl.index_type = GL_UNSIGNED_SHORT;
|
||||
}
|
||||
gl.fog_image_format = GL_ALPHA;
|
||||
gl.single_channel_format = GL_ALPHA;
|
||||
|
||||
GLint stencilBits = 0;
|
||||
glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
|
||||
@@ -440,13 +463,13 @@ void findGLVersion()
|
||||
{
|
||||
gl.gl_version = "GL3";
|
||||
gl.glsl_version_header = "#version 130";
|
||||
gl.fog_image_format = GL_RED;
|
||||
gl.single_channel_format = GL_RED;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.gl_version = "GL2";
|
||||
gl.glsl_version_header = "#version 120";
|
||||
gl.fog_image_format = GL_ALPHA;
|
||||
gl.single_channel_format = GL_ALPHA;
|
||||
}
|
||||
}
|
||||
gl.max_anisotropy = 1.f;
|
||||
@@ -564,13 +587,14 @@ bool CompilePipelineShader(PipelineShader *s)
|
||||
|
||||
sprintf(pshader,PixelPipelineShader, gl.glsl_version_header, gl.gl_version,
|
||||
s->cp_AlphaTest,s->pp_ClipTestMode,s->pp_UseAlpha,
|
||||
s->pp_Texture,s->pp_IgnoreTexA,s->pp_ShadInstr,s->pp_Offset,s->pp_FogCtrl, s->pp_Gouraud, s->pp_BumpMap, s->fog_clamping, s->trilinear);
|
||||
s->pp_Texture,s->pp_IgnoreTexA,s->pp_ShadInstr,s->pp_Offset,s->pp_FogCtrl, s->pp_Gouraud, s->pp_BumpMap,
|
||||
s->fog_clamping, s->trilinear, s->palette);
|
||||
|
||||
s->program = gl_CompileAndLink(vshader, pshader);
|
||||
|
||||
|
||||
//setup texture 0 as the input for the shader
|
||||
GLuint gu=glGetUniformLocation(s->program, "tex");
|
||||
GLint gu = glGetUniformLocation(s->program, "tex");
|
||||
if (s->pp_Texture==1)
|
||||
glUniform1i(gu,0);
|
||||
|
||||
@@ -603,6 +627,12 @@ bool CompilePipelineShader(PipelineShader *s)
|
||||
gu = glGetUniformLocation(s->program, "fog_table");
|
||||
if (gu != -1)
|
||||
glUniform1i(gu, 1);
|
||||
// And texture 2 as palette
|
||||
gu = glGetUniformLocation(s->program, "palette");
|
||||
if (gu != -1)
|
||||
glUniform1i(gu, 2);
|
||||
s->palette_index = glGetUniformLocation(s->program, "palette_index");
|
||||
|
||||
s->trilinear_alpha = glGetUniformLocation(s->program, "trilinear_alpha");
|
||||
|
||||
if (s->fog_clamping)
|
||||
@@ -698,11 +728,11 @@ static bool gl_create_resources(void)
|
||||
char fshader[8192];
|
||||
sprintf(fshader, ModifierVolumeShader, gl.glsl_version_header, gl.gl_version);
|
||||
|
||||
gl.modvol_shader.program=gl_CompileAndLink(vshader, fshader);
|
||||
gl.modvol_shader.scale = glGetUniformLocation(gl.modvol_shader.program, "scale");
|
||||
gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale");
|
||||
gl.modvol_shader.program = gl_CompileAndLink(vshader, fshader);
|
||||
gl.modvol_shader.scale = glGetUniformLocation(gl.modvol_shader.program, "scale");
|
||||
gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale");
|
||||
gl.modvol_shader.extra_depth_scale = glGetUniformLocation(gl.modvol_shader.program, "extra_depth_scale");
|
||||
gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor");
|
||||
gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -725,12 +755,34 @@ void UpdateFogTexture(u8 *fog_table, GLenum texture_slot, GLint fog_image_format
|
||||
u8 temp_tex_buffer[256];
|
||||
MakeFogTexture(temp_tex_buffer);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, fog_image_format, 128, 2, 0, fog_image_format, GL_UNSIGNED_BYTE, temp_tex_buffer);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void UpdatePaletteTexture(GLenum texture_slot)
|
||||
{
|
||||
glActiveTexture(texture_slot);
|
||||
if (paletteTextureId == 0)
|
||||
{
|
||||
paletteTextureId = glcache.GenTexture();
|
||||
glcache.BindTexture(GL_TEXTURE_2D, paletteTextureId);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
else
|
||||
glcache.BindTexture(GL_TEXTURE_2D, paletteTextureId);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, palette32_ram);
|
||||
glCheck();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void DrawVmuTexture(u8 vmu_screen_number);
|
||||
void DrawGunCrosshair(u8 port);
|
||||
|
||||
@@ -892,7 +944,12 @@ static bool RenderFrame(void)
|
||||
if (fog_needs_update)
|
||||
{
|
||||
fog_needs_update=false;
|
||||
UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE1, gl.fog_image_format);
|
||||
UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE1, gl.single_channel_format);
|
||||
}
|
||||
if (palette_updated)
|
||||
{
|
||||
UpdatePaletteTexture(GL_TEXTURE2);
|
||||
palette_updated = false;
|
||||
}
|
||||
|
||||
glcache.UseProgram(gl.modvol_shader.program);
|
||||
@@ -993,13 +1050,6 @@ static bool RenderFrame(void)
|
||||
//not all scaling affects pixel operations, scale to adjust for that
|
||||
scale_x *= scissoring_scale_x;
|
||||
|
||||
#if 0
|
||||
//handy to debug really stupid render-not-working issues ...
|
||||
DEBUG_LOG(RENDERER, "SS: %dx%d", screen_width, screen_height);
|
||||
DEBUG_LOG(RENDERER, "SCI: %d, %f", pvrrc.fb_X_CLIP.max, dc2s_scale_h);
|
||||
DEBUG_LOG(RENDERER, "SCI: %f, %f, %f, %f", offs_x+pvrrc.fb_X_CLIP.min/scale_x,(pvrrc.fb_Y_CLIP.min/scale_y)*dc2s_scale_h,(pvrrc.fb_X_CLIP.max-pvrrc.fb_X_CLIP.min+1)/scale_x*dc2s_scale_h,(pvrrc.fb_Y_CLIP.max-pvrrc.fb_Y_CLIP.min+1)/scale_y*dc2s_scale_h);
|
||||
#endif
|
||||
|
||||
if (!wide_screen_on)
|
||||
{
|
||||
float width = (pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1) / scale_x;
|
||||
|
||||
+36
-16
@@ -41,19 +41,32 @@ void DrawStrips(void);
|
||||
|
||||
struct PipelineShader
|
||||
{
|
||||
GLuint program;
|
||||
GLuint scale,depth_scale;
|
||||
GLuint extra_depth_scale;
|
||||
GLuint pp_ClipTest,cp_AlphaTestValue;
|
||||
GLuint sp_FOG_COL_RAM,sp_FOG_COL_VERT,sp_FOG_DENSITY;
|
||||
GLuint trilinear_alpha;
|
||||
GLuint fog_clamp_min, fog_clamp_max;
|
||||
GLuint program;
|
||||
GLint scale,depth_scale;
|
||||
GLint extra_depth_scale;
|
||||
GLint pp_ClipTest;
|
||||
GLint cp_AlphaTestValue;
|
||||
GLint sp_FOG_COL_RAM;
|
||||
GLint sp_FOG_COL_VERT;
|
||||
GLint sp_FOG_DENSITY;
|
||||
GLint trilinear_alpha;
|
||||
GLint fog_clamp_min, fog_clamp_max;
|
||||
GLint palette_index;
|
||||
|
||||
//
|
||||
u32 cp_AlphaTest; s32 pp_ClipTestMode;
|
||||
u32 pp_Texture, pp_UseAlpha, pp_IgnoreTexA, pp_ShadInstr, pp_Offset, pp_FogCtrl;
|
||||
bool pp_Gouraud, pp_BumpMap;
|
||||
bool cp_AlphaTest;
|
||||
s32 pp_ClipTestMode;
|
||||
bool pp_Texture;
|
||||
bool pp_UseAlpha;
|
||||
bool pp_IgnoreTexA;
|
||||
u32 pp_ShadInstr;
|
||||
bool pp_Offset;
|
||||
u32 pp_FogCtrl;
|
||||
bool pp_Gouraud;
|
||||
bool pp_BumpMap;
|
||||
bool fog_clamping;
|
||||
bool trilinear;
|
||||
bool palette;
|
||||
};
|
||||
|
||||
|
||||
@@ -64,9 +77,9 @@ struct gl_ctx
|
||||
{
|
||||
GLuint program;
|
||||
|
||||
GLuint scale,depth_scale;
|
||||
GLuint extra_depth_scale;
|
||||
GLuint sp_ShaderColor;
|
||||
GLint scale,depth_scale;
|
||||
GLint extra_depth_scale;
|
||||
GLint sp_ShaderColor;
|
||||
|
||||
} modvol_shader;
|
||||
|
||||
@@ -90,7 +103,7 @@ struct gl_ctx
|
||||
int gl_major;
|
||||
int gl_minor;
|
||||
bool is_gles;
|
||||
GLuint fog_image_format;
|
||||
GLuint single_channel_format;
|
||||
GLenum index_type;
|
||||
bool stencil_present;
|
||||
f32 max_anisotropy;
|
||||
@@ -114,6 +127,7 @@ enum ModifierVolumeMode { Xor, Or, Inclusion, Exclusion, ModeCount };
|
||||
|
||||
bool ProcessFrame(TA_context* ctx);
|
||||
void UpdateFogTexture(u8 *fog_table, GLenum texture_slot, GLint fog_image_format);
|
||||
void UpdatePaletteTexture(GLenum texture_slot);
|
||||
text_info raw_GetTexture(TSP tsp, TCW tcw);
|
||||
void DoCleanup();
|
||||
void SortPParams(int first, int count);
|
||||
@@ -128,7 +142,8 @@ void DrawFramebuffer(float w, float h);
|
||||
|
||||
PipelineShader *GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
||||
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
|
||||
u32 pp_FogCtrl, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, bool trilinear);
|
||||
u32 pp_FogCtrl, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, bool trilinear,
|
||||
bool palette);
|
||||
void vertex_buffer_unmap(void);
|
||||
|
||||
void findGLVersion();
|
||||
@@ -154,6 +169,7 @@ extern struct ShaderUniforms_t
|
||||
float trilinear_alpha;
|
||||
float fog_clamp_min[4];
|
||||
float fog_clamp_max[4];
|
||||
float palette_index;
|
||||
|
||||
void Set(const PipelineShader* s)
|
||||
{
|
||||
@@ -182,12 +198,16 @@ extern struct ShaderUniforms_t
|
||||
glUniform4fv(s->fog_clamp_min, 1, fog_clamp_min);
|
||||
if (s->fog_clamp_max != -1)
|
||||
glUniform4fv(s->fog_clamp_max, 1, fog_clamp_max);
|
||||
|
||||
if (s->palette_index != -1)
|
||||
glUniform1f(s->palette_index, palette_index);
|
||||
}
|
||||
|
||||
} ShaderUniforms;
|
||||
|
||||
struct TextureCacheData : BaseTextureCacheData
|
||||
class TextureCacheData : public BaseTextureCacheData
|
||||
{
|
||||
public:
|
||||
GLuint texID; //gl texture
|
||||
u16* pData;
|
||||
virtual std::string GetId() override { return std::to_string(texID); }
|
||||
|
||||
+24
-19
@@ -52,8 +52,9 @@ void TextureCacheData::UploadToGPU(int width, int height, u8 *temp_tex_buffer, b
|
||||
{
|
||||
//upload to OpenGL !
|
||||
glcache.BindTexture(GL_TEXTURE_2D, texID);
|
||||
GLuint comps = GL_RGBA;
|
||||
GLuint comps = tex_type == TextureType::_8 ? gl.single_channel_format : GL_RGBA;
|
||||
GLuint gltype;
|
||||
u32 bytes_per_pixel = 2;
|
||||
switch (tex_type)
|
||||
{
|
||||
case TextureType::_5551:
|
||||
@@ -67,10 +68,16 @@ void TextureCacheData::UploadToGPU(int width, int height, u8 *temp_tex_buffer, b
|
||||
gltype = GL_UNSIGNED_SHORT_4_4_4_4;
|
||||
break;
|
||||
case TextureType::_8888:
|
||||
bytes_per_pixel = 4;
|
||||
gltype = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case TextureType::_8:
|
||||
bytes_per_pixel = 1;
|
||||
gltype = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
default:
|
||||
die("Unsupported texture type");
|
||||
gltype = 0;
|
||||
break;
|
||||
}
|
||||
if (mipmapsIncluded)
|
||||
@@ -102,6 +109,13 @@ void TextureCacheData::UploadToGPU(int width, int height, u8 *temp_tex_buffer, b
|
||||
case TextureType::_8888:
|
||||
internalFormat = GL_RGBA8;
|
||||
break;
|
||||
case TextureType::_8:
|
||||
internalFormat = comps;
|
||||
break;
|
||||
default:
|
||||
die("Unsupported texture format");
|
||||
internalFormat = 0;
|
||||
break;
|
||||
}
|
||||
if (Updates == 1)
|
||||
{
|
||||
@@ -111,7 +125,7 @@ void TextureCacheData::UploadToGPU(int width, int height, u8 *temp_tex_buffer, b
|
||||
for (int i = 0; i < mipmapLevels; i++)
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_2D, mipmapLevels - i - 1, 0, 0, 1 << i, 1 << i, comps, gltype, temp_tex_buffer);
|
||||
temp_tex_buffer += (1 << (2 * i)) * (tex_type == TextureType::_8888 ? 4 : 2);
|
||||
temp_tex_buffer += (1 << (2 * i)) * bytes_per_pixel;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -122,7 +136,7 @@ void TextureCacheData::UploadToGPU(int width, int height, u8 *temp_tex_buffer, b
|
||||
for (int i = 0; i < mipmapLevels; i++)
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_2D, mipmapLevels - i - 1, comps, 1 << i, 1 << i, 0, comps, gltype, temp_tex_buffer);
|
||||
temp_tex_buffer += (1 << (2 * i)) * (tex_type == TextureType::_8888 ? 4 : 2);
|
||||
temp_tex_buffer += (1 << (2 * i)) * bytes_per_pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,10 +213,10 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt)
|
||||
gl.rtt.TexAddr=addy>>3;
|
||||
|
||||
// Find the smallest power of two texture that fits the viewport
|
||||
int fbh2 = 2;
|
||||
u32 fbh2 = 2;
|
||||
while (fbh2 < fbh)
|
||||
fbh2 *= 2;
|
||||
int fbw2 = 2;
|
||||
u32 fbw2 = 2;
|
||||
while (fbw2 < fbw)
|
||||
fbw2 *= 2;
|
||||
|
||||
@@ -304,9 +318,6 @@ void ReadRTTBuffer() {
|
||||
PixelBuffer<u32> tmp_buf;
|
||||
tmp_buf.init(w, h);
|
||||
|
||||
const u16 kval_bit = (FB_W_CTRL.fb_kval & 0x80) << 8;
|
||||
const u8 fb_alpha_threshold = FB_W_CTRL.fb_alpha_threshold;
|
||||
|
||||
u8 *p = (u8 *)tmp_buf.data();
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
|
||||
|
||||
@@ -340,8 +351,8 @@ void ReadRTTBuffer() {
|
||||
break;
|
||||
}
|
||||
TSP tsp = { 0 };
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8 << tsp.TexU) < w; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8 << tsp.TexV) < h; tsp.TexV++);
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8u << tsp.TexU) < w; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8u << tsp.TexV) < h; tsp.TexV++);
|
||||
|
||||
TextureCacheData *texture_data = TexCache.getTextureCacheData(tsp, tcw);
|
||||
if (texture_data->texID != 0)
|
||||
@@ -370,7 +381,7 @@ u64 gl_GetTexture(TSP tsp, TCW tcw)
|
||||
{
|
||||
TexCacheLookups++;
|
||||
|
||||
/* Lookup texture */
|
||||
//lookup texture
|
||||
TextureCacheData* tf = TexCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
if (tf->texID == 0)
|
||||
@@ -379,7 +390,7 @@ u64 gl_GetTexture(TSP tsp, TCW tcw)
|
||||
tf->texID = glcache.GenTexture();
|
||||
}
|
||||
|
||||
/* Update if needed */
|
||||
//update if needed
|
||||
if (tf->NeedsUpdate())
|
||||
tf->Update();
|
||||
else
|
||||
@@ -393,10 +404,7 @@ u64 gl_GetTexture(TSP tsp, TCW tcw)
|
||||
TexCacheHits++;
|
||||
}
|
||||
|
||||
/* Update state for opts/stuff */
|
||||
tf->Lookups++;
|
||||
|
||||
/* Return gl texture */
|
||||
// Return gl texture
|
||||
return tf->texID;
|
||||
}
|
||||
|
||||
@@ -414,9 +422,6 @@ text_info raw_GetTexture(TSP tsp, TCW tcw)
|
||||
if (tf->NeedsUpdate())
|
||||
tf->Update();
|
||||
|
||||
//update state for opts/stuff
|
||||
tf->Lookups++;
|
||||
|
||||
//return gl texture
|
||||
rv.height = tf->h;
|
||||
rv.width = tf->w;
|
||||
|
||||
@@ -211,19 +211,23 @@ void GenSorted(int first, int count, std::vector<SortTrigDrawParam>& pidx_sort,
|
||||
if (pvrrc.verts.used() == 0 || count == 0)
|
||||
return;
|
||||
|
||||
const Vertex *vtx_base = pvrrc.verts.head();
|
||||
const u32 *idx_base = pvrrc.idx.head();
|
||||
const Vertex * const vtx_base = pvrrc.verts.head();
|
||||
const u32 * const idx_base = pvrrc.idx.head();
|
||||
|
||||
const PolyParam *pp_base = &pvrrc.global_param_tr.head()[first];
|
||||
const PolyParam * const pp_base = &pvrrc.global_param_tr.head()[first];
|
||||
const PolyParam *pp = pp_base;
|
||||
const PolyParam *pp_end = pp + count;
|
||||
const PolyParam * const pp_end = pp + count;
|
||||
while (pp->count == 0 && pp < pp_end)
|
||||
pp++;
|
||||
if (pp == pp_end)
|
||||
return;
|
||||
|
||||
vtx_sort_base=vtx_base;
|
||||
|
||||
static u32 vtx_cnt;
|
||||
|
||||
int vtx_count = pvrrc.verts.used() - idx_base[pp->first];
|
||||
if (vtx_count>vtx_cnt)
|
||||
if ((u32)vtx_count > vtx_cnt)
|
||||
vtx_cnt=vtx_count;
|
||||
|
||||
#if PRINT_SORT_STATS
|
||||
|
||||
+29
-19
@@ -196,15 +196,25 @@ void Drawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sor
|
||||
// Trilinear pass A
|
||||
trilinearAlpha = 1.0 - trilinearAlpha;
|
||||
}
|
||||
|
||||
if (tileClip == TileClipping::Inside || trilinearAlpha != 1.f)
|
||||
bool palette = BaseTextureCacheData::IsGpuHandledPaletted(poly.tsp, poly.tcw);
|
||||
float palette_index = 0.f;
|
||||
if (palette)
|
||||
{
|
||||
std::array<float, 5> pushConstants = {
|
||||
if (poly.tcw.PixelFmt == PixelPal4)
|
||||
palette_index = float(poly.tcw.PalSelect << 4) / 1023.f;
|
||||
else
|
||||
palette_index = float((poly.tcw.PalSelect >> 4) << 8) / 1023.f;
|
||||
}
|
||||
|
||||
if (tileClip == TileClipping::Inside || trilinearAlpha != 1.f || palette)
|
||||
{
|
||||
std::array<float, 6> pushConstants = {
|
||||
(float)scissorRect.offset.x,
|
||||
(float)scissorRect.offset.y,
|
||||
(float)scissorRect.offset.x + (float)scissorRect.extent.width,
|
||||
(float)scissorRect.offset.y + (float)scissorRect.extent.height,
|
||||
trilinearAlpha
|
||||
trilinearAlpha,
|
||||
palette_index
|
||||
};
|
||||
cmdBuffer.pushConstants<float>(pipelineManager->GetPipelineLayout(), vk::ShaderStageFlagBits::eFragment, 0, pushConstants);
|
||||
}
|
||||
@@ -223,18 +233,15 @@ void Drawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sor
|
||||
void Drawer::DrawSorted(const vk::CommandBuffer& cmdBuffer, const std::vector<SortTrigDrawParam>& polys)
|
||||
{
|
||||
for (const SortTrigDrawParam& param : polys)
|
||||
{
|
||||
DrawPoly(cmdBuffer, ListType_Translucent, true, *param.ppid, pvrrc.idx.used() + param.first, param.count);
|
||||
}
|
||||
}
|
||||
|
||||
void Drawer::DrawList(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, const List<PolyParam>& polys, u32 first, u32 last)
|
||||
{
|
||||
for (u32 i = first; i < last; i++)
|
||||
{
|
||||
const PolyParam &pp = polys.head()[i];
|
||||
DrawPoly(cmdBuffer, listType, sortTriangles, pp, pp.first, pp.count);
|
||||
}
|
||||
const PolyParam *pp_end = polys.head() + last;
|
||||
for (const PolyParam *pp = polys.head() + first; pp != pp_end; pp++)
|
||||
if (pp->count > 2)
|
||||
DrawPoly(cmdBuffer, listType, sortTriangles, *pp, pp->first, pp->count);
|
||||
}
|
||||
|
||||
void Drawer::DrawModVols(const vk::CommandBuffer& cmdBuffer, int first, int count)
|
||||
@@ -251,7 +258,7 @@ void Drawer::DrawModVols(const vk::CommandBuffer& cmdBuffer, int first, int coun
|
||||
int mod_base = -1;
|
||||
vk::Pipeline pipeline;
|
||||
|
||||
for (u32 cmv = 0; cmv < count; cmv++)
|
||||
for (int cmv = 0; cmv < count; cmv++)
|
||||
{
|
||||
ModifierVolumeParam& param = params[cmv];
|
||||
|
||||
@@ -346,7 +353,7 @@ void Drawer::UploadMainBuffer(const VertexShaderUniforms& vertexUniforms, const
|
||||
buffer->upload(chunks.size(), &chunkSizes[0], &chunks[0]);
|
||||
}
|
||||
|
||||
bool Drawer::Draw(const Texture *fogTexture)
|
||||
bool Drawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
|
||||
{
|
||||
VertexShaderUniforms vtxUniforms;
|
||||
vtxUniforms.normal_matrix = matrices.GetNormalMatrix();
|
||||
@@ -364,7 +371,8 @@ bool Drawer::Draw(const Texture *fogTexture)
|
||||
UploadMainBuffer(vtxUniforms, fragUniforms);
|
||||
|
||||
// Update per-frame descriptor set and bind it
|
||||
GetCurrentDescSet().UpdateUniforms(GetMainBuffer(0)->buffer.get(), offsets.vertexUniformOffset, offsets.fragmentUniformOffset, fogTexture->GetImageView());
|
||||
GetCurrentDescSet().UpdateUniforms(GetMainBuffer(0)->buffer.get(), offsets.vertexUniformOffset, offsets.fragmentUniformOffset,
|
||||
fogTexture->GetImageView(), paletteTexture->GetImageView());
|
||||
GetCurrentDescSet().BindPerFrameDescriptorSets(cmdBuffer);
|
||||
// Reset per-poly descriptor set pool
|
||||
GetCurrentDescSet().Reset();
|
||||
@@ -433,10 +441,10 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass()
|
||||
u32 origHeight = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1;
|
||||
u32 upscaledWidth = origWidth;
|
||||
u32 upscaledHeight = origHeight;
|
||||
int heightPow2 = 8;
|
||||
u32 heightPow2 = 8;
|
||||
while (heightPow2 < upscaledHeight)
|
||||
heightPow2 *= 2;
|
||||
int widthPow2 = 8;
|
||||
u32 widthPow2 = 8;
|
||||
while (widthPow2 < upscaledWidth)
|
||||
widthPow2 *= 2;
|
||||
|
||||
@@ -487,8 +495,8 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass()
|
||||
}
|
||||
|
||||
TSP tsp = { 0 };
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8 << tsp.TexU) < origWidth; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8 << tsp.TexV) < origHeight; tsp.TexV++);
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8u << tsp.TexU) < origWidth; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8u << tsp.TexV) < origHeight; tsp.TexV++);
|
||||
|
||||
texture = textureCache->getTextureCacheData(tsp, tcw);
|
||||
if (texture->IsNew())
|
||||
@@ -502,13 +510,15 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass()
|
||||
texture->readOnlyImageView = *texture->imageView;
|
||||
textureCache->DestroyLater(texture);
|
||||
}
|
||||
textureCache->SetInFlight(texture);
|
||||
|
||||
if (texture->format != vk::Format::eR8G8B8A8Unorm || texture->extent.width != widthPow2 || texture->extent.height != heightPow2)
|
||||
{
|
||||
texture->extent = vk::Extent2D(widthPow2, heightPow2);
|
||||
texture->format = vk::Format::eR8G8B8A8Unorm;
|
||||
texture->needsStaging = true;
|
||||
texture->CreateImage(vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled,
|
||||
vk::ImageLayout::eUndefined, vk::MemoryPropertyFlags(), vk::ImageAspectFlagBits::eColor);
|
||||
vk::ImageLayout::eUndefined, vk::ImageAspectFlagBits::eColor);
|
||||
colorImageCurrentLayout = vk::ImageLayout::eUndefined;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -100,7 +100,7 @@ class Drawer : public BaseDrawer
|
||||
{
|
||||
public:
|
||||
virtual ~Drawer() = default;
|
||||
bool Draw(const Texture *fogTexture);
|
||||
bool Draw(const Texture *fogTexture, const Texture *paletteTexture);
|
||||
virtual void EndRenderPass() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <math.h>
|
||||
#include "oit_drawer.h"
|
||||
#include "hw/pvr/pvr_mem.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
void OITDrawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool autosort, Pass pass,
|
||||
const PolyParam& poly, u32 first, u32 count)
|
||||
{
|
||||
@@ -41,7 +42,17 @@ void OITDrawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool
|
||||
trilinearAlpha = 1.0 - trilinearAlpha;
|
||||
}
|
||||
|
||||
bool twoVolumes = poly.tsp1.full != -1 || poly.tcw1.full != -1;
|
||||
bool twoVolumes = poly.tsp1.full != (u32)-1 || poly.tcw1.full != (u32)-1;
|
||||
|
||||
bool palette = BaseTextureCacheData::IsGpuHandledPaletted(poly.tsp, poly.tcw);
|
||||
float palette_index = 0.f;
|
||||
if (palette)
|
||||
{
|
||||
if (poly.tcw.PixelFmt == PixelPal4)
|
||||
palette_index = float(poly.tcw.PalSelect << 4) / 1023.f;
|
||||
else
|
||||
palette_index = float((poly.tcw.PalSelect >> 4) << 8) / 1023.f;
|
||||
}
|
||||
|
||||
OITDescriptorSets::PushConstants pushConstants = {
|
||||
{
|
||||
@@ -52,9 +63,8 @@ void OITDrawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool
|
||||
},
|
||||
{ poly.tsp.SrcInstr, poly.tsp.DstInstr, 0, 0 },
|
||||
trilinearAlpha,
|
||||
(int)(&poly - (listType == ListType_Opaque ? pvrrc.global_param_op.head()
|
||||
: listType == ListType_Punch_Through ? pvrrc.global_param_pt.head()
|
||||
: pvrrc.global_param_tr.head())),
|
||||
listType == ListType_Translucent ? (int)(&poly - pvrrc.global_param_tr.head()) : 0,
|
||||
palette_index,
|
||||
};
|
||||
if (twoVolumes)
|
||||
{
|
||||
@@ -85,12 +95,10 @@ void OITDrawer::DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool
|
||||
void OITDrawer::DrawList(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, Pass pass,
|
||||
const List<PolyParam>& polys, u32 first, u32 last)
|
||||
{
|
||||
for (u32 i = first; i < last; i++)
|
||||
{
|
||||
const PolyParam &pp = polys.head()[i];
|
||||
if (pp.count > 2)
|
||||
DrawPoly(cmdBuffer, listType, sortTriangles, pass, pp, pp.first, pp.count);
|
||||
}
|
||||
const PolyParam *pp_end = polys.head() + last;
|
||||
for (const PolyParam *pp = polys.head() + first; pp != pp_end; pp++)
|
||||
if (pp->count > 2)
|
||||
DrawPoly(cmdBuffer, listType, sortTriangles, pass, *pp, pp->first, pp->count);
|
||||
}
|
||||
|
||||
template<bool Translucent>
|
||||
@@ -108,7 +116,7 @@ void OITDrawer::DrawModifierVolumes(const vk::CommandBuffer& cmdBuffer, int firs
|
||||
int mod_base = -1;
|
||||
vk::Pipeline pipeline;
|
||||
|
||||
for (u32 cmv = 0; cmv < count; cmv++)
|
||||
for (int cmv = 0; cmv < count; cmv++)
|
||||
{
|
||||
ModifierVolumeParam& param = params[cmv];
|
||||
|
||||
@@ -117,7 +125,7 @@ void OITDrawer::DrawModifierVolumes(const vk::CommandBuffer& cmdBuffer, int firs
|
||||
|
||||
u32 mv_mode = param.isp.DepthMode;
|
||||
|
||||
verify(param.first >= 0 && param.first + param.count <= pvrrc.modtrig.used());
|
||||
verify(param.first >= 0 && param.first + param.count <= (u32)pvrrc.modtrig.used());
|
||||
|
||||
if (mod_base == -1)
|
||||
mod_base = param.first;
|
||||
@@ -222,11 +230,12 @@ void OITDrawer::UploadMainBuffer(const OITDescriptorSets::VertexShaderUniforms&
|
||||
trPolyParams.push_back(0); // makes the validation layers happy
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < pvrrc.global_param_tr.used(); i++)
|
||||
const PolyParam *pp_end = pvrrc.global_param_tr.LastPtr(0);
|
||||
const PolyParam *pp = pvrrc.global_param_tr.head();
|
||||
for (int i = 0; pp != pp_end; i += 2, pp++)
|
||||
{
|
||||
const PolyParam& pp = pvrrc.global_param_tr.head()[i];
|
||||
trPolyParams[i * 2] = (pp.tsp.full & 0xffff00c0) | ((pp.isp.full >> 16) & 0xe400) | ((pp.pcw.full >> 7) & 1);
|
||||
trPolyParams[i * 2 + 1] = pp.tsp1.full;
|
||||
trPolyParams[i] = (pp->tsp.full & 0xffff00c0) | ((pp->isp.full >> 16) & 0xe400) | ((pp->pcw.full >> 7) & 1);
|
||||
trPolyParams[i + 1] = pp->tsp1.full;
|
||||
}
|
||||
}
|
||||
offsets.polyParamsSize = trPolyParams.size() * 4;
|
||||
@@ -238,7 +247,7 @@ void OITDrawer::UploadMainBuffer(const OITDescriptorSets::VertexShaderUniforms&
|
||||
buffer->upload(chunks.size(), &chunkSizes[0], &chunks[0]);
|
||||
}
|
||||
|
||||
bool OITDrawer::Draw(const Texture *fogTexture)
|
||||
bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
|
||||
{
|
||||
vk::CommandBuffer cmdBuffer = NewFrame();
|
||||
|
||||
@@ -271,7 +280,7 @@ bool OITDrawer::Draw(const Texture *fogTexture)
|
||||
GetCurrentDescSet().UpdateUniforms(mainBuffer, offsets.vertexUniformOffset, offsets.fragmentUniformOffset,
|
||||
fogTexture->GetImageView(), offsets.polyParamsOffset,
|
||||
offsets.polyParamsSize, depthAttachment->GetStencilView(),
|
||||
depthAttachment->GetImageView());
|
||||
depthAttachment->GetImageView(), paletteTexture->GetImageView());
|
||||
GetCurrentDescSet().BindPerFrameDescriptorSets(cmdBuffer);
|
||||
GetCurrentDescSet().UpdateColorInputDescSet(0, colorAttachments[0]->GetImageView());
|
||||
GetCurrentDescSet().UpdateColorInputDescSet(1, colorAttachments[1]->GetImageView());
|
||||
@@ -466,10 +475,10 @@ vk::CommandBuffer OITTextureDrawer::NewFrame()
|
||||
u32 origHeight = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1;
|
||||
u32 upscaledWidth = origWidth;
|
||||
u32 upscaledHeight = origHeight;
|
||||
int heightPow2 = 8;
|
||||
u32 heightPow2 = 8;
|
||||
while (heightPow2 < upscaledHeight)
|
||||
heightPow2 *= 2;
|
||||
int widthPow2 = 8;
|
||||
u32 widthPow2 = 8;
|
||||
while (widthPow2 < upscaledWidth)
|
||||
widthPow2 *= 2;
|
||||
|
||||
@@ -510,9 +519,9 @@ vk::CommandBuffer OITTextureDrawer::NewFrame()
|
||||
break;
|
||||
}
|
||||
|
||||
TSP tsp = { 0 };
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8 << tsp.TexU) < origWidth; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8 << tsp.TexV) < origHeight; tsp.TexV++);
|
||||
TSP tsp = {};
|
||||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8u << tsp.TexU) < origWidth; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8u << tsp.TexV) < origHeight; tsp.TexV++);
|
||||
|
||||
texture = textureCache->getTextureCacheData(tsp, tcw);
|
||||
if (texture->IsNew())
|
||||
@@ -526,12 +535,15 @@ vk::CommandBuffer OITTextureDrawer::NewFrame()
|
||||
texture->readOnlyImageView = *texture->imageView;
|
||||
textureCache->DestroyLater(texture);
|
||||
}
|
||||
textureCache->SetInFlight(texture);
|
||||
|
||||
if (texture->format != vk::Format::eR8G8B8A8Unorm || texture->extent.width != widthPow2 || texture->extent.height != heightPow2)
|
||||
{
|
||||
texture->extent = vk::Extent2D(widthPow2, heightPow2);
|
||||
texture->format = vk::Format::eR8G8B8A8Unorm;
|
||||
texture->needsStaging = true;
|
||||
texture->CreateImage(vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled,
|
||||
vk::ImageLayout::eUndefined, vk::MemoryPropertyFlags(), vk::ImageAspectFlagBits::eColor);
|
||||
vk::ImageLayout::eUndefined, vk::ImageAspectFlagBits::eColor);
|
||||
colorImageCurrentLayout = vk::ImageLayout::eUndefined;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -36,7 +36,7 @@ class OITDrawer : public BaseDrawer
|
||||
{
|
||||
public:
|
||||
virtual ~OITDrawer() = default;
|
||||
bool Draw(const Texture *fogTexture);
|
||||
bool Draw(const Texture *fogTexture, const Texture *paletteTexture);
|
||||
|
||||
virtual vk::CommandBuffer NewFrame() = 0;
|
||||
virtual void EndFrame() = 0;
|
||||
|
||||
@@ -156,7 +156,8 @@ void OITPipelineManager::CreatePipeline(u32 listType, bool autosort, const PolyP
|
||||
//params.trilinear = pp.pcw.Texture && pp.tsp.FilterMode > 1 && listType != ListType_Punch_Through;
|
||||
params.useAlpha = pp.tsp.UseAlpha;
|
||||
params.pass = pass;
|
||||
params.twoVolume = pp.tsp1.full != -1 || pp.tcw1.full != -1;
|
||||
params.twoVolume = pp.tsp1.full != (u32)-1 || pp.tcw1.full != (u32)-1;
|
||||
params.palette = BaseTextureCacheData::IsGpuHandledPaletted(pp.tsp, pp.tcw);
|
||||
vk::ShaderModule fragment_module = shaderManager->GetFragmentShader(params);
|
||||
|
||||
vk::PipelineShaderStageCreateInfo stages[] = {
|
||||
|
||||
@@ -55,7 +55,8 @@ public:
|
||||
glm::ivec4 blend_mode0; // Only using 2 elements but easier for std140
|
||||
float trilinearAlpha;
|
||||
int pp_Number;
|
||||
int _pad[2];
|
||||
float palette_index;
|
||||
int _pad;
|
||||
|
||||
// two volume mode
|
||||
glm::ivec4 blend_mode1; // Only using 2 elements but easier for std140
|
||||
@@ -80,7 +81,8 @@ public:
|
||||
}
|
||||
// FIXME way too many params
|
||||
void UpdateUniforms(vk::Buffer buffer, u32 vertexUniformOffset, u32 fragmentUniformOffset, vk::ImageView fogImageView,
|
||||
u32 polyParamsOffset, u32 polyParamsSize, vk::ImageView stencilImageView, vk::ImageView depthImageView)
|
||||
u32 polyParamsOffset, u32 polyParamsSize, vk::ImageView stencilImageView, vk::ImageView depthImageView,
|
||||
vk::ImageView paletteImageView)
|
||||
{
|
||||
if (!perFrameDescSet)
|
||||
{
|
||||
@@ -105,6 +107,17 @@ public:
|
||||
imageInfo = { fogSampler, fogImageView, vk::ImageLayout::eShaderReadOnlyOptimal };
|
||||
writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perFrameDescSet, 2, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr));
|
||||
}
|
||||
if (paletteImageView)
|
||||
{
|
||||
TSP palTsp = {};
|
||||
palTsp.FilterMode = 0;
|
||||
palTsp.ClampU = 1;
|
||||
palTsp.ClampV = 1;
|
||||
vk::Sampler palSampler = samplerManager->GetSampler(palTsp);
|
||||
static vk::DescriptorImageInfo imageInfo;
|
||||
imageInfo = { palSampler, paletteImageView, vk::ImageLayout::eShaderReadOnlyOptimal };
|
||||
writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perFrameDescSet, 6, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr));
|
||||
}
|
||||
if (polyParamsSize > 0)
|
||||
{
|
||||
static vk::DescriptorBufferInfo polyParamsBufferInfo;
|
||||
@@ -150,7 +163,7 @@ public:
|
||||
std::vector<vk::WriteDescriptorSet> writeDescriptorSets;
|
||||
writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perPolyDescSets.back(), 0, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo0, nullptr, nullptr));
|
||||
|
||||
if (textureId1 != -1)
|
||||
if (textureId1 != (u64)-1)
|
||||
{
|
||||
Texture *texture1 = reinterpret_cast<Texture *>(textureId1);
|
||||
vk::DescriptorImageInfo imageInfo1(samplerManager->GetSampler(tsp1), texture1->GetReadOnlyImageView(), vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
@@ -223,6 +236,7 @@ public:
|
||||
{ 3, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eFragment }, // Tr poly params
|
||||
{ 4, vk::DescriptorType::eInputAttachment, 1, vk::ShaderStageFlagBits::eFragment }, // stencil input attachment
|
||||
{ 5, vk::DescriptorType::eInputAttachment, 1, vk::ShaderStageFlagBits::eFragment }, // depth input attachment
|
||||
{ 6, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment },// palette texture
|
||||
};
|
||||
perFrameLayout = GetContext()->GetDevice().createDescriptorSetLayoutUnique(
|
||||
vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), ARRAY_SIZE(perFrameBindings), perFrameBindings));
|
||||
@@ -310,7 +324,7 @@ private:
|
||||
u32 hash = pp->pcw.Gouraud | (pp->pcw.Offset << 1) | (pp->pcw.Texture << 2) | (pp->pcw.Shadow << 3)
|
||||
| (((pp->tileclip >> 28) == 3) << 4);
|
||||
hash |= ((listType >> 1) << 5);
|
||||
if (pp->tcw1.full != -1 || pp->tsp1.full != -1)
|
||||
if (pp->tcw1.full != (u32)-1 || pp->tsp1.full != (u32)-1)
|
||||
{
|
||||
// Two-volume mode
|
||||
hash |= (1 << 31) | (pp->tsp.ColorClamp << 11);
|
||||
@@ -322,7 +336,7 @@ private:
|
||||
| (pp->tsp.SrcInstr << 14) | (pp->tsp.DstInstr << 17);
|
||||
}
|
||||
hash |= (pp->isp.ZWriteDis << 20) | (pp->isp.CullMode << 21) | ((autosort ? 6 : pp->isp.DepthMode) << 23);
|
||||
hash |= (u32)pass << 26;
|
||||
hash |= ((u32)BaseTextureCacheData::IsGpuHandledPaletted(pp->tsp, pp->tcw) << 26) | ((u32)pass << 27);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -18,36 +18,26 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <memory>
|
||||
#include <math.h>
|
||||
#include "../vulkan.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
#include "../commandpool.h"
|
||||
#include "../vulkan_renderer.h"
|
||||
#include "oit_drawer.h"
|
||||
#include "oit_shaders.h"
|
||||
#include "../pipeline.h"
|
||||
#include "oit_buffer.h"
|
||||
#include "../vmu.h"
|
||||
|
||||
void co_dc_yield();
|
||||
|
||||
class OITVulkanRenderer : public Renderer
|
||||
class OITVulkanRenderer final : public BaseVulkanRenderer
|
||||
{
|
||||
public:
|
||||
bool Init() override
|
||||
{
|
||||
DEBUG_LOG(RENDERER, "OITVulkanRenderer::Init");
|
||||
texCommandPool.Init();
|
||||
|
||||
oitBuffers.Init(0, 0);
|
||||
textureDrawer.Init(&samplerManager, &shaderManager, &textureCache, &oitBuffers);
|
||||
textureDrawer.Init(&samplerManager, &oitShaderManager, &textureCache, &oitBuffers);
|
||||
textureDrawer.SetCommandPool(&texCommandPool);
|
||||
|
||||
screenDrawer.Init(&samplerManager, &shaderManager, &oitBuffers);
|
||||
screenDrawer.Init(&samplerManager, &oitShaderManager, &oitBuffers);
|
||||
screenDrawer.SetCommandPool(&texCommandPool);
|
||||
quadPipeline.Init(®ularShaderManager, screenDrawer.GetRenderPass(), 2);
|
||||
vmus = std::unique_ptr<VulkanOSD>(new VulkanOSD());
|
||||
vmus->Init(&quadPipeline);
|
||||
BaseInit(screenDrawer.GetRenderPass(), 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -55,92 +45,20 @@ public:
|
||||
void Resize(int w, int h) override
|
||||
{
|
||||
NOTICE_LOG(RENDERER, "OIT Resize %d x %d", w, h);
|
||||
texCommandPool.Init();
|
||||
screenDrawer.Init(&samplerManager, &shaderManager, &oitBuffers);
|
||||
quadPipeline.Init(®ularShaderManager, screenDrawer.GetRenderPass(), 2);
|
||||
vmus->Init(&quadPipeline);
|
||||
screenDrawer.Init(&samplerManager, &oitShaderManager, &oitBuffers);
|
||||
BaseInit(screenDrawer.GetRenderPass(), 2);
|
||||
}
|
||||
|
||||
void Term() override
|
||||
{
|
||||
DEBUG_LOG(RENDERER, "VulkanRenderer::Term");
|
||||
GetContext()->WaitIdle();
|
||||
vmus.reset();
|
||||
oitShaderManager.Term();
|
||||
samplerManager.Term();
|
||||
screenDrawer.Term();
|
||||
textureDrawer.Term();
|
||||
oitBuffers.Term();
|
||||
textureCache.Clear();
|
||||
fogTexture = nullptr;
|
||||
texCommandPool.Term();
|
||||
framebufferTextures.clear();
|
||||
}
|
||||
|
||||
bool RenderFramebuffer()
|
||||
{
|
||||
if (FB_R_SIZE.fb_x_size == 0 || FB_R_SIZE.fb_y_size == 0)
|
||||
return false;
|
||||
|
||||
PixelBuffer<u32> pb;
|
||||
int width;
|
||||
int height;
|
||||
ReadFramebuffer(pb, width, height);
|
||||
|
||||
if (framebufferTextures.size() != GetContext()->GetSwapChainSize())
|
||||
framebufferTextures.resize(GetContext()->GetSwapChainSize());
|
||||
std::unique_ptr<Texture>& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
|
||||
if (!curTexture)
|
||||
{
|
||||
curTexture = std::unique_ptr<Texture>(new Texture());
|
||||
curTexture->tex_type = TextureType::_8888;
|
||||
curTexture->tcw.full = 0;
|
||||
curTexture->tsp.full = 0;
|
||||
curTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
curTexture->SetDevice(GetContext()->GetDevice());
|
||||
}
|
||||
curTexture->SetCommandBuffer(texCommandPool.Allocate());
|
||||
curTexture->UploadToGPU(width, height, (u8*)pb.data(), false);
|
||||
curTexture->SetCommandBuffer(nullptr);
|
||||
texCommandPool.EndFrame();
|
||||
|
||||
GetContext()->PresentFrame(curTexture->GetImage(), curTexture->GetImageView(), { 640, 480 });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Process(TA_context* ctx) override
|
||||
{
|
||||
texCommandPool.BeginFrame();
|
||||
textureCache.SetCurrentIndex(texCommandPool.GetIndex());
|
||||
|
||||
if (!ctx->rend.isRTT)
|
||||
vmus->PrepareOSD(&texCommandPool);
|
||||
|
||||
if (ctx->rend.isRenderFramebuffer)
|
||||
{
|
||||
return RenderFramebuffer();
|
||||
}
|
||||
|
||||
ctx->rend_inuse.Lock();
|
||||
|
||||
if (KillTex)
|
||||
textureCache.Clear();
|
||||
|
||||
bool result = ta_parse_vdrc(ctx);
|
||||
|
||||
textureCache.CollectCleanup();
|
||||
|
||||
if (ctx->rend.Overrun)
|
||||
WARN_LOG(PVR, "ERROR: TA context overrun");
|
||||
|
||||
result = result && !ctx->rend.Overrun;
|
||||
|
||||
if (result)
|
||||
CheckFogTexture();
|
||||
|
||||
if (!result)
|
||||
texCommandPool.EndFrame();
|
||||
|
||||
return result;
|
||||
BaseVulkanRenderer::Term();
|
||||
}
|
||||
|
||||
bool Render() override
|
||||
@@ -154,7 +72,7 @@ public:
|
||||
else
|
||||
drawer = &screenDrawer;
|
||||
|
||||
drawer->Draw(fogTexture.get());
|
||||
drawer->Draw(fogTexture.get(), paletteTexture.get());
|
||||
|
||||
if (!pvrrc.isRTT)
|
||||
vmus->DrawOSD(screenDrawer.GetCurrentCommandBuffer(), vk::Extent2D(screen_width, screen_height));
|
||||
@@ -164,79 +82,12 @@ public:
|
||||
return !pvrrc.isRTT;
|
||||
}
|
||||
|
||||
void Present() override
|
||||
{
|
||||
co_dc_yield();
|
||||
}
|
||||
|
||||
virtual u64 GetTexture(TSP tsp, TCW tcw) override
|
||||
{
|
||||
Texture* tf = textureCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
if (tf->IsNew())
|
||||
{
|
||||
tf->Create();
|
||||
tf->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
tf->SetDevice(GetContext()->GetDevice());
|
||||
}
|
||||
|
||||
//update if needed
|
||||
if (tf->NeedsUpdate())
|
||||
{
|
||||
textureCache.DestroyLater(tf);
|
||||
tf->SetCommandBuffer(texCommandPool.Allocate());
|
||||
tf->Update();
|
||||
}
|
||||
else if (tf->IsCustomTextureAvailable())
|
||||
{
|
||||
textureCache.DestroyLater(tf);
|
||||
tf->SetCommandBuffer(texCommandPool.Allocate());
|
||||
tf->CheckCustomTexture();
|
||||
}
|
||||
tf->SetCommandBuffer(nullptr);
|
||||
|
||||
return tf->GetIntId();
|
||||
}
|
||||
|
||||
private:
|
||||
VulkanContext *GetContext() const { return VulkanContext::Instance(); }
|
||||
|
||||
void CheckFogTexture()
|
||||
{
|
||||
if (!fogTexture)
|
||||
{
|
||||
fogTexture = std::unique_ptr<Texture>(new Texture());
|
||||
fogTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
fogTexture->SetDevice(GetContext()->GetDevice());
|
||||
fogTexture->tex_type = TextureType::_8;
|
||||
fog_needs_update = true;
|
||||
}
|
||||
if (!fog_needs_update)
|
||||
return;
|
||||
fog_needs_update = false;
|
||||
u8 texData[256];
|
||||
MakeFogTexture(texData);
|
||||
fogTexture->SetCommandBuffer(texCommandPool.Allocate());
|
||||
|
||||
fogTexture->UploadToGPU(128, 2, texData, false);
|
||||
|
||||
fogTexture->SetCommandBuffer(nullptr);
|
||||
}
|
||||
|
||||
OITBuffers oitBuffers;
|
||||
std::unique_ptr<Texture> fogTexture;
|
||||
CommandPool texCommandPool;
|
||||
|
||||
SamplerManager samplerManager;
|
||||
OITShaderManager shaderManager;
|
||||
ShaderManager normalShaderManager;
|
||||
OITShaderManager oitShaderManager;
|
||||
OITScreenDrawer screenDrawer;
|
||||
OITTextureDrawer textureDrawer;
|
||||
std::vector<std::unique_ptr<Texture>> framebufferTextures;
|
||||
TextureCache textureCache;
|
||||
ShaderManager regularShaderManager;
|
||||
QuadPipeline quadPipeline;
|
||||
std::unique_ptr<VulkanOSD> vmus;
|
||||
};
|
||||
|
||||
Renderer* rend_OITVulkan()
|
||||
|
||||
@@ -59,8 +59,7 @@ void main()
|
||||
vtx_base1 = vec4(in_base1) / 255.0; // New for OIT, only for OP/PT with 2-volume
|
||||
vtx_offs1 = vec4(in_offs1) / 255.0;
|
||||
vtx_uv1 = in_uv1;
|
||||
vec4 vpos = in_pos;
|
||||
vpos = uniformBuffer.normal_matrix * vpos;
|
||||
vec4 vpos = uniformBuffer.normal_matrix * in_pos;
|
||||
vpos.w = 1.0 / vpos.z;
|
||||
vpos.z = vpos.w;
|
||||
vpos.xy *= vpos.w;
|
||||
@@ -235,6 +234,7 @@ static const char OITFragmentShaderSource[] = R"(
|
||||
#define pp_Gouraud %d
|
||||
#define pp_BumpMap %d
|
||||
#define ColorClamping %d
|
||||
#define pp_Palette %d
|
||||
#define PASS %d
|
||||
#define PI 3.1415926
|
||||
|
||||
@@ -265,6 +265,7 @@ layout (push_constant) uniform pushBlock
|
||||
ivec4 blend_mode0;
|
||||
float trilinearAlpha;
|
||||
int pp_Number;
|
||||
float palette_index;
|
||||
|
||||
// two volume mode
|
||||
ivec4 blend_mode1;
|
||||
@@ -284,6 +285,9 @@ layout (set = 1, binding = 0) uniform sampler2D tex0;
|
||||
layout (set = 1, binding = 1) uniform sampler2D tex1;
|
||||
#endif
|
||||
#endif
|
||||
#if pp_Palette == 1
|
||||
layout (set = 0, binding = 6) uniform sampler2D palette;
|
||||
#endif
|
||||
|
||||
#if PASS == PASS_COLOR
|
||||
layout (input_attachment_index = 0, set = 0, binding = 4) uniform usubpassInput shadow_stencil;
|
||||
@@ -324,6 +328,16 @@ vec4 colorClamp(vec4 col)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if pp_Palette == 1
|
||||
|
||||
vec4 palettePixel(sampler2D tex, vec2 coords)
|
||||
{
|
||||
vec4 c = vec4(texture(tex, coords).r * 255.0 / 1023.0 + pushConstants.palette_index, 0.5, 0.0, 0.0);
|
||||
return texture(palette, c.xy);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
setFragDepth();
|
||||
@@ -382,10 +396,18 @@ void main()
|
||||
highp vec4 texcol;
|
||||
#if pp_TwoVolumes == 1
|
||||
if (area1)
|
||||
texcol = texture(tex1, uv);
|
||||
#if pp_Palette == 0
|
||||
texcol = texture(tex1, uv);
|
||||
#else
|
||||
texcol = palettePixel(tex1, uv);
|
||||
#endif
|
||||
else
|
||||
#endif
|
||||
texcol = texture(tex0, uv);
|
||||
#if pp_Palette == 0
|
||||
texcol = texture(tex0, uv);
|
||||
#else
|
||||
texcol = palettePixel(tex0, uv);
|
||||
#endif
|
||||
#if pp_BumpMap == 1
|
||||
highp float s = PI / 2.0 * (texcol.a * 15.0 * 16.0 + texcol.r * 15.0) / 255.0;
|
||||
highp float r = 2.0 * PI * (texcol.g * 15.0 * 16.0 + texcol.b * 15.0) / 255.0;
|
||||
@@ -776,7 +798,8 @@ vk::UniqueShaderModule OITShaderManager::compileShader(const FragmentShaderParam
|
||||
strcpy(buf, OITShaderHeader);
|
||||
sprintf(buf + strlen(buf), OITFragmentShaderSource, (int)params.alphaTest, (int)params.insideClipTest, (int)params.useAlpha,
|
||||
(int)params.texture, (int)params.ignoreTexAlpha, params.shaderInstr, (int)params.offset, params.fog,
|
||||
(int)params.twoVolume, (int)params.gouraud, (int)params.bumpmap, (int)params.clamping, (int)params.pass);
|
||||
(int)params.twoVolume, (int)params.gouraud, (int)params.bumpmap, (int)params.clamping, (int)params.palette,
|
||||
(int)params.pass);
|
||||
return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, buf);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
bool bumpmap;
|
||||
bool clamping;
|
||||
bool twoVolume;
|
||||
bool palette;
|
||||
Pass pass;
|
||||
|
||||
u32 hash()
|
||||
@@ -58,7 +59,7 @@ public:
|
||||
| ((u32)texture << 3) | ((u32)ignoreTexAlpha << 4) | (shaderInstr << 5)
|
||||
| ((u32)offset << 7) | ((u32)fog << 8) | ((u32)gouraud << 10)
|
||||
| ((u32)bumpmap << 11) | ((u32)clamping << 12) | ((u32)twoVolume << 13)
|
||||
| ((int)pass << 14);
|
||||
| ((u32)palette << 14) | ((int)pass << 15);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -101,6 +102,18 @@ public:
|
||||
clearShader = compileClearShader();
|
||||
return *clearShader;
|
||||
}
|
||||
void Term()
|
||||
{
|
||||
vertexShaders.clear();
|
||||
fragmentShaders.clear();
|
||||
modVolVertexShader.reset();
|
||||
modVolShader.reset();
|
||||
trModVolShaders.clear();
|
||||
finalVertexShader.reset();
|
||||
finalAutosortShader.reset();
|
||||
finalSortedShader.reset();
|
||||
clearShader.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
|
||||
@@ -302,6 +302,7 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol
|
||||
params.texture = pp.pcw.Texture;
|
||||
params.trilinear = pp.pcw.Texture && pp.tsp.FilterMode > 1 && listType != ListType_Punch_Through && pp.tcw.MipMapped == 1;
|
||||
params.useAlpha = pp.tsp.UseAlpha;
|
||||
params.palette = BaseTextureCacheData::IsGpuHandledPaletted(pp.tsp, pp.tcw);
|
||||
vk::ShaderModule fragment_module = shaderManager->GetFragmentShader(params);
|
||||
|
||||
vk::PipelineShaderStageCreateInfo stages[] = {
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
this->perPolyLayout = perPolyLayout;
|
||||
|
||||
}
|
||||
void UpdateUniforms(vk::Buffer buffer, u32 vertexUniformOffset, u32 fragmentUniformOffset, vk::ImageView fogImageView)
|
||||
void UpdateUniforms(vk::Buffer buffer, u32 vertexUniformOffset, u32 fragmentUniformOffset, vk::ImageView fogImageView, vk::ImageView paletteImageView)
|
||||
{
|
||||
if (!perFrameDescSet)
|
||||
{
|
||||
@@ -62,6 +62,17 @@ public:
|
||||
imageInfo = { fogSampler, fogImageView, vk::ImageLayout::eShaderReadOnlyOptimal };
|
||||
writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perFrameDescSet, 2, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr));
|
||||
}
|
||||
if (paletteImageView)
|
||||
{
|
||||
TSP palTsp = {};
|
||||
palTsp.FilterMode = 0;
|
||||
palTsp.ClampU = 1;
|
||||
palTsp.ClampV = 1;
|
||||
vk::Sampler palSampler = samplerManager->GetSampler(palTsp);
|
||||
static vk::DescriptorImageInfo imageInfo;
|
||||
imageInfo = { palSampler, paletteImageView, vk::ImageLayout::eShaderReadOnlyOptimal };
|
||||
writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perFrameDescSet, 3, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr));
|
||||
}
|
||||
GetContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr);
|
||||
}
|
||||
|
||||
@@ -138,6 +149,7 @@ public:
|
||||
{ 0, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex }, // vertex uniforms
|
||||
{ 1, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eFragment }, // fragment uniforms
|
||||
{ 2, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment },// fog texture
|
||||
{ 3, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment },// palette texture
|
||||
};
|
||||
vk::DescriptorSetLayoutBinding perPolyBindings[] = {
|
||||
{ 0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment },// texture
|
||||
@@ -147,7 +159,7 @@ public:
|
||||
perPolyLayout = GetContext()->GetDevice().createDescriptorSetLayoutUnique(
|
||||
vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), ARRAY_SIZE(perPolyBindings), perPolyBindings));
|
||||
vk::DescriptorSetLayout layouts[] = { *perFrameLayout, *perPolyLayout };
|
||||
vk::PushConstantRange pushConstant(vk::ShaderStageFlagBits::eFragment, 0, 20);
|
||||
vk::PushConstantRange pushConstant(vk::ShaderStageFlagBits::eFragment, 0, 24);
|
||||
pipelineLayout = GetContext()->GetDevice().createPipelineLayoutUnique(
|
||||
vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), ARRAY_SIZE(layouts), layouts, 1, &pushConstant));
|
||||
}
|
||||
@@ -205,7 +217,7 @@ private:
|
||||
| (pp->tsp.ColorClamp << 11) | (pp->tsp.FogCtrl << 12) | (pp->tsp.SrcInstr << 14)
|
||||
| (pp->tsp.DstInstr << 17);
|
||||
hash |= (pp->isp.ZWriteDis << 20) | (pp->isp.CullMode << 21) | (pp->isp.DepthMode << 23);
|
||||
hash |= (u32)sortTriangles << 26;
|
||||
hash |= ((u32)sortTriangles << 26) | ((u32)BaseTextureCacheData::IsGpuHandledPaletted(pp->tsp, pp->tcw) << 27);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -51,8 +51,7 @@ void main()
|
||||
vtx_base = vec4(in_base) / 255.0;
|
||||
vtx_offs = vec4(in_offs) / 255.0;
|
||||
vtx_uv = in_uv;
|
||||
vec4 vpos = in_pos;
|
||||
vpos = uniformBuffer.normal_matrix * vpos;
|
||||
vec4 vpos = uniformBuffer.normal_matrix * in_pos;
|
||||
vpos.w = 1.0 / vpos.z;
|
||||
vpos.z = vpos.w;
|
||||
vpos.xy *= vpos.w;
|
||||
@@ -74,6 +73,7 @@ static const char FragmentShaderSource[] = R"(#version 450
|
||||
#define pp_BumpMap %d
|
||||
#define ColorClamping %d
|
||||
#define pp_TriLinear %d
|
||||
#define pp_Palette %d
|
||||
#define PI 3.1415926
|
||||
|
||||
layout (location = 0) out vec4 FragColor;
|
||||
@@ -99,11 +99,15 @@ layout (push_constant) uniform pushBlock
|
||||
{
|
||||
vec4 clipTest;
|
||||
float trilinearAlpha;
|
||||
float palette_index;
|
||||
} pushConstants;
|
||||
|
||||
#if pp_Texture == 1
|
||||
layout (set = 1, binding = 0) uniform sampler2D tex;
|
||||
#endif
|
||||
#if pp_Palette == 1
|
||||
layout (set = 0, binding = 3) uniform sampler2D palette;
|
||||
#endif
|
||||
|
||||
// Vertex input
|
||||
layout (location = 0) INTERPOLATION in lowp vec4 vtx_base;
|
||||
@@ -133,6 +137,16 @@ vec4 colorClamp(vec4 col)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if pp_Palette == 1
|
||||
|
||||
vec4 palettePixel(sampler2D tex, vec2 coords)
|
||||
{
|
||||
vec4 c = vec4(texture(tex, coords).r * 255.0 / 1023.0 + pushConstants.palette_index, 0.5, 0.0, 0.0);
|
||||
return texture(palette, c.xy);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
// Clip inside the box
|
||||
@@ -151,7 +165,11 @@ void main()
|
||||
#endif
|
||||
#if pp_Texture == 1
|
||||
{
|
||||
vec4 texcol = texture(tex, vtx_uv);
|
||||
#if pp_Palette == 0
|
||||
vec4 texcol = texture(tex, vtx_uv);
|
||||
#else
|
||||
vec4 texcol = palettePixel(tex, vtx_uv);
|
||||
#endif
|
||||
|
||||
#if pp_BumpMap == 1
|
||||
float s = PI / 2.0 * (texcol.a * 15.0 * 16.0 + texcol.r * 15.0) / 255.0;
|
||||
@@ -310,7 +328,7 @@ vk::UniqueShaderModule ShaderManager::compileShader(const FragmentShaderParams&
|
||||
|
||||
sprintf(buf, FragmentShaderSource, (int)params.alphaTest, (int)params.insideClipTest, (int)params.useAlpha, (int)params.texture,
|
||||
(int)params.ignoreTexAlpha, params.shaderInstr, (int)params.offset, params.fog, (int)params.gouraud,
|
||||
(int)params.bumpmap, (int)params.clamping, (int)params.trilinear);
|
||||
(int)params.bumpmap, (int)params.clamping, (int)params.trilinear, (int)params.palette);
|
||||
return ShaderCompiler::Compile(vk::ShaderStageFlagBits::eFragment, buf);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,13 +45,15 @@ struct FragmentShaderParams
|
||||
bool bumpmap;
|
||||
bool clamping;
|
||||
bool trilinear;
|
||||
bool palette;
|
||||
|
||||
u32 hash()
|
||||
{
|
||||
return ((u32)alphaTest) | ((u32)insideClipTest << 1) | ((u32)useAlpha << 2)
|
||||
| ((u32)texture << 3) | ((u32)ignoreTexAlpha << 4) | (shaderInstr << 5)
|
||||
| ((u32)offset << 7) | ((u32)fog << 8) | ((u32)gouraud << 10)
|
||||
| ((u32)bumpmap << 11) | ((u32)clamping << 12) | ((u32)trilinear << 13);
|
||||
| ((u32)bumpmap << 11) | ((u32)clamping << 12) | ((u32)trilinear << 13)
|
||||
| ((u32)palette << 14);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -101,6 +103,15 @@ public:
|
||||
quadFragmentShader = compileQuadFragmentShader();
|
||||
return *quadFragmentShader;
|
||||
}
|
||||
void Term()
|
||||
{
|
||||
vertexShaders.clear();
|
||||
fragmentShaders.clear();
|
||||
modVolVertexShader.reset();
|
||||
modVolShader.reset();
|
||||
quadVertexShader.reset();
|
||||
quadFragmentShader.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
|
||||
@@ -18,10 +18,12 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <math.h>
|
||||
#include "texture.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk::Format format, u32 mipmapLevels, vk::ImageLayout oldImageLayout, vk::ImageLayout newImageLayout)
|
||||
{
|
||||
vk::AccessFlags sourceAccessMask;
|
||||
@@ -145,7 +147,7 @@ void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk:
|
||||
|
||||
void Texture::UploadToGPU(int width, int height, u8 *data, bool mipmapped, bool mipmapsIncluded)
|
||||
{
|
||||
vk::Format format;
|
||||
vk::Format format = vk::Format::eUndefined;
|
||||
u32 dataSize = width * height * 2;
|
||||
switch (tex_type)
|
||||
{
|
||||
@@ -173,13 +175,13 @@ void Texture::UploadToGPU(int width, int height, u8 *data, bool mipmapped, bool
|
||||
u32 size = dataSize / 4;
|
||||
while (w)
|
||||
{
|
||||
dataSize += size;
|
||||
dataSize += ((size + 3) >> 2) << 2; // offset must be a multiple of 4
|
||||
size /= 4;
|
||||
w /= 2;
|
||||
}
|
||||
}
|
||||
bool isNew = true;
|
||||
if (width != extent.width || height != extent.height || format != this->format)
|
||||
if (width != (int)extent.width || height != (int)extent.height || format != this->format)
|
||||
Init(width, height, format, dataSize, mipmapped, mipmapsIncluded);
|
||||
else
|
||||
isNew = false;
|
||||
@@ -200,37 +202,39 @@ void Texture::Init(u32 width, u32 height, vk::Format format, u32 dataSize, bool
|
||||
== vk::FormatFeatureFlagBits::eSampledImage
|
||||
? vk::ImageTiling::eOptimal
|
||||
: vk::ImageTiling::eLinear;
|
||||
if (height <= 32
|
||||
&& dataSize / height <= 64
|
||||
&& !mipmapped
|
||||
&& (formatProperties.linearTilingFeatures & vk::FormatFeatureFlagBits::eSampledImage) == vk::FormatFeatureFlagBits::eSampledImage)
|
||||
imageTiling = vk::ImageTiling::eLinear;
|
||||
needsStaging = imageTiling != vk::ImageTiling::eLinear;
|
||||
vk::ImageLayout initialLayout;
|
||||
vk::MemoryPropertyFlags requirements;
|
||||
vk::ImageUsageFlags usageFlags = vk::ImageUsageFlagBits::eSampled;
|
||||
if (needsStaging)
|
||||
{
|
||||
stagingBufferData = std::unique_ptr<BufferData>(new BufferData(dataSize, vk::BufferUsageFlagBits::eTransferSrc));
|
||||
usageFlags |= vk::ImageUsageFlagBits::eTransferDst;
|
||||
initialLayout = vk::ImageLayout::eUndefined;
|
||||
requirements = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
}
|
||||
else
|
||||
{
|
||||
verify((formatProperties.linearTilingFeatures & vk::FormatFeatureFlagBits::eSampledImage) == vk::FormatFeatureFlagBits::eSampledImage);
|
||||
initialLayout = vk::ImageLayout::ePreinitialized;
|
||||
requirements = vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible;
|
||||
}
|
||||
if (mipmapped && !mipmapsIncluded)
|
||||
usageFlags |= vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
|
||||
CreateImage(imageTiling, usageFlags, initialLayout, requirements, vk::ImageAspectFlagBits::eColor);
|
||||
CreateImage(imageTiling, usageFlags, initialLayout, vk::ImageAspectFlagBits::eColor);
|
||||
}
|
||||
|
||||
void Texture::CreateImage(vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::ImageLayout initialLayout,
|
||||
vk::MemoryPropertyFlags memoryProperties, vk::ImageAspectFlags aspectMask)
|
||||
vk::ImageAspectFlags aspectMask)
|
||||
{
|
||||
vk::ImageCreateInfo imageCreateInfo(vk::ImageCreateFlags(), vk::ImageType::e2D, format, vk::Extent3D(extent, 1), mipmapLevels, 1,
|
||||
vk::SampleCountFlagBits::e1, tiling, usage,
|
||||
vk::SharingMode::eExclusive, 0, nullptr, initialLayout);
|
||||
image = device.createImageUnique(imageCreateInfo);
|
||||
|
||||
VmaAllocationCreateInfo allocCreateInfo = { VmaAllocationCreateFlags(), VmaMemoryUsage::VMA_MEMORY_USAGE_GPU_ONLY };
|
||||
VmaAllocationCreateInfo allocCreateInfo = { VmaAllocationCreateFlags(), needsStaging ? VmaMemoryUsage::VMA_MEMORY_USAGE_GPU_ONLY : VmaMemoryUsage::VMA_MEMORY_USAGE_CPU_TO_GPU };
|
||||
if (!needsStaging)
|
||||
allocCreateInfo.flags = VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
||||
allocation = VulkanContext::Instance()->GetAllocator().AllocateForImage(*image, allocCreateInfo);
|
||||
@@ -245,8 +249,8 @@ void Texture::SetImage(u32 srcSize, void *srcData, bool isNew, bool genMipmaps)
|
||||
verify((bool)commandBuffer);
|
||||
commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit));
|
||||
|
||||
// if (!isNew && !needsStaging)
|
||||
// setImageLayout(commandBuffer, image.get(), format, mipmapLevels, vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eUndefined);
|
||||
if (!isNew && !needsStaging)
|
||||
setImageLayout(commandBuffer, image.get(), format, mipmapLevels, vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eGeneral);
|
||||
|
||||
void* data;
|
||||
if (needsStaging)
|
||||
@@ -255,6 +259,39 @@ void Texture::SetImage(u32 srcSize, void *srcData, bool isNew, bool genMipmaps)
|
||||
data = allocation.MapMemory();
|
||||
verify(data != nullptr);
|
||||
|
||||
if (mipmapLevels > 1 && !genMipmaps && tex_type != TextureType::_8888)
|
||||
{
|
||||
// Each mipmap level must start at a 4-byte boundary
|
||||
u8 *src = (u8 *)srcData;
|
||||
u8 *dst = (u8 *)data;
|
||||
for (u32 i = 0; i < mipmapLevels; i++)
|
||||
{
|
||||
const u32 size = (1 << (2 * i)) * 2;
|
||||
memcpy(dst, src, size);
|
||||
dst += ((size + 3) >> 2) << 2;
|
||||
src += size;
|
||||
}
|
||||
}
|
||||
else if (!needsStaging)
|
||||
{
|
||||
vk::SubresourceLayout layout = device.getImageSubresourceLayout(*image, vk::ImageSubresource(vk::ImageAspectFlagBits::eColor, 0, 0));
|
||||
if (layout.size != srcSize)
|
||||
{
|
||||
u8 *src = (u8 *)srcData;
|
||||
u8 *dst = (u8 *)data;
|
||||
u32 srcSz = extent.width * 2;
|
||||
if (tex_type == TextureType::_8888)
|
||||
srcSz *= 2;
|
||||
else if (tex_type == TextureType::_8)
|
||||
srcSz /= 2;
|
||||
u8 * const srcEnd = src + srcSz * extent.height;
|
||||
for (; src < srcEnd; src += srcSz, dst += layout.rowPitch)
|
||||
memcpy(dst, src, srcSz);
|
||||
}
|
||||
else
|
||||
memcpy(data, srcData, srcSize);
|
||||
}
|
||||
else
|
||||
memcpy(data, srcData, srcSize);
|
||||
|
||||
if (needsStaging)
|
||||
@@ -267,12 +304,13 @@ void Texture::SetImage(u32 srcSize, void *srcData, bool isNew, bool genMipmaps)
|
||||
if (mipmapLevels > 1 && !genMipmaps)
|
||||
{
|
||||
vk::DeviceSize bufferOffset = 0;
|
||||
for (int i = 0; i < mipmapLevels; i++)
|
||||
for (u32 i = 0; i < mipmapLevels; i++)
|
||||
{
|
||||
vk::BufferImageCopy copyRegion(bufferOffset, 1 << i, 1 << i, vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, mipmapLevels - i - 1, 0, 1),
|
||||
vk::Offset3D(0, 0, 0), vk::Extent3D(1 << i, 1 << i, 1));
|
||||
commandBuffer.copyBufferToImage(stagingBufferData->buffer.get(), image.get(), vk::ImageLayout::eTransferDstOptimal, copyRegion);
|
||||
bufferOffset += (1 << (2 * i)) * (tex_type == TextureType::_8888 ? 4 : 2);
|
||||
const u32 size = (1 << (2 * i)) * (tex_type == TextureType::_8888 ? 4 : 2);
|
||||
bufferOffset += ((size + 3) >> 2) << 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -292,7 +330,8 @@ void Texture::SetImage(u32 srcSize, void *srcData, bool isNew, bool genMipmaps)
|
||||
GenerateMipmaps();
|
||||
else
|
||||
// If we can use the linear tiled image as a texture, just do it
|
||||
setImageLayout(commandBuffer, image.get(), format, mipmapLevels, vk::ImageLayout::ePreinitialized, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
setImageLayout(commandBuffer, image.get(), format, mipmapLevels, isNew ? vk::ImageLayout::ePreinitialized : vk::ImageLayout::eGeneral,
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
}
|
||||
commandBuffer.end();
|
||||
}
|
||||
@@ -305,7 +344,7 @@ void Texture::GenerateMipmaps()
|
||||
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
*image, vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
|
||||
|
||||
for (int i = 1; i < mipmapLevels; i++)
|
||||
for (u32 i = 1; i < mipmapLevels; i++)
|
||||
{
|
||||
// Transition previous mipmap level from dst optimal/preinit to src optimal
|
||||
barrier.subresourceRange.baseMipLevel = i - 1;
|
||||
|
||||
+25
-15
@@ -19,17 +19,23 @@
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include "vulkan_context.h"
|
||||
#include "buffer.h"
|
||||
#include "rend/TexCache.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk::Format format, u32 mipmapLevels, vk::ImageLayout oldImageLayout, vk::ImageLayout newImageLayout);
|
||||
|
||||
struct Texture : BaseTextureCacheData
|
||||
class Texture : public BaseTextureCacheData
|
||||
{
|
||||
public:
|
||||
void UploadToGPU(int width, int height, u8 *data, bool mipmapped, bool mipmapsIncluded = false) override;
|
||||
u64 GetIntId() { return (u64)reinterpret_cast<uintptr_t>(this); }
|
||||
std::string GetId() override { char s[20]; sprintf(s, "%p", this); return s; }
|
||||
@@ -47,7 +53,7 @@ private:
|
||||
void Init(u32 width, u32 height, vk::Format format ,u32 dataSize, bool mipmapped, bool mipmapsIncluded);
|
||||
void SetImage(u32 size, void *data, bool isNew, bool genMipmaps);
|
||||
void CreateImage(vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::ImageLayout initialLayout,
|
||||
vk::MemoryPropertyFlags memoryProperties, vk::ImageAspectFlags aspectMask);
|
||||
vk::ImageAspectFlags aspectMask);
|
||||
void GenerateMipmaps();
|
||||
|
||||
vk::Format format = vk::Format::eUndefined;
|
||||
@@ -96,6 +102,10 @@ public:
|
||||
false, vk::CompareOp::eNever,
|
||||
0.0f, 256.0f, vk::BorderColor::eFloatOpaqueBlack)))).first->second.get();
|
||||
}
|
||||
void Term()
|
||||
{
|
||||
samplers.clear();
|
||||
}
|
||||
static const u32 TSP_Mask = 0x7ef00;
|
||||
|
||||
private:
|
||||
@@ -106,7 +116,7 @@ class FramebufferAttachment
|
||||
{
|
||||
public:
|
||||
FramebufferAttachment(vk::PhysicalDevice physicalDevice, vk::Device device)
|
||||
: physicalDevice(physicalDevice), device(device), format(vk::Format::eUndefined)
|
||||
: format(vk::Format::eUndefined), physicalDevice(physicalDevice), device(device)
|
||||
{}
|
||||
void Init(u32 width, u32 height, vk::Format format, vk::ImageUsageFlags usage);
|
||||
void Reset() { image.reset(); imageView.reset(); }
|
||||
@@ -134,13 +144,6 @@ private:
|
||||
class TextureCache : public BaseTextureCache<Texture>
|
||||
{
|
||||
public:
|
||||
Texture *getTextureCacheData(TSP tsp, TCW tcw)
|
||||
{
|
||||
Texture *texture = BaseTextureCache<Texture>::getTextureCacheData(tsp, tcw);
|
||||
inFlightTextures[currentIndex].insert(texture);
|
||||
return texture;
|
||||
}
|
||||
|
||||
void SetCurrentIndex(int index) {
|
||||
if (currentIndex < inFlightTextures.size())
|
||||
std::for_each(inFlightTextures[currentIndex].begin(), inFlightTextures[currentIndex].end(),
|
||||
@@ -155,8 +158,15 @@ public:
|
||||
|
||||
bool IsInFlight(Texture *texture)
|
||||
{
|
||||
return std::any_of(inFlightTextures.begin(), inFlightTextures.end(),
|
||||
[texture](const std::unordered_set<Texture *>& set) { return set.find(texture) != set.end(); });
|
||||
for (u32 i = 0; i < inFlightTextures.size(); i++)
|
||||
if (i != currentIndex && inFlightTextures[i].find(texture) != inFlightTextures[i].end())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetInFlight(Texture *texture)
|
||||
{
|
||||
inFlightTextures[currentIndex].insert(texture);
|
||||
}
|
||||
|
||||
void DestroyLater(Texture *texture)
|
||||
@@ -183,5 +193,5 @@ private:
|
||||
std::vector<std::vector<vk::UniqueImage>> trashedImages;
|
||||
std::vector<std::vector<Allocation>> trashedMem;
|
||||
std::vector<std::vector<std::unique_ptr<BufferData>>> trashedBuffers;
|
||||
int currentIndex = 0;
|
||||
u32 currentIndex = 0;
|
||||
};
|
||||
@@ -41,7 +41,7 @@ static const vk::CompareOp depthOps[] =
|
||||
vk::CompareOp::eAlways, //7 Always
|
||||
};
|
||||
|
||||
static vk::BlendFactor getBlendFactor(u32 instr, bool src)
|
||||
static inline vk::BlendFactor getBlendFactor(u32 instr, bool src)
|
||||
{
|
||||
switch (instr) {
|
||||
case 0: // zero
|
||||
@@ -78,6 +78,6 @@ static inline u32 findMemoryType(vk::PhysicalDeviceMemoryProperties const& memor
|
||||
}
|
||||
typeBits >>= 1;
|
||||
}
|
||||
verify(typeIndex != ~0);
|
||||
verify(typeIndex != u32(~0));
|
||||
return typeIndex;
|
||||
}
|
||||
@@ -331,20 +331,24 @@ void VulkanContext::PresentFrame(vk::Image image, vk::ImageView imageView, vk::O
|
||||
|
||||
void VulkanContext::Term()
|
||||
{
|
||||
if (device && pipelineCache)
|
||||
{
|
||||
std::vector<u8> cacheData = device.getPipelineCacheData(*pipelineCache);
|
||||
if (!cacheData.empty())
|
||||
if (device)
|
||||
{
|
||||
device.waitIdle();
|
||||
if (pipelineCache)
|
||||
{
|
||||
std::string cachePath = get_writable_data_path(PipelineCacheFileName);
|
||||
FILE *f = fopen(cachePath.c_str(), "wb");
|
||||
if (f != nullptr)
|
||||
std::vector<u8> cacheData = device.getPipelineCacheData(*pipelineCache);
|
||||
if (!cacheData.empty())
|
||||
{
|
||||
(void)fwrite(&cacheData[0], 1, cacheData.size(), f);
|
||||
fclose(f);
|
||||
std::string cachePath = get_writable_data_path(PipelineCacheFileName);
|
||||
FILE *f = fopen(cachePath.c_str(), "wb");
|
||||
if (f != nullptr)
|
||||
{
|
||||
(void)fwrite(&cacheData[0], 1, cacheData.size(), f);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ShaderCompiler::Term();
|
||||
descriptorPool.reset();
|
||||
allocator.Term();
|
||||
|
||||
@@ -21,121 +21,39 @@
|
||||
#include <memory>
|
||||
#include <math.h>
|
||||
#include "vulkan.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
#include "commandpool.h"
|
||||
#include "vulkan_renderer.h"
|
||||
#include "drawer.h"
|
||||
#include "shaders.h"
|
||||
#include "quad.h"
|
||||
#include "vmu.h"
|
||||
|
||||
void co_dc_yield();
|
||||
|
||||
class VulkanRenderer : public Renderer
|
||||
class VulkanRenderer final : public BaseVulkanRenderer
|
||||
{
|
||||
public:
|
||||
bool Init() override
|
||||
{
|
||||
DEBUG_LOG(RENDERER, "VulkanRenderer::Init");
|
||||
texCommandPool.Init();
|
||||
|
||||
textureDrawer.Init(&samplerManager, &shaderManager, &textureCache);
|
||||
textureDrawer.SetCommandPool(&texCommandPool);
|
||||
|
||||
screenDrawer.Init(&samplerManager, &shaderManager);
|
||||
screenDrawer.SetCommandPool(&texCommandPool);
|
||||
quadPipeline.Init(&shaderManager, screenDrawer.GetRenderPass());
|
||||
vmus = std::unique_ptr<VulkanOSD>(new VulkanOSD());
|
||||
vmus->Init(&quadPipeline);
|
||||
BaseInit(screenDrawer.GetRenderPass());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Resize(int w, int h) override
|
||||
{
|
||||
texCommandPool.Init();
|
||||
screenDrawer.Init(&samplerManager, &shaderManager);
|
||||
quadPipeline.Init(&shaderManager, screenDrawer.GetRenderPass());
|
||||
vmus->Init(&quadPipeline);
|
||||
BaseInit(screenDrawer.GetRenderPass());
|
||||
}
|
||||
|
||||
void Term() override
|
||||
{
|
||||
DEBUG_LOG(RENDERER, "VulkanRenderer::Term");
|
||||
GetContext()->WaitIdle();
|
||||
vmus.reset();
|
||||
quadPipeline.Term();
|
||||
textureCache.Clear();
|
||||
fogTexture = nullptr;
|
||||
texCommandPool.Term();
|
||||
framebufferTextures.clear();
|
||||
}
|
||||
|
||||
bool RenderFramebuffer()
|
||||
{
|
||||
if (FB_R_SIZE.fb_x_size == 0 || FB_R_SIZE.fb_y_size == 0)
|
||||
return false;
|
||||
|
||||
PixelBuffer<u32> pb;
|
||||
int width;
|
||||
int height;
|
||||
ReadFramebuffer(pb, width, height);
|
||||
|
||||
if (framebufferTextures.size() != GetContext()->GetSwapChainSize())
|
||||
framebufferTextures.resize(GetContext()->GetSwapChainSize());
|
||||
std::unique_ptr<Texture>& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
|
||||
if (!curTexture)
|
||||
{
|
||||
curTexture = std::unique_ptr<Texture>(new Texture());
|
||||
curTexture->tex_type = TextureType::_8888;
|
||||
curTexture->tcw.full = 0;
|
||||
curTexture->tsp.full = 0;
|
||||
curTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
curTexture->SetDevice(GetContext()->GetDevice());
|
||||
}
|
||||
curTexture->SetCommandBuffer(texCommandPool.Allocate());
|
||||
curTexture->UploadToGPU(width, height, (u8*)pb.data(), false);
|
||||
curTexture->SetCommandBuffer(nullptr);
|
||||
texCommandPool.EndFrame();
|
||||
|
||||
GetContext()->PresentFrame(curTexture->GetImage(), curTexture->GetImageView(), { 640, 480 });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Process(TA_context* ctx) override
|
||||
{
|
||||
texCommandPool.BeginFrame();
|
||||
textureCache.SetCurrentIndex(texCommandPool.GetIndex());
|
||||
|
||||
if (!ctx->rend.isRTT)
|
||||
vmus->PrepareOSD(&texCommandPool);
|
||||
|
||||
if (ctx->rend.isRenderFramebuffer)
|
||||
{
|
||||
return RenderFramebuffer();
|
||||
}
|
||||
|
||||
ctx->rend_inuse.Lock();
|
||||
|
||||
if (KillTex)
|
||||
textureCache.Clear();
|
||||
|
||||
bool result = ta_parse_vdrc(ctx);
|
||||
|
||||
textureCache.CollectCleanup();
|
||||
|
||||
if (ctx->rend.Overrun)
|
||||
WARN_LOG(PVR, "ERROR: TA context overrun");
|
||||
|
||||
result = result && !ctx->rend.Overrun;
|
||||
|
||||
if (result)
|
||||
CheckFogTexture();
|
||||
|
||||
if (!result)
|
||||
texCommandPool.EndFrame();
|
||||
|
||||
return result;
|
||||
samplerManager.Term();
|
||||
BaseVulkanRenderer::Term();
|
||||
}
|
||||
|
||||
bool Render() override
|
||||
@@ -149,7 +67,7 @@ public:
|
||||
else
|
||||
drawer = &screenDrawer;
|
||||
|
||||
drawer->Draw(fogTexture.get());
|
||||
drawer->Draw(fogTexture.get(), paletteTexture.get());
|
||||
|
||||
if (!pvrrc.isRTT)
|
||||
vmus->DrawOSD(screenDrawer.GetCurrentCommandBuffer(), vk::Extent2D(screen_width, screen_height));
|
||||
@@ -159,76 +77,11 @@ public:
|
||||
return !pvrrc.isRTT;
|
||||
}
|
||||
|
||||
void Present() override
|
||||
{
|
||||
co_dc_yield();
|
||||
}
|
||||
|
||||
virtual u64 GetTexture(TSP tsp, TCW tcw) override
|
||||
{
|
||||
Texture* tf = textureCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
if (tf->IsNew())
|
||||
{
|
||||
tf->Create();
|
||||
tf->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
tf->SetDevice(GetContext()->GetDevice());
|
||||
}
|
||||
|
||||
//update if needed
|
||||
if (tf->NeedsUpdate())
|
||||
{
|
||||
textureCache.DestroyLater(tf);
|
||||
tf->SetCommandBuffer(texCommandPool.Allocate());
|
||||
tf->Update();
|
||||
}
|
||||
else if (tf->IsCustomTextureAvailable())
|
||||
{
|
||||
textureCache.DestroyLater(tf);
|
||||
tf->SetCommandBuffer(texCommandPool.Allocate());
|
||||
tf->CheckCustomTexture();
|
||||
}
|
||||
tf->SetCommandBuffer(nullptr);
|
||||
|
||||
return tf->GetIntId();
|
||||
}
|
||||
|
||||
private:
|
||||
VulkanContext *GetContext() const { return VulkanContext::Instance(); }
|
||||
|
||||
void CheckFogTexture()
|
||||
{
|
||||
if (!fogTexture)
|
||||
{
|
||||
fogTexture = std::unique_ptr<Texture>(new Texture());
|
||||
fogTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
fogTexture->SetDevice(GetContext()->GetDevice());
|
||||
fogTexture->tex_type = TextureType::_8;
|
||||
fog_needs_update = true;
|
||||
}
|
||||
if (!fog_needs_update)
|
||||
return;
|
||||
fog_needs_update = false;
|
||||
u8 texData[256];
|
||||
MakeFogTexture(texData);
|
||||
fogTexture->SetCommandBuffer(texCommandPool.Allocate());
|
||||
|
||||
fogTexture->UploadToGPU(128, 2, texData, false);
|
||||
|
||||
fogTexture->SetCommandBuffer(nullptr);
|
||||
}
|
||||
|
||||
std::unique_ptr<Texture> fogTexture;
|
||||
CommandPool texCommandPool;
|
||||
|
||||
SamplerManager samplerManager;
|
||||
ShaderManager shaderManager;
|
||||
ScreenDrawer screenDrawer;
|
||||
TextureDrawer textureDrawer;
|
||||
std::vector<std::unique_ptr<Texture>> framebufferTextures;
|
||||
QuadPipeline quadPipeline;
|
||||
TextureCache textureCache;
|
||||
std::unique_ptr<VulkanOSD> vmus;
|
||||
};
|
||||
|
||||
Renderer* rend_Vulkan()
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
Copyright 2020 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast 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.
|
||||
|
||||
Flycast 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 Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "vulkan.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
#include "hw/pvr/ta.h"
|
||||
#include "commandpool.h"
|
||||
#include "pipeline.h"
|
||||
#include "vmu.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
void co_dc_yield();
|
||||
|
||||
class BaseVulkanRenderer : public Renderer
|
||||
{
|
||||
public:
|
||||
virtual void Term() override
|
||||
{
|
||||
shaderManager.Term();
|
||||
vmus.reset();
|
||||
quadPipeline.Term();
|
||||
textureCache.Clear();
|
||||
fogTexture = nullptr;
|
||||
paletteTexture = nullptr;
|
||||
texCommandPool.Term();
|
||||
framebufferTextures.clear();
|
||||
}
|
||||
|
||||
virtual u64 GetTexture(TSP tsp, TCW tcw) override
|
||||
{
|
||||
Texture* tf = textureCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
if (tf->IsNew())
|
||||
{
|
||||
tf->Create();
|
||||
tf->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
tf->SetDevice(GetContext()->GetDevice());
|
||||
}
|
||||
|
||||
//update if needed
|
||||
if (tf->NeedsUpdate())
|
||||
{
|
||||
// This kills performance when a frame is skipped and lots of texture updated each frame
|
||||
//if (textureCache.IsInFlight(tf))
|
||||
// textureCache.DestroyLater(tf);
|
||||
tf->SetCommandBuffer(texCommandPool.Allocate());
|
||||
tf->Update();
|
||||
}
|
||||
else if (tf->IsCustomTextureAvailable())
|
||||
{
|
||||
textureCache.DestroyLater(tf);
|
||||
tf->SetCommandBuffer(texCommandPool.Allocate());
|
||||
tf->CheckCustomTexture();
|
||||
}
|
||||
tf->SetCommandBuffer(nullptr);
|
||||
textureCache.SetInFlight(tf);
|
||||
|
||||
return tf->GetIntId();
|
||||
}
|
||||
|
||||
virtual bool Process(TA_context* ctx) override
|
||||
{
|
||||
texCommandPool.BeginFrame();
|
||||
textureCache.SetCurrentIndex(texCommandPool.GetIndex());
|
||||
|
||||
if (ctx->rend.isRenderFramebuffer)
|
||||
return RenderFramebuffer();
|
||||
|
||||
ctx->rend_inuse.Lock();
|
||||
|
||||
if (KillTex)
|
||||
textureCache.Clear();
|
||||
|
||||
bool result = ta_parse_vdrc(ctx);
|
||||
|
||||
textureCache.CollectCleanup();
|
||||
|
||||
if (result)
|
||||
{
|
||||
CheckFogTexture();
|
||||
CheckPaletteTexture();
|
||||
}
|
||||
else
|
||||
texCommandPool.EndFrame();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Present() override
|
||||
{
|
||||
co_dc_yield();
|
||||
}
|
||||
|
||||
protected:
|
||||
VulkanContext *GetContext() const { return VulkanContext::Instance(); }
|
||||
|
||||
bool BaseInit(vk::RenderPass renderPass, int subpass = 0)
|
||||
{
|
||||
texCommandPool.Init();
|
||||
quadPipeline.Init(&shaderManager, renderPass, subpass);
|
||||
vmus = std::unique_ptr<VulkanOSD>(new VulkanOSD());
|
||||
vmus->Init(&quadPipeline);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderFramebuffer()
|
||||
{
|
||||
if (FB_R_SIZE.fb_x_size == 0 || FB_R_SIZE.fb_y_size == 0)
|
||||
return false;
|
||||
|
||||
PixelBuffer<u32> pb;
|
||||
int width;
|
||||
int height;
|
||||
ReadFramebuffer(pb, width, height);
|
||||
|
||||
if (framebufferTextures.size() != GetContext()->GetSwapChainSize())
|
||||
framebufferTextures.resize(GetContext()->GetSwapChainSize());
|
||||
std::unique_ptr<Texture>& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
|
||||
if (!curTexture)
|
||||
{
|
||||
curTexture = std::unique_ptr<Texture>(new Texture());
|
||||
curTexture->tex_type = TextureType::_8888;
|
||||
curTexture->tcw.full = 0;
|
||||
curTexture->tsp.full = 0;
|
||||
curTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
curTexture->SetDevice(GetContext()->GetDevice());
|
||||
}
|
||||
curTexture->SetCommandBuffer(texCommandPool.Allocate());
|
||||
curTexture->UploadToGPU(width, height, (u8*)pb.data(), false);
|
||||
curTexture->SetCommandBuffer(nullptr);
|
||||
texCommandPool.EndFrame();
|
||||
|
||||
GetContext()->PresentFrame(curTexture->GetImage(), curTexture->GetImageView(), { 640, 480 });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CheckFogTexture()
|
||||
{
|
||||
if (!fogTexture)
|
||||
{
|
||||
fogTexture = std::unique_ptr<Texture>(new Texture());
|
||||
fogTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
fogTexture->SetDevice(GetContext()->GetDevice());
|
||||
fogTexture->tex_type = TextureType::_8;
|
||||
fog_needs_update = true;
|
||||
}
|
||||
if (!fog_needs_update)
|
||||
return;
|
||||
fog_needs_update = false;
|
||||
u8 texData[256];
|
||||
MakeFogTexture(texData);
|
||||
fogTexture->SetCommandBuffer(texCommandPool.Allocate());
|
||||
|
||||
fogTexture->UploadToGPU(128, 2, texData, false);
|
||||
|
||||
fogTexture->SetCommandBuffer(nullptr);
|
||||
}
|
||||
|
||||
void CheckPaletteTexture()
|
||||
{
|
||||
if (!paletteTexture)
|
||||
{
|
||||
paletteTexture = std::unique_ptr<Texture>(new Texture());
|
||||
paletteTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
paletteTexture->SetDevice(GetContext()->GetDevice());
|
||||
paletteTexture->tex_type = TextureType::_8888;
|
||||
palette_updated = true;
|
||||
}
|
||||
if (!palette_updated)
|
||||
return;
|
||||
palette_updated = false;
|
||||
|
||||
paletteTexture->SetCommandBuffer(texCommandPool.Allocate());
|
||||
|
||||
paletteTexture->UploadToGPU(1024, 1, (u8 *)palette32_ram, false);
|
||||
|
||||
paletteTexture->SetCommandBuffer(nullptr);
|
||||
}
|
||||
|
||||
ShaderManager shaderManager;
|
||||
std::unique_ptr<Texture> fogTexture;
|
||||
std::unique_ptr<Texture> paletteTexture;
|
||||
CommandPool texCommandPool;
|
||||
std::vector<std::unique_ptr<Texture>> framebufferTextures;
|
||||
TextureCache textureCache;
|
||||
QuadPipeline quadPipeline;
|
||||
std::unique_ptr<VulkanOSD> vmus;
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user