GS/OpenGL: Use shader+draw for CopyRectConv

This commit is contained in:
Connor McLaughlin 2021-11-18 20:06:20 +10:00 committed by lightningterror
parent f36d5fdbdf
commit 8ea24d9ff9
3 changed files with 100 additions and 87 deletions

View File

@ -1292,28 +1292,28 @@ GSTexture* GSDeviceOGL::CopyOffscreen(GSTexture* src, const GSVector4& sRect, in
}
// Copy a sub part of texture (same as below but force a conversion)
void GSDeviceOGL::CopyRectConv(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, bool at_origin)
void GSDeviceOGL::BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2i& dsize, bool at_origin, bool linear)
{
ASSERT(sTex && dTex);
if (!(sTex && dTex))
return;
const GLuint sid = static_cast<GSTextureOGL*>(sTex)->GetID();
GL_PUSH(format("CopyRectConv from %d", sid).c_str());
const GLuint& sid = static_cast<GSTextureOGL*>(sTex)->GetID();
const GLuint& did = static_cast<GSTextureOGL*>(dTex)->GetID();
// NOTE: This previously used glCopyTextureSubImage2D(), but this appears to leak memory in
// the loading screens of Evolution Snowboarding in Intel/NVIDIA drivers.
glDisable(GL_SCISSOR_TEST);
GL_PUSH(format("CopyRectConv from %d to %d", sid, did).c_str());
const GSVector4 float_r(r);
dTex->CommitRegion(GSVector2i(r.z, r.w));
BeginScene();
m_shader->BindPipeline(m_convert.ps[ShaderConvert_COPY]);
OMSetDepthStencilState(m_convert.dss);
OMSetBlendState();
OMSetColorMaskState();
PSSetShaderResource(0, sTex);
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt);
DrawStretchRect(float_r / (GSVector4(sTex->GetSize()).xyxy()), float_r, dsize);
EndScene();
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sid, 0);
if (at_origin)
glCopyTextureSubImage2D(did, GL_TEX_LEVEL_0, 0, 0, r.x, r.y, r.width(), r.height());
else
glCopyTextureSubImage2D(did, GL_TEX_LEVEL_0, r.x, r.y, r.x, r.y, r.width(), r.height());
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glEnable(GL_SCISSOR_TEST);
}
// Copy a sub part of a texture into another
@ -1373,7 +1373,7 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
}
const bool draw_in_depth = (ps == m_convert.ps[ShaderConvert_RGBA8_TO_FLOAT32] || ps == m_convert.ps[ShaderConvert_RGBA8_TO_FLOAT24] ||
ps == m_convert.ps[ShaderConvert_RGBA8_TO_FLOAT16] || ps == m_convert.ps[ShaderConvert_RGB5A1_TO_FLOAT16]);
ps == m_convert.ps[ShaderConvert_RGBA8_TO_FLOAT16] || ps == m_convert.ps[ShaderConvert_RGB5A1_TO_FLOAT16]);
// Performance optimization. It might be faster to use a framebuffer blit for standard case
// instead to emulate it with shader
@ -1413,6 +1413,40 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
// ************************************
// Flip y axis only when we render in the backbuffer
// By default everything is render in the wrong order (ie dx).
// 1/ consistency between several pass rendering (interlace)
// 2/ in case some GS code expect thing in dx order.
// Only flipping the backbuffer is transparent (I hope)...
GSVector4 flip_sr = sRect;
if (static_cast<GSTextureOGL*>(dTex)->IsBackbuffer())
{
flip_sr.y = sRect.w;
flip_sr.w = sRect.y;
}
// ************************************
// Texture
// ************************************
PSSetShaderResource(0, sTex);
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt);
// ************************************
// Draw
// ************************************
dTex->CommitRegion(GSVector2i((int)dRect.z + 1, (int)dRect.w + 1));
DrawStretchRect(flip_sr, dRect, ds);
// ************************************
// End
// ************************************
EndScene();
}
void GSDeviceOGL::DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds)
{
// Original code from DX
const float left = dRect.x * 2 / ds.x - 1.0f;
const float right = dRect.z * 2 / ds.x - 1.0f;
@ -1426,47 +1460,17 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
const float bottom = -1.0f + dRect.w * 2 / ds.y;
#endif
// Flip y axis only when we render in the backbuffer
// By default everything is render in the wrong order (ie dx).
// 1/ consistency between several pass rendering (interlace)
// 2/ in case some GS code expect thing in dx order.
// Only flipping the backbuffer is transparent (I hope)...
GSVector4 flip_sr = sRect;
if (static_cast<GSTextureOGL*>(dTex)->IsBackbuffer())
{
flip_sr.y = sRect.w;
flip_sr.w = sRect.y;
}
GSVertexPT1 vertices[] =
{
{GSVector4(left , top , 0.0f, 0.0f) , GSVector2(flip_sr.x , flip_sr.y)} ,
{GSVector4(right , top , 0.0f, 0.0f) , GSVector2(flip_sr.z , flip_sr.y)} ,
{GSVector4(left , bottom, 0.0f, 0.0f) , GSVector2(flip_sr.x , flip_sr.w)} ,
{GSVector4(right , bottom, 0.0f, 0.0f) , GSVector2(flip_sr.z , flip_sr.w)} ,
{GSVector4(left , top , 0.0f, 0.0f) , GSVector2(sRect.x , sRect.y)} ,
{GSVector4(right , top , 0.0f, 0.0f) , GSVector2(sRect.z , sRect.y)} ,
{GSVector4(left , bottom, 0.0f, 0.0f) , GSVector2(sRect.x , sRect.w)} ,
{GSVector4(right , bottom, 0.0f, 0.0f) , GSVector2(sRect.z , sRect.w)} ,
};
IASetVertexBuffer(vertices, 4);
IASetPrimitiveTopology(GL_TRIANGLE_STRIP);
// ************************************
// Texture
// ************************************
PSSetShaderResource(0, sTex);
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt);
// ************************************
// Draw
// ************************************
dTex->CommitRegion(GSVector2i((int)dRect.z + 1, (int)dRect.w + 1));
DrawPrimitive();
// ************************************
// End
// ************************************
EndScene();
}
void GSDeviceOGL::RenderOsd(GSTexture* dt)

View File

@ -575,6 +575,8 @@ private:
u16 ConvertBlendEnum(u16 generic) final;
void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds);
public:
GSShaderOGL* m_shader;
@ -606,7 +608,10 @@ public:
GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, int format = 0, int ps_shader = 0) final;
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r) final;
void CopyRectConv(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, bool at_origin);
// BlitRect *does* mess with GL state, be sure to re-bind.
void BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2i& dsize, bool at_origin, bool linear);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, int shader = 0, bool linear = true) final;
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, GLuint ps, bool linear = true);
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha) final;

View File

@ -1214,20 +1214,18 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
}
// DATE setup, no DATE_GL45 please
const GSVector4i commitRect = ComputeBoundingBox(rtscale, rtsize);
if (DATE && !DATE_GL45)
{
const GSVector4i dRect = ComputeBoundingBox(rtscale, rtsize);
// Reduce the quantity of clean function
glScissor(dRect.x, dRect.y, dRect.width(), dRect.height());
GLState::scissor = dRect;
glScissor(commitRect.x, commitRect.y, commitRect.width(), commitRect.height());
GLState::scissor = commitRect;
// Must be done here to avoid any GL state pertubation (clear function...)
// Create an r32ui image that will containt primitive ID
if (DATE_GL42)
{
dev->InitPrimDateTexture(rt, dRect);
dev->InitPrimDateTexture(rt, commitRect);
}
else if (DATE_one)
{
@ -1235,7 +1233,7 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
}
else
{
const GSVector4 src = GSVector4(dRect) / GSVector4(rtsize.x, rtsize.y).xyxy();
const GSVector4 src = GSVector4(commitRect) / GSVector4(rtsize.x, rtsize.y).xyxy();
const GSVector4 dst = src * 2.0f - 1.0f;
GSVertexPT1 vertices[] =
@ -1366,6 +1364,36 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
m_ps_sel.atst = ps_atst;
}
// rs
const GSVector4& hacked_scissor = m_channel_shuffle ? GSVector4(0, 0, 1024, 1024) : m_context->scissor.in;
const GSVector4i scissor = GSVector4i(GSVector4(rtscale).xyxy() * hacked_scissor).rintersect(GSVector4i(rtsize).zwxy());
if (rt)
rt->CommitRegion(GSVector2i(commitRect.z, commitRect.w));
if (ds)
ds->CommitRegion(GSVector2i(commitRect.z, commitRect.w));
if (m_ps_sel.hdr)
{
hdr_rt = dev->CreateTexture(rtsize.x, rtsize.y, GL_RGBA32F);
dev->OMSetRenderTargets(hdr_rt, ds, &scissor);
// save blend state, since BlitRect destroys it
const bool old_blend = GLState::blend;
hdr_rt->CommitRegion(GSVector2i(commitRect.z, commitRect.w));
dev->BlitRect(rt, commitRect, rt->GetSize(), false, false);
if (old_blend)
{
GLState::blend = old_blend;
glEnable(GL_BLEND);
}
}
else
{
dev->OMSetRenderTargets(rt, ds, &scissor);
}
if (tex)
{
EmulateTextureSampler(tex);
@ -1412,10 +1440,6 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
}
}
// rs
const GSVector4& hacked_scissor = m_channel_shuffle ? GSVector4(0, 0, 1024, 1024) : m_context->scissor.in;
const GSVector4i scissor = GSVector4i(GSVector4(rtscale).xyxy() * hacked_scissor).rintersect(GSVector4i(rtsize).zwxy());
SetupIA(sx, sy);
dev->OMSetColorMaskState(m_om_csel);
@ -1425,14 +1449,6 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
dev->SetupPipeline(m_vs_sel, m_gs_sel, m_ps_sel);
const GSVector4i commitRect = ComputeBoundingBox(rtscale, rtsize);
if (rt)
rt->CommitRegion(GSVector2i(commitRect.z, commitRect.w));
if (ds)
ds->CommitRegion(GSVector2i(commitRect.z, commitRect.w));
if (DATE_GL42)
{
GL_PUSH("Date GL42");
@ -1461,19 +1477,8 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
// Be sure that first pass is finished !
dev->Barrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
}
if (m_ps_sel.hdr)
{
hdr_rt = dev->CreateTexture(rtsize.x, rtsize.y, GL_RGBA32F);
dev->CopyRectConv(rt, hdr_rt, ComputeBoundingBox(rtscale, rtsize), false);
dev->OMSetRenderTargets(hdr_rt, ds, &scissor);
}
else
{
dev->OMSetRenderTargets(rt, ds, &scissor);
dev->OMSetRenderTargets(hdr_rt ? hdr_rt : rt, ds, &scissor);
}
if (ate_first_pass)
@ -1560,9 +1565,8 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour
// vertices will be overwritten. Trust me you don't want to do that.
if (hdr_rt)
{
const GSVector4 dRect(ComputeBoundingBox(rtscale, rtsize));
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
dev->StretchRect(hdr_rt, sRect, rt, dRect, ShaderConvert_MOD_256, false);
const GSVector4 sRect = GSVector4(commitRect) / GSVector4(rtsize.x, rtsize.y).xyxy();
dev->StretchRect(hdr_rt, sRect, rt, GSVector4(commitRect), ShaderConvert_MOD_256, false);
dev->Recycle(hdr_rt);
}