diff --git a/plugins/GSdx/GSDeviceOGL.cpp b/plugins/GSdx/GSDeviceOGL.cpp index 6b7d8b82b0..a5b45123a7 100644 --- a/plugins/GSdx/GSDeviceOGL.cpp +++ b/plugins/GSdx/GSDeviceOGL.cpp @@ -103,6 +103,23 @@ GSDeviceOGL::~GSDeviceOGL() // Clean various opengl allocation glDeleteProgramPipelines(1, &m_pipeline); glDeleteFramebuffers(1, &m_fbo); + + // Delete HW FX + delete m_vs_cb; + delete m_ps_cb; + glDeleteSamplers(1, &m_rt_ss); + delete m_vb; + + for (auto it : m_vs) glDeleteProgram(it.second); + for (auto it : m_gs) glDeleteProgram(it.second); + for (auto it : m_ps) glDeleteProgram(it.second); + for (auto it : m_ps_ss) glDeleteSamplers(1, &it.second); + m_vs.clear(); + m_gs.clear(); + m_ps.clear(); + m_ps_ss.clear(); + m_om_dss.clear(); + m_om_bs.clear(); } GSTexture* GSDeviceOGL::CreateSurface(int type, int w, int h, bool msaa, int format) @@ -291,6 +308,50 @@ bool GSDeviceOGL::Create(GSWnd* wnd) rd.AntialiasedLineEnable = false; #endif + // TODO Later + // **************************************************************** + // fxaa (bonus) + // **************************************************************** + // FIXME need to define FXAA_GLSL_130 for the shader + // FIXME need to manually set the index... + // FIXME need dofxaa interface too + // m_fxaa.cb = new GSUniformBufferOGL(3, sizeof(FXAAConstantBuffer)); + //CompileShaderFromSource("fxaa.fx", format("ps_main", i), GL_FRAGMENT_SHADER, &m_fxaa.ps); + + // **************************************************************** + // date + // **************************************************************** + + m_date.dss = new GSDepthStencilOGL(); + m_date.dss->m_stencil_enable = true; + m_date.dss->m_stencil_func = GL_ALWAYS; + m_date.dss->m_stencil_spass_dpass_op = GL_REPLACE; + //memset(&dsd, 0, sizeof(dsd)); + + //dsd.DepthEnable = false; + //dsd.StencilEnable = true; + //dsd.StencilReadMask = 1; + //dsd.StencilWriteMask = 1; + + //dsd.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + //dsd.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + //dsd.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + //dsd.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + + //m_dev->CreateDepthStencilState(&dsd, &m_date.dss); + + // FIXME are the blend state really empty + m_date.bs = new GSBlendStateOGL(); + //D3D11_BLEND_DESC blend; + + //memset(&blend, 0, sizeof(blend)); + + //m_dev->CreateBlendState(&blend, &m_date.bs); + + // **************************************************************** + // HW renderer shader + // **************************************************************** + CreateTextureFX(); // **************************************************************** // Finish window setup and backbuffer @@ -392,50 +453,7 @@ bool GSDeviceOGL::Create(GSWnd* wnd) } #endif - // TODO Later - // **************************************************************** - // fxaa (bonus) - // **************************************************************** - // FIXME need to define FXAA_GLSL_130 for the shader - // FIXME need to manually set the index... - // FIXME need dofxaa interface too - // m_fxaa.cb = new GSUniformBufferOGL(3, sizeof(FXAAConstantBuffer)); - //CompileShaderFromSource("fxaa.fx", format("ps_main", i), GL_FRAGMENT_SHADER, &m_fxaa.ps); - - // **************************************************************** - // date - // **************************************************************** - - m_date.dss = new GSDepthStencilOGL(); - m_date.dss->m_stencil_enable = true; - m_date.dss->m_stencil_func = GL_ALWAYS; - m_date.dss->m_stencil_spass_dpass_op = GL_REPLACE; - //memset(&dsd, 0, sizeof(dsd)); - - //dsd.DepthEnable = false; - //dsd.StencilEnable = true; - //dsd.StencilReadMask = 1; - //dsd.StencilWriteMask = 1; - - //dsd.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - //dsd.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - //dsd.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - //dsd.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - - //m_dev->CreateDepthStencilState(&dsd, &m_date.dss); - - // FIXME are the blend state really empty - m_date.bs = new GSBlendStateOGL(); - //D3D11_BLEND_DESC blend; - - //memset(&blend, 0, sizeof(blend)); - - //m_dev->CreateBlendState(&blend, &m_date.bs); - - // **************************************************************** - // HW renderer shader - // **************************************************************** - CreateTextureFX(); + return true; } bool GSDeviceOGL::Reset(int w, int h) @@ -472,6 +490,9 @@ void GSDeviceOGL::ClearRenderTarget(GSTexture* t, const GSVector4& c) OMSetFBO(0); //glClearBufferfv(GL_COLOR, GL_LEFT, c.v); glClearBufferfv(GL_COLOR, 0, c.v); + // code for the old interface + // glClearColor(c.x, c.y, c.z, c.w); + // glClear(GL_COLOR_BUFFER_BIT); } else { // FIXME I need to clarify this FBO attachment stuff // I would like to avoid FBO for a basic clean operation diff --git a/plugins/GSdx/GSTextureFXOGL.cpp b/plugins/GSdx/GSTextureFXOGL.cpp new file mode 100644 index 0000000000..28a02602eb --- /dev/null +++ b/plugins/GSdx/GSTextureFXOGL.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2011-2011 Gregory hainaut + * Copyright (C) 2007-2009 Gabest + * + * This Program 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, or (at your option) + * any later version. + * + * This Program 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSDeviceOGL.h" +#include "GSTables.h" + +void GSDeviceOGL::CreateTextureFX() +{ + m_vs_cb = new GSUniformBufferOGL(4, sizeof(VSConstantBuffer)); + m_ps_cb = new GSUniformBufferOGL(5, sizeof(PSConstantBuffer)); + + glGenSamplers(1, &m_rt_ss); + // FIXME, seem to have no difference between sampler !!! + m_palette_ss = m_rt_ss; + + glSamplerParameteri(m_rt_ss, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glSamplerParameteri(m_rt_ss, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glSamplerParameteri(m_rt_ss, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_rt_ss, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_rt_ss, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // FIXME which value for GL_TEXTURE_MIN_LOD + glSamplerParameteri(m_rt_ss, GL_TEXTURE_MAX_LOD, FLT_MAX); + // FIXME: seems there is 2 possibility in opengl + // DX: sd.ComparisonFunc = D3D11_COMPARISON_NEVER; + // glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); + // FIXME: need ogl extension sd.MaxAnisotropy = 16; + + //{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + //{"TEXCOORD", 1, DXGI_FORMAT_R32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + //float2 t : TEXCOORD0; + //float q : TEXCOORD1; + // + //{"POSITION", 0, DXGI_FORMAT_R16G16_UINT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0}, + //{"POSITION", 1, DXGI_FORMAT_R32_UINT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0}, + //uint2 p : POSITION0; + //uint z : POSITION1; + // + //{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, + //{"COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0}, + //float4 c : COLOR0; + //float4 f : COLOR1; + + GSInputLayout vert_format[6] = + { + // FIXME + {0 , 2 , GL_FLOAT , GL_FALSE , sizeof(GSVertexHW11) , (const GLvoid*)(0) } , + {1 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof(GSVertexHW11) , (const GLvoid*)(8) } , + {2 , 1 , GL_FLOAT , GL_FALSE , sizeof(GSVertexHW11) , (const GLvoid*)(12) } , + {3 , 2 , GL_UNSIGNED_SHORT , GL_FALSE , sizeof(GSVertexHW11) , (const GLvoid*)(16) } , + {4 , 1 , GL_UNSIGNED_INT , GL_FALSE , sizeof(GSVertexHW11) , (const GLvoid*)(20) } , + // note: there is a 32 bits pad + {5 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof(GSVertexHW11) , (const GLvoid*)(28) } , + }; + m_vb = new GSVertexBufferState(sizeof(GSVertexHW11), vert_format, countof(vert_format)); +} + +void GSDeviceOGL::SetupIA(const void* vertices, int count, GLenum prim) +{ + IASetVertexState(m_vb); + IASetVertexBuffer(vertices, count); + IASetPrimitiveTopology(prim); +} + +void GSDeviceOGL::SetupVS(VSSelector sel, const VSConstantBuffer* cb) +{ + // ************************************************************* + // Static + // ************************************************************* + auto i = m_vs.find(sel); + + if(i == m_vs.end()) + { + std::string macro = format("#define VS_BPPZ %d\n", sel.bppz) + + format("#define VS_TME %d\n", sel.tme) + + format("#define VS_FST %d\n", sel.fst) + + format("#define VS_RTCOPY %d\n", sel.rtcopy); + + GLuint vs; + CompileShaderFromSource("tfx.glsl", "vs_main", GL_VERTEX_SHADER, &vs, macro); + + m_vs[sel] = vs; + i = m_vs.find(sel); + } + + // ************************************************************* + // Dynamic + // ************************************************************* + if(m_vs_cb_cache.Update(cb)) + { + SetUniformBuffer(m_vs_cb); + m_vs_cb->upload(&cb); + } + + VSSetShader(i->second); +} + +void GSDeviceOGL::SetupGS(GSSelector sel) +{ + // ************************************************************* + // Static + // ************************************************************* + GLuint gs = 0; + if(sel.prim > 0 && (sel.iip == 0 || sel.prim == 3)) { + auto i = m_gs.find(sel); + + if(i == m_gs.end()) { + std::string macro = format("#define GS_IIP %d\n", sel.iip) + + format("#define GS_PRIM %d\n", sel.prim); + + CompileShaderFromSource("tfx.glsl", "gs_main", GL_GEOMETRY_SHADER, &gs, macro); + + m_gs[sel] = gs; + } else { + gs = i->second; + } + } + // ************************************************************* + // Dynamic + // ************************************************************* + GSSetShader(gs); +} + +void GSDeviceOGL::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel) +{ + // ************************************************************* + // Static + // ************************************************************* + GLuint ps; + auto i = m_ps.find(sel); + + if (i == m_ps.end()) + { + std::string macro = format("#define PS_FST %d\n", sel.fst) + + format("#define PS_WMS %d\n", sel.wms) + + format("#define PS_WMT %d\n", sel.wmt) + + format("#define PS_FMT %d\n", sel.fmt) + + format("#define PS_AEM %d\n", sel.aem) + + format("#define PS_TFX %d\n", sel.tfx) + + format("#define PS_TCC %d\n", sel.tcc) + + format("#define PS_ATST %d\n", sel.atst) + + format("#define PS_FOG %d\n", sel.fog) + + format("#define PS_CLR1 %d\n", sel.clr1) + + format("#define PS_FBA %d\n", sel.fba) + + format("#define PS_AOUT %d\n", sel.aout) + + format("#define PS_LTF %d\n", sel.ltf) + + format("#define PS_COLCLIP %d\n", sel.colclip) + + format("#define PS_DATE %d\n", sel.date); + + CompileShaderFromSource("tfx.glsl", "ps_main", GL_FRAGMENT_SHADER, &ps, macro); + + m_ps[sel] = ps; + i = m_ps.find(sel); + } else { + ps = i->second; + } + + // ************************************************************* + // Dynamic + // ************************************************************* + if(m_ps_cb_cache.Update(cb)) + { + SetUniformBuffer(m_ps_cb); + m_ps_cb->upload(&cb); + } + + GLuint ss0, ss1; + ss0 = ss1 = 0; + if(sel.tfx != 4) + { + if(!(sel.fmt < 3 && sel.wms < 3 && sel.wmt < 3)) + { + ssel.ltf = 0; + } + + auto i = m_ps_ss.find(ssel); + + if(i != m_ps_ss.end()) + { + ss0 = i->second; + } + else + { + // ************************************************************* + // Static + // ************************************************************* + glGenSamplers(1, &ss0); + if (ssel.ltf) { + glSamplerParameteri(ss0, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(ss0, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + glSamplerParameteri(ss0, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glSamplerParameteri(ss0, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + // FIXME ensure U -> S, V -> T and W->R + if (ssel.tau) + glSamplerParameteri(ss0, GL_TEXTURE_WRAP_S, GL_REPEAT); + else + glSamplerParameteri(ss0, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + + if (ssel.tav) + glSamplerParameteri(ss0, GL_TEXTURE_WRAP_T, GL_REPEAT); + else + glSamplerParameteri(ss0, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glSamplerParameteri(ss0, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + // FIXME which value for GL_TEXTURE_MIN_LOD + glSamplerParameteri(m_rt_ss, GL_TEXTURE_MAX_LOD, FLT_MAX); + // FIXME: seems there is 2 possibility in opengl + // DX: sd.ComparisonFunc = D3D11_COMPARISON_NEVER; + // glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glSamplerParameteri(m_rt_ss, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); + // FIXME: need ogl extension sd.MaxAnisotropy = 16; + + m_ps_ss[ssel] = ss0; + } + + if(sel.fmt >= 3) + { + ss1 = m_palette_ss; + } + } + + PSSetSamplerState(ss0, ss1, sel.date ? m_rt_ss : 0); + + PSSetShader(ps); +} + +void GSDeviceOGL::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, uint8 afix) +{ + auto i = m_om_dss.find(dssel); + + // ************************************************************* + // Static + // ************************************************************* + if (i == m_om_dss.end()) + { + GSDepthStencilOGL* dss = new GSDepthStencilOGL(); + + if (dssel.date) + { + dss->m_stencil_enable = true; + dss->m_stencil_func = GL_EQUAL; + dss->m_stencil_spass_dpass_op = GL_KEEP; + } + + if(dssel.ztst != ZTST_ALWAYS || dssel.zwe) + { + static const GLenum ztst[] = + { + GL_NEVER, + GL_ALWAYS, + GL_GEQUAL, + GL_GREATER + }; + dss->m_depth_enable = true; + dss->m_depth_mask = dssel.zwe ? GL_TRUE : GL_FALSE; + dss->m_depth_func = ztst[dssel.ztst]; + } + + m_om_dss[dssel] = dss; + i = m_om_dss.find(dssel); + } + + // ************************************************************* + // Dynamic + // ************************************************************* + OMSetDepthStencilState(i->second, 1); + + // ************************************************************* + // Static + // ************************************************************* + auto j = m_om_bs.find(bsel); + + if(j == m_om_bs.end()) + { + GSBlendStateOGL* bs = new GSBlendStateOGL(); + + bs->m_enable = bsel.abe; + + if(bsel.abe) + { + int i = ((bsel.a * 3 + bsel.b) * 3 + bsel.c) * 3 + bsel.d; + bs->m_equation_RGB = m_blendMapD3D9[i].op; + bs->m_func_sRGB = m_blendMapD3D9[i].src; + bs->m_func_dRGB = m_blendMapD3D9[i].dst; + + // Not very good but I don't wanna write another 81 row table + if(bsel.negative) + { + if(bs->m_equation_RGB == GL_FUNC_ADD) + bs->m_equation_RGB = GL_FUNC_REVERSE_SUBTRACT; + else if(bs->m_equation_RGB == GL_FUNC_REVERSE_SUBTRACT) + bs->m_equation_RGB = GL_FUNC_ADD; + else + ; // god knows, best just not to mess with it for now + } + + if(m_blendMapD3D9[i].bogus == 1) + { + if (bsel.a == 0) + bs->m_func_sRGB = GL_ONE; + else + bs->m_func_dRGB = GL_ONE; + + const string afixstr = format("%d >> 7", afix); + const char *col[3] = {"Cs", "Cd", "0"}; + const char *alpha[3] = {"As", "Ad", afixstr.c_str()}; + + // FIXME, need to investigate OGL capabilities. Maybe for OGL5 ;) + fprintf(stderr, "Impossible blend for D3D: (%s - %s) * %s + %s\n", col[bsel.a], col[bsel.b], alpha[bsel.c], col[bsel.d]); + } + + + } + + bs->m_r_msk = bsel.wr; + bs->m_g_msk = bsel.wg; + bs->m_b_msk = bsel.wb; + bs->m_a_msk = bsel.wa; + + m_om_bs[bsel] = bs; + j = m_om_bs.find(bsel); + } + + // ************************************************************* + // Dynamic + // ************************************************************* + OMSetBlendState(j->second, (float)(int)afix / 0x80); +}