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:
parent
71e9420929
commit
85b8c599c4
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue