2011-11-16 22:17:37 +00:00
|
|
|
/*
|
2013-07-06 10:08:52 +00:00
|
|
|
* Copyright (C) 2011-2013 Gregory hainaut
|
2011-11-16 22:17:37 +00:00
|
|
|
* 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
|
2012-09-09 18:16:11 +00:00
|
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
|
2011-11-16 22:17:37 +00:00
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2013-01-10 13:13:59 +00:00
|
|
|
#include "stdafx.h"
|
2011-11-16 22:17:37 +00:00
|
|
|
#include "GSDeviceOGL.h"
|
|
|
|
|
2013-05-18 09:17:30 +00:00
|
|
|
#include "res/convert.h"
|
|
|
|
#include "res/interlace.h"
|
|
|
|
#include "res/merge.h"
|
|
|
|
#include "res/shadeboost.h"
|
2013-06-14 21:22:44 +00:00
|
|
|
#include "res/fxaa.h"
|
2013-05-18 09:17:30 +00:00
|
|
|
|
2012-03-05 20:16:26 +00:00
|
|
|
// TODO performance cost to investigate
|
|
|
|
// Texture attachment/glDrawBuffer. For the moment it set every draw and potentially multiple time (first time in clear, second time in rendering)
|
|
|
|
// Attachment 1 is only used with the GL_16UI format
|
|
|
|
|
2012-01-12 07:29:31 +00:00
|
|
|
//#define LOUD_DEBUGGING
|
2012-01-04 23:19:17 +00:00
|
|
|
//#define PRINT_FRAME_NUMBER
|
|
|
|
//#define ONLY_LINES
|
2013-06-14 11:34:44 +00:00
|
|
|
#if 0
|
|
|
|
#ifdef _DEBUG
|
|
|
|
#define ENABLE_OGL_STENCIL_DEBUG
|
|
|
|
#endif
|
|
|
|
#endif
|
2011-12-29 14:24:26 +00:00
|
|
|
|
|
|
|
static uint32 g_draw_count = 0;
|
2012-01-12 07:29:31 +00:00
|
|
|
static uint32 g_frame_count = 1;
|
2011-12-29 14:24:26 +00:00
|
|
|
|
2013-04-19 19:16:26 +00:00
|
|
|
static const uint32 g_merge_cb_index = 10;
|
|
|
|
static const uint32 g_interlace_cb_index = 11;
|
|
|
|
static const uint32 g_shadeboost_cb_index = 12;
|
|
|
|
static const uint32 g_fxaa_cb_index = 13;
|
2011-12-29 14:24:26 +00:00
|
|
|
|
2011-11-16 22:17:37 +00:00
|
|
|
GSDeviceOGL::GSDeviceOGL()
|
2011-11-21 22:36:03 +00:00
|
|
|
: m_free_window(false)
|
|
|
|
, m_window(NULL)
|
2011-12-11 19:09:08 +00:00
|
|
|
, m_pipeline(0)
|
2011-12-10 19:19:44 +00:00
|
|
|
, m_fbo(0)
|
2012-01-08 21:59:42 +00:00
|
|
|
, m_fbo_read(0)
|
2011-12-15 18:27:58 +00:00
|
|
|
, m_vb_sr(NULL)
|
2013-07-06 10:08:52 +00:00
|
|
|
, m_shader(NULL)
|
2011-11-16 22:17:37 +00:00
|
|
|
{
|
2012-04-26 21:42:16 +00:00
|
|
|
m_msaa = !!theApp.GetConfig("UserHacks", 0) ? theApp.GetConfig("UserHacks_MSAA", 0) : 0;
|
2011-12-07 22:05:46 +00:00
|
|
|
|
2012-01-08 21:59:42 +00:00
|
|
|
memset(&m_merge_obj, 0, sizeof(m_merge_obj));
|
2011-11-21 22:36:03 +00:00
|
|
|
memset(&m_interlace, 0, sizeof(m_interlace));
|
|
|
|
memset(&m_convert, 0, sizeof(m_convert));
|
|
|
|
memset(&m_date, 0, sizeof(m_date));
|
|
|
|
memset(&m_state, 0, sizeof(m_state));
|
2012-01-31 17:08:05 +00:00
|
|
|
|
|
|
|
// Reset the debug file
|
2013-01-16 18:25:53 +00:00
|
|
|
#ifdef ENABLE_OGL_DEBUG
|
2012-01-31 17:08:05 +00:00
|
|
|
FILE* f = fopen("Debug.txt","w");
|
|
|
|
fclose(f);
|
2012-05-11 20:52:50 +00:00
|
|
|
#endif
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
GSDeviceOGL::~GSDeviceOGL()
|
|
|
|
{
|
2013-07-06 10:08:52 +00:00
|
|
|
// If the create function wasn't called nothing to do.
|
|
|
|
if (m_shader == NULL)
|
|
|
|
return;
|
|
|
|
|
2011-12-15 18:27:58 +00:00
|
|
|
// Clean vertex buffer state
|
|
|
|
delete (m_vb_sr);
|
|
|
|
|
2012-01-08 21:59:42 +00:00
|
|
|
// Clean m_merge_obj
|
2013-01-10 13:13:59 +00:00
|
|
|
for (uint32 i = 0; i < 2; i++)
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->Delete(m_merge_obj.ps[i]);
|
2012-01-08 21:59:42 +00:00
|
|
|
delete (m_merge_obj.cb);
|
|
|
|
delete (m_merge_obj.bs);
|
2013-07-06 10:08:52 +00:00
|
|
|
|
2011-11-26 11:46:51 +00:00
|
|
|
// Clean m_interlace
|
2013-01-10 13:13:59 +00:00
|
|
|
for (uint32 i = 0; i < 2; i++)
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->Delete(m_interlace.ps[i]);
|
2011-11-26 11:46:51 +00:00
|
|
|
delete (m_interlace.cb);
|
|
|
|
|
|
|
|
// Clean m_convert
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->Delete(m_convert.vs);
|
|
|
|
for (uint32 i = 0; i < 2; i++)
|
|
|
|
m_shader->Delete(m_convert.ps[i]);
|
2013-05-19 09:19:20 +00:00
|
|
|
gl_DeleteSamplers(1, &m_convert.ln);
|
|
|
|
gl_DeleteSamplers(1, &m_convert.pt);
|
2011-11-26 11:46:51 +00:00
|
|
|
delete m_convert.dss;
|
|
|
|
delete m_convert.bs;
|
|
|
|
|
2013-06-14 21:22:44 +00:00
|
|
|
// Clean m_fxaa
|
|
|
|
delete m_fxaa.cb;
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->Delete(m_fxaa.ps);
|
2013-06-14 21:22:44 +00:00
|
|
|
|
2011-11-26 11:46:51 +00:00
|
|
|
// Clean m_date
|
|
|
|
delete m_date.dss;
|
|
|
|
delete m_date.bs;
|
|
|
|
|
2013-06-30 11:18:46 +00:00
|
|
|
// Clean shadeboost
|
|
|
|
delete m_shadeboost.cb;
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->Delete(m_shadeboost.ps);
|
2013-06-30 11:18:46 +00:00
|
|
|
|
|
|
|
|
2011-11-26 11:46:51 +00:00
|
|
|
// Clean various opengl allocation
|
2013-05-19 09:19:20 +00:00
|
|
|
gl_DeleteFramebuffers(1, &m_fbo);
|
|
|
|
gl_DeleteFramebuffers(1, &m_fbo_read);
|
2011-12-21 19:08:31 +00:00
|
|
|
|
|
|
|
// Delete HW FX
|
|
|
|
delete m_vs_cb;
|
|
|
|
delete m_ps_cb;
|
2013-06-09 16:41:58 +00:00
|
|
|
gl_DeleteSamplers(1, &m_palette_ss);
|
2011-12-21 19:08:31 +00:00
|
|
|
delete m_vb;
|
|
|
|
|
2013-07-06 10:08:52 +00:00
|
|
|
for (uint32 key = 0; key < VSSelector::size(); key++) m_shader->Delete(m_vs[key]);
|
|
|
|
for (uint32 key = 0; key < GSSelector::size(); key++) m_shader->Delete(m_gs[key]);
|
|
|
|
for (auto it = m_ps.begin(); it != m_ps.end() ; it++) m_shader->Delete(it->second);
|
2013-06-30 11:18:46 +00:00
|
|
|
|
|
|
|
m_ps.clear();
|
2013-05-17 20:14:10 +00:00
|
|
|
|
2013-06-26 20:09:07 +00:00
|
|
|
gl_DeleteSamplers(PSSamplerSelector::size(), m_ps_ss);
|
|
|
|
|
|
|
|
for (uint32 key = 0; key < OMDepthStencilSelector::size(); key++) delete m_om_dss[key];
|
2013-06-30 11:18:46 +00:00
|
|
|
|
|
|
|
for (auto it = m_om_bs.begin(); it != m_om_bs.end(); it++) delete it->second;
|
2011-12-21 19:08:31 +00:00
|
|
|
m_om_bs.clear();
|
2011-11-21 22:36:03 +00:00
|
|
|
}
|
2011-11-16 22:17:37 +00:00
|
|
|
|
|
|
|
GSTexture* GSDeviceOGL::CreateSurface(int type, int w, int h, bool msaa, int format)
|
|
|
|
{
|
|
|
|
// A wrapper to call GSTextureOGL, with the different kind of parameter
|
2011-11-21 22:36:03 +00:00
|
|
|
GSTextureOGL* t = NULL;
|
2012-01-08 21:59:42 +00:00
|
|
|
t = new GSTextureOGL(type, w, h, msaa, format, m_fbo_read);
|
2011-11-21 22:36:03 +00:00
|
|
|
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case GSTexture::RenderTarget:
|
|
|
|
ClearRenderTarget(t, 0);
|
|
|
|
break;
|
|
|
|
case GSTexture::DepthStencil:
|
|
|
|
ClearDepth(t, 0);
|
|
|
|
//FIXME might be need to clear the stencil too
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return t;
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GSTexture* GSDeviceOGL::FetchSurface(int type, int w, int h, bool msaa, int format)
|
|
|
|
{
|
|
|
|
// FIXME: keep DX code. Do not know how work msaa but not important for the moment
|
2011-11-21 22:36:03 +00:00
|
|
|
// Current config give only 0 or 1
|
2011-11-16 22:17:37 +00:00
|
|
|
#if 0
|
|
|
|
if(m_msaa < 2) {
|
|
|
|
msaa = false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
msaa = false;
|
|
|
|
|
|
|
|
return GSDevice::FetchSurface(type, w, h, msaa, format);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GSDeviceOGL::Create(GSWnd* wnd)
|
|
|
|
{
|
2011-11-21 22:36:03 +00:00
|
|
|
if (m_window == NULL) {
|
2013-05-25 14:28:16 +00:00
|
|
|
if (!GLLoader::check_gl_version(3, 0)) return false;
|
2011-12-21 23:09:36 +00:00
|
|
|
|
2013-01-14 09:15:39 +00:00
|
|
|
if (!GLLoader::check_gl_supported_extension()) return false;
|
2011-11-21 22:36:03 +00:00
|
|
|
}
|
|
|
|
|
2011-11-26 11:46:51 +00:00
|
|
|
// FIXME disable it when code is ready
|
2012-10-29 21:35:47 +00:00
|
|
|
// glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
2011-12-08 16:39:14 +00:00
|
|
|
|
|
|
|
m_window = wnd;
|
2011-11-26 11:46:51 +00:00
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
// ****************************************************************
|
|
|
|
// Various object
|
|
|
|
// ****************************************************************
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader = new GSShaderOGL(!!theApp.GetConfig("debug_ogl_shader", 1), GLLoader::found_GL_ARB_separate_shader_objects, GLLoader::found_GL_ARB_shading_language_420pack);
|
2011-11-21 22:36:03 +00:00
|
|
|
|
2013-05-19 09:19:20 +00:00
|
|
|
gl_GenFramebuffers(1, &m_fbo);
|
|
|
|
gl_GenFramebuffers(1, &m_fbo_read);
|
2011-12-10 19:19:44 +00:00
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
// ****************************************************************
|
2011-12-15 18:27:58 +00:00
|
|
|
// Vertex buffer state
|
2011-11-21 22:36:03 +00:00
|
|
|
// ****************************************************************
|
2011-12-31 14:38:58 +00:00
|
|
|
GSInputLayoutOGL il_convert[2] =
|
2011-11-21 22:36:03 +00:00
|
|
|
{
|
2011-12-19 21:03:23 +00:00
|
|
|
{0, 4, GL_FLOAT, GL_FALSE, sizeof(GSVertexPT1), (const GLvoid*)offsetof(struct GSVertexPT1, p) },
|
|
|
|
{1, 2, GL_FLOAT, GL_FALSE, sizeof(GSVertexPT1), (const GLvoid*)offsetof(struct GSVertexPT1, t) },
|
2011-11-21 22:36:03 +00:00
|
|
|
};
|
2011-12-31 14:38:58 +00:00
|
|
|
m_vb_sr = new GSVertexBufferStateOGL(sizeof(GSVertexPT1), il_convert, countof(il_convert));
|
2011-11-21 22:36:03 +00:00
|
|
|
|
2011-12-15 18:27:58 +00:00
|
|
|
// ****************************************************************
|
|
|
|
// convert
|
|
|
|
// ****************************************************************
|
2013-07-06 10:08:52 +00:00
|
|
|
m_convert.vs = m_shader->Compile("convert.glsl", "vs_main", GL_VERTEX_SHADER, convert_glsl);
|
2013-06-29 12:02:03 +00:00
|
|
|
for(size_t i = 0; i < countof(m_convert.ps); i++)
|
2013-07-06 10:08:52 +00:00
|
|
|
m_convert.ps[i] = m_shader->Compile("convert.glsl", format("ps_main%d", i), GL_FRAGMENT_SHADER, convert_glsl);
|
2011-11-21 22:36:03 +00:00
|
|
|
|
|
|
|
// Note the following object are initialized to 0 so disabled.
|
|
|
|
// Note: maybe enable blend with a factor of 1
|
|
|
|
// m_convert.dss, m_convert.bs
|
|
|
|
|
2013-06-26 20:09:07 +00:00
|
|
|
m_convert.ln = CreateSampler(true, false, false);
|
|
|
|
m_convert.pt = CreateSampler(false, false, false);
|
2011-11-21 22:36:03 +00:00
|
|
|
|
2011-11-26 11:46:51 +00:00
|
|
|
m_convert.dss = new GSDepthStencilOGL();
|
|
|
|
m_convert.bs = new GSBlendStateOGL();
|
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
// ****************************************************************
|
|
|
|
// merge
|
|
|
|
// ****************************************************************
|
2013-04-19 19:16:26 +00:00
|
|
|
m_merge_obj.cb = new GSUniformBufferOGL(g_merge_cb_index, sizeof(MergeConstantBuffer));
|
2011-11-21 22:36:03 +00:00
|
|
|
|
2013-06-29 12:02:03 +00:00
|
|
|
for(size_t i = 0; i < countof(m_merge_obj.ps); i++)
|
2013-07-06 10:08:52 +00:00
|
|
|
m_merge_obj.ps[i] = m_shader->Compile("merge.glsl", format("ps_main%d", i), GL_FRAGMENT_SHADER, merge_glsl);
|
2011-11-21 22:36:03 +00:00
|
|
|
|
2012-01-08 21:59:42 +00:00
|
|
|
m_merge_obj.bs = new GSBlendStateOGL();
|
|
|
|
m_merge_obj.bs->EnableBlend();
|
|
|
|
m_merge_obj.bs->SetRGB(GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
2011-11-21 22:36:03 +00:00
|
|
|
|
|
|
|
// ****************************************************************
|
|
|
|
// interlace
|
|
|
|
// ****************************************************************
|
2013-04-19 19:16:26 +00:00
|
|
|
m_interlace.cb = new GSUniformBufferOGL(g_interlace_cb_index, sizeof(InterlaceConstantBuffer));
|
2011-11-21 22:36:03 +00:00
|
|
|
|
2013-06-29 12:02:03 +00:00
|
|
|
for(size_t i = 0; i < countof(m_interlace.ps); i++)
|
2013-07-06 10:08:52 +00:00
|
|
|
m_interlace.ps[i] = m_shader->Compile("interlace.glsl", format("ps_main%d", i), GL_FRAGMENT_SHADER, interlace_glsl);
|
2012-04-26 21:42:16 +00:00
|
|
|
// ****************************************************************
|
|
|
|
// Shade boost
|
|
|
|
// ****************************************************************
|
2013-04-19 19:16:26 +00:00
|
|
|
m_shadeboost.cb = new GSUniformBufferOGL(g_shadeboost_cb_index, sizeof(ShadeBoostConstantBuffer));
|
2012-04-26 21:42:16 +00:00
|
|
|
|
|
|
|
int ShadeBoost_Contrast = theApp.GetConfig("ShadeBoost_Contrast", 50);
|
|
|
|
int ShadeBoost_Brightness = theApp.GetConfig("ShadeBoost_Brightness", 50);
|
|
|
|
int ShadeBoost_Saturation = theApp.GetConfig("ShadeBoost_Saturation", 50);
|
2013-06-14 21:22:44 +00:00
|
|
|
std::string shade_macro = format("#define SB_SATURATION %d\n", ShadeBoost_Saturation)
|
2012-04-26 21:42:16 +00:00
|
|
|
+ format("#define SB_BRIGHTNESS %d\n", ShadeBoost_Brightness)
|
|
|
|
+ format("#define SB_CONTRAST %d\n", ShadeBoost_Contrast);
|
|
|
|
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shadeboost.ps = m_shader->Compile("shadeboost.glsl", "ps_main", GL_FRAGMENT_SHADER, shadeboost_glsl, shade_macro);
|
2011-11-21 22:36:03 +00:00
|
|
|
|
|
|
|
// ****************************************************************
|
|
|
|
// rasterization configuration
|
|
|
|
// ****************************************************************
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
// FIXME enable it when multisample code will be here
|
|
|
|
// DX: rd.MultisampleEnable = true;
|
|
|
|
glDisable(GL_MULTISAMPLE);
|
2012-01-04 23:19:17 +00:00
|
|
|
#ifdef ONLY_LINES
|
|
|
|
glLineWidth(5.0);
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
|
|
#endif
|
2011-11-21 22:36:03 +00:00
|
|
|
// Hum I don't know for those options but let's hope there are not activated
|
|
|
|
#if 0
|
|
|
|
rd.FrontCounterClockwise = false;
|
|
|
|
rd.DepthBias = false;
|
|
|
|
rd.DepthBiasClamp = 0;
|
|
|
|
rd.SlopeScaledDepthBias = 0;
|
|
|
|
rd.DepthClipEnable = false; // ???
|
|
|
|
rd.AntialiasedLineEnable = false;
|
|
|
|
#endif
|
|
|
|
|
2011-12-21 19:08:31 +00:00
|
|
|
// ****************************************************************
|
|
|
|
// fxaa (bonus)
|
|
|
|
// ****************************************************************
|
2013-06-14 21:22:44 +00:00
|
|
|
std::string fxaa_macro = "#define FXAA_GLSL_130 1\n";
|
2013-06-16 16:33:08 +00:00
|
|
|
if (GLLoader::found_GL_ARB_gpu_shader5) {
|
2013-06-14 21:22:44 +00:00
|
|
|
// This extension become core on openGL4
|
|
|
|
fxaa_macro += "#extension GL_ARB_gpu_shader5 : enable\n";
|
2013-06-15 10:35:10 +00:00
|
|
|
fxaa_macro += "#define FXAA_GATHER4_ALPHA 1\n";
|
2013-06-14 21:22:44 +00:00
|
|
|
}
|
|
|
|
m_fxaa.cb = new GSUniformBufferOGL(g_fxaa_cb_index, sizeof(FXAAConstantBuffer));
|
2013-07-06 10:08:52 +00:00
|
|
|
m_fxaa.ps = m_shader->Compile("fxaa.fx", "ps_main", GL_FRAGMENT_SHADER, fxaa_fx, fxaa_macro);
|
2011-12-21 19:08:31 +00:00
|
|
|
|
|
|
|
// ****************************************************************
|
2013-06-14 11:34:44 +00:00
|
|
|
// DATE
|
2011-12-21 19:08:31 +00:00
|
|
|
// ****************************************************************
|
|
|
|
|
|
|
|
m_date.dss = new GSDepthStencilOGL();
|
2012-01-03 13:11:40 +00:00
|
|
|
m_date.dss->EnableStencil();
|
|
|
|
m_date.dss->SetStencil(GL_ALWAYS, GL_REPLACE);
|
2011-12-21 19:08:31 +00:00
|
|
|
|
|
|
|
m_date.bs = new GSBlendStateOGL();
|
2013-06-14 11:34:44 +00:00
|
|
|
#ifndef ENABLE_OGL_STENCIL_DEBUG
|
|
|
|
// Only keep stencil data
|
|
|
|
m_date.bs->SetMask(false, false, false, false);
|
|
|
|
#endif
|
2011-12-21 19:08:31 +00:00
|
|
|
|
|
|
|
// ****************************************************************
|
|
|
|
// HW renderer shader
|
|
|
|
// ****************************************************************
|
|
|
|
CreateTextureFX();
|
2011-11-26 11:46:51 +00:00
|
|
|
|
|
|
|
// ****************************************************************
|
|
|
|
// Finish window setup and backbuffer
|
|
|
|
// ****************************************************************
|
|
|
|
if(!GSDevice::Create(wnd))
|
|
|
|
return false;
|
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
GSVector4i rect = wnd->GetClientRect();
|
|
|
|
Reset(rect.z, rect.w);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
|
|
|
|
DXGI_SWAP_CHAIN_DESC scd;
|
|
|
|
D3D11_BUFFER_DESC bd;
|
|
|
|
D3D11_SAMPLER_DESC sd;
|
|
|
|
D3D11_DEPTH_STENCIL_DESC dsd;
|
|
|
|
D3D11_RASTERIZER_DESC rd;
|
|
|
|
D3D11_BLEND_DESC bsd;
|
|
|
|
|
|
|
|
memset(&scd, 0, sizeof(scd));
|
|
|
|
|
|
|
|
scd.BufferCount = 2;
|
|
|
|
scd.BufferDesc.Width = 1;
|
|
|
|
scd.BufferDesc.Height = 1;
|
|
|
|
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
|
|
//scd.BufferDesc.RefreshRate.Numerator = 60;
|
|
|
|
//scd.BufferDesc.RefreshRate.Denominator = 1;
|
|
|
|
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
|
|
scd.OutputWindow = (HWND)m_wnd->GetHandle();
|
|
|
|
scd.SampleDesc.Count = 1;
|
|
|
|
scd.SampleDesc.Quality = 0;
|
|
|
|
|
|
|
|
// Always start in Windowed mode. According to MS, DXGI just "prefers" this, and it's more or less
|
|
|
|
// required if we want to add support for dual displays later on. The fullscreen/exclusive flip
|
|
|
|
// will be issued after all other initializations are complete.
|
|
|
|
|
|
|
|
scd.Windowed = TRUE;
|
|
|
|
|
|
|
|
// NOTE : D3D11_CREATE_DEVICE_SINGLETHREADED
|
|
|
|
// This flag is safe as long as the DXGI's internal message pump is disabled or is on the
|
|
|
|
// same thread as the GS window (which the emulator makes sure of, if it utilizes a
|
|
|
|
// multithreaded GS). Setting the flag is a nice and easy 5% speedup on GS-intensive scenes.
|
|
|
|
|
|
|
|
uint32 flags = D3D11_CREATE_DEVICE_SINGLETHREADED;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
flags |= D3D11_CREATE_DEVICE_DEBUG;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
D3D_FEATURE_LEVEL level;
|
|
|
|
|
|
|
|
const D3D_FEATURE_LEVEL levels[] =
|
|
|
|
{
|
|
|
|
D3D_FEATURE_LEVEL_11_0,
|
|
|
|
D3D_FEATURE_LEVEL_10_1,
|
|
|
|
D3D_FEATURE_LEVEL_10_0,
|
|
|
|
};
|
|
|
|
|
|
|
|
hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, levels, countof(levels), D3D11_SDK_VERSION, &scd, &m_swapchain, &m_dev, &level, &m_ctx);
|
|
|
|
// hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, flags, NULL, 0, D3D11_SDK_VERSION, &scd, &m_swapchain, &m_dev, &level, &m_ctx);
|
|
|
|
#endif
|
|
|
|
|
2011-12-21 19:08:31 +00:00
|
|
|
return true;
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GSDeviceOGL::Reset(int w, int h)
|
|
|
|
{
|
2011-11-21 22:36:03 +00:00
|
|
|
if(!GSDevice::Reset(w, h))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
// Opengl allocate the backbuffer with the window. The render is done in the backbuffer when
|
2011-11-26 11:46:51 +00:00
|
|
|
// there isn't any FBO. Only a dummy texture is created to easily detect when the rendering is done
|
2011-11-21 22:36:03 +00:00
|
|
|
// in the backbuffer
|
2012-01-08 21:59:42 +00:00
|
|
|
m_backbuffer = new GSTextureOGL(GSTextureOGL::Backbuffer, w, h, false, 0, m_fbo_read);
|
2011-11-21 22:36:03 +00:00
|
|
|
|
|
|
|
return true;
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
2012-10-21 18:10:13 +00:00
|
|
|
void GSDeviceOGL::SetVSync(bool enable)
|
|
|
|
{
|
|
|
|
m_wnd->SetVSync(enable);
|
|
|
|
}
|
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
void GSDeviceOGL::Flip()
|
|
|
|
{
|
2011-11-26 11:46:51 +00:00
|
|
|
// FIXME: disable it when code is working
|
2013-01-16 18:25:53 +00:00
|
|
|
#ifdef ENABLE_OGL_DEBUG
|
2011-11-26 11:46:51 +00:00
|
|
|
CheckDebugLog();
|
2012-05-11 20:52:50 +00:00
|
|
|
#endif
|
2012-03-30 19:02:37 +00:00
|
|
|
|
2011-12-07 22:05:46 +00:00
|
|
|
m_wnd->Flip();
|
2012-03-30 19:02:37 +00:00
|
|
|
|
2012-01-04 23:19:17 +00:00
|
|
|
#ifdef PRINT_FRAME_NUMBER
|
|
|
|
fprintf(stderr, "Draw %d (Frame %d)\n", g_draw_count, g_frame_count);
|
|
|
|
#endif
|
2013-05-18 16:09:09 +00:00
|
|
|
#if defined(ENABLE_OGL_DEBUG) || defined(PRINT_FRAME_NUMBER)
|
2013-05-18 09:17:30 +00:00
|
|
|
g_frame_count++;
|
2011-12-29 14:24:26 +00:00
|
|
|
#endif
|
2011-11-21 22:36:03 +00:00
|
|
|
}
|
|
|
|
|
2013-04-19 19:16:26 +00:00
|
|
|
void GSDeviceOGL::BeforeDraw()
|
2012-01-15 17:25:49 +00:00
|
|
|
{
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->UseProgram();
|
|
|
|
m_shader->SetupUniform();
|
2013-04-19 19:16:26 +00:00
|
|
|
}
|
2012-01-15 17:25:49 +00:00
|
|
|
|
2013-04-19 19:16:26 +00:00
|
|
|
void GSDeviceOGL::AfterDraw()
|
|
|
|
{
|
2013-05-18 16:09:09 +00:00
|
|
|
#if defined(ENABLE_OGL_DEBUG) || defined(PRINT_FRAME_NUMBER)
|
2011-12-29 14:24:26 +00:00
|
|
|
g_draw_count++;
|
|
|
|
#endif
|
2011-11-21 22:36:03 +00:00
|
|
|
}
|
|
|
|
|
2013-04-19 19:16:26 +00:00
|
|
|
void GSDeviceOGL::DrawPrimitive()
|
2012-01-15 17:25:49 +00:00
|
|
|
{
|
2013-04-19 19:16:26 +00:00
|
|
|
BeforeDraw();
|
|
|
|
m_state.vb->DrawPrimitive();
|
|
|
|
AfterDraw();
|
|
|
|
}
|
2012-01-15 17:25:49 +00:00
|
|
|
|
2013-04-19 19:16:26 +00:00
|
|
|
void GSDeviceOGL::DrawIndexedPrimitive()
|
|
|
|
{
|
|
|
|
BeforeDraw();
|
2012-01-15 17:25:49 +00:00
|
|
|
m_state.vb->DrawIndexedPrimitive();
|
2013-04-19 19:16:26 +00:00
|
|
|
AfterDraw();
|
2011-11-21 22:36:03 +00:00
|
|
|
}
|
|
|
|
|
2012-02-11 10:22:02 +00:00
|
|
|
void GSDeviceOGL::DrawIndexedPrimitive(int offset, int count)
|
|
|
|
{
|
2013-07-03 18:42:05 +00:00
|
|
|
ASSERT(offset + count <= (int)m_index.count);
|
2012-02-11 10:22:02 +00:00
|
|
|
|
2013-04-19 19:16:26 +00:00
|
|
|
BeforeDraw();
|
2012-02-11 10:22:02 +00:00
|
|
|
m_state.vb->DrawIndexedPrimitive(offset, count);
|
2013-04-19 19:16:26 +00:00
|
|
|
AfterDraw();
|
2012-02-11 10:22:02 +00:00
|
|
|
}
|
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
void GSDeviceOGL::ClearRenderTarget(GSTexture* t, const GSVector4& c)
|
|
|
|
{
|
2013-06-01 09:29:57 +00:00
|
|
|
glDisable(GL_SCISSOR_TEST);
|
2011-12-21 23:09:36 +00:00
|
|
|
if (static_cast<GSTextureOGL*>(t)->IsBackbuffer()) {
|
2011-12-08 11:17:59 +00:00
|
|
|
OMSetFBO(0);
|
2013-06-01 09:29:57 +00:00
|
|
|
|
|
|
|
// glDrawBuffer(GL_BACK); // this is the default when there is no FB
|
|
|
|
// 0 will select the first drawbuffer ie GL_BACK
|
2013-05-19 09:19:20 +00:00
|
|
|
gl_ClearBufferfv(GL_COLOR, 0, c.v);
|
2011-12-07 22:05:46 +00:00
|
|
|
} else {
|
2011-12-08 11:17:59 +00:00
|
|
|
OMSetFBO(m_fbo);
|
2011-12-21 23:09:36 +00:00
|
|
|
static_cast<GSTextureOGL*>(t)->Attach(GL_COLOR_ATTACHMENT0);
|
2013-06-01 09:29:57 +00:00
|
|
|
|
2013-05-19 09:19:20 +00:00
|
|
|
gl_ClearBufferfv(GL_COLOR, 0, c.v);
|
2011-12-07 22:05:46 +00:00
|
|
|
}
|
2013-06-01 09:29:57 +00:00
|
|
|
glEnable(GL_SCISSOR_TEST);
|
2011-11-21 22:36:03 +00:00
|
|
|
}
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
void GSDeviceOGL::ClearRenderTarget(GSTexture* t, uint32 c)
|
|
|
|
{
|
|
|
|
GSVector4 color = GSVector4::rgba32(c) * (1.0f / 255);
|
2011-12-07 22:05:46 +00:00
|
|
|
ClearRenderTarget(t, color);
|
2011-11-21 22:36:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::ClearDepth(GSTexture* t, float c)
|
|
|
|
{
|
2011-12-23 12:32:40 +00:00
|
|
|
OMSetFBO(m_fbo);
|
|
|
|
static_cast<GSTextureOGL*>(t)->Attach(GL_DEPTH_STENCIL_ATTACHMENT);
|
2013-06-01 09:29:57 +00:00
|
|
|
|
2012-08-08 17:49:23 +00:00
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
if (m_state.dss != NULL && m_state.dss->IsMaskEnable()) {
|
2013-05-19 09:19:20 +00:00
|
|
|
gl_ClearBufferfv(GL_DEPTH, 0, &c);
|
2012-08-08 17:49:23 +00:00
|
|
|
} else {
|
|
|
|
glDepthMask(true);
|
2013-05-19 09:19:20 +00:00
|
|
|
gl_ClearBufferfv(GL_DEPTH, 0, &c);
|
2012-08-08 17:49:23 +00:00
|
|
|
glDepthMask(false);
|
|
|
|
}
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
2011-11-21 22:36:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::ClearStencil(GSTexture* t, uint8 c)
|
|
|
|
{
|
2011-12-23 12:32:40 +00:00
|
|
|
OMSetFBO(m_fbo);
|
|
|
|
static_cast<GSTextureOGL*>(t)->Attach(GL_DEPTH_STENCIL_ATTACHMENT);
|
2011-11-21 22:36:03 +00:00
|
|
|
GLint color = c;
|
2013-06-01 09:29:57 +00:00
|
|
|
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
2013-05-19 09:19:20 +00:00
|
|
|
gl_ClearBufferiv(GL_STENCIL, 0, &color);
|
2013-06-01 09:29:57 +00:00
|
|
|
glEnable(GL_SCISSOR_TEST);
|
2011-11-21 22:36:03 +00:00
|
|
|
}
|
|
|
|
|
2013-06-26 20:09:07 +00:00
|
|
|
GLuint GSDeviceOGL::CreateSampler(bool bilinear, bool tau, bool tav)
|
2013-06-09 16:41:58 +00:00
|
|
|
{
|
2013-06-26 20:09:07 +00:00
|
|
|
GLuint sampler;
|
2013-06-09 16:41:58 +00:00
|
|
|
gl_GenSamplers(1, &sampler);
|
|
|
|
if (bilinear) {
|
|
|
|
gl_SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
gl_SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
} else {
|
|
|
|
gl_SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
gl_SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME ensure U -> S, V -> T and W->R
|
|
|
|
if (tau)
|
|
|
|
gl_SamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
|
|
else
|
|
|
|
gl_SamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
if (tav)
|
|
|
|
gl_SamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
else
|
|
|
|
gl_SamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
|
|
|
|
gl_SamplerParameteri(sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
|
|
|
|
|
|
|
// FIXME which value for GL_TEXTURE_MIN_LOD
|
|
|
|
gl_SamplerParameterf(sampler, GL_TEXTURE_MAX_LOD, FLT_MAX);
|
|
|
|
|
|
|
|
// FIXME: seems there is 2 possibility in opengl
|
|
|
|
// DX: sd.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
|
|
|
// gl_SamplerParameteri(sampler, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
|
|
|
gl_SamplerParameteri(sampler, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
|
|
|
gl_SamplerParameteri(sampler, GL_TEXTURE_COMPARE_FUNC, GL_NEVER);
|
|
|
|
// FIXME: need ogl extension sd.MaxAnisotropy = 16;
|
2013-06-26 20:09:07 +00:00
|
|
|
|
|
|
|
return sampler;
|
2013-06-09 16:41:58 +00:00
|
|
|
}
|
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
GSTexture* GSDeviceOGL::CreateRenderTarget(int w, int h, bool msaa, int format)
|
|
|
|
{
|
|
|
|
return GSDevice::CreateRenderTarget(w, h, msaa, format ? format : GL_RGBA8);
|
|
|
|
}
|
|
|
|
|
|
|
|
GSTexture* GSDeviceOGL::CreateDepthStencil(int w, int h, bool msaa, int format)
|
|
|
|
{
|
|
|
|
return GSDevice::CreateDepthStencil(w, h, msaa, format ? format : GL_DEPTH32F_STENCIL8);
|
|
|
|
}
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
GSTexture* GSDeviceOGL::CreateTexture(int w, int h, int format)
|
|
|
|
{
|
|
|
|
return GSDevice::CreateTexture(w, h, format ? format : GL_RGBA8);
|
|
|
|
}
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
GSTexture* GSDeviceOGL::CreateOffscreen(int w, int h, int format)
|
|
|
|
{
|
|
|
|
return GSDevice::CreateOffscreen(w, h, format ? format : GL_RGBA8);
|
|
|
|
}
|
2011-11-16 22:17:37 +00:00
|
|
|
|
|
|
|
// blit a texture into an offscreen buffer
|
|
|
|
GSTexture* GSDeviceOGL::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format)
|
|
|
|
{
|
|
|
|
GSTexture* dst = NULL;
|
|
|
|
|
2011-12-23 12:32:40 +00:00
|
|
|
if(format == 0) format = GL_RGBA8;
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-12-23 12:32:40 +00:00
|
|
|
if(format != GL_RGBA8 && format != GL_R16UI)
|
2011-11-16 22:17:37 +00:00
|
|
|
{
|
|
|
|
ASSERT(0);
|
|
|
|
|
2013-04-19 19:16:26 +00:00
|
|
|
return NULL;
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
2012-03-05 20:16:26 +00:00
|
|
|
// FIXME: It is possible to bypass completely offscreen-buffer on opengl but it needs some re-thinking of the code.
|
|
|
|
// For the moment mimic dx11
|
2011-12-23 12:32:40 +00:00
|
|
|
GSTexture* rt = CreateRenderTarget(w, h, false, format);
|
|
|
|
if(rt)
|
2011-11-16 22:17:37 +00:00
|
|
|
{
|
|
|
|
GSVector4 dr(0, 0, w, h);
|
|
|
|
|
|
|
|
if(GSTexture* src2 = src->IsMSAA() ? Resolve(src) : src)
|
|
|
|
{
|
2011-12-23 12:32:40 +00:00
|
|
|
StretchRect(src2, sr, rt, dr, m_convert.ps[format == GL_R16UI ? 1 : 0]);
|
2011-11-16 22:17:37 +00:00
|
|
|
|
|
|
|
if(src2 != src) Recycle(src2);
|
|
|
|
}
|
|
|
|
|
2012-03-05 20:16:26 +00:00
|
|
|
|
|
|
|
GSVector4i dor(0, 0, w, h);
|
2011-11-16 22:17:37 +00:00
|
|
|
dst = CreateOffscreen(w, h, format);
|
|
|
|
|
2012-03-05 20:16:26 +00:00
|
|
|
if (dst) CopyRect(rt, dst, dor);
|
|
|
|
#if 0
|
2011-11-16 22:17:37 +00:00
|
|
|
if(dst)
|
|
|
|
{
|
|
|
|
m_ctx->CopyResource(*(GSTexture11*)dst, *(GSTexture11*)rt);
|
|
|
|
}
|
2011-12-23 12:32:40 +00:00
|
|
|
#endif
|
2011-11-16 22:17:37 +00:00
|
|
|
|
|
|
|
Recycle(rt);
|
|
|
|
}
|
|
|
|
|
2012-03-05 20:16:26 +00:00
|
|
|
return dst;
|
|
|
|
//return rt;
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Copy a sub part of a texture into another
|
|
|
|
// Several question to answer did texture have same size?
|
|
|
|
// From a sub-part to the same sub-part
|
|
|
|
// From a sub-part to a full texture
|
|
|
|
void GSDeviceOGL::CopyRect(GSTexture* st, GSTexture* dt, const GSVector4i& r)
|
|
|
|
{
|
|
|
|
if(!st || !dt)
|
|
|
|
{
|
|
|
|
ASSERT(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-28 10:14:42 +00:00
|
|
|
// FIXME: the extension was integrated in opengl 4.3 (now we need driver that support OGL4.3)
|
2011-12-23 12:32:40 +00:00
|
|
|
// FIXME check those function work as expected
|
2012-01-31 17:08:05 +00:00
|
|
|
// void CopyImageSubDataNV(
|
2013-01-10 13:13:59 +00:00
|
|
|
// uint32 srcName, enum srcTarget, int srcLevel, int srcX, int srcY, int srcZ,
|
|
|
|
// uint32 dstName, enum dstTarget, int dstLevel, int dstX, int dstY, int dstZ,
|
2012-01-31 17:08:05 +00:00
|
|
|
// sizei width, sizei height, sizei depth);
|
2013-05-27 16:53:38 +00:00
|
|
|
if (GLLoader::found_GL_NV_copy_image) {
|
|
|
|
gl_CopyImageSubDataNV( static_cast<GSTextureOGL*>(st)->GetID(), static_cast<GSTextureOGL*>(st)->GetTarget(),
|
|
|
|
0, r.x, r.y, 0,
|
|
|
|
static_cast<GSTextureOGL*>(dt)->GetID(), static_cast<GSTextureOGL*>(dt)->GetTarget(),
|
|
|
|
0, r.x, r.y, 0,
|
|
|
|
r.width(), r.height(), 1);
|
|
|
|
} else if (GLLoader::found_GL_ARB_copy_image) {
|
|
|
|
// Would need an update of GL definition. For the moment it isn't supported by driver anyway.
|
|
|
|
#if 0
|
|
|
|
gl_CopyImageSubData( static_cast<GSTextureOGL*>(st)->GetID(), static_cast<GSTextureOGL*>(st)->GetTarget(),
|
|
|
|
0, r.x, r.y, 0,
|
|
|
|
static_cast<GSTextureOGL*>(dt)->GetID(), static_cast<GSTextureOGL*>(dt)->GetTarget(),
|
|
|
|
0, r.x, r.y, 0,
|
|
|
|
r.width(), r.height(), 1);
|
|
|
|
#endif
|
|
|
|
} else {
|
2013-05-27 18:02:27 +00:00
|
|
|
|
|
|
|
GSTextureOGL* st_ogl = (GSTextureOGL*) st;
|
|
|
|
GSTextureOGL* dt_ogl = (GSTextureOGL*) dt;
|
|
|
|
|
|
|
|
gl_BindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
|
|
|
|
|
|
|
|
st_ogl->AttachRead(GL_COLOR_ATTACHMENT0);
|
2013-06-01 09:29:57 +00:00
|
|
|
dt_ogl->EnableUnit(6);
|
2013-05-27 18:02:27 +00:00
|
|
|
glCopyTexSubImage2D(dt_ogl->GetTarget(), 0, r.x, r.y, r.x, r.y, r.width(), r.height());
|
|
|
|
|
|
|
|
gl_BindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
2013-05-27 16:53:38 +00:00
|
|
|
}
|
2012-01-31 17:08:05 +00:00
|
|
|
|
2011-11-21 22:36:03 +00:00
|
|
|
#if 0
|
2011-11-16 22:17:37 +00:00
|
|
|
D3D11_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1};
|
|
|
|
m_ctx->CopySubresourceRegion(*(GSTexture11*)dt, 0, 0, 0, 0, *(GSTexture11*)st, 0, &box);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, int shader, bool linear)
|
|
|
|
{
|
2011-12-11 19:11:01 +00:00
|
|
|
StretchRect(st, sr, dt, dr, m_convert.ps[shader], linear);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
2011-11-21 22:36:03 +00:00
|
|
|
|
2011-12-11 19:11:01 +00:00
|
|
|
void GSDeviceOGL::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, GLuint ps, bool linear)
|
2011-11-16 22:17:37 +00:00
|
|
|
{
|
2011-12-11 19:11:01 +00:00
|
|
|
StretchRect(st, sr, dt, dr, ps, m_convert.bs, linear);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
2011-12-11 19:11:01 +00:00
|
|
|
void GSDeviceOGL::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, GLuint ps, GSBlendStateOGL* bs, bool linear)
|
2011-11-16 22:17:37 +00:00
|
|
|
{
|
2011-12-07 22:05:46 +00:00
|
|
|
|
2011-11-16 22:17:37 +00:00
|
|
|
if(!st || !dt)
|
|
|
|
{
|
|
|
|
ASSERT(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
|
|
|
// Init
|
|
|
|
// ************************************
|
|
|
|
|
2011-11-16 22:17:37 +00:00
|
|
|
BeginScene();
|
|
|
|
|
|
|
|
GSVector2i ds = dt->GetSize();
|
|
|
|
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
2011-11-16 22:17:37 +00:00
|
|
|
// om
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
2011-11-16 22:17:37 +00:00
|
|
|
|
|
|
|
OMSetDepthStencilState(m_convert.dss, 0);
|
|
|
|
OMSetBlendState(bs, 0);
|
|
|
|
OMSetRenderTargets(dt, NULL);
|
|
|
|
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
2011-11-16 22:17:37 +00:00
|
|
|
// ia
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-12-11 19:09:08 +00:00
|
|
|
|
2013-06-11 11:14:26 +00:00
|
|
|
// Original code from DX
|
2011-11-16 22:17:37 +00:00
|
|
|
float left = dr.x * 2 / ds.x - 1.0f;
|
|
|
|
float right = dr.z * 2 / ds.x - 1.0f;
|
2013-06-11 11:14:26 +00:00
|
|
|
#if 0
|
|
|
|
float top = 1.0f - dr.y * 2 / ds.y;
|
2011-11-16 22:17:37 +00:00
|
|
|
float bottom = 1.0f - dr.w * 2 / ds.y;
|
2013-06-11 11:14:26 +00:00
|
|
|
#else
|
|
|
|
// Opengl get some issues with the coordinate
|
|
|
|
// I flip top/bottom to fix scaling of the internal resolution
|
|
|
|
float top = -1.0f + dr.y * 2 / ds.y;
|
|
|
|
float bottom = -1.0f + dr.w * 2 / ds.y;
|
|
|
|
#endif
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-12-11 19:09:08 +00:00
|
|
|
// 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 GSdx code expect thing in dx order.
|
|
|
|
// Only flipping the backbuffer is transparent (I hope)...
|
|
|
|
GSVector4 flip_sr = sr;
|
2011-12-21 23:09:36 +00:00
|
|
|
if (static_cast<GSTextureOGL*>(dt)->IsBackbuffer()) {
|
2013-06-11 11:14:26 +00:00
|
|
|
flip_sr.y = sr.w;
|
|
|
|
flip_sr.w = sr.y;
|
2011-12-11 19:09:08 +00:00
|
|
|
}
|
|
|
|
|
2011-12-07 22:05:46 +00:00
|
|
|
GSVertexPT1 vertices[] =
|
2011-11-16 22:17:37 +00:00
|
|
|
{
|
2013-06-11 11:14:26 +00:00
|
|
|
{GSVector4(left, top, 0.5f, 1.0f), GSVector2(flip_sr.x, flip_sr.y)},
|
|
|
|
{GSVector4(right, top, 0.5f, 1.0f), GSVector2(flip_sr.z, flip_sr.y)},
|
|
|
|
{GSVector4(left, bottom, 0.5f, 1.0f), GSVector2(flip_sr.x, flip_sr.w)},
|
|
|
|
{GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(flip_sr.z, flip_sr.w)},
|
2011-11-16 22:17:37 +00:00
|
|
|
};
|
2012-01-31 17:08:05 +00:00
|
|
|
//fprintf(stderr, "A:%fx%f B:%fx%f\n", left, top, bottom, right);
|
|
|
|
//fprintf(stderr, "SR: %f %f %f %f\n", sr.x, sr.y, sr.z, sr.w);
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-12-15 18:27:58 +00:00
|
|
|
IASetVertexState(m_vb_sr);
|
|
|
|
IASetVertexBuffer(vertices, 4);
|
|
|
|
IASetPrimitiveTopology(GL_TRIANGLE_STRIP);
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
2011-11-16 22:17:37 +00:00
|
|
|
// vs
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->VS(m_convert.vs);
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
2011-11-16 22:17:37 +00:00
|
|
|
// gs
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->GS(0);
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
2011-11-16 22:17:37 +00:00
|
|
|
// ps
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
2011-11-16 22:17:37 +00:00
|
|
|
|
|
|
|
PSSetShaderResources(st, NULL);
|
2011-11-30 21:42:41 +00:00
|
|
|
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt, 0);
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->PS(ps);
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
|
|
|
// Draw
|
|
|
|
// ************************************
|
2011-12-15 18:27:58 +00:00
|
|
|
DrawPrimitive();
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-12-10 19:19:44 +00:00
|
|
|
// ************************************
|
|
|
|
// End
|
|
|
|
// ************************************
|
2011-11-16 22:17:37 +00:00
|
|
|
|
|
|
|
EndScene();
|
|
|
|
|
|
|
|
PSSetShaderResources(NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::DoMerge(GSTexture* st[2], GSVector4* sr, GSTexture* dt, GSVector4* dr, bool slbg, bool mmod, const GSVector4& c)
|
|
|
|
{
|
|
|
|
ClearRenderTarget(dt, c);
|
|
|
|
|
|
|
|
if(st[1] && !slbg)
|
|
|
|
{
|
2012-01-08 21:59:42 +00:00
|
|
|
StretchRect(st[1], sr[1], dt, dr[1], m_merge_obj.ps[0]);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(st[0])
|
|
|
|
{
|
2012-01-08 21:59:42 +00:00
|
|
|
SetUniformBuffer(m_merge_obj.cb);
|
|
|
|
m_merge_obj.cb->upload(&c.v);
|
2011-12-11 19:09:08 +00:00
|
|
|
|
2012-01-08 21:59:42 +00:00
|
|
|
StretchRect(st[0], sr[0], dt, dr[0], m_merge_obj.ps[mmod ? 1 : 0], m_merge_obj.bs);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset)
|
|
|
|
{
|
|
|
|
GSVector4 s = GSVector4(dt->GetSize());
|
|
|
|
|
|
|
|
GSVector4 sr(0, 0, 1, 1);
|
|
|
|
GSVector4 dr(0.0f, yoffset, s.x, s.y + yoffset);
|
|
|
|
|
|
|
|
InterlaceConstantBuffer cb;
|
|
|
|
|
|
|
|
cb.ZrH = GSVector2(0, 1.0f / s.y);
|
|
|
|
cb.hH = s.y / 2;
|
|
|
|
|
2011-12-19 21:03:23 +00:00
|
|
|
SetUniformBuffer(m_interlace.cb);
|
|
|
|
m_interlace.cb->upload(&cb);
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2011-12-11 19:11:01 +00:00
|
|
|
StretchRect(st, sr, dt, dr, m_interlace.ps[shader], linear);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
2013-06-14 21:22:44 +00:00
|
|
|
void GSDeviceOGL::DoFXAA(GSTexture* st, GSTexture* dt)
|
|
|
|
{
|
|
|
|
GSVector2i s = dt->GetSize();
|
|
|
|
|
|
|
|
GSVector4 sr(0, 0, 1, 1);
|
|
|
|
GSVector4 dr(0, 0, s.x, s.y);
|
|
|
|
|
|
|
|
FXAAConstantBuffer cb;
|
|
|
|
|
|
|
|
// FIXME optimize: remove rcpFrameOpt. And reduce rcpFrame to vec2
|
|
|
|
cb.rcpFrame = GSVector4(1.0f / s.x, 1.0f / s.y, 0.0f, 0.0f);
|
|
|
|
cb.rcpFrameOpt = GSVector4::zero();
|
|
|
|
|
|
|
|
SetUniformBuffer(m_fxaa.cb);
|
|
|
|
m_fxaa.cb->upload(&cb);
|
|
|
|
|
|
|
|
StretchRect(st, sr, dt, dr, m_fxaa.ps, true);
|
|
|
|
}
|
|
|
|
|
2012-04-26 21:42:16 +00:00
|
|
|
void GSDeviceOGL::DoShadeBoost(GSTexture* st, GSTexture* dt)
|
|
|
|
{
|
|
|
|
GSVector2i s = dt->GetSize();
|
|
|
|
|
|
|
|
GSVector4 sr(0, 0, 1, 1);
|
|
|
|
GSVector4 dr(0, 0, s.x, s.y);
|
|
|
|
|
|
|
|
ShadeBoostConstantBuffer cb;
|
|
|
|
|
|
|
|
cb.rcpFrame = GSVector4(1.0f / s.x, 1.0f / s.y, 0.0f, 0.0f);
|
|
|
|
cb.rcpFrameOpt = GSVector4::zero();
|
|
|
|
|
|
|
|
SetUniformBuffer(m_shadeboost.cb);
|
|
|
|
m_shadeboost.cb->upload(&cb);
|
|
|
|
|
2013-06-16 07:05:57 +00:00
|
|
|
StretchRect(st, sr, dt, dr, m_shadeboost.ps, true);
|
2012-04-26 21:42:16 +00:00
|
|
|
}
|
|
|
|
|
2011-12-19 21:03:23 +00:00
|
|
|
void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vertices, bool datm)
|
|
|
|
{
|
2013-06-14 11:34:44 +00:00
|
|
|
#ifdef ENABLE_OGL_STENCIL_DEBUG
|
2011-12-19 21:03:23 +00:00
|
|
|
const GSVector2i& size = rt->GetSize();
|
2013-06-14 11:34:44 +00:00
|
|
|
GSTexture* t = CreateRenderTarget(size.x, size.y, rt->IsMSAA());
|
|
|
|
#else
|
|
|
|
GSTexture* t = NULL;
|
|
|
|
#endif
|
|
|
|
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
BeginScene();
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
ClearStencil(ds, 0);
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
// om
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
OMSetDepthStencilState(m_date.dss, 1);
|
|
|
|
OMSetBlendState(m_date.bs, 0);
|
|
|
|
OMSetRenderTargets(t, ds);
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
// ia
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
IASetVertexState(m_vb_sr);
|
|
|
|
IASetVertexBuffer(vertices, 4);
|
|
|
|
IASetPrimitiveTopology(GL_TRIANGLE_STRIP);
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
// vs
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->VS(m_convert.vs);
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
// gs
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->GS(0);
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
// ps
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
GSTexture* rt2 = rt->IsMSAA() ? Resolve(rt) : rt;
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
PSSetShaderResources(rt2, NULL);
|
|
|
|
PSSetSamplerState(m_convert.pt, 0);
|
2013-07-06 10:08:52 +00:00
|
|
|
m_shader->PS(m_convert.ps[datm ? 2 : 3]);
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
//
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
DrawPrimitive();
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
//
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
EndScene();
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
#ifdef ENABLE_OGL_STENCIL_DEBUG
|
|
|
|
Recycle(t);
|
|
|
|
#endif
|
2011-12-19 21:03:23 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
if(rt2 != rt) Recycle(rt2);
|
2011-12-19 21:03:23 +00:00
|
|
|
}
|
|
|
|
|
2011-11-16 22:17:37 +00:00
|
|
|
// copy a multisample texture to a non-texture multisample. On opengl you need 2 FBO with different level of
|
|
|
|
// sample and then do a blit. Headach expected to for the moment just drop MSAA...
|
|
|
|
GSTexture* GSDeviceOGL::Resolve(GSTexture* t)
|
|
|
|
{
|
|
|
|
ASSERT(t != NULL && t->IsMSAA());
|
2011-11-21 22:36:03 +00:00
|
|
|
#if 0
|
2011-11-16 22:17:37 +00:00
|
|
|
|
|
|
|
if(GSTexture* dst = CreateRenderTarget(t->GetWidth(), t->GetHeight(), false, t->GetFormat()))
|
|
|
|
{
|
|
|
|
dst->SetScale(t->GetScale());
|
|
|
|
|
|
|
|
m_ctx->ResolveSubresource(*(GSTexture11*)dst, 0, *(GSTexture11*)t, 0, (DXGI_FORMAT)t->GetFormat());
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-12-15 18:27:58 +00:00
|
|
|
void GSDeviceOGL::EndScene()
|
2011-12-10 19:19:44 +00:00
|
|
|
{
|
2012-01-15 17:25:49 +00:00
|
|
|
m_state.vb->EndScene();
|
2011-12-10 19:19:44 +00:00
|
|
|
}
|
|
|
|
|
2011-12-19 21:03:23 +00:00
|
|
|
void GSDeviceOGL::SetUniformBuffer(GSUniformBufferOGL* cb)
|
|
|
|
{
|
|
|
|
if (m_state.cb != cb) {
|
|
|
|
m_state.cb = cb;
|
|
|
|
cb->bind();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-03 16:12:34 +00:00
|
|
|
void GSDeviceOGL::IASetVertexState(GSVertexBufferStateOGL* vb)
|
2011-12-10 19:19:44 +00:00
|
|
|
{
|
2012-02-11 10:22:02 +00:00
|
|
|
if (vb == NULL) vb = m_vb;
|
|
|
|
|
2012-01-03 16:12:34 +00:00
|
|
|
if (m_state.vb != vb) {
|
|
|
|
m_state.vb = vb;
|
|
|
|
vb->bind();
|
2011-12-10 19:19:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-15 18:27:58 +00:00
|
|
|
void GSDeviceOGL::IASetVertexBuffer(const void* vertices, size_t count)
|
2011-11-16 22:17:37 +00:00
|
|
|
{
|
2012-01-15 17:25:49 +00:00
|
|
|
m_state.vb->UploadVB(vertices, count);
|
|
|
|
}
|
|
|
|
|
2012-02-11 10:22:02 +00:00
|
|
|
bool GSDeviceOGL::IAMapVertexBuffer(void** vertex, size_t stride, size_t count)
|
|
|
|
{
|
|
|
|
return m_state.vb->MapVB(vertex, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::IAUnmapVertexBuffer()
|
|
|
|
{
|
|
|
|
m_state.vb->UnmapVB();
|
|
|
|
}
|
|
|
|
|
2012-01-15 17:25:49 +00:00
|
|
|
void GSDeviceOGL::IASetIndexBuffer(const void* index, size_t count)
|
|
|
|
{
|
|
|
|
m_state.vb->UploadIB(index, count);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::IASetPrimitiveTopology(GLenum topology)
|
|
|
|
{
|
2012-01-03 16:12:34 +00:00
|
|
|
m_state.vb->SetTopology(topology);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::PSSetShaderResources(GSTexture* sr0, GSTexture* sr1)
|
|
|
|
{
|
|
|
|
PSSetShaderResource(0, sr0);
|
|
|
|
PSSetShaderResource(1, sr1);
|
2012-01-31 17:08:05 +00:00
|
|
|
//PSSetShaderResource(2, NULL);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::PSSetShaderResource(int i, GSTexture* sr)
|
|
|
|
{
|
2011-12-29 14:24:26 +00:00
|
|
|
GSTextureOGL* srv = static_cast<GSTextureOGL*>(sr);
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2013-06-01 09:29:57 +00:00
|
|
|
if (m_state.ps_srv[i] != srv)
|
2011-11-16 22:17:37 +00:00
|
|
|
{
|
|
|
|
m_state.ps_srv[i] = srv;
|
2013-06-01 09:29:57 +00:00
|
|
|
if (srv != NULL)
|
|
|
|
m_state.ps_srv[i]->EnableUnit(i);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::PSSetSamplerState(GLuint ss0, GLuint ss1, GLuint ss2)
|
|
|
|
{
|
2013-06-01 09:29:57 +00:00
|
|
|
if (m_state.ps_ss[0] != ss0) {
|
2011-11-16 22:17:37 +00:00
|
|
|
m_state.ps_ss[0] = ss0;
|
2013-06-01 09:29:57 +00:00
|
|
|
gl_BindSampler(0, ss0);
|
|
|
|
}
|
|
|
|
if (m_state.ps_ss[1] != ss1) {
|
2011-11-16 22:17:37 +00:00
|
|
|
m_state.ps_ss[1] = ss1;
|
2013-06-01 09:29:57 +00:00
|
|
|
gl_BindSampler(1, ss1);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-30 19:02:37 +00:00
|
|
|
void GSDeviceOGL::OMSetFBO(GLuint fbo, GLenum buffer)
|
2011-12-08 11:17:59 +00:00
|
|
|
{
|
|
|
|
if (m_state.fbo != fbo) {
|
|
|
|
m_state.fbo = fbo;
|
2013-05-19 09:19:20 +00:00
|
|
|
gl_BindFramebuffer(GL_FRAMEBUFFER, fbo);
|
2012-02-11 10:22:02 +00:00
|
|
|
// FIXME DEBUG
|
2013-05-19 09:19:20 +00:00
|
|
|
//if (fbo) fprintf(stderr, "FB status %x\n", gl_CheckFramebufferStatus(GL_FRAMEBUFFER));
|
2011-12-08 11:17:59 +00:00
|
|
|
}
|
2012-03-30 19:02:37 +00:00
|
|
|
|
|
|
|
if (m_state.draw != buffer) {
|
|
|
|
m_state.draw = buffer;
|
|
|
|
glDrawBuffer(buffer);
|
|
|
|
}
|
|
|
|
|
2011-12-08 11:17:59 +00:00
|
|
|
}
|
|
|
|
|
2011-11-16 22:17:37 +00:00
|
|
|
void GSDeviceOGL::OMSetDepthStencilState(GSDepthStencilOGL* dss, uint8 sref)
|
|
|
|
{
|
2013-06-01 09:29:57 +00:00
|
|
|
if (m_state.dss != dss) {
|
2011-11-16 22:17:37 +00:00
|
|
|
m_state.dss = dss;
|
|
|
|
|
2012-01-03 13:11:40 +00:00
|
|
|
dss->SetupDepth();
|
2013-06-14 11:34:44 +00:00
|
|
|
dss->SetupStencil();
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::OMSetBlendState(GSBlendStateOGL* bs, float bf)
|
|
|
|
{
|
2013-06-01 09:29:57 +00:00
|
|
|
if ( m_state.bs != bs || (m_state.bf != bf && bs->HasConstantFactor()) )
|
2011-11-16 22:17:37 +00:00
|
|
|
{
|
|
|
|
m_state.bs = bs;
|
|
|
|
m_state.bf = bf;
|
|
|
|
|
2012-01-03 13:11:40 +00:00
|
|
|
bs->SetupBlend(bf);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor)
|
|
|
|
{
|
2013-06-14 11:34:44 +00:00
|
|
|
if (rt == NULL || !static_cast<GSTextureOGL*>(rt)->IsBackbuffer()) {
|
|
|
|
if (rt) {
|
|
|
|
// FIXME DEBUG special case for GL_R16UI
|
|
|
|
if (rt->GetFormat() == GL_R16UI) {
|
|
|
|
OMSetFBO(m_fbo, GL_COLOR_ATTACHMENT1);
|
|
|
|
static_cast<GSTextureOGL*>(rt)->Attach(GL_COLOR_ATTACHMENT1);
|
|
|
|
} else {
|
|
|
|
OMSetFBO(m_fbo, GL_COLOR_ATTACHMENT0);
|
|
|
|
static_cast<GSTextureOGL*>(rt)->Attach(GL_COLOR_ATTACHMENT0);
|
|
|
|
}
|
2011-12-29 14:24:26 +00:00
|
|
|
} else {
|
2013-06-14 11:34:44 +00:00
|
|
|
// Note: NULL rt is only used in DATE so far. Color writing is disabled
|
|
|
|
// on the blend setup
|
|
|
|
OMSetFBO(m_fbo, GL_NONE);
|
2011-12-29 14:24:26 +00:00
|
|
|
}
|
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
// Note: it must be done after OMSetFBO
|
|
|
|
if (ds)
|
2011-12-21 23:09:36 +00:00
|
|
|
static_cast<GSTextureOGL*>(ds)->Attach(GL_DEPTH_STENCIL_ATTACHMENT);
|
2013-06-14 11:34:44 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// Render in the backbuffer
|
|
|
|
OMSetFBO(0);
|
2011-11-21 22:36:03 +00:00
|
|
|
}
|
2011-11-16 22:17:37 +00:00
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
GSVector2i size = rt ? rt->GetSize() : ds->GetSize();
|
|
|
|
if(m_state.viewport != size)
|
2011-11-16 22:17:37 +00:00
|
|
|
{
|
2013-06-14 11:34:44 +00:00
|
|
|
m_state.viewport = size;
|
|
|
|
glViewport(0, 0, size.x, size.y);
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
|
|
|
|
2013-06-14 11:34:44 +00:00
|
|
|
GSVector4i r = scissor ? *scissor : GSVector4i(size).zwxy();
|
2011-11-16 22:17:37 +00:00
|
|
|
|
|
|
|
if(!m_state.scissor.eq(r))
|
|
|
|
{
|
|
|
|
m_state.scissor = r;
|
2011-12-07 22:05:46 +00:00
|
|
|
glScissor( r.x, r.y, r.width(), r.height() );
|
2011-11-16 22:17:37 +00:00
|
|
|
}
|
2011-11-21 22:36:03 +00:00
|
|
|
}
|
|
|
|
|
2011-11-26 11:46:51 +00:00
|
|
|
void GSDeviceOGL::CheckDebugLog()
|
|
|
|
{
|
2013-06-09 16:41:58 +00:00
|
|
|
unsigned int count = 16; // max. num. of messages that will be read from the log
|
2011-11-26 11:46:51 +00:00
|
|
|
int bufsize = 2048;
|
2013-06-09 16:41:58 +00:00
|
|
|
unsigned int sources[16] = {};
|
|
|
|
unsigned int types[16] = {};
|
|
|
|
unsigned int ids[16] = {};
|
|
|
|
unsigned int severities[16] = {};
|
|
|
|
int lengths[16] = {};
|
2011-11-26 11:46:51 +00:00
|
|
|
char* messageLog = new char[bufsize];
|
|
|
|
|
2013-05-19 09:19:20 +00:00
|
|
|
unsigned int retVal = gl_GetDebugMessageLogARB(count, bufsize, sources, types, ids, severities, lengths, messageLog);
|
2011-11-26 11:46:51 +00:00
|
|
|
|
|
|
|
if(retVal > 0)
|
|
|
|
{
|
|
|
|
unsigned int pos = 0;
|
|
|
|
for(unsigned int i=0; i<retVal; i++)
|
|
|
|
{
|
|
|
|
DebugOutputToFile(sources[i], types[i], ids[i], severities[i],
|
|
|
|
&messageLog[pos]);
|
|
|
|
pos += lengths[i];
|
|
|
|
}
|
|
|
|
}
|
2013-06-30 11:18:46 +00:00
|
|
|
|
|
|
|
delete[] messageLog;
|
2011-11-26 11:46:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GSDeviceOGL::DebugOutputToFile(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, const char* message)
|
|
|
|
{
|
2011-12-08 11:17:59 +00:00
|
|
|
char debType[20], debSev[5];
|
2012-02-11 10:22:02 +00:00
|
|
|
static int sev_counter = 0;
|
2011-12-08 11:17:59 +00:00
|
|
|
|
|
|
|
if(type == GL_DEBUG_TYPE_ERROR_ARB)
|
|
|
|
strcpy(debType, "Error");
|
|
|
|
else if(type == GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB)
|
|
|
|
strcpy(debType, "Deprecated behavior");
|
|
|
|
else if(type == GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB)
|
|
|
|
strcpy(debType, "Undefined behavior");
|
|
|
|
else if(type == GL_DEBUG_TYPE_PORTABILITY_ARB)
|
|
|
|
strcpy(debType, "Portability");
|
|
|
|
else if(type == GL_DEBUG_TYPE_PERFORMANCE_ARB)
|
|
|
|
strcpy(debType, "Performance");
|
|
|
|
else if(type == GL_DEBUG_TYPE_OTHER_ARB)
|
|
|
|
strcpy(debType, "Other");
|
|
|
|
else
|
2011-12-10 11:56:34 +00:00
|
|
|
strcpy(debType, "UNKNOWN");
|
2011-12-08 11:17:59 +00:00
|
|
|
|
2012-02-11 10:22:02 +00:00
|
|
|
if(severity == GL_DEBUG_SEVERITY_HIGH_ARB) {
|
2011-12-08 11:17:59 +00:00
|
|
|
strcpy(debSev, "High");
|
2012-02-11 10:22:02 +00:00
|
|
|
sev_counter++;
|
|
|
|
}
|
2011-12-08 11:17:59 +00:00
|
|
|
else if(severity == GL_DEBUG_SEVERITY_MEDIUM_ARB)
|
|
|
|
strcpy(debSev, "Med");
|
|
|
|
else if(severity == GL_DEBUG_SEVERITY_LOW_ARB)
|
|
|
|
strcpy(debSev, "Low");
|
|
|
|
|
2011-12-10 11:56:34 +00:00
|
|
|
#ifdef LOUD_DEBUGGING
|
2012-02-11 10:22:02 +00:00
|
|
|
fprintf(stderr,"Type:%s\tID:%d\tSeverity:%s\tMessage:%s\n", debType, g_draw_count, debSev,message);
|
2011-12-10 11:56:34 +00:00
|
|
|
#endif
|
2011-12-08 11:17:59 +00:00
|
|
|
|
|
|
|
FILE* f = fopen("Debug.txt","a");
|
2011-11-26 11:46:51 +00:00
|
|
|
if(f)
|
|
|
|
{
|
2012-02-11 10:22:02 +00:00
|
|
|
fprintf(f,"Type:%s\tID:%d\tSeverity:%s\tMessage:%s\n", debType, g_draw_count, debSev,message);
|
2011-11-26 11:46:51 +00:00
|
|
|
fclose(f);
|
|
|
|
}
|
2012-02-11 10:22:02 +00:00
|
|
|
//if (sev_counter > 2) assert(0);
|
2011-11-26 11:46:51 +00:00
|
|
|
}
|
2011-12-19 21:03:23 +00:00
|
|
|
|
|
|
|
// (A - B) * C + D
|
|
|
|
// A: Cs/Cd/0
|
|
|
|
// B: Cs/Cd/0
|
|
|
|
// C: As/Ad/FIX
|
|
|
|
// D: Cs/Cd/0
|
|
|
|
|
|
|
|
// bogus: 0100, 0110, 0120, 0200, 0210, 0220, 1001, 1011, 1021
|
|
|
|
// tricky: 1201, 1211, 1221
|
|
|
|
|
|
|
|
// Source.rgb = float3(1, 1, 1);
|
|
|
|
// 1201 Cd*(1 + As) => Source * Dest color + Dest * Source alpha
|
|
|
|
// 1211 Cd*(1 + Ad) => Source * Dest color + Dest * Dest alpha
|
|
|
|
// 1221 Cd*(1 + F) => Source * Dest color + Dest * Factor
|
|
|
|
|
|
|
|
// Copy Dx blend table and convert it to ogl
|
|
|
|
#define D3DBLENDOP_ADD GL_FUNC_ADD
|
|
|
|
#define D3DBLENDOP_SUBTRACT GL_FUNC_SUBTRACT
|
|
|
|
#define D3DBLENDOP_REVSUBTRACT GL_FUNC_REVERSE_SUBTRACT
|
|
|
|
|
|
|
|
#define D3DBLEND_ONE GL_ONE
|
|
|
|
#define D3DBLEND_ZERO GL_ZERO
|
|
|
|
#define D3DBLEND_INVDESTALPHA GL_ONE_MINUS_DST_ALPHA
|
|
|
|
#define D3DBLEND_DESTALPHA GL_DST_ALPHA
|
|
|
|
#define D3DBLEND_DESTCOLOR GL_DST_COLOR
|
|
|
|
#define D3DBLEND_BLENDFACTOR GL_CONSTANT_COLOR
|
|
|
|
#define D3DBLEND_INVBLENDFACTOR GL_ONE_MINUS_CONSTANT_COLOR
|
2012-01-03 16:12:34 +00:00
|
|
|
|
2012-05-11 19:39:32 +00:00
|
|
|
#define D3DBLEND_SRCALPHA GL_SRC1_ALPHA
|
|
|
|
#define D3DBLEND_INVSRCALPHA GL_ONE_MINUS_SRC1_ALPHA
|
2011-12-19 21:03:23 +00:00
|
|
|
|
|
|
|
const GSDeviceOGL::D3D9Blend GSDeviceOGL::m_blendMapD3D9[3*3*3*3] =
|
|
|
|
{
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0000: (Cs - Cs)*As + Cs ==> Cs
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0001: (Cs - Cs)*As + Cd ==> Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0002: (Cs - Cs)*As + 0 ==> 0
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0010: (Cs - Cs)*Ad + Cs ==> Cs
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0011: (Cs - Cs)*Ad + Cd ==> Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0012: (Cs - Cs)*Ad + 0 ==> 0
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0020: (Cs - Cs)*F + Cs ==> Cs
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0021: (Cs - Cs)*F + Cd ==> Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0022: (Cs - Cs)*F + 0 ==> 0
|
|
|
|
{1, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, //*0100: (Cs - Cd)*As + Cs ==> Cs*(As + 1) - Cd*As
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA}, // 0101: (Cs - Cd)*As + Cd ==> Cs*As + Cd*(1 - As)
|
|
|
|
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 0102: (Cs - Cd)*As + 0 ==> Cs*As - Cd*As
|
|
|
|
{1, D3DBLENDOP_SUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, //*0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_INVDESTALPHA}, // 0111: (Cs - Cd)*Ad + Cd ==> Cs*Ad + Cd*(1 - Ad)
|
|
|
|
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 0112: (Cs - Cd)*Ad + 0 ==> Cs*Ad - Cd*Ad
|
|
|
|
{1, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, //*0120: (Cs - Cd)*F + Cs ==> Cs*(F + 1) - Cd*F
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_INVBLENDFACTOR}, // 0121: (Cs - Cd)*F + Cd ==> Cs*F + Cd*(1 - F)
|
|
|
|
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 0122: (Cs - Cd)*F + 0 ==> Cs*F - Cd*F
|
|
|
|
{1, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, //*0200: (Cs - 0)*As + Cs ==> Cs*(As + 1)
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 0201: (Cs - 0)*As + Cd ==> Cs*As + Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 0202: (Cs - 0)*As + 0 ==> Cs*As
|
|
|
|
{1, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, //*0210: (Cs - 0)*Ad + Cs ==> Cs*(Ad + 1)
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 0211: (Cs - 0)*Ad + Cd ==> Cs*Ad + Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 0212: (Cs - 0)*Ad + 0 ==> Cs*Ad
|
|
|
|
{1, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, //*0220: (Cs - 0)*F + Cs ==> Cs*(F + 1)
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 0221: (Cs - 0)*F + Cd ==> Cs*F + Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 0222: (Cs - 0)*F + 0 ==> Cs*F
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_SRCALPHA}, // 1000: (Cd - Cs)*As + Cs ==> Cd*As + Cs*(1 - As)
|
|
|
|
{1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, //*1001: (Cd - Cs)*As + Cd ==> Cd*(As + 1) - Cs*As
|
|
|
|
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 1002: (Cd - Cs)*As + 0 ==> Cd*As - Cs*As
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_DESTALPHA}, // 1010: (Cd - Cs)*Ad + Cs ==> Cd*Ad + Cs*(1 - Ad)
|
|
|
|
{1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, //*1011: (Cd - Cs)*Ad + Cd ==> Cd*(Ad + 1) - Cs*Ad
|
|
|
|
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 1012: (Cd - Cs)*Ad + 0 ==> Cd*Ad - Cs*Ad
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 1020: (Cd - Cs)*F + Cs ==> Cd*F + Cs*(1 - F)
|
|
|
|
{1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},//*1021: (Cd - Cs)*F + Cd ==> Cd*(F + 1) - Cs*F
|
|
|
|
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},// 1022: (Cd - Cs)*F + 0 ==> Cd*F - Cs*F
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1100: (Cd - Cd)*As + Cs ==> Cs
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1101: (Cd - Cd)*As + Cd ==> Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1102: (Cd - Cd)*As + 0 ==> 0
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1110: (Cd - Cd)*Ad + Cs ==> Cs
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1111: (Cd - Cd)*Ad + Cd ==> Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1112: (Cd - Cd)*Ad + 0 ==> 0
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1120: (Cd - Cd)*F + Cs ==> Cs
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1121: (Cd - Cd)*F + Cd ==> Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1122: (Cd - Cd)*F + 0 ==> 0
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 1200: (Cd - 0)*As + Cs ==> Cs + Cd*As
|
|
|
|
{2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_SRCALPHA}, //#1201: (Cd - 0)*As + Cd ==> Cd*(1 + As) // ffxii main menu background glow effect
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 1202: (Cd - 0)*As + 0 ==> Cd*As
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 1210: (Cd - 0)*Ad + Cs ==> Cs + Cd*Ad
|
|
|
|
{2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_DESTALPHA}, //#1211: (Cd - 0)*Ad + Cd ==> Cd*(1 + Ad)
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_DESTALPHA}, // 1212: (Cd - 0)*Ad + 0 ==> Cd*Ad
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 1220: (Cd - 0)*F + Cs ==> Cs + Cd*F
|
|
|
|
{2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_BLENDFACTOR}, //#1221: (Cd - 0)*F + Cd ==> Cd*(1 + F)
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_BLENDFACTOR}, // 1222: (Cd - 0)*F + 0 ==> Cd*F
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_ZERO}, // 2000: (0 - Cs)*As + Cs ==> Cs*(1 - As)
|
|
|
|
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 2001: (0 - Cs)*As + Cd ==> Cd - Cs*As
|
|
|
|
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 2002: (0 - Cs)*As + 0 ==> 0 - Cs*As
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_ZERO}, // 2010: (0 - Cs)*Ad + Cs ==> Cs*(1 - Ad)
|
|
|
|
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 2011: (0 - Cs)*Ad + Cd ==> Cd - Cs*Ad
|
|
|
|
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 2012: (0 - Cs)*Ad + 0 ==> 0 - Cs*Ad
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_ZERO}, // 2020: (0 - Cs)*F + Cs ==> Cs*(1 - F)
|
|
|
|
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 2021: (0 - Cs)*F + Cd ==> Cd - Cs*F
|
|
|
|
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 2022: (0 - Cs)*F + 0 ==> 0 - Cs*F
|
|
|
|
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 2100: (0 - Cd)*As + Cs ==> Cs - Cd*As
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVSRCALPHA}, // 2101: (0 - Cd)*As + Cd ==> Cd*(1 - As)
|
|
|
|
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 2102: (0 - Cd)*As + 0 ==> 0 - Cd*As
|
|
|
|
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2110: (0 - Cd)*Ad + Cs ==> Cs - Cd*Ad
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVDESTALPHA}, // 2111: (0 - Cd)*Ad + Cd ==> Cd*(1 - Ad)
|
|
|
|
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2112: (0 - Cd)*Ad + 0 ==> 0 - Cd*Ad
|
|
|
|
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2120: (0 - Cd)*F + Cs ==> Cs - Cd*F
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVBLENDFACTOR}, // 2121: (0 - Cd)*F + Cd ==> Cd*(1 - F)
|
|
|
|
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2122: (0 - Cd)*F + 0 ==> 0 - Cd*F
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2200: (0 - 0)*As + Cs ==> Cs
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2201: (0 - 0)*As + Cd ==> Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2202: (0 - 0)*As + 0 ==> 0
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2210: (0 - 0)*Ad + Cs ==> Cs
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2211: (0 - 0)*Ad + Cd ==> Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2212: (0 - 0)*Ad + 0 ==> 0
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2220: (0 - 0)*F + Cs ==> Cs
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2221: (0 - 0)*F + Cd ==> Cd
|
|
|
|
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2222: (0 - 0)*F + 0 ==> 0
|
|
|
|
};
|