pvr: object list is sometimes shared between op and tr modvols

Region tile object list pointers can be identical for op and tr modvols,
in which case tr modvols should be drawn using op modvols geometry.
Used by crazy taxi 1/2, alien front online, daytona usa and probably
many others.
Issue #717
This commit is contained in:
Flyinghead 2022-08-22 12:38:04 +02:00
parent 71e9420929
commit 85b8c599c4
8 changed files with 84 additions and 100 deletions

View File

@ -168,6 +168,7 @@ struct tad_context
struct RenderPass {
bool autosort;
bool z_clear;
bool mv_op_tr_shared; // Use opaque modvols geometry for translucent modvols
u32 op_count;
u32 mvo_count;
u32 pt_count;

View File

@ -1122,9 +1122,8 @@ private:
}
};
static bool ClearZBeforePass(int pass_number);
static bool UsingAutoSort(int pass_number);
static void getRegionTileClipping(u32& xmin, u32& xmax, u32& ymin, u32& ymax);
static void getRegionSettings(int passNumber, RenderPass& pass);
//
// Check if a vertex has huge x,y,z values or negative z
@ -1343,8 +1342,7 @@ static bool ta_parse_vdrc(TA_context* ctx)
render_pass->tr_count, mergeTranslucent, &vd_rc);
tr_poly_count = render_pass->tr_count;
render_pass->mvo_tr_count = vd_rc.global_param_mvo_tr.used();
render_pass->autosort = UsingAutoSort(pass);
render_pass->z_clear = ClearZBeforePass(pass);
getRegionSettings(pass, *render_pass);
}
childCtx = childCtx->nextContext;
pass++;
@ -1769,6 +1767,27 @@ void FillBGP(TA_context* ctx)
cv[3].v = max_v;
}
static void getRegionTileAddrAndSize(u32& address, u32& size)
{
address = REGION_BASE;
const bool type1_tile = ((FPU_PARAM_CFG >> 21) & 1) == 0;
size = (type1_tile ? 5 : 6) * 4;
bool empty_first_region = true;
for (int i = type1_tile ? 4 : 5; i > 0; i--)
if ((pvr_read32p<u32>(address + i * 4) & 0x80000000) == 0)
{
empty_first_region = false;
break;
}
if (empty_first_region)
address += size;
RegionArrayTile tile;
tile.full = pvr_read32p<u32>(address);
if (tile.PreSort)
// Windows CE weirdness
size = 6 * 4;
}
static void getRegionTileClipping(u32& xmin, u32& xmax, u32& ymin, u32& ymax)
{
xmin = 20;
@ -1776,18 +1795,9 @@ static void getRegionTileClipping(u32& xmin, u32& xmax, u32& ymin, u32& ymax)
ymin = 15;
ymax = 0;
u32 addr = REGION_BASE;
const bool type1_tile = ((FPU_PARAM_CFG >> 21) & 1) == 0;
int tile_size = (type1_tile ? 5 : 6) * 4;
bool empty_first_region = true;
for (int i = type1_tile ? 4 : 5; i > 0; i--)
if ((pvr_read32p<u32>(addr + i * 4) & 0x80000000) == 0)
{
empty_first_region = false;
break;
}
if (empty_first_region)
addr += tile_size;
u32 addr;
u32 tile_size;
getRegionTileAddrAndSize(addr, tile_size);
RegionArrayTile tile;
do {
@ -1796,9 +1806,6 @@ static void getRegionTileClipping(u32& xmin, u32& xmax, u32& ymin, u32& ymax)
xmax = std::max(xmax, tile.X);
ymin = std::min(ymin, tile.Y);
ymax = std::max(ymax, tile.Y);
if (type1_tile && tile.PreSort)
// Windows CE weirdness
tile_size = 6 * 4;
addr += tile_size;
} while (!tile.LastRegion);
@ -1808,72 +1815,14 @@ static void getRegionTileClipping(u32& xmin, u32& xmax, u32& ymin, u32& ymax)
ymax *= 32;
}
static RegionArrayTile getRegionTile(int pass_number)
{
u32 addr = REGION_BASE;
const bool type1_tile = ((FPU_PARAM_CFG >> 21) & 1) == 0;
int tile_size = (type1_tile ? 5 : 6) * 4;
bool empty_first_region = true;
for (int i = type1_tile ? 4 : 5; i > 0; i--)
if ((pvr_read32p<u32>(addr + i * 4) & 0x80000000) == 0)
{
empty_first_region = false;
break;
}
if (empty_first_region)
addr += tile_size;
RegionArrayTile tile;
tile.full = pvr_read32p<u32>(addr);
if (type1_tile && tile.PreSort)
// Windows CE weirdness
tile_size = 6 * 4;
tile.full = pvr_read32p<u32>(addr + pass_number * tile_size);
return tile;
}
static bool UsingAutoSort(int pass_number)
{
if (((FPU_PARAM_CFG >> 21) & 1) == 0)
// Type 1 region header type
return ((ISP_FEED_CFG & 1) == 0);
else
{
// Type 2
RegionArrayTile tile = getRegionTile(pass_number);
return !tile.PreSort;
}
}
static bool ClearZBeforePass(int pass_number)
{
RegionArrayTile tile = getRegionTile(pass_number);
return !tile.NoZClear;
}
int getTAContextAddresses(u32 *addresses)
{
u32 addr = REGION_BASE;
const bool type1_tile = ((FPU_PARAM_CFG >> 21) & 1) == 0;
int tile_size = (type1_tile ? 5 : 6) * 4;
bool empty_first_region = true;
for (int i = type1_tile ? 4 : 5; i > 0; i--)
if ((pvr_read32p<u32>(addr + i * 4) & 0x80000000) == 0)
{
empty_first_region = false;
break;
}
if (empty_first_region)
addr += tile_size;
u32 addr;
u32 tile_size;
getRegionTileAddrAndSize(addr, tile_size);
RegionArrayTile tile;
tile.full = pvr_read32p<u32>(addr);
if (type1_tile && tile.PreSort)
// Windows CE weirdness
tile_size = 6 * 4;
u32 x = tile.X;
u32 y = tile.Y;
u32 count = 0;
@ -1906,6 +1855,25 @@ int getTAContextAddresses(u32 *addresses)
return count;
}
static void getRegionSettings(int passNumber, RenderPass& pass)
{
u32 addr;
u32 tileSize;
getRegionTileAddrAndSize(addr, tileSize);
addr += passNumber * tileSize;
RegionArrayTile tile;
tile.full = pvr_read32p<u32>(addr);
if (((FPU_PARAM_CFG >> 21) & 1) == 0)
// Type 1 region header type
pass.autosort = (ISP_FEED_CFG & 1) == 0;
else
// Type 2
pass.autosort = !tile.PreSort;
pass.z_clear = !tile.NoZClear;
pass.mv_op_tr_shared = pvr_read32p<u32>(addr + 8) == pvr_read32p<u32>(addr + 16);
}
void rend_context::newRenderPass()
{
RenderPass pass;
@ -1914,7 +1882,6 @@ void rend_context::newRenderPass()
pass.pt_count = global_param_pt.used();
pass.mvo_count = global_param_mvo.used();
pass.mvo_tr_count = global_param_mvo_tr.used();
pass.autosort = UsingAutoSort(render_passes.used());
pass.z_clear = ClearZBeforePass(render_passes.used());
getRegionSettings(render_passes.used(), pass);
*render_passes.Append() = pass;
}

View File

@ -364,7 +364,7 @@ struct DX11OITRenderer : public DX11Renderer
}
template<bool Transparent>
void drawModVols(int first, int count)
void drawModVols(int first, int count, const ModifierVolumeParam *modVolParams)
{
if (count == 0 || pvrrc.modtrig.used() == 0 || !config::ModifierVolumes)
return;
@ -378,14 +378,14 @@ struct DX11OITRenderer : public DX11Renderer
deviceContext->PSSetShader(shaders.getModVolShader(), nullptr, 0);
deviceContext->RSSetScissorRects(1, &scissorRect);
ModifierVolumeParam* params = Transparent ? &pvrrc.global_param_mvo_tr.head()[first] : &pvrrc.global_param_mvo.head()[first];
const ModifierVolumeParam *params = &modVolParams[first];
int mod_base = -1;
const float *curMVMat = nullptr;
const float *curProjMat = nullptr;
for (int cmv = 0; cmv < count; cmv++)
{
ModifierVolumeParam& param = params[cmv];
const ModifierVolumeParam& param = params[cmv];
u32 mv_mode = param.isp.DepthMode;
@ -533,7 +533,9 @@ struct DX11OITRenderer : public DX11Renderer
u32 tr_count = current_pass.tr_count - previous_pass.tr_count;
u32 mvo_count = current_pass.mvo_count - previous_pass.mvo_count;
DEBUG_LOG(RENDERER, "Render pass %d OP %d PT %d TR %d MV %d Tr MV %d autosort %d", render_pass + 1,
op_count, pt_count, tr_count, mvo_count, current_pass.mvo_tr_count - previous_pass.mvo_tr_count, current_pass.autosort);
op_count, pt_count, tr_count, mvo_count,
current_pass.mv_op_tr_shared ? mvo_count : current_pass.mvo_tr_count - previous_pass.mvo_tr_count,
current_pass.autosort);
//
// PASS 1: Geometry pass to update depth and stencil
@ -547,7 +549,7 @@ struct DX11OITRenderer : public DX11Renderer
drawList<ListType_Opaque, false, DX11OITShaders::Depth>(pvrrc.global_param_op, previous_pass.op_count, op_count);
drawList<ListType_Punch_Through, false, DX11OITShaders::Depth>(pvrrc.global_param_pt, previous_pass.pt_count, pt_count);
drawModVols<false>(previous_pass.mvo_count, mvo_count);
drawModVols<false>(previous_pass.mvo_count, mvo_count, pvrrc.global_param_mvo.head());
//
// PASS 2: Render OP and PT to opaque render target
@ -580,8 +582,13 @@ struct DX11OITRenderer : public DX11Renderer
ID3D11ShaderResourceView *p = nullptr;
deviceContext->PSSetShaderResources(4, 1, &p);
if (!theDX11Context.isIntel())
{
// Intel Iris Plus 640 just crashes
drawModVols<true>(previous_pass.mvo_tr_count, current_pass.mvo_tr_count - previous_pass.mvo_tr_count);
if (current_pass.mv_op_tr_shared)
drawModVols<true>(previous_pass.mvo_count, mvo_count, pvrrc.global_param_mvo.head());
else
drawModVols<true>(previous_pass.mvo_tr_count, current_pass.mvo_tr_count - previous_pass.mvo_tr_count, pvrrc.global_param_mvo_tr.head());
}
}
else
{

View File

@ -456,7 +456,7 @@ static void abufferDrawQuad()
glCheck();
}
void DrawTranslucentModVols(int first, int count)
void DrawTranslucentModVols(int first, int count, bool useOpaqueGeom)
{
if (count == 0 || pvrrc.modtrig.used() == 0)
return;
@ -478,7 +478,7 @@ void DrawTranslucentModVols(int first, int count)
glCheck();
ModifierVolumeParam* params = &pvrrc.global_param_mvo_tr.head()[first];
ModifierVolumeParam* params = useOpaqueGeom ? &pvrrc.global_param_mvo.head()[first] : &pvrrc.global_param_mvo_tr.head()[first];
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT);

View File

@ -170,7 +170,7 @@ void initABuffer();
void termABuffer();
void reshapeABuffer(int width, int height);
void renderABuffer();
void DrawTranslucentModVols(int first, int count);
void DrawTranslucentModVols(int first, int count, bool useOpaqueGeom);
void checkOverflowAndReset();
extern GLuint stencilTexId;

View File

@ -532,7 +532,7 @@ void gl4DrawStrips(GLuint output_fbo, int width, int height)
current_pass.pt_count - previous_pass.pt_count,
current_pass.tr_count - previous_pass.tr_count,
current_pass.mvo_count - previous_pass.mvo_count,
current_pass.mvo_tr_count - previous_pass.mvo_tr_count,
current_pass.mv_op_tr_shared ? current_pass.mvo_count - previous_pass.mvo_count : current_pass.mvo_tr_count - previous_pass.mvo_tr_count,
current_pass.autosort);
glBindVertexArray(gl4.vbo.getMainVAO());
@ -645,7 +645,10 @@ void gl4DrawStrips(GLuint output_fbo, int width, int height)
if (config::ModifierVolumes)
{
SetBaseClipping();
DrawTranslucentModVols(previous_pass.mvo_tr_count, current_pass.mvo_tr_count - previous_pass.mvo_tr_count);
if (current_pass.mv_op_tr_shared)
DrawTranslucentModVols(previous_pass.mvo_count, current_pass.mvo_count - previous_pass.mvo_count, true);
else
DrawTranslucentModVols(previous_pass.mvo_tr_count, current_pass.mvo_tr_count - previous_pass.mvo_tr_count, false);
}
// Rebind the depth/stencil texture to the framebuffer

View File

@ -128,7 +128,7 @@ void OITDrawer::DrawList(const vk::CommandBuffer& cmdBuffer, u32 listType, bool
}
template<bool Translucent>
void OITDrawer::DrawModifierVolumes(const vk::CommandBuffer& cmdBuffer, int first, int count)
void OITDrawer::DrawModifierVolumes(const vk::CommandBuffer& cmdBuffer, int first, int count, const ModifierVolumeParam *modVolParams)
{
if (count == 0 || pvrrc.modtrig.used() == 0 || !config::ModifierVolumes)
return;
@ -137,14 +137,14 @@ void OITDrawer::DrawModifierVolumes(const vk::CommandBuffer& cmdBuffer, int firs
cmdBuffer.bindVertexBuffers(0, 1, &buffer, &offsets.modVolOffset);
SetScissor(cmdBuffer, baseScissor);
ModifierVolumeParam* params = Translucent ? &pvrrc.global_param_mvo_tr.head()[first] : &pvrrc.global_param_mvo.head()[first];
const ModifierVolumeParam *params = &modVolParams[first];
int mod_base = -1;
vk::Pipeline pipeline;
for (int cmv = 0; cmv < count; cmv++)
{
ModifierVolumeParam& param = params[cmv];
const ModifierVolumeParam& param = params[cmv];
if (param.count == 0)
continue;
@ -322,7 +322,8 @@ bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
current_pass.pt_count - previous_pass.pt_count,
current_pass.tr_count - previous_pass.tr_count,
current_pass.mvo_count - previous_pass.mvo_count,
current_pass.mvo_tr_count - previous_pass.mvo_tr_count, current_pass.autosort);
current_pass.mv_op_tr_shared ? current_pass.mvo_count - previous_pass.mvo_count : current_pass.mvo_tr_count - previous_pass.mvo_tr_count,
current_pass.autosort);
// Reset the pixel counter
oitBuffers->ResetPixelCounter(cmdBuffer);
@ -351,7 +352,7 @@ bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
DrawList(cmdBuffer, ListType_Opaque, false, Pass::Depth, pvrrc.global_param_op, previous_pass.op_count, current_pass.op_count);
DrawList(cmdBuffer, ListType_Punch_Through, false, Pass::Depth, pvrrc.global_param_pt, previous_pass.pt_count, current_pass.pt_count);
DrawModifierVolumes<false>(cmdBuffer, previous_pass.mvo_count, current_pass.mvo_count - previous_pass.mvo_count);
DrawModifierVolumes<false>(cmdBuffer, previous_pass.mvo_count, current_pass.mvo_count - previous_pass.mvo_count, pvrrc.global_param_mvo.head());
// Color subpass
cmdBuffer.nextSubpass(vk::SubpassContents::eInline);
@ -398,7 +399,12 @@ bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
}
// Tr modifier volumes
if (GetContext()->GetVendorID() != VulkanContext::VENDOR_QUALCOMM) // Adreno bug
DrawModifierVolumes<true>(cmdBuffer, previous_pass.mvo_tr_count, current_pass.mvo_tr_count - previous_pass.mvo_tr_count);
{
if (current_pass.mv_op_tr_shared)
DrawModifierVolumes<true>(cmdBuffer, previous_pass.mvo_count, current_pass.mvo_count - previous_pass.mvo_count, pvrrc.global_param_mvo.head());
else
DrawModifierVolumes<true>(cmdBuffer, previous_pass.mvo_tr_count, current_pass.mvo_tr_count - previous_pass.mvo_tr_count, pvrrc.global_param_mvo_tr.head());
}
vk::Pipeline pipeline = pipelineManager->GetFinalPipeline();
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline);

View File

@ -118,7 +118,7 @@ private:
void DrawList(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, Pass pass,
const List<PolyParam>& polys, u32 first, u32 last);
template<bool Translucent>
void DrawModifierVolumes(const vk::CommandBuffer& cmdBuffer, int first, int count);
void DrawModifierVolumes(const vk::CommandBuffer& cmdBuffer, int first, int count, const ModifierVolumeParam *modVolParams);
void UploadMainBuffer(const OITDescriptorSets::VertexShaderUniforms& vertexUniforms,
const OITDescriptorSets::FragmentShaderUniforms& fragmentUniforms);