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:
Flyinghead committed 2020-07-11 19:19:58 +02:00
1 parent 0e10e86ea9
commit c2f735809c
32 files changed
+1070 -767

No files matched your search

+83 -38
View File
@@ -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
View File
@@ -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)
{
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+6 -6
View File
@@ -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);
+27 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+9 -5
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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:
+37 -25
View File
@@ -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
+1 -1
View File
@@ -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;
+2 -1
View File
@@ -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[] = {
+19 -5
View File
@@ -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;
}
+12 -161
View File
@@ -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(&regularShaderManager, 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(&regularShaderManager, 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()
+28 -5
View File
@@ -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);
}
+14 -1
View File
@@ -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>
+1
View File
@@ -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[] = {
+15 -3
View File
@@ -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;
}
+22 -4
View File
@@ -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);
}
+12 -1
View File
@@ -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>
+55 -16
View File
@@ -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
View File
@@ -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;
};
+2 -2
View File
@@ -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;
}
+14 -10
View File
@@ -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();
+7 -154
View File
@@ -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()
+208
View File
@@ -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;
};