gsdx ogl: use an HLE shader to avoid upscaling line in ICO

ICO uses a depth of field effect for the fog. Depth is extracted
into the alpha channel of a texture. And then used as blending factor.
You need a 1:1 texture/pixel mapping otherwise you will line at boundaries.

In order to extract the DoF, ICO moves the depth buffer around the GS
memory. Memory moves are implemented in the not-scaled world. It means
that we can't have the above 1:1 ratio. And we don't know anymore that
data are coming from the current depth buffer.

The solution: I reused an HLE channel shader to read the depth buffer directly.
This way I have the guarantee that pixel/depth are aligned.

Close #1816
This commit is contained in:
Gregory Hainaut 2017-03-12 17:26:20 +01:00
parent 1a768ca438
commit a3efc77255
1 changed files with 34 additions and 0 deletions

View File

@ -1494,6 +1494,40 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
// Always bind the RT. This way special effect can use it.
dev->PSSetShaderResource(3, rt);
if (m_game.title == CRC::ICO) {
GSVertex* v = &m_vertex.buff[0];
if (tex && m_vt.m_primclass == GS_SPRITE_CLASS && m_vertex.next == 2 && PRIM->ABE && // Blend texture
v[1].U == 8200 && v[1].V == 7176 && // at display resolution 512x448
tex->m_TEX0.PSM == PSM_PSMT8H) { // i.e. read the alpha channel of a 32 bits texture
// Note potentially we can limit to TBP0:0x2800
// Depth buffer was moved so GSdx will invalide it which means a
// downscale. ICO uses the MSB depth bits as the texture alpha
// channel. However this depth of field effect requires
// texel:pixel mapping accuraccy.
//
// Use an HLE shader to sample depth directly as the alpha channel
GL_INS("ICO sample depth as alpha");
m_require_full_barrier = true;
// Extract the depth as palette index
m_ps_sel.depth_fmt = 1;
m_ps_sel.channel = 3;
dev->PSSetShaderResource(4, ds);
// We need the palette to convert the depth to the correct alpha value.
if (!tex->m_palette) {
tex->m_palette = m_dev->CreateTexture(256, 1);
const uint32* clut = m_mem.m_clut;
int pal = GSLocalMemory::m_psm[tex->m_TEX0.PSM].pal;
tex->m_palette->Update(GSVector4i(0, 0, pal, 1), clut, pal * sizeof(clut[0]));
tex->m_initpalette = false;
dev->PSSetShaderResource(1, tex->m_palette);
}
}
}
// rs
const GSVector4& hacked_scissor = m_channel_shuffle ? GSVector4(0, 0, 1024, 1024) : m_context->scissor.in;
GSVector4i scissor = GSVector4i(GSVector4(rtscale).xyxy() * hacked_scissor).rintersect(GSVector4i(rtsize).zwxy());